]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
systemctl: add --kill-value= argument to systemctl
authorLennart Poettering <lennart@poettering.net>
Wed, 15 Feb 2023 09:51:33 +0000 (10:51 +0100)
committerLennart Poettering <lennart@poettering.net>
Fri, 17 Feb 2023 08:55:35 +0000 (09:55 +0100)
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.

src/systemctl/systemctl-kill.c
src/systemctl/systemctl.c
src/systemctl/systemctl.h

index b3ae8bbcc29f3a3ca2b9f7caf2c2ccb07b975b53..c4c6096dc3d68adbd9e3a90e2d569b31ee1ab7dd 100644 (file)
@@ -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)
index 4e7fd0460c78eebcc3e74354098be239469811b1..4732398dd79a13bc643238881452e65a50b38ddc 100644 (file)
@@ -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)
index 9f9b8faa6963e36125a73f73f7729c378e12dafb..59da9e3ddbb6939d6837396580929d47da6d9a40 100644 (file)
@@ -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;