Implemented creation of root disks

This commit is contained in:
Alexei KADIR 2024-02-17 12:34:24 +01:00
parent 188e57dc31
commit 694092e12e
5 changed files with 328 additions and 30 deletions

View File

@ -7,6 +7,7 @@
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
#include <unistd.h> #include <unistd.h>
#include <libgen.h>
#include <sys/stat.h> #include <sys/stat.h>
bool is_entry_id_valid(const char* entry_id) { bool is_entry_id_valid(const char* entry_id) {
@ -43,6 +44,42 @@ Result get_entry_path(const char* entry_id, char** out_path) {
return format(out_path, "%s/%s", ENTRY_POOL_DIR, entry_id); return format(out_path, "%s/%s", ENTRY_POOL_DIR, entry_id);
} }
Result get_entry_disk_path(const char* entry_id, char** out_path) {
*out_path = NULL;
// Get the path of the entry
char* entry_path;
Result result = get_entry_path(entry_id, &entry_path);
if (result != SUCCESS)
return result;
// Get the path of the disk
result = format(out_path, "%s/disk", entry_path);
// Free the entry path
free(entry_path);
return result;
}
Result get_entry_type_path(const char* entry_id, char** out_path) {
*out_path = NULL;
// Get the path of the entry
char* entry_path;
Result result = get_entry_path(entry_id, &entry_path);
if (result != SUCCESS)
return result;
// Get the path of the type file
result = format(out_path, "%s/type", entry_path);
// Free the entry path
free(entry_path);
return result;
}
Result entry_exists(const char* entry_id, bool* out_exists) { Result entry_exists(const char* entry_id, bool* out_exists) {
*out_exists = false; *out_exists = false;
@ -64,3 +101,195 @@ Result entry_exists(const char* entry_id, bool* out_exists) {
return SUCCESS; return SUCCESS;
} }
Result add_entry(const char* entry_id, EntryType type) {
// Check that it does not exist
bool exists;
Result result = entry_exists(entry_id, &exists);
if (result != SUCCESS)
return result;
if (exists) {
log_message(LOG_LEVEL_ERROR, "The entry '%s' already exists.", entry_id);
return FAILURE;
}
// Get the path of the entry
char* entry_path;
result = get_entry_path(entry_id, &entry_path);
if (result != SUCCESS)
return result;
// Create the directory
if (mkdir(entry_path, 0755) == -1) {
log_message(LOG_LEVEL_ERROR, "Failed to create the directory '%s' (%s).", entry_path, strerror(errno));
free(entry_path);
return FAILURE;
}
// Free the entry path
free(entry_path);
// Get the path of the type file
char* type_path;
result = get_entry_type_path(entry_id, &type_path);
if (result != SUCCESS) {
remove_entry(entry_id);
return result;
}
// Write the type file
const char* type_string;
switch (type) {
case ENTRY_TYPE_ROOT:
type_string = ENTRY_TYPE_ROOT_STRING;
break;
case ENTRY_TYPE_BACKED:
type_string = ENTRY_TYPE_BACKED_STRING;
break;
case ENTRY_TYPE_AUTOMATIC:
type_string = ENTRY_TYPE_AUTOMATIC_STRING;
break;
default:
log_message(LOG_LEVEL_ERROR, "Invalid entry type.");
remove_entry(entry_id);
return FAILURE;
}
result = write_file(type_path, type_string);
// Free the type path
free(type_path);
if (result != SUCCESS) {
remove_entry(entry_id);
return result;
}
return SUCCESS;
}
Result add_root_entry(const char* entry_id, uint64_t size) {
// Add the entry
Result result = add_entry(entry_id, ENTRY_TYPE_ROOT);
if (result != SUCCESS)
return result;
// Get the path of the disk
char* disk_path;
result = get_entry_disk_path(entry_id, &disk_path);
if (result != SUCCESS) {
remove_entry(entry_id);
return result;
}
// Create the disk
result = create_root_disk(disk_path, size, 0644);
// Free the disk path
free(disk_path);
if (result != SUCCESS) {
remove_entry(entry_id);
return result;
}
return SUCCESS;
}
Result remove_entry(const char* entry_id) {
// Check that it exists
bool exists;
Result result = entry_exists(entry_id, &exists);
if (result != SUCCESS)
return result;
if (!exists) {
log_message(LOG_LEVEL_ERROR, "The entry '%s' does not exist.", entry_id);
return FAILURE;
}
// Get the path of the entry
char* entry_path;
result = get_entry_path(entry_id, &entry_path);
if (result != SUCCESS)
return result;
// Remove the directory
if (rmdir(entry_path) == -1) {
log_message(LOG_LEVEL_ERROR, "Failed to remove the directory '%s' (%s).", entry_path, strerror(errno));
free(entry_path);
return FAILURE;
}
// Free the entry path
free(entry_path);
return SUCCESS;
}
Result get_entry_info(const char* entry_id, EntryInfo* out_info) {
out_info->backing_id = NULL;
out_info->type = ENTRY_TYPE_UNKNOWN;
// Get the path of the type file
char* type_path;
Result result = get_entry_type_path(entry_id, &type_path);
if (result != SUCCESS)
return result;
// Read the type file
char* type;
result = read_file(type_path, &type);
if (result != SUCCESS) {
free(type_path);
return result;
}
// Free the type path
free(type_path);
// Check the type
if (strcmp(type, ENTRY_TYPE_ROOT_STRING) == 0)
out_info->type = ENTRY_TYPE_ROOT;
else if (strcmp(type, ENTRY_TYPE_BACKED_STRING) == 0)
out_info->type = ENTRY_TYPE_BACKED;
else if (strcmp(type, ENTRY_TYPE_AUTOMATIC_STRING) == 0)
out_info->type = ENTRY_TYPE_AUTOMATIC;
// Free the type
free(type);
// Get the path of the entry disk
char* disk_path;
result = get_entry_disk_path(entry_id, &disk_path);
if (result != SUCCESS)
return result;
// Get the information about the disk
result = get_disk_info(disk_path, &out_info->disk_info);
// Free the disk path
free(disk_path);
if (result != SUCCESS)
return result;
// Check if the disk is backed
if (out_info->disk_info.backing_file != NULL) {
out_info->backing_id = strdup(basename(out_info->disk_info.backing_file));
if (out_info->backing_id == NULL) {
free_disk_info(&out_info->disk_info);
return OUT_OF_MEMORY;
}
}
return SUCCESS;
}
void free_entry_info(EntryInfo* info) {
free(info->backing_id);
free_disk_info(&info->disk_info);
}

View File

@ -10,11 +10,16 @@
#define MAX_ENTRY_LENGTH 256 #define MAX_ENTRY_LENGTH 256
typedef enum { typedef enum {
ENTRY_TYPE_UNKNOWN,
ENTRY_TYPE_ROOT, ENTRY_TYPE_ROOT,
ENTRY_TYPE_BACKED, ENTRY_TYPE_BACKED,
ENTRY_TYPE_AUTOMATIC ENTRY_TYPE_AUTOMATIC
} EntryType; } EntryType;
#define ENTRY_TYPE_ROOT_STRING "root"
#define ENTRY_TYPE_BACKED_STRING "backed"
#define ENTRY_TYPE_AUTOMATIC_STRING "automatic"
typedef struct { typedef struct {
EntryType type; EntryType type;
char* backing_id; char* backing_id;
@ -33,12 +38,30 @@ bool is_entry_id_valid(const char* entry_id);
/// @return The result of the operation. /// @return The result of the operation.
Result get_entry_path(const char* entry_id, char** out_path); Result get_entry_path(const char* entry_id, char** out_path);
/// @brief Gets the path of the disk of the given entry.
/// @param entry_id The entry id.
/// @param out_path The pointer to the output path string. The caller is responsible for freeing the memory.
/// @return The result of the operation.
Result get_entry_disk_path(const char* entry_id, char** out_path);
/// @brief Gets the path of the type file of the given entry.
/// @param entry_id The entry id.
/// @param out_path The pointer to the output path string. The caller is responsible for freeing the memory.
/// @return The result of the operation.
Result get_entry_type_path(const char* entry_id, char** out_path);
/// @brief Checks whether the given entry exists in the pool. /// @brief Checks whether the given entry exists in the pool.
/// @param entry_id The entry id. /// @param entry_id The entry id.
/// @param out_exists The pointer to the output boolean. /// @param out_exists The pointer to the output boolean.
/// @return The result of the operation. /// @return The result of the operation.
Result entry_exists(const char* entry_id, bool* out_exists); Result entry_exists(const char* entry_id, bool* out_exists);
/// @brief Adds an entry directory to the pool.
/// @param entry_id The entry id.
/// @param type The type of the entry.
/// @return The result of the operation.
Result add_entry(const char* entry_id, EntryType type);
/// @brief Adds a root entry to the pool. /// @brief Adds a root entry to the pool.
/// @param entry_id The entry id. /// @param entry_id The entry id.
/// @param size The size of the entry. /// @param size The size of the entry.

View File

@ -19,7 +19,7 @@ const Command COMMANDS[] = {
"Adds an entry to the entry pool with the given id. The entry can either be a root entry or a backed entry. If the entry is a root entry, the size of the entry must be specified. If the entry is a backed entry, the backing id must be specified. By default, the entry will be an automatic entry, which will be backed by the latest backing disk available and will automatically reset to its initial state when a new backing disk is added."}, "Adds an entry to the entry pool with the given id. The entry can either be a root entry or a backed entry. If the entry is a root entry, the size of the entry must be specified. If the entry is a backed entry, the backing id must be specified. By default, the entry will be an automatic entry, which will be backed by the latest backing disk available and will automatically reset to its initial state when a new backing disk is added."},
{command_remove_entry, "remove-entry", "<entry id>", "Removes an entry from the entry pool.", {command_remove_entry, "remove-entry", "<entry id>", "Removes an entry from the entry pool.",
"Removes the entry with the given id from the entry pool."}, "Removes the entry with the given id from the entry pool."},
{command_list_entries, "list-entries", "", "Lists the entries in the entry pool.", {command_list_entries, "entries", "", "Lists the entries in the entry pool.",
"Lists the entries in the entry pool, as well as their types and backing disks."}, "Lists the entries in the entry pool, as well as their types and backing disks."},
{command_clear_entries, "clear-entries", "", "Removes all the entries from the entry pool.", {command_clear_entries, "clear-entries", "", "Removes all the entries from the entry pool.",
"Removes all the entries from the entry pool."}, "Removes all the entries from the entry pool."},
@ -119,24 +119,12 @@ int command_version(int argc, char* argv[]) {
} }
int command_add_entry(int argc, char* argv[]) { int command_add_entry(int argc, char* argv[]) {
if (argc < 1) {
log_message(LOG_LEVEL_ERROR, "Missing entry id.");
return EXIT_FAILURE;
}
// TODO: Parse options
// TODO: Call add_root_entry or add_backed_entry depending on the options // TODO: Call add_root_entry or add_backed_entry depending on the options
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
int command_remove_entry(int argc, char* argv[]) { int command_remove_entry(int argc, char* argv[]) {
if (argc < 1) {
log_message(LOG_LEVEL_ERROR, "Missing entry id.");
return EXIT_FAILURE;
}
// TODO: Call remove_entry // TODO: Call remove_entry
return EXIT_SUCCESS; return EXIT_SUCCESS;
@ -157,33 +145,18 @@ int command_clear_entries(int argc, char* argv[]) {
} }
int command_reset_entry(int argc, char* argv[]) { int command_reset_entry(int argc, char* argv[]) {
if (argc < 1) {
log_message(LOG_LEVEL_ERROR, "Missing entry id.");
return EXIT_FAILURE;
}
// TODO: Call reset_entry // TODO: Call reset_entry
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
int command_update_entry(int argc, char* argv[]) { int command_update_entry(int argc, char* argv[]) {
if (argc < 1) {
log_message(LOG_LEVEL_ERROR, "Missing entry id.");
return EXIT_FAILURE;
}
// TODO: Call update_entry // TODO: Call update_entry
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
int command_add_backing(int argc, char* argv[]) { int command_add_backing(int argc, char* argv[]) {
if (argc < 1) {
log_message(LOG_LEVEL_ERROR, "Missing entry id.");
return EXIT_FAILURE;
}
// TODO: Call add_backing // TODO: Call add_backing
return EXIT_SUCCESS; return EXIT_SUCCESS;

View File

@ -7,6 +7,7 @@
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
#include <unistd.h> #include <unistd.h>
#include <fcntl.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/wait.h> #include <sys/wait.h>
@ -287,3 +288,57 @@ Result read_fd(int fd, char** out_string) {
return SUCCESS; return SUCCESS;
} }
Result read_file(const char* path, char** out_string) {
*out_string = NULL;
// Open the file
int fd = open(path, O_RDONLY);
if (fd == -1) {
log_message(LOG_LEVEL_ERROR, "Failed to open the file '%s' (%s).", path, strerror(errno));
return FAILURE;
}
// Read the file
Result result = read_fd(fd, out_string);
// Close the file
close(fd);
return result;
}
Result write_fd(int fd, const char* string) {
// Write the string to the file descriptor
size_t length = strlen(string);
ssize_t bytes_written = 0;
while (bytes_written < length) {
ssize_t result = write(fd, string + bytes_written, length - bytes_written);
if (result == -1) {
log_message(LOG_LEVEL_ERROR, "Failed to write to the file descriptor (%s).", strerror(errno));
return FAILURE;
}
bytes_written += result;
}
return SUCCESS;
}
Result write_file(const char* path, const char* string) {
// Open the file
int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (fd == -1) {
log_message(LOG_LEVEL_ERROR, "Failed to open the file '%s' (%s).", path, strerror(errno));
return FAILURE;
}
// Write the string to the file
Result result = write_fd(fd, string);
// Close the file
close(fd);
return result;
}

View File

@ -47,3 +47,21 @@ Result run_executable(int* out_exit_code, char** out_stdout, char** out_stderr,
/// @param out_string The pointer to the output string. The caller is responsible for freeing the memory. /// @param out_string The pointer to the output string. The caller is responsible for freeing the memory.
/// @return The result of the operation. /// @return The result of the operation.
Result read_fd(int fd, char** out_string); Result read_fd(int fd, char** out_string);
/// @brief Reads the contents of a file into a string.
/// @param path The path of the file to read.
/// @param out_string The pointer to the output string. The caller is responsible for freeing the memory.
/// @return The result of the operation.
Result read_file(const char* path, char** out_string);
/// @brief Writes the given string to a file descriptor.
/// @param fd The file descriptor to write to.
/// @param string The string to write.
/// @return The result of the operation.
Result write_fd(int fd, const char* string);
/// @brief Writes the given string to a file.
/// @param path The path of the file to write.
/// @param string The string to write.
/// @return The result of the operation.
Result write_file(const char* path, const char* string);