From ca98b3a7db4994b82823d39634d73263767f8ccc Mon Sep 17 00:00:00 2001 From: Castulo Martinez Date: Fri, 20 Dec 2019 13:13:54 -0800 Subject: [PATCH] Adding "3rd-party clean" command This commit implements the swupd clean command for the 3rd-party bundles so users are able to clean the cache on their state directories. Signed-off-by: Castulo Martinez --- Makefile.am | 1 + scripts/flag_validator.bash | 2 +- src/3rd_party.c | 1 + src/3rd_party_clean.c | 138 ++++++++++++++++++++++++++++++++++++ src/clean.c | 42 +++++------ src/swupd.h | 3 + src/swupd_internal.h | 1 + swupd.bash | 7 +- swupd.zsh | 7 +- 9 files changed, 177 insertions(+), 25 deletions(-) create mode 100644 src/3rd_party_clean.c diff --git a/Makefile.am b/Makefile.am index 22b61a26..c733ffd3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -39,6 +39,7 @@ swupd_SOURCES = \ src/3rd_party_bundle_remove.c \ src/3rd_party.c \ src/3rd_party_check_update.c \ + src/3rd_party_clean.c \ src/3rd_party_diagnose.c \ src/3rd_party_list.c \ src/3rd_party_remove.c \ diff --git a/scripts/flag_validator.bash b/scripts/flag_validator.bash index e4131e0c..99799ae8 100755 --- a/scripts/flag_validator.bash +++ b/scripts/flag_validator.bash @@ -5,7 +5,7 @@ SWUPD_DIR="$SCRIPTS_DIR"/.. SWUPD="$SWUPD_DIR"/swupd swupd_commands=(info autoupdate check-update update bundle-add bundle-remove bundle-list bundle-info search-file diagnose repair os-install mirror clean hashdump 3rd-party) -third_party_commands=(add remove list bundle-add bundle-remove bundle-list bundle-info update diagnose repair check-update) +third_party_commands=(add remove list bundle-add bundle-remove bundle-list bundle-info update diagnose repair check-update clean) conflict=0 count_global_flags() { diff --git a/src/3rd_party.c b/src/3rd_party.c index eae72815..7cf3df5e 100644 --- a/src/3rd_party.c +++ b/src/3rd_party.c @@ -36,6 +36,7 @@ static struct subcmd third_party_commands[] = { { "diagnose", "Verify content from a third party repository", third_party_diagnose_main }, { "repair", "Repair local issues relative to a third party repository", third_party_repair_main }, { "check-update", "Check if a new version of a third party repository is available", third_party_check_update_main }, + { "clean", "Clean cached files of a third party repository", third_party_clean_main }, { 0 } }; diff --git a/src/3rd_party_clean.c b/src/3rd_party_clean.c new file mode 100644 index 00000000..a86950b5 --- /dev/null +++ b/src/3rd_party_clean.c @@ -0,0 +1,138 @@ +/*/* + * Software Updater - client side + * + * Copyright © 2019 Intel Corporation. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2 or later of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#define _GNU_SOURCE + +#include "3rd_party_repos.h" +#include "swupd.h" + +#ifdef THIRDPARTY + +#define FLAG_ALL 2000 +#define FLAG_DRY_RUN 2001 + +static bool cmdline_option_all = false; +static bool cmdline_option_dry_run = false; +static char *cmdline_option_repo = NULL; + +static void print_help(void) +{ + print("Remove cached content used for updates from state directory of a 3rd-party repository\n\n"); + print("Usage:\n"); + print(" swupd 3rd-party clean [OPTION...]\n\n"); + + global_print_help(); + + print("Options:\n"); + print(" -R, --repo Specify the 3rd-party repository to use\n"); + print(" --all Remove all the content including recent metadata\n"); + print(" --dry-run Just print files that would be removed\n"); + print("\n"); +} + +static const struct option prog_opts[] = { + { "all", no_argument, 0, FLAG_ALL }, + { "dry-run", no_argument, 0, FLAG_DRY_RUN }, + { "repo", required_argument, 0, 'R' }, +}; + +static bool parse_opt(int opt, char *optarg UNUSED_PARAM) +{ + switch (opt) { + case FLAG_ALL: + cmdline_option_all = optarg_to_bool(optarg); + return true; + case FLAG_DRY_RUN: + cmdline_option_dry_run = optarg_to_bool(optarg); + return true; + case 'R': + cmdline_option_repo = strdup_or_die(optarg); + return true; + default: + return false; + } + return false; +} + +static const struct global_options opts = { + prog_opts, + sizeof(prog_opts) / sizeof(struct option), + parse_opt, + print_help, +}; + +static bool parse_options(int argc, char **argv) +{ + int optind = global_parse_options(argc, argv, &opts); + + if (optind < 0) { + return false; + } + + if (argc > optind) { + error("unexpected arguments\n\n"); + return false; + } + + return true; +} + +static enum swupd_code clean_repos_state(UNUSED_PARAM char *unused) +{ + enum swupd_code ret; + int files_removed; + + ret = clean_statedir(cmdline_option_dry_run, cmdline_option_all); + files_removed = clean_get_stats(); + if (cmdline_option_dry_run) { + print("Would remove %d files\n", files_removed); + } else { + print("%d files removed\n", files_removed); + } + + return ret; +} + +enum swupd_code third_party_clean_main(int argc, char **argv) +{ + enum swupd_code ret_code = SWUPD_OK; + const int steps_in_clean = 1; + + if (!parse_options(argc, argv)) { + print_help(); + return SWUPD_INVALID_OPTION; + } + + ret_code = swupd_init(SWUPD_ALL); + if (ret_code != SWUPD_OK) { + error("Failed swupd initialization, exiting now\n"); + return ret_code; + } + progress_init_steps("3rd-party-clean", steps_in_clean); + + /* clean the cache */ + ret_code = third_party_run_operation_multirepo(cmdline_option_repo, clean_repos_state, SWUPD_OK); + + swupd_deinit(); + progress_finish_steps(ret_code); + + return ret_code; +} + +#endif diff --git a/src/clean.c b/src/clean.c index 44644eb7..f65c860b 100644 --- a/src/clean.c +++ b/src/clean.c @@ -54,6 +54,11 @@ static struct { int files_removed; } stats; +int clean_get_stats(void) +{ + return stats.files_removed; +} + static struct timespec now; static const struct option prog_opts[] = { @@ -367,22 +372,13 @@ enum swupd_code clean_main(int argc, char **argv) print_help(); return SWUPD_INVALID_OPTION; } - progress_init_steps("clean", steps_in_clean); ret = swupd_init(SWUPD_ALL); if (ret != 0) { error("Failed swupd initialization, exiting now\n"); - goto exit; - } - - if (!options.all) { - ret = clock_gettime(CLOCK_REALTIME, &now); - if (ret != 0) { - ret = SWUPD_TIME_UNKNOWN; - error("couldn't read current time to decide what files to clean"); - goto end; - } + return ret; } + progress_init_steps("clean", steps_in_clean); /* NOTE: Delete specific file patterns to avoid disasters in case some paths are * set incorrectly. */ @@ -393,6 +389,7 @@ enum swupd_code clean_main(int argc, char **argv) * and keeping all the staged files of the current version. This helps recovering the * current version. Or do it for the previous version to allow a rollback. */ ret = clean_statedir(options.dry_run, options.all); + /* TODO: Also print the bytes removed, need to take into account the hardlinks. */ if (options.dry_run) { print("Would remove %d files\n", stats.files_removed); @@ -400,11 +397,9 @@ enum swupd_code clean_main(int argc, char **argv) print("%d files removed\n", stats.files_removed); } -end: swupd_deinit(); - -exit: progress_finish_steps(ret); + return ret; } @@ -414,28 +409,35 @@ exit: * be removed but will not actually remove them. */ enum swupd_code clean_statedir(bool dry_run, bool all) { - + enum swupd_code ret; char *staged_dir = NULL; + + if (!all) { + if (clock_gettime(CLOCK_REALTIME, &now)) { + error("couldn't read current time to decide what files to clean\n\n"); + return SWUPD_TIME_UNKNOWN; + } + } + string_or_die(&staged_dir, "%s/staged", globals.state_dir); - int ret = remove_if(staged_dir, dry_run, is_fullfile); + ret = remove_if(staged_dir, dry_run, is_fullfile); free_string(&staged_dir); - if (ret != 0) { + if (ret != SWUPD_OK) { return ret; } /* Pack presence indicator files. */ ret = remove_if(globals.state_dir, dry_run, is_pack_indicator); - if (ret != 0) { + if (ret != SWUPD_OK) { return ret; } /* Manifest delta files. */ ret = remove_if(globals.state_dir, dry_run, is_manifest_delta); - if (ret != 0) { + if (ret != SWUPD_OK) { return ret; } /* NOTE: do not clean the state_dir/bundles directory */ - return clean_staged_manifests(globals.state_dir, dry_run, all); } diff --git a/src/swupd.h b/src/swupd.h index d9762634..b2524697 100644 --- a/src/swupd.h +++ b/src/swupd.h @@ -368,6 +368,9 @@ extern void bundle_list_set_option_all(bool opt); extern void bundle_list_set_option_has_dep(char *bundle); extern void bundle_list_set_option_deps(char *bundle); +/* clean.c */ +extern int clean_get_stats(void); + /* telemetry.c */ typedef enum telem_prio_t { TELEMETRY_DEBG = 1, diff --git a/src/swupd_internal.h b/src/swupd_internal.h index 3584546d..cf9ea906 100644 --- a/src/swupd_internal.h +++ b/src/swupd_internal.h @@ -34,6 +34,7 @@ enum swupd_code third_party_update_main(int argc, char **argv); enum swupd_code third_party_diagnose_main(int argc, char **argv); enum swupd_code third_party_repair_main(int argc, char **argv); enum swupd_code third_party_check_update_main(int argc, char **argv); +enum swupd_code third_party_clean_main(int argc, char **argv); /** * @brief Creates a new third-party repo under THIRDPARTY_REPO_PREFIX diff --git a/swupd.bash b/swupd.bash index a43d16d7..af536372 100644 --- a/swupd.bash +++ b/swupd.bash @@ -84,7 +84,7 @@ _swupd() opts="$global --version --manifest --fix --picky --picky-tree --picky-whitelist --install --quick --force --install " break;; ("3rd-party") - opts="$global add remove list bundle-add bundle-list bundle-remove bundle-info update diagnose repair check-update " + opts="$global add remove list bundle-add bundle-list bundle-remove bundle-info update diagnose repair check-update clean " break;; ("add") opts="$global --repo" @@ -157,6 +157,11 @@ _swupd() opts+="--repo" fi ;; + ("clean") + if [ "${COMP_WORDS[$i - 1]}" = "3rd-party" ]; then + opts+="--repo" + fi + ;; ("hashdump") # Add in filenames. TODO add in directory completion opts+=" $( compgen -f -- "$2" )" diff --git a/swupd.zsh b/swupd.zsh index a16345e0..5d3074fe 100644 --- a/swupd.zsh +++ b/swupd.zsh @@ -188,9 +188,9 @@ if [[ -n "$state" ]]; then 3rd-party) local -a thirdparty; thirdparty=( $global_opt - '(help)list[List third party repo(s)]' - '(help)remove[Remove third party repo]' - '(help)add[Add third party repo]' + '(help)list[List third party repositories]' + '(help)remove[Remove third party repository]' + '(help)add[Add third party repository]' '(help)bundle-add[Install a bundle from a third party repository]' '(help)bundle-remove[Uninstall a bundle from a third party repository]' '(help)bundle-list[List bundles from a third party repository]' @@ -199,6 +199,7 @@ if [[ -n "$state" ]]; then '(help)diagnose[Verify content from a third party repository]' '(help)repair[Repair local issues relative to a third party repository]' '(help)check-update[Check if a new version of a third party repository is available]' + '(help)clean[Clean cached files of a third party repository]' _arguments $thirdparty && ret=0 ;; add)