2024-02-19 16:01:53 +01:00
|
|
|
#include "container.h"
|
|
|
|
|
|
|
|
#include "disk.h"
|
|
|
|
#include "backing.h"
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
2024-02-19 20:23:26 +01:00
|
|
|
#include <libgen.h>
|
2024-02-19 16:01:53 +01:00
|
|
|
#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) {
|
2024-02-19 18:18:18 +01:00
|
|
|
// Initialize the output parameters
|
|
|
|
*_path = NULL;
|
|
|
|
|
2024-02-19 16:01:53 +01:00
|
|
|
return format(_path, "/var/lib/sandbox/containers");
|
|
|
|
}
|
|
|
|
|
|
|
|
result_t get_container_path(char** _path, const char* container) {
|
2024-02-19 18:18:18 +01:00
|
|
|
// Initialize the output parameters
|
|
|
|
*_path = NULL;
|
|
|
|
|
2024-02-19 16:01:53 +01:00
|
|
|
// 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;
|
|
|
|
|
2024-02-19 20:03:30 +01:00
|
|
|
// Check that the backing exists
|
|
|
|
result = check_backing_exists(backing);
|
|
|
|
if (result != success()) {
|
|
|
|
free(path);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2024-02-19 16:01:53 +01:00
|
|
|
// 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) {
|
2024-02-19 18:18:18 +01:00
|
|
|
// Initialize the output parameters
|
|
|
|
*_containers = NULL;
|
|
|
|
|
2024-02-19 16:01:53 +01:00
|
|
|
// 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;
|
2024-02-19 20:23:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
result_t get_container_backing(char** _backing, const char* container) {
|
|
|
|
// Initialize the output parameters
|
|
|
|
*_backing = NULL;
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
|
|
|
|
// Get the disk information
|
|
|
|
disk_info_t info;
|
|
|
|
result = get_disk_info(&info, path);
|
|
|
|
if (result != success()) {
|
|
|
|
free(path);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Free the container path as it is no longer needed
|
|
|
|
free(path);
|
|
|
|
|
|
|
|
// Check if the disk is backed
|
|
|
|
if (info.backing_path == NULL) {
|
|
|
|
free_disk_info(&info);
|
|
|
|
success();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the backing identifier
|
|
|
|
char* backing = strdup(basename(info.backing_path));
|
|
|
|
|
|
|
|
// Free the disk information as it is no longer needed
|
|
|
|
free_disk_info(&info);
|
|
|
|
|
|
|
|
if (backing == NULL)
|
|
|
|
return failure("Failed to get backing identifier for container '%s'.", container);
|
|
|
|
|
|
|
|
*_backing = backing;
|
|
|
|
return success();
|
|
|
|
}
|