mirror of
https://github.com/systemd/systemd
synced 2025-11-06 10:24:44 +01:00
Compare commits
No commits in common. "8457f2a3951bca7fca5dd67d4cbdba667a49576c" and "05b880ac46b27c65de09d7add6b0e2f5ac3bcd9a" have entirely different histories.
8457f2a395
...
05b880ac46
@ -2856,10 +2856,6 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("invalidates")
|
||||
readonly a(sasasttttuii) ExecReloadEx = [...];
|
||||
@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 = [...];
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("invalidates")
|
||||
readonly a(sasasttttuii) ExecStopEx = [...];
|
||||
@ -3541,10 +3537,10 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
|
||||
|
||||
<!--property ExecReloadEx is not documented!-->
|
||||
|
||||
<!--property ExecReloadPostEx is not documented!-->
|
||||
|
||||
<!--property ExecStopEx is not documented!-->
|
||||
|
||||
<!--property ExecStopPost is not documented!-->
|
||||
|
||||
<!--property ExecStopPostEx 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="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="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>
|
||||
|
||||
<para><varname>ExecStartPre</varname>, <varname>ExecStart</varname>, <varname>ExecStartPost</varname>,
|
||||
<varname>ExecReload</varname>, <varname>ExecReloadPost</varname>, <varname>ExecStop</varname>, and
|
||||
<varname>ExecStopPost</varname> are arrays of structures where each struct contains: the binary path
|
||||
to execute; an array with all arguments to pass to the executed command, starting with argument 0;
|
||||
a boolean whether it should be considered a failure if the process exits uncleanly; two pairs of
|
||||
<varname>ExecReload</varname>, <varname>ExecStop</varname>, and <varname>ExecStop</varname> are arrays
|
||||
of structures where each struct contains: the binary path to execute; an array with all arguments to
|
||||
pass to the executed command, starting with argument 0; a boolean whether it should be considered a
|
||||
failure if the process exits uncleanly; two pairs of
|
||||
<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 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 ExecStopPost is not documented!-->
|
||||
|
||||
<!--property Slice is not documented!-->
|
||||
|
||||
<!--property ControlGroupId is not documented!-->
|
||||
@ -12550,10 +12544,8 @@ $ gdbus introspect --system --dest org.freedesktop.systemd1 \
|
||||
<varname>LogsDirectoryAccounting</varname>, and
|
||||
<function>KillSubgroup()</function> were added in version 258.</para>
|
||||
<para><varname>UserNamespacePath</varname>,
|
||||
<varname>OOMKills</varname>,
|
||||
<varname>ManagedOOMKills</varname>,
|
||||
<varname>ExecReloadPost</varname>, and
|
||||
<varname>ExecReloadPostEx</varname> were added in version 259.</para>
|
||||
<varname>OOMKills</varname>, and
|
||||
<varname>ManagedOOMKills</varname> were added in 259.</para>
|
||||
</refsect2>
|
||||
<refsect2>
|
||||
<title>Socket Unit Objects</title>
|
||||
|
||||
@ -475,8 +475,8 @@
|
||||
<varlistentry>
|
||||
<term><varname>ExecReload=</varname></term>
|
||||
|
||||
<listitem><para>Commands to execute to trigger a configuration reload in the service. This setting
|
||||
may take multiple command lines, following the same scheme as described 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>
|
||||
@ -486,12 +486,13 @@
|
||||
|
||||
<programlisting>ExecReload=kill -HUP $MAINPID</programlisting>
|
||||
|
||||
<para>Note however that reloading a daemon by enqueuing a signal without completion notification
|
||||
(as is the case 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=notify-reload</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
|
||||
<para>Note however that reloading a daemon by enqueuing 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>
|
||||
|
||||
@ -499,22 +500,6 @@
|
||||
/org/freedesktop/DBus org.freedesktop.DBus \
|
||||
ReloadConfig
|
||||
</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>
|
||||
</varlistentry>
|
||||
|
||||
@ -1087,14 +1072,18 @@
|
||||
|
||||
<varlistentry>
|
||||
<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
|
||||
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>
|
||||
for more information), is only applied to the process started with <varname>ExecStart=</varname>,
|
||||
and not to the various other <varname>ExecStartPre=</varname>, <varname>ExecStartPost=</varname>,
|
||||
<varname>ExecReload=</varname>, <varname>ExecReloadPost=</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>
|
||||
for more information), is only applied to the process started
|
||||
with <varname>ExecStart=</varname>, and not to the various
|
||||
other <varname>ExecStartPre=</varname>,
|
||||
<varname>ExecStartPost=</varname>,
|
||||
<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>
|
||||
|
||||
@ -1011,7 +1011,7 @@ static int xfopenat_regular(int dir_fd, const char *path, const char *mode, int
|
||||
assert(mode);
|
||||
assert(ret);
|
||||
|
||||
if (dir_fd == AT_FDCWD && path && open_flags == 0)
|
||||
if (dir_fd == AT_FDCWD && open_flags == 0 && path)
|
||||
f = fopen(path, mode);
|
||||
else {
|
||||
_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)
|
||||
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)
|
||||
return fd;
|
||||
}
|
||||
|
||||
@ -224,11 +224,10 @@ static const char* const service_state_table[_SERVICE_STATE_MAX] = {
|
||||
[SERVICE_START_POST] = "start-post",
|
||||
[SERVICE_RUNNING] = "running",
|
||||
[SERVICE_EXITED] = "exited",
|
||||
[SERVICE_REFRESH_EXTENSIONS] = "refresh-extensions",
|
||||
[SERVICE_RELOAD] = "reload",
|
||||
[SERVICE_RELOAD_SIGNAL] = "reload-signal",
|
||||
[SERVICE_RELOAD_NOTIFY] = "reload-notify",
|
||||
[SERVICE_RELOAD_POST] = "reload-post",
|
||||
[SERVICE_REFRESH_EXTENSIONS] = "refresh-extensions",
|
||||
[SERVICE_STOP] = "stop",
|
||||
[SERVICE_STOP_WATCHDOG] = "stop-watchdog",
|
||||
[SERVICE_STOP_SIGTERM] = "stop-sigterm",
|
||||
|
||||
@ -131,11 +131,10 @@ typedef enum ServiceState {
|
||||
SERVICE_START_POST,
|
||||
SERVICE_RUNNING,
|
||||
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_SIGNAL, /* Reloading via SIGHUP requested */
|
||||
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_STOP, /* No STOP_PRE state, instead just register multiple STOP executables */
|
||||
SERVICE_STOP_WATCHDOG,
|
||||
|
||||
@ -114,20 +114,12 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
break;
|
||||
|
||||
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;
|
||||
if (strv_push(&arg_names, optarg) < 0) /* push optarg if not empty */
|
||||
return log_oom();
|
||||
break;
|
||||
|
||||
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;
|
||||
if (strv_push(&arg_names, optarg) < 0) /* push optarg if not empty */
|
||||
return log_oom();
|
||||
|
||||
@ -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_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_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_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),
|
||||
|
||||
@ -904,16 +904,8 @@ static int get_supplementary_groups(
|
||||
bool keep_groups = false;
|
||||
if (user && gid_is_valid(gid) && gid != 0) {
|
||||
/* First step, initialize groups from /etc/groups */
|
||||
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;
|
||||
}
|
||||
if (initgroups(user, gid) < 0)
|
||||
return -errno;
|
||||
|
||||
keep_groups = true;
|
||||
}
|
||||
|
||||
@ -436,11 +436,13 @@ bool job_type_is_redundant(JobType a, UnitActiveState b) {
|
||||
switch (a) {
|
||||
|
||||
case JOB_START:
|
||||
case JOB_VERIFY_ACTIVE:
|
||||
return UNIT_IS_ACTIVE_OR_RELOADING(b);
|
||||
return IN_SET(b, UNIT_ACTIVE, UNIT_RELOADING, UNIT_REFRESHING);
|
||||
|
||||
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:
|
||||
/* Reload jobs are never considered redundant/duplicate. Refer to jobs_may_late_merge() for
|
||||
|
||||
@ -162,17 +162,17 @@ int job_coldplug(Job *j);
|
||||
JobDependency* job_dependency_new(Job *subject, Job *object, bool matters, bool conflicts);
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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 */
|
||||
if (b == JOB_NOP)
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
* the state of the unit which it is going to be applied to. */
|
||||
|
||||
@ -430,9 +430,8 @@ Service.PIDFile, config_parse_pid_file,
|
||||
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.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.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.ExecStopPost, config_parse_exec, SERVICE_EXEC_STOP_POST, offsetof(Service, exec_command)
|
||||
Service.RestartSec, config_parse_sec, 0, offsetof(Service, restart_usec)
|
||||
|
||||
@ -56,8 +56,6 @@
|
||||
#include "unit-name.h"
|
||||
#include "utf8.h"
|
||||
|
||||
#define STATUS_TEXT_MAX (16U*1024U)
|
||||
|
||||
#define service_spawn(...) service_spawn_internal(__func__, __VA_ARGS__)
|
||||
|
||||
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_RUNNING] = UNIT_ACTIVE,
|
||||
[SERVICE_EXITED] = UNIT_ACTIVE,
|
||||
[SERVICE_REFRESH_EXTENSIONS] = UNIT_REFRESHING,
|
||||
[SERVICE_RELOAD] = UNIT_RELOADING,
|
||||
[SERVICE_RELOAD_SIGNAL] = UNIT_RELOADING,
|
||||
[SERVICE_RELOAD_NOTIFY] = UNIT_RELOADING,
|
||||
[SERVICE_RELOAD_POST] = UNIT_RELOADING,
|
||||
[SERVICE_REFRESH_EXTENSIONS] = UNIT_REFRESHING,
|
||||
[SERVICE_MOUNTING] = UNIT_REFRESHING,
|
||||
[SERVICE_STOP] = 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_RUNNING] = UNIT_ACTIVE,
|
||||
[SERVICE_EXITED] = UNIT_ACTIVE,
|
||||
[SERVICE_REFRESH_EXTENSIONS] = UNIT_REFRESHING,
|
||||
[SERVICE_RELOAD] = UNIT_RELOADING,
|
||||
[SERVICE_RELOAD_SIGNAL] = UNIT_RELOADING,
|
||||
[SERVICE_RELOAD_NOTIFY] = UNIT_RELOADING,
|
||||
[SERVICE_RELOAD_POST] = UNIT_RELOADING,
|
||||
[SERVICE_REFRESH_EXTENSIONS] = UNIT_REFRESHING,
|
||||
[SERVICE_MOUNTING] = UNIT_REFRESHING,
|
||||
[SERVICE_STOP] = 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 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 bool SERVICE_STATE_WITH_MAIN_PROCESS(ServiceState state) {
|
||||
return IN_SET(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_MOUNTING,
|
||||
SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
|
||||
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,
|
||||
SERVICE_CONDITION,
|
||||
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_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
|
||||
SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL,
|
||||
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) {
|
||||
Service *s = SERVICE(u);
|
||||
|
||||
@ -189,7 +175,6 @@ static void service_init(Unit *u) {
|
||||
EXEC_KEYRING_PRIVATE : EXEC_KEYRING_INHERIT;
|
||||
|
||||
s->notify_access_override = _NOTIFY_ACCESS_INVALID;
|
||||
s->notify_state = _NOTIFY_STATE_INVALID;
|
||||
|
||||
s->watchdog_original_usec = USEC_INFINITY;
|
||||
|
||||
@ -1304,7 +1289,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_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_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
|
||||
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)
|
||||
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);
|
||||
|
||||
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:
|
||||
case SERVICE_START_POST:
|
||||
case SERVICE_REFRESH_EXTENSIONS:
|
||||
case SERVICE_RELOAD:
|
||||
case SERVICE_RELOAD_SIGNAL:
|
||||
case SERVICE_RELOAD_NOTIFY:
|
||||
case SERVICE_RELOAD_POST:
|
||||
case SERVICE_REFRESH_EXTENSIONS:
|
||||
case SERVICE_MOUNTING:
|
||||
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))
|
||||
(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)
|
||||
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 */
|
||||
s->forbid_restart = false;
|
||||
|
||||
/* Reset notify states */
|
||||
/* Reset NotifyAccess override */
|
||||
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. */
|
||||
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];
|
||||
if (s->control_command) {
|
||||
s->control_command_id = SERVICE_EXEC_STOP_POST;
|
||||
pidref_done(&s->control_pid);
|
||||
|
||||
r = service_spawn(s,
|
||||
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];
|
||||
if (s->control_command) {
|
||||
s->control_command_id = SERVICE_EXEC_STOP;
|
||||
pidref_done(&s->control_pid);
|
||||
|
||||
r = service_spawn(s,
|
||||
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];
|
||||
if (s->control_command) {
|
||||
s->control_command_id = SERVICE_EXEC_START_POST;
|
||||
pidref_done(&s->control_pid);
|
||||
|
||||
r = service_spawn(s,
|
||||
s->control_command,
|
||||
@ -2552,6 +2538,7 @@ static void service_enter_start(Service *s) {
|
||||
|
||||
case SERVICE_FORKING:
|
||||
/* For forking services we wait until the start process exited. */
|
||||
pidref_done(&s->control_pid);
|
||||
s->control_pid = TAKE_PIDREF(pidref);
|
||||
return service_set_state(s, SERVICE_START);
|
||||
|
||||
@ -2625,6 +2612,7 @@ static void service_enter_condition(Service *s) {
|
||||
goto fail;
|
||||
|
||||
s->control_command_id = SERVICE_EXEC_CONDITION;
|
||||
pidref_done(&s->control_pid);
|
||||
|
||||
r = service_spawn(s,
|
||||
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);
|
||||
if (r < 0) {
|
||||
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);
|
||||
@ -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));
|
||||
}
|
||||
|
||||
static void service_enter_reload_post(Service *s) {
|
||||
static void service_enter_reload_signal_exec(Service *s) {
|
||||
bool killed = false;
|
||||
int r;
|
||||
|
||||
assert(s);
|
||||
|
||||
service_unwatch_control_pid(s);
|
||||
s->reload_result = SERVICE_SUCCESS;
|
||||
|
||||
s->control_command = s->exec_command[SERVICE_EXEC_RELOAD_POST];
|
||||
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;
|
||||
}
|
||||
usec_t ts = now(CLOCK_MONOTONIC);
|
||||
|
||||
if (s->type == SERVICE_NOTIFY_RELOAD && pidref_is_set(&s->main_pid)) {
|
||||
r = pidref_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;
|
||||
}
|
||||
|
||||
service_set_state(s, SERVICE_RELOAD_SIGNAL);
|
||||
} 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);
|
||||
killed = true;
|
||||
}
|
||||
|
||||
s->control_command = s->exec_command[SERVICE_EXEC_RELOAD];
|
||||
if (s->control_command) {
|
||||
s->control_command_id = SERVICE_EXEC_RELOAD;
|
||||
pidref_done(&s->control_pid);
|
||||
|
||||
r = service_spawn(s,
|
||||
s->control_command,
|
||||
@ -2812,12 +2742,33 @@ static void service_enter_reload(Service *s) {
|
||||
&s->control_pid);
|
||||
if (r < 0) {
|
||||
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);
|
||||
} else
|
||||
service_enter_reload_signal(s);
|
||||
} else if (killed) {
|
||||
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) {
|
||||
@ -2854,20 +2805,15 @@ static void service_enter_refresh_extensions(Service *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))
|
||||
return service_enter_reload(s);
|
||||
return (void) service_enter_reload_signal_exec(s);
|
||||
|
||||
service_unwatch_control_pid(s);
|
||||
s->reload_result = SERVICE_SUCCESS;
|
||||
s->control_command = NULL;
|
||||
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
|
||||
* directly, and instead fork a worker process. */
|
||||
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;
|
||||
|
||||
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) {
|
||||
@ -2938,15 +2905,13 @@ static void service_run_next_control(Service *s) {
|
||||
s->control_command = s->control_command->command_next;
|
||||
service_unwatch_control_pid(s);
|
||||
|
||||
if (IN_SET(s->state,
|
||||
SERVICE_CONDITION,
|
||||
SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
|
||||
SERVICE_RUNNING,
|
||||
SERVICE_RELOAD, SERVICE_RELOAD_POST))
|
||||
if (IN_SET(s->state, SERVICE_CONDITION, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD))
|
||||
timeout = s->timeout_start_usec;
|
||||
else
|
||||
timeout = s->timeout_stop_usec;
|
||||
|
||||
pidref_done(&s->control_pid);
|
||||
|
||||
r = service_spawn(s,
|
||||
s->control_command,
|
||||
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);
|
||||
else if (s->state == SERVICE_STOP_POST)
|
||||
service_enter_dead(s, SERVICE_FAILURE_RESOURCES, /* allow_restart= */ true);
|
||||
else if (IN_SET(s->state, SERVICE_RELOAD, SERVICE_RELOAD_POST))
|
||||
service_reload_finish(s, SERVICE_FAILURE_RESOURCES);
|
||||
else
|
||||
else if (s->state == SERVICE_RELOAD) {
|
||||
s->reload_result = SERVICE_FAILURE_RESOURCES;
|
||||
service_enter_running(s, SERVICE_SUCCESS);
|
||||
} else
|
||||
service_enter_stop(s, SERVICE_FAILURE_RESOURCES);
|
||||
}
|
||||
}
|
||||
@ -3013,6 +2979,8 @@ static int service_start(Unit *u) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
s->result = SERVICE_SUCCESS;
|
||||
s->reload_result = SERVICE_SUCCESS;
|
||||
s->main_pid_known = false;
|
||||
s->main_pid_alien = false;
|
||||
s->forbid_restart = false;
|
||||
@ -3021,17 +2989,13 @@ static int service_start(Unit *u) {
|
||||
if (s->state != SERVICE_AUTO_RESTART_QUEUED)
|
||||
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_errno = 0;
|
||||
s->status_bus_error = mfree(s->status_bus_error);
|
||||
s->status_varlink_error = mfree(s->status_varlink_error);
|
||||
|
||||
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_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);
|
||||
}
|
||||
|
||||
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) {
|
||||
Service *s = ASSERT_PTR(SERVICE(u));
|
||||
|
||||
@ -3127,7 +3077,6 @@ static int service_stop(Unit *u) {
|
||||
case SERVICE_RELOAD:
|
||||
case SERVICE_RELOAD_SIGNAL:
|
||||
case SERVICE_RELOAD_NOTIFY:
|
||||
case SERVICE_RELOAD_POST:
|
||||
case SERVICE_STOP_WATCHDOG:
|
||||
/* If there's already something running we go directly into kill mode. */
|
||||
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));
|
||||
|
||||
s->reload_result = SERVICE_SUCCESS;
|
||||
|
||||
service_enter_refresh_extensions(s);
|
||||
service_enter_reload_mounting(s);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -3361,8 +3308,6 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) {
|
||||
|
||||
if (s->notify_access_override >= 0)
|
||||
(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);
|
||||
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);
|
||||
else
|
||||
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")) {
|
||||
r = safe_atou(value, &s->n_restarts);
|
||||
if (r < 0)
|
||||
@ -4180,11 +4115,10 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
|
||||
switch (s->state) {
|
||||
|
||||
case SERVICE_START_POST:
|
||||
case SERVICE_REFRESH_EXTENSIONS:
|
||||
case SERVICE_RELOAD:
|
||||
case SERVICE_RELOAD_SIGNAL:
|
||||
case SERVICE_RELOAD_NOTIFY:
|
||||
case SERVICE_RELOAD_POST:
|
||||
case SERVICE_REFRESH_EXTENSIONS:
|
||||
case SERVICE_MOUNTING:
|
||||
/* If neither main nor control processes are running then the current
|
||||
* 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,
|
||||
code, status);
|
||||
|
||||
if (!IN_SET(s->state, SERVICE_REFRESH_EXTENSIONS, SERVICE_RELOAD, SERVICE_RELOAD_POST, SERVICE_MOUNTING) &&
|
||||
s->result == SERVICE_SUCCESS)
|
||||
if (!IN_SET(s->state, SERVICE_RELOAD, SERVICE_MOUNTING) && s->result == SERVICE_SUCCESS)
|
||||
s->result = f;
|
||||
|
||||
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);
|
||||
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:
|
||||
if (f != SERVICE_SUCCESS) {
|
||||
service_reload_finish(s, f);
|
||||
break;
|
||||
}
|
||||
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);
|
||||
|
||||
if (service_load_pid_file(s, true) < 0)
|
||||
service_search_main_pid(s);
|
||||
s->reload_result = f;
|
||||
|
||||
service_enter_reload_signal(s);
|
||||
/* 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;
|
||||
|
||||
case SERVICE_RELOAD_POST:
|
||||
service_reload_finish(s, f);
|
||||
case SERVICE_REFRESH_EXTENSIONS:
|
||||
/* Remounting extensions asynchronously done, proceed to signal */
|
||||
service_enter_reload_signal_exec(s);
|
||||
break;
|
||||
|
||||
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);
|
||||
break;
|
||||
|
||||
case SERVICE_REFRESH_EXTENSIONS:
|
||||
case SERVICE_RELOAD:
|
||||
case SERVICE_RELOAD_SIGNAL:
|
||||
case SERVICE_RELOAD_NOTIFY:
|
||||
case SERVICE_RELOAD_POST:
|
||||
case SERVICE_REFRESH_EXTENSIONS:
|
||||
log_unit_warning(UNIT(s), "Reload operation timed out. Killing reload process.");
|
||||
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;
|
||||
|
||||
case SERVICE_MOUNTING:
|
||||
@ -4814,90 +4747,6 @@ finish:
|
||||
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(
|
||||
Unit *u,
|
||||
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));
|
||||
}
|
||||
|
||||
usec_t monotonic_usec = USEC_INFINITY;
|
||||
bool notify_dbus = false;
|
||||
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);
|
||||
if (r > 0 &&
|
||||
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) &&
|
||||
(!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= */
|
||||
e = strv_find_startswith(tags, "STATUS=");
|
||||
@ -5196,11 +5118,10 @@ static bool pick_up_pid_from_bus_name(Service *s) {
|
||||
SERVICE_START,
|
||||
SERVICE_START_POST,
|
||||
SERVICE_RUNNING,
|
||||
SERVICE_REFRESH_EXTENSIONS,
|
||||
SERVICE_RELOAD,
|
||||
SERVICE_RELOAD_SIGNAL,
|
||||
SERVICE_RELOAD_NOTIFY,
|
||||
SERVICE_RELOAD_POST,
|
||||
SERVICE_REFRESH_EXTENSIONS,
|
||||
SERVICE_MOUNTING);
|
||||
}
|
||||
|
||||
@ -5382,11 +5303,10 @@ static bool service_needs_console(Unit *u) {
|
||||
SERVICE_START,
|
||||
SERVICE_START_POST,
|
||||
SERVICE_RUNNING,
|
||||
SERVICE_REFRESH_EXTENSIONS,
|
||||
SERVICE_RELOAD,
|
||||
SERVICE_RELOAD_SIGNAL,
|
||||
SERVICE_RELOAD_NOTIFY,
|
||||
SERVICE_RELOAD_POST,
|
||||
SERVICE_REFRESH_EXTENSIONS,
|
||||
SERVICE_MOUNTING,
|
||||
SERVICE_STOP,
|
||||
SERVICE_STOP_WATCHDOG,
|
||||
@ -5819,36 +5739,34 @@ static const char* const service_exit_type_table[_SERVICE_EXIT_TYPE_MAX] = {
|
||||
DEFINE_STRING_TABLE_LOOKUP(service_exit_type, ServiceExitType);
|
||||
|
||||
static const char* const service_exec_command_table[_SERVICE_EXEC_COMMAND_MAX] = {
|
||||
[SERVICE_EXEC_CONDITION] = "ExecCondition",
|
||||
[SERVICE_EXEC_START_PRE] = "ExecStartPre",
|
||||
[SERVICE_EXEC_START] = "ExecStart",
|
||||
[SERVICE_EXEC_START_POST] = "ExecStartPost",
|
||||
[SERVICE_EXEC_RELOAD] = "ExecReload",
|
||||
[SERVICE_EXEC_RELOAD_POST] = "ExecReloadPost",
|
||||
[SERVICE_EXEC_STOP] = "ExecStop",
|
||||
[SERVICE_EXEC_STOP_POST] = "ExecStopPost",
|
||||
[SERVICE_EXEC_CONDITION] = "ExecCondition",
|
||||
[SERVICE_EXEC_START_PRE] = "ExecStartPre",
|
||||
[SERVICE_EXEC_START] = "ExecStart",
|
||||
[SERVICE_EXEC_START_POST] = "ExecStartPost",
|
||||
[SERVICE_EXEC_RELOAD] = "ExecReload",
|
||||
[SERVICE_EXEC_STOP] = "ExecStop",
|
||||
[SERVICE_EXEC_STOP_POST] = "ExecStopPost",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(service_exec_command, ServiceExecCommand);
|
||||
|
||||
static const char* const service_exec_ex_command_table[_SERVICE_EXEC_COMMAND_MAX] = {
|
||||
[SERVICE_EXEC_CONDITION] = "ExecConditionEx",
|
||||
[SERVICE_EXEC_START_PRE] = "ExecStartPreEx",
|
||||
[SERVICE_EXEC_START] = "ExecStartEx",
|
||||
[SERVICE_EXEC_START_POST] = "ExecStartPostEx",
|
||||
[SERVICE_EXEC_RELOAD] = "ExecReloadEx",
|
||||
[SERVICE_EXEC_RELOAD_POST] = "ExecReloadPostEx",
|
||||
[SERVICE_EXEC_STOP] = "ExecStopEx",
|
||||
[SERVICE_EXEC_STOP_POST] = "ExecStopPostEx",
|
||||
[SERVICE_EXEC_CONDITION] = "ExecConditionEx",
|
||||
[SERVICE_EXEC_START_PRE] = "ExecStartPreEx",
|
||||
[SERVICE_EXEC_START] = "ExecStartEx",
|
||||
[SERVICE_EXEC_START_POST] = "ExecStartPostEx",
|
||||
[SERVICE_EXEC_RELOAD] = "ExecReloadEx",
|
||||
[SERVICE_EXEC_STOP] = "ExecStopEx",
|
||||
[SERVICE_EXEC_STOP_POST] = "ExecStopPostEx",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(service_exec_ex_command, ServiceExecCommand);
|
||||
|
||||
static const char* const notify_state_table[_NOTIFY_STATE_MAX] = {
|
||||
[NOTIFY_READY] = "ready",
|
||||
[NOTIFY_RELOADING] = "reloading",
|
||||
[NOTIFY_RELOAD_READY] = "reload-ready",
|
||||
[NOTIFY_STOPPING] = "stopping",
|
||||
[NOTIFY_UNKNOWN] = "unknown",
|
||||
[NOTIFY_READY] = "ready",
|
||||
[NOTIFY_RELOADING] = "reloading",
|
||||
[NOTIFY_STOPPING] = "stopping",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(notify_state, NotifyState);
|
||||
|
||||
@ -46,7 +46,6 @@ typedef enum ServiceExecCommand {
|
||||
SERVICE_EXEC_START,
|
||||
SERVICE_EXEC_START_POST,
|
||||
SERVICE_EXEC_RELOAD,
|
||||
SERVICE_EXEC_RELOAD_POST,
|
||||
SERVICE_EXEC_STOP,
|
||||
SERVICE_EXEC_STOP_POST,
|
||||
_SERVICE_EXEC_COMMAND_MAX,
|
||||
@ -54,9 +53,9 @@ typedef enum ServiceExecCommand {
|
||||
} ServiceExecCommand;
|
||||
|
||||
typedef enum NotifyState {
|
||||
NOTIFY_UNKNOWN,
|
||||
NOTIFY_READY,
|
||||
NOTIFY_RELOADING,
|
||||
NOTIFY_RELOAD_READY,
|
||||
NOTIFY_STOPPING,
|
||||
_NOTIFY_STATE_MAX,
|
||||
_NOTIFY_STATE_INVALID = -EINVAL,
|
||||
@ -299,5 +298,7 @@ ServiceTimeoutFailureMode service_timeout_failure_mode_from_string(const char *s
|
||||
|
||||
DEFINE_CAST(SERVICE, Service);
|
||||
|
||||
#define STATUS_TEXT_MAX (16U*1024U)
|
||||
|
||||
/* Only exported for unit tests */
|
||||
int service_deserialize_exec_command(Unit *u, const char *key, const char *value);
|
||||
|
||||
@ -2148,6 +2148,8 @@ static void socket_enter_stop_post(Socket *s, SocketResult f) {
|
||||
s->control_command = s->exec_command[SOCKET_EXEC_STOP_POST];
|
||||
|
||||
if (s->control_command) {
|
||||
pidref_done(&s->control_pid);
|
||||
|
||||
r = socket_spawn(s, s->control_command, &s->control_pid);
|
||||
if (r < 0) {
|
||||
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];
|
||||
|
||||
if (s->control_command) {
|
||||
pidref_done(&s->control_pid);
|
||||
|
||||
r = socket_spawn(s, s->control_command, &s->control_pid);
|
||||
if (r < 0) {
|
||||
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];
|
||||
|
||||
if (s->control_command) {
|
||||
pidref_done(&s->control_pid);
|
||||
|
||||
r = socket_spawn(s, s->control_command, &s->control_pid);
|
||||
if (r < 0) {
|
||||
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];
|
||||
|
||||
if (s->control_command) {
|
||||
pidref_done(&s->control_pid);
|
||||
|
||||
r = socket_spawn(s, s->control_command, &s->control_pid);
|
||||
if (r < 0) {
|
||||
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;
|
||||
|
||||
pidref_done(&s->control_pid);
|
||||
|
||||
r = socket_spawn(s, s->control_command, &s->control_pid);
|
||||
if (r < 0) {
|
||||
log_unit_warning_errno(UNIT(s), r, "Failed to spawn next task: %m");
|
||||
|
||||
@ -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_19(X, ...) case X: CASE_F_18( __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(...) \
|
||||
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, \
|
||||
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) \
|
||||
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_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__)
|
||||
|
||||
#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) \
|
||||
* 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__ }; \
|
||||
assert_cc(ELEMENTSOF(__assert_in_set) <= 21); \
|
||||
assert_cc(ELEMENTSOF(__assert_in_set) <= 20); \
|
||||
switch (x) { \
|
||||
FOR_EACH_MAKE_CASE(first, __VA_ARGS__) \
|
||||
_found = true; \
|
||||
|
||||
@ -3453,8 +3453,10 @@ _public_ int sd_json_parse_file_at(
|
||||
|
||||
if (f)
|
||||
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);
|
||||
else
|
||||
return -EINVAL;
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
||||
@ -2649,8 +2649,6 @@ static const BusProperty service_properties[] = {
|
||||
{ "ExecStartPostEx", bus_append_exec_command }, /* compat */
|
||||
{ "ExecReload", bus_append_exec_command },
|
||||
{ "ExecReloadEx", bus_append_exec_command }, /* compat */
|
||||
{ "ExecReloadPost", bus_append_exec_command },
|
||||
{ "ExecReloadPostEx", bus_append_exec_command }, /* compat */
|
||||
{ "ExecStop", bus_append_exec_command },
|
||||
{ "ExecStopEx", bus_append_exec_command }, /* compat */
|
||||
{ "ExecStopPost", bus_append_exec_command },
|
||||
|
||||
@ -619,7 +619,6 @@ static int image_make(
|
||||
static int pick_image_search_path(
|
||||
RuntimeScope scope,
|
||||
ImageClass class,
|
||||
const char *root,
|
||||
char ***ret) {
|
||||
|
||||
int r;
|
||||
@ -636,11 +635,11 @@ static int pick_image_search_path(
|
||||
if (scope < 0) {
|
||||
_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)
|
||||
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)
|
||||
return r;
|
||||
|
||||
@ -656,15 +655,8 @@ static int pick_image_search_path(
|
||||
|
||||
case RUNTIME_SCOPE_SYSTEM: {
|
||||
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 */
|
||||
ns = is_initrd && image_search_path_initrd[class] ?
|
||||
ns = in_initrd() && image_search_path_initrd[class] ?
|
||||
image_search_path_initrd[class] :
|
||||
image_search_path[class];
|
||||
if (!ns)
|
||||
@ -771,7 +763,7 @@ int image_find(RuntimeScope scope,
|
||||
return -ENOMEM;
|
||||
|
||||
_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)
|
||||
return r;
|
||||
|
||||
@ -962,7 +954,7 @@ int image_discover(
|
||||
assert(images);
|
||||
|
||||
_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)
|
||||
return r;
|
||||
|
||||
@ -2109,7 +2101,7 @@ bool image_in_search_path(
|
||||
assert(image);
|
||||
|
||||
_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)
|
||||
return r;
|
||||
|
||||
|
||||
@ -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
|
||||
* 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.)
|
||||
* With --root= we default to the regular policy, though. (To change that, the check would need
|
||||
* to prepend (or cut away) arg_root.) */
|
||||
* other directories we assume the appropriate level of trust was already established already. */
|
||||
|
||||
if (in_initrd() && !arg_root) {
|
||||
if (in_initrd()) {
|
||||
if (path_startswith(img->path, "/.extra/sysext/"))
|
||||
return &image_policy_sysext_strict;
|
||||
if (path_startswith(img->path, "/.extra/global_sysext/"))
|
||||
@ -1907,19 +1905,13 @@ static int merge_subprocess(
|
||||
if (force)
|
||||
log_debug("Force mode enabled, skipping version validation.");
|
||||
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(
|
||||
img->name,
|
||||
host_os_release_id,
|
||||
host_os_release_id_like,
|
||||
host_os_release_version_id,
|
||||
host_os_release_api_level,
|
||||
is_initrd ? "initrd" : "system",
|
||||
in_initrd() ? "initrd" : "system",
|
||||
image_extension_release(img, image_class),
|
||||
image_class);
|
||||
if (r < 0)
|
||||
|
||||
@ -95,28 +95,8 @@ static int parse_shutdown_time_spec(const char *t, usec_t *ret) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (s <= n) {
|
||||
/* The specified time is today, but in the past. We need to schedule it for tomorrow
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
while (s <= n)
|
||||
s += USEC_PER_DAY;
|
||||
|
||||
*ret = s;
|
||||
}
|
||||
|
||||
@ -2284,8 +2284,6 @@ static int show_one(
|
||||
{ "ExecStartPostEx", "a(sasasttttuii)", map_exec, 0 },
|
||||
{ "ExecReload", "a(sasbttttuii)", 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 },
|
||||
{ "ExecStop", "a(sasbttttuii)", map_exec, 0 },
|
||||
{ "ExecStopEx", "a(sasasttttuii)", map_exec, 0 },
|
||||
|
||||
@ -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) {
|
||||
_cleanup_close_ int fd = ASSERT_FD(_fd); /* Take ownership of the passed fd */
|
||||
_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;
|
||||
int r;
|
||||
|
||||
@ -238,10 +240,16 @@ static int job_parse_child_output(int _fd, sd_json_variant **ret) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_json_parse_file_at(/* f = */ NULL, fd, /* path = */ NULL, /* flags = */ 0,
|
||||
&v, /* reterr_line = */ NULL, /* reterr_column = */ NULL);
|
||||
if (lseek(fd, SEEK_SET, 0) == (off_t) -1)
|
||||
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)
|
||||
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);
|
||||
return 0;
|
||||
|
||||
@ -1,4 +0,0 @@
|
||||
[Service]
|
||||
Type=notify-reload
|
||||
TimeoutStartSec=40
|
||||
ExecStart=/usr/lib/systemd/tests/testdata/TEST-80-NOTIFYACCESS.units/reload-timeout.sh
|
||||
@ -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
|
||||
@ -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
|
||||
# when sharing is disabled
|
||||
set +o pipefail
|
||||
# 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"
|
||||
d=""
|
||||
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")"
|
||||
test $((n_before + 1)) -eq "$(dmsetup ls | grep loop | grep -c verity || true)"
|
||||
umount -R "$IMAGE_DIR/mount"
|
||||
timeout 60 bash -c "while test -e $d; do sleep 0.1; done"
|
||||
( ! dmsetup ls | grep -q "$(basename "$d")")
|
||||
test "$n_before" -eq "$(dmsetup ls | grep loop | grep -c verity || true)"
|
||||
set -o pipefail
|
||||
|
||||
# Test BindLogSockets=
|
||||
systemd-run --wait -p RootImage="$MINIMAL_IMAGE.raw" mountpoint /run/systemd/journal/socket
|
||||
|
||||
@ -1130,13 +1130,10 @@ extension_verify_after_unmerge "$fake_root" "$hierarchy" -h
|
||||
fake_root=${roots_dir:+"$roots_dir/mutable-directory-with-invalid-permissions"}
|
||||
hierarchy=/opt
|
||||
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_extension_image "$fake_root" "$hierarchy"
|
||||
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"
|
||||
|
||||
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)
|
||||
)
|
||||
|
||||
( 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
|
||||
|
||||
|
||||
|
||||
@ -868,8 +868,8 @@ EOF
|
||||
for ((i = 0; i < ${#devices[@]}; i++)); do
|
||||
# Intentionally use weaker cipher-related settings, since we don't care
|
||||
# about security here as it's a throwaway LUKS partition
|
||||
SYSTEMD_LOG_LEVEL=debug udevadm lock --timeout=30 --device="${devices[$i]}" \
|
||||
cryptsetup luksFormat -q --debug \
|
||||
udevadm lock --timeout=30 --device="${devices[$i]}" \
|
||||
cryptsetup luksFormat -q \
|
||||
--use-urandom --pbkdf pbkdf2 --pbkdf-force-iterations 1000 \
|
||||
--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"
|
||||
|
||||
@ -81,11 +81,6 @@ systemd-run --wait --pipe --user --machine=testuser@ \
|
||||
systemd-run --wait --pipe --user --machine=testuser@ \
|
||||
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
|
||||
# don't have unprivileged user namespaces.
|
||||
if [[ "$(sysctl -ne kernel.apparmor_restrict_unprivileged_userns)" -ne 1 ]]; then
|
||||
|
||||
@ -62,33 +62,6 @@ assert_eq "$(systemctl show notify.service -p NotifyAccess --value)" "none"
|
||||
systemctl stop notify.service
|
||||
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
|
||||
|
||||
# Explicitly test busctl's BUSERROR= reporting and systemctl status should show it
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user