pid1,systemctl: allow symbolic exit code names

This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2019-07-28 12:37:31 +02:00
parent 62b21e2e89
commit 2e2ed88062
4 changed files with 54 additions and 46 deletions

3
TODO
View File

@ -220,9 +220,6 @@ Features:
* add --vacuum-xyz options to coredumpctl, matching those journalctl already has. * 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 * 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 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 removed after the unit goes down again. A bit like --ephemeral for

View File

@ -852,27 +852,32 @@
<varlistentry> <varlistentry>
<term><varname>SuccessExitStatus=</varname></term> <term><varname>SuccessExitStatus=</varname></term>
<listitem><para>Takes a list of exit status definitions that, <listitem><para>Takes a list of exit status definitions that, when returned by the main service
when returned by the main service process, will be considered process, will be considered successful termination, in addition to the normal successful exit code 0
successful termination, in addition to the normal successful and the signals <constant>SIGHUP</constant>, <constant>SIGINT</constant>,
exit code 0 and the signals <constant>SIGHUP</constant>, <constant>SIGTERM</constant>, and <constant>SIGPIPE</constant>. Exit status definitions can be
<constant>SIGINT</constant>, <constant>SIGTERM</constant>, and numeric exit codes, termination code names, or termination signal names, separated by spaces. See the
<constant>SIGPIPE</constant>. Exit status definitions can Process Exit Codes section in
either be numeric exit codes or termination signal names, <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
separated by spaces. For example: a list of termination codes names (for this setting only the part without the
<literal>EXIT_</literal> or <literal>EX_</literal> prefix should be used). See
<programlisting>SuccessExitStatus=1 2 8 SIGKILL</programlisting> <citerefentry project='man-pages'><refentrytitle>signal</refentrytitle><manvolnum>7</manvolnum></citerefentry> for
a list of signal names.</para>
ensures that exit codes 1, 2, 8 and
the termination signal <constant>SIGKILL</constant> are
considered clean service terminations.
</para>
<para>This option may appear more than once, in which case the <para>This option may appear more than once, in which case the
list of successful exit statuses is merged. If the empty list of successful exit statuses is merged. If the empty
string is assigned to this option, the list is reset, all string is assigned to this option, the list is reset, all
prior assignments of this option will have no prior assignments of this option will have no
effect.</para></listitem> effect.</para>
<example>
<title>A service with with the the <varname>SuccessExitStatus=</varname> setting</title>
<programlisting>SuccessExitStatus=TEMPFAIL 250 SIGUSR1</programlisting>
<para>Exit codes 75 (<constant>TEMPFAIL</constant>), 250, and the termination signal
<constant>SIGKILL</constant> are considered clean service terminations.</para>
</example></listitem>
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>

View File

@ -3936,33 +3936,33 @@ int config_parse_set_status(
FOREACH_WORD(word, l, rvalue, state) { FOREACH_WORD(word, l, rvalue, state) {
_cleanup_free_ char *temp; _cleanup_free_ char *temp;
int val;
Bitmap *bitmap; Bitmap *bitmap;
temp = strndup(word, l); temp = strndup(word, l);
if (!temp) if (!temp)
return log_oom(); return log_oom();
r = safe_atoi(temp, &val); /* We need to call exit_status_from_string() first, because we want
if (r < 0) { * to parse numbers as exit statuses, not signals. */
val = signal_from_string(temp);
if (val <= 0) { r = exit_status_from_string(temp);
log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse value, ignoring: %s", word); 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; continue;
} }
bitmap = &status_set->signal; 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) if (r < 0)
return log_oom(); return log_error_errno(r, "Failed to set signal or status %s: %m", word);
} }
if (!isempty(state)) if (!isempty(state))
log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring."); log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");

View File

@ -10,6 +10,7 @@
#include "cpu-set-util.h" #include "cpu-set-util.h"
#include "escape.h" #include "escape.h"
#include "exec-util.h" #include "exec-util.h"
#include "exit-status.h"
#include "hexdecoct.h" #include "hexdecoct.h"
#include "hostname-util.h" #include "hostname-util.h"
#include "in-addr-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;;) { for (p = eq;;) {
_cleanup_free_ char *word = NULL; _cleanup_free_ char *word = NULL;
int val;
r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE); r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
if (r == 0) if (r == 0)
@ -1454,24 +1454,30 @@ static int bus_append_service_property(sd_bus_message *m, const char *field, con
if (r < 0) if (r < 0)
return log_error_errno(r, "Invalid syntax in %s: %s", field, eq); return log_error_errno(r, "Invalid syntax in %s: %s", field, eq);
r = safe_atoi(word, &val); /* We need to call exit_status_from_string() first, because we want
if (r < 0) { * to parse numbers as exit statuses, not signals. */
val = signal_from_string(word);
if (val < 0)
return log_error_errno(r, "Invalid status or signal %s in %s: %m", word, field);
signal = reallocarray(signal, n_signal + 1, sizeof(int)); r = exit_status_from_string(word);
if (!signal) if (r >= 0) {
return log_oom(); assert(r >= 0 && r < 256);
signal[n_signal++] = val;
} else {
status = reallocarray(status, n_status + 1, sizeof(int)); status = reallocarray(status, n_status + 1, sizeof(int));
if (!status) if (!status)
return log_oom(); 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"); r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");