As it says on the tin, configures the unit to survive a soft reboot.
Currently all the following options have to be set by hand:
Conflicts=reboot.target kexec.target poweroff.target halt.target
Before=reboot.target kexec.target poweroff.target halt.target
After=sysinit.target basic.target
DefaultDependencies=no
IgnoreOnIsolate=yes
This is not very user friendly. If new default dependencies are added,
or new shutdown/reboot types, they also have to be added manually.
The new option is much simpler, easy to find, and does the right thing
by default.
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly b DefaultDependencies = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
+ readonly b IgnoreOnSoftReboot = ...;
+ @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s OnSuccessJobMode = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s OnFailureJobMode = '...';
<!--property CanFreeze is not documented!-->
+ <!--property IgnoreOnSoftReboot is not documented!-->
+
<!--property OnSuccessJobMode is not documented!-->
<!--property OnFailureJobMode is not documented!-->
<variablelist class="dbus-property" generated="True" extra-ref="DefaultDependencies"/>
+ <variablelist class="dbus-property" generated="True" extra-ref="IgnoreOnSoftReboot"/>
+
<variablelist class="dbus-property" generated="True" extra-ref="OnSuccessJobMode"/>
<variablelist class="dbus-property" generated="True" extra-ref="OnFailureJobMode"/>
otherwise the old root filesystem will be kept in memory as long as the unit is running.</para>
<para>If units shall be left running until the very end of shutdown during a soft reboot operation, but
- shall be terminated regularly during other forms of shutdown, it's recommended to set
- <varname>DefaultDependencies=no</varname> and then place
- <varname>Conflicts=</varname>/<varname>Before=</varname> onto <filename>reboot.target</filename>,
- <filename>kexec.target</filename>, <filename>poweroff.target</filename> and
- <filename>halt.target</filename> (but <emphasis>not</emphasis> onto
- <filename>soft-reboot.target</filename>).</para>
+ shall be terminated regularly during other forms of shutdown, <varname>IgnoreOnSoftReboot=yes</varname>
+ can be set. This will ensure that soft reboot operations do not affect it, but other types of reboot
+ or shutdown stop it as expected.</para>
</refsect1>
<refsect1>
ones.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>IgnoreOnSoftReboot=</varname></term>
+
+ <listitem><para>Takes a boolean argument. Defaults to <option>no</option>. If <option>yes</option>,
+ the unit will be configured to survive a soft reboot operation (see:
+ <citerefentry><refentrytitle>systemd-soft-reboot.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>).
+ This will ensure the unit is stopped normally during reboot or shutdown operations, but it survives
+ a soft reboot by not being stopped on the way down or on the way back up.</para></listitem>
+ </varlistentry>
+
<varlistentry>
<term><varname>CollectMode=</varname></term>
SD_BUS_PROPERTY("RefuseManualStop", "b", bus_property_get_bool, offsetof(Unit, refuse_manual_stop), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("AllowIsolate", "b", bus_property_get_bool, offsetof(Unit, allow_isolate), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("DefaultDependencies", "b", bus_property_get_bool, offsetof(Unit, default_dependencies), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("IgnoreOnSoftReboot", "b", bus_property_get_bool, offsetof(Unit, ignore_on_soft_reboot), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("OnSuccesJobMode", "s", property_get_job_mode, offsetof(Unit, on_success_job_mode), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN), /* deprecated */
SD_BUS_PROPERTY("OnSuccessJobMode", "s", property_get_job_mode, offsetof(Unit, on_success_job_mode), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("OnFailureJobMode", "s", property_get_job_mode, offsetof(Unit, on_failure_job_mode), SD_BUS_VTABLE_PROPERTY_CONST),
if (streq(name, "DefaultDependencies"))
return bus_set_transient_bool(u, name, &u->default_dependencies, message, flags, error);
+ if (streq(name, "IgnoreOnSoftReboot"))
+ return bus_set_transient_bool(u, name, &u->ignore_on_soft_reboot, message, flags, error);
+
if (streq(name, "OnSuccessJobMode"))
return bus_set_transient_job_mode(u, name, &u->on_success_job_mode, message, flags, error);
Unit.RefuseManualStop, config_parse_bool, 0, offsetof(Unit, refuse_manual_stop)
Unit.AllowIsolate, config_parse_bool, 0, offsetof(Unit, allow_isolate)
Unit.DefaultDependencies, config_parse_bool, 0, offsetof(Unit, default_dependencies)
+Unit.IgnoreOnSoftReboot, config_parse_bool, 0, offsetof(Unit, ignore_on_soft_reboot)
Unit.OnSuccessJobMode, config_parse_job_mode, 0, offsetof(Unit, on_success_job_mode)
Unit.OnFailureJobMode, config_parse_job_mode, 0, offsetof(Unit, on_failure_job_mode)
{# The following is a legacy alias name for compatibility #}
return r;
if (MANAGER_IS_SYSTEM(UNIT(p)->manager)) {
- r = unit_add_two_dependencies_by_name(UNIT(p), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
+ r = unit_add_two_dependencies_by_name(UNIT(p),
+ UNIT_AFTER,
+ UNIT(p)->ignore_on_soft_reboot ? -EINVAL : UNIT_REQUIRES,
+ SPECIAL_SYSINIT_TARGET,
+ true,
+ UNIT_DEPENDENCY_DEFAULT);
if (r < 0)
return r;
}
- return unit_add_two_dependencies_by_name(UNIT(p), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
+ if (!UNIT(p)->ignore_on_soft_reboot)
+ return unit_add_two_dependencies_by_name(
+ UNIT(p),
+ UNIT_BEFORE, UNIT_CONFLICTS,
+ SPECIAL_SHUTDOWN_TARGET, true,
+ UNIT_DEPENDENCY_DEFAULT);
+
+ return unit_add_dependencies_on_real_shutdown_targets(UNIT(p));
}
static int path_add_trigger_dependencies(Path *p) {
}
static int scope_add_default_dependencies(Scope *s) {
- int r;
-
assert(s);
if (!UNIT(s)->default_dependencies)
return 0;
/* Make sure scopes are unloaded on shutdown */
- r = unit_add_two_dependencies_by_name(
- UNIT(s),
- UNIT_BEFORE, UNIT_CONFLICTS,
- SPECIAL_SHUTDOWN_TARGET, true,
- UNIT_DEPENDENCY_DEFAULT);
- if (r < 0)
- return r;
+ if (!UNIT(s)->ignore_on_soft_reboot)
+ return unit_add_two_dependencies_by_name(
+ UNIT(s),
+ UNIT_BEFORE, UNIT_CONFLICTS,
+ SPECIAL_SHUTDOWN_TARGET, true,
+ UNIT_DEPENDENCY_DEFAULT);
- return 0;
+ /* Unless we are meant to survive soft reboot, in which case we need to conflict with
+ * non-soft-reboot targets. */
+ return unit_add_dependencies_on_real_shutdown_targets(UNIT(s));
}
static int scope_verify(Scope *s) {
* majority of services. */
if (MANAGER_IS_SYSTEM(UNIT(s)->manager)) {
- /* First, pull in the really early boot stuff, and
- * require it, so that we fail if we can't acquire
- * it. */
-
- r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
+ /* First, pull in the really early boot stuff, and require it, so that we fail if we can't
+ * acquire it. But only add ordering if this is meant to survive a soft reboot, otherwise
+ * it will be pulled down. */
+
+ r = unit_add_two_dependencies_by_name(UNIT(s),
+ UNIT_AFTER,
+ UNIT(s)->ignore_on_soft_reboot ? -EINVAL : UNIT_REQUIRES,
+ SPECIAL_SYSINIT_TARGET,
+ true,
+ UNIT_DEPENDENCY_DEFAULT);
if (r < 0)
return r;
} else {
return r;
/* Third, add us in for normal shutdown. */
- return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
+ if (!UNIT(s)->ignore_on_soft_reboot)
+ return unit_add_two_dependencies_by_name(UNIT(s),
+ UNIT_BEFORE,
+ UNIT_CONFLICTS,
+ SPECIAL_SHUTDOWN_TARGET,
+ true,
+ UNIT_DEPENDENCY_DEFAULT);
+
+ /* Unless we are meant to survive soft reboot, in which case we need to conflict with
+ * non-soft-reboot targets. */
+ return unit_add_dependencies_on_real_shutdown_targets(UNIT(s));
}
static void service_fix_stdio(Service *s) {
}
static int slice_add_default_dependencies(Slice *s) {
- int r;
-
assert(s);
if (!UNIT(s)->default_dependencies)
return 0;
/* Make sure slices are unloaded on shutdown */
- r = unit_add_two_dependencies_by_name(
- UNIT(s),
- UNIT_BEFORE, UNIT_CONFLICTS,
- SPECIAL_SHUTDOWN_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
- if (r < 0)
- return r;
-
- return 0;
+ if (!UNIT(s)->ignore_on_soft_reboot)
+ return unit_add_two_dependencies_by_name(
+ UNIT(s),
+ UNIT_BEFORE, UNIT_CONFLICTS,
+ SPECIAL_SHUTDOWN_TARGET, true,
+ UNIT_DEPENDENCY_DEFAULT);
+
+ /* Unless we are meant to survive soft reboot, in which case we need to conflict with
+ * non-soft-reboot targets. */
+ return unit_add_dependencies_on_real_shutdown_targets(UNIT(s));
}
static int slice_verify(Slice *s) {
return r;
if (MANAGER_IS_SYSTEM(UNIT(s)->manager)) {
- r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
+ r = unit_add_two_dependencies_by_name(UNIT(s),
+ UNIT_AFTER,
+ UNIT(s)->ignore_on_soft_reboot ? -EINVAL : UNIT_REQUIRES,
+ SPECIAL_SYSINIT_TARGET,
+ true,
+ UNIT_DEPENDENCY_DEFAULT);
if (r < 0)
return r;
}
- return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
+ if (!UNIT(s)->ignore_on_soft_reboot)
+ return unit_add_two_dependencies_by_name(
+ UNIT(s),
+ UNIT_BEFORE, UNIT_CONFLICTS,
+ SPECIAL_SHUTDOWN_TARGET, true,
+ UNIT_DEPENDENCY_DEFAULT);
+
+ return unit_add_dependencies_on_real_shutdown_targets(UNIT(s));
}
_pure_ static bool socket_has_exec(Socket *s) {
return 0;
/* Make sure targets are unloaded on shutdown */
- return unit_add_two_dependencies_by_name(UNIT(t), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
+ if (!UNIT(t)->ignore_on_soft_reboot)
+ return unit_add_two_dependencies_by_name(
+ UNIT(t),
+ UNIT_BEFORE, UNIT_CONFLICTS,
+ SPECIAL_SHUTDOWN_TARGET, true,
+ UNIT_DEPENDENCY_DEFAULT);
+
+ /* Unless we are meant to survive soft reboot, in which case we need to conflict with
+ * non-soft-reboot targets. */
+ return unit_add_dependencies_on_real_shutdown_targets(UNIT(t));
}
static int target_load(Unit *u) {
return r;
if (MANAGER_IS_SYSTEM(UNIT(t)->manager)) {
- r = unit_add_two_dependencies_by_name(UNIT(t), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
+ r = unit_add_two_dependencies_by_name(UNIT(t),
+ UNIT_AFTER,
+ UNIT(t)->ignore_on_soft_reboot ? -EINVAL : UNIT_REQUIRES,
+ SPECIAL_SYSINIT_TARGET,
+ true,
+ UNIT_DEPENDENCY_DEFAULT);
if (r < 0)
return r;
}
}
- return unit_add_two_dependencies_by_name(UNIT(t), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
+ if (!UNIT(t)->ignore_on_soft_reboot)
+ return unit_add_two_dependencies_by_name(
+ UNIT(t),
+ UNIT_BEFORE, UNIT_CONFLICTS,
+ SPECIAL_SHUTDOWN_TARGET, true,
+ UNIT_DEPENDENCY_DEFAULT);
+
+ return unit_add_dependencies_on_real_shutdown_targets(UNIT(t));
}
static int timer_add_trigger_dependencies(Timer *t) {
HASHMAP_FOREACH(j, m->jobs) {
assert(j->installed);
- if (j->unit->ignore_on_isolate)
+ if (j->unit->ignore_on_isolate || j->unit->ignore_on_soft_reboot)
continue;
if (hashmap_contains(tr->jobs, j->unit))
if (u->ignore_on_isolate)
return false;
+ if (u->ignore_on_soft_reboot)
+ return false;
+
/* Is there already something listed for this? */
if (hashmap_contains(tr->jobs, u))
return false;
"%s\tRefuseManualStart: %s\n"
"%s\tRefuseManualStop: %s\n"
"%s\tDefaultDependencies: %s\n"
+ "%s\tIgnoreOnSoftReboot: %s\n"
"%s\tOnSuccessJobMode: %s\n"
"%s\tOnFailureJobMode: %s\n"
"%s\tIgnoreOnIsolate: %s\n",
prefix, yes_no(u->refuse_manual_start),
prefix, yes_no(u->refuse_manual_stop),
prefix, yes_no(u->default_dependencies),
+ prefix, yes_no(u->ignore_on_soft_reboot),
prefix, job_mode_to_string(u->on_success_job_mode),
prefix, job_mode_to_string(u->on_failure_job_mode),
prefix, yes_no(u->ignore_on_isolate));
}
int unit_add_two_dependencies(Unit *u, UnitDependency d, UnitDependency e, Unit *other, bool add_reference, UnitDependencyMask mask) {
- int r, s;
+ int r = 0, s = 0;
assert(u);
+ assert(d >= 0 || e >= 0);
- r = unit_add_dependency(u, d, other, add_reference, mask);
- if (r < 0)
- return r;
+ if (d >= 0) {
+ r = unit_add_dependency(u, d, other, add_reference, mask);
+ if (r < 0)
+ return r;
+ }
- s = unit_add_dependency(u, e, other, add_reference, mask);
- if (s < 0)
- return s;
+ if (e >= 0) {
+ s = unit_add_dependency(u, e, other, add_reference, mask);
+ if (s < 0)
+ return s;
+ }
return r > 0 || s > 0;
}
+int unit_add_dependencies_on_real_shutdown_targets(Unit *u) {
+ int r;
+
+ assert(u);
+
+ STRV_FOREACH(target, STRV_MAKE(SPECIAL_REBOOT_TARGET,
+ SPECIAL_KEXEC_TARGET,
+ SPECIAL_HALT_TARGET,
+ SPECIAL_POWEROFF_TARGET)) {
+ r = unit_add_two_dependencies_by_name(u,
+ UNIT_BEFORE,
+ UNIT_CONFLICTS,
+ *target,
+ /* add_reference= */ true,
+ UNIT_DEPENDENCY_DEFAULT);
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
+}
+
static int resolve_template(Unit *u, const char *name, char **buf, const char **ret) {
int r;
/* Create default dependencies */
bool default_dependencies;
+ /* Configure so that the unit survives a soft reboot without stopping/starting. */
+ bool ignore_on_soft_reboot;
+
/* Refuse manual starting, allow starting only indirectly via dependency. */
bool refuse_manual_start;
int unit_add_two_dependencies_by_name(Unit *u, UnitDependency d, UnitDependency e, const char *name, bool add_reference, UnitDependencyMask mask);
int unit_add_exec_dependencies(Unit *u, ExecContext *c);
+/* Helper for IgnoreOnSoftReboot units that need to survive soft-reboot.target but not others */
+int unit_add_dependencies_on_real_shutdown_targets(Unit *u);
int unit_choose_id(Unit *u, const char *name);
int unit_set_description(Unit *u, const char *description);
"RefuseManualStop",
"AllowIsolate",
"IgnoreOnIsolate",
+ "IgnoreOnSoftReboot",
"DefaultDependencies"))
return bus_append_parse_boolean(m, field, eq);
exec sleep infinity
EOF
chmod +x "$T"
- # This sets DefaultDependencies=no so that it remains running until the
- # very end, and IgnoreOnIsolate=yes so that it isn't stopped via the
- # "testsuite.target" isolation we do on next boot
- systemd-run -p Type=notify -p DefaultDependencies=no -p IgnoreOnIsolate=yes --unit=testsuite-82-survive.service "$T"
- systemd-run -p Type=exec -p DefaultDependencies=no -p IgnoreOnIsolate=yes --unit=testsuite-82-nosurvive.service sleep infinity
+ # Configure this transient unit to survive the soft reboot - it will not conflict with shutdown.target
+ # and it will be ignored on the isolate that happens in the next boot.
+ systemd-run -p Type=notify -p IgnoreOnSoftReboot=yes --unit=testsuite-82-survive.service "$T"
+ systemd-run -p Type=exec -p IgnoreOnSoftReboot=yes --unit=testsuite-82-nosurvive.service sleep infinity
# Now issue the soft reboot. We should be right back soon.
touch /run/testsuite82.touch