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.
* 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

View File

@ -852,27 +852,32 @@
<varlistentry>
<term><varname>SuccessExitStatus=</varname></term>
<listitem><para>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 <constant>SIGHUP</constant>,
<constant>SIGINT</constant>, <constant>SIGTERM</constant>, and
<constant>SIGPIPE</constant>. Exit status definitions can
either be numeric exit codes or termination signal names,
separated by spaces. For example:
<programlisting>SuccessExitStatus=1 2 8 SIGKILL</programlisting>
ensures that exit codes 1, 2, 8 and
the termination signal <constant>SIGKILL</constant> are
considered clean service terminations.
</para>
<listitem><para>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 <constant>SIGHUP</constant>, <constant>SIGINT</constant>,
<constant>SIGTERM</constant>, and <constant>SIGPIPE</constant>. 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
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
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
<citerefentry project='man-pages'><refentrytitle>signal</refentrytitle><manvolnum>7</manvolnum></citerefentry> for
a list of signal names.</para>
<para>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.</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>

View File

@ -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.");

View File

@ -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");