core: only process one of READY=1, STOPPING=1 or RELOADING=1 in sd_notify() handling
authorLennart Poettering <lennart@poettering.net>
Mon, 13 Nov 2017 17:14:20 +0000 (18:14 +0100)
committerLennart Poettering <lennart@poettering.net>
Mon, 27 Nov 2017 16:01:00 +0000 (17:01 +0100)
Of course, it's not really a valid sd_notify() message if multiple of
these fields are used in one, but let's handle this somewhat gracefully,
by only processing one of them, and ignoring the rest.

src/core/service.c
src/systemd/sd-daemon.h

index 0beb25b..b25ed49 100644 (file)
@@ -3348,6 +3348,7 @@ static void service_notify_message(Unit *u, pid_t pid, char **tags, FDSet *fds)
         Service *s = SERVICE(u);
         bool notify_dbus = false;
         const char *e;
+        char **i;
 
         assert(u);
 
@@ -3377,44 +3378,43 @@ static void service_notify_message(Unit *u, pid_t pid, char **tags, FDSet *fds)
                 }
         }
 
-        /* Interpret RELOADING= */
-        if (strv_find(tags, "RELOADING=1")) {
+        /* Interpret READY=/STOPPING=/RELOADING=. Last one wins. */
+        STRV_FOREACH_BACKWARDS(i, tags) {
 
-                s->notify_state = NOTIFY_RELOADING;
+                if (streq(*i, "READY=1")) {
+                        s->notify_state = NOTIFY_READY;
 
-                if (s->state == SERVICE_RUNNING)
-                        service_enter_reload_by_notify(s);
-
-                notify_dbus = true;
-        }
+                        /* Type=notify services inform us about completed
+                         * initialization with READY=1 */
+                        if (s->type == SERVICE_NOTIFY && s->state == SERVICE_START)
+                                service_enter_start_post(s);
 
-        /* Interpret READY= */
-        if (strv_find(tags, "READY=1")) {
+                        /* Sending READY=1 while we are reloading informs us
+                         * that the reloading is complete */
+                        if (s->state == SERVICE_RELOAD && s->control_pid == 0)
+                                service_enter_running(s, SERVICE_SUCCESS);
 
-                s->notify_state = NOTIFY_READY;
+                        notify_dbus = true;
+                        break;
 
-                /* Type=notify services inform us about completed
-                 * initialization with READY=1 */
-                if (s->type == SERVICE_NOTIFY && s->state == SERVICE_START)
-                        service_enter_start_post(s);
+                } else if (streq(*i, "RELOADING=1")) {
+                        s->notify_state = NOTIFY_RELOADING;
 
-                /* Sending READY=1 while we are reloading informs us
-                 * that the reloading is complete */
-                if (s->state == SERVICE_RELOAD && s->control_pid == 0)
-                        service_enter_running(s, SERVICE_SUCCESS);
+                        if (s->state == SERVICE_RUNNING)
+                                service_enter_reload_by_notify(s);
 
-                notify_dbus = true;
-        }
+                        notify_dbus = true;
+                        break;
 
-        /* Interpret STOPPING= */
-        if (strv_find(tags, "STOPPING=1")) {
+                } else if (streq(*i, "STOPPING=1")) {
+                        s->notify_state = NOTIFY_STOPPING;
 
-                s->notify_state = NOTIFY_STOPPING;
+                        if (s->state == SERVICE_RUNNING)
+                                service_enter_stop_by_notify(s);
 
-                if (s->state == SERVICE_RUNNING)
-                        service_enter_stop_by_notify(s);
-
-                notify_dbus = true;
+                        notify_dbus = true;
+                        break;
+                }
         }
 
         /* Interpret STATUS= */
index 54e8256..3fd0cc6 100644 (file)
@@ -175,12 +175,22 @@ int sd_is_mq(int fd, const char *path);
   newline separated environment-style variable assignments in a
   string. The following variables are known:
 
-     READY=1      Tells systemd that daemon startup is finished (only
-                  relevant for services of Type=notify). The passed
-                  argument is a boolean "1" or "0". Since there is
-                  little value in signaling non-readiness the only
+     MAINPID=...  The main PID of a daemon, in case systemd did not
+                  fork off the process itself. Example: "MAINPID=4711"
+
+     READY=1      Tells systemd that daemon startup or daemon reload
+                  is finished (only relevant for services of Type=notify).
+                  The passed argument is a boolean "1" or "0". Since there
+                  is little value in signaling non-readiness the only
                   value daemons should send is "READY=1".
 
+     RELOADING=1  Tell systemd that the daemon began reloading its
+                  configuration. When the configuration has been
+                  reloaded completely, READY=1 should be sent to inform
+                  systemd about this.
+
+     STOPPING=1   Tells systemd that the daemon is about to go down.
+
      STATUS=...   Passes a single-line status string back to systemd
                   that describes the daemon state. This is free-form
                   and can be used for various purposes: general state
@@ -195,9 +205,6 @@ int sd_is_mq(int fd, const char *path);
      BUSERROR=... If a daemon fails, the D-Bus error-style error
                   code. Example: "BUSERROR=org.freedesktop.DBus.Error.TimedOut"
 
-     MAINPID=...  The main pid of a daemon, in case systemd did not
-                  fork off the process itself. Example: "MAINPID=4711"
-
      WATCHDOG=1   Tells systemd to update the watchdog timestamp.
                   Services using this feature should do this in
                   regular intervals. A watchdog framework can use the