mirror of
https://github.com/systemd/systemd.git
synced 2025-03-08 08:58:27 +03:00
Merge pull request #27435 from poettering/renew-reboot
pid1: add a new method of rebooting: userspace only under the name "soft-reboot"
This commit is contained in:
commit
4d824ac0d3
9
TODO
9
TODO
@ -153,6 +153,10 @@ Features:
|
||||
dont), of sd-stub and data supplied by user. Then measure sbat too in
|
||||
sd-stub, explicitly.
|
||||
|
||||
* figure out what to do about credentials sealed to PCRs in kexec + soft-reboot
|
||||
scenarios. Maybe insist sealing is done additionally against some keypair in
|
||||
the TPM to which access is updated on each boot, for the next, or so?
|
||||
|
||||
* open up creds for uses in generators, and document clearly that encrypted
|
||||
creds are only supported if strictly tpm bound, but not when using the host
|
||||
secret (as that is only avilable if /var/ is around.
|
||||
@ -162,6 +166,11 @@ Features:
|
||||
idea, and specifically works around the fact the autofs ignores busy by mount
|
||||
namespaces)
|
||||
|
||||
* refuse using the switch-root operation without /etc/initrd-release. Now
|
||||
that we have a concept of userspace reboot, we can clearly say: switch-root
|
||||
is for transitioning from initrd to host (or initrd to next initrd), while
|
||||
userspace reboot is for switching host to next version of the host.
|
||||
|
||||
* mount most file systems with a restrictive uidmap. e.g. mount /usr/ with a
|
||||
uidmap that blocks out anything outside 0…1000 (i.e. system users) and similar.
|
||||
|
||||
|
@ -576,16 +576,15 @@ node /org/freedesktop/login1 {
|
||||
|
||||
<para><function>PowerOff()</function>, <function>Reboot()</function>, <function>Halt()</function>,
|
||||
<function>Suspend()</function>, and <function>Hibernate()</function> result in the system being powered
|
||||
off, rebooted, halted (shut down without turning off power), suspended (the system state is
|
||||
saved to RAM and the CPU is turned off), or hibernated (the system state is saved to disk and
|
||||
the machine is powered down). <function>HybridSleep()</function> results in the system entering a
|
||||
hybrid-sleep mode, i.e. the system is both hibernated and suspended.
|
||||
<function>SuspendThenHibernate()</function> results in the system being suspended, then later woken
|
||||
using an RTC timer and hibernated. The only argument is the polkit interactivity boolean
|
||||
<varname>interactive</varname> (see below). The main purpose of these calls is that they enforce
|
||||
polkit policy and hence allow powering off/rebooting/suspending/hibernating even by unprivileged
|
||||
users. They also enforce inhibition locks for non-privileged users. UIs should expose these calls
|
||||
as the primary mechanism to poweroff/reboot/suspend/hibernate the machine. Methods
|
||||
off, rebooted, halted (shut down without turning off power), suspended (the system state is saved to
|
||||
RAM and the CPU is turned off), or hibernated (the system state is saved to disk and the machine is
|
||||
powered down). <function>HybridSleep()</function> results in the system entering a hybrid-sleep mode,
|
||||
i.e. the system is both hibernated and suspended. <function>SuspendThenHibernate()</function> results
|
||||
in the system being suspended, then later woken using an RTC timer and hibernated. The only argument is
|
||||
the polkit interactivity boolean <varname>interactive</varname> (see below). The main purpose of these
|
||||
calls is that they enforce polkit policy and hence allow powering off/rebooting/suspending/hibernating
|
||||
even by unprivileged users. They also enforce inhibition locks for non-privileged users. UIs should
|
||||
expose these calls as the primary mechanism to poweroff/reboot/suspend/hibernate the machine. Methods
|
||||
<function>PowerOffWithFlags()</function>, <function>RebootWithFlags()</function>,
|
||||
<function>HaltWithFlags()</function>, <function>SuspendWithFlags()</function>,
|
||||
<function>HibernateWithFlags()</function>, <function>HybridSleepWithFlags()</function> and
|
||||
@ -594,12 +593,14 @@ node /org/freedesktop/login1 {
|
||||
<programlisting>
|
||||
#define SD_LOGIND_ROOT_CHECK_INHIBITORS (UINT64_C(1) << 0)
|
||||
#define SD_LOGIND_KEXEC_REBOOT (UINT64_C(1) << 1)
|
||||
#define SD_LOGIND_SOFT_REBOOT (UINT64_C(1) << 2)
|
||||
</programlisting>
|
||||
<para> When the <varname>flags</varname> is 0 then these methods behave just like the versions
|
||||
without flags. When <constant>SD_LOGIND_ROOT_CHECK_INHIBITORS</constant> (0x01) is set, active
|
||||
inhibitors are honoured for privileged users too. When <constant>SD_LOGIND_KEXEC_REBOOT</constant>
|
||||
(0x02) is set, then <function>RebootWithFlags()</function> perform kexec reboot if kexec
|
||||
kernel is loaded.</para>
|
||||
<para>When the <varname>flags</varname> is 0 then these methods behave just like the versions without
|
||||
flags. When <constant>SD_LOGIND_ROOT_CHECK_INHIBITORS</constant> (0x01) is set, active inhibitors are
|
||||
honoured for privileged users too. When <constant>SD_LOGIND_KEXEC_REBOOT</constant> (0x02) is set, then
|
||||
<function>RebootWithFlags()</function> performs a kexec reboot if kexec kernel is loaded. When
|
||||
<constant>SD_LOGIND_SOFT_REBOOT</constant> (0x04) is set, then <function>RebootWithFlags()</function>
|
||||
performs a userspace reboot only.</para>
|
||||
|
||||
<para><function>SetRebootParameter()</function> sets a parameter for a subsequent reboot operation.
|
||||
See the description of <command>reboot</command> in
|
||||
|
@ -183,6 +183,8 @@ node /org/freedesktop/systemd1 {
|
||||
@org.freedesktop.systemd1.Privileged("true")
|
||||
Reboot();
|
||||
@org.freedesktop.systemd1.Privileged("true")
|
||||
SoftReboot(in s new_root);
|
||||
@org.freedesktop.systemd1.Privileged("true")
|
||||
PowerOff();
|
||||
@org.freedesktop.systemd1.Privileged("true")
|
||||
Halt();
|
||||
@ -912,6 +914,8 @@ node /org/freedesktop/systemd1 {
|
||||
|
||||
<variablelist class="dbus-method" generated="True" extra-ref="Reboot()"/>
|
||||
|
||||
<variablelist class="dbus-method" generated="True" extra-ref="SoftReboot()"/>
|
||||
|
||||
<variablelist class="dbus-method" generated="True" extra-ref="PowerOff()"/>
|
||||
|
||||
<variablelist class="dbus-method" generated="True" extra-ref="Halt()"/>
|
||||
@ -1415,15 +1419,18 @@ node /org/freedesktop/systemd1 {
|
||||
<para><function>Exit()</function> may be invoked to ask the manager to exit. This is not available for
|
||||
the system manager and is useful only for user session managers.</para>
|
||||
|
||||
<para><function>Reboot()</function>, <function>PowerOff()</function>, <function>Halt()</function>, or
|
||||
<function>KExec()</function> may be used to ask for immediate reboot, powering down, halt or kexec
|
||||
based reboot of the system. Note that this does not shut down any services and immediately transitions
|
||||
into the reboot process. These functions are normally only called as the last step of shutdown and should
|
||||
not be called directly. To shut down the machine, it is generally a better idea to invoke
|
||||
<function>Reboot()</function> or <function>PowerOff()</function> on the
|
||||
<para><function>Reboot()</function>, <function>PowerOff()</function>, <function>Halt()</function>,
|
||||
<function>KExec()</function> and <function>SoftReboot()</function> may be used to ask for immediate
|
||||
reboot, powering down, halt, kexec based reboot, or soft reboot of the system. Note that this does not
|
||||
shut down any services and immediately transitions into the later shutdown operation. These functions
|
||||
are normally only called as the last step of shutdown and should not be called directly. To shut down
|
||||
the machine, it is generally a better idea to invoke <function>Reboot()</function>,
|
||||
<function>RebootWithFlags()</function> or <function>PowerOff()</function> on the
|
||||
<filename>systemd-logind</filename> manager object; see
|
||||
<citerefentry><refentrytitle>org.freedesktop.login1</refentrytitle><manvolnum>5</manvolnum></citerefentry>
|
||||
for more information.</para>
|
||||
for more information. <function>SoftReboot()</function> accepts an argument indicating the path for the
|
||||
root file system to activate for the next boot cycle. If an empty string is specified the
|
||||
<filename>/run/nextroot/</filename> path is used if it exists.</para>
|
||||
|
||||
<para><function>SwitchRoot()</function> may be used to transition to a new root directory. This is
|
||||
intended to be used in the initrd, and also to transition from the host system into a shutdown initrd.
|
||||
|
@ -1036,6 +1036,7 @@ manpages = [
|
||||
['systemd-sleep.conf', '5', ['sleep.conf.d'], ''],
|
||||
['systemd-socket-activate', '1', [], ''],
|
||||
['systemd-socket-proxyd', '8', [], ''],
|
||||
['systemd-soft-reboot.service', '8', [], ''],
|
||||
['systemd-stdio-bridge', '1', [], ''],
|
||||
['systemd-stub',
|
||||
'7',
|
||||
|
@ -1559,6 +1559,24 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><command>soft-reboot</command></term>
|
||||
|
||||
<listitem>
|
||||
<para>Shut down and reboot userspace. This is equivalent to <command>systemctl start
|
||||
soft-reboot.target --job-mode=replace-irreversibly --no-block</command>. This command is
|
||||
asynchronous; it will return after the reboot operation is enqueued, without waiting for it to
|
||||
complete.</para>
|
||||
|
||||
<para>This command honors <option>--force</option> and <option>--when=</option> in a similar way
|
||||
as <command>halt</command>.</para>
|
||||
|
||||
<para>This operation only reboots userspace, leaving the kernel running. See
|
||||
<citerefentry><refentrytitle>systemd-soft-reboot.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||
for details.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><command>exit</command> <optional><replaceable>EXIT_CODE</replaceable></optional></term>
|
||||
|
||||
|
@ -68,6 +68,10 @@
|
||||
<para>Note that <filename>systemd-poweroff.service</filename> (and the related units) should never be
|
||||
executed directly. Instead, trigger system shutdown with a command such as <literal>systemctl
|
||||
poweroff</literal>.</para>
|
||||
|
||||
<para>Another form of shutdown is provided by the
|
||||
<citerefentry><refentrytitle>systemd-soft-reboot.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||
functionality. It reboots only the OS userspace, leaving the kernel, firmware, and hardware as it is.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
@ -78,6 +82,7 @@
|
||||
<citerefentry><refentrytitle>systemd.special</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>reboot</refentrytitle><manvolnum>2</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>systemd-suspend.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>systemd-soft-reboot.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>bootup</refentrytitle><manvolnum>7</manvolnum></citerefentry>
|
||||
</para>
|
||||
</refsect1>
|
||||
|
158
man/systemd-soft-reboot.service.xml
Normal file
158
man/systemd-soft-reboot.service.xml
Normal file
@ -0,0 +1,158 @@
|
||||
<?xml version='1.0'?> <!--*-nxml-*-->
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
||||
<!-- SPDX-License-Identifier: LGPL-2.1-or-later -->
|
||||
|
||||
<refentry id="systemd-soft-reboot.service">
|
||||
|
||||
<refentryinfo>
|
||||
<title>systemd-soft-reboot.service</title>
|
||||
<productname>systemd</productname>
|
||||
</refentryinfo>
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>systemd-soft-reboot.service</refentrytitle>
|
||||
<manvolnum>8</manvolnum>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>systemd-soft-reboot.service</refname>
|
||||
<refpurpose>Userspace reboot operation</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<para><filename>systemd-soft-reboot.service</filename></para>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<para><filename>systemd-soft-reboot.service</filename> is a system service that is pulled in by
|
||||
<filename>soft-reboot.target</filename> and is responsible for performing a userspace-only reboot
|
||||
operation. When invoked, it will send the <constant>SIGTERM</constant> signal to any processes left
|
||||
running (but does not follow up with <constant>SIGKILL</constant>, and does not wait for the processes to
|
||||
exit). If the <filename>/run/nextroot/</filename> directory exists (which may be a regular directory, a
|
||||
directory mount point or a symlink to either) then it will switch the file system root to it. It then
|
||||
reexecutes the service manager off the (possibly now new) root file system, which will enqueue a new boot
|
||||
transaction as in a normal reboot.</para>
|
||||
|
||||
<para>Such a userspace-only reboot operation permits updating or resetting the entirety of userspace with
|
||||
minimal downtime, as the reboot operation does <emphasis>not</emphasis> transition through:</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem><para>The second phase of regular shutdown, as implemented by
|
||||
<citerefentry><refentrytitle>systemd-shutdown</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para></listitem>
|
||||
|
||||
<listitem><para>The third phase of regular shutdown, i.e. the return to the initrd
|
||||
context</para></listitem>
|
||||
|
||||
<listitem><para>The hardware reboot operation</para></listitem>
|
||||
|
||||
<listitem><para>The firmware initialization</para></listitem>
|
||||
|
||||
<listitem><para>The boot loader initialization</para></listitem>
|
||||
|
||||
<listitem><para>The kernel initialization</para></listitem>
|
||||
|
||||
<listitem><para>The initrd initialization</para></listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>However this form of reboot comes with drawbacks as well:</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem><para>The OS update remains incomplete, as the kernel is not reset and continues
|
||||
running.</para></listitem>
|
||||
|
||||
<listitem><para>Kernel settings (such as <filename>/proc/sys/</filename> settings, a.k.a. "sysctl", or
|
||||
<filename>/sys/</filename> settings) are not reset.</para></listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>These limitations may be addressed by various means, which are outside of the scope of this
|
||||
documentation, such as kernel live-patching and sufficiently comprehensive
|
||||
<filename>/etc/sysctl.d/</filename> files.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Resource Pass-Through</title>
|
||||
|
||||
<para>Various runtime OS resources can passed from a system runtime to the next, through the userspace
|
||||
reboot operation. Specificially:</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem><para>File descriptors placed in the file descriptor store of services that remain active
|
||||
until the very end are passed to the next boot, where they are placed in the file descriptor store of
|
||||
the same unit. For this to work, units must declare <varname>DefaultDependencies=no</varname> (and
|
||||
avoid a manual <varname>Conflicts=shutdown.target</varname> or similar) to ensure they are not
|
||||
terminated as usual during the system shutdown operation. Alternatively, use
|
||||
<varname>FileDescriptorStorePreserve=</varname> to allow the file descriptor store to remain pinned
|
||||
even when the unit is down. See
|
||||
<citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
|
||||
details about the file descriptor store.</para></listitem>
|
||||
|
||||
<listitem><para>Similar to this, file descriptors associated with <filename>.socket</filename> units
|
||||
remain open (and connectible) if the units are not stopped during the transition. (Achieved by
|
||||
<varname>DefaultDependencies=no</varname>.)</para></listitem>
|
||||
|
||||
<listitem><para>The <filename>/run/</filename> file system remains mounted and populated and may be
|
||||
used to pass state information between such userspace reboot cycles.</para></listitem>
|
||||
|
||||
<listitem><para>Service processes may continue to run over the transition, if they are placed in
|
||||
services that remain active until the very end of shutdown (which again is achieved via
|
||||
<varname>DefaultDependencies=no</varname>). They must also be set up to avoid being killed by the
|
||||
aforementioned <constant>SIGTERM</constant> spree (as per <ulink
|
||||
url="https://systemd.io/ROOT_STORAGE_DAEMONS">systemd and Storage Daemons for the Root File
|
||||
System</ulink>).</para></listitem>
|
||||
|
||||
<listitem><para>File system mounts may remain mounted during the transition, and complex storage
|
||||
attached, if configured to remain until the very end of the shutdown process. (Also achieved via
|
||||
<varname>DefaultDependencies=no</varname>, and by avoiding
|
||||
<varname>Conflicts=umount.target</varname>)</para></listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>Even though passing resources from one soft reboot cycle to the next is possible this way, we
|
||||
strongly suggest to use this functionality sparingly only, as it creates a more fragile system as
|
||||
resources from different versions of the OS and applications might be mixed with unforeseen
|
||||
consequences. In particular it's recommended to <emphasis>avoid</emphasis> allowing processes to survive
|
||||
the soft reboot operation, as this means code updates will necessarily be incomplete, and processes
|
||||
typically pin various other resources (such as the file system they are backed by), thus increasing
|
||||
memory usage (as two versions of the OS/application/file system might be kept in memory). Leaving
|
||||
processes running during a soft-reboot operation requires disconnecting the service comprehensively from
|
||||
the rest of the OS, i.e. minimizing IPC and reducing sharing of resources with the rest of the OS. A
|
||||
possible mechanism to achieve this is the concept of <ulink
|
||||
url="https://systemd.io/PORTABLE_SERVICES">Portable Services</ulink>.</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>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Notes</title>
|
||||
|
||||
<para>Note that because
|
||||
<citerefentry><refentrytitle>systemd-shutdown</refentrytitle><manvolnum>8</manvolnum></citerefentry> is
|
||||
not executed, the executables in <filename>/usr/lib/systemd/system-shutdown/</filename> are not executed
|
||||
either.</para>
|
||||
|
||||
<para>Note that <filename>systemd-soft-reboot.service</filename> (and related units) should never be
|
||||
executed directly. Instead, trigger system shutdown with a command such as <literal>systemctl
|
||||
soft-reboot</literal>.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>See Also</title>
|
||||
<para>
|
||||
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>systemd.special</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>systemd-poweroff.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>systemd-suspend.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>bootup</refentrytitle><manvolnum>7</manvolnum></citerefentry>
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
</refentry>
|
@ -437,8 +437,12 @@
|
||||
|
||||
<listitem><para>An additional filesystem to be mounted in the initrd. See
|
||||
<filename>initrd-fs.target</filename> description in
|
||||
<citerefentry><refentrytitle>systemd.special</refentrytitle><manvolnum>7</manvolnum></citerefentry>.
|
||||
</para></listitem>
|
||||
<citerefentry><refentrytitle>systemd.special</refentrytitle><manvolnum>7</manvolnum></citerefentry>. This
|
||||
is both an indicator to the initrd to mount this partition early and an indicator to the host to
|
||||
leave the partition mounted until final shutdown. Or in other words, if this flag is set it is
|
||||
assumed the mount shall be active during the entire regular runtime of the system, i.e. established
|
||||
before the initrd transitions into the host all the way until the host transitions to the final
|
||||
shutdown phase.</para></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
|
||||
|
@ -81,6 +81,7 @@
|
||||
<filename>slices.target</filename>,
|
||||
<filename>smartcard.target</filename>,
|
||||
<filename>sockets.target</filename>,
|
||||
<filename>soft-reboot.target</filename>,
|
||||
<filename>sound.target</filename>,
|
||||
<filename>suspend.target</filename>,
|
||||
<filename>swap.target</filename>,
|
||||
@ -442,15 +443,18 @@
|
||||
<varlistentry>
|
||||
<term><filename>kexec.target</filename></term>
|
||||
<listitem>
|
||||
<para>A special target unit for shutting down and rebooting
|
||||
the system via kexec.</para>
|
||||
<para>A special target unit for shutting down and rebooting the system via kexec.</para>
|
||||
|
||||
<para>Applications wanting to reboot the system should not start this unit
|
||||
directly, but should instead execute <command>systemctl kexec</command>
|
||||
(possibly with the <option>--no-block</option> option) or call
|
||||
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>'s
|
||||
<command>org.freedesktop.systemd1.Manager.KExec</command> D-Bus method
|
||||
<para>Applications wanting to reboot the system should not start this unit directly, but should
|
||||
instead execute <command>systemctl kexec</command> (possibly with the
|
||||
<option>--no-block</option> option) or call
|
||||
<citerefentry><refentrytitle>systemd-logind</refentrytitle><manvolnum>8</manvolnum></citerefentry>'s
|
||||
<function>org.freedesktop.login1.Manager.RebootWithFlags()</function> D-Bus method
|
||||
directly.</para>
|
||||
|
||||
<para>See
|
||||
<citerefentry><refentrytitle>systemd-kexec.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||
for further details of the operation this target pulls in.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
@ -559,18 +563,20 @@
|
||||
<varlistentry>
|
||||
<term><filename>reboot.target</filename></term>
|
||||
<listitem>
|
||||
<para>A special target unit for shutting down and rebooting
|
||||
the system.</para>
|
||||
<para>A special target unit for shutting down and rebooting the system.</para>
|
||||
|
||||
<para>Applications wanting to reboot the system should not start this unit
|
||||
directly, but should instead execute <command>systemctl reboot</command>
|
||||
(possibly with the <option>--no-block</option> option) or call
|
||||
<para>Applications wanting to reboot the system should not start this unit directly, but should
|
||||
instead execute <command>systemctl reboot</command> (possibly with the
|
||||
<option>--no-block</option> option) or call
|
||||
<citerefentry><refentrytitle>systemd-logind</refentrytitle><manvolnum>8</manvolnum></citerefentry>'s
|
||||
<command>org.freedesktop.login1.Manager.Reboot</command> D-Bus method
|
||||
directly.</para>
|
||||
<function>org.freedesktop.login1.Manager.Reboot()</function> D-Bus method directly.</para>
|
||||
|
||||
<para><filename>runlevel6.target</filename> is an alias for
|
||||
this target unit, for compatibility with SysV.</para>
|
||||
<para>See
|
||||
<citerefentry><refentrytitle>systemd-reboot.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||
for further details of the operation this target pulls in.</para>
|
||||
|
||||
<para><filename>runlevel6.target</filename> is an alias for this target unit, for compatibility
|
||||
with SysV.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
@ -703,6 +709,24 @@
|
||||
section.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><filename>soft-reboot.target</filename></term>
|
||||
<listitem>
|
||||
<para>A special target unit for shutting down and rebooting the userspace of the system (leaving
|
||||
the kernel running).</para>
|
||||
|
||||
<para>Applications wanting to reboot the system should not start this unit directly, but should
|
||||
instead execute <command>systemctl soft-reboot</command> (possibly with the
|
||||
<option>--no-block</option> option) or call
|
||||
<citerefentry><refentrytitle>systemd-logind</refentrytitle><manvolnum>8</manvolnum></citerefentry>'s
|
||||
<function>org.freedesktop.login1.Manager.RebootWithFlags()</function> D-Bus method
|
||||
directly.</para>
|
||||
|
||||
<para>See
|
||||
<citerefentry><refentrytitle>systemd-soft-reboot.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||
for further details of the operation this target pulls in.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><filename>suspend.target</filename></term>
|
||||
<listitem>
|
||||
|
@ -999,27 +999,34 @@
|
||||
<term><varname>FailureAction=</varname></term>
|
||||
<term><varname>SuccessAction=</varname></term>
|
||||
|
||||
<listitem><para>Configure the action to take when the unit stops and enters a failed state or inactive state.
|
||||
Takes one of <option>none</option>, <option>reboot</option>, <option>reboot-force</option>,
|
||||
<option>reboot-immediate</option>, <option>poweroff</option>, <option>poweroff-force</option>,
|
||||
<option>poweroff-immediate</option>, <option>exit</option>, and <option>exit-force</option>. In system mode,
|
||||
all options are allowed. In user mode, only <option>none</option>, <option>exit</option>, and
|
||||
<option>exit-force</option> are allowed. Both options default to <option>none</option>.</para>
|
||||
<listitem><para>Configure the action to take when the unit stops and enters a failed state or
|
||||
inactive state. Takes one of <option>none</option>, <option>reboot</option>,
|
||||
<option>reboot-force</option>, <option>reboot-immediate</option>, <option>poweroff</option>,
|
||||
<option>poweroff-force</option>, <option>poweroff-immediate</option>, <option>exit</option>,
|
||||
<option>exit-force</option>, <option>soft-reboot</option> and <option>soft-reboot-force</option>. In
|
||||
system mode, all options are allowed. In user mode, only <option>none</option>,
|
||||
<option>exit</option>, <option>exit-force</option>, <option>soft-reboot</option> and
|
||||
<option>soft-reboot-force</option> are allowed. Both options default to <option>none</option>.</para>
|
||||
|
||||
<para>If <option>none</option> is set, no action will be triggered. <option>reboot</option> causes a reboot
|
||||
following the normal shutdown procedure (i.e. equivalent to <command>systemctl reboot</command>).
|
||||
<option>reboot-force</option> causes a forced reboot which will terminate all processes forcibly but should
|
||||
cause no dirty file systems on reboot (i.e. equivalent to <command>systemctl reboot -f</command>) and
|
||||
<option>reboot-immediate</option> causes immediate execution of the
|
||||
<citerefentry><refentrytitle>reboot</refentrytitle><manvolnum>2</manvolnum></citerefentry> system call, which
|
||||
might result in data loss (i.e. equivalent to <command>systemctl reboot -ff</command>). Similarly,
|
||||
<option>poweroff</option>, <option>poweroff-force</option>, <option>poweroff-immediate</option> have the effect
|
||||
of powering down the system with similar semantics. <option>exit</option> causes the manager to exit following
|
||||
the normal shutdown procedure, and <option>exit-force</option> causes it terminate without shutting down
|
||||
services. When <option>exit</option> or <option>exit-force</option> is used by default the exit status of the
|
||||
main process of the unit (if this applies) is returned from the service manager. However, this may be overridden
|
||||
with <varname>FailureActionExitStatus=</varname>/<varname>SuccessActionExitStatus=</varname>, see
|
||||
below.</para></listitem>
|
||||
<para>If <option>none</option> is set, no action will be triggered. <option>reboot</option> causes a
|
||||
reboot following the normal shutdown procedure (i.e. equivalent to <command>systemctl
|
||||
reboot</command>). <option>reboot-force</option> causes a forced reboot which will terminate all
|
||||
processes forcibly but should cause no dirty file systems on reboot (i.e. equivalent to
|
||||
<command>systemctl reboot -f</command>) and <option>reboot-immediate</option> causes immediate
|
||||
execution of the
|
||||
<citerefentry><refentrytitle>reboot</refentrytitle><manvolnum>2</manvolnum></citerefentry> system
|
||||
call, which might result in data loss (i.e. equivalent to <command>systemctl reboot
|
||||
-ff</command>). Similarly, <option>poweroff</option>, <option>poweroff-force</option>,
|
||||
<option>poweroff-immediate</option> have the effect of powering down the system with similar
|
||||
semantics. <option>exit</option> causes the manager to exit following the normal shutdown procedure,
|
||||
and <option>exit-force</option> causes it terminate without shutting down services. When
|
||||
<option>exit</option> or <option>exit-force</option> is used by default the exit status of the main
|
||||
process of the unit (if this applies) is returned from the service manager. However, this may be
|
||||
overridden with
|
||||
<varname>FailureActionExitStatus=</varname>/<varname>SuccessActionExitStatus=</varname>, see
|
||||
below. <option>soft-reboot</option> will trigger a userspace reboot
|
||||
operation. <option>soft-reboot-force</option> does that too, but does not go through the shutdown
|
||||
transaction beforehand.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
|
@ -519,6 +519,15 @@
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><constant>SIGRTMIN+7</constant></term>
|
||||
|
||||
<listitem><para>Reboots userspace, starts the <filename>soft-reboot.target</filename> unit. This is
|
||||
mostly equivalent to <command>systemctl start soft-reboot.target
|
||||
--job-mode=replace-irreversibly</command>.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><constant>SIGRTMIN+13</constant></term>
|
||||
|
||||
@ -543,6 +552,12 @@
|
||||
<listitem><para>Immediately reboots the machine with kexec.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><constant>SIGRTMIN+17</constant></term>
|
||||
|
||||
<listitem><para>Immediately reboots the userspace.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><constant>SIGRTMIN+20</constant></term>
|
||||
|
||||
|
@ -6,11 +6,12 @@
|
||||
|
||||
#define SD_LOGIND_ROOT_CHECK_INHIBITORS (UINT64_C(1) << 0)
|
||||
#define SD_LOGIND_REBOOT_VIA_KEXEC (UINT64_C(1) << 1)
|
||||
#define SD_LOGIND_SOFT_REBOOT (UINT64_C(1) << 2)
|
||||
|
||||
/* For internal use only */
|
||||
#define SD_LOGIND_INTERACTIVE (UINT64_C(1) << 63)
|
||||
|
||||
#define SD_LOGIND_SHUTDOWN_AND_SLEEP_FLAGS_PUBLIC (SD_LOGIND_ROOT_CHECK_INHIBITORS|SD_LOGIND_REBOOT_VIA_KEXEC)
|
||||
#define SD_LOGIND_SHUTDOWN_AND_SLEEP_FLAGS_PUBLIC (SD_LOGIND_ROOT_CHECK_INHIBITORS|SD_LOGIND_REBOOT_VIA_KEXEC|SD_LOGIND_SOFT_REBOOT)
|
||||
#define SD_LOGIND_SHUTDOWN_AND_SLEEP_FLAGS_ALL (SD_LOGIND_SHUTDOWN_AND_SLEEP_FLAGS_PUBLIC|SD_LOGIND_INTERACTIVE)
|
||||
|
||||
bool session_id_valid(const char *id);
|
||||
|
@ -14,6 +14,7 @@
|
||||
#define SPECIAL_HALT_TARGET "halt.target"
|
||||
#define SPECIAL_POWEROFF_TARGET "poweroff.target"
|
||||
#define SPECIAL_REBOOT_TARGET "reboot.target"
|
||||
#define SPECIAL_SOFT_REBOOT_TARGET "soft-reboot.target"
|
||||
#define SPECIAL_KEXEC_TARGET "kexec.target"
|
||||
#define SPECIAL_EXIT_TARGET "exit.target"
|
||||
#define SPECIAL_SUSPEND_TARGET "suspend.target"
|
||||
|
@ -1713,6 +1713,45 @@ static int method_reboot(sd_bus_message *message, void *userdata, sd_bus_error *
|
||||
return sd_bus_reply_method_return(message, NULL);
|
||||
}
|
||||
|
||||
static int method_soft_reboot(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
_cleanup_free_ char *rt = NULL;
|
||||
Manager *m = ASSERT_PTR(userdata);
|
||||
const char *root;
|
||||
int r;
|
||||
|
||||
assert(message);
|
||||
|
||||
r = verify_run_space_permissive("soft reboot may fail", error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = mac_selinux_access_check(message, "reboot", error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_read(message, "s", &root);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!isempty(root)) {
|
||||
if (!path_is_valid(root))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||
"New root directory '%s' must be a valid path.", root);
|
||||
if (!path_is_absolute(root))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||
"New root directory path '%s' is not absolute.", root);
|
||||
|
||||
rt = strdup(root);
|
||||
if (!rt)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
free_and_replace(m->switch_root, rt);
|
||||
m->objective = MANAGER_SOFT_REBOOT;
|
||||
|
||||
return sd_bus_reply_method_return(message, NULL);
|
||||
}
|
||||
|
||||
static int method_poweroff(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
Manager *m = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
@ -1772,8 +1811,8 @@ static int method_kexec(sd_bus_message *message, void *userdata, sd_bus_error *e
|
||||
|
||||
static int method_switch_root(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
_cleanup_free_ char *ri = NULL, *rt = NULL;
|
||||
const char *root, *init;
|
||||
Manager *m = ASSERT_PTR(userdata);
|
||||
const char *root, *init;
|
||||
int r;
|
||||
|
||||
assert(message);
|
||||
@ -3260,6 +3299,11 @@ const sd_bus_vtable bus_manager_vtable[] = {
|
||||
NULL,
|
||||
method_reboot,
|
||||
SD_BUS_VTABLE_CAPABILITY(CAP_SYS_BOOT)),
|
||||
SD_BUS_METHOD_WITH_ARGS("SoftReboot",
|
||||
SD_BUS_ARGS("s", new_root),
|
||||
SD_BUS_NO_RESULT,
|
||||
method_soft_reboot,
|
||||
SD_BUS_VTABLE_CAPABILITY(CAP_SYS_BOOT)),
|
||||
SD_BUS_METHOD("PowerOff",
|
||||
NULL,
|
||||
NULL,
|
||||
|
@ -22,6 +22,8 @@ static const char* const emergency_action_table[_EMERGENCY_ACTION_MAX] = {
|
||||
[EMERGENCY_ACTION_POWEROFF_IMMEDIATE] = "poweroff-immediate",
|
||||
[EMERGENCY_ACTION_EXIT] = "exit",
|
||||
[EMERGENCY_ACTION_EXIT_FORCE] = "exit-force",
|
||||
[EMERGENCY_ACTION_SOFT_REBOOT] = "soft-reboot",
|
||||
[EMERGENCY_ACTION_SOFT_REBOOT_FORCE] = "soft-reboot-force",
|
||||
};
|
||||
|
||||
static void log_and_status(Manager *m, bool warn, const char *message, const char *reason) {
|
||||
@ -47,7 +49,7 @@ void emergency_action(
|
||||
assert(action < _EMERGENCY_ACTION_MAX);
|
||||
|
||||
/* Is the special shutdown target active or queued? If so, we are in shutdown state */
|
||||
if (IN_SET(action, EMERGENCY_ACTION_REBOOT, EMERGENCY_ACTION_POWEROFF, EMERGENCY_ACTION_EXIT)) {
|
||||
if (IN_SET(action, EMERGENCY_ACTION_REBOOT, EMERGENCY_ACTION_SOFT_REBOOT, EMERGENCY_ACTION_POWEROFF, EMERGENCY_ACTION_EXIT)) {
|
||||
u = manager_get_unit(m, SPECIAL_SHUTDOWN_TARGET);
|
||||
if (u && unit_active_or_pending(u)) {
|
||||
log_notice("Shutdown is already active. Skipping emergency action request %s.",
|
||||
@ -80,7 +82,6 @@ void emergency_action(
|
||||
|
||||
(void) update_reboot_parameter_and_warn(reboot_arg, true);
|
||||
m->objective = MANAGER_REBOOT;
|
||||
|
||||
break;
|
||||
|
||||
case EMERGENCY_ACTION_REBOOT_IMMEDIATE:
|
||||
@ -98,6 +99,18 @@ void emergency_action(
|
||||
(void) reboot(RB_AUTOBOOT);
|
||||
break;
|
||||
|
||||
case EMERGENCY_ACTION_SOFT_REBOOT:
|
||||
log_and_status(m, warn, "Soft-rebooting", reason);
|
||||
|
||||
(void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_SOFT_REBOOT_TARGET, JOB_REPLACE_IRREVERSIBLY, NULL, NULL);
|
||||
break;
|
||||
|
||||
case EMERGENCY_ACTION_SOFT_REBOOT_FORCE:
|
||||
log_and_status(m, warn, "Forcibly soft-rebooting", reason);
|
||||
|
||||
m->objective = MANAGER_SOFT_REBOOT;
|
||||
break;
|
||||
|
||||
case EMERGENCY_ACTION_EXIT:
|
||||
|
||||
if (exit_status >= 0)
|
||||
|
@ -16,6 +16,8 @@ typedef enum EmergencyAction {
|
||||
EMERGENCY_ACTION_EXIT,
|
||||
_EMERGENCY_ACTION_FIRST_USER_ACTION = EMERGENCY_ACTION_EXIT,
|
||||
EMERGENCY_ACTION_EXIT_FORCE,
|
||||
EMERGENCY_ACTION_SOFT_REBOOT,
|
||||
EMERGENCY_ACTION_SOFT_REBOOT_FORCE,
|
||||
_EMERGENCY_ACTION_MAX,
|
||||
_EMERGENCY_ACTION_INVALID = -EINVAL,
|
||||
} EmergencyAction;
|
||||
|
@ -1788,7 +1788,7 @@ static int do_reexecute(
|
||||
const char **args;
|
||||
int r;
|
||||
|
||||
assert(IN_SET(objective, MANAGER_REEXECUTE, MANAGER_SWITCH_ROOT));
|
||||
assert(IN_SET(objective, MANAGER_REEXECUTE, MANAGER_SWITCH_ROOT, MANAGER_SOFT_REBOOT));
|
||||
assert(argc >= 0);
|
||||
assert(saved_rlimit_nofile);
|
||||
assert(saved_rlimit_memlock);
|
||||
@ -1823,13 +1823,24 @@ static int do_reexecute(
|
||||
if (saved_rlimit_memlock->rlim_cur != RLIM_INFINITY)
|
||||
(void) setrlimit(RLIMIT_MEMLOCK, saved_rlimit_memlock);
|
||||
|
||||
if (switch_root_dir) {
|
||||
/* Kill all remaining processes from the initrd, but don't wait for them, so that we can
|
||||
* handle the SIGCHLD for them after deserializing. */
|
||||
broadcast_signal(SIGTERM, false, true, arg_default_timeout_stop_usec);
|
||||
/* Kill all remaining processes from the initrd, but don't wait for them, so that we can handle the
|
||||
* SIGCHLD for them after deserializing. */
|
||||
if (IN_SET(objective, MANAGER_SWITCH_ROOT, MANAGER_SOFT_REBOOT))
|
||||
broadcast_signal(SIGTERM, /* wait_for_exit= */ false, /* send_sighup= */ true, arg_default_timeout_stop_usec);
|
||||
|
||||
/* And switch root with MS_MOVE, because we remove the old directory afterwards and detach it. */
|
||||
r = switch_root(switch_root_dir, /* old_root_after= */ NULL, MS_MOVE);
|
||||
if (!switch_root_dir && objective == MANAGER_SOFT_REBOOT) {
|
||||
/* If no switch root dir is specified, then check if /run/nextroot/ qualifies and use that */
|
||||
r = path_is_os_tree("/run/nextroot");
|
||||
if (r < 0 && r != -ENOENT)
|
||||
log_debug_errno(r, "Failed to determine if /run/nextroot/ is a valid OS tree, ignoring: %m");
|
||||
else if (r > 0)
|
||||
switch_root_dir = "/run/nextroot";
|
||||
}
|
||||
|
||||
if (switch_root_dir) {
|
||||
r = switch_root(/* new_root= */ switch_root_dir,
|
||||
/* old_root_after= */ NULL,
|
||||
/* flags= */ objective == MANAGER_SWITCH_ROOT ? SWITCH_ROOT_DESTROY_OLD_ROOT : 0);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to switch root, trying to continue: %m");
|
||||
}
|
||||
@ -1851,7 +1862,7 @@ static int do_reexecute(
|
||||
i = 1; /* Leave args[0] empty for now. */
|
||||
filter_args(args, &i, argv, argc);
|
||||
|
||||
if (switch_root_dir)
|
||||
if (IN_SET(objective, MANAGER_SWITCH_ROOT, MANAGER_SOFT_REBOOT))
|
||||
args[i++] = "--switched-root";
|
||||
args[i++] = runtime_scope_cmdline_option_to_string(arg_runtime_scope);
|
||||
args[i++] = sfd;
|
||||
@ -2036,6 +2047,24 @@ static int invoke_main_loop(
|
||||
|
||||
return objective;
|
||||
|
||||
case MANAGER_SOFT_REBOOT:
|
||||
manager_send_reloading(m);
|
||||
manager_set_switching_root(m, true);
|
||||
|
||||
r = prepare_reexecute(m, &arg_serialization, ret_fds, /* switching_root= */ true);
|
||||
if (r < 0) {
|
||||
*ret_error_message = "Failed to prepare for reexecution";
|
||||
return r;
|
||||
}
|
||||
|
||||
log_notice("Soft-rebooting.");
|
||||
|
||||
*ret_retval = EXIT_SUCCESS;
|
||||
*ret_switch_root_dir = TAKE_PTR(m->switch_root);
|
||||
*ret_switch_root_init = NULL;
|
||||
|
||||
return objective;
|
||||
|
||||
case MANAGER_EXIT:
|
||||
if (MANAGER_IS_USER(m)) {
|
||||
log_debug("Exit.");
|
||||
@ -3093,6 +3122,7 @@ int main(int argc, char *argv[]) {
|
||||
MANAGER_RELOAD,
|
||||
MANAGER_REEXECUTE,
|
||||
MANAGER_REBOOT,
|
||||
MANAGER_SOFT_REBOOT,
|
||||
MANAGER_POWEROFF,
|
||||
MANAGER_HALT,
|
||||
MANAGER_KEXEC,
|
||||
@ -3109,7 +3139,7 @@ finish:
|
||||
|
||||
mac_selinux_finish();
|
||||
|
||||
if (IN_SET(r, MANAGER_REEXECUTE, MANAGER_SWITCH_ROOT))
|
||||
if (IN_SET(r, MANAGER_REEXECUTE, MANAGER_SWITCH_ROOT, MANAGER_SOFT_REBOOT))
|
||||
r = do_reexecute(r,
|
||||
argc, argv,
|
||||
&saved_rlimit_nofile,
|
||||
|
@ -561,6 +561,7 @@ static int manager_setup_signals(Manager *m) {
|
||||
SIGRTMIN+4, /* systemd: start poweroff.target */
|
||||
SIGRTMIN+5, /* systemd: start reboot.target */
|
||||
SIGRTMIN+6, /* systemd: start kexec.target */
|
||||
SIGRTMIN+7, /* systemd: start soft-reboot.target */
|
||||
|
||||
/* ... space for more special targets ... */
|
||||
|
||||
@ -568,9 +569,7 @@ static int manager_setup_signals(Manager *m) {
|
||||
SIGRTMIN+14, /* systemd: Immediate poweroff */
|
||||
SIGRTMIN+15, /* systemd: Immediate reboot */
|
||||
SIGRTMIN+16, /* systemd: Immediate kexec */
|
||||
|
||||
/* ... space for one more immediate system state change ... */
|
||||
|
||||
SIGRTMIN+17, /* systemd: Immediate soft-reboot */
|
||||
SIGRTMIN+18, /* systemd: control command */
|
||||
|
||||
/* ... space ... */
|
||||
@ -1627,7 +1626,7 @@ Manager* manager_free(Manager *m) {
|
||||
unit_vtable[c]->shutdown(m);
|
||||
|
||||
/* Keep the cgroup hierarchy in place except when we know we are going down for good */
|
||||
manager_shutdown_cgroup(m, IN_SET(m->objective, MANAGER_EXIT, MANAGER_REBOOT, MANAGER_POWEROFF, MANAGER_HALT, MANAGER_KEXEC));
|
||||
manager_shutdown_cgroup(m, /* delete= */ IN_SET(m->objective, MANAGER_EXIT, MANAGER_REBOOT, MANAGER_POWEROFF, MANAGER_HALT, MANAGER_KEXEC));
|
||||
|
||||
lookup_paths_flush_generator(&m->lookup_paths);
|
||||
|
||||
@ -2979,13 +2978,14 @@ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t
|
||||
const char *target;
|
||||
JobMode mode;
|
||||
} target_table[] = {
|
||||
[0] = { SPECIAL_DEFAULT_TARGET, JOB_ISOLATE },
|
||||
[1] = { SPECIAL_RESCUE_TARGET, JOB_ISOLATE },
|
||||
[2] = { SPECIAL_EMERGENCY_TARGET, JOB_ISOLATE },
|
||||
[3] = { SPECIAL_HALT_TARGET, JOB_REPLACE_IRREVERSIBLY },
|
||||
[4] = { SPECIAL_POWEROFF_TARGET, JOB_REPLACE_IRREVERSIBLY },
|
||||
[5] = { SPECIAL_REBOOT_TARGET, JOB_REPLACE_IRREVERSIBLY },
|
||||
[6] = { SPECIAL_KEXEC_TARGET, JOB_REPLACE_IRREVERSIBLY },
|
||||
[0] = { SPECIAL_DEFAULT_TARGET, JOB_ISOLATE },
|
||||
[1] = { SPECIAL_RESCUE_TARGET, JOB_ISOLATE },
|
||||
[2] = { SPECIAL_EMERGENCY_TARGET, JOB_ISOLATE },
|
||||
[3] = { SPECIAL_HALT_TARGET, JOB_REPLACE_IRREVERSIBLY },
|
||||
[4] = { SPECIAL_POWEROFF_TARGET, JOB_REPLACE_IRREVERSIBLY },
|
||||
[5] = { SPECIAL_REBOOT_TARGET, JOB_REPLACE_IRREVERSIBLY },
|
||||
[6] = { SPECIAL_KEXEC_TARGET, JOB_REPLACE_IRREVERSIBLY },
|
||||
[7] = { SPECIAL_SOFT_REBOOT_TARGET, JOB_REPLACE_IRREVERSIBLY },
|
||||
};
|
||||
|
||||
/* Starting SIGRTMIN+13, so that target halt and system halt are 10 apart */
|
||||
@ -2994,6 +2994,7 @@ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t
|
||||
[1] = MANAGER_POWEROFF,
|
||||
[2] = MANAGER_REBOOT,
|
||||
[3] = MANAGER_KEXEC,
|
||||
[4] = MANAGER_SOFT_REBOOT,
|
||||
};
|
||||
|
||||
if ((int) sfsi.ssi_signo >= SIGRTMIN+0 &&
|
||||
|
@ -44,6 +44,7 @@ typedef enum ManagerObjective {
|
||||
MANAGER_RELOAD,
|
||||
MANAGER_REEXECUTE,
|
||||
MANAGER_REBOOT,
|
||||
MANAGER_SOFT_REBOOT,
|
||||
MANAGER_POWEROFF,
|
||||
MANAGER_HALT,
|
||||
MANAGER_KEXEC,
|
||||
|
@ -67,6 +67,18 @@ static const HandleActionData handle_action_data_table[_HANDLE_ACTION_MAX] = {
|
||||
.message = "System is rebooting with kexec",
|
||||
.log_verb = "kexec",
|
||||
},
|
||||
[HANDLE_SOFT_REBOOT] = {
|
||||
.handle = HANDLE_SOFT_REBOOT,
|
||||
.target = SPECIAL_SOFT_REBOOT_TARGET,
|
||||
.inhibit_what = INHIBIT_SHUTDOWN,
|
||||
.polkit_action = "org.freedesktop.login1.reboot",
|
||||
.polkit_action_multiple_sessions = "org.freedesktop.login1.reboot-multiple-sessions",
|
||||
.polkit_action_ignore_inhibit = "org.freedesktop.login1.reboot-ignore-inhibit",
|
||||
.sleep_operation = _SLEEP_OPERATION_INVALID,
|
||||
.message_id = SD_MESSAGE_SHUTDOWN_STR,
|
||||
.message = "System userspace is rebooting",
|
||||
.log_verb = "soft-reboot",
|
||||
},
|
||||
[HANDLE_SUSPEND] = {
|
||||
.handle = HANDLE_SUSPEND,
|
||||
.target = SPECIAL_SUSPEND_TARGET,
|
||||
@ -133,6 +145,7 @@ int manager_handle_action(
|
||||
[HANDLE_REBOOT] = "Rebooting...",
|
||||
[HANDLE_HALT] = "Halting...",
|
||||
[HANDLE_KEXEC] = "Rebooting via kexec...",
|
||||
[HANDLE_SOFT_REBOOT] = "Rebooting userspace...",
|
||||
[HANDLE_SUSPEND] = "Suspending...",
|
||||
[HANDLE_HIBERNATE] = "Hibernating...",
|
||||
[HANDLE_HYBRID_SLEEP] = "Hibernating and suspending...",
|
||||
@ -257,6 +270,7 @@ static const char* const handle_action_verb_table[_HANDLE_ACTION_MAX] = {
|
||||
[HANDLE_REBOOT] = "reboot",
|
||||
[HANDLE_HALT] = "halt",
|
||||
[HANDLE_KEXEC] = "kexec",
|
||||
[HANDLE_SOFT_REBOOT] = "soft-reboot",
|
||||
[HANDLE_SUSPEND] = "suspend",
|
||||
[HANDLE_HIBERNATE] = "hibernate",
|
||||
[HANDLE_HYBRID_SLEEP] = "enter hybrid sleep",
|
||||
@ -273,6 +287,7 @@ static const char* const handle_action_table[_HANDLE_ACTION_MAX] = {
|
||||
[HANDLE_REBOOT] = "reboot",
|
||||
[HANDLE_HALT] = "halt",
|
||||
[HANDLE_KEXEC] = "kexec",
|
||||
[HANDLE_SOFT_REBOOT] = "soft-reboot",
|
||||
[HANDLE_SUSPEND] = "suspend",
|
||||
[HANDLE_HIBERNATE] = "hibernate",
|
||||
[HANDLE_HYBRID_SLEEP] = "hybrid-sleep",
|
||||
|
@ -9,6 +9,7 @@ typedef enum HandleAction {
|
||||
HANDLE_REBOOT,
|
||||
HANDLE_HALT,
|
||||
HANDLE_KEXEC,
|
||||
HANDLE_SOFT_REBOOT,
|
||||
HANDLE_SUSPEND,
|
||||
HANDLE_HIBERNATE,
|
||||
HANDLE_HYBRID_SLEEP,
|
||||
|
@ -1860,9 +1860,19 @@ static int method_do_shutdown_or_sleep(
|
||||
if ((flags & ~SD_LOGIND_SHUTDOWN_AND_SLEEP_FLAGS_PUBLIC) != 0)
|
||||
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||
"Invalid flags parameter");
|
||||
if (a->handle != HANDLE_REBOOT && (flags & SD_LOGIND_REBOOT_VIA_KEXEC))
|
||||
|
||||
if (FLAGS_SET(flags, (SD_LOGIND_REBOOT_VIA_KEXEC|SD_LOGIND_SOFT_REBOOT)))
|
||||
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||
"Reboot via kexec is only applicable with reboot operations");
|
||||
"Both reboot via kexec and soft reboot selected, which is not supported");
|
||||
|
||||
if (a->handle != HANDLE_REBOOT) {
|
||||
if (flags & SD_LOGIND_REBOOT_VIA_KEXEC)
|
||||
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||
"Reboot via kexec option is only applicable with reboot operations");
|
||||
if (flags & SD_LOGIND_SOFT_REBOOT)
|
||||
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||
"Soft reboot option is only applicable with reboot operations");
|
||||
}
|
||||
} else {
|
||||
/* Old style method: no flags parameter, but interactive bool passed as boolean in
|
||||
* payload. Let's convert this argument to the new-style flags parameter for our internal
|
||||
@ -1878,6 +1888,8 @@ static int method_do_shutdown_or_sleep(
|
||||
|
||||
if ((flags & SD_LOGIND_REBOOT_VIA_KEXEC) && kexec_loaded())
|
||||
a = handle_action_lookup(HANDLE_KEXEC);
|
||||
else if ((flags & SD_LOGIND_SOFT_REBOOT))
|
||||
a = handle_action_lookup(HANDLE_SOFT_REBOOT);
|
||||
|
||||
/* Don't allow multiple jobs being executed at the same time */
|
||||
if (m->delayed_action)
|
||||
@ -2221,7 +2233,7 @@ static int method_schedule_shutdown(sd_bus_message *message, void *userdata, sd_
|
||||
}
|
||||
|
||||
handle = handle_action_from_string(type);
|
||||
if (!IN_SET(handle, HANDLE_POWEROFF, HANDLE_REBOOT, HANDLE_HALT, HANDLE_KEXEC))
|
||||
if (!IN_SET(handle, HANDLE_POWEROFF, HANDLE_REBOOT, HANDLE_SOFT_REBOOT, HANDLE_HALT, HANDLE_KEXEC))
|
||||
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Unsupported shutdown type");
|
||||
|
||||
a = handle_action_lookup(handle);
|
||||
|
@ -47,6 +47,7 @@ bool fstab_is_extrinsic(const char *mount, const char *opts) {
|
||||
|
||||
if (PATH_STARTSWITH_SET(mount,
|
||||
"/run/initramfs", /* This should stay around from before we boot until after we shutdown */
|
||||
"/run/nextroot", /* Similar (though might be updated from the host) */
|
||||
"/proc", /* All of this is API VFS */
|
||||
"/sys", /* … dito … */
|
||||
"/dev")) /* … dito … */
|
||||
|
@ -376,8 +376,9 @@ static int relabel_cb(
|
||||
return RECURSE_DIR_CONTINUE;
|
||||
|
||||
case RECURSE_DIR_ENTER:
|
||||
/* /run/initramfs is static data and big, no need to dynamically relabel its contents at boot... */
|
||||
if (path_equal(path, "/run/initramfs"))
|
||||
/* /run/initramfs/ + /run/nextroot/ are static data and big, no need to dynamically relabel
|
||||
* its contents at boot... */
|
||||
if (PATH_STARTSWITH_SET(path, "/run/initramfs", "/run/nextroot"))
|
||||
return RECURSE_DIR_SKIP_ENTRY;
|
||||
|
||||
_fallthrough_;
|
||||
|
@ -1099,6 +1099,24 @@ int make_mount_point(const char *path) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int fd_make_mount_point(int fd) {
|
||||
int r;
|
||||
|
||||
assert(fd >= 0);
|
||||
|
||||
r = fd_is_mount_point(fd, NULL, 0);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to determine whether file descriptor is a mount point: %m");
|
||||
if (r > 0)
|
||||
return 0;
|
||||
|
||||
r = mount_follow_verbose(LOG_DEBUG, FORMAT_PROC_FD_PATH(fd), FORMAT_PROC_FD_PATH(fd), NULL, MS_BIND|MS_REC, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int make_userns(uid_t uid_shift, uid_t uid_range, uid_t owner, RemountIdmapping idmapping) {
|
||||
_cleanup_close_ int userns_fd = -EBADF;
|
||||
_cleanup_free_ char *line = NULL;
|
||||
|
@ -100,6 +100,7 @@ int bind_mount_in_namespace(pid_t target, const char *propagate_path, const char
|
||||
int mount_image_in_namespace(pid_t target, const char *propagate_path, const char *incoming_path, const char *src, const char *dest, bool read_only, bool make_file_or_directory, const MountOptions *options, const ImagePolicy *image_policy);
|
||||
|
||||
int make_mount_point(const char *path);
|
||||
int fd_make_mount_point(int fd);
|
||||
|
||||
typedef enum RemountIdmapping {
|
||||
REMOUNT_IDMAPPING_NONE,
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
#include "base-filesystem.h"
|
||||
#include "chase.h"
|
||||
#include "creds-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "initrd-util.h"
|
||||
#include "log.h"
|
||||
@ -27,14 +28,26 @@
|
||||
|
||||
int switch_root(const char *new_root,
|
||||
const char *old_root_after, /* path below the new root, where to place the old root after the transition; may be NULL to unmount it */
|
||||
unsigned long mount_flags) { /* MS_MOVE or MS_BIND used for /proc/, /dev/, /run/, /sys/ */
|
||||
SwitchRootFlags flags) {
|
||||
|
||||
struct {
|
||||
const char *path;
|
||||
unsigned long mount_flags;
|
||||
} transfer_table[] = {
|
||||
{ "/dev", MS_BIND|MS_REC }, /* Recursive, because we want to save the original /dev/shm + /dev/pts and similar */
|
||||
{ "/sys", MS_BIND|MS_REC }, /* Similar, we want to retain various API VFS, or the cgroupv1 /sys/fs/cgroup/ tree */
|
||||
{ "/proc", MS_BIND|MS_REC }, /* Similar */
|
||||
{ "/run", MS_BIND }, /* Stuff mounted below this we don't save, as it might have lost its relevance, i.e. credentials, removable media and such, we rather want that the new boot mounts this fresh */
|
||||
{ SYSTEM_CREDENTIALS_DIRECTORY, MS_BIND }, /* Credentials passed into the system should survive */
|
||||
{ ENCRYPTED_SYSTEM_CREDENTIALS_DIRECTORY, MS_BIND }, /* Similar */
|
||||
{ "/run/host", MS_BIND|MS_REC }, /* Host supplied hierarchy should also survive */
|
||||
};
|
||||
|
||||
_cleanup_close_ int old_root_fd = -EBADF, new_root_fd = -EBADF;
|
||||
_cleanup_free_ char *resolved_old_root_after = NULL;
|
||||
int r, istmp;
|
||||
|
||||
assert(new_root);
|
||||
assert(IN_SET(mount_flags, MS_MOVE, MS_BIND));
|
||||
|
||||
/* Check if we shall remove the contents of the old root */
|
||||
old_root_fd = open("/", O_DIRECTORY|O_CLOEXEC);
|
||||
@ -53,11 +66,19 @@ int switch_root(const char *new_root,
|
||||
return 0;
|
||||
}
|
||||
|
||||
istmp = fd_is_temporary_fs(old_root_fd);
|
||||
if (istmp < 0)
|
||||
return log_error_errno(istmp, "Failed to stat root directory: %m");
|
||||
if (istmp > 0)
|
||||
log_debug("Root directory is on tmpfs, will do cleanup later.");
|
||||
/* Make the new root directory a mount point if it isn't */
|
||||
r = fd_make_mount_point(new_root_fd);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to make new root directory a mount point: %m");
|
||||
|
||||
if (FLAGS_SET(flags, SWITCH_ROOT_DESTROY_OLD_ROOT)) {
|
||||
istmp = fd_is_temporary_fs(old_root_fd);
|
||||
if (istmp < 0)
|
||||
return log_error_errno(istmp, "Failed to stat root directory: %m");
|
||||
if (istmp > 0)
|
||||
log_debug("Root directory is on tmpfs, will do cleanup later.");
|
||||
} else
|
||||
istmp = -1; /* don't know */
|
||||
|
||||
if (old_root_after) {
|
||||
/* Determine where we shall place the old root after the transition */
|
||||
@ -73,7 +94,8 @@ int switch_root(const char *new_root,
|
||||
* all while making them invisible/inaccessible in the file system tree for later code. That makes
|
||||
* sync'ing them then difficult. Let's hence issue a manual sync() here, so that we at least can
|
||||
* guarantee all file systems are an a good state before entering this state. */
|
||||
sync();
|
||||
if (!FLAGS_SET(flags, SWITCH_ROOT_DONT_SYNC))
|
||||
sync();
|
||||
|
||||
/* Work-around for kernel design: the kernel refuses MS_MOVE if any file systems are mounted
|
||||
* MS_SHARED. Hence remount them MS_PRIVATE here as a work-around.
|
||||
@ -82,32 +104,35 @@ int switch_root(const char *new_root,
|
||||
if (mount(NULL, "/", NULL, MS_REC|MS_PRIVATE, NULL) < 0)
|
||||
return log_error_errno(errno, "Failed to set \"/\" mount propagation to private: %m");
|
||||
|
||||
FOREACH_STRING(path, "/sys", "/dev", "/run", "/proc") {
|
||||
_cleanup_free_ char *chased = NULL;
|
||||
|
||||
r = chase(path, new_root, CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &chased, NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to resolve %s/%s: %m", new_root, path);
|
||||
if (r > 0) {
|
||||
/* Already exists. Let's see if it is a mount point already. */
|
||||
r = path_is_mount_point(chased, NULL, 0);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to determine whether %s is a mount point: %m", chased);
|
||||
if (r > 0) /* If it is already mounted, then do nothing */
|
||||
continue;
|
||||
} else
|
||||
/* Doesn't exist yet? */
|
||||
(void) mkdir_p_label(chased, 0755);
|
||||
|
||||
if (mount(path, chased, NULL, mount_flags, NULL) < 0)
|
||||
return log_error_errno(errno, "Failed to mount %s to %s: %m", path, chased);
|
||||
}
|
||||
|
||||
/* Do not fail if base_filesystem_create() fails. Not all switch roots are like base_filesystem_create() wants
|
||||
* them to look like. They might even boot, if they are RO and don't have the FS layout. Just ignore the error
|
||||
* and switch_root() nevertheless. */
|
||||
(void) base_filesystem_create_fd(new_root_fd, new_root, UID_INVALID, GID_INVALID);
|
||||
|
||||
FOREACH_ARRAY(transfer, transfer_table, ELEMENTSOF(transfer_table)) {
|
||||
_cleanup_free_ char *chased = NULL;
|
||||
|
||||
if (access(transfer->path, F_OK) < 0) {
|
||||
log_debug_errno(errno, "Path '%s' to move to target root directory, not found, ignoring: %m", transfer->path);
|
||||
continue;
|
||||
}
|
||||
|
||||
r = chase(transfer->path, new_root, CHASE_PREFIX_ROOT, &chased, NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to resolve %s/%s: %m", new_root, transfer->path);
|
||||
|
||||
/* Let's see if it is a mount point already. */
|
||||
r = path_is_mount_point(chased, NULL, 0);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to determine whether %s is a mount point: %m", chased);
|
||||
if (r > 0) /* If it is already mounted, then do nothing */
|
||||
continue;
|
||||
|
||||
r = mount_nofollow_verbose(LOG_ERR, transfer->path, chased, NULL, transfer->mount_flags, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (fchdir(new_root_fd) < 0)
|
||||
return log_error_errno(errno, "Failed to change directory to %s: %m", new_root);
|
||||
|
||||
@ -144,7 +169,7 @@ int switch_root(const char *new_root,
|
||||
return log_error_errno(errno, "Failed to change directory: %m");
|
||||
}
|
||||
|
||||
if (istmp) {
|
||||
if (istmp > 0) {
|
||||
struct stat rb;
|
||||
|
||||
if (fstat(old_root_fd, &rb) < 0)
|
||||
|
@ -3,4 +3,9 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
int switch_root(const char *new_root, const char *old_root_after, unsigned long mount_flags);
|
||||
typedef enum SwitchRootFlags {
|
||||
SWITCH_ROOT_DESTROY_OLD_ROOT = 1 << 0, /* rm -rf old root when switching – under the condition that it is backed by non-persistent tmpfs/ramfs/… */
|
||||
SWITCH_ROOT_DONT_SYNC = 1 << 1, /* don't call sync() immediately before switching root */
|
||||
} SwitchRootFlags;
|
||||
|
||||
int switch_root(const char *new_root, const char *old_root_after, SwitchRootFlags flags);
|
||||
|
@ -163,17 +163,15 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
static int switch_root_initramfs(void) {
|
||||
if (mount("/run/initramfs", "/run/initramfs", NULL, MS_BIND, NULL) < 0)
|
||||
return log_error_errno(errno, "Failed to mount bind /run/initramfs on /run/initramfs: %m");
|
||||
|
||||
if (mount(NULL, "/run/initramfs", NULL, MS_PRIVATE, NULL) < 0)
|
||||
return log_error_errno(errno, "Failed to make /run/initramfs private mount: %m");
|
||||
|
||||
/* switch_root with MS_BIND, because there might still be processes lurking around, which have open file descriptors.
|
||||
* /run/initramfs/shutdown will take care of these.
|
||||
* Also do not detach the old root, because /run/initramfs/shutdown needs to access it.
|
||||
*/
|
||||
return switch_root("/run/initramfs", "/oldroot", MS_BIND);
|
||||
/* Do not detach the old root, because /run/initramfs/shutdown needs to access it.
|
||||
*
|
||||
* Disable sync() during switch-root, we after all sync'ed here plenty, and a dumb sync (as opposed
|
||||
* to the "smart" sync() we did here that looks at progress parameters) would defeat much of our
|
||||
* efforts here. */
|
||||
return switch_root(
|
||||
/* new_root= */ "/run/initramfs",
|
||||
/* old_root_after= */ "/oldroot",
|
||||
/* flags= */ SWITCH_ROOT_DONT_SYNC);
|
||||
}
|
||||
|
||||
/* Read the following fields from /proc/meminfo:
|
||||
|
@ -45,6 +45,7 @@ int logind_reboot(enum action a) {
|
||||
[ACTION_POWEROFF] = "PowerOff",
|
||||
[ACTION_REBOOT] = "Reboot",
|
||||
[ACTION_KEXEC] = "Reboot",
|
||||
[ACTION_SOFT_REBOOT] = "Reboot",
|
||||
[ACTION_HALT] = "Halt",
|
||||
[ACTION_SUSPEND] = "Suspend",
|
||||
[ACTION_HIBERNATE] = "Hibernate",
|
||||
@ -80,6 +81,7 @@ int logind_reboot(enum action a) {
|
||||
|
||||
SET_FLAG(flags, SD_LOGIND_ROOT_CHECK_INHIBITORS, arg_check_inhibitors > 0);
|
||||
SET_FLAG(flags, SD_LOGIND_REBOOT_VIA_KEXEC, a == ACTION_KEXEC);
|
||||
SET_FLAG(flags, SD_LOGIND_SOFT_REBOOT, a == ACTION_SOFT_REBOOT);
|
||||
|
||||
r = bus_call_method(bus, bus_login_mgr, method_with_flags, &error, NULL, "t", flags);
|
||||
if (r >= 0)
|
||||
|
@ -199,6 +199,7 @@ int verb_start_special(int argc, char *argv[], void *userdata) {
|
||||
case ACTION_REBOOT:
|
||||
case ACTION_KEXEC:
|
||||
case ACTION_HALT:
|
||||
case ACTION_SOFT_REBOOT:
|
||||
if (arg_when == 0)
|
||||
r = logind_reboot(a);
|
||||
else if (arg_when != USEC_INFINITY)
|
||||
|
@ -222,6 +222,7 @@ const struct action_metadata action_table[_ACTION_MAX] = {
|
||||
[ACTION_POWEROFF] = { SPECIAL_POWEROFF_TARGET, "poweroff", "replace-irreversibly" },
|
||||
[ACTION_REBOOT] = { SPECIAL_REBOOT_TARGET, "reboot", "replace-irreversibly" },
|
||||
[ACTION_KEXEC] = { SPECIAL_KEXEC_TARGET, "kexec", "replace-irreversibly" },
|
||||
[ACTION_SOFT_REBOOT] = { SPECIAL_SOFT_REBOOT_TARGET, "soft-reboot", "replace-irreversibly" },
|
||||
[ACTION_RUNLEVEL2] = { SPECIAL_MULTI_USER_TARGET, NULL, "isolate" },
|
||||
[ACTION_RUNLEVEL3] = { SPECIAL_MULTI_USER_TARGET, NULL, "isolate" },
|
||||
[ACTION_RUNLEVEL4] = { SPECIAL_MULTI_USER_TARGET, NULL, "isolate" },
|
||||
|
@ -30,6 +30,7 @@ int verb_trivial_method(int argc, char *argv[], void *userdata) {
|
||||
streq(argv[0], "halt") ? "Halt" :
|
||||
streq(argv[0], "reboot") ? "Reboot" :
|
||||
streq(argv[0], "kexec") ? "KExec" :
|
||||
streq(argv[0], "soft-reboot") ? "SoftReboot" :
|
||||
streq(argv[0], "exit") ? "Exit" :
|
||||
/* poweroff */ "PowerOff";
|
||||
|
||||
|
@ -242,6 +242,7 @@ static int systemctl_help(void) {
|
||||
" poweroff Shut down and power-off the system\n"
|
||||
" reboot Shut down and reboot the system\n"
|
||||
" kexec Shut down and reboot the system with kexec\n"
|
||||
" soft-reboot Shut down and reboot userspace\n"
|
||||
" exit [EXIT_CODE] Request user instance or container exit\n"
|
||||
" switch-root [ROOT [INIT]] Change to a different root file system\n"
|
||||
" suspend Suspend the system\n"
|
||||
@ -285,8 +286,9 @@ static int systemctl_help(void) {
|
||||
" --now Start or stop unit after enabling or disabling it\n"
|
||||
" --dry-run Only print what would be done\n"
|
||||
" Currently supported by verbs: halt, poweroff, reboot,\n"
|
||||
" kexec, suspend, hibernate, suspend-then-hibernate,\n"
|
||||
" hybrid-sleep, default, rescue, emergency, and exit.\n"
|
||||
" kexec, soft-reboot, suspend, hibernate, \n"
|
||||
" suspend-then-hibernate, hybrid-sleep, default,\n"
|
||||
" rescue, emergency, and exit.\n"
|
||||
" -q --quiet Suppress output\n"
|
||||
" --no-warn Suppress several warnings shown by default\n"
|
||||
" --wait For (re)start, wait until service stopped again\n"
|
||||
@ -1180,6 +1182,7 @@ static int systemctl_main(int argc, char *argv[]) {
|
||||
{ "poweroff", VERB_ANY, 1, VERB_ONLINE_ONLY, verb_start_system_special },
|
||||
{ "reboot", VERB_ANY, 1, VERB_ONLINE_ONLY, verb_start_system_special },
|
||||
{ "kexec", VERB_ANY, 1, VERB_ONLINE_ONLY, verb_start_system_special },
|
||||
{ "soft-reboot", VERB_ANY, 1, VERB_ONLINE_ONLY, verb_start_system_special },
|
||||
{ "suspend", VERB_ANY, 1, VERB_ONLINE_ONLY, verb_start_system_special },
|
||||
{ "hibernate", VERB_ANY, 1, VERB_ONLINE_ONLY, verb_start_system_special },
|
||||
{ "hybrid-sleep", VERB_ANY, 1, VERB_ONLINE_ONLY, verb_start_system_special },
|
||||
|
@ -16,6 +16,7 @@ enum action {
|
||||
ACTION_POWEROFF,
|
||||
ACTION_REBOOT,
|
||||
ACTION_KEXEC,
|
||||
ACTION_SOFT_REBOOT,
|
||||
ACTION_EXIT,
|
||||
ACTION_SUSPEND,
|
||||
ACTION_HIBERNATE,
|
||||
|
@ -519,6 +519,55 @@ TEST(umount_recursive) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(fd_make_mount_point) {
|
||||
_cleanup_(rm_rf_physical_and_freep) char *t = NULL;
|
||||
_cleanup_free_ char *s = NULL;
|
||||
int r;
|
||||
|
||||
if (geteuid() != 0 || have_effective_cap(CAP_SYS_ADMIN) <= 0) {
|
||||
(void) log_tests_skipped("not running privileged");
|
||||
return;
|
||||
}
|
||||
|
||||
assert_se(mkdtemp_malloc(NULL, &t) >= 0);
|
||||
|
||||
assert_se(asprintf(&s, "%s/somerandomname%" PRIu64, t, random_u64()) >= 0);
|
||||
assert_se(s);
|
||||
assert_se(mkdir(s, 0700) >= 0);
|
||||
|
||||
r = safe_fork("(make_mount-point)",
|
||||
FORK_RESET_SIGNALS |
|
||||
FORK_CLOSE_ALL_FDS |
|
||||
FORK_DEATHSIG |
|
||||
FORK_WAIT |
|
||||
FORK_REOPEN_LOG |
|
||||
FORK_LOG |
|
||||
FORK_NEW_MOUNTNS |
|
||||
FORK_MOUNTNS_SLAVE,
|
||||
NULL);
|
||||
assert_se(r >= 0);
|
||||
|
||||
if (r == 0) {
|
||||
_cleanup_close_ int fd = -EBADF, fd2 = -EBADF;
|
||||
|
||||
fd = open(s, O_PATH|O_CLOEXEC);
|
||||
assert_se(fd >= 0);
|
||||
|
||||
assert_se(fd_is_mount_point(fd, NULL, AT_SYMLINK_FOLLOW) == 0);
|
||||
|
||||
assert_se(fd_make_mount_point(fd) > 0);
|
||||
|
||||
/* Reopen the inode so that we end up on the new mount */
|
||||
fd2 = open(s, O_PATH|O_CLOEXEC);
|
||||
|
||||
assert_se(fd_is_mount_point(fd2, NULL, AT_SYMLINK_FOLLOW) > 0);
|
||||
|
||||
assert_se(fd_make_mount_point(fd2) == 0);
|
||||
|
||||
_exit(EXIT_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
static int intro(void) {
|
||||
/* Create a dummy network interface for testing remount_sysfs(). */
|
||||
(void) system("ip link add dummy-test-mnt type dummy");
|
||||
|
1
test/TEST-82-SOFTREBOOT/Makefile
Symbolic link
1
test/TEST-82-SOFTREBOOT/Makefile
Symbolic link
@ -0,0 +1 @@
|
||||
../TEST-01-BASIC/Makefile
|
21
test/TEST-82-SOFTREBOOT/test.sh
Executable file
21
test/TEST-82-SOFTREBOOT/test.sh
Executable file
@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env bash
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
set -e
|
||||
|
||||
TEST_DESCRIPTION="Test Soft-Rebooting"
|
||||
|
||||
# shellcheck source=test/test-functions
|
||||
. "$TEST_BASE_DIR/test-functions"
|
||||
|
||||
test_append_files() {
|
||||
local workspace="${1:?}"
|
||||
# prevent shutdown in test suite, the expect script does that manually.
|
||||
mkdir -p "${workspace:?}/etc/systemd/system/end.service.d"
|
||||
cat >"$workspace/etc/systemd/system/end.service.d/99-override.conf" <<EOF
|
||||
[Service]
|
||||
ExecStart=
|
||||
ExecStart=/bin/true
|
||||
EOF
|
||||
}
|
||||
|
||||
do_test "$@"
|
@ -28,6 +28,7 @@ systemctl log-level info
|
||||
# FIXME: systemd-run doesn't play well with daemon-reexec
|
||||
# See: https://github.com/systemd/systemd/issues/27204
|
||||
sed -i '/\[org.freedesktop.systemd1\]/aorg.freedesktop.systemd1.Manager:Reexecute FIXME' /etc/dfuzzer.conf
|
||||
sed -i '/\[org.freedesktop.systemd1\]/aorg.freedesktop.systemd1.Manager:SoftReboot destructive' /etc/dfuzzer.conf
|
||||
|
||||
# TODO
|
||||
# * check for possibly newly introduced buses?
|
||||
|
11
test/units/testsuite-82.service
Normal file
11
test/units/testsuite-82.service
Normal file
@ -0,0 +1,11 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
[Unit]
|
||||
Description=TEST-82-SOFTREBOOT
|
||||
DefaultDependencies=no
|
||||
After=basic.target
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh
|
||||
FileDescriptorStoreMax=3
|
||||
NotifyAccess=all
|
147
test/units/testsuite-82.sh
Executable file
147
test/units/testsuite-82.sh
Executable file
@ -0,0 +1,147 @@
|
||||
#!/usr/bin/env bash
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
set -ex
|
||||
set -o pipefail
|
||||
|
||||
systemd-analyze log-level debug
|
||||
|
||||
export SYSTEMD_LOG_LEVEL=debug
|
||||
|
||||
if [ -f /run/testsuite82.touch3 ]; then
|
||||
echo "This is the fourth boot!"
|
||||
systemd-notify --status="Fourth Boot"
|
||||
|
||||
rm /run/testsuite82.touch3
|
||||
mount
|
||||
rmdir /original-root /run/nextroot
|
||||
|
||||
# Check that the fdstore entry still exists
|
||||
test "$LISTEN_FDS" -eq 3
|
||||
read -r x <&5
|
||||
test "$x" = "oinkoink"
|
||||
|
||||
# Check that the surviving service is still around
|
||||
test "$(systemctl show -P ActiveState testsuite-82-survive.service)" = "active"
|
||||
test "$(systemctl show -P ActiveState testsuite-82-nosurvive.service)" != "active"
|
||||
|
||||
# Take out the big guns now, and kill the service via SIGKILL (SIGTERM is blocked after all, see below)
|
||||
systemctl --signal=KILL kill testsuite-82-survive.service
|
||||
systemctl stop testsuite-82-survive.service
|
||||
|
||||
# All succeeded, exit cleanly now
|
||||
|
||||
elif [ -f /run/testsuite82.touch2 ]; then
|
||||
echo "This is the third boot!"
|
||||
systemd-notify --status="Third Boot"
|
||||
|
||||
rm /run/testsuite82.touch2
|
||||
|
||||
# Check that the fdstore entry still exists
|
||||
test "$LISTEN_FDS" -eq 2
|
||||
read -r x <&4
|
||||
test "$x" = "miaumiau"
|
||||
|
||||
# Upload another entry
|
||||
T="/dev/shm/fdstore.$RANDOM"
|
||||
echo "oinkoink" >"$T"
|
||||
systemd-notify --fd=3 --pid=parent 3<"$T"
|
||||
rm "$T"
|
||||
|
||||
# Check that the surviving service is still around
|
||||
test "$(systemctl show -P ActiveState testsuite-82-survive.service)" = "active"
|
||||
test "$(systemctl show -P ActiveState testsuite-82-nosurvive.service)" != "active"
|
||||
|
||||
# Test that we really are in the new overlayfs root fs
|
||||
read -r x </lower
|
||||
test "$x" = "miep"
|
||||
|
||||
# Switch back to the original root, away from the overlayfs
|
||||
mount --bind /original-root /run/nextroot
|
||||
mount
|
||||
|
||||
# Now issue the soft reboot. We should be right back soon.
|
||||
touch /run/testsuite82.touch3
|
||||
systemctl --no-block soft-reboot
|
||||
|
||||
# Now block until the soft-boot killing spree kills us
|
||||
exec sleep infinity
|
||||
|
||||
elif [ -f /run/testsuite82.touch ]; then
|
||||
echo "This is the second boot!"
|
||||
systemd-notify --status="Second Boot"
|
||||
|
||||
# Clean up what we created earlier
|
||||
rm /run/testsuite82.touch
|
||||
|
||||
# Check that the fdstore entry still exists
|
||||
test "$LISTEN_FDS" -eq 1
|
||||
read -r x <&3
|
||||
test "$x" = "wuffwuff"
|
||||
|
||||
# Upload another entry
|
||||
T="/dev/shm/fdstore.$RANDOM"
|
||||
echo "miaumiau" >"$T"
|
||||
systemd-notify --fd=3 --pid=parent 3<"$T"
|
||||
rm "$T"
|
||||
|
||||
# Check that the surviving service is still around
|
||||
test "$(systemctl show -P ActiveState testsuite-82-survive.service)" = "active"
|
||||
test "$(systemctl show -P ActiveState testsuite-82-nosurvive.service)" != "active"
|
||||
|
||||
# This time we test the /run/nextroot/ root switching logic. (We synthesize a new rootfs from the old via overlayfs)
|
||||
mkdir -p /run/nextroot /tmp/nextroot-lower /original-root
|
||||
mount -t tmpfs tmpfs /tmp/nextroot-lower
|
||||
echo miep >/tmp/nextroot-lower/lower
|
||||
mount -t overlay nextroot /run/nextroot -o lowerdir=/:/tmp/nextroot-lower,ro
|
||||
|
||||
# Bind our current root into the target so that we later can return to it
|
||||
mount --bind / /run/nextroot/original-root
|
||||
|
||||
# Now issue the soft reboot. We should be right back soon.
|
||||
touch /run/testsuite82.touch2
|
||||
systemctl --no-block soft-reboot
|
||||
|
||||
# Now block until the soft-boot killing spree kills us
|
||||
exec sleep infinity
|
||||
else
|
||||
# This is the first boot
|
||||
systemd-notify --status="First Boot"
|
||||
|
||||
# Let's upload an fd to the fdstore, so that we can verify fdstore passing works correcly
|
||||
T="/dev/shm/fdstore.$RANDOM"
|
||||
echo "wuffwuff" >"$T"
|
||||
systemd-notify --fd=3 --pid=parent 3<"$T"
|
||||
rm "$T"
|
||||
|
||||
# Create a script that can survive the soft reboot by ignoring SIGTERM (we
|
||||
# do this instead of the argv[0][0] = '@' thing because that's so hard to
|
||||
# do from a shell
|
||||
T="/dev/shm/survive-$RANDOM.sh"
|
||||
cat >$T <<EOF
|
||||
#!/bin/bash
|
||||
trap "" TERM
|
||||
systemd-notify --ready
|
||||
rm "$T"
|
||||
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
|
||||
|
||||
# Now issue the soft reboot. We should be right back soon.
|
||||
touch /run/testsuite82.touch
|
||||
systemctl --no-block soft-reboot
|
||||
|
||||
# Now block until the soft-boot killing spree kills us
|
||||
exec sleep infinity
|
||||
fi
|
||||
|
||||
systemd-analyze log-level info
|
||||
echo OK >/testok
|
||||
|
||||
systemctl --no-block poweroff
|
||||
|
||||
exit 0
|
@ -67,6 +67,7 @@ units = [
|
||||
['proc-sys-fs-binfmt_misc.mount', 'ENABLE_BINFMT'],
|
||||
['reboot.target', '',
|
||||
'ctrl-alt-del.target' + (with_runlevels ? ' runlevel6.target' : '')],
|
||||
['soft-reboot.target', ''],
|
||||
['remote-cryptsetup.target', 'HAVE_LIBCRYPTSETUP',
|
||||
'initrd-root-device.target.wants/'],
|
||||
['remote-veritysetup.target', 'HAVE_LIBCRYPTSETUP',
|
||||
@ -137,6 +138,7 @@ units = [
|
||||
['systemd-networkd.socket', 'ENABLE_NETWORKD'],
|
||||
['systemd-poweroff.service', ''],
|
||||
['systemd-reboot.service', ''],
|
||||
['systemd-soft-reboot.service', ''],
|
||||
['systemd-rfkill.socket', 'ENABLE_RFKILL'],
|
||||
['systemd-sysext.service', 'ENABLE_SYSEXT'],
|
||||
['systemd-confext.service', 'ENABLE_SYSEXT'],
|
||||
|
18
units/soft-reboot.target
Normal file
18
units/soft-reboot.target
Normal file
@ -0,0 +1,18 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
#
|
||||
# This file is part of systemd.
|
||||
#
|
||||
# systemd is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation; either version 2.1 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
[Unit]
|
||||
Description=Reboot System Userspace
|
||||
Documentation=man:systemd.special(7)
|
||||
DefaultDependencies=no
|
||||
Requires=systemd-soft-reboot.service
|
||||
After=systemd-soft-reboot.service
|
||||
AllowIsolate=yes
|
||||
JobTimeoutSec=30min
|
||||
JobTimeoutAction=soft-reboot-force
|
16
units/systemd-soft-reboot.service
Normal file
16
units/systemd-soft-reboot.service
Normal file
@ -0,0 +1,16 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
#
|
||||
# This file is part of systemd.
|
||||
#
|
||||
# systemd is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation; either version 2.1 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
[Unit]
|
||||
Description=Reboot System Userspace
|
||||
Documentation=man:systemd-soft-reboot.service(8)
|
||||
DefaultDependencies=no
|
||||
Requires=shutdown.target umount.target final.target
|
||||
After=shutdown.target umount.target final.target
|
||||
SuccessAction=soft-reboot-force
|
Loading…
x
Reference in New Issue
Block a user