linuxinstall/src/sandbox.c

253 lines
7.3 KiB
C
Raw Normal View History

#include "sandbox.h"
#include "utils.h"
#include "backing.h"
#include "entry.h"
#include "disk.h"
#include <stdio.h>
2024-02-15 19:42:22 +01:00
#include <stdlib.h>
2024-02-16 17:13:52 +01:00
#include <string.h>
2024-02-17 15:15:40 +01:00
#include <pwd.h>
#include <unistd.h>
#include <time.h>
2024-02-17 01:20:20 +01:00
#include <sys/resource.h>
const Command COMMANDS[] = {
{command_help, "help", "[command]", "Prints the help message.",
"Prints the help message for the given command. If no command is given, prints the help message for all commands."},
{command_version, "version", "", "Prints the version.",
"Prints the version of the program."},
{},
{command_add_entry, "add-entry", "<entry id> [--root|-r <size>] [--backed|-b <backing id>]", "Adds an entry to the entry pool.",
"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.",
"Removes the entry with the given id from the entry pool."},
2024-02-17 12:34:24 +01:00
{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."},
{command_clear_entries, "clear-entries", "", "Removes all the entries from the entry pool.",
"Removes all the entries from the entry pool."},
{command_reset_entry, "reset-entry", "<entry id>", "Resets an entry to its initial state.",
"TODO"},
{command_update_entry, "update-entry", "<entry id>", "Updates the backing disk of the given entry to the latest available.",
"TODO"},
2024-02-17 02:18:16 +01:00
{},
};
int main(int argc, char* argv[]) {
2024-02-17 15:15:40 +01:00
// Check that the user 'sandbox' exists
struct passwd* user = getpwnam(SANDBOX_USER);
if (user == NULL) {
log_message(LOG_LEVEL_ERROR, "User '%s' does not exist. Please check the installation.", SANDBOX_USER);
return EXIT_FAILURE;
}
// Check that the program is either run as root or as the user 'sandbox'
if (geteuid() != 0 && geteuid() != user->pw_uid) {
log_message(LOG_LEVEL_ERROR, "This program must be run as root or as the user '%s'.", SANDBOX_USER);
return EXIT_FAILURE;
}
// If the program is run as root, switch to the user 'sandbox'
if (geteuid() == 0) {
if (setregid(user->pw_gid, user->pw_gid) != 0) {
log_message(LOG_LEVEL_ERROR, "Failed to switch to the user '%s'.", SANDBOX_USER);
return EXIT_FAILURE;
}
if (setreuid(user->pw_uid, user->pw_uid) != 0) {
log_message(LOG_LEVEL_ERROR, "Failed to switch to the user '%s'.", SANDBOX_USER);
return EXIT_FAILURE;
}
}
if (argc < 2)
return command_help(0, NULL);
size_t input_length = strlen(argv[1]);
const Command* command = NULL;
for (int i = 0; i < ARRAY_SIZE(COMMANDS); i++) {
if (COMMANDS[i].name == NULL)
continue;
// Check that the length of the input is equal or less than the length of the command name
if (input_length > strlen(COMMANDS[i].name))
continue;
// Check that the input matches the command name
if (strncmp(argv[1], COMMANDS[i].name, input_length) == 0) {
// Check for multiple matches
if (command != NULL) {
log_message(LOG_LEVEL_ERROR, "Ambiguous command '%s'.", argv[1]);
return EXIT_FAILURE;
}
command = &COMMANDS[i];
}
2024-02-16 17:13:52 +01:00
}
2024-02-16 16:53:02 +01:00
// Check if the command is NULL (no matches)
2024-02-16 17:13:52 +01:00
if (command == NULL) {
log_message(LOG_LEVEL_ERROR, "Unknown command '%s'.", argv[1]);
return EXIT_FAILURE;
2024-02-16 17:13:52 +01:00
}
2024-02-16 16:53:02 +01:00
return command->handler(argc - 2, argv + 2);
}
int command_help(int argc, char* argv[]) {
// Check the number of arguments
if (argc == 0) {
fprintf(stdout, "Usage: sandbox [command] [arguments]\n\n");
fprintf(stdout, "Commands:\n");
for (int i = 0; i < ARRAY_SIZE(COMMANDS); i++)
if (COMMANDS[i].name == NULL)
printf("\n");
else
fprintf(stdout, " %s %s - %s\n", COMMANDS[i].name, COMMANDS[i].arguments, COMMANDS[i].description);
fprintf(stdout, "\nRun 'sandbox help [command]' for more information on a command.\n");
return EXIT_SUCCESS;
} else if (argc == 1) {
// Find the command that matches the given name
const Command* command = NULL;
for (int i = 0; i < ARRAY_SIZE(COMMANDS); i++) {
if (COMMANDS[i].name == NULL)
continue;
2024-02-16 18:26:02 +01:00
if (strcmp(argv[0], COMMANDS[i].name) == 0) {
command = &COMMANDS[i];
break;
}
}
// Check if the command is NULL (no matches)
if (command == NULL) {
log_message(LOG_LEVEL_ERROR, "Unknown command '%s'.", argv[0]);
return EXIT_FAILURE;
}
2024-02-16 17:19:56 +01:00
// Print the help message for the command
fprintf(stdout, "Usage: sandbox %s %s\n\n", command->name, command->arguments);
fprintf(stdout, " %s\n", command->details);
return EXIT_SUCCESS;
} else {
log_message(LOG_LEVEL_ERROR, "Too many arguments for 'help' command.");
return EXIT_FAILURE;
2024-02-16 17:13:52 +01:00
}
}
2024-02-16 16:53:02 +01:00
int command_version(int argc, char* argv[]) {
fprintf(stdout, "Sandbox manager v%s\n", VERSION);
return EXIT_SUCCESS;
2024-02-16 16:53:02 +01:00
}
int command_add_entry(int argc, char* argv[]) {
2024-02-17 14:38:52 +01:00
// Extract the primary arguments
if (argc < 1) {
log_message(LOG_LEVEL_ERROR, "Missing entry id.");
return EXIT_FAILURE;
}
const char* entry_id = argv[0];
// Extract the options
bool is_root = false;
uint64_t size = 0;
bool is_backed = false;
const char* backing_id = NULL;
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "--root") == 0 || strcmp(argv[i], "-r") == 0) {
if (is_backed) {
log_message(LOG_LEVEL_ERROR, "Cannot specify both --root and --backed options.");
return EXIT_FAILURE;
}
is_root = true;
if (i + 1 >= argc) {
log_message(LOG_LEVEL_ERROR, "Missing size for root entry.");
return EXIT_FAILURE;
}
Result result = parse_size(argv[i + 1], &size);
if (result != SUCCESS)
return EXIT_FAILURE;
i++; // Consume the next argument
} else if (strcmp(argv[i], "--backed") == 0 || strcmp(argv[i], "-b") == 0) {
if (is_root) {
log_message(LOG_LEVEL_ERROR, "Cannot specify both --root and --backed options.");
return EXIT_FAILURE;
}
is_backed = true;
if (i + 1 >= argc) {
log_message(LOG_LEVEL_ERROR, "Missing backing id for backed entry.");
return EXIT_FAILURE;
}
backing_id = argv[i + 1];
i++; // Consume the next argument
} else {
log_message(LOG_LEVEL_ERROR, "Too many arguments for 'add-entry' command.");
2024-02-17 14:38:52 +01:00
return EXIT_FAILURE;
}
}
Result result;
if (is_root)
result = add_root_entry(entry_id, size);
else if (is_backed)
result = add_backed_entry(entry_id, backing_id);
else
result = add_automatic_entry(entry_id);
if (result != SUCCESS)
return EXIT_FAILURE;
2024-02-17 02:18:16 +01:00
return EXIT_SUCCESS;
}
int command_remove_entry(int argc, char* argv[]) {
2024-02-17 15:15:40 +01:00
if (argc < 1) {
log_message(LOG_LEVEL_ERROR, "Missing entry id.");
return EXIT_FAILURE;
}
const char* entry_id = argv[0];
if (argc > 1) {
log_message(LOG_LEVEL_ERROR, "Too many arguments for 'remove-entry' command.");
2024-02-17 15:15:40 +01:00
return EXIT_FAILURE;
}
Result result = remove_entry(entry_id);
if (result != SUCCESS)
return EXIT_FAILURE;
return EXIT_SUCCESS;
}
int command_list_entries(int argc, char* argv[]) {
return EXIT_SUCCESS;
}
int command_clear_entries(int argc, char* argv[]) {
return EXIT_SUCCESS;
}
int command_reset_entry(int argc, char* argv[]) {
return EXIT_SUCCESS;
}
int command_update_entry(int argc, char* argv[]) {
return EXIT_SUCCESS;
}