diff options
| author | 2023-12-25 21:59:53 -0600 | |
|---|---|---|
| committer | 2023-12-25 21:59:53 -0600 | |
| commit | 5a1568cb0c3ef6ed697269add229c4d5e6829b9b (patch) | |
| tree | 80d73cb8155a4381718794a6fefe10f9e8f05567 /src | |
| parent | [WIP] Add instances (diff) | |
add instance remove
Diffstat (limited to 'src')
| -rw-r--r-- | src/cmd-instance.c | 203 | ||||
| -rw-r--r-- | src/instance.c | 6 | ||||
| -rw-r--r-- | src/macros.h | 1 |
3 files changed, 201 insertions, 9 deletions
diff --git a/src/cmd-instance.c b/src/cmd-instance.c index 89494af..e187b7d 100644 --- a/src/cmd-instance.c +++ b/src/cmd-instance.c @@ -2,12 +2,18 @@ #include "command.h" #include "instance.h" #include "l2su.h" +#include "uuid/uuid.h" +#include "macros.h" #include <stdio.h> #include <string.h> #include <errno.h> #include <stdlib.h> #include <stdbool.h> +#include <sys/types.h> +#include <dirent.h> +#include <ftw.h> +#include <unistd.h> unsigned cmd_instance_add(struct l2_context_node *ctx, char **args) { @@ -17,10 +23,21 @@ unsigned cmd_instance_add(struct l2_context_node *ctx, char **args) char *newpath = NULL; uuid_t uuid; char uuidstr[UUID_STRLEN+1]; + bool flag_force = false; + DIR *dir = NULL; + + for (char **cur = args; *cur; ++cur) { + if (!strcmp(*cur, "--force")) { + flag_force = true; + } else { + fprintf(stderr, "fatal: Unknown argument '%s'.\n", *cur); + return CMD_RESULT_FAIL; + } + } if (res != INSTANCE_SUCCESS) { if (res == INSTANCE_ERRNO) { - fprintf(stderr, "fatal: Error loading instances: %s", strerror(errno)); + fprintf(stderr, "fatal: Error loading instances: %s\n", strerror(errno)); } else { fprintf(stderr, "fatal: Error loading instances (%d)\n", res); } @@ -72,9 +89,12 @@ unsigned cmd_instance_add(struct l2_context_node *ctx, char **args) } while (found); /* create the directory at "path" (if it isn't empty, complain) */ - if (path && *path != '/') { - fputs("fatal: Specified path is not an absolute path\n", stderr); - return CMD_RESULT_FAIL; + if (path) { + newpath = realpath(path, NULL); + if (!newpath) { + fprintf(stderr, "fatal: Failed to canonicalize specified path: %s\n", strerror(errno)); + return CMD_RESULT_FAIL; + } } else if (!path) { newpath = strdup(l2_state.paths.data); if (!newpath) { @@ -90,9 +110,44 @@ unsigned cmd_instance_add(struct l2_context_node *ctx, char **args) l2_uuid_to_string(&uuid, uuidstr); newpath = l2_launcher_strapp(newpath, uuidstr); if (!newpath) goto newpath_append_fail; + + path = newpath; } /* TODO: now create the directory for realsies */ + if (l2_launcher_mkdir_parents(path) < 0) { + fprintf(stderr, "fatal: Could not create instance directory: %s\n", strerror(errno)); + res = CMD_RESULT_FAIL; + goto cleanup; + } + + if (!flag_force) { + dir = opendir(path); + if (!dir) { + fprintf(stderr, "fatal: Could not check instance directory: %s\n", strerror(errno)); + res = CMD_RESULT_FAIL; + goto cleanup; + } + + struct dirent *ent; + errno = 0; + while ((ent = readdir(dir))) { + if (strcmp(ent->d_name, ".") && strcmp(ent->d_name, "..")) { + fprintf(stderr, "fatal: Instance directory '%s' is not empty. If this is intentional, rerun the command with --force.\n", path); + res = CMD_RESULT_FAIL; + goto cleanup; + } + } + + closedir(dir); + dir = NULL; + + if (errno) { + fprintf(stderr, "fatal: Error scanning instance directory: %s\n", strerror(errno)); + res = CMD_RESULT_FAIL; + goto cleanup; + } + } /* add the instance */ @@ -100,7 +155,7 @@ unsigned cmd_instance_add(struct l2_context_node *ctx, char **args) inst.uuid = uuid; inst.name = name; - inst.path = path ? path : newpath; + inst.path = path; if ((res = l2_instance_add_instance(&inst)) != INSTANCE_SUCCESS) { fprintf(stderr, "fatal: Failed to add instance (%d)\n", res); @@ -114,18 +169,150 @@ unsigned cmd_instance_add(struct l2_context_node *ctx, char **args) goto cleanup; } - printf("add command yay\n"); - res = CMD_RESULT_SUCCESS; cleanup: + if (dir) closedir(dir); free(newpath); return res; } +int cmd__delete_with_reckless_abandon(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf) +{ + L2_UNUSED(sb); + L2_UNUSED(ftwbuf); + + switch (typeflag) { + case FTW_F: + case FTW_SL: + if (unlink(fpath) < 0) return errno; + break; + case FTW_DP: + if (rmdir(fpath) < 0) return errno; + break; + /* unlink */ + case FTW_NS: + case FTW_DNR: + return -2; + /* error */ + } + + return 0; +} + unsigned cmd_instance_remove(struct l2_context_node *ctx, char **args) { - return CMD_RESULT_SUCCESS; + char *name = NULL; + bool flag_remove = false, flag_byid = false; + int res; + uuid_t instid = UUID_NULL_INIT; + struct l2_instance *to_remove = NULL; + char *removepath = NULL; + + for (char **cur = args; *cur; ++cur) { + if (!strcmp("--remove", *cur)) { + flag_remove = true; + } else if (!strcmp("--id", *cur)) { + flag_byid = true; + } else { + fprintf(stderr, "fatal: Unknown argument '%s'\n", *cur); + return CMD_RESULT_FAIL; + } + } + + for (struct l2_context_node *cur = ctx; cur; cur = cur->next) { + if (cur->node->type != CMD_NODE_TYPE_ARGUMENT) continue; + + if (!strcmp("name", cur->node->name)) { + name = cur->value; + } + } + + if (!name) { + fputs("fatal: Name not specified\n", stderr); + return CMD_RESULT_FAIL; + } + + if (flag_byid && !l2_uuid_from_string(&instid, name)) { + fprintf(stderr, "Failed to parse instance UUID '%s'.\n", name); + return CMD_RESULT_FAIL; + } + + res = l2_instance_load_all(); + if (res != INSTANCE_SUCCESS) { + fprintf(stderr, "fatal: Failed to load instances (%d).\n", res); + return CMD_RESULT_FAIL; + } + + /* find the thing */ + if (flag_byid) { + for (struct l2_instance *inst = l2_state.instance_head; inst; inst = inst->next) { + if (!l2_uuid_compare(&inst->uuid, &instid)) { + to_remove = inst; + break; + } + } + } else { + for (struct l2_instance *inst = l2_state.instance_head; inst; inst = inst->next) { + if (!strcmp(inst->name, name)) { + to_remove = inst; + break; + } + } + } + + if (!to_remove) { + fputs("fatal: Instance not found.\n", stderr); + return CMD_RESULT_FAIL; + } + + if (flag_remove) { + removepath = strdup(to_remove->path); + if (!removepath) { + fputs("fatal: Failed to create path.\n", stderr); + return CMD_RESULT_FAIL; + } + } + + /* remove the thing */ + if ((res = l2_instance_del_instance(to_remove)) != INSTANCE_SUCCESS) { + fprintf(stderr, "fatal: Failed to remove instance (%d).\n", res); + return CMD_RESULT_FAIL; + } + + to_remove = NULL; /* del_instance frees the instance */ + + if ((res = l2_instance_save_all()) != INSTANCE_SUCCESS) { + fprintf(stderr, "fatal: Failed to save instances (%d).\n", res); + return CMD_RESULT_FAIL; + } + + /* delete the thing if it is necessary */ + if (flag_remove) { + res = nftw(removepath, &cmd__delete_with_reckless_abandon, 128, FTW_DEPTH | FTW_PHYS); + switch (res) { + case -2: + fputs("Unreadable file/folder encountered while walking file tree.\n", stderr); + res = CMD_RESULT_FAIL; + goto cleanup; + case -1: + fputs("Error walking file tree.\n", stderr); + res = CMD_RESULT_FAIL; + goto cleanup; + case 0: + break; + default: + fprintf(stderr, "Error removing a file: %s\n", strerror(res)); + res = CMD_RESULT_FAIL; + goto cleanup; + } + } + + res = CMD_RESULT_SUCCESS; + +cleanup: + if (removepath) free(removepath); + return res; } unsigned cmd_instance_list(struct l2_context_node *ctx, char **args) diff --git a/src/instance.c b/src/instance.c index 20c0f59..148f71d 100644 --- a/src/instance.c +++ b/src/instance.c @@ -46,7 +46,7 @@ int l2_instance_load_all(void) int l2_instance_save_all(void) { json_t *js = NULL; - int instfd = l2_launcher_open_config("instance.json", O_WRONLY | O_CREAT, 0644); + int instfd = l2_launcher_open_config("instance.json", O_WRONLY | O_CREAT | O_TRUNC, 0644); if (instfd < 0) return INSTANCE_ERRNO; int retval = INSTANCE_SUCCESS; @@ -116,6 +116,10 @@ int l2_instance_del_instance(struct l2_instance *inst) l2_state.instance_head = inst->next; } + free((char *)inst->name); /* okay to cast away const because any instance in the list will be allocated with strdup */ + free((char *)inst->path); + free(inst); + return INSTANCE_SUCCESS; } diff --git a/src/macros.h b/src/macros.h index 771032c..4cf6e7b 100644 --- a/src/macros.h +++ b/src/macros.h @@ -4,5 +4,6 @@ #include "config.h" #define L2_ARRLEN(_a) (sizeof(_a) / sizeof(*(_a))) +#define L2_UNUSED(_v) ((void)(_v)) #endif /* include guard */ |
