]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
systemctl: Implement --wait for kill command
authorDaan De Meyer <daan.j.demeyer@gmail.com>
Tue, 30 Apr 2024 20:03:00 +0000 (22:03 +0200)
committerDaan De Meyer <daan.j.demeyer@gmail.com>
Wed, 1 May 2024 07:40:32 +0000 (09:40 +0200)
TEST-26-SYSTEMCTL is racy as we call systemctl is-active immediately
after systemctl kill. Let's implement --wait for systemctl kill and
use it in TEST-26-SYSTEMCTL to avoid the race.

NEWS
man/systemctl.xml
src/systemctl/systemctl-kill.c
src/systemctl/systemctl.c
test/units/testsuite-26.sh

diff --git a/NEWS b/NEWS
index ba206afdfbc50ba3d1112bd8cb18123673d3006f..0259d79d763820611f089f49eb250ba85aca49aa 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -258,6 +258,9 @@ CHANGES WITH 256-rc1:
           that configures what to do after the system manager (PID 1) crashes.
           This can also be configured through CrashAction= in systemd.conf.
 
+        * "systemctl kill" now supports --wait which will make the command wait
+          until the signalled services terminate.
+
         Journal:
 
         * systemd-journald can now forward journal entries to a socket
index a68ff5c958bd4a62148192708b0898f4ed06fb26..287decffb219b0952caf04b313dccd4aaeeb48ac 100644 (file)
@@ -2377,14 +2377,16 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
         <term><option>--wait</option></term>
 
         <listitem>
-          <para>Synchronously wait for started units to terminate again.
-          This option may not be combined with <option>--no-block</option>.
-          Note that this will wait forever if any given unit never terminates
-          (by itself or by getting stopped explicitly); particularly services
-          which use <literal>RemainAfterExit=yes</literal>.</para>
-
-          <para>When used with <command>is-system-running</command>, wait
-          until the boot process is completed before returning.</para>
+          <para>When used with <command>start</command> or <command>restart</command>, synchronously wait for
+          started units to terminate again. This option may not be combined with <option>--no-block</option>.
+          Note that this will wait forever if any given unit never terminates (by itself or by getting
+          stopped explicitly); particularly services which use <literal>RemainAfterExit=yes</literal>.</para>
+
+          <para>When used with <command>is-system-running</command>, wait until the boot process is completed
+          before returning.</para>
+
+          <para>When used with <command>kill</command>, wait until the signalled units terminate. Note that
+          this will wait forever if any given unit never terminates.</para>
 
           <xi:include href="version-info.xml" xpointer="v232"/>
         </listitem>
index c4c6096dc3d68adbd9e3a90e2d569b31ee1ab7dd..4c1829e0c68668e7b7e92417a818a028eceab507 100644 (file)
@@ -2,11 +2,13 @@
 
 #include "bus-error.h"
 #include "bus-locator.h"
+#include "bus-wait-for-units.h"
 #include "systemctl-kill.h"
 #include "systemctl-util.h"
 #include "systemctl.h"
 
 int verb_kill(int argc, char *argv[], void *userdata) {
+        _cleanup_(bus_wait_for_units_freep) BusWaitForUnits *w = NULL;
         _cleanup_strv_free_ char **names = NULL;
         const char *kill_whom;
         sd_bus *bus;
@@ -16,6 +18,12 @@ int verb_kill(int argc, char *argv[], void *userdata) {
         if (r < 0)
                 return r;
 
+        if (arg_wait) {
+                r = bus_wait_for_units_new(bus, &w);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to allocate unit watch context: %m");
+        }
+
         polkit_agent_open_maybe();
 
         kill_whom = arg_kill_whom ?: "all";
@@ -48,11 +56,24 @@ int verb_kill(int argc, char *argv[], void *userdata) {
                                         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)
-                                r = q;
+                        RET_GATHER(r, log_error_errno(q, "Failed to kill unit %s: %s", *name, bus_error_message(&error, q)));
+                        continue;
+                }
+
+                if (w) {
+                        q = bus_wait_for_units_add_unit(w, *name, BUS_WAIT_FOR_INACTIVE|BUS_WAIT_NO_JOB, NULL, NULL);
+                        if (q < 0)
+                                RET_GATHER(r, log_error_errno(q, "Failed to watch unit %s: %m", *name));
                 }
         }
 
+        if (w) {
+                q = bus_wait_for_units_run(w);
+                if (q < 0)
+                        return log_error_errno(q, "Failed to wait for units: %m");
+                if (q == BUS_WAIT_FAILURE)
+                        RET_GATHER(r, -EIO);
+        }
+
         return r;
 }
index f159844c5eb464d742dbc155dbe698938487de2f..0ca76ac23dbf58831e6313342c3fd0e2c8bf3187 100644 (file)
@@ -305,6 +305,7 @@ static int systemctl_help(void) {
                "     --no-warn           Suppress several warnings shown by default\n"
                "     --wait              For (re)start, wait until service stopped again\n"
                "                         For is-system-running, wait until startup is completed\n"
+               "                         For kill, wait until service stopped\n"
                "     --no-block          Do not wait until operation finished\n"
                "     --no-wall           Don't send wall message before halt/power-off/reboot\n"
                "     --message=MESSAGE   Specify human readable reason for system shutdown\n"
index 61b0ffd8126902b6accd4f60441ba9e170cd03c5..117ffb81f31b74e9c920b9c86612f619a5122946 100755 (executable)
@@ -141,7 +141,7 @@ systemctl reload -T "$UNIT_NAME"
 systemctl restart -T "$UNIT_NAME"
 systemctl try-restart --show-transaction "$UNIT_NAME"
 systemctl try-reload-or-restart --show-transaction "$UNIT_NAME"
-systemctl kill "$UNIT_NAME"
+timeout 10 systemctl kill --wait "$UNIT_NAME"
 (! systemctl is-active "$UNIT_NAME")
 systemctl restart "$UNIT_NAME"
 systemctl is-active "$UNIT_NAME"