From 2e2ed88062fcd4fbe138a5198a979ccdea4fb11c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Sun, 28 Jul 2019 12:37:31 +0200 Subject: [PATCH] pid1,systemctl: allow symbolic exit code names --- TODO | 3 --- man/systemd.service.xml | 37 +++++++++++++++++++++---------------- src/core/load-fragment.c | 28 ++++++++++++++-------------- src/shared/bus-unit-util.c | 32 +++++++++++++++++++------------- 4 files changed, 54 insertions(+), 46 deletions(-) diff --git a/TODO b/TODO index af41aa57ac..ae52d9fc3b 100644 --- a/TODO +++ b/TODO @@ -220,9 +220,6 @@ Features: * add --vacuum-xyz options to coredumpctl, matching those journalctl already has. -* SuccessExitStatus= and friends should probably also accept symbolic exit - codes names, i.e. error codes from the list maintained in exit-codes.[ch] - * introduce Ephemeral= unit file switch, that creates an ephemeral copy of all files and directories that are left writable for a unit, and which are removed after the unit goes down again. A bit like --ephemeral for diff --git a/man/systemd.service.xml b/man/systemd.service.xml index 90c1257f37..06116df1b0 100644 --- a/man/systemd.service.xml +++ b/man/systemd.service.xml @@ -852,27 +852,32 @@ SuccessExitStatus= - Takes a list of exit status definitions that, - when returned by the main service process, will be considered - successful termination, in addition to the normal successful - exit code 0 and the signals SIGHUP, - SIGINT, SIGTERM, and - SIGPIPE. Exit status definitions can - either be numeric exit codes or termination signal names, - separated by spaces. For example: - - SuccessExitStatus=1 2 8 SIGKILL - - ensures that exit codes 1, 2, 8 and - the termination signal SIGKILL are - considered clean service terminations. - + Takes a list of exit status definitions that, when returned by the main service + process, will be considered successful termination, in addition to the normal successful exit code 0 + and the signals SIGHUP, SIGINT, + SIGTERM, and SIGPIPE. Exit status definitions can be + numeric exit codes, termination code names, or termination signal names, separated by spaces. See the + Process Exit Codes section in + systemd.exec5 for + a list of termination codes names (for this setting only the part without the + EXIT_ or EX_ prefix should be used). See + signal7 for + a list of signal names. This option may appear more than once, in which case the list of successful exit statuses is merged. If the empty string is assigned to this option, the list is reset, all prior assignments of this option will have no - effect. + effect. + + + A service with with the the <varname>SuccessExitStatus=</varname> setting + + SuccessExitStatus=TEMPFAIL 250 SIGUSR1 + + Exit codes 75 (TEMPFAIL), 250, and the termination signal + SIGKILL are considered clean service terminations. + diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index ecea4f526a..8664500e1d 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -3936,33 +3936,33 @@ int config_parse_set_status( FOREACH_WORD(word, l, rvalue, state) { _cleanup_free_ char *temp; - int val; Bitmap *bitmap; temp = strndup(word, l); if (!temp) return log_oom(); - r = safe_atoi(temp, &val); - if (r < 0) { - val = signal_from_string(temp); + /* We need to call exit_status_from_string() first, because we want + * to parse numbers as exit statuses, not signals. */ - if (val <= 0) { - log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse value, ignoring: %s", word); + r = exit_status_from_string(temp); + if (r >= 0) { + assert(r >= 0 && r < 256); + bitmap = &status_set->status; + } else { + r = signal_from_string(temp); + + if (r <= 0) { + log_syntax(unit, LOG_ERR, filename, line, 0, + "Failed to parse value, ignoring: %s", word); continue; } bitmap = &status_set->signal; - } else { - if (val < 0 || val > 255) { - log_syntax(unit, LOG_ERR, filename, line, 0, "Value %d is outside range 0-255, ignoring", val); - continue; - } - bitmap = &status_set->status; } - r = bitmap_set(bitmap, val); + r = bitmap_set(bitmap, r); if (r < 0) - return log_oom(); + return log_error_errno(r, "Failed to set signal or status %s: %m", word); } if (!isempty(state)) log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring."); diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 99511d338a..e53b9d5ea2 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -10,6 +10,7 @@ #include "cpu-set-util.h" #include "escape.h" #include "exec-util.h" +#include "exit-status.h" #include "hexdecoct.h" #include "hostname-util.h" #include "in-addr-util.h" @@ -1444,7 +1445,6 @@ static int bus_append_service_property(sd_bus_message *m, const char *field, con for (p = eq;;) { _cleanup_free_ char *word = NULL; - int val; r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE); if (r == 0) @@ -1454,24 +1454,30 @@ static int bus_append_service_property(sd_bus_message *m, const char *field, con if (r < 0) return log_error_errno(r, "Invalid syntax in %s: %s", field, eq); - r = safe_atoi(word, &val); - if (r < 0) { - val = signal_from_string(word); - if (val < 0) - return log_error_errno(r, "Invalid status or signal %s in %s: %m", word, field); + /* We need to call exit_status_from_string() first, because we want + * to parse numbers as exit statuses, not signals. */ - signal = reallocarray(signal, n_signal + 1, sizeof(int)); - if (!signal) - return log_oom(); + r = exit_status_from_string(word); + if (r >= 0) { + assert(r >= 0 && r < 256); - signal[n_signal++] = val; - } else { status = reallocarray(status, n_status + 1, sizeof(int)); if (!status) return log_oom(); - status[n_status++] = val; - } + status[n_status++] = r; + + } else if ((r = signal_from_string(word)) >= 0) { + signal = reallocarray(signal, n_signal + 1, sizeof(int)); + if (!signal) + return log_oom(); + + signal[n_signal++] = r; + + } else + /* original r from exit_status_to_string() */ + return log_error_errno(r, "Invalid status or signal %s in %s: %m", + word, field); } r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");