diff --git a/man/systemd-run.xml b/man/systemd-run.xml index 610c3acd37c..3a1d18dae9a 100644 --- a/man/systemd-run.xml +++ b/man/systemd-run.xml @@ -399,8 +399,13 @@ Exit status - On success, 0 is returned, a non-zero failure - code otherwise. + On success, 0 is returned. If systemd-run failed to start the service, a + non-zero return value will be returned. If systemd-run waits for the service to + terminate, the return value will be propagated from the service. 0 will be returned on success, including + all the cases where systemd considers a service to have exited cleanly, see the discussion of + SuccessExitStatus= in + systemd.service5. + @@ -503,6 +508,16 @@ There is a screen on: $ loginctl enable-linger + + + Return value + + $ systemd-run --user --wait true +$ systemd-run --user --wait -p SuccessExitStatus=11 bash -c 'exit 11' +$ systemd-run --user --wait -p SuccessExitStatus=SIGUSR1 bash -c 'kill -SIGUSR1 $$$$' + + Those three invocations will succeed, i.e. terminate with an exit code of 0. + diff --git a/src/run/run.c b/src/run/run.c index afa9d14af36..de968caf3f8 100644 --- a/src/run/run.c +++ b/src/run/run.c @@ -16,6 +16,7 @@ #include "bus-wait-for-jobs.h" #include "calendarspec.h" #include "env-util.h" +#include "exit-status.h" #include "fd-util.h" #include "format-util.h" #include "main-func.h" @@ -1256,7 +1257,7 @@ static int start_transient_service( if (arg_wait && !arg_quiet) { - /* Explicitly destroy the PTY forwarder, so that the PTY device is usable again, in its + /* Explicitly destroy the PTY forwarder, so that the PTY device is usable again, with its * original settings (i.e. proper line breaks), so that we can show the summary in a pretty * way. */ c.forward = pty_forward_free(c.forward); @@ -1265,43 +1266,52 @@ static int start_transient_service( log_info("Finished with result: %s", strna(c.result)); if (c.exit_code == CLD_EXITED) - log_info("Main processes terminated with: code=%s/status=%i", sigchld_code_to_string(c.exit_code), c.exit_status); + log_info("Main processes terminated with: code=%s/status=%i", + sigchld_code_to_string(c.exit_code), c.exit_status); else if (c.exit_code > 0) - log_info("Main processes terminated with: code=%s/status=%s", sigchld_code_to_string(c.exit_code), signal_to_string(c.exit_status)); + log_info("Main processes terminated with: code=%s/status=%s", + sigchld_code_to_string(c.exit_code), signal_to_string(c.exit_status)); if (timestamp_is_set(c.inactive_enter_usec) && timestamp_is_set(c.inactive_exit_usec) && c.inactive_enter_usec > c.inactive_exit_usec) { char ts[FORMAT_TIMESPAN_MAX]; - log_info("Service runtime: %s", format_timespan(ts, sizeof(ts), c.inactive_enter_usec - c.inactive_exit_usec, USEC_PER_MSEC)); + log_info("Service runtime: %s", + format_timespan(ts, sizeof ts, c.inactive_enter_usec - c.inactive_exit_usec, USEC_PER_MSEC)); } if (c.cpu_usage_nsec != NSEC_INFINITY) { char ts[FORMAT_TIMESPAN_MAX]; - log_info("CPU time consumed: %s", format_timespan(ts, sizeof(ts), (c.cpu_usage_nsec + NSEC_PER_USEC - 1) / NSEC_PER_USEC, USEC_PER_MSEC)); + log_info("CPU time consumed: %s", + format_timespan(ts, sizeof ts, (c.cpu_usage_nsec + NSEC_PER_USEC - 1) / NSEC_PER_USEC, USEC_PER_MSEC)); } if (c.ip_ingress_bytes != UINT64_MAX) { char bytes[FORMAT_BYTES_MAX]; - log_info("IP traffic received: %s", format_bytes(bytes, sizeof(bytes), c.ip_ingress_bytes)); + log_info("IP traffic received: %s", format_bytes(bytes, sizeof bytes, c.ip_ingress_bytes)); } if (c.ip_egress_bytes != UINT64_MAX) { char bytes[FORMAT_BYTES_MAX]; - log_info("IP traffic sent: %s", format_bytes(bytes, sizeof(bytes), c.ip_egress_bytes)); + log_info("IP traffic sent: %s", format_bytes(bytes, sizeof bytes, c.ip_egress_bytes)); } if (c.io_read_bytes != UINT64_MAX) { char bytes[FORMAT_BYTES_MAX]; - log_info("IO bytes read: %s", format_bytes(bytes, sizeof(bytes), c.io_read_bytes)); + log_info("IO bytes read: %s", format_bytes(bytes, sizeof bytes, c.io_read_bytes)); } if (c.io_write_bytes != UINT64_MAX) { char bytes[FORMAT_BYTES_MAX]; - log_info("IO bytes written: %s", format_bytes(bytes, sizeof(bytes), c.io_write_bytes)); + log_info("IO bytes written: %s", format_bytes(bytes, sizeof bytes, c.io_write_bytes)); } } - /* Try to propagate the service's return value */ - if (c.result && STR_IN_SET(c.result, "success", "exit-code") && c.exit_code == CLD_EXITED) + /* Try to propagate the service's return value. But if the service defines + * e.g. SuccessExitStatus, honour this, and return 0 to mean "success". */ + if (streq_ptr(c.result, "success")) + *retval = 0; + else if (streq_ptr(c.result, "exit-code") && c.exit_status > 0) *retval = c.exit_status; + else if (streq_ptr(c.result, "signal")) + *retval = EXIT_EXCEPTION; else *retval = EXIT_FAILURE; }