From d81bc51fe32f1e77d3ebb2ad1aa0dced3c35e558 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 1 Apr 2019 18:57:46 +0200 Subject: [PATCH] systemctl: add new "clean" operation to systemctl This exposes the CleanUnit() bus calls in systemctl, i.e. makes all the infrastructure we previously added useful to people. --- src/systemctl/systemctl.c | 136 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index b7de0107048..616ac0f5d47 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -28,6 +28,7 @@ #include "bus-unit-util.h" #include "bus-util.h" #include "bus-wait-for-jobs.h" +#include "bus-wait-for-units.h" #include "cgroup-show.h" #include "cgroup-util.h" #include "copy.h" @@ -162,12 +163,14 @@ static const char *arg_boot_loader_entry = NULL; static bool arg_now = false; static bool arg_jobs_before = false; static bool arg_jobs_after = false; +static char **arg_clean_what = NULL; STATIC_DESTRUCTOR_REGISTER(arg_wall, strv_freep); STATIC_DESTRUCTOR_REGISTER(arg_root, freep); STATIC_DESTRUCTOR_REGISTER(arg_types, strv_freep); STATIC_DESTRUCTOR_REGISTER(arg_states, strv_freep); STATIC_DESTRUCTOR_REGISTER(arg_properties, strv_freep); +STATIC_DESTRUCTOR_REGISTER(arg_clean_what, strv_freep); static int daemon_reload(int argc, char *argv[], void* userdata); static int trivial_method(int argc, char *argv[], void *userdata); @@ -3951,6 +3954,101 @@ static int kill_unit(int argc, char *argv[], void *userdata) { return r; } +static int clean_unit(int argc, char *argv[], void *userdata) { + _cleanup_(bus_wait_for_units_freep) BusWaitForUnits *w = NULL; + _cleanup_strv_free_ char **names = NULL; + int r, ret = EXIT_SUCCESS; + char **name; + sd_bus *bus; + + r = acquire_bus(BUS_FULL, &bus); + if (r < 0) + return r; + + polkit_agent_open_maybe(); + + if (!arg_clean_what) { + arg_clean_what = strv_new("cache", "runtime"); + if (!arg_clean_what) + return log_oom(); + } + + r = expand_names(bus, strv_skip(argv, 1), NULL, &names); + if (r < 0) + return log_error_errno(r, "Failed to expand names: %m"); + + if (!arg_no_block) { + r = bus_wait_for_units_new(bus, &w); + if (r < 0) + return log_error_errno(r, "Failed to allocate unit waiter: %m"); + } + + STRV_FOREACH(name, names) { + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; + + if (w) { + /* If we shall wait for the cleaning to complete, let's add a ref on the unit first */ + r = sd_bus_call_method( + bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "RefUnit", + &error, + NULL, + "s", *name); + if (r < 0) { + log_error_errno(r, "Failed to add reference to unit %s: %s", *name, bus_error_message(&error, r)); + if (ret == EXIT_SUCCESS) + ret = r; + continue; + } + } + + r = sd_bus_message_new_method_call( + bus, + &m, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "CleanUnit"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append(m, "s", *name); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append_strv(m, arg_clean_what); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_call(bus, m, 0, &error, NULL); + if (r < 0) { + log_error_errno(r, "Failed to clean unit %s: %s", *name, bus_error_message(&error, r)); + if (ret == EXIT_SUCCESS) { + ret = r; + continue; + } + } + + if (w) { + r = bus_wait_for_units_add_unit(w, *name, BUS_WAIT_REFFED|BUS_WAIT_FOR_MAINTENANCE_END, NULL, NULL); + if (r < 0) + return log_error_errno(r, "Failed to watch unit %s: %m", *name); + } + } + + r = bus_wait_for_units_run(w); + if (r < 0) + return log_error_errno(r, "Failed to wait for units: %m"); + if (r == BUS_WAIT_FAILURE) + ret = EXIT_FAILURE; + + return ret; +} + typedef struct ExecStatusInfo { char *name; @@ -7712,6 +7810,7 @@ static int systemctl_help(void) { " When shutting down or sleeping, ignore inhibitors\n" " --kill-who=WHO Who to send signal to\n" " -s --signal=SIGNAL Which signal to send\n" + " --what=RESOURCES Which types of resources to remove\n" " --now Start or stop unit in addition to enabling or disabling it\n" " --dry-run Only print what would be done\n" " -q --quiet Suppress output\n" @@ -7760,6 +7859,8 @@ static int systemctl_help(void) { " if supported, otherwise restart\n" " isolate UNIT Start one unit and stop all others\n" " kill UNIT... Send signal to processes of a unit\n" + " clean UNIT... Clean runtime, cache, state, logs or\n" + " or configuration of unit\n" " is-active PATTERN... Check whether units are active\n" " is-failed PATTERN... Check whether units are failed\n" " status [PATTERN...|PID...] Show runtime status of one or more units\n" @@ -8063,6 +8164,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) { ARG_NOW, ARG_MESSAGE, ARG_WAIT, + ARG_WHAT, }; static const struct option options[] = { @@ -8114,6 +8216,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) { { "now", no_argument, NULL, ARG_NOW }, { "message", required_argument, NULL, ARG_MESSAGE }, { "show-transaction", no_argument, NULL, 'T' }, + { "what", required_argument, NULL, ARG_WHAT }, {} }; @@ -8466,6 +8569,38 @@ static int systemctl_parse_argv(int argc, char *argv[]) { arg_show_transaction = true; break; + case ARG_WHAT: { + const char *p; + + if (isempty(optarg)) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "--what= requires arguments."); + + for (p = optarg;;) { + _cleanup_free_ char *k = NULL; + + r = extract_first_word(&p, &k, ",", 0); + if (r < 0) + return log_error_errno(r, "Failed to parse directory type: %s", optarg); + if (r == 0) + break; + + if (streq(k, "help")) { + puts("runtime\n" + "state\n" + "cache\n" + "logs\n" + "configuration"); + return 0; + } + + r = strv_consume(&arg_clean_what, TAKE_PTR(k)); + if (r < 0) + return log_oom(); + } + + break; + } + case '.': /* Output an error mimicking getopt, and print a hint afterwards */ log_error("%s: invalid option -- '.'", program_invocation_name); @@ -8912,6 +9047,7 @@ static int systemctl_main(int argc, char *argv[]) { { "condrestart", 2, VERB_ANY, VERB_ONLINE_ONLY, start_unit }, /* For compatibility with RH */ { "isolate", 2, 2, VERB_ONLINE_ONLY, start_unit }, { "kill", 2, VERB_ANY, VERB_ONLINE_ONLY, kill_unit }, + { "clean", 2, VERB_ANY, VERB_ONLINE_ONLY, clean_unit }, { "is-active", 2, VERB_ANY, VERB_ONLINE_ONLY, check_unit_active }, { "check", 2, VERB_ANY, VERB_ONLINE_ONLY, check_unit_active }, /* deprecated alias of is-active */ { "is-failed", 2, VERB_ANY, VERB_ONLINE_ONLY, check_unit_failed }, -- 2.47.3