From 01729897178dfd1b69d2992fee082acd52975aa2 Mon Sep 17 00:00:00 2001 From: Castulo Martinez Date: Mon, 16 Dec 2019 11:24:35 -0800 Subject: [PATCH] Revert operation when theres an error adding repos When adding 3rd-party repositories, errors may occur, in these cases the operation has to be reverted completely because we don't want to be left with an invalid repo. Signed-off-by: Castulo Martinez --- src/3rd_party_add.c | 49 +++++++++++++++++++++++++++++++++++++++++- src/3rd_party_remove.c | 21 +----------------- src/3rd_party_repos.c | 23 ++++++++++++++++++-- src/3rd_party_repos.h | 11 +++++++++- 4 files changed, 80 insertions(+), 24 deletions(-) diff --git a/src/3rd_party_add.c b/src/3rd_party_add.c index 093aa2c1..a8b5cb35 100644 --- a/src/3rd_party_add.c +++ b/src/3rd_party_add.c @@ -69,6 +69,23 @@ static bool parse_options(int argc, char **argv) return false; } +static int remove_repo(const char *repo_name) +{ + int ret; + + ret = third_party_remove_repo(repo_name); + if (ret != 0 && ret != -ENOENT) { + return ret; + } + + ret = third_party_remove_repo_directory(repo_name); + if (ret != 0 && ret != -ENOENT) { + return ret; + } + + return 0; +} + enum swupd_code third_party_add_main(int argc, char **argv) { @@ -77,6 +94,9 @@ enum swupd_code third_party_add_main(int argc, char **argv) const char *name, *url; struct list *repos = NULL; struct repo *repo = NULL; + char *path_prefix = NULL; + char *state_dir = NULL; + bool revert = false; int repo_version; int ret; @@ -95,9 +115,14 @@ enum swupd_code third_party_add_main(int argc, char **argv) url = argv[argc - 1]; if (!is_url_allowed(url)) { - return SWUPD_INVALID_OPTION; + ret_code = SWUPD_INVALID_OPTION; + goto finish; } + /* backup the original global values */ + path_prefix = strdup_or_die(globals.path_prefix); + state_dir = strdup_or_die(globals.state_dir); + /* The last two in reverse are the repo-name, repo-url */ ret = third_party_add_repo(name, url); if (ret) { @@ -117,12 +142,14 @@ enum swupd_code third_party_add_main(int argc, char **argv) if (!repo) { /* this should not happen */ ret_code = SWUPD_UNEXPECTED_CONDITION; + revert = true; goto finish; } /* set the appropriate content_dir and state_dir for the selected 3rd-party repo */ ret_code = third_party_set_repo(globals.state_dir, globals.path_prefix, repo); if (ret_code) { + revert = true; goto finish; } @@ -131,6 +158,7 @@ enum swupd_code third_party_add_main(int argc, char **argv) if (repo_version < 0) { error("Unable to determine the latest version for repository %s\n\n", repo->name); ret_code = SWUPD_INVALID_REPOSITORY; + revert = true; goto finish; } @@ -142,12 +170,31 @@ enum swupd_code third_party_add_main(int argc, char **argv) struct list *bundle_to_install = NULL; bundle_to_install = list_append_data(bundle_to_install, "os-core"); ret_code = bundle_add(bundle_to_install, repo_version); + if (ret_code) { + revert = true; + } list_free_list(bundle_to_install); finish: + if (revert) { + /* there was an error adding the repo, revert the action, + * we don't want to keep a corrupt repo */ + info("There was an error adding 3rd-party repository %s, reverting...\n", name); + set_path_prefix(path_prefix); + set_state_dir(state_dir); + ret = remove_repo(name); + if (!ret) { + info("Operation reverted\n"); + } else { + error("There was an error removing the repository (errno: %d)\n", ret); + } + } list_free_list_and_data(repos, repo_free_data); + free_string(&path_prefix); + free_string(&state_dir); swupd_deinit(); progress_finish_steps(ret_code); + return ret_code; } diff --git a/src/3rd_party_remove.c b/src/3rd_party_remove.c index 80eb5921..122c9474 100644 --- a/src/3rd_party_remove.c +++ b/src/3rd_party_remove.c @@ -25,25 +25,6 @@ #ifdef THIRDPARTY -static int remove_repo_directory(char *repo_name) -{ - char *repo_dir; - int ret = 0; - - //TODO: use a global function to get this value - repo_dir = str_or_die("%s/%s/%s", globals.path_prefix, "opt/3rd_party", repo_name); - ret = sys_rm_recursive(repo_dir); - if (ret == -ENOENT) { - ret = 0; - } - if (ret < 0) { - error("Failed to delete repository directory\n"); - } - - free(repo_dir); - return ret; -} - static void print_help(void) { print("Usage:\n"); @@ -112,7 +93,7 @@ enum swupd_code third_party_remove_main(int argc, char **argv) goto exit; } - if (remove_repo_directory(argv[argc - 1]) < 0) { + if (third_party_remove_repo_directory(argv[argc - 1]) < 0) { ret = SWUPD_COULDNT_REMOVE_FILE; goto exit; } diff --git a/src/3rd_party_repos.c b/src/3rd_party_repos.c index 46d3d118..54b0068f 100644 --- a/src/3rd_party_repos.c +++ b/src/3rd_party_repos.c @@ -193,14 +193,14 @@ exit: return ret; } -int third_party_remove_repo(char *repo_name) +int third_party_remove_repo(const char *repo_name) { struct repo *repo; struct list *repos; int ret = 0; repos = third_party_get_repos(); - repo = list_remove(repo_name, &repos, repo_name_cmp); + repo = list_remove((void *)repo_name, &repos, repo_name_cmp); if (!repo) { error("Repository not found\n"); @@ -219,6 +219,25 @@ exit: return ret; } +int third_party_remove_repo_directory(const char *repo_name) +{ + char *repo_dir; + int ret = 0; + + //TODO: use a global function to get this value + repo_dir = str_or_die("%s/%s/%s", globals.path_prefix, "opt/3rd_party", repo_name); + ret = sys_rm_recursive(repo_dir); + if (ret == -ENOENT) { + ret = 0; + } + if (ret < 0) { + error("Failed to delete repository directory\n"); + } + + free(repo_dir); + return ret; +} + enum swupd_code third_party_set_repo(const char *state_dir, const char *path_prefix, struct repo *repo) { char *repo_state_dir; diff --git a/src/3rd_party_repos.h b/src/3rd_party_repos.h index 8c8c5e4b..7fa08491 100644 --- a/src/3rd_party_repos.h +++ b/src/3rd_party_repos.h @@ -63,7 +63,16 @@ int third_party_add_repo(const char *repo_name, const char *repo_url); * @returns 0 on success ie: a repo is found, removed & repo config is adjusted * otherwise a -1 on any failure */ -int third_party_remove_repo(char *repo_name); +int third_party_remove_repo(const char *repo_name); + +/** + * @brief This function removes the directory where the content of a repo is installed. + * + * @param repo_name A string containing repo_name + * + * @returns 0 on success, otherwise a negative errno on any failure + */ +int third_party_remove_repo_directory(const char *repo_name); /** * @brief This function sets up swupd to use a specific 3rd-party repo.