Made some small adjustments
This commit is contained in:
parent
1896e41b8a
commit
5cf1b33178
14
.clang-format
Executable file
14
.clang-format
Executable file
@ -0,0 +1,14 @@
|
||||
---
|
||||
BasedOnStyle: LLVM
|
||||
AlignOperands: 'true'
|
||||
IndentWidth: '4'
|
||||
IndentWrappedFunctionNames: 'true'
|
||||
KeepEmptyLinesAtTheStartOfBlocks: 'false'
|
||||
TabWidth: '4'
|
||||
UseTab: Always
|
||||
ColumnLimit: '0'
|
||||
PointerAlignment: Left
|
||||
BreakConstructorInitializers: BeforeComma
|
||||
AccessModifierOffset: -4
|
||||
SortIncludes: 'false'
|
||||
SortUsingDeclarations: 'false'
|
0
.gitignore
vendored
Normal file → Executable file
0
.gitignore
vendored
Normal file → Executable file
4
Makefile
Normal file → Executable file
4
Makefile
Normal file → Executable file
@ -1,7 +1,7 @@
|
||||
# ---- ---- #
|
||||
|
||||
CC = clang
|
||||
CF = -Wall -lkrb5 -lvirt -ljson-c -g
|
||||
CC = gcc
|
||||
CF = -Wall -lkrb5 -lvirt -ljson-c -lcrypto -g
|
||||
|
||||
# ---- ---- #
|
||||
|
||||
|
221
src/backing.c
Executable file
221
src/backing.c
Executable file
@ -0,0 +1,221 @@
|
||||
#include "backing.h"
|
||||
|
||||
#include "container.h"
|
||||
#include "disk.h"
|
||||
|
||||
#include <md5.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
result_t check_backing_identifier(const char* backing) {
|
||||
// Check that the identifier is not null
|
||||
if (backing == NULL)
|
||||
return failure("Backing identifier cannot be null.");
|
||||
|
||||
// Check that the identifier is the length of a md5 hash
|
||||
size_t length = strlen(backing);
|
||||
if (length != MD5_DIGEST_STRING_LENGTH - 1) // -1 because the string is null-terminated
|
||||
return failure("Backing identifier must be %d characters long.", MD5_DIGEST_STRING_LENGTH - 1);
|
||||
|
||||
// Check that the identifier only contains allowed characters
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
char c = backing[i];
|
||||
if (c >= 'a' && c <= 'f')
|
||||
continue;
|
||||
if (c >= '0' && c <= '9')
|
||||
continue;
|
||||
|
||||
return failure("Backing identifier cannot contain the character '%c' at index %d.", c, i);
|
||||
}
|
||||
|
||||
return success();
|
||||
}
|
||||
|
||||
result_t check_backing_exists(const char* backing) {
|
||||
// Get the backing path
|
||||
char* path;
|
||||
result_t result = get_backing_path(&path, backing);
|
||||
if (result != success())
|
||||
return result;
|
||||
|
||||
// Check that the backing exists
|
||||
struct stat st;
|
||||
errno = 0;
|
||||
if (stat(path, &st) != 0) {
|
||||
if (errno == ENOENT)
|
||||
result = failure("Backing '%s' does not exist.", backing);
|
||||
else
|
||||
result = failure("Failed to check if backing '%s' exists (%s).", backing, strerror(errno));
|
||||
|
||||
free(path);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Check that the backing is a file
|
||||
if (!S_ISREG(st.st_mode)) {
|
||||
result = failure("Backing '%s' is not a regular file.", backing);
|
||||
free(path);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Free the backing path
|
||||
free(path);
|
||||
|
||||
return success();
|
||||
}
|
||||
|
||||
result_t get_backing_pool_path(char** _path) {
|
||||
return format(_path, "/var/lib/sandbox/backings");
|
||||
}
|
||||
|
||||
result_t get_backing_path(char** _path, const char* backing) {
|
||||
// Check the backing identifier
|
||||
result_t result = check_backing_identifier(backing);
|
||||
if (result != success())
|
||||
return result;
|
||||
|
||||
// Get the backing pool path
|
||||
char* pool_path;
|
||||
result = get_backing_pool_path(&pool_path);
|
||||
if (result != success())
|
||||
return result;
|
||||
|
||||
// Format the backing path
|
||||
result = format(_path, "%s/%s", pool_path, backing);
|
||||
|
||||
free(pool_path);
|
||||
return result;
|
||||
}
|
||||
|
||||
result_t get_backing_default_path(char** _path) {
|
||||
// Get the backing pool path
|
||||
char* pool_path;
|
||||
result_t result = get_backing_pool_path(&pool_path);
|
||||
if (result != success())
|
||||
return result;
|
||||
|
||||
// Format the backing path
|
||||
result = format(_path, "%s/default", pool_path);
|
||||
|
||||
free(pool_path);
|
||||
return result;
|
||||
}
|
||||
|
||||
result_t remove_backing(const char* backing) {
|
||||
// Check that the backing exists
|
||||
result_t result = check_backing_exists(backing);
|
||||
if (result != success())
|
||||
return result;
|
||||
|
||||
// Get the backing path
|
||||
char* path;
|
||||
result = get_backing_path(&path, backing);
|
||||
if (result != success())
|
||||
return result;
|
||||
|
||||
// Remove the backing
|
||||
errno = 0;
|
||||
remove(path);
|
||||
|
||||
// Check for errors during the removal
|
||||
if (errno != 0) {
|
||||
free(path);
|
||||
return failure("Failed to remove backing '%s' (%s).", backing, strerror(errno));
|
||||
}
|
||||
|
||||
free(path);
|
||||
return success();
|
||||
}
|
||||
|
||||
bool backing_filter(const char* file) {
|
||||
// Check that a backing with the same name exists
|
||||
return check_backing_exists(file) == success();
|
||||
}
|
||||
|
||||
result_t list_backings(char*** _backings) {
|
||||
// Get the backing pool path
|
||||
char* pool_path;
|
||||
result_t result = get_backing_pool_path(&pool_path);
|
||||
if (result != success())
|
||||
return result;
|
||||
|
||||
// List the backings
|
||||
result = list_files(_backings, pool_path, &backing_filter);
|
||||
|
||||
free(pool_path);
|
||||
return result;
|
||||
}
|
||||
|
||||
result_t get_default_backing(char** _backing) {
|
||||
// Get the backing default path
|
||||
char* path;
|
||||
result_t result = get_backing_default_path(&path);
|
||||
if (result != success())
|
||||
return result;
|
||||
|
||||
char* backing;
|
||||
|
||||
// Read the default backing
|
||||
result = read_file(&backing, path);
|
||||
|
||||
free(path);
|
||||
|
||||
if (result != success())
|
||||
return failure("No default backing configured.");
|
||||
|
||||
// Check that the backing is valid
|
||||
result = check_backing_identifier(backing);
|
||||
if (result != success()) {
|
||||
free(backing);
|
||||
return failure("Default backing '%s' is not a valid backing identifier.", backing);
|
||||
}
|
||||
|
||||
// Check that the backing exists
|
||||
result = check_backing_exists(backing);
|
||||
if (result != success()) {
|
||||
free(backing);
|
||||
return failure("Default backing '%s' does not exist.", backing);
|
||||
}
|
||||
|
||||
*_backing = backing;
|
||||
return result;
|
||||
}
|
||||
|
||||
result_t set_default_backing(const char* backing) {
|
||||
// Get the backing default path
|
||||
char* path;
|
||||
result_t result = get_backing_default_path(&path);
|
||||
if (result != success())
|
||||
return result;
|
||||
|
||||
// If the backing is null, remove the default backing file
|
||||
if (backing == NULL) {
|
||||
errno = 0;
|
||||
remove(path);
|
||||
free(path);
|
||||
|
||||
if (errno == ENOENT)
|
||||
return success();
|
||||
else if (errno != 0)
|
||||
return failure("Failed to remove the default backing file (%s).", strerror(errno));
|
||||
|
||||
return success();
|
||||
} else {
|
||||
// Check that the backing exists
|
||||
result = check_backing_exists(backing);
|
||||
if (result != success()) {
|
||||
free(path);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Write the default backing
|
||||
result = write_file(path, backing);
|
||||
|
||||
free(path);
|
||||
return result;
|
||||
}
|
||||
}
|
19
src/backing.h
Executable file
19
src/backing.h
Executable file
@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
result_t check_backing_identifier(const char* backing);
|
||||
result_t check_backing_exists(const char* backing);
|
||||
|
||||
result_t get_backing_pool_path(char** _path);
|
||||
result_t get_backing_path(char** _path, const char* backing);
|
||||
result_t get_backing_default_path(char** _path);
|
||||
|
||||
result_t add_backing(const char* backing, const char* container);
|
||||
result_t remove_backing(const char* backing);
|
||||
|
||||
bool backing_filter(const char* file);
|
||||
result_t list_backings(char*** _backings);
|
||||
|
||||
result_t get_default_backing(char** _backing);
|
||||
result_t set_default_backing(const char* backing);
|
222
src/container.c
Executable file
222
src/container.c
Executable file
@ -0,0 +1,222 @@
|
||||
#include "container.h"
|
||||
|
||||
#include "disk.h"
|
||||
#include "backing.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
result_t check_container_identifier(const char* container) {
|
||||
// Check that the container identifier is not null
|
||||
if (container == NULL)
|
||||
return failure("Container identifier cannot be null.");
|
||||
|
||||
// Check that the container identifier is not empty, nor too long
|
||||
size_t length = strlen(container);
|
||||
if (length == 0)
|
||||
return failure("Container identifier cannot be empty.");
|
||||
if (length > CONTAINER_IDENTIFIER_MAX_LENGTH)
|
||||
return failure("Container identifier cannot be longer than %d characters.", CONTAINER_IDENTIFIER_MAX_LENGTH);
|
||||
|
||||
// Check that the container identifier only contains allowed characters
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
char c = container[i];
|
||||
if (c >= 'a' && c <= 'z')
|
||||
continue;
|
||||
if (c >= 'A' && c <= 'Z')
|
||||
continue;
|
||||
if (c >= '0' && c <= '9')
|
||||
continue;
|
||||
if ((c == '-' || c == '_' || c == '.') && i > 0) // Not at the beginning
|
||||
continue;
|
||||
|
||||
return failure("Container identifier cannot contain the character '%c' at index %d.", c, i);
|
||||
}
|
||||
|
||||
return success();
|
||||
}
|
||||
|
||||
result_t check_container_exists(const char* container) {
|
||||
// Get the container path
|
||||
char* path;
|
||||
result_t result = get_container_path(&path, container);
|
||||
if (result != success())
|
||||
return result;
|
||||
|
||||
// Check that the container exists
|
||||
struct stat st;
|
||||
errno = 0;
|
||||
if (stat(path, &st) != 0) {
|
||||
if (errno == ENOENT)
|
||||
result = failure("Container '%s' does not exist.", container);
|
||||
else
|
||||
result = failure("Failed to check if container '%s' exists (%s).", container, strerror(errno));
|
||||
|
||||
free(path);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Check that the container is a file
|
||||
if (!S_ISREG(st.st_mode)) {
|
||||
result = failure("Container '%s' is not a file.", container);
|
||||
free(path);
|
||||
return result;
|
||||
}
|
||||
|
||||
free(path);
|
||||
return success();
|
||||
}
|
||||
|
||||
result_t get_container_pool_path(char** _path) {
|
||||
return format(_path, "/var/lib/sandbox/containers");
|
||||
}
|
||||
|
||||
result_t get_container_path(char** _path, const char* container) {
|
||||
// Check the container identifier
|
||||
result_t result = check_container_identifier(container);
|
||||
if (result != success())
|
||||
return result;
|
||||
|
||||
// Get the container pool path
|
||||
char* pool_path;
|
||||
result = get_container_pool_path(&pool_path);
|
||||
if (result != success())
|
||||
return result;
|
||||
|
||||
// Format the container path
|
||||
result = format(_path, "%s/%s", pool_path, container);
|
||||
|
||||
free(pool_path);
|
||||
return result;
|
||||
}
|
||||
|
||||
result_t add_root_container(const char* container, uint64_t size) {
|
||||
// Check that the container does not already exist
|
||||
result_t result = check_container_exists(container);
|
||||
if (result == success())
|
||||
return failure("Container '%s' already exists.", container);
|
||||
|
||||
// Get the container path
|
||||
char* path;
|
||||
result = get_container_path(&path, container);
|
||||
if (result != success())
|
||||
return result;
|
||||
|
||||
// Create the root container
|
||||
result = create_root_disk(path, size);
|
||||
|
||||
free(path);
|
||||
return result;
|
||||
}
|
||||
|
||||
result_t add_backed_container(const char* container, const char* backing) {
|
||||
// Check that the container does not already exist
|
||||
result_t result = check_container_exists(container);
|
||||
if (result == success())
|
||||
return failure("Container '%s' already exists.", container);
|
||||
|
||||
// Get the container path
|
||||
char* path;
|
||||
result = get_container_path(&path, container);
|
||||
if (result != success())
|
||||
return result;
|
||||
|
||||
// Get the backing path
|
||||
char* backing_path;
|
||||
result = get_backing_path(&backing_path, backing);
|
||||
if (result != success()) {
|
||||
free(path);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Create the backed container
|
||||
result = create_backed_disk(path, backing_path);
|
||||
|
||||
free(backing_path);
|
||||
free(path);
|
||||
return result;
|
||||
}
|
||||
|
||||
result_t remove_container(const char* container) {
|
||||
// Check that the container exists
|
||||
result_t result = check_container_exists(container);
|
||||
if (result != success())
|
||||
return result;
|
||||
|
||||
// Get the container path
|
||||
char* path;
|
||||
result = get_container_path(&path, container);
|
||||
if (result != success())
|
||||
return result;
|
||||
|
||||
// Delete the container
|
||||
errno = 0;
|
||||
remove(path);
|
||||
|
||||
free(path);
|
||||
|
||||
if (errno != 0)
|
||||
return failure("Failed to remove container '%s' (%s).", container, strerror(errno));
|
||||
|
||||
return success();
|
||||
}
|
||||
|
||||
result_t trim_container(const char* container) {
|
||||
// Check that the container exists
|
||||
result_t result = check_container_exists(container);
|
||||
if (result != success())
|
||||
return result;
|
||||
|
||||
// Get the container path
|
||||
char* path;
|
||||
result = get_container_path(&path, container);
|
||||
if (result != success())
|
||||
return result;
|
||||
|
||||
// Trim the container
|
||||
result = trim_disk(path);
|
||||
|
||||
free(path);
|
||||
return result;
|
||||
}
|
||||
|
||||
result_t reset_container(const char* container) {
|
||||
// Check that the container exists
|
||||
result_t result = check_container_exists(container);
|
||||
if (result != success())
|
||||
return result;
|
||||
|
||||
// Get the container path
|
||||
char* path;
|
||||
result = get_container_path(&path, container);
|
||||
if (result != success())
|
||||
return result;
|
||||
|
||||
// Reset the container
|
||||
result = reset_disk(path);
|
||||
|
||||
free(path);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool container_filter(const char* file) {
|
||||
// Check that a container with the same name exists
|
||||
return check_container_exists(file) == success();
|
||||
}
|
||||
|
||||
result_t list_containers(char*** _containers) {
|
||||
// Get the container pool path
|
||||
char* pool_path;
|
||||
result_t result = get_container_pool_path(&pool_path);
|
||||
if (result != success())
|
||||
return result;
|
||||
|
||||
// List the files in the container pool
|
||||
result = list_files(_containers, pool_path, container_filter);
|
||||
|
||||
free(pool_path);
|
||||
return result;
|
||||
}
|
21
src/container.h
Executable file
21
src/container.h
Executable file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
#define CONTAINER_IDENTIFIER_MAX_LENGTH 64
|
||||
|
||||
result_t check_container_identifier(const char* container);
|
||||
result_t check_container_exists(const char* container);
|
||||
|
||||
result_t get_container_pool_path(char** _path);
|
||||
result_t get_container_path(char** _path, const char* container);
|
||||
|
||||
result_t add_root_container(const char* container, uint64_t size);
|
||||
result_t add_backed_container(const char* container, const char* backing);
|
||||
result_t remove_container(const char* container);
|
||||
|
||||
result_t trim_container(const char* container);
|
||||
result_t reset_container(const char* container);
|
||||
|
||||
bool container_filter(const char* file);
|
||||
result_t list_containers(char*** _containers);
|
395
src/disk.c
Normal file → Executable file
395
src/disk.c
Normal file → Executable file
File diff suppressed because it is too large
Load Diff
19
src/disk.h
Normal file → Executable file
19
src/disk.h
Normal file → Executable file
@ -5,14 +5,15 @@
|
||||
typedef struct {
|
||||
uint64_t size;
|
||||
uint64_t allocated;
|
||||
char* backing_file_path;
|
||||
char* backing_identifier;
|
||||
} DiskInfo;
|
||||
char* backing_path;
|
||||
} disk_info_t;
|
||||
|
||||
Result CreateRootDisk(const char* disk_path, uint64_t size);
|
||||
Result CreateBackedDisk(const char* disk_path, const char* backing_disk_path);
|
||||
Result TrimDisk(const char* disk_path);
|
||||
Result RebackDisk(const char* disk_path, const char* backing_disk_path);
|
||||
result_t create_root_disk(const char* path, uint64_t size);
|
||||
result_t create_backed_disk(const char* path, const char* backing_path);
|
||||
|
||||
Result GetDiskInfo(const char* disk_path, DiskInfo* _info);
|
||||
Result FreeDiskInfo(DiskInfo* info);
|
||||
result_t trim_disk(const char* path);
|
||||
result_t reset_disk(const char* path);
|
||||
result_t reback_disk(const char* path, const char* backing_path);
|
||||
|
||||
result_t get_disk_info(disk_info_t* _info, const char* path);
|
||||
void free_disk_info(disk_info_t* _info);
|
||||
|
415
src/image.c
415
src/image.c
@ -1,415 +0,0 @@
|
||||
#include "image.h"
|
||||
|
||||
#include "disk.h"
|
||||
#include "template.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <dirent.h>
|
||||
|
||||
Result IsImageIdentifierValid(const char* image_id, bool* _valid) {
|
||||
*_valid = false;
|
||||
|
||||
// Check that the image identifier is not NULL
|
||||
if (image_id == NULL)
|
||||
return SUCCESS;
|
||||
|
||||
// Check that the image identifier is not empty or too long
|
||||
size_t length = strlen(image_id);
|
||||
if (length == 0 || length > MAX_IMAGE_ID_LENGTH)
|
||||
return SUCCESS;
|
||||
|
||||
// Check that the image identifier contains characters that are allowed as a user name
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
char c = image_id[i];
|
||||
if (c >= 'a' && c <= 'z')
|
||||
continue;
|
||||
if (c >= 'A' && c <= 'Z')
|
||||
continue;
|
||||
if (c >= '0' && c <= '9')
|
||||
continue;
|
||||
if (c == '_' || c == '-' || c == '.')
|
||||
continue;
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
// Check that the image identifier is not a reserved name
|
||||
if (strcmp(image_id, ".") == 0 || strcmp(image_id, "..") == 0)
|
||||
return SUCCESS;
|
||||
|
||||
*_valid = true;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
Result GetImagePoolPath(char** _path) {
|
||||
return Format(_path, "/var/lib/sandbox/images");
|
||||
}
|
||||
|
||||
Result GetImageDirectoryPath(const char* image_id, char** _path) {
|
||||
// Check that the image identifier is valid
|
||||
if (IsImageIdentifierValid(image_id, NULL) != SUCCESS)
|
||||
return FAILURE;
|
||||
|
||||
// Get the path to the image pool
|
||||
char* pool_path;
|
||||
if (GetImagePoolPath(&pool_path) != SUCCESS)
|
||||
return FAILURE;
|
||||
|
||||
// Format the image directory path
|
||||
Result result = Format(_path, "%s/%s", pool_path, image_id);
|
||||
|
||||
free(pool_path);
|
||||
return result;
|
||||
}
|
||||
|
||||
Result GetImageDiskPath(const char* image_id, char** _path) {
|
||||
// Get the path to the image directory
|
||||
char* directory_path;
|
||||
if (GetImageDirectoryPath(image_id, &directory_path) != SUCCESS)
|
||||
return FAILURE;
|
||||
|
||||
// Format the image disk path
|
||||
Result result = Format(_path, "%s/disk", directory_path);
|
||||
|
||||
free(directory_path);
|
||||
return result;
|
||||
}
|
||||
|
||||
Result DoesImageDirectoryExist(const char* image_id, bool* _exists) {
|
||||
// Get the path to the image directory
|
||||
char* directory_path;
|
||||
if (GetImageDirectoryPath(image_id, &directory_path) != SUCCESS)
|
||||
return FAILURE;
|
||||
|
||||
// Check if the image directory exists
|
||||
struct stat st;
|
||||
*_exists = stat(directory_path, &st) == 0 && S_ISDIR(st.st_mode);
|
||||
|
||||
free(directory_path);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
Result DoesImageDiskExist(const char* image_id, bool* _exists) {
|
||||
// Get the path to the image disk
|
||||
char* disk_path;
|
||||
if (GetImageDiskPath(image_id, &disk_path) != SUCCESS)
|
||||
return FAILURE;
|
||||
|
||||
// Check if the image disk exists
|
||||
struct stat st;
|
||||
*_exists = stat(disk_path, &st) == 0 && S_ISREG(st.st_mode);
|
||||
|
||||
free(disk_path);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
Result AddImage(const char* image_id) {
|
||||
// Check if the image directory already exists
|
||||
bool directory_exists;
|
||||
if (DoesImageDirectoryExist(image_id, &directory_exists) != SUCCESS)
|
||||
return FAILURE;
|
||||
|
||||
if (directory_exists) {
|
||||
Log(LOG_LEVEL_ERROR, "Image '%s' already exists", image_id);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
// Get the path to the image directory
|
||||
char* directory_path;
|
||||
if (GetImageDirectoryPath(image_id, &directory_path) != SUCCESS)
|
||||
return FAILURE;
|
||||
|
||||
// Create the image directory
|
||||
Result result = mkdir(directory_path, 0755) == 0 ? SUCCESS : FAILURE;
|
||||
|
||||
if (result == FAILURE)
|
||||
Log(LOG_LEVEL_ERROR, "Failed to create image '%s' (%s)", directory_path, strerror(errno));
|
||||
|
||||
free(directory_path);
|
||||
return result;
|
||||
}
|
||||
|
||||
Result RemoveImage(const char* image_id) {
|
||||
// Check if the image directory exists
|
||||
bool directory_exists;
|
||||
if (DoesImageDirectoryExist(image_id, &directory_exists) != SUCCESS)
|
||||
return FAILURE;
|
||||
|
||||
if (!directory_exists) {
|
||||
Log(LOG_LEVEL_ERROR, "Image '%s' does not exist", image_id);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
// Check if there is a disk for the image and remove it if it exists
|
||||
bool disk_exists;
|
||||
if (DoesImageDiskExist(image_id, &disk_exists) != SUCCESS)
|
||||
return FAILURE;
|
||||
if (disk_exists)
|
||||
RemoveImageDisk(image_id);
|
||||
|
||||
// Get the path to the image directory
|
||||
char* directory_path;
|
||||
if (GetImageDirectoryPath(image_id, &directory_path) != SUCCESS)
|
||||
return FAILURE;
|
||||
|
||||
// Remove the image directory
|
||||
Result result = rmdir(directory_path) == 0 ? SUCCESS : FAILURE;
|
||||
|
||||
if (result == FAILURE)
|
||||
Log(LOG_LEVEL_ERROR, "Failed to remove image '%s' (%s)", directory_path, strerror(errno));
|
||||
|
||||
free(directory_path);
|
||||
return result;
|
||||
}
|
||||
|
||||
Result ListImages(char*** _image_ids) {
|
||||
// Get the path to the image pool
|
||||
char* pool_path;
|
||||
if (GetImagePoolPath(&pool_path) != SUCCESS)
|
||||
return FAILURE;
|
||||
|
||||
// Open the image pool directory
|
||||
DIR* pool_dir = opendir(pool_path);
|
||||
if (pool_dir == NULL) {
|
||||
Log(LOG_LEVEL_ERROR, "Failed to open image pool directory '%s' (%s)", pool_path, strerror(errno));
|
||||
free(pool_path);
|
||||
return FAILURE;
|
||||
}
|
||||
free(pool_path);
|
||||
|
||||
// Allocate an initial array, one element is reserved for the NULL terminator
|
||||
*_image_ids = malloc(sizeof(char*));
|
||||
if (*_image_ids == NULL) {
|
||||
Log(LOG_LEVEL_ERROR, "Failed to allocate memory for image identifiers");
|
||||
closedir(pool_dir);
|
||||
return FAILURE;
|
||||
}
|
||||
(*_image_ids)[0] = NULL;
|
||||
|
||||
// Iterate over the image pool directory
|
||||
int count = 0;
|
||||
struct dirent* entry;
|
||||
while ((entry = readdir(pool_dir)) != NULL) {
|
||||
// Skip the current and parent directory
|
||||
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
|
||||
continue;
|
||||
|
||||
// Check that the entry actually exists
|
||||
bool exists;
|
||||
if (DoesImageDirectoryExist(entry->d_name, &exists) != SUCCESS || !exists)
|
||||
continue;
|
||||
|
||||
// Allocate a new element in the array
|
||||
char** new_image_ids = realloc(*_image_ids, (count + 2) * sizeof(char*)); // One element is reserved for the NULL terminator
|
||||
if (new_image_ids == NULL) {
|
||||
Log(LOG_LEVEL_ERROR, "Failed to allocate memory for image identifiers");
|
||||
closedir(pool_dir);
|
||||
for (int i = 0; i < count; i++)
|
||||
free((*_image_ids)[i]);
|
||||
free(*_image_ids);
|
||||
return FAILURE;
|
||||
}
|
||||
*_image_ids = new_image_ids;
|
||||
|
||||
// Copy the entry name into the array
|
||||
if (Duplicate(entry->d_name, &(*_image_ids)[count]) != SUCCESS) {
|
||||
Log(LOG_LEVEL_ERROR, "Failed to allocate memory for image identifier");
|
||||
closedir(pool_dir);
|
||||
for (int i = 0; i < count; i++)
|
||||
free((*_image_ids)[i]);
|
||||
free(*_image_ids);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
// Null-terminate the array
|
||||
(*_image_ids)[count + 1] = NULL;
|
||||
|
||||
// Increment the count
|
||||
count++;
|
||||
}
|
||||
|
||||
// Close the image pool directory
|
||||
closedir(pool_dir);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
Result ClearImages(void) {
|
||||
// Get the image identifiers
|
||||
char** image_ids;
|
||||
if (ListImages(&image_ids) != SUCCESS)
|
||||
return FAILURE;
|
||||
|
||||
// Remove each image
|
||||
for (int i = 0; image_ids[i] != NULL; i++)
|
||||
RemoveImage(image_ids[i]);
|
||||
|
||||
// Free the image identifiers
|
||||
for (int i = 0; image_ids[i] != NULL; i++)
|
||||
free(image_ids[i]);
|
||||
free(image_ids);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
Result AddRootImageDisk(const char* image_id, uint64_t size) {
|
||||
// Check that the image directory exists
|
||||
bool directory_exists;
|
||||
if (DoesImageDirectoryExist(image_id, &directory_exists) != SUCCESS)
|
||||
return FAILURE;
|
||||
|
||||
if (!directory_exists) {
|
||||
Log(LOG_LEVEL_ERROR, "Image '%s' does not exist", image_id);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
// Check that the image disk does not exist
|
||||
bool disk_exists;
|
||||
if (DoesImageDiskExist(image_id, &disk_exists) != SUCCESS)
|
||||
return FAILURE;
|
||||
|
||||
if (disk_exists) {
|
||||
Log(LOG_LEVEL_ERROR, "Disk for image '%s' already exists", image_id);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
// Get the path to the image disk
|
||||
char* disk_path;
|
||||
if (GetImageDiskPath(image_id, &disk_path) != SUCCESS)
|
||||
return FAILURE;
|
||||
|
||||
// Create the root disk
|
||||
Result result = CreateRootDisk(disk_path, size);
|
||||
|
||||
free(disk_path);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Result AddTemplatedImageDisk(const char* image_id, const char* template_id) {
|
||||
// Check that the image directory exists
|
||||
bool directory_exists;
|
||||
if (DoesImageDirectoryExist(image_id, &directory_exists) != SUCCESS)
|
||||
return FAILURE;
|
||||
|
||||
if (!directory_exists) {
|
||||
Log(LOG_LEVEL_ERROR, "Image '%s' does not exist", image_id);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
// Check that the image disk does not exist
|
||||
bool disk_exists;
|
||||
if (DoesImageDiskExist(image_id, &disk_exists) != SUCCESS)
|
||||
return FAILURE;
|
||||
|
||||
if (disk_exists) {
|
||||
Log(LOG_LEVEL_ERROR, "Disk for image '%s' already exists", image_id);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
// Check that the template exists
|
||||
bool template_exists;
|
||||
if (DoesTemplateExist(template_id, &template_exists) != SUCCESS)
|
||||
return FAILURE;
|
||||
|
||||
if (!template_exists) {
|
||||
Log(LOG_LEVEL_ERROR, "Template '%s' does not exist", template_id);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
// Get the path to the template disk
|
||||
char* template_disk_path;
|
||||
if (GetTemplateDiskPath(template_id, &template_disk_path) != SUCCESS)
|
||||
return FAILURE;
|
||||
|
||||
// Get the path to the image disk
|
||||
char* disk_path;
|
||||
if (GetImageDiskPath(image_id, &disk_path) != SUCCESS) {
|
||||
free(template_disk_path);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
// Create the templated disk
|
||||
Result result = CreateBackedDisk(disk_path, template_disk_path);
|
||||
|
||||
free(template_disk_path);
|
||||
free(disk_path);
|
||||
return result;
|
||||
}
|
||||
|
||||
Result RemoveImageDisk(const char* image_id) {
|
||||
// Check that the image directory exists
|
||||
bool directory_exists;
|
||||
if (DoesImageDirectoryExist(image_id, &directory_exists) != SUCCESS)
|
||||
return FAILURE;
|
||||
|
||||
if (!directory_exists) {
|
||||
Log(LOG_LEVEL_ERROR, "Image '%s' does not exist", image_id);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
// Check that the image disk exists
|
||||
bool disk_exists;
|
||||
if (DoesImageDiskExist(image_id, &disk_exists) != SUCCESS)
|
||||
return FAILURE;
|
||||
|
||||
if (!disk_exists) {
|
||||
Log(LOG_LEVEL_ERROR, "Disk for image '%s' does not exist", image_id);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
// Get the path to the image disk
|
||||
char* disk_path;
|
||||
if (GetImageDiskPath(image_id, &disk_path) != SUCCESS)
|
||||
return FAILURE;
|
||||
|
||||
// Remove the image disk
|
||||
int result = unlink(disk_path);
|
||||
|
||||
free(disk_path);
|
||||
|
||||
if (result != 0) {
|
||||
Log(LOG_LEVEL_ERROR, "Failed to remove disk for image '%s' (%s)", image_id, strerror(errno));
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
Result TrimImageDisk(const char* image_id) {
|
||||
// Check that the image directory exists
|
||||
bool directory_exists;
|
||||
if (DoesImageDirectoryExist(image_id, &directory_exists) != SUCCESS)
|
||||
return FAILURE;
|
||||
|
||||
if (!directory_exists) {
|
||||
Log(LOG_LEVEL_ERROR, "Image '%s' does not exist", image_id);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
// Check that the image disk exists
|
||||
bool disk_exists;
|
||||
if (DoesImageDiskExist(image_id, &disk_exists) != SUCCESS)
|
||||
return FAILURE;
|
||||
|
||||
if (!disk_exists) {
|
||||
Log(LOG_LEVEL_ERROR, "Disk for image '%s' does not exist", image_id);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
// Get the path to the image disk
|
||||
char* disk_path;
|
||||
if (GetImageDiskPath(image_id, &disk_path) != SUCCESS)
|
||||
return FAILURE;
|
||||
|
||||
// Trim the image disk
|
||||
Result result = TrimDisk(disk_path);
|
||||
|
||||
free(disk_path);
|
||||
|
||||
return result;
|
||||
}
|
24
src/image.h
24
src/image.h
@ -1,24 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
#define MAX_IMAGE_ID_LENGTH 64
|
||||
|
||||
Result IsImageIdentifierValid(const char* image_id, bool* _valid);
|
||||
|
||||
Result GetImagePoolPath(char** _path);
|
||||
Result GetImageDirectoryPath(const char* image_id, char** _path);
|
||||
Result GetImageDiskPath(const char* image_id, char** _path);
|
||||
|
||||
Result DoesImageDirectoryExist(const char* image_id, bool* _exists);
|
||||
Result DoesImageDiskExist(const char* image_id, bool* _exists);
|
||||
|
||||
Result AddImage(const char* image_id);
|
||||
Result RemoveImage(const char* image_id);
|
||||
Result ListImages(char*** _image_ids);
|
||||
Result ClearImages(void);
|
||||
|
||||
Result AddRootImageDisk(const char* image_id, uint64_t size);
|
||||
Result AddTemplatedImageDisk(const char* image_id, const char* template_id);
|
||||
Result RemoveImageDisk(const char* image_id);
|
||||
Result TrimImageDisk(const char* image_id);
|
241
src/sandbox.c
Normal file → Executable file
241
src/sandbox.c
Normal file → Executable file
@ -2,268 +2,37 @@
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <pwd.h>
|
||||
#include <unistd.h>
|
||||
|
||||
Command COMMANDS[] = {
|
||||
{
|
||||
command_help,
|
||||
{{"help", NULL}, NULL},
|
||||
NULL,
|
||||
{{"command", "TODO: Add description.", false}, NULL},
|
||||
"TODO: Add description.",
|
||||
"TODO: Add details."
|
||||
},
|
||||
{
|
||||
command_version,
|
||||
{{"version", NULL}, NULL},
|
||||
NULL,
|
||||
NULL,
|
||||
"TODO: Add description.",
|
||||
"TODO: Add details."
|
||||
},
|
||||
{
|
||||
command_config,
|
||||
{{"config", NULL}, NULL},
|
||||
NULL,
|
||||
NULL,
|
||||
"TODO: Add description.",
|
||||
"TODO: Add details."
|
||||
},
|
||||
{
|
||||
command_container_add,
|
||||
{{"container", "add", NULL}, NULL},
|
||||
{
|
||||
{
|
||||
{"-r", "--root", NULL},
|
||||
{{"size", "TODO: Add description.", true}, NULL},
|
||||
"TODO: Add description."
|
||||
},
|
||||
{
|
||||
{"-i", "--image", NULL},
|
||||
{{"image", "TODO: Add description.", true}, NULL},
|
||||
"TODO: Add description."
|
||||
},
|
||||
NULL
|
||||
},
|
||||
{{"container", "TODO: Add description.", true}, NULL},
|
||||
"TODO: Add description.",
|
||||
"TODO: Add details."
|
||||
},
|
||||
{
|
||||
command_container_remove,
|
||||
{{"container", "rm", NULL}, {"container", "remove", NULL}, {"container", "del", NULL}, {"container", "delete", NULL}, NULL},
|
||||
NULL,
|
||||
{{"container", "TODO: Add description.", true}, NULL},
|
||||
"TODO: Add description.",
|
||||
"TODO: Add details."
|
||||
},
|
||||
{
|
||||
command_container_reset,
|
||||
{{"container", "reset", NULL}, NULL},
|
||||
NULL,
|
||||
{{"container", "TODO: Add description.", true}, NULL},
|
||||
"Resets the container.",
|
||||
"TODO: Add details."
|
||||
},
|
||||
{
|
||||
command_container_trim,
|
||||
{{"container", "trim", NULL}, NULL},
|
||||
NULL,
|
||||
{{"container", "TODO: Add description.", true}, NULL},
|
||||
"TODO: Add description.",
|
||||
"TODO: Add details."
|
||||
},
|
||||
{
|
||||
command_container_info,
|
||||
{{"container", "info", NULL}, NULL},
|
||||
NULL,
|
||||
{{"container", "TODO: Add description.", true}, NULL},
|
||||
"TODO: Add description.",
|
||||
"TODO: Add details."
|
||||
},
|
||||
{
|
||||
command_container_list,
|
||||
{{"container", "ls", NULL}, {"container", "list", NULL}, NULL},
|
||||
NULL,
|
||||
NULL,
|
||||
"TODO: Add description.",
|
||||
"TODO: Add details."
|
||||
},
|
||||
{
|
||||
command_container_wipe,
|
||||
{{"container", "wipe", NULL}, NULL},
|
||||
NULL,
|
||||
NULL,
|
||||
"TODO: Add description.",
|
||||
"TODO: Add details."
|
||||
},
|
||||
{
|
||||
command_container_start,
|
||||
{{"container", "start", NULL}, NULL},
|
||||
{
|
||||
{
|
||||
{"-p", "--no-pci", NULL},
|
||||
NULL,
|
||||
"TODO: Add description."
|
||||
},
|
||||
{
|
||||
{"-v", "--vnc", NULL},
|
||||
{
|
||||
{"port", "TODO: Add description.", true},
|
||||
{"password", "TODO: Add description.", true},
|
||||
NULL
|
||||
},
|
||||
"TODO: Add description."
|
||||
},
|
||||
{
|
||||
{"-i", "--iso", NULL},
|
||||
{
|
||||
{"iso", "TODO: Add description.", true},
|
||||
NULL
|
||||
},
|
||||
"TODO: Add description."
|
||||
},
|
||||
NULL
|
||||
},
|
||||
{{"container", "TODO: Add description.", true}, NULL},
|
||||
"TODO: Add description.",
|
||||
"TODO: Add details."
|
||||
},
|
||||
{
|
||||
command_container_stop,
|
||||
{{"container", "stop", NULL}, NULL},
|
||||
{
|
||||
{
|
||||
{"-f", "--force", NULL},
|
||||
NULL,
|
||||
"TODO: Add description."
|
||||
},
|
||||
{
|
||||
{"-t", "--timeout", NULL},
|
||||
{
|
||||
{"timeout", "TODO: Add description.", true},
|
||||
NULL
|
||||
},
|
||||
"TODO: Add description."
|
||||
},
|
||||
NULL
|
||||
},
|
||||
{{"container", "TODO: Add description.", true}, NULL},
|
||||
"TODO: Add description.",
|
||||
"TODO: Add details."
|
||||
},
|
||||
{
|
||||
command_container_ps,
|
||||
{{"container", "ps", NULL}, NULL},
|
||||
NULL,
|
||||
NULL,
|
||||
"TODO: Add description.",
|
||||
"TODO: Add details."
|
||||
},
|
||||
{
|
||||
command_image_sync,
|
||||
{{"image", "sync", NULL}, NULL},
|
||||
NULL,
|
||||
NULL,
|
||||
"TODO: Add description.",
|
||||
"TODO: Add details."
|
||||
},
|
||||
{
|
||||
command_image_add,
|
||||
{{"image", "add", NULL}, NULL},
|
||||
NULL,
|
||||
{
|
||||
{"container", "The name of the container to add.", true},
|
||||
NULL
|
||||
},
|
||||
"TODO: Add details.",
|
||||
"TODO: Add details."
|
||||
},
|
||||
{
|
||||
command_image_import,
|
||||
{{"image", "import", NULL}, NULL},
|
||||
NULL,
|
||||
{
|
||||
{"file", "TODO: Add description.", true},
|
||||
NULL
|
||||
},
|
||||
"TODO: Add description.",
|
||||
"TODO: Add details."
|
||||
},
|
||||
{
|
||||
command_image_remove,
|
||||
{{"image", "rm", NULL}, {"image", "remove", NULL}, NULL},
|
||||
NULL,
|
||||
{{"image", "TODO: Add description.", true}, NULL},
|
||||
"TODO: Add description.",
|
||||
"TODO: Add details."
|
||||
},
|
||||
{
|
||||
command_image_default,
|
||||
{{"image", "default", NULL}, NULL},
|
||||
NULL,
|
||||
{{"image", "TODO: Add description.", false}, NULL},
|
||||
"TODO: Add description.",
|
||||
"TODO: Add details."
|
||||
},
|
||||
{
|
||||
command_image_list,
|
||||
{{"image", "ls", NULL}, {"image", "list", NULL}, NULL},
|
||||
NULL,
|
||||
NULL,
|
||||
"TODO: Add description.",
|
||||
"TODO: Add details."
|
||||
}
|
||||
};
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
// Ensure the sandbox user exists
|
||||
struct passwd* pw = getpwnam(SANDBOX_USER);
|
||||
if (pw == NULL) {
|
||||
Log(LOG_LEVEL_ERROR, "User '%s' does not exist. Please check that the program is installed correctly.", SANDBOX_USER);
|
||||
fprintf(stderr, "User '%s' does not exist. Please check that the program is installed correctly.\n", SANDBOX_USER);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Check that the program is either run as root or as the sandbox user
|
||||
if (geteuid() != 0 && geteuid() != pw->pw_uid) {
|
||||
Log(LOG_LEVEL_ERROR, "This program must be run as root or as the user '%s'.", SANDBOX_USER);
|
||||
fprintf(stderr, "This program must be run as root or as the user '%s'.\n", SANDBOX_USER);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// If the program is run as root, switch to the sandbox user
|
||||
if (geteuid() == 0) {
|
||||
if (setregid(pw->pw_gid, pw->pw_gid) != 0) {
|
||||
Log(LOG_LEVEL_ERROR, "Failed to switch to the group '%s'.", pw->pw_name);
|
||||
fprintf(stderr, "Failed to switch to the group '%s'.\n", pw->pw_name);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (setreuid(pw->pw_uid, pw->pw_uid) != 0) {
|
||||
Log(LOG_LEVEL_ERROR, "Failed to switch to the user '%s'.", pw->pw_name);
|
||||
fprintf(stderr, "Failed to switch to the user '%s'.\n", pw->pw_name);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Parse commands from the command line
|
||||
}
|
||||
|
||||
int command_help(int argc, char** argv) { return EXIT_SUCCESS; }
|
||||
int command_version(int argc, char** argv) { return EXIT_SUCCESS; }
|
||||
int command_config(int argc, char** argv) { return EXIT_SUCCESS; }
|
||||
int command_container_add(int argc, char** argv) { return EXIT_SUCCESS; }
|
||||
int command_container_remove(int argc, char** argv) { return EXIT_SUCCESS; }
|
||||
int command_container_reset(int argc, char** argv) { return EXIT_SUCCESS; }
|
||||
int command_container_trim(int argc, char** argv) { return EXIT_SUCCESS; }
|
||||
int command_container_info(int argc, char** argv) { return EXIT_SUCCESS; }
|
||||
int command_container_list(int argc, char** argv) { return EXIT_SUCCESS; }
|
||||
int command_container_wipe(int argc, char** argv) { return EXIT_SUCCESS; }
|
||||
int command_container_start(int argc, char** argv) { return EXIT_SUCCESS; }
|
||||
int command_container_stop(int argc, char** argv) { return EXIT_SUCCESS; }
|
||||
int command_container_ps(int argc, char** argv) { return EXIT_SUCCESS; }
|
||||
int command_image_sync(int argc, char** argv) { return EXIT_SUCCESS; }
|
||||
int command_image_add(int argc, char** argv) { return EXIT_SUCCESS; }
|
||||
int command_image_import(int argc, char** argv) { return EXIT_SUCCESS; }
|
||||
int command_image_remove(int argc, char** argv) { return EXIT_SUCCESS; }
|
||||
int command_image_default(int argc, char** argv) { return EXIT_SUCCESS; }
|
||||
int command_image_list(int argc, char** argv) { return EXIT_SUCCESS; }
|
||||
|
23
src/sandbox.h
Normal file → Executable file
23
src/sandbox.h
Normal file → Executable file
@ -2,28 +2,7 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#define SANDBOX_VERSION "0.1.2"
|
||||
#define SANDBOX_VERSION "0.1.4"
|
||||
#define SANDBOX_USER "sandbox"
|
||||
|
||||
typedef struct {
|
||||
const char* name;
|
||||
const char* description;
|
||||
const bool required;
|
||||
} Argument;
|
||||
|
||||
typedef struct {
|
||||
const char** aliases;
|
||||
const Argument* arguments;
|
||||
const char* description;
|
||||
} Option;
|
||||
|
||||
typedef struct {
|
||||
int (*handler)(int argc, char* argv[]);
|
||||
const char*** aliases;
|
||||
const Option* options;
|
||||
const Argument* arguments;
|
||||
const char* description;
|
||||
const char* details;
|
||||
} Command;
|
||||
|
||||
int main(int argc, char** argv);
|
||||
|
353
src/template.c
353
src/template.c
@ -1,353 +0,0 @@
|
||||
#include "template.h"
|
||||
|
||||
#include "image.h"
|
||||
#include "disk.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#include <libgen.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
Result IsTemplateIdentifierValid(const char* template_id, bool* _valid) {
|
||||
*_valid = false;
|
||||
|
||||
// Check that the template identifier is not NULL
|
||||
if (template_id == NULL)
|
||||
return SUCCESS;
|
||||
|
||||
// Check that the template identifier is not empty or too long
|
||||
size_t length = strlen(template_id);
|
||||
if (length == 0 || length > MAX_TEMPLATE_ID_LENGTH)
|
||||
return SUCCESS;
|
||||
|
||||
// Check that the template identifier only contains allowed characters
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
char c = template_id[i];
|
||||
if (c >= 'a' && c <= 'z')
|
||||
continue;
|
||||
if (c >= 'A' && c <= 'Z')
|
||||
continue;
|
||||
if (c >= '0' && c <= '9')
|
||||
continue;
|
||||
if (c == '_' || c == '-' || c == '.' || c == ' ')
|
||||
continue;
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
// Check that the template identifier is not a reserved name
|
||||
if (strcmp(template_id, ".") == 0 || strcmp(template_id, "..") == 0)
|
||||
return SUCCESS;
|
||||
|
||||
// Check that the template identifier starts with a number (the order)
|
||||
if (template_id[0] < '0' || template_id[0] > '9')
|
||||
return SUCCESS;
|
||||
|
||||
*_valid = true;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
Result GetTemplateIdentifierOrder(const char* template_id, uint64_t* _order) {
|
||||
// Check that the template identifier is valid
|
||||
bool valid;
|
||||
if (IsTemplateIdentifierValid(template_id, &valid) != SUCCESS || !valid)
|
||||
return FAILURE;
|
||||
|
||||
// Get the order from the template identifier
|
||||
*_order = strtoull(template_id, NULL, 10);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
Result GetTemplateIdentifierDescription(const char* template_id, char** _description) {
|
||||
// Check that the template identifier is valid
|
||||
bool valid;
|
||||
if (IsTemplateIdentifierValid(template_id, &valid) != SUCCESS || !valid)
|
||||
return FAILURE;
|
||||
|
||||
// Get the length of the order
|
||||
size_t length = 0;
|
||||
while (template_id[length] >= '0' && template_id[length] <= '9')
|
||||
length++;
|
||||
|
||||
// Get the substring after the order
|
||||
return Substring(template_id, length, strlen(template_id), _description);
|
||||
}
|
||||
|
||||
Result CreateTemplateIdentifier(uint64_t order, const char* template_description, char** _template_id) {
|
||||
// Check that the description does not start with a number
|
||||
if (template_description[0] >= '0' && template_description[0] <= '9')
|
||||
return FAILURE;
|
||||
|
||||
// Format the template identifier
|
||||
if (Format(_template_id, "%llu%s", order, template_description) != SUCCESS)
|
||||
return FAILURE;
|
||||
|
||||
// Check that the template identifier is valid
|
||||
bool valid;
|
||||
return IsTemplateIdentifierValid(*_template_id, &valid) == SUCCESS && valid ? SUCCESS : FAILURE;
|
||||
}
|
||||
|
||||
Result GetTemplatePoolPath(char** _path) {
|
||||
return Format(_path, "/var/lib/sandbox/templates");
|
||||
}
|
||||
|
||||
Result GetTemplateDiskPath(const char* template_id, char** _path) {
|
||||
// Check that the template identifier is valid
|
||||
bool valid;
|
||||
if (IsTemplateIdentifierValid(template_id, &valid) != SUCCESS || !valid)
|
||||
return FAILURE;
|
||||
|
||||
// Get the path to the template pool
|
||||
char* pool_path;
|
||||
if (GetTemplatePoolPath(&pool_path) != SUCCESS)
|
||||
return FAILURE;
|
||||
|
||||
// Format the template disk path
|
||||
Result result = Format(_path, "%s/%s", pool_path, template_id);
|
||||
|
||||
free(pool_path);
|
||||
return result;
|
||||
}
|
||||
|
||||
Result DoesTemplateExist(const char* template_id, bool* _exists) {
|
||||
// Get the path to the template disk
|
||||
char* disk_path;
|
||||
if (GetTemplateDiskPath(template_id, &disk_path) != SUCCESS)
|
||||
return FAILURE;
|
||||
|
||||
// Check if the template disk exists
|
||||
struct stat st;
|
||||
*_exists = stat(disk_path, &st) == 0 && S_ISDIR(st.st_mode);
|
||||
|
||||
free(disk_path);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
Result AddTemplate(const char* template_id, const char* image_id) {
|
||||
// Check that the template does not already exist
|
||||
bool exists;
|
||||
if (DoesTemplateExist(template_id, &exists) != SUCCESS)
|
||||
return FAILURE;
|
||||
|
||||
if (exists) {
|
||||
Log(LOG_LEVEL_ERROR, "Template '%s' already exists.", template_id);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
// Check that the image exists
|
||||
bool image_exists;
|
||||
if (DoesImageDiskExist(image_id, &image_exists) != SUCCESS)
|
||||
return FAILURE;
|
||||
|
||||
if (!image_exists) {
|
||||
Log(LOG_LEVEL_ERROR, "Image '%s' does not exist.", image_id);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
// Check that the image has a disk
|
||||
bool image_has_disk;
|
||||
if (DoesImageDiskExist(image_id, &image_has_disk) != SUCCESS)
|
||||
return FAILURE;
|
||||
|
||||
if (!image_has_disk) {
|
||||
Log(LOG_LEVEL_ERROR, "Image '%s' does not have a disk.", image_id);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
// Get the path of the image disk
|
||||
char* image_disk_path;
|
||||
if (GetImageDiskPath(image_id, &image_disk_path) != SUCCESS)
|
||||
return FAILURE;
|
||||
|
||||
// Get information about the image disk
|
||||
DiskInfo image_disk_info;
|
||||
if (GetDiskInfo(image_disk_path, &image_disk_info) != SUCCESS) {
|
||||
free(image_disk_path);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
// If the image disk has a backing, check that the backing is an existing template
|
||||
if (image_disk_info.backing_identifier != NULL) {
|
||||
bool backing_exists;
|
||||
if (DoesTemplateExist(image_disk_info.backing_identifier, &backing_exists) != SUCCESS) {
|
||||
free(image_disk_path);
|
||||
FreeDiskInfo(&image_disk_info);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
if (!backing_exists) {
|
||||
Log(LOG_LEVEL_ERROR, "Backing template '%s' of image '%s' does not exist.", image_disk_info.backing_identifier, image_id);
|
||||
free(image_disk_path);
|
||||
FreeDiskInfo(&image_disk_info);
|
||||
return FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the path to the template disk
|
||||
char* template_disk_path;
|
||||
if (GetTemplateDiskPath(template_id, &template_disk_path) != SUCCESS) {
|
||||
free(image_disk_path);
|
||||
FreeDiskInfo(&image_disk_info);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
// Copy the image disk to the template disk
|
||||
Result result = CopyFile(image_disk_path, template_disk_path);
|
||||
|
||||
free(image_disk_path);
|
||||
|
||||
if (result != SUCCESS) {
|
||||
free(template_disk_path);
|
||||
FreeDiskInfo(&image_disk_info);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
// If the image disk has a backing, reback the template disk to be relative
|
||||
if (image_disk_info.backing_identifier != NULL)
|
||||
if (RebackDisk(template_disk_path, image_disk_info.backing_identifier) != SUCCESS) {
|
||||
unlink(template_disk_path);
|
||||
free(template_disk_path);
|
||||
FreeDiskInfo(&image_disk_info);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
// Free the template disk path and image disk info
|
||||
free(template_disk_path);
|
||||
FreeDiskInfo(&image_disk_info);
|
||||
|
||||
// Return success
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
Result RemoveTemplate(const char* template_id) {
|
||||
// Check that the template exists
|
||||
bool exists;
|
||||
if (DoesTemplateExist(template_id, &exists) != SUCCESS)
|
||||
return FAILURE;
|
||||
|
||||
if (!exists) {
|
||||
Log(LOG_LEVEL_ERROR, "Template '%s' does not exist.", template_id);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
// Get the path to the template disk
|
||||
char* disk_path;
|
||||
if (GetTemplateDiskPath(template_id, &disk_path) != SUCCESS)
|
||||
return FAILURE;
|
||||
|
||||
// Remove the template disk
|
||||
int result = rmdir(disk_path);
|
||||
|
||||
// TODO: Remove any template that is based on this template
|
||||
|
||||
free(disk_path);
|
||||
return result == 0 ? SUCCESS : FAILURE;
|
||||
}
|
||||
|
||||
Result ListTemplates(char*** _template_ids) {
|
||||
// Get the path to the template pool
|
||||
char* pool_path;
|
||||
if (GetTemplatePoolPath(&pool_path) != SUCCESS)
|
||||
return FAILURE;
|
||||
|
||||
// Open the template pool directory
|
||||
DIR* pool_dir = opendir(pool_path);
|
||||
if (pool_dir == NULL) {
|
||||
Log(LOG_LEVEL_ERROR, "Failed to open template pool directory '%s' (%s).", pool_path, strerror(errno));
|
||||
free(pool_path);
|
||||
return FAILURE;
|
||||
}
|
||||
free(pool_path);
|
||||
|
||||
// Allocate an initial array, one element is reserved for the NULL terminator
|
||||
*_template_ids = malloc(sizeof(char*));
|
||||
if (*_template_ids == NULL) {
|
||||
Log(LOG_LEVEL_ERROR, "Failed to allocate memory for template identifiers.");
|
||||
closedir(pool_dir);
|
||||
return FAILURE;
|
||||
}
|
||||
(*_template_ids)[0] = NULL;
|
||||
|
||||
// Iterate over the template pool directory
|
||||
int count = 0;
|
||||
struct dirent* entry;
|
||||
while ((entry = readdir(pool_dir)) != NULL) {
|
||||
// Skip the current and parent directory
|
||||
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
|
||||
continue;
|
||||
|
||||
// Check that the entry actually exists
|
||||
bool exists;
|
||||
if (DoesTemplateExist(entry->d_name, &exists) != SUCCESS || !exists)
|
||||
continue;
|
||||
|
||||
// Allocate a new element in the array
|
||||
char** new_template_ids = realloc(*_template_ids, (count + 2) * sizeof(char*)); // One element is reserved for the NULL terminator
|
||||
if (new_template_ids == NULL) {
|
||||
Log(LOG_LEVEL_ERROR, "Failed to allocate memory for template identifiers.");
|
||||
closedir(pool_dir);
|
||||
for (int i = 0; i < count; i++)
|
||||
free((*_template_ids)[i]);
|
||||
free(*_template_ids);
|
||||
return FAILURE;
|
||||
}
|
||||
*_template_ids = new_template_ids;
|
||||
|
||||
// Copy the entry name into the array
|
||||
if (Duplicate(entry->d_name, &(*_template_ids)[count]) != SUCCESS) {
|
||||
Log(LOG_LEVEL_ERROR, "Failed to allocate memory for template identifier.");
|
||||
closedir(pool_dir);
|
||||
for (int i = 0; i < count; i++)
|
||||
free((*_template_ids)[i]);
|
||||
free(*_template_ids);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
// Null-terminate the array
|
||||
(*_template_ids)[count + 1] = NULL;
|
||||
|
||||
// Increment the count
|
||||
count++;
|
||||
}
|
||||
|
||||
// Close the template pool directory
|
||||
closedir(pool_dir);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
Result GetHighestOrderTemplate(char** _template_id) {
|
||||
*_template_id = NULL;
|
||||
|
||||
// Get the list of template identifiers
|
||||
char** template_ids;
|
||||
if (ListTemplates(&template_ids) != SUCCESS)
|
||||
return FAILURE;
|
||||
|
||||
// Find the highest order template identifier
|
||||
uint64_t highest_order = -1;
|
||||
char* highest_template_id = NULL;
|
||||
|
||||
for (int i = 0; template_ids[i] != NULL; i++) {
|
||||
uint64_t order;
|
||||
if (GetTemplateIdentifierOrder(template_ids[i], &order) != SUCCESS)
|
||||
continue;
|
||||
|
||||
if (order > highest_order) {
|
||||
highest_order = order;
|
||||
highest_template_id = template_ids[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Duplicate the highest order template identifier
|
||||
if (Duplicate(highest_template_id, _template_id) != SUCCESS)
|
||||
return FAILURE;
|
||||
|
||||
for (int i = 0; template_ids[i] != NULL; i++)
|
||||
free(template_ids[i]);
|
||||
free(template_ids);
|
||||
return SUCCESS;
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
#define MAX_TEMPLATE_ID_LENGTH 64
|
||||
|
||||
Result IsTemplateIdentifierValid(const char* template_id, bool* _valid);
|
||||
Result GetTemplateIdentifierOrder(const char* template_id, uint64_t* _order);
|
||||
Result GetTemplateIdentifierDescription(const char* template_id, char** _description);
|
||||
Result CreateTemplateIdentifier(uint64_t order, const char* template_description, char** _template_id);
|
||||
|
||||
Result GetTemplatePoolPath(char** _path);
|
||||
Result GetTemplateDiskPath(const char* template_id, char** _path);
|
||||
Result DoesTemplateExist(const char* template_id, bool* _exists);
|
||||
|
||||
Result AddTemplate(const char* template_id, const char* image_id);
|
||||
Result RemoveTemplate(const char* template_id);
|
||||
Result ListTemplates(char*** _template_ids);
|
||||
Result GetHighestOrderTemplate(char** _template_id);
|
618
src/utils.c
Normal file → Executable file
618
src/utils.c
Normal file → Executable file
File diff suppressed because it is too large
Load Diff
42
src/utils.h
Normal file → Executable file
42
src/utils.h
Normal file → Executable file
@ -1,38 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef enum {
|
||||
SUCCESS,
|
||||
FAILURE
|
||||
} Result;
|
||||
#define ERROR_BUFFER_SIZE 4096
|
||||
|
||||
typedef enum {
|
||||
LOG_LEVEL_DEBUG,
|
||||
LOG_LEVEL_INFO,
|
||||
LOG_LEVEL_WARNING,
|
||||
LOG_LEVEL_ERROR,
|
||||
} LogLevel;
|
||||
extern char _error_buffer[];
|
||||
|
||||
extern LogLevel LOG_LEVEL;
|
||||
typedef int result_t;
|
||||
|
||||
void SetLogLevel(LogLevel level);
|
||||
void Log(LogLevel level, const char* format, ...);
|
||||
result_t success(void);
|
||||
result_t failure(const char* format, ...);
|
||||
const char* error(void);
|
||||
|
||||
Result Format(char** _string, const char* fmt, ...);
|
||||
Result Duplicate(const char* string, char** _duplicate);
|
||||
Result Substring(const char* string, size_t start, size_t end, char** _substring);
|
||||
result_t format(char** _str, const char* format, ...);
|
||||
result_t substring(char** _str, const char* str, size_t start, size_t length);
|
||||
|
||||
Result FormatSize(uint64_t size, char** _size_str);
|
||||
Result ParseSize(const char* size_str, uint64_t* _size);
|
||||
result_t format_size(char** _str, uint64_t size);
|
||||
result_t parse_size(uint64_t* _size, const char* str);
|
||||
|
||||
Result RunExecutable(int* _exit_code, char** _stdout, char** _stderr, const char* executable, ...);
|
||||
result_t execute(int* _exit_code, char** _stdoutbuf, char** _stderrbuf, const char* executable, ...);
|
||||
|
||||
Result ReadFileDescriptor(int fd, char** _content);
|
||||
Result WriteFileDescriptor(int fd, const char* content);
|
||||
Result ReadFile(const char* path, char** _content);
|
||||
Result WriteFile(const char* path, const char* content);
|
||||
result_t read_fd(char** _str, int fd);
|
||||
result_t write_fd(int fd, const char* str);
|
||||
result_t read_file(char** _str, const char* path);
|
||||
result_t write_file(const char* path, const char* str);
|
||||
|
||||
Result CopyFile(const char* source_path, const char* destination_path);
|
||||
result_t list_files(char*** _files, const char* path, bool (*filter)(const char*));
|
||||
|
Loading…
Reference in New Issue
Block a user