1
0
mirror of https://github.com/systemd/systemd synced 2025-11-07 02:44:46 +01:00

Compare commits

..

No commits in common. "8457f2a3951bca7fca5dd67d4cbdba667a49576c" and "05b880ac46b27c65de09d7add6b0e2f5ac3bcd9a" have entirely different histories.

29 changed files with 298 additions and 546 deletions

View File

@ -2856,10 +2856,6 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
@org.freedesktop.DBus.Property.EmitsChangedSignal("invalidates") @org.freedesktop.DBus.Property.EmitsChangedSignal("invalidates")
readonly a(sasasttttuii) ExecReloadEx = [...]; readonly a(sasasttttuii) ExecReloadEx = [...];
@org.freedesktop.DBus.Property.EmitsChangedSignal("invalidates") @org.freedesktop.DBus.Property.EmitsChangedSignal("invalidates")
readonly a(sasbttttuii) ExecReloadPost = [...];
@org.freedesktop.DBus.Property.EmitsChangedSignal("invalidates")
readonly a(sasasttttuii) ExecReloadPostEx = [...];
@org.freedesktop.DBus.Property.EmitsChangedSignal("invalidates")
readonly a(sasbttttuii) ExecStop = [...]; readonly a(sasbttttuii) ExecStop = [...];
@org.freedesktop.DBus.Property.EmitsChangedSignal("invalidates") @org.freedesktop.DBus.Property.EmitsChangedSignal("invalidates")
readonly a(sasasttttuii) ExecStopEx = [...]; readonly a(sasasttttuii) ExecStopEx = [...];
@ -3541,10 +3537,10 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
<!--property ExecReloadEx is not documented!--> <!--property ExecReloadEx is not documented!-->
<!--property ExecReloadPostEx is not documented!-->
<!--property ExecStopEx is not documented!--> <!--property ExecStopEx is not documented!-->
<!--property ExecStopPost is not documented!-->
<!--property ExecStopPostEx is not documented!--> <!--property ExecStopPostEx is not documented!-->
<!--property Slice is not documented!--> <!--property Slice is not documented!-->
@ -4215,10 +4211,6 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
<variablelist class="dbus-property" generated="True" extra-ref="ExecReloadEx"/> <variablelist class="dbus-property" generated="True" extra-ref="ExecReloadEx"/>
<variablelist class="dbus-property" generated="True" extra-ref="ExecReloadPost"/>
<variablelist class="dbus-property" generated="True" extra-ref="ExecReloadPostEx"/>
<variablelist class="dbus-property" generated="True" extra-ref="ExecStop"/> <variablelist class="dbus-property" generated="True" extra-ref="ExecStop"/>
<variablelist class="dbus-property" generated="True" extra-ref="ExecStopEx"/> <variablelist class="dbus-property" generated="True" extra-ref="ExecStopEx"/>
@ -4849,10 +4841,10 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
last watchdog ping received from the service, or 0 if none was ever received.</para> last watchdog ping received from the service, or 0 if none was ever received.</para>
<para><varname>ExecStartPre</varname>, <varname>ExecStart</varname>, <varname>ExecStartPost</varname>, <para><varname>ExecStartPre</varname>, <varname>ExecStart</varname>, <varname>ExecStartPost</varname>,
<varname>ExecReload</varname>, <varname>ExecReloadPost</varname>, <varname>ExecStop</varname>, and <varname>ExecReload</varname>, <varname>ExecStop</varname>, and <varname>ExecStop</varname> are arrays
<varname>ExecStopPost</varname> are arrays of structures where each struct contains: the binary path of structures where each struct contains: the binary path to execute; an array with all arguments to
to execute; an array with all arguments to pass to the executed command, starting with argument 0; pass to the executed command, starting with argument 0; a boolean whether it should be considered a
a boolean whether it should be considered a failure if the process exits uncleanly; two pairs of failure if the process exits uncleanly; two pairs of
<constant>CLOCK_REALTIME</constant>/<constant>CLOCK_MONOTONIC</constant> microsecond timestamps when <constant>CLOCK_REALTIME</constant>/<constant>CLOCK_MONOTONIC</constant> microsecond timestamps when
the process began and finished running the last time, or 0 if it never ran or never finished running; the process began and finished running the last time, or 0 if it never ran or never finished running;
the PID of the process, or 0 if it has not run yet; the exit code and status of the last run. This the PID of the process, or 0 if it has not run yet; the exit code and status of the last run. This
@ -5822,6 +5814,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
<!--property ExecStopPre is not documented!--> <!--property ExecStopPre is not documented!-->
<!--property ExecStopPost is not documented!-->
<!--property Slice is not documented!--> <!--property Slice is not documented!-->
<!--property ControlGroupId is not documented!--> <!--property ControlGroupId is not documented!-->
@ -12550,10 +12544,8 @@ $ gdbus introspect --system --dest org.freedesktop.systemd1 \
<varname>LogsDirectoryAccounting</varname>, and <varname>LogsDirectoryAccounting</varname>, and
<function>KillSubgroup()</function> were added in version 258.</para> <function>KillSubgroup()</function> were added in version 258.</para>
<para><varname>UserNamespacePath</varname>, <para><varname>UserNamespacePath</varname>,
<varname>OOMKills</varname>, <varname>OOMKills</varname>, and
<varname>ManagedOOMKills</varname>, <varname>ManagedOOMKills</varname> were added in 259.</para>
<varname>ExecReloadPost</varname>, and
<varname>ExecReloadPostEx</varname> were added in version 259.</para>
</refsect2> </refsect2>
<refsect2> <refsect2>
<title>Socket Unit Objects</title> <title>Socket Unit Objects</title>

View File

@ -475,8 +475,8 @@
<varlistentry> <varlistentry>
<term><varname>ExecReload=</varname></term> <term><varname>ExecReload=</varname></term>
<listitem><para>Commands to execute to trigger a configuration reload in the service. This setting <listitem><para>Commands to execute to trigger a configuration reload in the service. This argument
may take multiple command lines, following the same scheme as described for takes multiple command lines, following the same scheme as described for
<varname>ExecStart=</varname> above. Use of this setting is optional. Specifier and environment <varname>ExecStart=</varname> above. Use of this setting is optional. Specifier and environment
variable substitution is supported here following the same scheme as for variable substitution is supported here following the same scheme as for
<varname>ExecStart=</varname>.</para> <varname>ExecStart=</varname>.</para>
@ -486,12 +486,13 @@
<programlisting>ExecReload=kill -HUP $MAINPID</programlisting> <programlisting>ExecReload=kill -HUP $MAINPID</programlisting>
<para>Note however that reloading a daemon by enqueuing a signal without completion notification <para>Note however that reloading a daemon by enqueuing a signal (as with the example line above) is
(as is the case with the example line above) is usually not a good choice, because this is an usually not a good choice, because this is an asynchronous operation and hence not suitable when
asynchronous operation and hence not suitable when ordering reloads of multiple services against ordering reloads of multiple services against each other. It is thus strongly recommended to either
each other. It is thus strongly recommended to either use <varname>Type=notify-reload</varname>, use <varname>Type=</varname><option>notify-reload</option> in place of
or to set <varname>ExecReload=</varname> to a command that not only triggers a configuration reload <varname>ExecReload=</varname>, or to set <varname>ExecReload=</varname> to a command that not only
of the daemon, but also synchronously waits for it to complete. For example, <citerefentry 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> project='mankier'><refentrytitle>dbus-broker</refentrytitle><manvolnum>1</manvolnum></citerefentry>
uses the following:</para> uses the following:</para>
@ -499,22 +500,6 @@
/org/freedesktop/DBus org.freedesktop.DBus \ /org/freedesktop/DBus org.freedesktop.DBus \
ReloadConfig ReloadConfig
</programlisting> </programlisting>
<para>This setting can be combined with <varname>Type=notify-reload</varname>, in which case
the service main process is signaled after all specified command lines finish execution. Specially,
if <literal>RELOADING=1</literal> notification is received before <varname>ExecReload=</varname>
completes, the signaling is skipped and the service manager immediately starts listening for
<literal>READY=1</literal>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>ExecReloadPost=</varname></term>
<listitem><para>Commands to execute after a successful reload operation. Syntax for this setting
is exactly the same as <varname>ExecReload=</varname>.</para>
<xi:include href="version-info.xml" xpointer="v259"/>
</listitem> </listitem>
</varlistentry> </varlistentry>
@ -1087,14 +1072,18 @@
<varlistentry> <varlistentry>
<term><varname>RootDirectoryStartOnly=</varname></term> <term><varname>RootDirectoryStartOnly=</varname></term>
<listitem><para>Takes a boolean argument. If true, the root directory, as configured with the <listitem><para>Takes a boolean argument. If true, the root
directory, as configured with the
<varname>RootDirectory=</varname> option (see <varname>RootDirectory=</varname> option (see
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for more information), is only applied to the process started with <varname>ExecStart=</varname>, for more information), is only applied to the process started
and not to the various other <varname>ExecStartPre=</varname>, <varname>ExecStartPost=</varname>, with <varname>ExecStart=</varname>, and not to the various
<varname>ExecReload=</varname>, <varname>ExecReloadPost=</varname>, <varname>ExecStop=</varname>, other <varname>ExecStartPre=</varname>,
and <varname>ExecStopPost=</varname> commands. If false, the setting is applied to all <varname>ExecStartPost=</varname>,
configured commands the same way. Defaults to false.</para></listitem> <varname>ExecReload=</varname>, <varname>ExecStop=</varname>,
and <varname>ExecStopPost=</varname> commands. If false, the
setting is applied to all configured commands the same way.
Defaults to false.</para></listitem>
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>

View File

