From 2b5c9fceaaa30ec9c2d031c9ca32b71c43f22f98 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 3 Jan 2023 12:55:50 +0100 Subject: [PATCH] notify: add --stopping + --reloading switches These wrap RELOADING=1 and STOPPING=1 messages. The former is particularly useful, since we want to insert the MONOTONIC_USEC= field into the message automatically, which is easy from C but harder from shell. (cherry picked from commit fd0f4da5457fbf7136f2d1888142d5fea75fd45a) Related: RHEL-6090 --- man/systemd-notify.xml | 107 ++++++++++++++++++++++++----------------- src/notify/notify.c | 39 +++++++++++++-- 2 files changed, 97 insertions(+), 49 deletions(-) diff --git a/man/systemd-notify.xml b/man/systemd-notify.xml index 1327d23155..a275123d40 100644 --- a/man/systemd-notify.xml +++ b/man/systemd-notify.xml @@ -30,34 +30,35 @@ Description - systemd-notify may be called by daemon - scripts to notify the init system about status changes. It can be - used to send arbitrary information, encoded in an - environment-block-like list of strings. Most importantly, it can be - used for start-up completion notification. - - This is mostly just a wrapper around - sd_notify() and makes this functionality + systemd-notify may be called by service scripts to notify the invoking service + manager about status changes. It can be used to send arbitrary information, encoded in an + environment-block-like list of strings. Most importantly, it can be used for start-up completion + notification. + + This is mostly just a wrapper around sd_notify() and makes this functionality available to shell scripts. For details see sd_notify3. - The command line may carry a list of environment variables - to send as part of the status update. + The command line may carry a list of environment variables to send as part of the status + update. Note that systemd will refuse reception of status updates from this command unless NotifyAccess= is set for the service unit this command is called from. - Note that sd_notify() notifications may be attributed to units correctly only if either - the sending process is still around at the time PID 1 processes the message, or if the sending process is - explicitly runtime-tracked by the service manager. The latter is the case if the service manager originally forked - off the process, i.e. on all processes that match NotifyAccess= or - NotifyAccess=. Conversely, if an auxiliary process of the unit sends an - sd_notify() message and immediately exits, the service manager might not be able to properly - attribute the message to the unit, and thus will ignore it, even if NotifyAccess= is set for it. When is used, all synchronization for reception of notifications - is disabled, and hence the aforementioned race may occur if the invoking process is not the service manager or spawned - by the service manager. + Note that sd_notify() notifications may be attributed to units correctly only + if either the sending process is still around at the time the service manager processes the message, or + if the sending process is explicitly runtime-tracked by the service manager. The latter is the case if + the service manager originally forked off the process, i.e. on all processes that match + NotifyAccess= or + NotifyAccess=. Conversely, if an auxiliary process of the unit + sends an sd_notify() message and immediately exits, the service manager might not be + able to properly attribute the message to the unit, and thus will ignore it, even if + NotifyAccess= is set for it. To address this + systemd-notify will wait until the notification message has been processed by the + service manager. When is used, this synchronization for reception of + notifications is disabled, and hence the aforementioned race may occur if the invoking process is not the + service manager or spawned by the service manager. Hence, systemd-notify will first attempt to invoke sd_notify() pretending to have the PID of the invoking process. This will only succeed when invoked with sufficient privileges. @@ -66,7 +67,6 @@ — appears as sender of the message, which in turn is helpful if the shell process is the main process of a service, due to the limitations of NotifyAccess=. Use the switch to tweak this behaviour. - @@ -78,22 +78,42 @@ - Inform the init system about service start-up - completion. This is equivalent to systemd-notify - READY=1. For details about the semantics of this - option see + Inform the invoking service manager about service start-up or configuration reload + completion. This is equivalent to systemd-notify READY=1. For details about the + semantics of this option see + sd_notify3. + + + + + + Inform the invoking service manager about the beginning of a configuration reload + cycle. This is equivalent to systemd-notify RELOADING=1 (but implicitly also sets + a MONOTONIC_USEC= field as required for Type=notify-reload + services, see + systemd.service5, + for details). For details about the semantics of this option see + sd_notify3. + + + + + + Inform the invoking service manager about the beginning of the shutdown phase of the + service. This is equivalent to systemd-notify STOPPING=1. For details about the + semantics of this option see sd_notify3. - Inform the service manager about the main PID of the daemon. Takes a PID as + Inform the service manager about the main PID of the service. Takes a PID as argument. If the argument is specified as auto or omitted, the PID of the process that invoked systemd-notify is used, except if that's the service manager. If the argument is specified as self, the PID of the systemd-notify command itself is used, and if parent is specified the calling process' PID is - used — even if it is the service manager. This is equivalent to systemd-notify + used — even if it is the service manager. The latter is equivalent to systemd-notify MAINPID=$PID. For details about the semantics of this option see sd_notify3. @@ -110,27 +130,26 @@ - Send a free-form status string for the daemon - to the init systemd. This option takes the status string as - argument. This is equivalent to systemd-notify - STATUS=…. For details about the semantics of this - option see - sd_notify3. + Send a free-form human readable status string for the daemon to the service + manager. This option takes the status string as argument. This is equivalent to + systemd-notify STATUS=…. For details about the semantics of this option see + sd_notify3. This + information is shown in + systemctl1's + status output, among other places. - Returns 0 if the system was booted up with - systemd, non-zero otherwise. If this option is passed, no - message is sent. This option is hence unrelated to the other - options. For details about the semantics of this option, see + Returns 0 if the system was booted up with systemd, non-zero otherwise. If this + option is passed, no message is sent. This option is hence unrelated to the other options. For + details about the semantics of this option, see sd_booted3. An alternate way to check for this state is to call - systemctl1 - with the is-system-running command. It will - return offline if the system was not booted - with systemd. + systemctl1 with + the is-system-running command. It will return offline if the + system was not booted with systemd. @@ -162,9 +181,8 @@ Start-up Notification and Status Updates - A simple shell daemon that sends start-up notifications - after having set up its communication channel. During runtime it - sends further status updates to the init system: + A simple shell daemon that sends start-up notifications after having set up its communication + channel. During runtime it sends further status updates to the init system: #!/bin/sh @@ -192,5 +210,4 @@ done sd_booted3 - diff --git a/src/notify/notify.c b/src/notify/notify.c index 7b23e7bdb0..2d4900a110 100644 --- a/src/notify/notify.c +++ b/src/notify/notify.c @@ -23,6 +23,8 @@ #include "util.h" static bool arg_ready = false; +static bool arg_reloading = false; +static bool arg_stopping = false; static pid_t arg_pid = 0; static const char *arg_status = NULL; static bool arg_booted = false; @@ -42,7 +44,10 @@ static int help(void) { "\n%sNotify the init system about service status updates.%s\n\n" " -h --help Show this help\n" " --version Show package version\n" - " --ready Inform the init system about service start-up completion\n" + " --ready Inform the service manager about service start-up/reload\n" + " completion\n" + " --reloading Inform the service manager about configuration reloading\n" + " --stopping Inform the service manager about service shutdown\n" " --pid[=PID] Set main PID of daemon\n" " --uid=USER Set user to send from\n" " --status=TEXT Set status text\n" @@ -81,6 +86,8 @@ static int parse_argv(int argc, char *argv[]) { enum { ARG_READY = 0x100, + ARG_RELOADING, + ARG_STOPPING, ARG_VERSION, ARG_PID, ARG_STATUS, @@ -93,6 +100,8 @@ static int parse_argv(int argc, char *argv[]) { { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, ARG_VERSION }, { "ready", no_argument, NULL, ARG_READY }, + { "reloading", no_argument, NULL, ARG_RELOADING }, + { "stopping", no_argument, NULL, ARG_STOPPING }, { "pid", optional_argument, NULL, ARG_PID }, { "status", required_argument, NULL, ARG_STATUS }, { "booted", no_argument, NULL, ARG_BOOTED }, @@ -120,6 +129,14 @@ static int parse_argv(int argc, char *argv[]) { arg_ready = true; break; + case ARG_RELOADING: + arg_reloading = true; + break; + + case ARG_STOPPING: + arg_stopping = true; + break; + case ARG_PID: if (isempty(optarg) || streq(optarg, "auto")) { arg_pid = getppid(); @@ -176,6 +193,8 @@ static int parse_argv(int argc, char *argv[]) { if (optind >= argc && !arg_ready && + !arg_stopping && + !arg_reloading && !arg_status && !arg_pid && !arg_booted) { @@ -187,10 +206,10 @@ static int parse_argv(int argc, char *argv[]) { } static int run(int argc, char* argv[]) { - _cleanup_free_ char *status = NULL, *cpid = NULL, *n = NULL; + _cleanup_free_ char *status = NULL, *cpid = NULL, *n = NULL, *monotonic_usec = NULL; _cleanup_strv_free_ char **final_env = NULL; - char* our_env[4]; - unsigned i = 0; + char* our_env[7]; + size_t i = 0; pid_t source_pid; int r; @@ -212,9 +231,21 @@ static int run(int argc, char* argv[]) { return r <= 0; } + if (arg_reloading) { + our_env[i++] = (char*) "RELOADING=1"; + + if (asprintf(&monotonic_usec, "MONOTONIC_USEC=" USEC_FMT, now(CLOCK_MONOTONIC)) < 0) + return log_oom(); + + our_env[i++] = monotonic_usec; + } + if (arg_ready) our_env[i++] = (char*) "READY=1"; + if (arg_stopping) + our_env[i++] = (char*) "STOPPING=1"; + if (arg_status) { status = strjoin("STATUS=", arg_status); if (!status)