From: Lennart Poettering Date: Wed, 15 Feb 2023 09:51:33 +0000 (+0100) Subject: systemctl: add --kill-value= argument to systemctl X-Git-Tag: v254-rc1~1251^2~5 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=d06e61996d71f1600ec0bd88453f0ef043b5ca2b;p=thirdparty%2Fsystemd.git systemctl: add --kill-value= argument to systemctl This allows accompanying a signal with a value (as supported for Linux Realtime signals). This is particularly useful as it allows us to do stuff like this: systemctl kill --kill-whom=main --kill-value=0x300 systemd-journald In order to ask journald to flush its allocation caches and compact memory. --- diff --git a/src/systemctl/systemctl-kill.c b/src/systemctl/systemctl-kill.c index b3ae8bbcc29..c4c6096dc3d 100644 --- a/src/systemctl/systemctl-kill.c +++ b/src/systemctl/systemctl-kill.c @@ -8,7 +8,7 @@ int verb_kill(int argc, char *argv[], void *userdata) { _cleanup_strv_free_ char **names = NULL; - char *kill_whom = NULL; + const char *kill_whom; sd_bus *bus; int r, q; @@ -18,12 +18,11 @@ int verb_kill(int argc, char *argv[], void *userdata) { polkit_agent_open_maybe(); - if (!arg_kill_whom) - arg_kill_whom = "all"; + kill_whom = arg_kill_whom ?: "all"; /* --fail was specified */ if (streq(arg_job_mode(), "fail")) - kill_whom = strjoina(arg_kill_whom, "-fail"); + kill_whom = strjoina(kill_whom, "-fail"); r = expand_unit_names(bus, strv_skip(argv, 1), NULL, &names, NULL); if (r < 0) @@ -32,13 +31,22 @@ int verb_kill(int argc, char *argv[], void *userdata) { STRV_FOREACH(name, names) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; - q = bus_call_method( - bus, - bus_systemd_mgr, - "KillUnit", - &error, - NULL, - "ssi", *name, kill_whom ?: arg_kill_whom, arg_signal); + if (arg_kill_value_set) + q = bus_call_method( + bus, + bus_systemd_mgr, + "QueueSignalUnit", + &error, + NULL, + "ssii", *name, kill_whom, arg_signal, arg_kill_value); + else + q = bus_call_method( + bus, + bus_systemd_mgr, + "KillUnit", + &error, + NULL, + "ssi", *name, kill_whom, arg_signal); if (q < 0) { log_error_errno(q, "Failed to kill unit %s: %s", *name, bus_error_message(&error, q)); if (r == 0) diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 4e7fd0460c7..4732398dd79 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -97,6 +97,8 @@ UnitFilePresetMode arg_preset_mode = UNIT_FILE_PRESET_FULL; char **arg_wall = NULL; const char *arg_kill_whom = NULL; int arg_signal = SIGTERM; +int arg_kill_value; +bool arg_kill_value_set = false; char *arg_root = NULL; char *arg_image = NULL; usec_t arg_when = 0; @@ -273,6 +275,7 @@ static int systemctl_help(void) { " sleeping, or hibernating\n" " -i Shortcut for --check-inhibitors=no\n" " --kill-whom=WHOM Whom to send signal to\n" + " --kill-value=INT Signal value to enqueue\n" " -s --signal=SIGNAL Which signal to send\n" " --what=RESOURCES Which types of resources to remove\n" " --now Start or stop unit after enabling or disabling it\n" @@ -419,6 +422,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) { ARG_IMAGE, ARG_NO_RELOAD, ARG_KILL_WHOM, + ARG_KILL_VALUE, ARG_NO_ASK_PASSWORD, ARG_FAILED, ARG_RUNTIME, @@ -479,6 +483,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) { { "force", no_argument, NULL, 'f' }, { "no-reload", no_argument, NULL, ARG_NO_RELOAD }, { "kill-whom", required_argument, NULL, ARG_KILL_WHOM }, + { "kill-value", required_argument, NULL, ARG_KILL_VALUE }, { "signal", required_argument, NULL, 's' }, { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD }, { "host", required_argument, NULL, 'H' }, @@ -723,6 +728,30 @@ static int systemctl_parse_argv(int argc, char *argv[]) { arg_kill_whom = optarg; break; + case ARG_KILL_VALUE: { + unsigned u; + + if (isempty(optarg)) { + arg_kill_value_set = false; + return 0; + } + + /* First, try to parse unsigned, so that we can support the prefixes 0x, 0o, 0b */ + r = safe_atou_full(optarg, 0, &u); + if (r < 0) + /* If this didn't work, try as signed integer, without those prefixes */ + r = safe_atoi(optarg, &arg_kill_value); + else if (u > INT_MAX) + r = -ERANGE; + else + arg_kill_value = (int) u; + if (r < 0) + return log_error_errno(r, "Unable to parse signal queue value: %s", optarg); + + arg_kill_value_set = true; + break; + } + case 's': r = parse_signal_argument(optarg, &arg_signal); if (r <= 0) diff --git a/src/systemctl/systemctl.h b/src/systemctl/systemctl.h index 9f9b8faa696..59da9e3ddbb 100644 --- a/src/systemctl/systemctl.h +++ b/src/systemctl/systemctl.h @@ -77,6 +77,8 @@ extern UnitFilePresetMode arg_preset_mode; extern char **arg_wall; extern const char *arg_kill_whom; extern int arg_signal; +extern int arg_kill_value; +extern bool arg_kill_value_set; extern char *arg_root; extern usec_t arg_when; extern const char *arg_reboot_argument;