From 7f4b7142b09205dc773a915e3fe3cb7954f6d041 Mon Sep 17 00:00:00 2001 From: bigfoot547 Date: Tue, 26 Dec 2023 22:33:51 -0600 Subject: refactor instances --- src/cmd-instance.c | 286 +++++++++++++++++++---------------------------------- 1 file changed, 101 insertions(+), 185 deletions(-) (limited to 'src/cmd-instance.c') diff --git a/src/cmd-instance.c b/src/cmd-instance.c index 6982eb3..c81eb7c 100644 --- a/src/cmd-instance.c +++ b/src/cmd-instance.c @@ -15,9 +15,39 @@ #include #include +#define CMD_MSG_INSTANCE_LOAD_ERR "Error loading instances" +#define CMD_MSG_INSTANCE_ADD_ERR "Error adding the instance" +#define CMD_MSG_INSTANCE_SAVE_ERR "Error saving the instance" +#define CMD_MSG_INSTANCE_DEL_ERR "Error removing the instance" +#define CMD_MSG_INSTANCE_RENAME_ERR "Error renaming the instance" + +#define CMD_MSG_INSTANCE_INVALID_NAME "The instance name is invalid." +#define CMD_MSG_INSTANCE_DUPLICATE "An instance named '%s' already exists." +#define CMD_MSG_INSTANCE_DIR_CREATE_E "Error creating instance directory: %s" +#define CMD_MSG_INSTANCE_DIR_CHECK_E "Error checking instance directory: %s" +#define CMD_MSG_INSTANCE_DIR_DIRTY "The instance directory '%s' is not empty. If this is intentional, rerun the command with --force." + +#define CMD_MSG_INSTANCE_NAME_NOT_FOUND "An instance by the name '%s' could not be found." +#define CMD_MSG_INSTANCE_UUID_NOT_FOUND "An instance by the UUID '%s' could not be found." + +#define CMD_MSG_INSTANCE_DELDIR_ERR(_msg) "Error deleting instance directory: " _msg + +#define CMD_INSTANCE_CHECK(_res, _v, _msg) do { \ + switch (((_res) = (_v))) { \ + case INSTANCE_SUCCESS: break; \ + case INSTANCE_ERRNO: \ + CMD_FATAL(_msg ": %s: %s", l2_instance_errormsg[(_res)], strerror(errno)); \ + break; \ + default: \ + CMD_FATAL(_msg ": %s", l2_instance_errormsg[(_res)]); \ + } \ +} while (0) + +void cmd_instance__check_name(const char *instname); + unsigned cmd_instance_add(struct l2_context_node *ctx, char **args) { - int res = l2_instance_load_all(); + int res; char *name = NULL; char *path = NULL; char *newpath = NULL; @@ -30,78 +60,40 @@ unsigned cmd_instance_add(struct l2_context_node *ctx, char **args) if (!strcmp(*cur, "--force")) { flag_force = true; } else { - fprintf(stderr, "fatal: Unknown argument '%s'.\n", *cur); - return CMD_RESULT_FAIL; + CMD_FATAL(CMD_MSG_UNKNOWN_ARGUMENT, *cur); } } - if (res != INSTANCE_SUCCESS) { - if (res == INSTANCE_ERRNO) { - fprintf(stderr, "fatal: Error loading instances: %s\n", strerror(errno)); - } else { - fprintf(stderr, "fatal: Error loading instances (%d)\n", res); - } - return CMD_RESULT_FAIL; - } + CMD_INSTANCE_CHECK(res, l2_instance_load_all(), CMD_MSG_INSTANCE_LOAD_ERR); /* get the name and path (if it exists) */ - 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; - } else if (!strcmp("location", cur->node->name)) { - path = cur->value; - } - } + l2_cmd_collect_args(ctx, 2, "name", &name, "#location", &path); /* make sure the name and path make sense (path should be an absolute path, name shouldn't be empty) */ - if (!name || !*name) { - fputs("fatal: The specified name is invalid\n", stderr); - return CMD_RESULT_FAIL; - } - - for (char *cur = name; *cur; ++cur) { - if (*cur < ' ') { - fputs("fatal: The specified name contains invalid characters\n", stderr); - return CMD_RESULT_FAIL; - } - } + cmd_instance__check_name(name); /* make sure there is not a profile with that name already */ - for (struct l2_instance *cur = l2_state.instance_head; cur; cur = cur->next) { - if (!strcmp(cur->name, name)) { - fprintf(stderr, "fatal: An instance by the name '%s' already exists.\n", cur->name); - return CMD_RESULT_FAIL; - } + if (l2_instance_find_by_name(name)) { + CMD_FATAL(CMD_MSG_INSTANCE_DUPLICATE, name); } /* also find an unused UUID through rejection sampling */ - bool found; - do { - found = false; + while (true) { l2_uuid_random(&uuid); - for (struct l2_instance *cur = l2_state.instance_head; cur; cur = cur->next) { - if (!l2_uuid_compare(&cur->uuid, &uuid)) { - found = true; - break; - } - } - } while (found); + if (!l2_instance_find_by_uuid(&uuid)) break; + } /* create the directory at "path" (if it isn't empty, complain) */ if (path) { newpath = realpath(path, NULL); if (!newpath) { - fprintf(stderr, "fatal: Failed to canonicalize specified path: %s\n", strerror(errno)); - return CMD_RESULT_FAIL; + CMD_FATAL0(CMD_MSG_ALLOCATION_FAILED); } } else if (!path) { newpath = strdup(l2_state.paths.data); if (!newpath) { newpath_append_fail: - free(newpath); - fprintf(stderr, "fatal: Allocation failed: %s\n", strerror(errno)); - return CMD_RESULT_FAIL; + CMD_FATAL0(CMD_MSG_ALLOCATION_FAILED); } newpath = l2_launcher_strapp(newpath, "/instances/"); @@ -116,38 +108,32 @@ unsigned cmd_instance_add(struct l2_context_node *ctx, char **args) /* 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; + CMD_FATAL(CMD_MSG_INSTANCE_DIR_CREATE_E, strerror(errno)); } 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; + CMD_FATAL(CMD_MSG_INSTANCE_DIR_CHECK_E, strerror(errno)); } struct dirent *ent; - errno = 0; + errno = 0; /* readdir can return NULL on success */ 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; + CMD_FATAL(CMD_MSG_INSTANCE_DIR_DIRTY, path); } - } - closedir(dir); - dir = NULL; + errno = 0; + } if (errno) { - fprintf(stderr, "fatal: Error scanning instance directory: %s\n", strerror(errno)); - res = CMD_RESULT_FAIL; - goto cleanup; + CMD_FATAL(CMD_MSG_INSTANCE_DIR_CHECK_E, strerror(errno)); } - } + + closedir(dir); + dir = NULL; + } /* add the instance */ @@ -157,24 +143,14 @@ unsigned cmd_instance_add(struct l2_context_node *ctx, char **args) inst.name = name; inst.path = path; - if ((res = l2_instance_add_instance(&inst)) != INSTANCE_SUCCESS) { - fprintf(stderr, "fatal: Failed to add instance (%d)\n", res); - res = CMD_RESULT_FAIL; - goto cleanup; - } - - if ((res = l2_instance_save_all()) != INSTANCE_SUCCESS) { - fprintf(stderr, "fatal: Failed to add instance (%d)\n", res); - res = CMD_RESULT_FAIL; - goto cleanup; - } + CMD_INSTANCE_CHECK(res, l2_instance_add_instance(&inst), CMD_MSG_INSTANCE_ADD_ERR); - res = CMD_RESULT_SUCCESS; + CMD_INSTANCE_CHECK(res, l2_instance_save_all(), CMD_MSG_INSTANCE_SAVE_ERR); -cleanup: if (dir) closedir(dir); free(newpath); - return res; + + return CMD_RESULT_SUCCESS; } int cmd__delete_with_reckless_abandon(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf) @@ -208,6 +184,7 @@ unsigned cmd_instance_remove(struct l2_context_node *ctx, char **args) uuid_t instid = UUID_NULL_INIT; struct l2_instance *to_remove = NULL; char *removepath = NULL; + char instid_pretty[UUID_STRLEN + 1]; for (char **cur = args; *cur; ++cur) { if (!strcmp("--delete", *cur)) { @@ -215,121 +192,73 @@ unsigned cmd_instance_remove(struct l2_context_node *ctx, char **args) } 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; + CMD_FATAL(CMD_MSG_UNKNOWN_ARGUMENT, *cur); } } - if (!name) { - fputs("fatal: Name not specified\n", stderr); - return CMD_RESULT_FAIL; - } + l2_cmd_collect_args(ctx, 1, "name", &name); if (flag_byid && !l2_uuid_from_string(&instid, name)) { - fprintf(stderr, "Failed to parse instance UUID '%s'.\n", name); - return CMD_RESULT_FAIL; + CMD_FATAL(CMD_MSG_INVALID_UUID, name); } - res = l2_instance_load_all(); - if (res != INSTANCE_SUCCESS) { - fprintf(stderr, "fatal: Failed to load instances (%d).\n", res); - return CMD_RESULT_FAIL; - } + CMD_INSTANCE_CHECK(res, l2_instance_load_all(), CMD_MSG_INSTANCE_LOAD_ERR); /* 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; - } + to_remove = l2_instance_find_by_uuid(&instid); + if (!to_remove) { + l2_uuid_to_string(&instid, instid_pretty); + CMD_FATAL(CMD_MSG_INSTANCE_UUID_NOT_FOUND, instid_pretty); } } 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; + to_remove = l2_instance_find_by_name(name); + if (!to_remove) CMD_FATAL(CMD_MSG_INSTANCE_NAME_NOT_FOUND, name); } if (flag_remove) { removepath = strdup(to_remove->path); if (!removepath) { - fputs("fatal: Failed to create path.\n", stderr); - return CMD_RESULT_FAIL; + CMD_FATAL0(CMD_MSG_ALLOCATION_FAILED); } } /* 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; - } + CMD_INSTANCE_CHECK(res, l2_instance_del_instance(to_remove), CMD_MSG_INSTANCE_DEL_ERR); 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; - } + CMD_INSTANCE_CHECK(res, l2_instance_save_all(), CMD_MSG_INSTANCE_SAVE_ERR); /* 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; + CMD_FATAL0(CMD_MSG_INSTANCE_DELDIR_ERR("unreadable file/folder encountered")); case -1: - fputs("Error walking file tree.\n", stderr); - res = CMD_RESULT_FAIL; - goto cleanup; + CMD_FATAL0(CMD_MSG_INSTANCE_DELDIR_ERR("error walking file tree")); case 0: break; default: - fprintf(stderr, "Error removing a file: %s\n", strerror(res)); - res = CMD_RESULT_FAIL; - goto cleanup; + CMD_FATAL(CMD_MSG_INSTANCE_DELDIR_ERR("error removing a file: %s"), strerror(res)); } } - res = CMD_RESULT_SUCCESS; - -cleanup: if (removepath) free(removepath); - return res; + return CMD_RESULT_SUCCESS; } unsigned cmd_instance_list(struct l2_context_node *ctx, char **args) { L2_UNUSED(ctx); + int res; if (*args) { - fprintf(stderr, "fatal: Unknown argument '%s'.\n", *args); - return CMD_RESULT_FAIL; + CMD_FATAL(CMD_MSG_UNKNOWN_ARGUMENT, *args); } - int res = l2_instance_load_all(); - - if (res != INSTANCE_SUCCESS) { - fprintf(stderr, "fatal: Failed to load instances. (%d)\n", res); - return CMD_RESULT_FAIL; - } + CMD_INSTANCE_CHECK(res, l2_instance_load_all(), CMD_MSG_INSTANCE_LOAD_ERR); if (l2_state.instance_head) { char idstr[UUID_STRLEN + 1]; @@ -352,53 +281,40 @@ unsigned cmd_instance_rename(struct l2_context_node *ctx, char **args) struct l2_instance *to_rename = NULL; if (*args) { - fprintf(stderr, "fatal: Unknown argument '%s'.\n", *args); - return CMD_RESULT_FAIL; + CMD_FATAL(CMD_MSG_UNKNOWN_ARGUMENT, *args); } - res = l2_instance_load_all(); + CMD_INSTANCE_CHECK(res, l2_instance_load_all(), CMD_MSG_INSTANCE_LOAD_ERR); - if (res != INSTANCE_SUCCESS) { - fprintf(stderr, "fatal: Failed to load instances. (%d)\n", res); - return CMD_RESULT_FAIL; - } + l2_cmd_collect_args(ctx, 2, "oldname", &oldname, "newname", &newname); - for (struct l2_context_node *cur = ctx; cur; cur = cur->next) { - if (!strcmp("oldname", cur->node->name)) { - oldname = cur->value; - } else if (!strcmp("newname", cur->node->name)) { - newname = cur->value; - } - } + cmd_instance__check_name(newname); - if (!(oldname && newname)) { /* TODO: sanitize newname like in "instance add" */ - fputs("fatal: Invalid usage.\n", stderr); - return CMD_RESULT_FAIL; + if (l2_instance_find_by_name(newname)) { + CMD_FATAL(CMD_MSG_INSTANCE_DUPLICATE, newname); } - for (struct l2_instance *cur = l2_state.instance_head; cur; cur = cur->next) { - if (!strcmp(cur->name, oldname)) { - to_rename = cur; - } else if (!strcmp(cur->name, newname)) { - fprintf(stderr, "fatal: An instance by the name '%s' already exists.\n", newname); - return CMD_RESULT_FAIL; - } + if (!(to_rename = l2_instance_find_by_name(oldname))) { + CMD_FATAL(CMD_MSG_INSTANCE_NAME_NOT_FOUND, oldname); } - if (!to_rename) { - fprintf(stderr, "fatal: No instance found by the name '%s'.\n", oldname); - return CMD_RESULT_FAIL; - } + CMD_INSTANCE_CHECK(res, l2_instance_rename_instance(to_rename, newname), CMD_MSG_INSTANCE_RENAME_ERR); - if ((res = l2_instance_rename_instance(to_rename, newname)) != INSTANCE_SUCCESS) { - fprintf(stderr, "fatal: Failed to rename the instance. (%d)\n", res); - return CMD_RESULT_FAIL; - } + CMD_INSTANCE_CHECK(res, l2_instance_save_all(), CMD_MSG_INSTANCE_SAVE_ERR); + + return CMD_RESULT_SUCCESS; +} - if ((res = l2_instance_save_all()) != INSTANCE_SUCCESS) { - fprintf(stderr, "fatal: Failed to save instances. (%d)\n", res); - return CMD_RESULT_FAIL; +void cmd_instance__check_name(const char *instname) +{ + if (!*instname) goto failure; + + for (const char *cur = instname; *cur; ++cur) { + if (*cur <= ' ') goto failure; /* not like you couldn't just use a unicode NBSP or something */ } - return CMD_RESULT_SUCCESS; + return; + +failure: + CMD_FATAL0(CMD_MSG_INSTANCE_INVALID_NAME); } -- cgit v1.2.3-70-g09d2