Skip to content

Commit

Permalink
Merge pull request #4745 from joukewitteveen/notify
Browse files Browse the repository at this point in the history
Improvements for notify services (including #4212)
  • Loading branch information
evverx committed Nov 30, 2016
2 parents e7330df + 6375bd2 commit 97506e8
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 13 deletions.
4 changes: 4 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ CHANGES WITH 233 in spe
The 'n' choice for the confirmation spawn prompt has been removed,
because its meaning was confusing.

* Services of Type=notify require a READY=1 notification to be sent
during startup. If no such message is sent, the service now fails,
even if the main process exited with a successful exit code.

CHANGES WITH 232:

* The new RemoveIPC= option can be used to remove IPC objects owned by
Expand Down
6 changes: 3 additions & 3 deletions man/systemd.exec.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1772,9 +1772,9 @@
<listitem><para>Only defined for the service unit type, this environment variable is passed to all
<varname>ExecStop=</varname> and <varname>ExecStopPost=</varname> processes, and encodes the service
"result". Currently, the following values are defined: <literal>protocol</literal> (in case of a protocol
violation; if a service did not take the steps required by its configuration), <literal>timeout</literal> (in
case of an operation timeout), <literal>exit-code</literal> (if a service process exited with a non-zero exit
code; see <varname>$EXIT_CODE</varname> below for the actual exit code returned), <literal>signal</literal>
violation; if a service did not take the steps required by its unit configuration), <literal>timeout</literal>
(in case of an operation timeout), <literal>exit-code</literal> (if a service process exited with a non-zero
exit code; see <varname>$EXIT_CODE</varname> below for the actual exit code returned), <literal>signal</literal>
(if a service process was terminated abnormally by a signal; see <varname>$EXIT_CODE</varname> below for the
actual signal used for the termination), <literal>core-dump</literal> (if a service process terminated
abnormally and dumped core), <literal>watchdog</literal> (if the watchdog keep-alive ping was enabled for the
Expand Down
13 changes: 8 additions & 5 deletions man/systemd.service.xml
Original file line number Diff line number Diff line change
Expand Up @@ -798,11 +798,14 @@
notification socket, as accessible via the
<citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>
call. Takes one of <option>none</option> (the default),
<option>main</option> or <option>all</option>. If
<option>none</option>, no daemon status updates are accepted
from the service processes, all status update messages are
ignored. If <option>main</option>, only service updates sent
from the main process of the service are accepted. If
<option>main</option>, <option>exec</option> or
<option>all</option>. If <option>none</option>, no daemon status
updates are accepted from the service processes, all status
update messages are ignored. If <option>main</option>, only
service updates sent from the main process of the service are
accepted. If <option>exec</option>, only service updates sent
from any of the control processes originating from one of the
<varname>Exec*=</varname> commands are accepted. If
<option>all</option>, all services updates from all members of
the service's control group are accepted. This option should
be set to open access to the notification socket when using
Expand Down
48 changes: 43 additions & 5 deletions src/core/service.c
Original file line number Diff line number Diff line change
Expand Up @@ -1179,6 +1179,25 @@ static int service_collect_fds(Service *s, int **fds, char ***fd_names) {
return rn_fds;
}

static bool service_exec_needs_notify_socket(Service *s, ExecFlags flags) {
assert(s);

/* Notifications are accepted depending on the process and
* the access setting of the service:
* process: \ access: NONE MAIN EXEC ALL
* main no yes yes yes
* control no no yes yes
* other (forked) no no no yes */

if (flags & EXEC_IS_CONTROL)
/* A control process */
return IN_SET(s->notify_access, NOTIFY_EXEC, NOTIFY_ALL);

/* We only spawn main processes and control processes, so any
* process that is not a control process is a main process */
return s->notify_access != NOTIFY_NONE;
}

static int service_spawn(
Service *s,
ExecCommand *c,
Expand Down Expand Up @@ -1252,7 +1271,7 @@ static int service_spawn(
if (!our_env)
return -ENOMEM;

if ((flags & EXEC_IS_CONTROL) ? s->notify_access == NOTIFY_ALL : s->notify_access != NOTIFY_NONE)
if (service_exec_needs_notify_socket(s, flags))
if (asprintf(our_env + n_env++, "NOTIFY_SOCKET=%s", UNIT(s)->manager->notify_socket) < 0)
return -ENOMEM;

Expand Down Expand Up @@ -2579,11 +2598,16 @@ static void service_notify_cgroup_empty_event(Unit *u) {
* SIGCHLD for. */

case SERVICE_START:
case SERVICE_START_POST:
if (s->type == SERVICE_NOTIFY)
if (s->type == SERVICE_NOTIFY) {
/* No chance of getting a ready notification anymore */
service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_PROTOCOL);
else if (s->pid_file_pathspec) {
break;
}

/* Fall through */

case SERVICE_START_POST:
if (s->pid_file_pathspec) {
/* Give up hoping for the daemon to write its PID file */
log_unit_warning(u, "Daemon never wrote its PID file. Failing.");

Expand Down Expand Up @@ -3056,7 +3080,18 @@ static void service_notify_message(Unit *u, pid_t pid, char **tags, FDSet *fds)
if (s->main_pid != 0)
log_unit_warning(u, "Got notification message from PID "PID_FMT", but reception only permitted for main PID "PID_FMT, pid, s->main_pid);
else
log_unit_debug(u, "Got notification message from PID "PID_FMT", but reception only permitted for main PID which is currently not known", pid);
log_unit_warning(u, "Got notification message from PID "PID_FMT", but reception only permitted for main PID which is currently not known", pid);
return;
} else if (s->notify_access == NOTIFY_EXEC && pid != s->main_pid && pid != s->control_pid) {
if (s->main_pid != 0 && s->control_pid != 0)
log_unit_warning(u, "Got notification message from PID "PID_FMT", but reception only permitted for main PID "PID_FMT" and control PID "PID_FMT,
pid, s->main_pid, s->control_pid);
else if (s->main_pid != 0)
log_unit_warning(u, "Got notification message from PID "PID_FMT", but reception only permitted for main PID "PID_FMT, pid, s->main_pid);
else if (s->control_pid != 0)
log_unit_warning(u, "Got notification message from PID "PID_FMT", but reception only permitted for control PID "PID_FMT, pid, s->control_pid);
else
log_unit_warning(u, "Got notification message from PID "PID_FMT", but reception only permitted for main PID and control PID which are currently not known", pid);
return;
} else
log_unit_debug(u, "Got notification message from PID "PID_FMT" (%s)", pid, isempty(cc) ? "n/a" : cc);
Expand All @@ -3066,6 +3101,8 @@ static void service_notify_message(Unit *u, pid_t pid, char **tags, FDSet *fds)
if (e && IN_SET(s->state, SERVICE_START, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD)) {
if (parse_pid(e, &pid) < 0)
log_unit_warning(u, "Failed to parse MAINPID= field in notification message: %s", e);
else if (pid == s->control_pid)
log_unit_warning(u, "A control process cannot also be the main process");
else {
service_set_main_pid(s, pid);
unit_watch_pid(UNIT(s), pid);
Expand Down Expand Up @@ -3381,6 +3418,7 @@ DEFINE_STRING_TABLE_LOOKUP(service_exec_command, ServiceExecCommand);
static const char* const notify_access_table[_NOTIFY_ACCESS_MAX] = {
[NOTIFY_NONE] = "none",
[NOTIFY_MAIN] = "main",
[NOTIFY_EXEC] = "exec",
[NOTIFY_ALL] = "all"
};

Expand Down
1 change: 1 addition & 0 deletions src/core/service.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ typedef enum NotifyAccess {
NOTIFY_NONE,
NOTIFY_ALL,
NOTIFY_MAIN,
NOTIFY_EXEC,
_NOTIFY_ACCESS_MAX,
_NOTIFY_ACCESS_INVALID = -1
} NotifyAccess;
Expand Down
1 change: 1 addition & 0 deletions src/shared/bus-unit-util.c
Original file line number Diff line number Diff line change
Expand Up @@ -764,6 +764,7 @@ static const struct {
const char *result, *explanation;
} explanations [] = {
{ "resources", "of unavailable resources or another system error" },
{ "protocol", "the service did not take the steps required by its unit configuration" },
{ "timeout", "a timeout was exceeded" },
{ "exit-code", "the control process exited with error code" },
{ "signal", "a fatal signal was delivered to the control process" },
Expand Down

0 comments on commit 97506e8

Please sign in to comment.