@ -1011,7 +1011,7 @@ static int xfopenat_regular(int dir_fd, const char *path, const char *mode, int
assert(mode); assert(mode);
assert(ret); assert(ret);
if (dir_fd == AT_FDCWD && path && open_flags == 0) if (dir_fd == AT_FDCWD && open_flags == 0 && path)
f = fopen(path, mode); f = fopen(path, mode);
else { else {
_cleanup_close_ int fd = -EBADF; _cleanup_close_ int fd = -EBADF;
@ -1029,7 +1029,7 @@ static int xfopenat_regular(int dir_fd, const char *path, const char *mode, int
if (dir_fd == AT_FDCWD) if (dir_fd == AT_FDCWD)
return -EBADF; return -EBADF;
fd = fd_reopen(dir_fd, (mode_flags | open_flags) & ~O_NOFOLLOW); fd = fd_reopen(dir_fd, mode_flags | open_flags);
if (fd < 0) if (fd < 0)
return fd; return fd;
} }

View File

@ -224,11 +224,10 @@ static const char* const service_state_table[_SERVICE_STATE_MAX] = {
[SERVICE_START_POST] = "start-post", [SERVICE_START_POST] = "start-post",
[SERVICE_RUNNING] = "running", [SERVICE_RUNNING] = "running",
[SERVICE_EXITED] = "exited", [SERVICE_EXITED] = "exited",
[SERVICE_REFRESH_EXTENSIONS] = "refresh-extensions",
[SERVICE_RELOAD] = "reload", [SERVICE_RELOAD] = "reload",
[SERVICE_RELOAD_SIGNAL] = "reload-signal", [SERVICE_RELOAD_SIGNAL] = "reload-signal",
[SERVICE_RELOAD_NOTIFY] = "reload-notify", [SERVICE_RELOAD_NOTIFY] = "reload-notify",
[SERVICE_RELOAD_POST] = "reload-post", [SERVICE_REFRESH_EXTENSIONS] = "refresh-extensions",
[SERVICE_STOP] = "stop", [SERVICE_STOP] = "stop",
[SERVICE_STOP_WATCHDOG] = "stop-watchdog", [SERVICE_STOP_WATCHDOG] = "stop-watchdog",
[SERVICE_STOP_SIGTERM] = "stop-sigterm", [SERVICE_STOP_SIGTERM] = "stop-sigterm",

View File

@ -131,11 +131,10 @@ typedef enum ServiceState {
SERVICE_START_POST, SERVICE_START_POST,
SERVICE_RUNNING, SERVICE_RUNNING,
SERVICE_EXITED, /* Nothing is running anymore, but RemainAfterExit is true hence this is OK */ SERVICE_EXITED, /* Nothing is running anymore, but RemainAfterExit is true hence this is OK */
SERVICE_REFRESH_EXTENSIONS, /* Refreshing extensions for a reload request */
SERVICE_RELOAD, /* Reloading via ExecReload= */ SERVICE_RELOAD, /* Reloading via ExecReload= */
SERVICE_RELOAD_SIGNAL, /* Reloading via SIGHUP requested */ SERVICE_RELOAD_SIGNAL, /* Reloading via SIGHUP requested */
SERVICE_RELOAD_NOTIFY, /* Waiting for READY=1 after RELOADING=1 notify */ SERVICE_RELOAD_NOTIFY, /* Waiting for READY=1 after RELOADING=1 notify */
SERVICE_RELOAD_POST, SERVICE_REFRESH_EXTENSIONS, /* Refreshing extensions for a reload request */
SERVICE_MOUNTING, /* Performing a live mount into the namespace of the service */ SERVICE_MOUNTING, /* Performing a live mount into the namespace of the service */
SERVICE_STOP, /* No STOP_PRE state, instead just register multiple STOP executables */ SERVICE_STOP, /* No STOP_PRE state, instead just register multiple STOP executables */
SERVICE_STOP_WATCHDOG, SERVICE_STOP_WATCHDOG,

View File

@ -114,20 +114,12 @@ static int parse_argv(int argc, char *argv[]) {
break; break;
case 'u': case 'u':
if (arg_show_unit == SHOW_UNIT_USER)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Cannot combine --unit with --user-unit.");
arg_show_unit = SHOW_UNIT_SYSTEM; arg_show_unit = SHOW_UNIT_SYSTEM;
if (strv_push(&arg_names, optarg) < 0) /* push optarg if not empty */ if (strv_push(&arg_names, optarg) < 0) /* push optarg if not empty */
return log_oom(); return log_oom();
break; break;
case ARG_USER_UNIT: case ARG_USER_UNIT:
if (arg_show_unit == SHOW_UNIT_SYSTEM)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Cannot combine --user-unit with --unit.");
arg_show_unit = SHOW_UNIT_USER; arg_show_unit = SHOW_UNIT_USER;
if (strv_push(&arg_names, optarg) < 0) /* push optarg if not empty */ if (strv_push(&arg_names, optarg) < 0) /* push optarg if not empty */
return log_oom(); return log_oom();

View File

@ -383,8 +383,6 @@ const sd_bus_vtable bus_service_vtable[] = {
BUS_EXEC_EX_COMMAND_LIST_VTABLE("ExecStartPostEx", offsetof(Service, exec_command[SERVICE_EXEC_START_POST]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION), BUS_EXEC_EX_COMMAND_LIST_VTABLE("ExecStartPostEx", offsetof(Service, exec_command[SERVICE_EXEC_START_POST]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
BUS_EXEC_COMMAND_LIST_VTABLE("ExecReload", offsetof(Service, exec_command[SERVICE_EXEC_RELOAD]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION), BUS_EXEC_COMMAND_LIST_VTABLE("ExecReload", offsetof(Service, exec_command[SERVICE_EXEC_RELOAD]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
BUS_EXEC_EX_COMMAND_LIST_VTABLE("ExecReloadEx", offsetof(Service, exec_command[SERVICE_EXEC_RELOAD]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION), BUS_EXEC_EX_COMMAND_LIST_VTABLE("ExecReloadEx", offsetof(Service, exec_command[SERVICE_EXEC_RELOAD]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
BUS_EXEC_COMMAND_LIST_VTABLE("ExecReloadPost", offsetof(Service, exec_command[SERVICE_EXEC_RELOAD_POST]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
BUS_EXEC_EX_COMMAND_LIST_VTABLE("ExecReloadPostEx", offsetof(Service, exec_command[SERVICE_EXEC_RELOAD_POST]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
BUS_EXEC_COMMAND_LIST_VTABLE("ExecStop", offsetof(Service, exec_command[SERVICE_EXEC_STOP]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION), BUS_EXEC_COMMAND_LIST_VTABLE("ExecStop", offsetof(Service, exec_command[SERVICE_EXEC_STOP]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
BUS_EXEC_EX_COMMAND_LIST_VTABLE("ExecStopEx", offsetof(Service, exec_command[SERVICE_EXEC_STOP]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION), BUS_EXEC_EX_COMMAND_LIST_VTABLE("ExecStopEx", offsetof(Service, exec_command[SERVICE_EXEC_STOP]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
BUS_EXEC_COMMAND_LIST_VTABLE("ExecStopPost", offsetof(Service, exec_command[SERVICE_EXEC_STOP_POST]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION), BUS_EXEC_COMMAND_LIST_VTABLE("ExecStopPost", offsetof(Service, exec_command[SERVICE_EXEC_STOP_POST]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),

View File

@ -904,16 +904,8 @@ static int get_supplementary_groups(
bool keep_groups = false; bool keep_groups = false;
if (user && gid_is_valid(gid) && gid != 0) { if (user && gid_is_valid(gid) && gid != 0) {
/* First step, initialize groups from /etc/groups */ /* First step, initialize groups from /etc/groups */
if (initgroups(user, gid) < 0) { if (initgroups(user, gid) < 0)
/* If our primary gid is already the one specified in Group= (i.e. we're running in
* user mode), gracefully handle the case where we have no privilege to re-initgroups().
*
* Note that group memberships of the current user might have been modified, but
* the change will only take effect after re-login. It's better to continue on with
* existing credentials rather than erroring out. */
if (!ERRNO_IS_PRIVILEGE(errno) || gid != getgid())
return -errno; return -errno;
}
keep_groups = true; keep_groups = true;
} }

View File

@ -436,11 +436,13 @@ bool job_type_is_redundant(JobType a, UnitActiveState b) {
switch (a) { switch (a) {
case JOB_START: case JOB_START:
case JOB_VERIFY_ACTIVE: return IN_SET(b, UNIT_ACTIVE, UNIT_RELOADING, UNIT_REFRESHING);
return UNIT_IS_ACTIVE_OR_RELOADING(b);
case JOB_STOP: case JOB_STOP:
return UNIT_IS_INACTIVE_OR_FAILED(b); return IN_SET(b, UNIT_INACTIVE, UNIT_FAILED);
case JOB_VERIFY_ACTIVE:
return IN_SET(b, UNIT_ACTIVE, UNIT_RELOADING, UNIT_REFRESHING);
case JOB_RELOAD: case JOB_RELOAD:
/* Reload jobs are never considered redundant/duplicate. Refer to jobs_may_late_merge() for /* Reload jobs are never considered redundant/duplicate. Refer to jobs_may_late_merge() for

View File

@ -162,17 +162,17 @@ int job_coldplug(Job *j);
JobDependency* job_dependency_new(Job *subject, Job *object, bool matters, bool conflicts); JobDependency* job_dependency_new(Job *subject, Job *object, bool matters, bool conflicts);
void job_dependency_free(JobDependency *l); void job_dependency_free(JobDependency *l);
JobType job_type_lookup_merge(JobType a, JobType b) _const_; JobType job_type_lookup_merge(JobType a, JobType b) _pure_;
static inline bool job_type_is_mergeable(JobType a, JobType b) { _pure_ static inline bool job_type_is_mergeable(JobType a, JobType b) {
return job_type_lookup_merge(a, b) >= 0; return job_type_lookup_merge(a, b) >= 0;
} }
static inline bool job_type_is_conflicting(JobType a, JobType b) { _pure_ static inline bool job_type_is_conflicting(JobType a, JobType b) {
return a != JOB_NOP && b != JOB_NOP && !job_type_is_mergeable(a, b); return a != JOB_NOP && b != JOB_NOP && !job_type_is_mergeable(a, b);
} }
static inline bool job_type_is_superset(JobType a, JobType b) { _pure_ static inline bool job_type_is_superset(JobType a, JobType b) {
/* Checks whether operation a is a "superset" of b in its actions */ /* Checks whether operation a is a "superset" of b in its actions */
if (b == JOB_NOP) if (b == JOB_NOP)
return true; return true;
@ -181,7 +181,7 @@ static inline bool job_type_is_superset(JobType a, JobType b) {
return a == job_type_lookup_merge(a, b); return a == job_type_lookup_merge(a, b);
} }
bool job_type_is_redundant(JobType a, UnitActiveState b) _const_; bool job_type_is_redundant(JobType a, UnitActiveState b) _pure_;
/* Collapses a state-dependent job type into a simpler type by observing /* Collapses a state-dependent job type into a simpler type by observing
* the state of the unit which it is going to be applied to. */ * the state of the unit which it is going to be applied to. */

View File

@ -430,9 +430,8 @@ Service.PIDFile, config_parse_pid_file,
Service.ExecCondition, config_parse_exec, SERVICE_EXEC_CONDITION, offsetof(Service, exec_command) Service.ExecCondition, config_parse_exec, SERVICE_EXEC_CONDITION, offsetof(Service, exec_command)
Service.ExecStartPre, config_parse_exec, SERVICE_EXEC_START_PRE, offsetof(Service, exec_command) Service.ExecStartPre, config_parse_exec, SERVICE_EXEC_START_PRE, offsetof(Service, exec_command)
Service.ExecStart, config_parse_exec, SERVICE_EXEC_START, offsetof(Service, exec_command) Service.ExecStart, config_parse_exec, SERVICE_EXEC_START, offsetof(Service, exec_command)
Service.ExecStartPost, config_parse_exec, SERVICE_EXEC_START_POST, offsetof(Service, exec_command)
Service.ExecReload, config_parse_exec, SERVICE_EXEC_RELOAD, offsetof(Service, exec_command) Service.ExecReload, config_parse_exec, SERVICE_EXEC_RELOAD, offsetof(Service, exec_command)
Service.ExecReloadPost, config_parse_exec, SERVICE_EXEC_RELOAD_POST, offsetof(Service, exec_command) Service.ExecStartPost, config_parse_exec, SERVICE_EXEC_START_POST, offsetof(Service, exec_command)
Service.ExecStop, config_parse_exec, SERVICE_EXEC_STOP, offsetof(Service, exec_command) Service.ExecStop, config_parse_exec, SERVICE_EXEC_STOP, offsetof(Service, exec_command)
Service.ExecStopPost, config_parse_exec, SERVICE_EXEC_STOP_POST, offsetof(Service, exec_command) Service.ExecStopPost, config_parse_exec, SERVICE_EXEC_STOP_POST, offsetof(Service, exec_command)
Service.RestartSec, config_parse_sec, 0, offsetof(Service, restart_usec) Service.RestartSec, config_parse_sec, 0, offsetof(Service, restart_usec)

View File

@ -56,8 +56,6 @@
#include "unit-name.h" #include "unit-name.h"
#include "utf8.h" #include "utf8.h"
#define STATUS_TEXT_MAX (16U*1024U)
#define service_spawn(...) service_spawn_internal(__func__, __VA_ARGS__) #define service_spawn(...) service_spawn_internal(__func__, __VA_ARGS__)
static const UnitActiveState state_translation_table[_SERVICE_STATE_MAX] = { static const UnitActiveState state_translation_table[_SERVICE_STATE_MAX] = {
@ -68,11 +66,10 @@ static const UnitActiveState state_translation_table[_SERVICE_STATE_MAX] = {
[SERVICE_START_POST] = UNIT_ACTIVATING, [SERVICE_START_POST] = UNIT_ACTIVATING,
[SERVICE_RUNNING] = UNIT_ACTIVE, [SERVICE_RUNNING] = UNIT_ACTIVE,
[SERVICE_EXITED] = UNIT_ACTIVE, [SERVICE_EXITED] = UNIT_ACTIVE,
[SERVICE_REFRESH_EXTENSIONS] = UNIT_REFRESHING,
[SERVICE_RELOAD] = UNIT_RELOADING, [SERVICE_RELOAD] = UNIT_RELOADING,
[SERVICE_RELOAD_SIGNAL] = UNIT_RELOADING, [SERVICE_RELOAD_SIGNAL] = UNIT_RELOADING,
[SERVICE_RELOAD_NOTIFY] = UNIT_RELOADING, [SERVICE_RELOAD_NOTIFY] = UNIT_RELOADING,
[SERVICE_RELOAD_POST] = UNIT_RELOADING, [SERVICE_REFRESH_EXTENSIONS] = UNIT_REFRESHING,
[SERVICE_MOUNTING] = UNIT_REFRESHING, [SERVICE_MOUNTING] = UNIT_REFRESHING,
[SERVICE_STOP] = UNIT_DEACTIVATING, [SERVICE_STOP] = UNIT_DEACTIVATING,
[SERVICE_STOP_WATCHDOG] = UNIT_DEACTIVATING, [SERVICE_STOP_WATCHDOG] = UNIT_DEACTIVATING,
@ -101,11 +98,10 @@ static const UnitActiveState state_translation_table_idle[_SERVICE_STATE_MAX] =
[SERVICE_START_POST] = UNIT_ACTIVE, [SERVICE_START_POST] = UNIT_ACTIVE,
[SERVICE_RUNNING] = UNIT_ACTIVE, [SERVICE_RUNNING] = UNIT_ACTIVE,
[SERVICE_EXITED] = UNIT_ACTIVE, [SERVICE_EXITED] = UNIT_ACTIVE,
[SERVICE_REFRESH_EXTENSIONS] = UNIT_REFRESHING,
[SERVICE_RELOAD] = UNIT_RELOADING, [SERVICE_RELOAD] = UNIT_RELOADING,
[SERVICE_RELOAD_SIGNAL] = UNIT_RELOADING, [SERVICE_RELOAD_SIGNAL] = UNIT_RELOADING,
[SERVICE_RELOAD_NOTIFY] = UNIT_RELOADING, [SERVICE_RELOAD_NOTIFY] = UNIT_RELOADING,
[SERVICE_RELOAD_POST] = UNIT_RELOADING, [SERVICE_REFRESH_EXTENSIONS] = UNIT_REFRESHING,
[SERVICE_MOUNTING] = UNIT_REFRESHING, [SERVICE_MOUNTING] = UNIT_REFRESHING,
[SERVICE_STOP] = UNIT_DEACTIVATING, [SERVICE_STOP] = UNIT_DEACTIVATING,
[SERVICE_STOP_WATCHDOG] = UNIT_DEACTIVATING, [SERVICE_STOP_WATCHDOG] = UNIT_DEACTIVATING,
@ -130,15 +126,13 @@ static int service_dispatch_watchdog(sd_event_source *source, usec_t usec, void
static int service_dispatch_exec_io(sd_event_source *source, int fd, uint32_t events, void *userdata); static int service_dispatch_exec_io(sd_event_source *source, int fd, uint32_t events, void *userdata);
static void service_enter_signal(Service *s, ServiceState state, ServiceResult f); static void service_enter_signal(Service *s, ServiceState state, ServiceResult f);
static void service_reload_finish(Service *s, ServiceResult f);
static void service_enter_reload_by_notify(Service *s); static void service_enter_reload_by_notify(Service *s);
static bool SERVICE_STATE_WITH_MAIN_PROCESS(ServiceState state) { static bool SERVICE_STATE_WITH_MAIN_PROCESS(ServiceState state) {
return IN_SET(state, return IN_SET(state,
SERVICE_START, SERVICE_START_POST, SERVICE_START, SERVICE_START_POST,
SERVICE_RUNNING, SERVICE_RUNNING,
SERVICE_REFRESH_EXTENSIONS, SERVICE_RELOAD, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY, SERVICE_RELOAD_POST, SERVICE_RELOAD, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY, SERVICE_REFRESH_EXTENSIONS,
SERVICE_MOUNTING, SERVICE_MOUNTING,
SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST, SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL); SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL);
@ -148,21 +142,13 @@ static bool SERVICE_STATE_WITH_CONTROL_PROCESS(ServiceState state) {
return IN_SET(state, return IN_SET(state,
SERVICE_CONDITION, SERVICE_CONDITION,
SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
SERVICE_REFRESH_EXTENSIONS, SERVICE_RELOAD, SERVICE_RELOAD_POST, SERVICE_RELOAD, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY, SERVICE_REFRESH_EXTENSIONS,
SERVICE_MOUNTING, SERVICE_MOUNTING,
SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST, SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL, SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL,
SERVICE_CLEANING); SERVICE_CLEANING);
} }
static bool SERVICE_STATE_WITH_WATCHDOG(ServiceState state) {
return IN_SET(state,
SERVICE_START_POST,
SERVICE_RUNNING,
SERVICE_REFRESH_EXTENSIONS, SERVICE_RELOAD, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY, SERVICE_RELOAD_POST,
SERVICE_MOUNTING);
}
static void service_init(Unit *u) { static void service_init(Unit *u) {
Service *s = SERVICE(u); Service *s = SERVICE(u);
@ -189,7 +175,6 @@ static void service_init(Unit *u) {
EXEC_KEYRING_PRIVATE : EXEC_KEYRING_INHERIT; EXEC_KEYRING_PRIVATE : EXEC_KEYRING_INHERIT;
s->notify_access_override = _NOTIFY_ACCESS_INVALID; s->notify_access_override = _NOTIFY_ACCESS_INVALID;
s->notify_state = _NOTIFY_STATE_INVALID;
s->watchdog_original_usec = USEC_INFINITY; s->watchdog_original_usec = USEC_INFINITY;
@ -1304,7 +1289,7 @@ static void service_set_state(Service *s, ServiceState state) {
if (!IN_SET(state, if (!IN_SET(state,
SERVICE_CONDITION, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, SERVICE_CONDITION, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
SERVICE_RUNNING, SERVICE_RUNNING,
SERVICE_REFRESH_EXTENSIONS, SERVICE_RELOAD, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY, SERVICE_RELOAD_POST, SERVICE_RELOAD, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY, SERVICE_REFRESH_EXTENSIONS,
SERVICE_MOUNTING, SERVICE_MOUNTING,
SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST, SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL, SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL,
@ -1332,7 +1317,7 @@ static void service_set_state(Service *s, ServiceState state) {
if (state != SERVICE_START) if (state != SERVICE_START)
s->exec_fd_event_source = sd_event_source_disable_unref(s->exec_fd_event_source); s->exec_fd_event_source = sd_event_source_disable_unref(s->exec_fd_event_source);
if (!SERVICE_STATE_WITH_WATCHDOG(state)) if (!IN_SET(state, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY, SERVICE_REFRESH_EXTENSIONS, SERVICE_MOUNTING))
service_stop_watchdog(s); service_stop_watchdog(s);
if (state != SERVICE_MOUNTING) /* Just in case */ if (state != SERVICE_MOUNTING) /* Just in case */
@ -1374,11 +1359,10 @@ static usec_t service_coldplug_timeout(Service *s) {
case SERVICE_START_PRE: case SERVICE_START_PRE:
case SERVICE_START: case SERVICE_START:
case SERVICE_START_POST: case SERVICE_START_POST:
case SERVICE_REFRESH_EXTENSIONS:
case SERVICE_RELOAD: case SERVICE_RELOAD:
case SERVICE_RELOAD_SIGNAL: case SERVICE_RELOAD_SIGNAL:
case SERVICE_RELOAD_NOTIFY: case SERVICE_RELOAD_NOTIFY:
case SERVICE_RELOAD_POST: case SERVICE_REFRESH_EXTENSIONS:
case SERVICE_MOUNTING: case SERVICE_MOUNTING:
return usec_add(UNIT(s)->state_change_timestamp.monotonic, s->timeout_start_usec); return usec_add(UNIT(s)->state_change_timestamp.monotonic, s->timeout_start_usec);
@ -1445,7 +1429,7 @@ static int service_coldplug(Unit *u) {
SERVICE_DEAD_RESOURCES_PINNED)) SERVICE_DEAD_RESOURCES_PINNED))
(void) unit_setup_exec_runtime(u); (void) unit_setup_exec_runtime(u);
if (SERVICE_STATE_WITH_WATCHDOG(s->deserialized_state) && if (IN_SET(s->deserialized_state, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY, SERVICE_REFRESH_EXTENSIONS, SERVICE_MOUNTING) &&
freezer_state_objective(u->freezer_state) == FREEZER_RUNNING) freezer_state_objective(u->freezer_state) == FREEZER_RUNNING)
service_start_watchdog(s); service_start_watchdog(s);
@ -2183,9 +2167,8 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart)
/* The next restart might not be a manual stop, hence reset the flag indicating manual stops */ /* The next restart might not be a manual stop, hence reset the flag indicating manual stops */
s->forbid_restart = false; s->forbid_restart = false;
/* Reset notify states */ /* Reset NotifyAccess override */
s->notify_access_override = _NOTIFY_ACCESS_INVALID; s->notify_access_override = _NOTIFY_ACCESS_INVALID;
s->notify_state = _NOTIFY_STATE_INVALID;
/* We want fresh tmpdirs and ephemeral snapshots in case the service is started again immediately. */ /* We want fresh tmpdirs and ephemeral snapshots in case the service is started again immediately. */
s->exec_runtime = exec_runtime_destroy(s->exec_runtime); s->exec_runtime = exec_runtime_destroy(s->exec_runtime);
@ -2222,6 +2205,7 @@ static void service_enter_stop_post(Service *s, ServiceResult f) {
s->control_command = s->exec_command[SERVICE_EXEC_STOP_POST]; s->control_command = s->exec_command[SERVICE_EXEC_STOP_POST];
if (s->control_command) { if (s->control_command) {
s->control_command_id = SERVICE_EXEC_STOP_POST; s->control_command_id = SERVICE_EXEC_STOP_POST;
pidref_done(&s->control_pid);
r = service_spawn(s, r = service_spawn(s,
s->control_command, s->control_command,
@ -2334,6 +2318,7 @@ static void service_enter_stop(Service *s, ServiceResult f) {
s->control_command = s->exec_command[SERVICE_EXEC_STOP]; s->control_command = s->exec_command[SERVICE_EXEC_STOP];
if (s->control_command) { if (s->control_command) {
s->control_command_id = SERVICE_EXEC_STOP; s->control_command_id = SERVICE_EXEC_STOP;
pidref_done(&s->control_pid);
r = service_spawn(s, r = service_spawn(s,
s->control_command, s->control_command,
@ -2419,6 +2404,7 @@ static void service_enter_start_post(Service *s) {
s->control_command = s->exec_command[SERVICE_EXEC_START_POST]; s->control_command = s->exec_command[SERVICE_EXEC_START_POST];
if (s->control_command) { if (s->control_command) {
s->control_command_id = SERVICE_EXEC_START_POST; s->control_command_id = SERVICE_EXEC_START_POST;
pidref_done(&s->control_pid);
r = service_spawn(s, r = service_spawn(s,
s->control_command, s->control_command,
@ -2552,6 +2538,7 @@ static void service_enter_start(Service *s) {
case SERVICE_FORKING: case SERVICE_FORKING:
/* For forking services we wait until the start process exited. */ /* For forking services we wait until the start process exited. */
pidref_done(&s->control_pid);
s->control_pid = TAKE_PIDREF(pidref); s->control_pid = TAKE_PIDREF(pidref);
return service_set_state(s, SERVICE_START); return service_set_state(s, SERVICE_START);
@ -2625,6 +2612,7 @@ static void service_enter_condition(Service *s) {
goto fail; goto fail;
s->control_command_id = SERVICE_EXEC_CONDITION; s->control_command_id = SERVICE_EXEC_CONDITION;
pidref_done(&s->control_pid);
r = service_spawn(s, r = service_spawn(s,
s->control_command, s->control_command,
@ -2708,7 +2696,9 @@ static void service_enter_reload_by_notify(Service *s) {
r = service_arm_timer(s, /* relative= */ true, s->timeout_start_usec); r = service_arm_timer(s, /* relative= */ true, s->timeout_start_usec);
if (r < 0) { if (r < 0) {
log_unit_warning_errno(UNIT(s), r, "Failed to install timer: %m"); log_unit_warning_errno(UNIT(s), r, "Failed to install timer: %m");
return service_reload_finish(s, SERVICE_FAILURE_RESOURCES); s->reload_result = SERVICE_FAILURE_RESOURCES;
service_enter_running(s, SERVICE_SUCCESS);
return;
} }
service_set_state(s, SERVICE_RELOAD_NOTIFY); service_set_state(s, SERVICE_RELOAD_NOTIFY);
@ -2719,91 +2709,31 @@ static void service_enter_reload_by_notify(Service *s) {
log_unit_warning(UNIT(s), "Failed to schedule propagation of reload, ignoring: %s", bus_error_message(&error, r)); log_unit_warning(UNIT(s), "Failed to schedule propagation of reload, ignoring: %s", bus_error_message(&error, r));
} }
static void service_enter_reload_post(Service *s) { static void service_enter_reload_signal_exec(Service *s) {
bool killed = false;
int r; int r;
assert(s); assert(s);
service_unwatch_control_pid(s); service_unwatch_control_pid(s);
s->reload_result = SERVICE_SUCCESS;
s->control_command = s->exec_command[SERVICE_EXEC_RELOAD_POST]; usec_t ts = now(CLOCK_MONOTONIC);
if (s->control_command) {
s->control_command_id = SERVICE_EXEC_RELOAD_POST;
r = service_spawn(s,
s->control_command,
service_exec_flags(s->control_command_id, /* cred_flag = */ 0),
s->timeout_start_usec,
&s->control_pid);
if (r < 0) {
log_unit_warning_errno(UNIT(s), r, "Failed to spawn 'reload-post' task: %m");
return service_reload_finish(s, SERVICE_FAILURE_RESOURCES);
}
service_set_state(s, SERVICE_RELOAD_POST);
} else
service_reload_finish(s, SERVICE_SUCCESS);
}
static void service_enter_reload_signal(Service *s) {
int r;
assert(s);
if (s->type != SERVICE_NOTIFY_RELOAD)
return service_enter_reload_post(s);
if (s->state == SERVICE_RELOAD) {
/* We executed ExecReload=, and the service has already notified us the result?
* Directly transition to next state. */
if (s->notify_state == NOTIFY_RELOADING)
return service_set_state(s, SERVICE_RELOAD_NOTIFY);
if (s->notify_state == NOTIFY_RELOAD_READY)
return service_enter_reload_post(s);
}
if (pidref_is_set(&s->main_pid)) {
r = service_arm_timer(s, /* relative= */ true, s->timeout_start_usec);
if (r < 0) {
log_unit_warning_errno(UNIT(s), r, "Failed to install timer: %m");
goto fail;
}
if (s->type == SERVICE_NOTIFY_RELOAD && pidref_is_set(&s->main_pid)) {
r = pidref_kill_and_sigcont(&s->main_pid, s->reload_signal); r = pidref_kill_and_sigcont(&s->main_pid, s->reload_signal);
if (r < 0) { if (r < 0) {
log_unit_warning_errno(UNIT(s), r, "Failed to send reload signal: %m"); log_unit_warning_errno(UNIT(s), r, "Failed to send reload signal: %m");
goto fail; goto fail;
} }
service_set_state(s, SERVICE_RELOAD_SIGNAL); killed = true;
} else
service_enter_reload_post(s);
return;
fail:
service_reload_finish(s, SERVICE_FAILURE_RESOURCES);
} }
static void service_enter_reload(Service *s) {
int r;
assert(s);
service_unwatch_control_pid(s);
if (IN_SET(s->notify_state, NOTIFY_RELOADING, NOTIFY_RELOAD_READY))
s->notify_state = _NOTIFY_STATE_INVALID;
/* 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 = now(CLOCK_MONOTONIC);
s->control_command = s->exec_command[SERVICE_EXEC_RELOAD]; s->control_command = s->exec_command[SERVICE_EXEC_RELOAD];
if (s->control_command) { if (s->control_command) {
s->control_command_id = SERVICE_EXEC_RELOAD; s->control_command_id = SERVICE_EXEC_RELOAD;
pidref_done(&s->control_pid);
r = service_spawn(s, r = service_spawn(s,
s->control_command, s->control_command,
@ -2812,12 +2742,33 @@ static void service_enter_reload(Service *s) {
&s->control_pid); &s->control_pid);
if (r < 0) { if (r < 0) {
log_unit_warning_errno(UNIT(s), r, "Failed to spawn 'reload' task: %m"); log_unit_warning_errno(UNIT(s), r, "Failed to spawn 'reload' task: %m");
return service_reload_finish(s, SERVICE_FAILURE_RESOURCES); goto fail;
} }
service_set_state(s, SERVICE_RELOAD); service_set_state(s, SERVICE_RELOAD);
} else } else if (killed) {
service_enter_reload_signal(s); r = service_arm_timer(s, /* relative= */ true, s->timeout_start_usec);
if (r < 0) {
log_unit_warning_errno(UNIT(s), r, "Failed to install timer: %m");
goto fail;
}
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:
s->reload_result = SERVICE_FAILURE_RESOURCES;
service_enter_running(s, SERVICE_SUCCESS);
} }
static bool service_should_reload_extensions(Service *s) { static bool service_should_reload_extensions(Service *s) {
@ -2854,20 +2805,15 @@ static void service_enter_refresh_extensions(Service *s) {
assert(s); assert(s);
/* If we don't have extensions to refresh, immediately transition to reload state */ /* If we don't have extensions to reload, immediately go to the signal step */
if (!service_should_reload_extensions(s)) if (!service_should_reload_extensions(s))
return service_enter_reload(s); return (void) service_enter_reload_signal_exec(s);
service_unwatch_control_pid(s); service_unwatch_control_pid(s);
s->reload_result = SERVICE_SUCCESS;
s->control_command = NULL; s->control_command = NULL;
s->control_command_id = _SERVICE_EXEC_COMMAND_INVALID; s->control_command_id = _SERVICE_EXEC_COMMAND_INVALID;
r = service_arm_timer(s, /* relative= */ true, s->timeout_start_usec);
if (r < 0) {
log_unit_warning_errno(UNIT(s), r, "Failed to install timer: %m");
goto fail;
}
/* Given we are running from PID1, avoid doing potentially heavy I/O operations like opening images /* Given we are running from PID1, avoid doing potentially heavy I/O operations like opening images
* directly, and instead fork a worker process. */ * directly, and instead fork a worker process. */
r = unit_fork_helper_process(UNIT(s), "(sd-refresh-extensions)", /* into_cgroup= */ false, &worker); r = unit_fork_helper_process(UNIT(s), "(sd-refresh-extensions)", /* into_cgroup= */ false, &worker);
@ -2922,7 +2868,28 @@ static void service_enter_refresh_extensions(Service *s) {
return; return;
fail: fail:
service_reload_finish(s, SERVICE_FAILURE_RESOURCES); s->reload_result = SERVICE_FAILURE_RESOURCES;
service_enter_running(s, SERVICE_SUCCESS);
}
static void service_enter_reload_mounting(Service *s) {
int r;
assert(s);
usec_t ts = now(CLOCK_MONOTONIC);
r = service_arm_timer(s, /* relative= */ true, s->timeout_start_usec);
if (r < 0) {
log_unit_warning_errno(UNIT(s), r, "Failed to install timer: %m");
s->reload_result = SERVICE_FAILURE_RESOURCES;
service_enter_running(s, SERVICE_SUCCESS);
return;
}
s->reload_begin_usec = ts;
service_enter_refresh_extensions(s);
} }
static void service_run_next_control(Service *s) { static void service_run_next_control(Service *s) {
@ -2938,15 +2905,13 @@ static void service_run_next_control(Service *s) {
s->control_command = s->control_command->command_next; s->control_command = s->control_command->command_next;
service_unwatch_control_pid(s); service_unwatch_control_pid(s);
if (IN_SET(s->state, if (IN_SET(s->state, SERVICE_CONDITION, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD))
SERVICE_CONDITION,
SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
SERVICE_RUNNING,
SERVICE_RELOAD, SERVICE_RELOAD_POST))
timeout = s->timeout_start_usec; timeout = s->timeout_start_usec;
else else
timeout = s->timeout_stop_usec; timeout = s->timeout_stop_usec;
pidref_done(&s->control_pid);
r = service_spawn(s, r = service_spawn(s,
s->control_command, s->control_command,
service_exec_flags(s->control_command_id, /* cred_flag = */ 0), service_exec_flags(s->control_command_id, /* cred_flag = */ 0),
@ -2959,9 +2924,10 @@ static void service_run_next_control(Service *s) {
service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_RESOURCES); service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_RESOURCES);
else if (s->state == SERVICE_STOP_POST) else if (s->state == SERVICE_STOP_POST)
service_enter_dead(s, SERVICE_FAILURE_RESOURCES, /* allow_restart= */ true); service_enter_dead(s, SERVICE_FAILURE_RESOURCES, /* allow_restart= */ true);
else if (IN_SET(s->state, SERVICE_RELOAD, SERVICE_RELOAD_POST)) else if (s->state == SERVICE_RELOAD) {
service_reload_finish(s, SERVICE_FAILURE_RESOURCES); s->reload_result = SERVICE_FAILURE_RESOURCES;
else service_enter_running(s, SERVICE_SUCCESS);
} else
service_enter_stop(s, SERVICE_FAILURE_RESOURCES); service_enter_stop(s, SERVICE_FAILURE_RESOURCES);
} }
} }
@ -3013,6 +2979,8 @@ static int service_start(Unit *u) {
if (r < 0) if (r < 0)
return r; return r;
s->result = SERVICE_SUCCESS;
s->reload_result = SERVICE_SUCCESS;
s->main_pid_known = false; s->main_pid_known = false;
s->main_pid_alien = false; s->main_pid_alien = false;
s->forbid_restart = false; s->forbid_restart = false;
@ -3021,17 +2989,13 @@ static int service_start(Unit *u) {
if (s->state != SERVICE_AUTO_RESTART_QUEUED) if (s->state != SERVICE_AUTO_RESTART_QUEUED)
s->n_restarts = 0; s->n_restarts = 0;
s->result = SERVICE_SUCCESS;
s->reload_result = SERVICE_SUCCESS;
s->reload_begin_usec = USEC_INFINITY;
s->status_text = mfree(s->status_text); s->status_text = mfree(s->status_text);
s->status_errno = 0; s->status_errno = 0;
s->status_bus_error = mfree(s->status_bus_error); s->status_bus_error = mfree(s->status_bus_error);
s->status_varlink_error = mfree(s->status_varlink_error); s->status_varlink_error = mfree(s->status_varlink_error);
s->notify_access_override = _NOTIFY_ACCESS_INVALID; s->notify_access_override = _NOTIFY_ACCESS_INVALID;
s->notify_state = _NOTIFY_STATE_INVALID; s->notify_state = NOTIFY_UNKNOWN;
s->watchdog_original_usec = s->watchdog_usec; s->watchdog_original_usec = s->watchdog_usec;
s->watchdog_override_enable = false; s->watchdog_override_enable = false;
@ -3076,20 +3040,6 @@ static void service_live_mount_finish(Service *s, ServiceResult f, const char *e
s->mount_request = sd_bus_message_unref(s->mount_request); s->mount_request = sd_bus_message_unref(s->mount_request);
} }
static void service_reload_finish(Service *s, ServiceResult f) {
assert(s);
s->reload_result = f;
s->reload_begin_usec = USEC_INFINITY;
/* If notify state is still in dangling NOTIFY_RELOADING, reset it so service_enter_running()
* won't get confused (see #37515) */
if (s->notify_state == NOTIFY_RELOADING)
s->notify_state = _NOTIFY_STATE_INVALID;
service_enter_running(s, SERVICE_SUCCESS);
}
static int service_stop(Unit *u) { static int service_stop(Unit *u) {
Service *s = ASSERT_PTR(SERVICE(u)); Service *s = ASSERT_PTR(SERVICE(u));
@ -3127,7 +3077,6 @@ static int service_stop(Unit *u) {
case SERVICE_RELOAD: case SERVICE_RELOAD:
case SERVICE_RELOAD_SIGNAL: case SERVICE_RELOAD_SIGNAL:
case SERVICE_RELOAD_NOTIFY: case SERVICE_RELOAD_NOTIFY:
case SERVICE_RELOAD_POST:
case SERVICE_STOP_WATCHDOG: case SERVICE_STOP_WATCHDOG:
/* If there's already something running we go directly into kill mode. */ /* If there's already something running we go directly into kill mode. */
service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_SUCCESS); service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_SUCCESS);
@ -3159,9 +3108,7 @@ static int service_reload(Unit *u) {
assert(IN_SET(s->state, SERVICE_RUNNING, SERVICE_EXITED)); assert(IN_SET(s->state, SERVICE_RUNNING, SERVICE_EXITED));
s->reload_result = SERVICE_SUCCESS; service_enter_reload_mounting(s);
service_enter_refresh_extensions(s);
return 1; return 1;
} }
@ -3361,8 +3308,6 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) {
if (s->notify_access_override >= 0) if (s->notify_access_override >= 0)
(void) serialize_item(f, "notify-access-override", notify_access_to_string(s->notify_access_override)); (void) serialize_item(f, "notify-access-override", notify_access_to_string(s->notify_access_override));
if (s->notify_state >= 0)
(void) serialize_item(f, "notify-state", notify_state_to_string(s->notify_state));
r = serialize_item_escaped(f, "status-text", s->status_text); r = serialize_item_escaped(f, "status-text", s->status_text);
if (r < 0) if (r < 0)
@ -3673,16 +3618,6 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value,
log_unit_debug(u, "Failed to parse notify-access-override value: %s", value); log_unit_debug(u, "Failed to parse notify-access-override value: %s", value);
else else
s->notify_access_override = notify_access; s->notify_access_override = notify_access;
} else if (streq(key, "notify-state")) {
NotifyState notify_state;
notify_state = notify_state_from_string(value);
if (notify_state < 0)
log_unit_debug(u, "Failed to parse notify-state value: %s", value);
else
s->notify_state = notify_state;
} else if (streq(key, "n-restarts")) { } else if (streq(key, "n-restarts")) {
r = safe_atou(value, &s->n_restarts); r = safe_atou(value, &s->n_restarts);
if (r < 0) if (r < 0)
@ -4180,11 +4115,10 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
switch (s->state) { switch (s->state) {
case SERVICE_START_POST: case SERVICE_START_POST:
case SERVICE_REFRESH_EXTENSIONS:
case SERVICE_RELOAD: case SERVICE_RELOAD:
case SERVICE_RELOAD_SIGNAL: case SERVICE_RELOAD_SIGNAL:
case SERVICE_RELOAD_NOTIFY: case SERVICE_RELOAD_NOTIFY:
case SERVICE_RELOAD_POST: case SERVICE_REFRESH_EXTENSIONS:
case SERVICE_MOUNTING: case SERVICE_MOUNTING:
/* If neither main nor control processes are running then the current /* If neither main nor control processes are running then the current
* state can never exit cleanly, hence immediately terminate the * state can never exit cleanly, hence immediately terminate the
@ -4300,8 +4234,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
success, success,
code, status); code, status);
if (!IN_SET(s->state, SERVICE_REFRESH_EXTENSIONS, SERVICE_RELOAD, SERVICE_RELOAD_POST, SERVICE_MOUNTING) && if (!IN_SET(s->state, SERVICE_RELOAD, SERVICE_MOUNTING) && s->result == SERVICE_SUCCESS)
s->result == SERVICE_SUCCESS)
s->result = f; s->result = f;
if (s->control_command && if (s->control_command &&
@ -4388,28 +4321,28 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
service_enter_running(s, SERVICE_SUCCESS); service_enter_running(s, SERVICE_SUCCESS);
break; break;
case SERVICE_REFRESH_EXTENSIONS:
if (f == SERVICE_SUCCESS)
/* Remounting extensions asynchronously done, proceed to reload */
service_enter_reload(s);
else
service_reload_finish(s, f);
break;
case SERVICE_RELOAD: case SERVICE_RELOAD:
if (f != SERVICE_SUCCESS) { case SERVICE_RELOAD_SIGNAL:
service_reload_finish(s, f); case SERVICE_RELOAD_NOTIFY:
break; if (f == SERVICE_SUCCESS)
}
if (service_load_pid_file(s, true) < 0) if (service_load_pid_file(s, true) < 0)
service_search_main_pid(s); service_search_main_pid(s);
service_enter_reload_signal(s); s->reload_result = f;
/* If the last notification we received from the service process indicates
* 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; break;
case SERVICE_RELOAD_POST: case SERVICE_REFRESH_EXTENSIONS:
service_reload_finish(s, f); /* Remounting extensions asynchronously done, proceed to signal */
service_enter_reload_signal_exec(s);
break; break;
case SERVICE_MOUNTING: case SERVICE_MOUNTING:
@ -4507,14 +4440,14 @@ static int service_dispatch_timer(sd_event_source *source, usec_t usec, void *us
service_enter_stop(s, SERVICE_FAILURE_TIMEOUT); service_enter_stop(s, SERVICE_FAILURE_TIMEOUT);
break; break;
case SERVICE_REFRESH_EXTENSIONS:
case SERVICE_RELOAD: case SERVICE_RELOAD:
case SERVICE_RELOAD_SIGNAL: case SERVICE_RELOAD_SIGNAL:
case SERVICE_RELOAD_NOTIFY: case SERVICE_RELOAD_NOTIFY:
case SERVICE_RELOAD_POST: case SERVICE_REFRESH_EXTENSIONS:
log_unit_warning(UNIT(s), "Reload operation timed out. Killing reload process."); log_unit_warning(UNIT(s), "Reload operation timed out. Killing reload process.");
service_kill_control_process(s); service_kill_control_process(s);
service_reload_finish(s, SERVICE_FAILURE_TIMEOUT); s->reload_result = SERVICE_FAILURE_TIMEOUT;
service_enter_running(s, SERVICE_SUCCESS);
break; break;
case SERVICE_MOUNTING: case SERVICE_MOUNTING:
@ -4814,90 +4747,6 @@ finish:
return 1; return 1;
} }
static void service_notify_message_process_state(Service *s, char * const *tags) {
usec_t monotonic_usec = USEC_INFINITY;
int r;
assert(s);
const char *e = strv_find_startswith(tags, "MONOTONIC_USEC=");
if (e) {
r = safe_atou64(e, &monotonic_usec);
if (r < 0)
log_unit_warning_errno(UNIT(s), r, "Failed to parse MONOTONIC_USEC= field in notification message, ignoring: %s", e);
}
/* Interpret READY=/STOPPING=/RELOADING=. STOPPING= wins over the others, and READY= over RELOADING= */
if (strv_contains(tags, "STOPPING=1")) {
s->notify_state = NOTIFY_STOPPING;
if (IN_SET(s->state, SERVICE_RUNNING, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY, SERVICE_REFRESH_EXTENSIONS))
service_enter_stop_by_notify(s);
return;
}
/* Disallow resurrecting a dying service */
if (s->notify_state == NOTIFY_STOPPING)
return;
if (strv_contains(tags, "READY=1")) {
if (s->notify_state == NOTIFY_RELOADING)
s->notify_state = NOTIFY_RELOAD_READY;
else
s->notify_state = NOTIFY_READY;
/* Combined RELOADING=1 and READY=1? Then this is indication that the service started and
* immediately finished reloading. */
if (strv_contains(tags, "RELOADING=1")) {
if (s->state == SERVICE_RELOAD_SIGNAL &&
monotonic_usec != USEC_INFINITY &&
monotonic_usec >= s->reload_begin_usec)
/* Valid Type=notify-reload protocol? Then we're all good. */
service_enter_reload_post(s);
else if (s->state == SERVICE_RUNNING) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
/* Propagate a reload explicitly for plain RELOADING=1 (semantically equivalent to
* service_enter_reload_by_notify() call in below) */
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));
}
}
/* Type=notify(-reload) 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);
/* Sending READY=1 while we are reloading informs us that the reloading is complete. */
if (s->state == SERVICE_RELOAD_NOTIFY)
service_enter_reload_post(s);
} 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 timeout. */
service_set_state(s, SERVICE_RELOAD_NOTIFY);
if (s->state == SERVICE_RUNNING)
service_enter_reload_by_notify(s);
}
}
static void service_notify_message( static void service_notify_message(
Unit *u, Unit *u,
PidRef *pidref, PidRef *pidref,
@ -4919,6 +4768,7 @@ static void service_notify_message(
log_unit_debug(u, "Got notification message from PID "PID_FMT": %s", pidref->pid, empty_to_na(cc)); log_unit_debug(u, "Got notification message from PID "PID_FMT": %s", pidref->pid, empty_to_na(cc));
} }
usec_t monotonic_usec = USEC_INFINITY;
bool notify_dbus = false; bool notify_dbus = false;
const char *e; const char *e;
@ -4928,7 +4778,7 @@ static void service_notify_message(
r = service_notify_message_parse_new_pid(u, tags, fds, &new_main_pid); r = service_notify_message_parse_new_pid(u, tags, fds, &new_main_pid);
if (r > 0 && if (r > 0 &&
IN_SET(s->state, SERVICE_START, SERVICE_START_POST, SERVICE_RUNNING, IN_SET(s->state, SERVICE_START, SERVICE_START_POST, SERVICE_RUNNING,
SERVICE_REFRESH_EXTENSIONS, SERVICE_RELOAD, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY, SERVICE_RELOAD_POST, SERVICE_RELOAD, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY, SERVICE_REFRESH_EXTENSIONS,
SERVICE_STOP, SERVICE_STOP_SIGTERM) && SERVICE_STOP, SERVICE_STOP_SIGTERM) &&
(!s->main_pid_known || !pidref_equal(&new_main_pid, &s->main_pid))) { (!s->main_pid_known || !pidref_equal(&new_main_pid, &s->main_pid))) {
@ -4953,7 +4803,79 @@ static void service_notify_message(
} }
} }
service_notify_message_process_state(s, 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);
}
/* Interpret READY=/STOPPING=/RELOADING=. STOPPING= wins over the others, and READY= over RELOADING= */
if (strv_contains(tags, "STOPPING=1")) {
s->notify_state = NOTIFY_STOPPING;
if (IN_SET(s->state, SERVICE_RUNNING, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY, SERVICE_REFRESH_EXTENSIONS))
service_enter_stop_by_notify(s);
notify_dbus = true;
} else if (strv_contains(tags, "READY=1")) {
s->notify_state = NOTIFY_READY;
/* Combined RELOADING=1 and READY=1? Then this is indication that the service started and
* immediately finished reloading. */
if (strv_contains(tags, "RELOADING=1")) {
if (s->state == SERVICE_RELOAD_SIGNAL &&
monotonic_usec != USEC_INFINITY &&
monotonic_usec >= s->reload_begin_usec)
/* Valid Type=notify-reload protocol? Then we're all good. */
service_enter_running(s, SERVICE_SUCCESS);
else if (s->state == SERVICE_RUNNING) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
/* Propagate a reload explicitly for plain RELOADING=1 (semantically equivalent to
* service_enter_reload_mounting() call in below) */
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));
}
}
/* Type=notify(-reload) 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);
/* 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);
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 timeout. */
service_set_state(s, SERVICE_RELOAD_NOTIFY);
if (s->state == SERVICE_RUNNING)
service_enter_reload_by_notify(s);
notify_dbus = true;
}
/* Interpret STATUS= */ /* Interpret STATUS= */
e = strv_find_startswith(tags, "STATUS="); e = strv_find_startswith(tags, "STATUS=");
@ -5196,11 +5118,10 @@ static bool pick_up_pid_from_bus_name(Service *s) {
SERVICE_START, SERVICE_START,
SERVICE_START_POST, SERVICE_START_POST,
SERVICE_RUNNING, SERVICE_RUNNING,
SERVICE_REFRESH_EXTENSIONS,
SERVICE_RELOAD, SERVICE_RELOAD,
SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_SIGNAL,
SERVICE_RELOAD_NOTIFY, SERVICE_RELOAD_NOTIFY,
SERVICE_RELOAD_POST, SERVICE_REFRESH_EXTENSIONS,
SERVICE_MOUNTING); SERVICE_MOUNTING);
} }
@ -5382,11 +5303,10 @@ static bool service_needs_console(Unit *u) {
SERVICE_START, SERVICE_START,
SERVICE_START_POST, SERVICE_START_POST,
SERVICE_RUNNING, SERVICE_RUNNING,
SERVICE_REFRESH_EXTENSIONS,
SERVICE_RELOAD, SERVICE_RELOAD,
SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_SIGNAL,
SERVICE_RELOAD_NOTIFY, SERVICE_RELOAD_NOTIFY,
SERVICE_RELOAD_POST, SERVICE_REFRESH_EXTENSIONS,
SERVICE_MOUNTING, SERVICE_MOUNTING,
SERVICE_STOP, SERVICE_STOP,
SERVICE_STOP_WATCHDOG, SERVICE_STOP_WATCHDOG,
@ -5824,7 +5744,6 @@ static const char* const service_exec_command_table[_SERVICE_EXEC_COMMAND_MAX] =
[SERVICE_EXEC_START] = "ExecStart", [SERVICE_EXEC_START] = "ExecStart",
[SERVICE_EXEC_START_POST] = "ExecStartPost", [SERVICE_EXEC_START_POST] = "ExecStartPost",
[SERVICE_EXEC_RELOAD] = "ExecReload", [SERVICE_EXEC_RELOAD] = "ExecReload",
[SERVICE_EXEC_RELOAD_POST] = "ExecReloadPost",
[SERVICE_EXEC_STOP] = "ExecStop", [SERVICE_EXEC_STOP] = "ExecStop",
[SERVICE_EXEC_STOP_POST] = "ExecStopPost", [SERVICE_EXEC_STOP_POST] = "ExecStopPost",
}; };
@ -5837,7 +5756,6 @@ static const char* const service_exec_ex_command_table[_SERVICE_EXEC_COMMAND_MAX
[SERVICE_EXEC_START] = "ExecStartEx", [SERVICE_EXEC_START] = "ExecStartEx",
[SERVICE_EXEC_START_POST] = "ExecStartPostEx", [SERVICE_EXEC_START_POST] = "ExecStartPostEx",
[SERVICE_EXEC_RELOAD] = "ExecReloadEx", [SERVICE_EXEC_RELOAD] = "ExecReloadEx",
[SERVICE_EXEC_RELOAD_POST] = "ExecReloadPostEx",
[SERVICE_EXEC_STOP] = "ExecStopEx", [SERVICE_EXEC_STOP] = "ExecStopEx",
[SERVICE_EXEC_STOP_POST] = "ExecStopPostEx", [SERVICE_EXEC_STOP_POST] = "ExecStopPostEx",
}; };
@ -5845,9 +5763,9 @@ static const char* const service_exec_ex_command_table[_SERVICE_EXEC_COMMAND_MAX
DEFINE_STRING_TABLE_LOOKUP(service_exec_ex_command, ServiceExecCommand); DEFINE_STRING_TABLE_LOOKUP(service_exec_ex_command, ServiceExecCommand);
static const char* const notify_state_table[_NOTIFY_STATE_MAX] = { static const char* const notify_state_table[_NOTIFY_STATE_MAX] = {
[NOTIFY_UNKNOWN] = "unknown",
[NOTIFY_READY] = "ready", [NOTIFY_READY] = "ready",
[NOTIFY_RELOADING] = "reloading", [NOTIFY_RELOADING] = "reloading",
[NOTIFY_RELOAD_READY] = "reload-ready",
[NOTIFY_STOPPING] = "stopping", [NOTIFY_STOPPING] = "stopping",
}; };

View File

@ -46,7 +46,6 @@ typedef enum ServiceExecCommand {
SERVICE_EXEC_START, SERVICE_EXEC_START,
SERVICE_EXEC_START_POST, SERVICE_EXEC_START_POST,
SERVICE_EXEC_RELOAD, SERVICE_EXEC_RELOAD,
SERVICE_EXEC_RELOAD_POST,
SERVICE_EXEC_STOP, SERVICE_EXEC_STOP,
SERVICE_EXEC_STOP_POST, SERVICE_EXEC_STOP_POST,
_SERVICE_EXEC_COMMAND_MAX, _SERVICE_EXEC_COMMAND_MAX,
@ -54,9 +53,9 @@ typedef enum ServiceExecCommand {
} ServiceExecCommand; } ServiceExecCommand;
typedef enum NotifyState { typedef enum NotifyState {
NOTIFY_UNKNOWN,
NOTIFY_READY, NOTIFY_READY,
NOTIFY_RELOADING, NOTIFY_RELOADING,
NOTIFY_RELOAD_READY,
NOTIFY_STOPPING, NOTIFY_STOPPING,
_NOTIFY_STATE_MAX, _NOTIFY_STATE_MAX,
_NOTIFY_STATE_INVALID = -EINVAL, _NOTIFY_STATE_INVALID = -EINVAL,
@ -299,5 +298,7 @@ ServiceTimeoutFailureMode service_timeout_failure_mode_from_string(const char *s
DEFINE_CAST(SERVICE, Service); DEFINE_CAST(SERVICE, Service);
#define STATUS_TEXT_MAX (16U*1024U)
/* Only exported for unit tests */ /* Only exported for unit tests */
int service_deserialize_exec_command(Unit *u, const char *key, const char *value); int service_deserialize_exec_command(Unit *u, const char *key, const char *value);

View File

@ -2148,6 +2148,8 @@ static void socket_enter_stop_post(Socket *s, SocketResult f) {
s->control_command = s->exec_command[SOCKET_EXEC_STOP_POST]; s->control_command = s->exec_command[SOCKET_EXEC_STOP_POST];
if (s->control_command) { if (s->control_command) {
pidref_done(&s->control_pid);
r = socket_spawn(s, s->control_command, &s->control_pid); r = socket_spawn(s, s->control_command, &s->control_pid);
if (r < 0) { if (r < 0) {
log_unit_warning_errno(UNIT(s), r, "Failed to spawn 'stop-post' task: %m"); log_unit_warning_errno(UNIT(s), r, "Failed to spawn 'stop-post' task: %m");
@ -2224,6 +2226,8 @@ static void socket_enter_stop_pre(Socket *s, SocketResult f) {
s->control_command = s->exec_command[SOCKET_EXEC_STOP_PRE]; s->control_command = s->exec_command[SOCKET_EXEC_STOP_PRE];
if (s->control_command) { if (s->control_command) {
pidref_done(&s->control_pid);
r = socket_spawn(s, s->control_command, &s->control_pid); r = socket_spawn(s, s->control_command, &s->control_pid);
if (r < 0) { if (r < 0) {
log_unit_warning_errno(UNIT(s), r, "Failed to spawn 'stop-pre' task: %m"); log_unit_warning_errno(UNIT(s), r, "Failed to spawn 'stop-pre' task: %m");
@ -2285,6 +2289,8 @@ static void socket_enter_start_post(Socket *s) {
s->control_command = s->exec_command[SOCKET_EXEC_START_POST]; s->control_command = s->exec_command[SOCKET_EXEC_START_POST];
if (s->control_command) { if (s->control_command) {
pidref_done(&s->control_pid);
r = socket_spawn(s, s->control_command, &s->control_pid); r = socket_spawn(s, s->control_command, &s->control_pid);
if (r < 0) { if (r < 0) {
log_unit_warning_errno(UNIT(s), r, "Failed to spawn 'start-post' task: %m"); log_unit_warning_errno(UNIT(s), r, "Failed to spawn 'start-post' task: %m");
@ -2357,6 +2363,8 @@ static void socket_enter_start_pre(Socket *s) {
s->control_command = s->exec_command[SOCKET_EXEC_START_PRE]; s->control_command = s->exec_command[SOCKET_EXEC_START_PRE];
if (s->control_command) { if (s->control_command) {
pidref_done(&s->control_pid);
r = socket_spawn(s, s->control_command, &s->control_pid); r = socket_spawn(s, s->control_command, &s->control_pid);
if (r < 0) { if (r < 0) {
log_unit_warning_errno(UNIT(s), r, "Failed to spawn 'start-pre' task: %m"); log_unit_warning_errno(UNIT(s), r, "Failed to spawn 'start-pre' task: %m");
@ -2604,6 +2612,8 @@ static void socket_run_next(Socket *s) {
s->control_command = s->control_command->command_next; s->control_command = s->control_command->command_next;
pidref_done(&s->control_pid);
r = socket_spawn(s, s->control_command, &s->control_pid); r = socket_spawn(s, s->control_command, &s->control_pid);
if (r < 0) { if (r < 0) {
log_unit_warning_errno(UNIT(s), r, "Failed to spawn next task: %m"); log_unit_warning_errno(UNIT(s), r, "Failed to spawn next task: %m");

View File

@ -350,12 +350,11 @@ assert_cc(sizeof(long long) == sizeof(intmax_t));
#define CASE_F_18(X, ...) case X: CASE_F_17( __VA_ARGS__) #define CASE_F_18(X, ...) case X: CASE_F_17( __VA_ARGS__)
#define CASE_F_19(X, ...) case X: CASE_F_18( __VA_ARGS__) #define CASE_F_19(X, ...) case X: CASE_F_18( __VA_ARGS__)
#define CASE_F_20(X, ...) case X: CASE_F_19( __VA_ARGS__) #define CASE_F_20(X, ...) case X: CASE_F_19( __VA_ARGS__)
#define CASE_F_21(X, ...) case X: CASE_F_20( __VA_ARGS__)
#define GET_CASE_F(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,NAME,...) NAME #define GET_CASE_F(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,NAME,...) NAME
#define FOR_EACH_MAKE_CASE(...) \ #define FOR_EACH_MAKE_CASE(...) \
GET_CASE_F(__VA_ARGS__,CASE_F_21,CASE_F_20,CASE_F_19,CASE_F_18,CASE_F_17,CASE_F_16,CASE_F_15,CASE_F_14,CASE_F_13,CASE_F_12, \ GET_CASE_F(__VA_ARGS__,CASE_F_20,CASE_F_19,CASE_F_18,CASE_F_17,CASE_F_16,CASE_F_15,CASE_F_14,CASE_F_13,CASE_F_12,CASE_F_11, \
CASE_F_11,CASE_F_10,CASE_F_9,CASE_F_8,CASE_F_7,CASE_F_6,CASE_F_5,CASE_F_4,CASE_F_3,CASE_F_2,CASE_F_1) \ CASE_F_10,CASE_F_9,CASE_F_8,CASE_F_7,CASE_F_6,CASE_F_5,CASE_F_4,CASE_F_3,CASE_F_2,CASE_F_1) \
(__VA_ARGS__) (__VA_ARGS__)
#define IN_SET(x, first, ...) \ #define IN_SET(x, first, ...) \
@ -364,7 +363,7 @@ assert_cc(sizeof(long long) == sizeof(intmax_t));
/* If the build breaks in the line below, you need to extend the case macros. We use typeof(+x) \ /* If the build breaks in the line below, you need to extend the case macros. We use typeof(+x) \
* here to widen the type of x if it is a bit-field as this would otherwise be illegal. */ \ * here to widen the type of x if it is a bit-field as this would otherwise be illegal. */ \
static const typeof(+x) __assert_in_set[] _unused_ = { first, __VA_ARGS__ }; \ static const typeof(+x) __assert_in_set[] _unused_ = { first, __VA_ARGS__ }; \
assert_cc(ELEMENTSOF(__assert_in_set) <= 21); \ assert_cc(ELEMENTSOF(__assert_in_set) <= 20); \
switch (x) { \ switch (x) { \
FOR_EACH_MAKE_CASE(first, __VA_ARGS__) \ FOR_EACH_MAKE_CASE(first, __VA_ARGS__) \
_found = true; \ _found = true; \

View File

@ -3453,8 +3453,10 @@ _public_ int sd_json_parse_file_at(
if (f) if (f)
r = read_full_stream(f, &text, NULL); r = read_full_stream(f, &text, NULL);
else else if (path)
r = read_full_file_full(dir_fd, path, UINT64_MAX, SIZE_MAX, 0, NULL, &text, NULL); r = read_full_file_full(dir_fd, path, UINT64_MAX, SIZE_MAX, 0, NULL, &text, NULL);
else
return -EINVAL;
if (r < 0) if (r < 0)
return r; return r;

View File

@ -2649,8 +2649,6 @@ static const BusProperty service_properties[] = {
{ "ExecStartPostEx", bus_append_exec_command }, /* compat */ { "ExecStartPostEx", bus_append_exec_command }, /* compat */
{ "ExecReload", bus_append_exec_command }, { "ExecReload", bus_append_exec_command },
{ "ExecReloadEx", bus_append_exec_command }, /* compat */ { "ExecReloadEx", bus_append_exec_command }, /* compat */
{ "ExecReloadPost", bus_append_exec_command },
{ "ExecReloadPostEx", bus_append_exec_command }, /* compat */
{ "ExecStop", bus_append_exec_command }, { "ExecStop", bus_append_exec_command },
{ "ExecStopEx", bus_append_exec_command }, /* compat */ { "ExecStopEx", bus_append_exec_command }, /* compat */
{ "ExecStopPost", bus_append_exec_command }, { "ExecStopPost", bus_append_exec_command },

View File

@ -619,7 +619,6 @@ static int image_make(
static int pick_image_search_path( static int pick_image_search_path(
RuntimeScope scope, RuntimeScope scope,
ImageClass class, ImageClass class,
const char *root,
char ***ret) { char ***ret) {
int r; int r;
@ -636,11 +635,11 @@ static int pick_image_search_path(
if (scope < 0) { if (scope < 0) {
_cleanup_strv_free_ char **a = NULL, **b = NULL; _cleanup_strv_free_ char **a = NULL, **b = NULL;
r = pick_image_search_path(RUNTIME_SCOPE_USER, class, root, &a); r = pick_image_search_path(RUNTIME_SCOPE_USER, class, &a);
if (r < 0) if (r < 0)
return r; return r;
r = pick_image_search_path(RUNTIME_SCOPE_SYSTEM, class, root, &b); r = pick_image_search_path(RUNTIME_SCOPE_SYSTEM, class, &b);
if (r < 0) if (r < 0)
return r; return r;
@ -656,15 +655,8 @@ static int pick_image_search_path(
case RUNTIME_SCOPE_SYSTEM: { case RUNTIME_SCOPE_SYSTEM: {
const char *ns; const char *ns;
bool is_initrd;
r = chase_and_access("/etc/initrd-release", root, CHASE_PREFIX_ROOT, F_OK, /* ret_path= */ NULL);
if (r < 0 && r != -ENOENT)
return r;
is_initrd = r >= 0;
/* Use the initrd search path if there is one, otherwise use the common one */ /* Use the initrd search path if there is one, otherwise use the common one */
ns = is_initrd && image_search_path_initrd[class] ? ns = in_initrd() && image_search_path_initrd[class] ?
image_search_path_initrd[class] : image_search_path_initrd[class] :
image_search_path[class]; image_search_path[class];
if (!ns) if (!ns)
@ -771,7 +763,7 @@ int image_find(RuntimeScope scope,
return -ENOMEM; return -ENOMEM;
_cleanup_strv_free_ char **search = NULL; _cleanup_strv_free_ char **search = NULL;
r = pick_image_search_path(scope, class, root, &search); r = pick_image_search_path(scope, class, &search);
if (r < 0) if (r < 0)
return r; return r;
@ -962,7 +954,7 @@ int image_discover(
assert(images); assert(images);
_cleanup_strv_free_ char **search = NULL; _cleanup_strv_free_ char **search = NULL;
r = pick_image_search_path(scope, class, root, &search); r = pick_image_search_path(scope, class, &search);
if (r < 0) if (r < 0)
return r; return r;
@ -2109,7 +2101,7 @@ bool image_in_search_path(
assert(image); assert(image);
_cleanup_strv_free_ char **search = NULL; _cleanup_strv_free_ char **search = NULL;
r = pick_image_search_path(scope, class, root, &search); r = pick_image_search_path(scope, class, &search);
if (r < 0) if (r < 0)
return r; return r;

View File

@ -1707,11 +1707,9 @@ static const ImagePolicy *pick_image_policy(const Image *img) {
/* If located in /.extra/ in the initrd, then it was placed there by systemd-stub, and was /* If located in /.extra/ in the initrd, then it was placed there by systemd-stub, and was
* picked up from an untrusted ESP. Thus, require a stricter policy by default for them. (For the * picked up from an untrusted ESP. Thus, require a stricter policy by default for them. (For the
* other directories we assume the appropriate level of trust was already established.) * other directories we assume the appropriate level of trust was already established already. */
* With --root= we default to the regular policy, though. (To change that, the check would need
* to prepend (or cut away) arg_root.) */
if (in_initrd() && !arg_root) { if (in_initrd()) {
if (path_startswith(img->path, "/.extra/sysext/")) if (path_startswith(img->path, "/.extra/sysext/"))
return &image_policy_sysext_strict; return &image_policy_sysext_strict;
if (path_startswith(img->path, "/.extra/global_sysext/")) if (path_startswith(img->path, "/.extra/global_sysext/"))
@ -1907,19 +1905,13 @@ static int merge_subprocess(
if (force) if (force)
log_debug("Force mode enabled, skipping version validation."); log_debug("Force mode enabled, skipping version validation.");
else { else {
bool is_initrd;
r = chase_and_access("/etc/initrd-release", arg_root, CHASE_PREFIX_ROOT, F_OK, /* ret_path= */ NULL);
if (r < 0 && r != -ENOENT)
return log_error_errno(r, "Failed to check for /etc/initrd-release: %m");
is_initrd = r >= 0;
r = extension_release_validate( r = extension_release_validate(
img->name, img->name,
host_os_release_id, host_os_release_id,
host_os_release_id_like, host_os_release_id_like,
host_os_release_version_id, host_os_release_version_id,
host_os_release_api_level, host_os_release_api_level,
is_initrd ? "initrd" : "system", in_initrd() ? "initrd" : "system",
image_extension_release(img, image_class), image_extension_release(img, image_class),
image_class); image_class);
if (r < 0) if (r < 0)

View File

@ -95,28 +95,8 @@ static int parse_shutdown_time_spec(const char *t, usec_t *ret) {
if (r < 0) if (r < 0)
return r; return r;
if (s <= n) { while (s <= n)
/* The specified time is today, but in the past. We need to schedule it for tomorrow s += USEC_PER_DAY;
* at the same time. Adding USEC_PER_DAY would be wrong across DST changes, so just
* let mktime() normalise it. */
int requested_hour = tm.tm_hour;
int requested_min = tm.tm_min;
tm.tm_mday++;
tm.tm_isdst = -1;
r = mktime_or_timegm_usec(&tm, /* utc= */ false, &s);
if (r < 0)
return r;
if (tm.tm_hour != requested_hour || tm.tm_min != requested_min) {
log_warning("Requested shutdown time %02d:%02d does not exist. "
"Rescheduling to %02d:%02d.",
requested_hour,
requested_min,
tm.tm_hour,
tm.tm_min);
}
}
*ret = s; *ret = s;
} }

View File

@ -2284,8 +2284,6 @@ static int show_one(
{ "ExecStartPostEx", "a(sasasttttuii)", map_exec, 0 }, { "ExecStartPostEx", "a(sasasttttuii)", map_exec, 0 },
{ "ExecReload", "a(sasbttttuii)", map_exec, 0 }, { "ExecReload", "a(sasbttttuii)", map_exec, 0 },
{ "ExecReloadEx", "a(sasasttttuii)", map_exec, 0 }, { "ExecReloadEx", "a(sasasttttuii)", map_exec, 0 },
{ "ExecReloadPost", "a(sasbttttuii)", map_exec, 0 },
{ "ExecReloadPostEx", "a(sasasttttuii)", map_exec, 0 },
{ "ExecStopPre", "a(sasbttttuii)", map_exec, 0 }, { "ExecStopPre", "a(sasbttttuii)", map_exec, 0 },
{ "ExecStop", "a(sasbttttuii)", map_exec, 0 }, { "ExecStop", "a(sasbttttuii)", map_exec, 0 },
{ "ExecStopEx", "a(sasasttttuii)", map_exec, 0 }, { "ExecStopEx", "a(sasasttttuii)", map_exec, 0 },

View File

@ -221,8 +221,10 @@ static int job_new(JobType type, Target *t, sd_bus_message *msg, JobComplete com
} }
static int job_parse_child_output(int _fd, sd_json_variant **ret) { static int job_parse_child_output(int _fd, sd_json_variant **ret) {
_cleanup_close_ int fd = ASSERT_FD(_fd); /* Take ownership of the passed fd */
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL; _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
/* Take ownership of the passed fd */
_cleanup_close_ int fd = _fd;
_cleanup_fclose_ FILE *f = NULL;
struct stat st; struct stat st;
int r; int r;
@ -238,10 +240,16 @@ static int job_parse_child_output(int _fd, sd_json_variant **ret) {
return 0; return 0;
} }
r = sd_json_parse_file_at(/* f = */ NULL, fd, /* path = */ NULL, /* flags = */ 0, if (lseek(fd, SEEK_SET, 0) == (off_t) -1)
&v, /* reterr_line = */ NULL, /* reterr_column = */ NULL); return log_debug_errno(errno, "Failed to seek to beginning of memfd: %m");
f = take_fdopen(&fd, "r");
if (!f)
return log_debug_errno(errno, "Failed to reopen memfd: %m");
r = sd_json_parse_file(f, "stdout", 0, &v, NULL, NULL);
if (r < 0) if (r < 0)
return log_debug_errno(r, "Failed to parse child output as JSON: %m"); return log_debug_errno(r, "Failed to parse JSON: %m");
*ret = TAKE_PTR(v); *ret = TAKE_PTR(v);
return 0; return 0;

View File

@ -1,4 +0,0 @@
[Service]
Type=notify-reload
TimeoutStartSec=40
ExecStart=/usr/lib/systemd/tests/testdata/TEST-80-NOTIFYACCESS.units/reload-timeout.sh

View File

@ -1,40 +0,0 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: LGPL-2.1-or-later
# shellcheck disable=SC2016
set -eux
set -o pipefail
COUNTER=0
sync_in() {
read -r x < /tmp/syncfifo2
test "$x" = "$1"
}
wait_for_signal() {
sleep infinity &
wait "$!" || :
}
sighup_handler() {
echo "hup$(( ++COUNTER ))" > /tmp/syncfifo1
}
trap sighup_handler SIGHUP
export SYSTEMD_LOG_LEVEL=debug
systemd-notify --ready
wait_for_signal
systemd-notify --reloading
wait_for_signal
systemd-notify --reloading
sync_in ready
systemd-notify --ready
wait_for_signal
systemd-notify --reloading --ready
exec sleep infinity

View File

@ -80,20 +80,14 @@ systemd-dissect --umount "$IMAGE_DIR/mount2"
# Ensure the deferred close flag is set up correctly and we don't leak verity devices # Ensure the deferred close flag is set up correctly and we don't leak verity devices
# when sharing is disabled # when sharing is disabled
set +o pipefail
# The devices are named 'loopXYZ-verity' when sharing is disabled # The devices are named 'loopXYZ-verity' when sharing is disabled
n_before=$(dmsetup ls | grep loop | grep -c verity || true)
SYSTEMD_VERITY_SHARING=0 systemd-dissect --mount "$MINIMAL_IMAGE.raw" "$IMAGE_DIR/mount" SYSTEMD_VERITY_SHARING=0 systemd-dissect --mount "$MINIMAL_IMAGE.raw" "$IMAGE_DIR/mount"
d="" test $((n_before + 1)) -eq "$(dmsetup ls | grep loop | grep -c verity || true)"
for f in /dev/mapper/*; do
if [[ "$(basename "$f")" =~ ^loop.*-verity ]] && veritysetup status "$(basename "$f")" | grep -q "$MINIMAL_IMAGE.raw"; then
d="$f"
break
fi
done
test -n "$d"
dmsetup ls | grep -q "$(basename "$d")"
umount -R "$IMAGE_DIR/mount" umount -R "$IMAGE_DIR/mount"
timeout 60 bash -c "while test -e $d; do sleep 0.1; done" test "$n_before" -eq "$(dmsetup ls | grep loop | grep -c verity || true)"
( ! dmsetup ls | grep -q "$(basename "$d")") set -o pipefail
# Test BindLogSockets= # Test BindLogSockets=
systemd-run --wait -p RootImage="$MINIMAL_IMAGE.raw" mountpoint /run/systemd/journal/socket systemd-run --wait -p RootImage="$MINIMAL_IMAGE.raw" mountpoint /run/systemd/journal/socket

View File

@ -1130,13 +1130,10 @@ extension_verify_after_unmerge "$fake_root" "$hierarchy" -h
fake_root=${roots_dir:+"$roots_dir/mutable-directory-with-invalid-permissions"} fake_root=${roots_dir:+"$roots_dir/mutable-directory-with-invalid-permissions"}
hierarchy=/opt hierarchy=/opt
extension_data_dir="$fake_root/var/lib/extensions.mutable$hierarchy" extension_data_dir="$fake_root/var/lib/extensions.mutable$hierarchy"
extension_data_dir_usr="$fake_root/var/lib/extensions.mutable/usr"
prepare_root "$fake_root" "$hierarchy" prepare_root "$fake_root" "$hierarchy"
prepare_extension_image "$fake_root" "$hierarchy" prepare_extension_image "$fake_root" "$hierarchy"
prepare_extension_mutable_dir "$extension_data_dir" prepare_extension_mutable_dir "$extension_data_dir"
prepend_trap "rm -rf ${extension_data_dir@Q}"
prepend_trap "rm -rf ${extension_data_dir_usr@Q}"
prepare_hierarchy "$fake_root" "$hierarchy" prepare_hierarchy "$fake_root" "$hierarchy"
old_mode=$(stat --format '%#a' "$fake_root$hierarchy") old_mode=$(stat --format '%#a' "$fake_root$hierarchy")
@ -1147,29 +1144,6 @@ chmod 0700 "$extension_data_dir"
(! run_systemd_sysext "$fake_root" --mutable=yes merge) (! run_systemd_sysext "$fake_root" --mutable=yes merge)
) )
( init_trap
: "Check if merging fails in case of --root= being an initrd but the extension is not for it"
# Since this is really about whether --root= gets prepended for the /etc/initrd-release check,
# this also tests the more interesting reverse case that we are in the initrd and prepare
# the mounts for the final system with --root=/sysroot
fake_root=${roots_dir:+"$roots_dir/initrd-env-with-non-initrd-extension"}
hierarchy=/opt
prepare_root "$fake_root" "$hierarchy"
prepare_extension_image "$fake_root" "$hierarchy"
mkdir -p "${fake_root}/etc"
touch "${fake_root}/etc/initrd-release"
prepare_read_only_hierarchy "$fake_root" "$hierarchy"
# Should be a no-op, thus we also don't run unmerge afterwards (otherwise the test is broken)
run_systemd_sysext "$fake_root" merge
if run_systemd_sysext "$fake_root" status --json=pretty | jq -r '.[].extensions' | grep -v '^none$' ; then
echo >&2 "Extension got loaded for an initrd structure passed as --root= while the extension does not declare itself compatible with the initrd scope"
exit 1
fi
rm "${fake_root}/etc/initrd-release"
)
} # End of run_sysext_tests } # End of run_sysext_tests

View File

@ -868,8 +868,8 @@ EOF
for ((i = 0; i < ${#devices[@]}; i++)); do for ((i = 0; i < ${#devices[@]}; i++)); do
# Intentionally use weaker cipher-related settings, since we don't care # Intentionally use weaker cipher-related settings, since we don't care
# about security here as it's a throwaway LUKS partition # about security here as it's a throwaway LUKS partition
SYSTEMD_LOG_LEVEL=debug udevadm lock --timeout=30 --device="${devices[$i]}" \ udevadm lock --timeout=30 --device="${devices[$i]}" \
cryptsetup luksFormat -q --debug \ cryptsetup luksFormat -q \
--use-urandom --pbkdf pbkdf2 --pbkdf-force-iterations 1000 \ --use-urandom --pbkdf pbkdf2 --pbkdf-force-iterations 1000 \
--uuid "deadbeef-dead-dead-beef-11111111111$i" --label "encdisk$i" "${devices[$i]}" /etc/btrfs_keyfile --uuid "deadbeef-dead-dead-beef-11111111111$i" --label "encdisk$i" "${devices[$i]}" /etc/btrfs_keyfile
udevadm wait --settle --timeout=30 "/dev/disk/by-uuid/deadbeef-dead-dead-beef-11111111111$i" "/dev/disk/by-label/encdisk$i" udevadm wait --settle --timeout=30 "/dev/disk/by-uuid/deadbeef-dead-dead-beef-11111111111$i" "/dev/disk/by-label/encdisk$i"

View File

@ -81,11 +81,6 @@ systemd-run --wait --pipe --user --machine=testuser@ \
systemd-run --wait --pipe --user --machine=testuser@ \ systemd-run --wait --pipe --user --machine=testuser@ \
bash -xec '[[ "$PWD" == /home/testuser && -n "$INVOCATION_ID" ]]' bash -xec '[[ "$PWD" == /home/testuser && -n "$INVOCATION_ID" ]]'
# https://github.com/systemd/systemd/issues/39038
systemd-run --wait --machine=testuser@ --user -p User=testuser true
systemd-run --wait --machine=testuser@ --user -p Group=testuser true
(! systemd-run --wait --machine=testuser@ --user -p Group=testuser -p SupplementaryGroups=root true)
# PrivateTmp=yes implies PrivateUsers=yes for user manager, so skip this if we # PrivateTmp=yes implies PrivateUsers=yes for user manager, so skip this if we
# don't have unprivileged user namespaces. # don't have unprivileged user namespaces.
if [[ "$(sysctl -ne kernel.apparmor_restrict_unprivileged_userns)" -ne 1 ]]; then if [[ "$(sysctl -ne kernel.apparmor_restrict_unprivileged_userns)" -ne 1 ]]; then

View File

@ -62,33 +62,6 @@ assert_eq "$(systemctl show notify.service -p NotifyAccess --value)" "none"
systemctl stop notify.service systemctl stop notify.service
assert_eq "$(systemctl show notify.service -p NotifyAccess --value)" "all" assert_eq "$(systemctl show notify.service -p NotifyAccess --value)" "all"
# Timeout of READY=1 for Type=notify-reload services (issue #37515)
systemctl start reload-timeout.service
systemctl reload --no-block reload-timeout.service
timeout 10 bash -c 'until [[ $(systemctl show reload-timeout.service -P SubState) == "reload-signal" ]]; do sleep .5; done'
sync_in hup1
timeout 10 bash -c 'until [[ $(systemctl show reload-timeout.service -P SubState) == "reload-notify" ]]; do sleep .5; done'
timeout 80 bash -c 'until [[ $(systemctl show reload-timeout.service -P SubState) == "running" ]]; do sleep 5; done'
assert_eq "$(systemctl show reload-timeout.service -P ReloadResult)" "timeout"
systemctl reload --no-block reload-timeout.service
timeout 10 bash -c 'until [[ $(systemctl show reload-timeout.service -P SubState) == "reload-signal" ]]; do sleep .5; done'
assert_eq "$(systemctl show reload-timeout.service -P ReloadResult)" "success"
sync_in hup2
timeout 10 bash -c 'until [[ $(systemctl show reload-timeout.service -P SubState) == "reload-notify" ]]; do sleep .5; done'
sync_out ready
timeout 40 bash -c 'until [[ $(systemctl show reload-timeout.service -P SubState) == "running" ]]; do sleep 1; done'
assert_eq "$(systemctl show reload-timeout.service -P ReloadResult)" "success"
systemctl reload --no-block reload-timeout.service
sync_in hup3
timeout 40 bash -c 'until [[ $(systemctl show reload-timeout.service -P SubState) == "running" ]]; do sleep 1; done'
assert_eq "$(systemctl show reload-timeout.service -P ReloadResult)" "success"
systemctl stop reload-timeout.service
rm /tmp/syncfifo1 /tmp/syncfifo2 rm /tmp/syncfifo1 /tmp/syncfifo2
# Explicitly test busctl's BUSERROR= reporting and systemctl status should show it # Explicitly test busctl's BUSERROR= reporting and systemctl status should show it