Made some small adjustments

This commit is contained in:
Alexei KADIR 2024-02-19 16:01:53 +01:00
parent 1896e41b8a
commit 5cf1b33178
17 changed files with 1055 additions and 1637 deletions

14
.clang-format Executable file
View 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
View File

4
Makefile Normal file → Executable file
View File

@ -1,7 +1,7 @@
# ---- ---- # # ---- ---- #
CC = clang CC = gcc
CF = -Wall -lkrb5 -lvirt -ljson-c -g CF = -Wall -lkrb5 -lvirt -ljson-c -lcrypto -g
# ---- ---- # # ---- ---- #

221
src/backing.c Executable file
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

19
src/disk.h Normal file → Executable file
View File

@ -5,14 +5,15 @@
typedef struct { typedef struct {
uint64_t size; uint64_t size;
uint64_t allocated; uint64_t allocated;
char* backing_file_path; char* backing_path;
char* backing_identifier; } disk_info_t;
} DiskInfo;
Result CreateRootDisk(const char* disk_path, uint64_t size); result_t create_root_disk(const char* path, uint64_t size);
Result CreateBackedDisk(const char* disk_path, const char* backing_disk_path); result_t create_backed_disk(const char* path, const char* backing_path);
Result TrimDisk(const char* disk_path);
Result RebackDisk(const char* disk_path, const char* backing_disk_path);
Result GetDiskInfo(const char* disk_path, DiskInfo* _info); result_t trim_disk(const char* path);
Result FreeDiskInfo(DiskInfo* info); 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);

View File

@ -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;
}

View File

@ -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
View File

@ -2,268 +2,37 @@
#include "utils.h" #include "utils.h"
#include <stdio.h>
#include <stdbool.h> #include <stdbool.h>
#include <pwd.h> #include <pwd.h>
#include <unistd.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) { int main(int argc, char** argv) {
// Ensure the sandbox user exists // Ensure the sandbox user exists
struct passwd* pw = getpwnam(SANDBOX_USER); struct passwd* pw = getpwnam(SANDBOX_USER);
if (pw == NULL) { 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; return EXIT_FAILURE;
} }
// Check that the program is either run as root or as the sandbox user // Check that the program is either run as root or as the sandbox user
if (geteuid() != 0 && geteuid() != pw->pw_uid) { 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; return EXIT_FAILURE;
} }
// If the program is run as root, switch to the sandbox user // If the program is run as root, switch to the sandbox user
if (geteuid() == 0) { if (geteuid() == 0) {
if (setregid(pw->pw_gid, pw->pw_gid) != 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; return EXIT_FAILURE;
} }
if (setreuid(pw->pw_uid, pw->pw_uid) != 0) { 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; return EXIT_FAILURE;
} }
} }
// TODO: Parse commands from the command line // 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
View File

@ -2,28 +2,7 @@
#include <stdbool.h> #include <stdbool.h>
#define SANDBOX_VERSION "0.1.2" #define SANDBOX_VERSION "0.1.4"
#define SANDBOX_USER "sandbox" #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); int main(int argc, char** argv);

View File

@ -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;
}

View File

@ -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

File diff suppressed because it is too large Load Diff

42
src/utils.h Normal file → Executable file
View File

@ -1,38 +1,30 @@
#pragma once #pragma once
#include <stdlib.h>
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdlib.h>
typedef enum { #define ERROR_BUFFER_SIZE 4096
SUCCESS,
FAILURE
} Result;
typedef enum { extern char _error_buffer[];
LOG_LEVEL_DEBUG,
LOG_LEVEL_INFO,
LOG_LEVEL_WARNING,
LOG_LEVEL_ERROR,
} LogLevel;
extern LogLevel LOG_LEVEL; typedef int result_t;
void SetLogLevel(LogLevel level); result_t success(void);
void Log(LogLevel level, const char* format, ...); result_t failure(const char* format, ...);
const char* error(void);
Result Format(char** _string, const char* fmt, ...); result_t format(char** _str, const char* format, ...);
Result Duplicate(const char* string, char** _duplicate); result_t substring(char** _str, const char* str, size_t start, size_t length);
Result Substring(const char* string, size_t start, size_t end, char** _substring);
Result FormatSize(uint64_t size, char** _size_str); result_t format_size(char** _str, uint64_t size);
Result ParseSize(const char* size_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_t read_fd(char** _str, int fd);
Result WriteFileDescriptor(int fd, const char* content); result_t write_fd(int fd, const char* str);
Result ReadFile(const char* path, char** _content); result_t read_file(char** _str, const char* path);
Result WriteFile(const char* path, const char* content); 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*));