<div dir="ltr"><div><div></div>The capability of directly propagating a return code out to the caller of systemd --user from within something like an OnFailure unit has utility.<br><br></div><div>This also contains a minor fixup to the documentation adding "exit" to the --force section.<br><br></div>Cheers,<br>Vito Caputo<br><br><div><div>---<br> man/systemctl.xml         | 11 ++++++-----<br> src/core/dbus-manager.c   |  6 +++++-<br> src/core/main.c           |  2 +-<br> src/core/manager.c        |  1 +<br> src/core/manager.h        |  1 +<br> src/systemctl/systemctl.c | 20 ++++++++++++++++++--<br> 6 files changed, 32 insertions(+), 9 deletions(-)<br><br>diff --git a/man/systemctl.xml b/man/systemctl.xml<br>index 7cbaa6c..25ad2f7 100644<br>--- a/man/systemctl.xml<br>+++ b/man/systemctl.xml<br>@@ -432,9 +432,9 @@ along with systemd; If not, see <<a href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>>.<br>           <para>When used with <command>enable</command>, overwrite<br>           any existing conflicting symlinks.</para><br><br>-          <para>When used with <command>halt</command>,<br>-          <command>poweroff</command>, <command>reboot</command> or<br>-          <command>kexec</command>, execute the selected operation<br>+         <para>When used with <command>exit</command>, <command>halt</command>,<br>+         <command>poweroff</command>, <command>reboot</command> or<br>+         <command>kexec</command>, execute the selected operation<br>           without shutting down all units. However, all processes will<br>           be killed forcibly and all file systems are unmounted or<br>           remounted read-only. This is hence a drastic but relatively<br>@@ -1485,13 +1485,14 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service<br>           </listitem><br>         </varlistentry><br>         <varlistentry><br>-          <term><command>exit</command></term><br>+          <term><command>exit <optional><replaceable>STATUS</replaceable></optional></command></term><br><br>           <listitem><br>             <para>Ask the systemd manager to quit. This is only<br>             supported for user service managers (i.e. in conjunction<br>             with the <option>--user</option> option) and will fail<br>-            otherwise.</para><br>+            otherwise.  Used in conjunction with --force a status code may be<br>+           propagated into the sytemd manager's exit code.</para><br>           </listitem><br><br>         </varlistentry><br>diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c<br>index c54abd3..78f7f6d 100644<br>--- a/src/core/dbus-manager.c<br>+++ b/src/core/dbus-manager.c<br>@@ -1140,6 +1140,10 @@ static int method_exit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_<br>         if (m->running_as == SYSTEMD_SYSTEM)<br>                 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Exit is only supported for user service managers.");<br><br>+        r = sd_bus_message_read(message, "i", &m->exit_retval);<br>+        if (r < 0)<br>+                return r;<br>+<br>         m->exit_code = MANAGER_EXIT;<br><br>         return sd_bus_reply_method_return(message, NULL);<br>@@ -1918,7 +1922,7 @@ const sd_bus_vtable bus_manager_vtable[] = {<br>         SD_BUS_METHOD("RemoveSnapshot", "s", NULL, method_remove_snapshot, 0),<br>         SD_BUS_METHOD("Reload", NULL, NULL, method_reload, SD_BUS_VTABLE_UNPRIVILEGED),<br>         SD_BUS_METHOD("Reexecute", NULL, NULL, method_reexecute, SD_BUS_VTABLE_UNPRIVILEGED),<br>-        SD_BUS_METHOD("Exit", NULL, NULL, method_exit, 0),<br>+        SD_BUS_METHOD("Exit", "i", NULL, method_exit, 0),<br>         SD_BUS_METHOD("Reboot", NULL, NULL, method_reboot, SD_BUS_VTABLE_CAPABILITY(CAP_SYS_BOOT)),<br>         SD_BUS_METHOD("PowerOff", NULL, NULL, method_poweroff, SD_BUS_VTABLE_CAPABILITY(CAP_SYS_BOOT)),<br>         SD_BUS_METHOD("Halt", NULL, NULL, method_halt, SD_BUS_VTABLE_CAPABILITY(CAP_SYS_BOOT)),<br>diff --git a/src/core/main.c b/src/core/main.c<br>index d48604e..2481f5c 100644<br>--- a/src/core/main.c<br>+++ b/src/core/main.c<br>@@ -1737,7 +1737,7 @@ int main(int argc, char *argv[]) {<br>                 switch (m->exit_code) {<br><br>                 case MANAGER_EXIT:<br>-                        retval = EXIT_SUCCESS;<br>+                        retval = m->exit_retval;<br>                         log_debug("Exit.");<br>                         goto finish;<br><br>diff --git a/src/core/manager.c b/src/core/manager.c<br>index 129f6dd..e417514 100644<br>--- a/src/core/manager.c<br>+++ b/src/core/manager.c<br>@@ -550,6 +550,7 @@ int manager_new(SystemdRunningAs running_as, bool test_run, Manager **_m) {<br><br>         m->running_as = running_as;<br>         m->exit_code = _MANAGER_EXIT_CODE_INVALID;<br>+        m->exit_retval = EXIT_SUCCESS;<br>         m->default_timer_accuracy_usec = USEC_PER_MINUTE;<br><br>         m->idle_pipe[0] = m->idle_pipe[1] = m->idle_pipe[2] = m->idle_pipe[3] = -1;<br>diff --git a/src/core/manager.h b/src/core/manager.h<br>index ab72548..ef96e03 100644<br>--- a/src/core/manager.h<br>+++ b/src/core/manager.h<br>@@ -232,6 +232,7 @@ struct Manager {<br>         /* Flags */<br>         SystemdRunningAs running_as;<br>         ManagerExitCode exit_code:5;<br>+        int exit_retval;<br><br>         bool dispatching_load_queue:1;<br>         bool dispatching_dbus_queue:1;<br>diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c<br>index d9e9c2a..11c7e55 100644<br>--- a/src/systemctl/systemctl.c<br>+++ b/src/systemctl/systemctl.c<br>@@ -4875,6 +4875,22 @@ static int daemon_reload(sd_bus *bus, char **args) {<br>         if (r < 0)<br>                 return bus_log_create_error(r);<br><br>+        if (streq(method, "Exit")) {<br>+                int retval = EXIT_SUCCESS;<br>+<br>+                if (strv_length(args) > 1) {<br>+                        r = safe_atoi(args[1], &retval);<br>+                        if (r < 0) {<br>+                                log_error("Invalid exit status: %s", strerror(-r));<br>+                                return -EINVAL;<br>+                        }<br>+                }<br>+<br>+                r = sd_bus_message_append(m, "i", retval);<br>+                if (r < 0)<br>+                        return bus_log_create_error(r);<br>+        }<br>+<br>         r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);<br>         if (r < 0)<br>                 return bus_log_create_error(r);<br>@@ -5849,7 +5865,7 @@ static void systemctl_help(void) {<br>                "  poweroff                        Shut down and power-off the system\n"<br>                "  reboot [ARG]                    Shut down and reboot the system\n"<br>                "  kexec                           Shut down and reboot the system with kexec\n"<br>-               "  exit                            Request user instance exit\n"<br>+               "  exit [STATUS]                   Request user instance exit\n"<br>                "  switch-root ROOT [INIT]         Change to a different root file system\n"<br>                "  suspend                         Suspend the system\n"<br>                "  hibernate                       Hibernate the system\n"<br>@@ -6815,7 +6831,7 @@ static int systemctl_main(sd_bus *bus, int argc, char *argv[], int bus_error) {<br>                 { "default",               EQUAL, 1, start_special     },<br>                 { "rescue",                EQUAL, 1, start_special     },<br>                 { "emergency",             EQUAL, 1, start_special     },<br>-                { "exit",                  EQUAL, 1, start_special     },<br>+                { "exit",                  LESS,  2, start_special     },<br>                 { "reset-failed",          MORE,  1, reset_failed      },<br>                 { "enable",                MORE,  2, enable_unit,      NOBUS },<br>                 { "disable",               MORE,  2, enable_unit,      NOBUS },<br>--<br>2.1.1<br><br></div></div></div>