diff --git a/TODO b/TODO
index 0208a5445e..899b6a1de1 100644
--- a/TODO
+++ b/TODO
@@ -763,17 +763,9 @@ Features:
and synthesize initrd from it, and measure it. Signing is not necessary, as
microcode does that on its own. Pass as first initrd to kernel.
-* Add a new service type very similar to Type=notify, that goes one step
- further and extends the protocol to cover reloads. Specifically, SIGHUP will
- become the official way to reload, and daemon has to respond with sd_notify()
- to report when it starts reloading, and when it is complete reloading. Care
- must be taken to remove races from this model. I.e. PID 1 needs to take
- CLOCK_MONOTONIC, then send SIGHUP, then wait for at least one RELOADING=1
- message that comes with a newer timestamp, then wait for a READY=1 message.
- while we are at it, also maybe extend the logic to require handling of some
- specific SIGRT signal for setting debug log level, that carries the level via
- the sigqueue() data parameter. With that we extended with minimal logic the
- service runtime logic quite substantially.
+* Maybe extend the service protocol to support handling of some specific SIGRT
+ signal for setting service log level, that carries the level via the
+ sigqueue() data parameter. Enable this via unit file setting.
* firstboot: maybe just default to C.UTF-8 locale if nothing is set, so that we
don't query this unnecessarily in entirely uninitialized
@@ -1774,7 +1766,6 @@ Features:
* unit files:
- allow port=0 in .socket units
- maybe introduce ExecRestartPre=
- - add ReloadSignal= for configuring a reload signal to use
- implement Register= switch in .socket units to enable registration
in Avahi, RPC and other socket registration services.
- allow Type=simple with PIDFile=
diff --git a/man/org.freedesktop.systemd1.xml b/man/org.freedesktop.systemd1.xml
index 5154638c33..8eb30afd85 100644
--- a/man/org.freedesktop.systemd1.xml
+++ b/man/org.freedesktop.systemd1.xml
@@ -2578,6 +2578,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
readonly s OOMPolicy = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly a(sst) OpenFile = [...];
+ @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
+ readonly i ReloadSignal = ...;
readonly t ExecMainStartTimestamp = ...;
readonly t ExecMainStartTimestampMonotonic = ...;
readonly t ExecMainExitTimestamp = ...;
@@ -3177,6 +3179,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
+
+
@@ -3735,6 +3739,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
+
+
diff --git a/man/sd_notify.xml b/man/sd_notify.xml
index 021cd0384f..0ba191c0ce 100644
--- a/man/sd_notify.xml
+++ b/man/sd_notify.xml
@@ -102,23 +102,35 @@
READY=1
- Tells the service manager that service startup is finished, or the service finished loading its
- configuration. This is only used by systemd if the service definition file has Type=notify
- set. Since there is little value in signaling non-readiness, the only value services should send is
- READY=1 (i.e. READY=0 is not defined).
+ Tells the service manager that service startup is finished, or the service finished
+ re-loading its configuration. This is only used by systemd if the service definition file has
+ Type=notify or Type=notify-reload set. Since there is little
+ value in signaling non-readiness, the only value services should send is READY=1
+ (i.e. READY=0 is not defined).RELOADING=1
- Tells the service manager that the service is
- reloading its configuration. This is useful to allow the
- service manager to track the service's internal state, and
- present it to the user. Note that a service that sends this
- notification must also send a READY=1
- notification when it completed reloading its
- configuration. Reloads are propagated in the same way as they
- are when initiated by the user.
+ Tells the service manager that the service is beginning to reload its
+ configuration. This is useful to allow the service manager to track the service's internal state, and
+ present it to the user. Note that a service that sends this notification must also send a
+ READY=1 notification when it completed reloading its configuration. Reloads the
+ service manager is notified about with this mechanisms are propagated in the same way as they are
+ when originally initiated through the service manager. This message is particularly relevant for
+ Type=notify-reload services, to inform the service manager that the request to
+ reload the service has been received and is now being processed.
+
+
+
+ MONOTONIC_USEC=…
+
+ A field carrying the monotonic timestamp (as per
+ CLOCK_MONOTONIC) formatted in decimal in µs, when the notification message was
+ generated by the client. This is typically used in combination with RELOADING=1,
+ to allow the service manager to properly synchronize reload cycles. See
+ systemd.service5
+ for details, specifically Type=notify-reload.
diff --git a/man/systemd-notify.xml b/man/systemd-notify.xml
index 9479fbd759..dd76cc0fb6 100644
--- a/man/systemd-notify.xml
+++ b/man/systemd-notify.xml
@@ -30,20 +30,18 @@
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.
+ 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
+ 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 appropriately set for the service unit this command is called
@@ -52,9 +50,9 @@
details.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
+ 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
@@ -84,22 +82,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.
@@ -124,27 +142,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.
@@ -176,9 +193,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
@@ -207,5 +223,4 @@ donesd_booted3
-
diff --git a/man/systemd.service.xml b/man/systemd.service.xml
index e327f688f4..f123fa2e4c 100644
--- a/man/systemd.service.xml
+++ b/man/systemd.service.xml
@@ -157,7 +157,7 @@
Configures the process start-up type for this service unit. One of ,
, , , ,
- or :
+ , or :
If set to (the default if ExecStart= is
@@ -216,14 +216,30 @@
logic thus should be prepared to receive a SIGTERM (or whichever signal is
configured in KillSignal=) as result.
- Behavior of is similar to ; however, it is
- expected that the service sends a notification message via
- sd_notify3 or an
- equivalent call when it has finished starting up. systemd will proceed with starting follow-up units after
- this notification message has been sent. If this option is used, NotifyAccess= (see
- below) should be set to open access to the notification socket provided by systemd. If
- NotifyAccess= is missing or set to , it will be forcibly set to
- .
+ Behavior of is similar to ; however,
+ it is expected that the service sends a READY=1 notification message via
+ sd_notify3 or
+ an equivalent call when it has finished starting up. systemd will proceed with starting follow-up
+ units after this notification message has been sent. If this option is used,
+ NotifyAccess= (see below) should be set to open access to the notification
+ socket provided by systemd. If NotifyAccess= is missing or set to
+ , it will be forcibly set to .
+
+ Behavior of is identical to
+ . However, it extends the logic in one way: the
+ SIGHUP UNIX process signal is sent to the service's main process when the
+ service is asked to reload. (The signal to send can be tweaked via
+ ReloadSignal=, see below.). When
+ initiating the reload process the service is then expected to reply with a notification message
+ via sd_notify3
+ that contains the RELOADING=1 field in combination with
+ MONOTONIC_USEC= set to the current monotonic time
+ (i.e. CLOCK_MONOTONIC in
+ clock_gettime2)
+ in µs, formatted as decimal string. Once reloading is complete another notification message must
+ be sent, containing READY=1. Using this service type and implementing this
+ reload protocol is an efficient alternative to providing an ExecReload=
+ command for reloading of the service's configuration.Behavior of is very similar to ; however,
actual execution of the service program is delayed until all active jobs are dispatched. This may be used
@@ -233,25 +249,27 @@
anyway.
- It is generally recommended to use Type= for long-running
- services whenever possible, as it is the simplest and fastest option. However, as this service type won't
- propagate service start-up failures and doesn't allow ordering of other units against completion of
- initialization of the service (which for example is useful if clients need to connect to the service through
- some form of IPC, and the IPC channel is only established by the service itself — in contrast to doing this
- ahead of time through socket or bus activation or similar), it might not be sufficient for many cases. If so,
- or (the latter only in case the service provides a D-Bus
- interface) are the preferred options as they allow service program code to precisely schedule when to
- consider the service started up successfully and when to proceed with follow-up units. The
- service type requires explicit support in the service codebase (as
- sd_notify() or an equivalent API needs to be invoked by the service at the appropriate
- time) — if it's not supported, then is an alternative: it supports the traditional
- UNIX service start-up protocol. Finally, might be an option for cases where it is
- enough to ensure the service binary is invoked, and where the service binary itself executes no or little
- initialization on its own (and its initialization is unlikely to fail). Note that using any type other than
- possibly delays the boot process, as the service manager needs to wait for service
- initialization to complete. It is hence recommended not to needlessly use any types other than
- . (Also note it is generally not recommended to use or
- for long-running services.)
+ It is generally recommended to use Type= for
+ long-running services whenever possible, as it is the simplest and fastest option. However, as this
+ service type won't propagate service start-up failures and doesn't allow ordering of other units
+ against completion of initialization of the service (which for example is useful if clients need to
+ connect to the service through some form of IPC, and the IPC channel is only established by the
+ service itself — in contrast to doing this ahead of time through socket or bus activation or
+ similar), it might not be sufficient for many cases. If so, ,
+ or (the latter only in case the service
+ provides a D-Bus interface) are the preferred options as they allow service program code to
+ precisely schedule when to consider the service started up successfully and when to proceed with
+ follow-up units. The / service types require
+ explicit support in the service codebase (as sd_notify() or an equivalent API
+ needs to be invoked by the service at the appropriate time) — if it's not supported, then
+ is an alternative: it supports the traditional UNIX service start-up
+ protocol. Finally, might be an option for cases where it is enough to ensure
+ the service binary is invoked, and where the service binary itself executes no or little
+ initialization on its own (and its initialization is unlikely to fail). Note that using any type
+ other than possibly delays the boot process, as the service manager needs
+ to wait for service initialization to complete. It is hence recommended not to needlessly use any
+ types other than . (Also note it is generally not recommended to use
+ or for long-running services.)
@@ -319,9 +337,10 @@
the file may not be a symlink to a file owned by a different user (neither directly nor indirectly), and the
PID file must refer to a process already belonging to the service.
- Note that PID files should be avoided in modern projects. Use or
- where possible, which does not require use of PID files to determine the
- main process of a service and avoids needless forking.
+ Note that PID files should be avoided in modern projects. Use ,
+ or where possible, which does not
+ require use of PID files to determine the main process of a service and avoids needless
+ forking.
@@ -443,12 +462,13 @@
with a - exit successfully.
ExecStartPost= commands are only run after the commands specified in
- ExecStart= have been invoked successfully, as determined by Type=
- (i.e. the process has been started for Type=simple or Type=idle, the last
- ExecStart= process exited successfully for Type=oneshot, the initial
- process exited successfully for Type=forking, READY=1 is sent for
- Type=notify, or the BusName= has been taken for
- Type=dbus).
+ ExecStart= have been invoked successfully, as determined by
+ Type= (i.e. the process has been started for Type=simple or
+ Type=idle, the last ExecStart= process exited successfully for
+ Type=oneshot, the initial process exited successfully for
+ Type=forking, READY=1 is sent for
+ Type=notify/Type=notify-reload, or the
+ BusName= has been taken for Type=dbus).
Note that ExecStartPre= may not be
used to start long-running processes. All processes forked
@@ -487,30 +507,26 @@
ExecReload=
- Commands to execute to trigger a configuration
- reload in the service. This argument takes multiple command
- lines, following the same scheme as described for
- ExecStart= above. Use of this setting is
- optional. Specifier and environment variable substitution is
- supported here following the same scheme as for
+
+ Commands to execute to trigger a configuration reload in the service. This argument
+ takes multiple command lines, following the same scheme as described for
+ ExecStart= above. Use of this setting is optional. Specifier and environment
+ variable substitution is supported here following the same scheme as for
ExecStart=.
- One additional, special environment variable is set: if
- known, $MAINPID is set to the main process
- of the daemon, and may be used for command lines like the
- following:
+ One additional, special environment variable is set: if known, $MAINPID is
+ set to the main process of the daemon, and may be used for command lines like the following:ExecReload=kill -HUP $MAINPID
- Note however that reloading a daemon by sending a signal
- (as with the example line above) is usually not a good choice,
- because this is an asynchronous operation and hence not
- suitable to order reloads of multiple services against each
- other. It is strongly recommended to set
- ExecReload= to a command that not only
- triggers a configuration reload of the daemon, but also
- synchronously waits for it to complete. For example,
- dbus-broker1
+ Note however that reloading a daemon by enqueing a signal (as with the example line above) is
+ usually not a good choice, because this is an asynchronous operation and hence not suitable when
+ ordering reloads of multiple services against each other. It is thus strongly recommended to either
+ use Type= in place of
+ ExecReload=, or to set ExecReload= to a command that not only
+ triggers a configuration reload of the daemon, but also synchronously waits for it to complete. For
+ example, dbus-broker1
uses the following:ExecReload=busctl call org.freedesktop.DBus \
@@ -605,12 +621,13 @@
systemd-system.conf5).
- If a service of Type=notify sends EXTEND_TIMEOUT_USEC=…, this may cause
- the start time to be extended beyond TimeoutStartSec=. The first receipt of this message
- must occur before TimeoutStartSec= is exceeded, and once the start time has extended beyond
- TimeoutStartSec=, the service manager will allow the service to continue to start, provided
- the service repeats EXTEND_TIMEOUT_USEC=… within the interval specified until the service
- startup status is finished by READY=1. (see
+ If a service of Type=notify/Type=notify-reload sends
+ EXTEND_TIMEOUT_USEC=…, this may cause the start time to be extended beyond
+ TimeoutStartSec=. The first receipt of this message must occur before
+ TimeoutStartSec= is exceeded, and once the start time has extended beyond
+ TimeoutStartSec=, the service manager will allow the service to continue to start,
+ provided the service repeats EXTEND_TIMEOUT_USEC=… within the interval specified
+ until the service startup status is finished by READY=1. (see
sd_notify3).
@@ -633,12 +650,14 @@
systemd-system.conf5).
- If a service of Type=notify sends EXTEND_TIMEOUT_USEC=…, this may cause
- the stop time to be extended beyond TimeoutStopSec=. The first receipt of this message
- must occur before TimeoutStopSec= is exceeded, and once the stop time has extended beyond
- TimeoutStopSec=, the service manager will allow the service to continue to stop, provided
- the service repeats EXTEND_TIMEOUT_USEC=… within the interval specified, or terminates itself
- (see sd_notify3).
+ If a service of Type=notify/Type=notify-reload sends
+ EXTEND_TIMEOUT_USEC=…, this may cause the stop time to be extended beyond
+ TimeoutStopSec=. The first receipt of this message must occur before
+ TimeoutStopSec= is exceeded, and once the stop time has extended beyond
+ TimeoutStopSec=, the service manager will allow the service to continue to stop,
+ provided the service repeats EXTEND_TIMEOUT_USEC=… within the interval specified,
+ or terminates itself (see
+ sd_notify3).
@@ -661,13 +680,15 @@
systemd-system.conf5).
- If a service of Type=notify handles SIGABRT itself (instead of relying
- on the kernel to write a core dump) it can send EXTEND_TIMEOUT_USEC=… to
- extended the abort time beyond TimeoutAbortSec=. The first receipt of this message
- must occur before TimeoutAbortSec= is exceeded, and once the abort time has extended beyond
- TimeoutAbortSec=, the service manager will allow the service to continue to abort, provided
- the service repeats EXTEND_TIMEOUT_USEC=… within the interval specified, or terminates itself
- (see sd_notify3).
+ If a service of Type=notify/Type=notify-reload handles
+ SIGABRT itself (instead of relying on the kernel to write a core dump) it can
+ send EXTEND_TIMEOUT_USEC=… to extended the abort time beyond
+ TimeoutAbortSec=. The first receipt of this message must occur before
+ TimeoutAbortSec= is exceeded, and once the abort time has extended beyond
+ TimeoutAbortSec=, the service manager will allow the service to continue to abort,
+ provided the service repeats EXTEND_TIMEOUT_USEC=… within the interval specified,
+ or terminates itself (see
+ sd_notify3).
@@ -710,12 +731,13 @@
activation completed. Pass infinity (the default) to configure no runtime
limit.
- If a service of Type=notify sends EXTEND_TIMEOUT_USEC=…, this may cause
- the runtime to be extended beyond RuntimeMaxSec=. The first receipt of this message
- must occur before RuntimeMaxSec= is exceeded, and once the runtime has extended beyond
- RuntimeMaxSec=, the service manager will allow the service to continue to run, provided
- the service repeats EXTEND_TIMEOUT_USEC=… within the interval specified until the service
- shutdown is achieved by STOPPING=1 (or termination). (see
+ If a service of Type=notify/Type=notify-reload sends
+ EXTEND_TIMEOUT_USEC=…, this may cause the runtime to be extended beyond
+ RuntimeMaxSec=. The first receipt of this message must occur before
+ RuntimeMaxSec= is exceeded, and once the runtime has extended beyond
+ RuntimeMaxSec=, the service manager will allow the service to continue to run,
+ provided the service repeats EXTEND_TIMEOUT_USEC=… within the interval specified
+ until the service shutdown is achieved by STOPPING=1 (or termination). (see
sd_notify3).
@@ -1023,16 +1045,19 @@
NotifyAccess=Controls access to the service status notification socket, as accessible via the
- sd_notify3 call. Takes one
- of (the default), , or
- . If , no daemon status updates are accepted from the service
- processes, all status update messages are ignored. If , only service updates sent from the
- main process of the service are accepted. If , only service updates sent from any of the
- main or control processes originating from one of the Exec*= commands are accepted. If
- , 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 Type=notify or
- WatchdogSec= (see above). If those options are used but NotifyAccess= is
- not configured, it will be implicitly set to .
+ sd_notify3
+ call. Takes one of (the default), ,
+ or . If , no daemon status updates are accepted from the
+ service processes, all status update messages are ignored. If , only service
+ updates sent from the main process of the service are accepted. If , only
+ service updates sent from any of the main or control processes originating from one of the
+ Exec*= commands are accepted. If , 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
+ Type=notify/Type=notify-reload or
+ WatchdogSec= (see above). If those options are used but
+ NotifyAccess= is not configured, it will be implicitly set to
+ .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
@@ -1156,6 +1181,7 @@
kills, this setting determines the state of the unit after systemd-oomd kills a
cgroup associated with it.
+
OpenFile=Takes an argument of the form path:fd-name:options,
@@ -1187,6 +1213,14 @@
If the empty string is assigned, the entire list of open files defined prior to this is reset.
+
+ ReloadSignal=
+ Configures the UNIX process signal to send to the service's main process when asked
+ to reload the service's configuration. Defaults to SIGHUP. This option has no
+ effect unless Type= is used, see
+ above.
+
+
Check
@@ -1350,16 +1384,13 @@ WantedBy=multi-user.target
systemd.kill5
for details.
- Note that this unit type does not include any type of
- notification when a service has completed initialization. For
- this, you should use other unit types, such as
- Type= if the service
- understands systemd's notification protocol,
- Type= if the service
- can background itself or
- Type= if the unit
- acquires a DBus name once initialization is complete. See
- below.
+ Note that this unit type does not include any type of notification when a service has completed
+ initialization. For this, you should use other unit types, such as
+ Type=/Type=
+ if the service understands systemd's notification protocol,
+ Type= if the service can background itself or
+ Type= if the unit acquires a DBus name once initialization is
+ complete. See below.
@@ -1536,15 +1567,12 @@ SystemdService=simple-dbus-service.service
Services that notify systemd about their initialization
- Type= services
- are really easy to write, but have the major disadvantage of
- systemd not being able to tell when initialization of the given
- service is complete. For this reason, systemd supports a simple
- notification protocol that allows daemons to make systemd aware
- that they are done initializing. Use
- Type= for this. A
- typical service file for such a daemon would look like
- this:
+ Type= services are really easy to write, but have the
+ major disadvantage of systemd not being able to tell when initialization of the given service is
+ complete. For this reason, systemd supports a simple notification protocol that allows daemons to make
+ systemd aware that they are done initializing. Use Type= or
+ Type= for this. A typical service file for such a
+ daemon would look like this:[Unit]
Description=Simple notifying service
diff --git a/src/basic/unit-def.c b/src/basic/unit-def.c
index 94cd603e32..bdb1860246 100644
--- a/src/basic/unit-def.c
+++ b/src/basic/unit-def.c
@@ -188,6 +188,8 @@ static const char* const service_state_table[_SERVICE_STATE_MAX] = {
[SERVICE_RUNNING] = "running",
[SERVICE_EXITED] = "exited",
[SERVICE_RELOAD] = "reload",
+ [SERVICE_RELOAD_SIGNAL] = "reload-signal",
+ [SERVICE_RELOAD_NOTIFY] = "reload-notify",
[SERVICE_STOP] = "stop",
[SERVICE_STOP_WATCHDOG] = "stop-watchdog",
[SERVICE_STOP_SIGTERM] = "stop-sigterm",
diff --git a/src/basic/unit-def.h b/src/basic/unit-def.h
index 5fcd51c095..bae132ea09 100644
--- a/src/basic/unit-def.h
+++ b/src/basic/unit-def.h
@@ -132,7 +132,9 @@ typedef enum ServiceState {
SERVICE_START_POST,
SERVICE_RUNNING,
SERVICE_EXITED, /* Nothing is running anymore, but RemainAfterExit is true hence this is OK */
- SERVICE_RELOAD,
+ SERVICE_RELOAD, /* Reloading via ExecReload= */
+ SERVICE_RELOAD_SIGNAL, /* Reloading via SIGHUP requested */
+ SERVICE_RELOAD_NOTIFY, /* Waiting for READY=1 after RELOADING=1 notify */
SERVICE_STOP, /* No STOP_PRE state, instead just register multiple STOP executables */
SERVICE_STOP_WATCHDOG,
SERVICE_STOP_SIGTERM,
diff --git a/src/core/dbus-service.c b/src/core/dbus-service.c
index 0d437afe6b..079cb9b92d 100644
--- a/src/core/dbus-service.c
+++ b/src/core/dbus-service.c
@@ -258,6 +258,7 @@ const sd_bus_vtable bus_service_vtable[] = {
SD_BUS_PROPERTY("NRestarts", "u", bus_property_get_unsigned, offsetof(Service, n_restarts), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("OOMPolicy", "s", bus_property_get_oom_policy, offsetof(Service, oom_policy), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("OpenFile", "a(sst)", property_get_open_files, offsetof(Service, open_files), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("ReloadSignal", "i", bus_property_get_int, offsetof(Service, reload_signal), SD_BUS_VTABLE_PROPERTY_CONST),
BUS_EXEC_STATUS_VTABLE("ExecMain", offsetof(Service, main_exec_status), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
BUS_EXEC_COMMAND_LIST_VTABLE("ExecCondition", offsetof(Service, exec_command[SERVICE_EXEC_CONDITION]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
@@ -404,6 +405,7 @@ static BUS_DEFINE_SET_TRANSIENT_PARSE(service_restart, ServiceRestart, service_r
static BUS_DEFINE_SET_TRANSIENT_PARSE(oom_policy, OOMPolicy, oom_policy_from_string);
static BUS_DEFINE_SET_TRANSIENT_STRING_WITH_CHECK(bus_name, sd_bus_service_name_is_valid);
static BUS_DEFINE_SET_TRANSIENT_PARSE(timeout_failure_mode, ServiceTimeoutFailureMode, service_timeout_failure_mode_from_string);
+static BUS_DEFINE_SET_TRANSIENT_TO_STRING(reload_signal, "i", int32_t, int, "%" PRIi32, signal_to_string_with_check);
static int bus_service_set_transient_property(
Service *s,
@@ -612,6 +614,9 @@ static int bus_service_set_transient_property(
return 1;
}
+ if (streq(name, "ReloadSignal"))
+ return bus_set_transient_reload_signal(u, name, &s->reload_signal, message, flags, error);
+
return 0;
}
diff --git a/src/core/load-fragment-gperf.gperf.in b/src/core/load-fragment-gperf.gperf.in
index 81eb586cfe..3ea3ca3200 100644
--- a/src/core/load-fragment-gperf.gperf.in
+++ b/src/core/load-fragment-gperf.gperf.in
@@ -427,6 +427,7 @@ Service.USBFunctionDescriptors, config_parse_unit_path_printf,
Service.USBFunctionStrings, config_parse_unit_path_printf, 0, offsetof(Service, usb_function_strings)
Service.OOMPolicy, config_parse_oom_policy, 0, offsetof(Service, oom_policy)
Service.OpenFile, config_parse_open_file, 0, offsetof(Service, open_files)
+Service.ReloadSignal, config_parse_signal, 0, offsetof(Service, reload_signal)
{{ EXEC_CONTEXT_CONFIG_ITEMS('Service') }}
{{ CGROUP_CONTEXT_CONFIG_ITEMS('Service') }}
{{ KILL_CONTEXT_CONFIG_ITEMS('Service') }}
diff --git a/src/core/main.c b/src/core/main.c
index c833050db0..94055f08de 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -1961,6 +1961,8 @@ static int invoke_main_loop(
LogTarget saved_log_target;
int saved_log_level;
+ manager_send_reloading(m);
+
log_info("Reloading.");
/* First, save any overridden log level/target, then parse the configuration file,
@@ -1991,6 +1993,10 @@ static int invoke_main_loop(
}
case MANAGER_REEXECUTE:
+
+ manager_send_reloading(m); /* From the perspective of the manager calling us this is
+ * pretty much the same as a reload */
+
r = prepare_reexecute(m, &arg_serialization, ret_fds, false);
if (r < 0) {
*ret_error_message = "Failed to prepare for reexecution";
@@ -2005,6 +2011,10 @@ static int invoke_main_loop(
return objective;
case MANAGER_SWITCH_ROOT:
+
+ manager_send_reloading(m); /* From the perspective of the manager calling us this is
+ * pretty much the same as a reload */
+
manager_set_switching_root(m, true);
if (!m->switch_root_init) {
diff --git a/src/core/manager.c b/src/core/manager.c
index 739933b97c..f8576cca1a 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -809,6 +809,8 @@ static int manager_find_credentials_dirs(Manager *m) {
}
void manager_set_switching_root(Manager *m, bool switching_root) {
+ assert(m);
+
m->switching_root = MANAGER_IS_SYSTEM(m) && switching_root;
}
@@ -3646,6 +3648,18 @@ void manager_check_finished(Manager *m) {
manager_invalidate_startup_units(m);
}
+void manager_send_reloading(Manager *m) {
+ assert(m);
+
+ /* Let whoever invoked us know that we are now reloading */
+ (void) sd_notifyf(/* unset= */ false,
+ "RELOADING=1\n"
+ "MONOTONIC_USEC=" USEC_FMT "\n", now(CLOCK_MONOTONIC));
+
+ /* And ensure that we'll send READY=1 again as soon as we are ready again */
+ m->ready_sent = false;
+}
+
static bool generator_path_any(const char* const* paths) {
bool found = false;
diff --git a/src/core/manager.h b/src/core/manager.h
index 4d4b56c3cc..c13de8fe78 100644
--- a/src/core/manager.h
+++ b/src/core/manager.h
@@ -538,6 +538,7 @@ void manager_send_unit_plymouth(Manager *m, Unit *u);
bool manager_unit_inactive_or_pending(Manager *m, const char *name);
void manager_check_finished(Manager *m);
+void manager_send_reloading(Manager *m);
void disable_printk_ratelimit(void);
void manager_recheck_dbus(Manager *m);
diff --git a/src/core/service.c b/src/core/service.c
index 0efcb9a081..a376b70f42 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -54,6 +54,8 @@ static const UnitActiveState state_translation_table[_SERVICE_STATE_MAX] = {
[SERVICE_RUNNING] = UNIT_ACTIVE,
[SERVICE_EXITED] = UNIT_ACTIVE,
[SERVICE_RELOAD] = UNIT_RELOADING,
+ [SERVICE_RELOAD_SIGNAL] = UNIT_RELOADING,
+ [SERVICE_RELOAD_NOTIFY] = UNIT_RELOADING,
[SERVICE_STOP] = UNIT_DEACTIVATING,
[SERVICE_STOP_WATCHDOG] = UNIT_DEACTIVATING,
[SERVICE_STOP_SIGTERM] = UNIT_DEACTIVATING,
@@ -78,6 +80,8 @@ static const UnitActiveState state_translation_table_idle[_SERVICE_STATE_MAX] =
[SERVICE_RUNNING] = UNIT_ACTIVE,
[SERVICE_EXITED] = UNIT_ACTIVE,
[SERVICE_RELOAD] = UNIT_RELOADING,
+ [SERVICE_RELOAD_SIGNAL] = UNIT_RELOADING,
+ [SERVICE_RELOAD_NOTIFY] = UNIT_RELOADING,
[SERVICE_STOP] = UNIT_DEACTIVATING,
[SERVICE_STOP_WATCHDOG] = UNIT_DEACTIVATING,
[SERVICE_STOP_SIGTERM] = UNIT_DEACTIVATING,
@@ -124,6 +128,8 @@ static void service_init(Unit *u) {
s->watchdog_original_usec = USEC_INFINITY;
s->oom_policy = _OOM_POLICY_INVALID;
+ s->reload_begin_usec = USEC_INFINITY;
+ s->reload_signal = SIGHUP;
}
static void service_unwatch_control_pid(Service *s) {
@@ -767,7 +773,7 @@ static int service_add_extras(Service *s) {
/* If the service needs the notify socket, let's enable it automatically. */
if (s->notify_access == NOTIFY_NONE &&
- (s->type == SERVICE_NOTIFY || s->watchdog_usec > 0 || s->n_fd_store_max > 0))
+ (IN_SET(s->type, SERVICE_NOTIFY, SERVICE_NOTIFY_RELOAD) || s->watchdog_usec > 0 || s->n_fd_store_max > 0))
s->notify_access = NOTIFY_MAIN;
/* If no OOM policy was explicitly set, then default to the configure default OOM policy. Except when
@@ -832,7 +838,8 @@ static void service_dump(Unit *u, FILE *f, const char *prefix) {
"%sRestart: %s\n"
"%sNotifyAccess: %s\n"
"%sNotifyState: %s\n"
- "%sOOMPolicy: %s\n",
+ "%sOOMPolicy: %s\n"
+ "%sReloadSignal: %s\n",
prefix, service_state_to_string(s->state),
prefix, service_result_to_string(s->result),
prefix, service_result_to_string(s->reload_result),
@@ -845,7 +852,8 @@ static void service_dump(Unit *u, FILE *f, const char *prefix) {
prefix, service_restart_to_string(s->restart),
prefix, notify_access_to_string(s->notify_access),
prefix, notify_state_to_string(s->notify_state),
- prefix, oom_policy_to_string(s->oom_policy));
+ prefix, oom_policy_to_string(s->oom_policy),
+ prefix, signal_to_string(s->reload_signal));
if (s->control_pid > 0)
fprintf(f,
@@ -1105,7 +1113,7 @@ static void service_set_state(Service *s, ServiceState state) {
if (!IN_SET(state,
SERVICE_CONDITION, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
SERVICE_RUNNING,
- SERVICE_RELOAD,
+ SERVICE_RELOAD, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY,
SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL,
SERVICE_AUTO_RESTART,
@@ -1114,7 +1122,8 @@ static void service_set_state(Service *s, ServiceState state) {
if (!IN_SET(state,
SERVICE_START, SERVICE_START_POST,
- SERVICE_RUNNING, SERVICE_RELOAD,
+ SERVICE_RUNNING,
+ SERVICE_RELOAD, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY,
SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL)) {
service_unwatch_main_pid(s);
@@ -1123,7 +1132,7 @@ static void service_set_state(Service *s, ServiceState state) {
if (!IN_SET(state,
SERVICE_CONDITION, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
- SERVICE_RELOAD,
+ SERVICE_RELOAD, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY,
SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL,
SERVICE_CLEANING)) {
@@ -1139,7 +1148,8 @@ static void service_set_state(Service *s, ServiceState state) {
if (!IN_SET(state,
SERVICE_CONDITION, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
- SERVICE_RUNNING, SERVICE_RELOAD,
+ SERVICE_RUNNING,
+ SERVICE_RELOAD, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY,
SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL) &&
!(state == SERVICE_DEAD && UNIT(s)->job))
@@ -1148,7 +1158,7 @@ static void service_set_state(Service *s, ServiceState state) {
if (state != SERVICE_START)
s->exec_fd_event_source = sd_event_source_disable_unref(s->exec_fd_event_source);
- if (!IN_SET(state, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD))
+ if (!IN_SET(state, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY))
service_stop_watchdog(s);
/* For the inactive states unit_notify() will trim the cgroup,
@@ -1174,6 +1184,8 @@ static usec_t service_coldplug_timeout(Service *s) {
case SERVICE_START:
case SERVICE_START_POST:
case SERVICE_RELOAD:
+ case SERVICE_RELOAD_SIGNAL:
+ case SERVICE_RELOAD_NOTIFY:
return usec_add(UNIT(s)->state_change_timestamp.monotonic, s->timeout_start_usec);
case SERVICE_RUNNING:
@@ -1220,7 +1232,8 @@ static int service_coldplug(Unit *u) {
pid_is_unwaited(s->main_pid) &&
(IN_SET(s->deserialized_state,
SERVICE_START, SERVICE_START_POST,
- SERVICE_RUNNING, SERVICE_RELOAD,
+ SERVICE_RUNNING,
+ SERVICE_RELOAD, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY,
SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL))) {
r = unit_watch_pid(UNIT(s), s->main_pid, false);
@@ -1232,7 +1245,7 @@ static int service_coldplug(Unit *u) {
pid_is_unwaited(s->control_pid) &&
IN_SET(s->deserialized_state,
SERVICE_CONDITION, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
- SERVICE_RELOAD,
+ SERVICE_RELOAD, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY,
SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL,
SERVICE_CLEANING)) {
@@ -1247,7 +1260,7 @@ static int service_coldplug(Unit *u) {
(void) unit_setup_exec_runtime(u);
}
- if (IN_SET(s->deserialized_state, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD))
+ if (IN_SET(s->deserialized_state, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY))
service_start_watchdog(s);
if (UNIT_ISSET(s->accept_socket)) {
@@ -2274,7 +2287,7 @@ static void service_enter_start(Service *s) {
s->control_pid = pid;
service_set_state(s, SERVICE_START);
- } else if (IN_SET(s->type, SERVICE_ONESHOT, SERVICE_DBUS, SERVICE_NOTIFY, SERVICE_EXEC)) {
+ } else if (IN_SET(s->type, SERVICE_ONESHOT, SERVICE_DBUS, SERVICE_NOTIFY, SERVICE_NOTIFY_RELOAD, SERVICE_EXEC)) {
/* For oneshot services we wait until the start process exited, too, but it is our main process. */
@@ -2418,7 +2431,7 @@ static void service_enter_reload_by_notify(Service *s) {
assert(s);
service_arm_timer(s, /* relative= */ true, s->timeout_start_usec);
- service_set_state(s, SERVICE_RELOAD);
+ service_set_state(s, SERVICE_RELOAD_NOTIFY);
/* service_enter_reload_by_notify is never called during a reload, thus no loops are possible. */
r = manager_propagate_reload(UNIT(s)->manager, UNIT(s), JOB_FAIL, &error);
@@ -2427,6 +2440,7 @@ static void service_enter_reload_by_notify(Service *s) {
}
static void service_enter_reload(Service *s) {
+ bool killed = false;
int r;
assert(s);
@@ -2434,6 +2448,18 @@ static void service_enter_reload(Service *s) {
service_unwatch_control_pid(s);
s->reload_result = SERVICE_SUCCESS;
+ usec_t ts = now(CLOCK_MONOTONIC);
+
+ if (s->type == SERVICE_NOTIFY_RELOAD && s->main_pid > 0) {
+ r = kill_and_sigcont(s->main_pid, s->reload_signal);
+ if (r < 0) {
+ log_unit_warning_errno(UNIT(s), r, "Failed to send reload signal: %m");
+ goto fail;
+ }
+
+ killed = true;
+ }
+
s->control_command = s->exec_command[SERVICE_EXEC_RELOAD];
if (s->control_command) {
s->control_command_id = SERVICE_EXEC_RELOAD;
@@ -2443,17 +2469,28 @@ static void service_enter_reload(Service *s) {
s->timeout_start_usec,
EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_IS_CONTROL|EXEC_CONTROL_CGROUP,
&s->control_pid);
- if (r < 0)
+ if (r < 0) {
+ log_unit_warning_errno(UNIT(s), r, "Failed to run 'reload' task: %m");
goto fail;
+ }
service_set_state(s, SERVICE_RELOAD);
- } else
+ } else if (killed) {
+ service_arm_timer(s, /* relative= */ true, s->timeout_start_usec);
+ service_set_state(s, SERVICE_RELOAD_SIGNAL);
+ } else {
service_enter_running(s, SERVICE_SUCCESS);
+ return;
+ }
+ /* Store the timestamp when we started reloading: when reloading via SIGHUP we won't leave the reload
+ * state until we received both RELOADING=1 and READY=1 with MONOTONIC_USEC= set to a value above
+ * this. Thus we know for sure the reload cycle was executed *after* we requested it, and is not one
+ * that was already in progress before. */
+ s->reload_begin_usec = ts;
return;
fail:
- log_unit_warning_errno(UNIT(s), r, "Failed to run 'reload' task: %m");
s->reload_result = SERVICE_FAILURE_RESOURCES;
service_enter_running(s, SERVICE_SUCCESS);
}
@@ -2616,9 +2653,8 @@ static int service_stop(Unit *u) {
return 0;
}
- /* If there's already something running we go directly into
- * kill mode. */
- if (IN_SET(s->state, SERVICE_CONDITION, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, SERVICE_RELOAD, SERVICE_STOP_WATCHDOG)) {
+ /* If there's already something running we go directly into kill mode. */
+ if (IN_SET(s->state, SERVICE_CONDITION, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, SERVICE_RELOAD, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY, SERVICE_STOP_WATCHDOG)) {
service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_SUCCESS);
return 0;
}
@@ -2651,7 +2687,8 @@ _pure_ static bool service_can_reload(Unit *u) {
assert(s);
- return !!s->exec_command[SERVICE_EXEC_RELOAD];
+ return s->exec_command[SERVICE_EXEC_RELOAD] ||
+ s->type == SERVICE_NOTIFY_RELOAD;
}
static unsigned service_exec_command_index(Unit *u, ServiceExecCommand id, ExecCommand *current) {
@@ -2827,6 +2864,9 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) {
if (s->watchdog_original_usec != USEC_INFINITY)
(void) serialize_item_format(f, "watchdog-original-usec", USEC_FMT, s->watchdog_original_usec);
+ if (s->reload_begin_usec != USEC_INFINITY)
+ (void) serialize_item_format(f, "reload-begin-usec", USEC_FMT, s->reload_begin_usec);
+
return 0;
}
@@ -3165,6 +3205,10 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value,
log_unit_debug_errno(u, r, "Failed to parse serialized flush restart counter setting '%s': %m", value);
else
s->flush_n_restarts = r;
+ } else if (streq(key, "reload-begin-usec")) {
+ r = deserialize_usec(value, &s->reload_begin_usec);
+ if (r < 0)
+ log_unit_debug_errno(u, r, "Failed to parse serialized reload begin timestamp '%s', ignoring: %m", value);
} else
log_unit_debug(u, "Unknown serialization key: %s", key);
@@ -3368,7 +3412,7 @@ static void service_notify_cgroup_empty_event(Unit *u) {
* SIGCHLD for. */
case SERVICE_START:
- if (s->type == SERVICE_NOTIFY &&
+ if (IN_SET(s->type, SERVICE_NOTIFY, SERVICE_NOTIFY_RELOAD) &&
main_pid_good(s) == 0 &&
control_pid_good(s) == 0) {
/* No chance of getting a ready notification anymore */
@@ -3572,17 +3616,19 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
} else {
s->main_command = NULL;
- /* Services with ExitType=cgroup do not act on main PID exiting,
- * unless the cgroup is already empty */
+ /* Services with ExitType=cgroup do not act on main PID exiting, unless the cgroup is
+ * already empty */
if (s->exit_type == SERVICE_EXIT_MAIN || cgroup_good(s) <= 0) {
/* The service exited, so the service is officially gone. */
switch (s->state) {
case SERVICE_START_POST:
case SERVICE_RELOAD:
- /* If neither main nor control processes are running then
- * the current state can never exit cleanly, hence immediately
- * terminate the service. */
+ case SERVICE_RELOAD_SIGNAL:
+ case SERVICE_RELOAD_NOTIFY:
+ /* If neither main nor control processes are running then the current
+ * state can never exit cleanly, hence immediately terminate the
+ * service. */
if (control_pid_good(s) <= 0)
service_enter_stop(s, f);
@@ -3601,7 +3647,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
else
service_enter_signal(s, SERVICE_STOP_SIGTERM, f);
break;
- } else if (s->type == SERVICE_NOTIFY) {
+ } else if (IN_SET(s->type, SERVICE_NOTIFY, SERVICE_NOTIFY_RELOAD)) {
/* Only enter running through a notification, so that the
* SERVICE_START state signifies that no ready notification
* has been received */
@@ -3694,15 +3740,13 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
s->control_command->command_next &&
f == SERVICE_SUCCESS) {
- /* There is another command to *
- * execute, so let's do that. */
+ /* There is another command to * execute, so let's do that. */
log_unit_debug(u, "Running next control command for state %s.", service_state_to_string(s->state));
service_run_next_control(s);
} else {
- /* No further commands for this step, so let's
- * figure out what to do next */
+ /* No further commands for this step, so let's figure out what to do next */
s->control_command = NULL;
s->control_command_id = _SERVICE_EXEC_COMMAND_INVALID;
@@ -3780,12 +3824,22 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
break;
case SERVICE_RELOAD:
+ case SERVICE_RELOAD_SIGNAL:
+ case SERVICE_RELOAD_NOTIFY:
if (f == SERVICE_SUCCESS)
if (service_load_pid_file(s, true) < 0)
service_search_main_pid(s);
s->reload_result = f;
- service_enter_running(s, SERVICE_SUCCESS);
+
+ /* If the last notification we received from the service process indiciates
+ * we are still reloading, then don't leave reloading state just yet, just
+ * transition into SERVICE_RELOAD_NOTIFY, to wait for the READY=1 coming,
+ * too. */
+ if (s->notify_state == NOTIFY_RELOADING)
+ service_set_state(s, SERVICE_RELOAD_NOTIFY);
+ else
+ service_enter_running(s, SERVICE_SUCCESS);
break;
case SERVICE_STOP:
@@ -3888,6 +3942,8 @@ static int service_dispatch_timer(sd_event_source *source, usec_t usec, void *us
break;
case SERVICE_RELOAD:
+ case SERVICE_RELOAD_SIGNAL:
+ case SERVICE_RELOAD_NOTIFY:
log_unit_warning(UNIT(s), "Reload operation timed out. Killing reload process.");
service_kill_control_process(s);
s->reload_result = SERVICE_FAILURE_TIMEOUT;
@@ -4113,6 +4169,7 @@ static void service_notify_message(
Service *s = SERVICE(u);
bool notify_dbus = false;
+ usec_t monotonic_usec = USEC_INFINITY;
const char *e;
int r;
@@ -4131,7 +4188,7 @@ static void service_notify_message(
/* Interpret MAINPID= */
e = strv_find_startswith(tags, "MAINPID=");
- if (e && IN_SET(s->state, SERVICE_START, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD)) {
+ if (e && IN_SET(s->state, SERVICE_START, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY)) {
pid_t new_main_pid;
if (parse_pid(e, &new_main_pid) < 0)
@@ -4160,43 +4217,73 @@ static void service_notify_message(
}
}
- /* Interpret READY=/STOPPING=/RELOADING=. Last one wins. */
- STRV_FOREACH_BACKWARDS(i, tags) {
+ /* Parse MONOTONIC_USEC= */
+ e = strv_find_startswith(tags, "MONOTONIC_USEC=");
+ if (e) {
+ r = safe_atou64(e, &monotonic_usec);
+ if (r < 0)
+ log_unit_warning_errno(u, r, "Failed to parse MONOTONIC_USEC= field in notification message, ignoring: %s", e);
+ }
- if (streq(*i, "READY=1")) {
- s->notify_state = NOTIFY_READY;
+ /* Interpret READY=/STOPPING=/RELOADING=. STOPPING= wins over the others, and READY= over RELOADING= */
+ if (strv_contains(tags, "STOPPING=1")) {
+ s->notify_state = NOTIFY_STOPPING;
- /* 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);
+ if (IN_SET(s->state, SERVICE_RUNNING, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY))
+ service_enter_stop_by_notify(s);
- /* 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);
+ notify_dbus = true;
- notify_dbus = true;
- break;
+ } else if (strv_contains(tags, "READY=1")) {
- } else if (streq(*i, "RELOADING=1")) {
- s->notify_state = NOTIFY_RELOADING;
+ s->notify_state = NOTIFY_READY;
- if (s->state == SERVICE_RUNNING)
- service_enter_reload_by_notify(s);
+ /* Type=notify services inform us about completed initialization with READY=1 */
+ if (IN_SET(s->type, SERVICE_NOTIFY, SERVICE_NOTIFY_RELOAD) &&
+ s->state == SERVICE_START)
+ service_enter_start_post(s);
- notify_dbus = true;
- break;
+ /* Sending READY=1 while we are reloading informs us that the reloading is complete. */
+ if (s->state == SERVICE_RELOAD_NOTIFY)
+ service_enter_running(s, SERVICE_SUCCESS);
- } else if (streq(*i, "STOPPING=1")) {
- s->notify_state = NOTIFY_STOPPING;
+ /* Combined RELOADING=1 and READY=1? Then this is indication that the service started and
+ * immediately finished reloading. */
+ if (s->state == SERVICE_RELOAD_SIGNAL &&
+ strv_contains(tags, "RELOADING=1") &&
+ monotonic_usec != USEC_INFINITY &&
+ monotonic_usec >= s->reload_begin_usec) {
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- if (s->state == SERVICE_RUNNING)
- service_enter_stop_by_notify(s);
+ /* Propagate a reload explicitly */
+ r = manager_propagate_reload(UNIT(s)->manager, UNIT(s), JOB_FAIL, &error);
+ if (r < 0)
+ log_unit_warning(UNIT(s), "Failed to schedule propagation of reload, ignoring: %s", bus_error_message(&error, r));
- notify_dbus = true;
- break;
+ service_enter_running(s, SERVICE_SUCCESS);
}
+
+ notify_dbus = true;
+
+ } else if (strv_contains(tags, "RELOADING=1")) {
+
+ s->notify_state = NOTIFY_RELOADING;
+
+ /* Sending RELOADING=1 after we send SIGHUP to request a reload will transition
+ * things to "reload-notify" state, where we'll wait for READY=1 to let us know the
+ * reload is done. Note that we insist on a timestamp being sent along here, so that
+ * we know for sure this is a reload cycle initiated *after* we sent the signal */
+ if (s->state == SERVICE_RELOAD_SIGNAL &&
+ monotonic_usec != USEC_INFINITY &&
+ monotonic_usec >= s->reload_begin_usec)
+ /* Note, we don't call service_enter_reload_by_notify() here, because we
+ * don't need reload propagation nor do we want to restart the time-out. */
+ service_set_state(s, SERVICE_RELOAD_NOTIFY);
+
+ if (s->state == SERVICE_RUNNING)
+ service_enter_reload_by_notify(s);
+
+ notify_dbus = true;
}
/* Interpret STATUS= */
@@ -4326,7 +4413,9 @@ static bool pick_up_pid_from_bus_name(Service *s) {
SERVICE_START,
SERVICE_START_POST,
SERVICE_RUNNING,
- SERVICE_RELOAD);
+ SERVICE_RELOAD,
+ SERVICE_RELOAD_SIGNAL,
+ SERVICE_RELOAD_NOTIFY);
}
static int bus_name_pid_lookup_callback(sd_bus_message *reply, void *userdata, sd_bus_error *ret_error) {
@@ -4533,6 +4622,8 @@ static bool service_needs_console(Unit *u) {
SERVICE_START_POST,
SERVICE_RUNNING,
SERVICE_RELOAD,
+ SERVICE_RELOAD_SIGNAL,
+ SERVICE_RELOAD_NOTIFY,
SERVICE_STOP,
SERVICE_STOP_WATCHDOG,
SERVICE_STOP_SIGTERM,
@@ -4655,13 +4746,14 @@ static const char* const service_restart_table[_SERVICE_RESTART_MAX] = {
DEFINE_STRING_TABLE_LOOKUP(service_restart, ServiceRestart);
static const char* const service_type_table[_SERVICE_TYPE_MAX] = {
- [SERVICE_SIMPLE] = "simple",
- [SERVICE_FORKING] = "forking",
- [SERVICE_ONESHOT] = "oneshot",
- [SERVICE_DBUS] = "dbus",
- [SERVICE_NOTIFY] = "notify",
- [SERVICE_IDLE] = "idle",
- [SERVICE_EXEC] = "exec",
+ [SERVICE_SIMPLE] = "simple",
+ [SERVICE_FORKING] = "forking",
+ [SERVICE_ONESHOT] = "oneshot",
+ [SERVICE_DBUS] = "dbus",
+ [SERVICE_NOTIFY] = "notify",
+ [SERVICE_NOTIFY_RELOAD] = "notify-reload",
+ [SERVICE_IDLE] = "idle",
+ [SERVICE_EXEC] = "exec",
};
DEFINE_STRING_TABLE_LOOKUP(service_type, ServiceType);
diff --git a/src/core/service.h b/src/core/service.h
index 763398e315..fd242a7cbf 100644
--- a/src/core/service.h
+++ b/src/core/service.h
@@ -25,13 +25,14 @@ typedef enum ServiceRestart {
} ServiceRestart;
typedef enum ServiceType {
- SERVICE_SIMPLE, /* we fork and go on right-away (i.e. modern socket activated daemons) */
- SERVICE_FORKING, /* forks by itself (i.e. traditional daemons) */
- SERVICE_ONESHOT, /* we fork and wait until the program finishes (i.e. programs like fsck which run and need to finish before we continue) */
- SERVICE_DBUS, /* we fork and wait until a specific D-Bus name appears on the bus */
- SERVICE_NOTIFY, /* we fork and wait until a daemon sends us a ready message with sd_notify() */
- SERVICE_IDLE, /* much like simple, but delay exec() until all jobs are dispatched. */
- SERVICE_EXEC, /* we fork and wait until we execute exec() (this means our own setup is waited for) */
+ SERVICE_SIMPLE, /* we fork and go on right-away (i.e. modern socket activated daemons) */
+ SERVICE_FORKING, /* forks by itself (i.e. traditional daemons) */
+ SERVICE_ONESHOT, /* we fork and wait until the program finishes (i.e. programs like fsck which run and need to finish before we continue) */
+ SERVICE_DBUS, /* we fork and wait until a specific D-Bus name appears on the bus */
+ SERVICE_NOTIFY, /* we fork and wait until a daemon sends us a ready message with sd_notify() */
+ SERVICE_NOTIFY_RELOAD, /* just like SERVICE_NOTIFY, but also implements a reload protocol via SIGHUP */
+ SERVICE_IDLE, /* much like simple, but delay exec() until all jobs are dispatched. */
+ SERVICE_EXEC, /* we fork and wait until we execute exec() (this means our own setup is waited for) */
_SERVICE_TYPE_MAX,
_SERVICE_TYPE_INVALID = -EINVAL,
} ServiceType;
@@ -218,6 +219,9 @@ struct Service {
OOMPolicy oom_policy;
LIST_HEAD(OpenFile, open_files);
+
+ int reload_signal;
+ usec_t reload_begin_usec;
};
static inline usec_t service_timeout_abort_usec(Service *s) {
diff --git a/src/login/logind.c b/src/login/logind.c
index def2f5a442..1feacd3601 100644
--- a/src/login/logind.c
+++ b/src/login/logind.c
@@ -1020,6 +1020,11 @@ static int manager_dispatch_reload_signal(sd_event_source *s, const struct signa
Manager *m = userdata;
int r;
+ (void) sd_notifyf(/* unset= */ false,
+ "RELOADING=1\n"
+ "STATUS=Reloading configuration...\n"
+ "MONOTONIC_USEC=" USEC_FMT, now(CLOCK_MONOTONIC));
+
manager_reset_config(m);
r = manager_parse_config_file(m);
if (r < 0)
@@ -1027,6 +1032,7 @@ static int manager_dispatch_reload_signal(sd_event_source *s, const struct signa
else
log_info("Config file reloaded.");
+ (void) sd_notify(/* unset= */ false, NOTIFY_READY);
return 0;
}
diff --git a/src/network/networkd-manager-bus.c b/src/network/networkd-manager-bus.c
index 2ab3aaadc2..67f951df69 100644
--- a/src/network/networkd-manager-bus.c
+++ b/src/network/networkd-manager-bus.c
@@ -197,7 +197,6 @@ static int bus_method_reconfigure_link(sd_bus_message *message, void *userdata,
static int bus_method_reload(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *manager = userdata;
- Link *link;
int r;
r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
@@ -209,20 +208,10 @@ static int bus_method_reload(sd_bus_message *message, void *userdata, sd_bus_err
if (r == 0)
return 1; /* Polkit will call us back */
- r = netdev_load(manager, true);
+ r = manager_reload(manager);
if (r < 0)
return r;
- r = network_reload(manager);
- if (r < 0)
- return r;
-
- HASHMAP_FOREACH(link, manager->links_by_index) {
- r = link_reconfigure(link, /* force = */ false);
- if (r < 0)
- return r;
- }
-
return sd_bus_reply_method_return(message, NULL);
}
diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c
index 7d067a8c46..f82117cc1e 100644
--- a/src/network/networkd-manager.c
+++ b/src/network/networkd-manager.c
@@ -474,6 +474,14 @@ static int signal_restart_callback(sd_event_source *s, const struct signalfd_sig
return sd_event_exit(sd_event_source_get_event(s), 0);
}
+static int signal_reload_callback(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
+ Manager *m = ASSERT_PTR(userdata);
+
+ manager_reload(m);
+
+ return 0;
+}
+
static int manager_set_keep_configuration(Manager *m) {
int r;
@@ -508,12 +516,11 @@ int manager_setup(Manager *m) {
if (r < 0)
return r;
- assert_se(sigprocmask_many(SIG_SETMASK, NULL, SIGINT, SIGTERM, SIGUSR2, -1) >= 0);
-
(void) sd_event_set_watchdog(m->event, true);
- (void) sd_event_add_signal(m->event, NULL, SIGTERM, signal_terminate_callback, m);
- (void) sd_event_add_signal(m->event, NULL, SIGINT, signal_terminate_callback, m);
- (void) sd_event_add_signal(m->event, NULL, SIGUSR2, signal_restart_callback, m);
+ (void) sd_event_add_signal(m->event, NULL, SIGTERM | SD_EVENT_SIGNAL_PROCMASK, signal_terminate_callback, m);
+ (void) sd_event_add_signal(m->event, NULL, SIGINT | SD_EVENT_SIGNAL_PROCMASK, signal_terminate_callback, m);
+ (void) sd_event_add_signal(m->event, NULL, SIGUSR2 | SD_EVENT_SIGNAL_PROCMASK, signal_restart_callback, m);
+ (void) sd_event_add_signal(m->event, NULL, SIGHUP | SD_EVENT_SIGNAL_PROCMASK, signal_reload_callback, m);
r = sd_event_add_post(m->event, NULL, manager_dirty_handler, m);
if (r < 0)
@@ -1069,3 +1076,34 @@ int manager_set_timezone(Manager *m, const char *tz) {
return 0;
}
+
+int manager_reload(Manager *m) {
+ Link *link;
+ int r;
+
+ assert(m);
+
+ (void) sd_notifyf(/* unset= */ false,
+ "RELOADING=1\n"
+ "STATUS=Reloading configuration...\n"
+ "MONOTONIC_USEC=" USEC_FMT, now(CLOCK_MONOTONIC));
+
+ r = netdev_load(m, /* reload= */ true);
+ if (r < 0)
+ goto finish;
+
+ r = network_reload(m);
+ if (r < 0)
+ goto finish;
+
+ HASHMAP_FOREACH(link, m->links_by_index) {
+ r = link_reconfigure(link, /* force = */ false);
+ if (r < 0)
+ goto finish;
+ }
+
+ r = 0;
+finish:
+ (void) sd_notify(/* unset= */ false, NOTIFY_READY);
+ return r;
+}
diff --git a/src/network/networkd-manager.h b/src/network/networkd-manager.h
index 40e6092f85..e6183af0e4 100644
--- a/src/network/networkd-manager.h
+++ b/src/network/networkd-manager.h
@@ -115,4 +115,6 @@ int manager_enumerate(Manager *m);
int manager_set_hostname(Manager *m, const char *hostname);
int manager_set_timezone(Manager *m, const char *timezone);
+int manager_reload(Manager *m);
+
DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
diff --git a/src/network/networkd.c b/src/network/networkd.c
index d61769d9f3..68760e8ff4 100644
--- a/src/network/networkd.c
+++ b/src/network/networkd.c
@@ -81,8 +81,6 @@ static int run(int argc, char *argv[]) {
if (r < 0)
log_warning_errno(r, "Could not create runtime directory 'lldp': %m");
- assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
-
r = manager_new(&m, /* test_mode = */ false);
if (r < 0)
return log_error_errno(r, "Could not create manager: %m");
diff --git a/src/notify/notify.c b/src/notify/notify.c
index c4f54920ac..b1348383f5 100644
--- a/src/notify/notify.c
+++ b/src/notify/notify.c
@@ -23,6 +23,8 @@
#include "user-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)
diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c
index 0fa2dea2d4..1e95e36678 100644
--- a/src/shared/bus-unit-util.c
+++ b/src/shared/bus-unit-util.c
@@ -2094,7 +2094,8 @@ static int bus_append_kill_property(sd_bus_message *m, const char *field, const
if (STR_IN_SET(field, "KillSignal",
"RestartKillSignal",
"FinalKillSignal",
- "WatchdogSignal"))
+ "WatchdogSignal",
+ "ReloadSignal"))
return bus_append_signal_from_string(m, field, eq);
return 0;
diff --git a/src/udev/udevd.c b/src/udev/udevd.c
index 28b76bfbab..6fb0305e09 100644
--- a/src/udev/udevd.c
+++ b/src/udev/udevd.c
@@ -32,6 +32,7 @@
#include "cgroup-setup.h"
#include "cgroup-util.h"
#include "cpu-set-util.h"
+#include "daemon-util.h"
#include "dev-setup.h"
#include "device-monitor-private.h"
#include "device-private.h"
@@ -330,9 +331,7 @@ static void manager_exit(Manager *manager) {
manager->exit = true;
- sd_notify(false,
- "STOPPING=1\n"
- "STATUS=Starting shutdown...");
+ (void) sd_notify(/* unset= */ false, NOTIFY_STOPPING);
/* close sources of new events and discard buffered events */
manager->ctrl = udev_ctrl_unref(manager->ctrl);
@@ -350,7 +349,7 @@ static void manager_exit(Manager *manager) {
static void notify_ready(void) {
int r;
- r = sd_notifyf(false,
+ r = sd_notifyf(/* unset= */ false,
"READY=1\n"
"STATUS=Processing with %u children at max", arg_children_max);
if (r < 0)
@@ -375,23 +374,33 @@ static void manager_reload(Manager *manager, bool force) {
mac_selinux_maybe_reload();
/* Nothing changed. It is not necessary to reload. */
- if (!udev_rules_should_reload(manager->rules) && !udev_builtin_should_reload())
- return;
+ if (!udev_rules_should_reload(manager->rules) && !udev_builtin_should_reload()) {
- sd_notify(false,
- "RELOADING=1\n"
- "STATUS=Flushing configuration...");
+ if (!force)
+ return;
- manager_kill_workers(manager, false);
+ /* If we eat this up, then tell our service manager to just continue */
+ (void) sd_notifyf(/* unset= */ false,
+ "RELOADING=1\n"
+ "STATUS=Skipping configuration reloading, nothing changed.\n"
+ "MONOTONIC_USEC=" USEC_FMT, now(CLOCK_MONOTONIC));
+ } else {
+ (void) sd_notifyf(/* unset= */ false,
+ "RELOADING=1\n"
+ "STATUS=Flushing configuration...\n"
+ "MONOTONIC_USEC=" USEC_FMT, now(CLOCK_MONOTONIC));
- udev_builtin_exit();
- udev_builtin_init();
+ manager_kill_workers(manager, false);
- r = udev_rules_load(&rules, arg_resolve_name_timing);
- if (r < 0)
- log_warning_errno(r, "Failed to read udev rules, using the previously loaded rules, ignoring: %m");
- else
- udev_rules_free_and_replace(manager->rules, rules);
+ udev_builtin_exit();
+ udev_builtin_init();
+
+ r = udev_rules_load(&rules, arg_resolve_name_timing);
+ if (r < 0)
+ log_warning_errno(r, "Failed to read udev rules, using the previously loaded rules, ignoring: %m");
+ else
+ udev_rules_free_and_replace(manager->rules, rules);
+ }
notify_ready();
}
@@ -1985,9 +1994,7 @@ static int main_loop(Manager *manager) {
if (r < 0)
log_error_errno(r, "Event loop failed: %m");
- sd_notify(false,
- "STOPPING=1\n"
- "STATUS=Shutting down...");
+ (void) sd_notify(/* unset= */ false, NOTIFY_STOPPING);
return r;
}
diff --git a/test/units/testsuite-59.sh b/test/units/testsuite-59.sh
index ab6b2216fe..db8dc27ab9 100755
--- a/test/units/testsuite-59.sh
+++ b/test/units/testsuite-59.sh
@@ -104,6 +104,59 @@ sleep 10
systemctl daemon-reload
+# Let's now test the notify-reload logic
+
+cat >/run/notify-reload-test.sh </testok
exit 0
diff --git a/units/systemd-logind.service.in b/units/systemd-logind.service.in
index 042ea75d7a..24f5ddaa17 100644
--- a/units/systemd-logind.service.in
+++ b/units/systemd-logind.service.in
@@ -58,6 +58,7 @@ StateDirectory=systemd/linger
SystemCallArchitectures=native
SystemCallErrorNumber=EPERM
SystemCallFilter=@system-service
+Type=notify-reload
{{SERVICE_WATCHDOG}}
# Increase the default a bit in order to allow many simultaneous logins since
diff --git a/units/systemd-networkd.service.in b/units/systemd-networkd.service.in
index d15129e7f0..d8b935a358 100644
--- a/units/systemd-networkd.service.in
+++ b/units/systemd-networkd.service.in
@@ -24,7 +24,6 @@ BusName=org.freedesktop.network1
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_BROADCAST CAP_NET_RAW
DeviceAllow=char-* rw
ExecStart=!!{{ROOTLIBEXECDIR}}/systemd-networkd
-ExecReload=networkctl reload
FileDescriptorStoreMax=512
LockPersonality=yes
MemoryDenyWriteExecute=yes
@@ -48,7 +47,7 @@ RuntimeDirectoryPreserve=yes
SystemCallArchitectures=native
SystemCallErrorNumber=EPERM
SystemCallFilter=@system-service
-Type=notify
+Type=notify-reload
User=systemd-network
{{SERVICE_WATCHDOG}}
diff --git a/units/systemd-udevd.service.in b/units/systemd-udevd.service.in
index e9dbe85ef4..dfc2a0e341 100644
--- a/units/systemd-udevd.service.in
+++ b/units/systemd-udevd.service.in
@@ -18,14 +18,13 @@ ConditionPathIsReadWrite=/sys
[Service]
CapabilityBoundingSet=~CAP_SYS_TIME CAP_WAKE_ALARM
Delegate=pids
-Type=notify
+Type=notify-reload
# Note that udev will reset the value internally for its workers
OOMScoreAdjust=-1000
Sockets=systemd-udevd-control.socket systemd-udevd-kernel.socket
Restart=always
RestartSec=0
ExecStart={{ROOTLIBEXECDIR}}/systemd-udevd
-ExecReload=udevadm control --reload --timeout 0
KillMode=mixed
TasksMax=infinity
PrivateMounts=yes
diff --git a/units/user@.service.in b/units/user@.service.in
index 1660de0326..1558764909 100644
--- a/units/user@.service.in
+++ b/units/user@.service.in
@@ -17,7 +17,7 @@ IgnoreOnIsolate=yes
[Service]
User=%i
PAMName=systemd-user
-Type=notify
+Type=notify-reload
ExecStart={{ROOTLIBEXECDIR}}/systemd --user
Slice=user-%i.slice
KillMode=mixed