Merge pull request #25916 from poettering/reload-notify

pid1: add new Type=notify-reload service type for a service reload protocol based on SIGHUP
This commit is contained in:
Lennart Poettering
2023-01-11 09:23:47 +01:00
committed by GitHub
27 changed files with 601 additions and 294 deletions
+3 -12
View File
@@ -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=
+6
View File
@@ -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 {
<!--property OpenFile is not documented!-->
<!--property ReloadSignal is not documented!-->
<!--property ExecCondition is not documented!-->
<!--property ExecConditionEx is not documented!-->
@@ -3735,6 +3739,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
<variablelist class="dbus-property" generated="True" extra-ref="OpenFile"/>
<variablelist class="dbus-property" generated="True" extra-ref="ReloadSignal"/>
<variablelist class="dbus-property" generated="True" extra-ref="ExecMainStartTimestamp"/>
<variablelist class="dbus-property" generated="True" extra-ref="ExecMainStartTimestampMonotonic"/>
+24 -12
View File
@@ -102,23 +102,35 @@
<varlistentry>
<term>READY=1</term>
<listitem><para>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 <varname>Type=notify</varname>
set. Since there is little value in signaling non-readiness, the only value services should send is
<literal>READY=1</literal> (i.e. <literal>READY=0</literal> is not defined).</para></listitem>
<listitem><para>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
<varname>Type=notify</varname> or <varname>Type=notify-reload</varname> set. Since there is little
value in signaling non-readiness, the only value services should send is <literal>READY=1</literal>
(i.e. <literal>READY=0</literal> is not defined).</para></listitem>
</varlistentry>
<varlistentry>
<term>RELOADING=1</term>
<listitem><para>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 <literal>READY=1</literal>
notification when it completed reloading its
configuration. Reloads are propagated in the same way as they
are when initiated by the user.</para></listitem>
<listitem><para>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
<literal>READY=1</literal> 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
<varname>Type=notify-reload</varname> services, to inform the service manager that the request to
reload the service has been received and is now being processed.</para></listitem>
</varlistentry>
<varlistentry>
<term>MONOTONIC_USEC=…</term>
<listitem><para>A field carrying the monotonic timestamp (as per
<constant>CLOCK_MONOTONIC</constant>) formatted in decimal in µs, when the notification message was
generated by the client. This is typically used in combination with <literal>RELOADING=1</literal>,
to allow the service manager to properly synchronize reload cycles. See
<citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for details, specifically <literal>Type=notify-reload</literal>.</para></listitem>
</varlistentry>
<varlistentry>
+51 -36
View File
@@ -30,20 +30,18 @@
<refsect1>
<title>Description</title>
<para><command>systemd-notify</command> 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.</para>
<para><command>systemd-notify</command> 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.</para>
<para>This is mostly just a wrapper around
<function>sd_notify()</function> and makes this functionality
<para>This is mostly just a wrapper around <function>sd_notify()</function> and makes this functionality
available to shell scripts. For details see
<citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
</para>
<para>The command line may carry a list of environment variables
to send as part of the status update.</para>
<para>The command line may carry a list of environment variables to send as part of the status
update.</para>
<para>Note that systemd will refuse reception of status updates from this command unless
<varname>NotifyAccess=</varname> is appropriately set for the service unit this command is called
@@ -52,9 +50,9 @@
details.</para>
<para>Note that <function>sd_notify()</function> 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
<varname>NotifyAccess=</varname><option>main</option> or
<varname>NotifyAccess=</varname><option>exec</option>. Conversely, if an auxiliary process of the unit
sends an <function>sd_notify()</function> message and immediately exits, the service manager might not be
@@ -84,22 +82,42 @@
<varlistentry>
<term><option>--ready</option></term>
<listitem><para>Inform the init system about service start-up
completion. This is equivalent to <command>systemd-notify
READY=1</command>. For details about the semantics of this
option see
<listitem><para>Inform the invoking service manager about service start-up or configuration reload
completion. This is equivalent to <command>systemd-notify READY=1</command>. For details about the
semantics of this option see
<citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--reloading</option></term>
<listitem><para>Inform the invoking service manager about the beginning of a configuration reload
cycle. This is equivalent to <command>systemd-notify RELOADING=1</command> (but implicitly also sets
a <varname>MONOTONIC_USEC=</varname> field as required for <varname>Type=notify-reload</varname>
services, see
<citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
for details). For details about the semantics of this option see
<citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--stopping</option></term>
<listitem><para>Inform the invoking service manager about the beginning of the shutdown phase of the
service. This is equivalent to <command>systemd-notify STOPPING=1</command>. For details about the
semantics of this option see
<citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--pid=</option></term>
<listitem><para>Inform the service manager about the main PID of the daemon. Takes a PID as
<listitem><para>Inform the service manager about the main PID of the service. Takes a PID as
argument. If the argument is specified as <literal>auto</literal> or omitted, the PID of the process
that invoked <command>systemd-notify</command> is used, except if that's the service manager. If the
argument is specified as <literal>self</literal>, the PID of the <command>systemd-notify</command>
command itself is used, and if <literal>parent</literal> is specified the calling process' PID is
used — even if it is the service manager. This is equivalent to <command>systemd-notify
used — even if it is the service manager. The latter is equivalent to <command>systemd-notify
MAINPID=$PID</command>. For details about the semantics of this option see
<citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para>
@@ -124,27 +142,26 @@
<varlistentry>
<term><option>--status=</option></term>
<listitem><para>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 <command>systemd-notify
STATUS=…</command>. For details about the semantics of this
option see
<citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para></listitem>
<listitem><para>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
<command>systemd-notify STATUS=…</command>. For details about the semantics of this option see
<citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>. This
information is shown in
<citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>'s
<command>status</command> output, among other places.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--booted</option></term>
<listitem><para>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
<listitem><para>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
<citerefentry><refentrytitle>sd_booted</refentrytitle><manvolnum>3</manvolnum></citerefentry>. An
alternate way to check for this state is to call
<citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
with the <command>is-system-running</command> command. It will
return <literal>offline</literal> if the system was not booted
with systemd. </para></listitem>
<citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry> with
the <command>is-system-running</command> command. It will return <literal>offline</literal> if the
system was not booted with systemd. </para></listitem>
</varlistentry>
<varlistentry>
@@ -176,9 +193,8 @@
<example>
<title>Start-up Notification and Status Updates</title>
<para>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:</para>
<para>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:</para>
<programlisting>#!/bin/sh
@@ -207,5 +223,4 @@ done</programlisting>
<citerefentry><refentrytitle>sd_booted</refentrytitle><manvolnum>3</manvolnum></citerefentry>
</para>
</refsect1>
</refentry>
+138 -110
View File
@@ -157,7 +157,7 @@
<listitem>
<para>Configures the process start-up type for this service unit. One of <option>simple</option>,
<option>exec</option>, <option>forking</option>, <option>oneshot</option>, <option>dbus</option>,
<option>notify</option> or <option>idle</option>:</para>
<option>notify</option>, <option>notify-reload</option> or <option>idle</option>:</para>
<itemizedlist>
<listitem><para>If set to <option>simple</option> (the default if <varname>ExecStart=</varname> is
@@ -216,14 +216,30 @@
logic thus should be prepared to receive a <constant>SIGTERM</constant> (or whichever signal is
configured in <varname>KillSignal=</varname>) as result.</para></listitem>
<listitem><para>Behavior of <option>notify</option> is similar to <option>exec</option>; however, it is
expected that the service sends a notification message via
<citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry> 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, <varname>NotifyAccess=</varname> (see
below) should be set to open access to the notification socket provided by systemd. If
<varname>NotifyAccess=</varname> is missing or set to <option>none</option>, it will be forcibly set to
<option>main</option>.</para></listitem>
<listitem><para>Behavior of <option>notify</option> is similar to <option>exec</option>; however,
it is expected that the service sends a <literal>READY=1</literal> notification message via
<citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry> 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,
<varname>NotifyAccess=</varname> (see below) should be set to open access to the notification
socket provided by systemd. If <varname>NotifyAccess=</varname> is missing or set to
<option>none</option>, it will be forcibly set to <option>main</option>.</para></listitem>
<listitem><para>Behavior of <option>notify-reload</option> is identical to
<option>notify</option>. However, it extends the logic in one way: the
<constant>SIGHUP</constant> 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
<varname>ReloadSignal=</varname>, see below.). When
initiating the reload process the service is then expected to reply with a notification message
via <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>
that contains the <literal>RELOADING=1</literal> field in combination with
<literal>MONOTONIC_USEC=</literal> set to the current monotonic time
(i.e. <constant>CLOCK_MONOTONIC</constant> in
<citerefentry><refentrytitle>clock_gettime</refentrytitle><manvolnum>2</manvolnum></citerefentry>)
in µs, formatted as decimal string. Once reloading is complete another notification message must
be sent, containing <literal>READY=1</literal>. Using this service type and implementing this
reload protocol is an efficient alternative to providing an <varname>ExecReload=</varname>
command for reloading of the service's configuration.</para></listitem>
<listitem><para>Behavior of <option>idle</option> is very similar to <option>simple</option>; however,
actual execution of the service program is delayed until all active jobs are dispatched. This may be used
@@ -233,25 +249,27 @@
anyway.</para></listitem>
</itemizedlist>
<para>It is generally recommended to use <varname>Type=</varname><option>simple</option> 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,
<option>notify</option> or <option>dbus</option> (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
<option>notify</option> service type requires explicit support in the service codebase (as
<function>sd_notify()</function> or an equivalent API needs to be invoked by the service at the appropriate
time) — if it's not supported, then <option>forking</option> is an alternative: it supports the traditional
UNIX service start-up protocol. Finally, <option>exec</option> 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
<option>simple</option> 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
<option>simple</option>. (Also note it is generally not recommended to use <option>idle</option> or
<option>oneshot</option> for long-running services.)</para>
<para>It is generally recommended to use <varname>Type=</varname><option>simple</option> 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, <option>notify</option>,
<option>notify-reload</option> or <option>dbus</option> (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 <option>notify</option>/<option>notify-reload</option> service types require
explicit support in the service codebase (as <function>sd_notify()</function> or an equivalent API
needs to be invoked by the service at the appropriate time) — if it's not supported, then
<option>forking</option> is an alternative: it supports the traditional UNIX service start-up
protocol. Finally, <option>exec</option> 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 <option>simple</option> 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 <option>simple</option>. (Also note it is generally not recommended to use
<option>idle</option> or <option>oneshot</option> for long-running services.)</para>
</listitem>
</varlistentry>
@@ -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.</para>
<para>Note that PID files should be avoided in modern projects. Use <option>Type=notify</option> or
<option>Type=simple</option> where possible, which does not require use of PID files to determine the
main process of a service and avoids needless forking.</para></listitem>
<para>Note that PID files should be avoided in modern projects. Use <option>Type=notify</option>,
<option>Type=notify-reload</option> or <option>Type=simple</option> where possible, which does not
require use of PID files to determine the main process of a service and avoids needless
forking.</para></listitem>
</varlistentry>
<varlistentry>
@@ -443,12 +462,13 @@
with a <literal>-</literal> exit successfully.</para>
<para><varname>ExecStartPost=</varname> commands are only run after the commands specified in
<varname>ExecStart=</varname> have been invoked successfully, as determined by <varname>Type=</varname>
(i.e. the process has been started for <varname>Type=simple</varname> or <varname>Type=idle</varname>, the last
<varname>ExecStart=</varname> process exited successfully for <varname>Type=oneshot</varname>, the initial
process exited successfully for <varname>Type=forking</varname>, <literal>READY=1</literal> is sent for
<varname>Type=notify</varname>, or the <varname>BusName=</varname> has been taken for
<varname>Type=dbus</varname>).</para>
<varname>ExecStart=</varname> have been invoked successfully, as determined by
<varname>Type=</varname> (i.e. the process has been started for <varname>Type=simple</varname> or
<varname>Type=idle</varname>, the last <varname>ExecStart=</varname> process exited successfully for
<varname>Type=oneshot</varname>, the initial process exited successfully for
<varname>Type=forking</varname>, <literal>READY=1</literal> is sent for
<varname>Type=notify</varname>/<varname>Type=notify-reload</varname>, or the
<varname>BusName=</varname> has been taken for <varname>Type=dbus</varname>).</para>
<para>Note that <varname>ExecStartPre=</varname> may not be
used to start long-running processes. All processes forked
@@ -487,30 +507,26 @@
<varlistentry>
<term><varname>ExecReload=</varname></term>
<listitem><para>Commands to execute to trigger a configuration
reload in the service. This argument takes multiple command
lines, following the same scheme as described for
<varname>ExecStart=</varname> above. Use of this setting is
optional. Specifier and environment variable substitution is
supported here following the same scheme as for
<listitem><para>Commands to execute to trigger a configuration reload in the service. This argument
takes multiple command lines, following the same scheme as described for
<varname>ExecStart=</varname> above. Use of this setting is optional. Specifier and environment
variable substitution is supported here following the same scheme as for
<varname>ExecStart=</varname>.</para>
<para>One additional, special environment variable is set: if
known, <varname>$MAINPID</varname> is set to the main process
of the daemon, and may be used for command lines like the
following:</para>
<para>One additional, special environment variable is set: if known, <varname>$MAINPID</varname> is
set to the main process of the daemon, and may be used for command lines like the following:</para>
<programlisting>ExecReload=kill -HUP $MAINPID</programlisting>
<para>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
<varname>ExecReload=</varname> to a command that not only
triggers a configuration reload of the daemon, but also
synchronously waits for it to complete. For example,
<citerefentry project='mankier'><refentrytitle>dbus-broker</refentrytitle><manvolnum>1</manvolnum></citerefentry>
<para>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 <varname>Type=</varname><option>notify-reload</option> in place of
<varname>ExecReload=</varname>, or to set <varname>ExecReload=</varname> to a command that not only
triggers a configuration reload of the daemon, but also synchronously waits for it to complete. For
example, <citerefentry
project='mankier'><refentrytitle>dbus-broker</refentrytitle><manvolnum>1</manvolnum></citerefentry>
uses the following:</para>
<programlisting>ExecReload=busctl call org.freedesktop.DBus \
@@ -605,12 +621,13 @@
<citerefentry><refentrytitle>systemd-system.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>).
</para>
<para>If a service of <varname>Type=notify</varname> sends <literal>EXTEND_TIMEOUT_USEC=…</literal>, this may cause
the start time to be extended beyond <varname>TimeoutStartSec=</varname>. The first receipt of this message
must occur before <varname>TimeoutStartSec=</varname> is exceeded, and once the start time has extended beyond
<varname>TimeoutStartSec=</varname>, the service manager will allow the service to continue to start, provided
the service repeats <literal>EXTEND_TIMEOUT_USEC=…</literal> within the interval specified until the service
startup status is finished by <literal>READY=1</literal>. (see
<para>If a service of <varname>Type=notify</varname>/<varname>Type=notify-reload</varname> sends
<literal>EXTEND_TIMEOUT_USEC=…</literal>, this may cause the start time to be extended beyond
<varname>TimeoutStartSec=</varname>. The first receipt of this message must occur before
<varname>TimeoutStartSec=</varname> is exceeded, and once the start time has extended beyond
<varname>TimeoutStartSec=</varname>, the service manager will allow the service to continue to start,
provided the service repeats <literal>EXTEND_TIMEOUT_USEC=…</literal> within the interval specified
until the service startup status is finished by <literal>READY=1</literal>. (see
<citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>).
</para></listitem>
</varlistentry>
@@ -633,12 +650,14 @@
<citerefentry><refentrytitle>systemd-system.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>).
</para>
<para>If a service of <varname>Type=notify</varname> sends <literal>EXTEND_TIMEOUT_USEC=…</literal>, this may cause
the stop time to be extended beyond <varname>TimeoutStopSec=</varname>. The first receipt of this message
must occur before <varname>TimeoutStopSec=</varname> is exceeded, and once the stop time has extended beyond
<varname>TimeoutStopSec=</varname>, the service manager will allow the service to continue to stop, provided
the service repeats <literal>EXTEND_TIMEOUT_USEC=…</literal> within the interval specified, or terminates itself
(see <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>).
<para>If a service of <varname>Type=notify</varname>/<varname>Type=notify-reload</varname> sends
<literal>EXTEND_TIMEOUT_USEC=…</literal>, this may cause the stop time to be extended beyond
<varname>TimeoutStopSec=</varname>. The first receipt of this message must occur before
<varname>TimeoutStopSec=</varname> is exceeded, and once the stop time has extended beyond
<varname>TimeoutStopSec=</varname>, the service manager will allow the service to continue to stop,
provided the service repeats <literal>EXTEND_TIMEOUT_USEC=…</literal> within the interval specified,
or terminates itself (see
<citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>).
</para></listitem>
</varlistentry>
@@ -661,13 +680,15 @@
<citerefentry><refentrytitle>systemd-system.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>).
</para>
<para>If a service of <varname>Type=notify</varname> handles <constant>SIGABRT</constant> itself (instead of relying
on the kernel to write a core dump) it can send <literal>EXTEND_TIMEOUT_USEC=…</literal> to
extended the abort time beyond <varname>TimeoutAbortSec=</varname>. The first receipt of this message
must occur before <varname>TimeoutAbortSec=</varname> is exceeded, and once the abort time has extended beyond
<varname>TimeoutAbortSec=</varname>, the service manager will allow the service to continue to abort, provided
the service repeats <literal>EXTEND_TIMEOUT_USEC=…</literal> within the interval specified, or terminates itself
(see <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>).
<para>If a service of <varname>Type=notify</varname>/<varname>Type=notify-reload</varname> handles
<constant>SIGABRT</constant> itself (instead of relying on the kernel to write a core dump) it can
send <literal>EXTEND_TIMEOUT_USEC=…</literal> to extended the abort time beyond
<varname>TimeoutAbortSec=</varname>. The first receipt of this message must occur before
<varname>TimeoutAbortSec=</varname> is exceeded, and once the abort time has extended beyond
<varname>TimeoutAbortSec=</varname>, the service manager will allow the service to continue to abort,
provided the service repeats <literal>EXTEND_TIMEOUT_USEC=…</literal> within the interval specified,
or terminates itself (see
<citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>).
</para></listitem>
</varlistentry>
@@ -710,12 +731,13 @@
activation completed. Pass <literal>infinity</literal> (the default) to configure no runtime
limit.</para>
<para>If a service of <varname>Type=notify</varname> sends <literal>EXTEND_TIMEOUT_USEC=…</literal>, this may cause
the runtime to be extended beyond <varname>RuntimeMaxSec=</varname>. The first receipt of this message
must occur before <varname>RuntimeMaxSec=</varname> is exceeded, and once the runtime has extended beyond
<varname>RuntimeMaxSec=</varname>, the service manager will allow the service to continue to run, provided
the service repeats <literal>EXTEND_TIMEOUT_USEC=…</literal> within the interval specified until the service
shutdown is achieved by <literal>STOPPING=1</literal> (or termination). (see
<para>If a service of <varname>Type=notify</varname>/<varname>Type=notify-reload</varname> sends
<literal>EXTEND_TIMEOUT_USEC=…</literal>, this may cause the runtime to be extended beyond
<varname>RuntimeMaxSec=</varname>. The first receipt of this message must occur before
<varname>RuntimeMaxSec=</varname> is exceeded, and once the runtime has extended beyond
<varname>RuntimeMaxSec=</varname>, the service manager will allow the service to continue to run,
provided the service repeats <literal>EXTEND_TIMEOUT_USEC=…</literal> within the interval specified
until the service shutdown is achieved by <literal>STOPPING=1</literal> (or termination). (see
<citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>).
</para></listitem>
</varlistentry>
@@ -1023,16 +1045,19 @@
<varlistentry>
<term><varname>NotifyAccess=</varname></term>
<listitem><para>Controls access to the service status 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>, <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
main or 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 <varname>Type=notify</varname> or
<varname>WatchdogSec=</varname> (see above). If those options are used but <varname>NotifyAccess=</varname> is
not configured, it will be implicitly set to <option>main</option>.</para>
<citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>
call. Takes one of <option>none</option> (the default), <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 main or 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
<varname>Type=notify</varname>/<varname>Type=notify-reload</varname> or
<varname>WatchdogSec=</varname> (see above). If those options are used but
<varname>NotifyAccess=</varname> is not configured, it will be implicitly set to
<option>main</option>.</para>
<para>Note that <function>sd_notify()</function> 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 <command>systemd-oomd</command> kills a
cgroup associated with it.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>OpenFile=</varname></term>
<listitem><para>Takes an argument of the form <literal>path<optional><replaceable>:fd-name:options</replaceable></optional></literal>,
@@ -1187,6 +1213,14 @@
If the empty string is assigned, the entire list of open files defined prior to this is reset.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>ReloadSignal=</varname></term>
<listitem><para>Configures the UNIX process signal to send to the service's main process when asked
to reload the service's configuration. Defaults to <constant>SIGHUP</constant>. This option has no
effect unless <varname>Type=</varname><option>notify-reload</option> is used, see
above.</para></listitem>
</varlistentry>
</variablelist>
<para id='shared-unit-options'>Check
@@ -1350,16 +1384,13 @@ WantedBy=multi-user.target</programlisting>
<citerefentry><refentrytitle>systemd.kill</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for details.</para>
<para>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
<varname>Type=</varname><option>notify</option> if the service
understands systemd's notification protocol,
<varname>Type=</varname><option>forking</option> if the service
can background itself or
<varname>Type=</varname><option>dbus</option> if the unit
acquires a DBus name once initialization is complete. See
below.</para>
<para>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
<varname>Type=</varname><option>notify</option>/<varname>Type=</varname><option>notify-reload</option>
if the service understands systemd's notification protocol,
<varname>Type=</varname><option>forking</option> if the service can background itself or
<varname>Type=</varname><option>dbus</option> if the unit acquires a DBus name once initialization is
complete. See below.</para>
</example>
<example>
@@ -1536,15 +1567,12 @@ SystemdService=simple-dbus-service.service</programlisting>
<example>
<title>Services that notify systemd about their initialization</title>
<para><varname>Type=</varname><option>simple</option> 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
<varname>Type=</varname><option>notify</option> for this. A
typical service file for such a daemon would look like
this:</para>
<para><varname>Type=</varname><option>simple</option> 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 <varname>Type=</varname><option>notify</option> or
<varname>Type=</varname><option>notify-reload</option> for this. A typical service file for such a
daemon would look like this:</para>
<programlisting>[Unit]
Description=Simple notifying service
+2
View File
@@ -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",
+3 -1
View File
@@ -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,
+5
View File
@@ -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;
}
+1
View File
@@ -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') }}
+10
View File
@@ -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) {
+14
View File
@@ -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;
+1
View File
@@ -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);
+159 -67
View File
@@ -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);
+11 -7
View File
@@ -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) {
+6
View File
@@ -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;
}
+1 -12
View File
@@ -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);
}
+43 -5
View File
@@ -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;
}
+2
View File
@@ -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);
-2
View File
@@ -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");
+35 -4
View File
@@ -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)
+2 -1
View File
@@ -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;
+27 -20
View File
@@ -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;
}
+53
View File
@@ -104,6 +104,59 @@ sleep 10
systemctl daemon-reload
# Let's now test the notify-reload logic
cat >/run/notify-reload-test.sh <<EOF
#!/usr/bin/env bash
set -eux
set -o pipefail
EXIT_STATUS=88
LEAVE=0
function reload() {
systemd-notify --reloading --status="Adding 11 to exit status"
EXIT_STATUS=\$((\$EXIT_STATUS + 11))
systemd-notify --ready --status="Back running"
}
function leave() {
systemd-notify --stopping --status="Adding 7 to exit status"
EXIT_STATUS=\$((\$EXIT_STATUS + 7))
LEAVE=1
return 0
}
trap reload SIGHUP
trap leave SIGTERM
systemd-notify --ready
systemd-notify --status="Running now"
while [ \$LEAVE = 0 ] ; do
sleep 1
done
systemd-notify --status="Adding 3 to exit status"
EXIT_STATUS=\$((\$EXIT_STATUS + 3))
exit \$EXIT_STATUS
EOF
chmod +x /run/notify-reload-test.sh
systemd-analyze log-level debug
systemd-run --unit notify-reload-test -p Type=notify-reload -p KillMode=process /run/notify-reload-test.sh
systemctl reload notify-reload-test
systemctl stop notify-reload-test
test "$(systemctl show -p ExecMainStatus --value notify-reload-test)" = 109
systemctl reset-failed notify-reload-test
rm /run/notify-reload-test.sh
systemd-analyze log-level info
echo OK >/testok
exit 0
+1
View File
@@ -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
+1 -2
View File
@@ -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}}
+1 -2
View File
@@ -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
+1 -1
View File
@@ -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