mirror of
https://github.com/systemd/systemd
synced 2025-10-06 20:24:45 +02:00
Compare commits
14 Commits
9120022587
...
7ebbe57ece
Author | SHA1 | Date | |
---|---|---|---|
![]() |
7ebbe57ece | ||
![]() |
9ae2dbf7f4 | ||
![]() |
6eab4cd44c | ||
![]() |
f12cc0d3be | ||
![]() |
c3116558ad | ||
![]() |
75df71d180 | ||
![]() |
e58ba80a40 | ||
![]() |
dc1505555b | ||
![]() |
8ba48d4bf8 | ||
![]() |
af925f7eb3 | ||
![]() |
5572fb18c0 | ||
![]() |
c17516a84a | ||
![]() |
2cc6c651ee | ||
![]() |
5921c48fcf |
@ -38,9 +38,7 @@ The following exceptions apply:
|
||||
verbatim from the Linux kernel source tree and are licensed under **GPL-2.0 WITH
|
||||
Linux-syscall-note** and are used within the scope of the Linux-syscall-note
|
||||
exception provisions
|
||||
* the following sources are licensed under the **LGPL-2.0-or-later** license:
|
||||
- src/basic/utf8.c
|
||||
- src/shared/initreq.h
|
||||
* the src/basic/utf8.c source is licensed under the **LGPL-2.0-or-later** license.
|
||||
* the src/basic/include/linux/bpf_insn.h header is copied from the Linux kernel
|
||||
source tree and is licensed under either **BSD-2-Clause** or **GPL-2.0-only**,
|
||||
and thus is included in the systemd build under the BSD-2-Clause license.
|
||||
|
9
NEWS
9
NEWS
@ -139,6 +139,15 @@ CHANGES WITH 258 in spe:
|
||||
* The command 'journalctl --follow' now exits with success on
|
||||
SIGTERM/SIGINT, or its pipe STDOUT is disconnected.
|
||||
|
||||
* Support for System V style system state control has been removed:
|
||||
- The /dev/initctl device node has been removed.
|
||||
- The initctl, runlevel and telinit commands have been removed.
|
||||
- Support for system state control via the init command (e.g.
|
||||
'init 3') has been removed.
|
||||
- The units runlevel[0-6].target have been removed.
|
||||
- The concept of runlevels has been removed, so runlevel transitions
|
||||
are no longer recorded in the utmp/wtmp databases.
|
||||
|
||||
Announcements of Future Feature Removals:
|
||||
|
||||
* Support for System V service scripts is deprecated and will be
|
||||
|
2
TODO
2
TODO
@ -2268,7 +2268,7 @@ Features:
|
||||
|
||||
* clean up date formatting and parsing so that all absolute/relative timestamps we format can also be parsed
|
||||
|
||||
* on shutdown: move utmp, wall, audit logic all into PID 1 (or logind?), get rid of systemd-update-utmp-runlevel
|
||||
* on shutdown: move utmp, wall, audit logic all into PID 1 (or logind?)
|
||||
|
||||
* make repeated alt-ctrl-del presses printing a dump
|
||||
|
||||
|
10
docs/FAQ.md
10
docs/FAQ.md
@ -11,13 +11,7 @@ Also check out the [Tips & Tricks](/TIPS_AND_TRICKS)!
|
||||
|
||||
**Q: How do I change the current runlevel?**
|
||||
|
||||
A: In systemd runlevels are exposed via "target units". You can change them like this:
|
||||
|
||||
```sh
|
||||
# systemctl isolate runlevel5.target
|
||||
```
|
||||
|
||||
Note however, that the concept of runlevels is a bit out of date, and it is usually nicer to use modern names for this. e.g.:
|
||||
A: The concept of runlevels is obsolete. A set of target units are exposed that carry similar semantics, e.g. runlevel 5 -> `graphical.target`:
|
||||
|
||||
```sh
|
||||
# systemctl isolate graphical.target
|
||||
@ -47,8 +41,6 @@ A: Note that there might be more than one target active at the same time. So the
|
||||
$ systemctl list-units --type=target
|
||||
```
|
||||
|
||||
If you are just interested in a single number, you can use the venerable _runlevel_ command, but again, its output might be misleading.
|
||||
|
||||
**Q: I want to change a service file, but rpm keeps overwriting it in /usr/lib/systemd/system all the time, how should I handle this?**
|
||||
|
||||
A: The recommended way is to copy the service file from /usr/lib/systemd/system to /etc/systemd/system and edit it there. The latter directory takes precedence over the former, and rpm will never overwrite it. If you want to use the distributed service file again you can simply delete (or rename) the service file in /etc/systemd/system again.
|
||||
|
@ -79,7 +79,6 @@ manpages = [
|
||||
['resolvectl', '1', ['resolvconf'], 'ENABLE_RESOLVE'],
|
||||
['resolved.conf', '5', ['resolved.conf.d'], 'ENABLE_RESOLVE'],
|
||||
['run0', '1', [], ''],
|
||||
['runlevel', '8', [], 'HAVE_SYSV_COMPAT'],
|
||||
['sd-bus-errors',
|
||||
'3',
|
||||
['SD_BUS_ERROR_ACCESS_DENIED',
|
||||
@ -998,10 +997,6 @@ manpages = [
|
||||
['systemd-import-generator', '8', [], ''],
|
||||
['systemd-importd.service', '8', ['systemd-importd'], 'ENABLE_IMPORTD'],
|
||||
['systemd-inhibit', '1', [], ''],
|
||||
['systemd-initctl.service',
|
||||
'8',
|
||||
['systemd-initctl', 'systemd-initctl.socket'],
|
||||
'HAVE_SYSV_COMPAT'],
|
||||
['systemd-integritysetup-generator', '8', [], 'HAVE_LIBCRYPTSETUP'],
|
||||
['systemd-integritysetup@.service',
|
||||
'8',
|
||||
@ -1190,10 +1185,7 @@ manpages = [
|
||||
'systemd-udevd-varlink.socket'],
|
||||
''],
|
||||
['systemd-update-done.service', '8', ['systemd-update-done'], ''],
|
||||
['systemd-update-utmp.service',
|
||||
'8',
|
||||
['systemd-update-utmp', 'systemd-update-utmp-runlevel.service'],
|
||||
'ENABLE_UTMP'],
|
||||
['systemd-update-utmp.service', '8', ['systemd-update-utmp'], 'ENABLE_UTMP'],
|
||||
['systemd-user-sessions.service', '8', ['systemd-user-sessions'], 'HAVE_PAM'],
|
||||
['systemd-userdbd.service', '8', ['systemd-userdbd'], 'ENABLE_USERDB'],
|
||||
['systemd-validatefs@.service', '8', [], 'HAVE_BLKID'],
|
||||
@ -1249,7 +1241,6 @@ manpages = [
|
||||
['sysupdate.d', '5', [], 'ENABLE_SYSUPDATE'],
|
||||
['sysupdate.features', '5', [], 'ENABLE_SYSUPDATE'],
|
||||
['sysusers.d', '5', [], 'ENABLE_SYSUSERS'],
|
||||
['telinit', '8', [], 'HAVE_SYSV_COMPAT'],
|
||||
['timedatectl', '1', [], 'ENABLE_TIMEDATECTL'],
|
||||
['timesyncd.conf', '5', ['timesyncd.conf.d'], 'ENABLE_TIMESYNCD'],
|
||||
['tmpfiles.d', '5', [], ''],
|
||||
|
164
man/runlevel.xml
164
man/runlevel.xml
@ -1,164 +0,0 @@
|
||||
<?xml version='1.0'?> <!--*-nxml-*-->
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
||||
<!-- SPDX-License-Identifier: LGPL-2.1-or-later -->
|
||||
|
||||
<refentry id="runlevel" conditional='HAVE_SYSV_COMPAT'
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
|
||||
<refentryinfo>
|
||||
<title>runlevel</title>
|
||||
<productname>systemd</productname>
|
||||
</refentryinfo>
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>runlevel</refentrytitle>
|
||||
<manvolnum>8</manvolnum>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>runlevel</refname>
|
||||
<refpurpose>Print previous and current SysV runlevel</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<cmdsynopsis>
|
||||
<command>runlevel</command>
|
||||
<arg choice="opt" rep="repeat">options</arg>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1>
|
||||
<title>Overview</title>
|
||||
|
||||
<para>"Runlevels" are an obsolete way to start and stop groups of
|
||||
services used in SysV init. systemd provides a compatibility layer
|
||||
that maps runlevels to targets, and associated binaries like
|
||||
<command>runlevel</command>. Nevertheless, only one runlevel can
|
||||
be "active" at a given time, while systemd can activate multiple
|
||||
targets concurrently, so the mapping to runlevels is confusing
|
||||
and only approximate. Runlevels should not be used in new code,
|
||||
and are mostly useful as a shorthand way to refer the matching
|
||||
systemd targets in kernel boot parameters.</para>
|
||||
|
||||
<table>
|
||||
<title>Mapping between runlevels and systemd targets</title>
|
||||
<tgroup cols='2' align='left' colsep='1' rowsep='1'>
|
||||
<colspec colname="runlevel" />
|
||||
<colspec colname="target" />
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Runlevel</entry>
|
||||
<entry>Target</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>0</entry>
|
||||
<entry><filename>poweroff.target</filename></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>1</entry>
|
||||
<entry><filename>rescue.target</filename></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>2, 3, 4</entry>
|
||||
<entry><filename>multi-user.target</filename></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>5</entry>
|
||||
<entry><filename>graphical.target</filename></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>6</entry>
|
||||
<entry><filename>reboot.target</filename></entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<para><command>runlevel</command> prints the previous and current
|
||||
SysV runlevel if they are known.</para>
|
||||
|
||||
<para>The two runlevel characters are separated by a single space
|
||||
character. If a runlevel cannot be determined, N is printed
|
||||
instead. If neither can be determined, the word "unknown" is
|
||||
printed.</para>
|
||||
|
||||
<para>Unless overridden in the environment, this will check the
|
||||
utmp database for recent runlevel changes.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Options</title>
|
||||
|
||||
<para>The following option is understood:</para>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><option>--help</option></term>
|
||||
|
||||
<xi:include href="standard-options.xml" xpointer="help-text" />
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Exit status</title>
|
||||
|
||||
<para>If one or both runlevels could be determined, 0 is returned,
|
||||
a non-zero failure code otherwise.</para>
|
||||
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Environment</title>
|
||||
|
||||
<variablelist class='environment-variables'>
|
||||
<varlistentry>
|
||||
<term><varname>$RUNLEVEL</varname></term>
|
||||
|
||||
<listitem><para>If <varname>$RUNLEVEL</varname> is set,
|
||||
<command>runlevel</command> will print this value as current
|
||||
runlevel and ignore utmp.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>$PREVLEVEL</varname></term>
|
||||
|
||||
<listitem><para>If <varname>$PREVLEVEL</varname> is set,
|
||||
<command>runlevel</command> will print this value as previous
|
||||
runlevel and ignore utmp.</para></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Files</title>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><filename>/run/utmp</filename></term>
|
||||
|
||||
<listitem><para>The utmp database <command>runlevel</command> reads the previous and current runlevel
|
||||
from.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v237"/></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>See Also</title>
|
||||
<para><simplelist type="inline">
|
||||
<member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
||||
<member><citerefentry><refentrytitle>systemd.target</refentrytitle><manvolnum>5</manvolnum></citerefentry></member>
|
||||
<member><citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
||||
</simplelist></para>
|
||||
</refsect1>
|
||||
</refentry>
|
@ -527,6 +527,18 @@
|
||||
<xi:include href="version-info.xml" xpointer="v240"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>LoaderTpm2ActivePcrBanks</varname></term>
|
||||
|
||||
<listitem><para>Hexadecimal string representation of a bitmask with values defined by the TCG EFI
|
||||
Protocol Specification for TPM 2.0 as EFI_TCG2_BOOT_HASH_ALG_*. If no TPM2 support or no active
|
||||
banks were detected, will be set to <constant>0</constant>. Set by the boot loader. Use
|
||||
<citerefentry><refentrytitle>systemd-analyze</refentrytitle><manvolnum>1</manvolnum></citerefentry>
|
||||
to view this data.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v258"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>LoaderImageIdentifier</varname></term>
|
||||
|
||||
|
@ -1,49 +0,0 @@
|
||||
<?xml version='1.0'?> <!--*-nxml-*-->
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
||||
<!-- SPDX-License-Identifier: LGPL-2.1-or-later -->
|
||||
|
||||
<refentry id="systemd-initctl.service" conditional='HAVE_SYSV_COMPAT'>
|
||||
|
||||
<refentryinfo>
|
||||
<title>systemd-initctl.service</title>
|
||||
<productname>systemd</productname>
|
||||
</refentryinfo>
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>systemd-initctl.service</refentrytitle>
|
||||
<manvolnum>8</manvolnum>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>systemd-initctl.service</refname>
|
||||
<refname>systemd-initctl.socket</refname>
|
||||
<refname>systemd-initctl</refname>
|
||||
<refpurpose>/dev/initctl compatibility</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<para><filename>systemd-initctl.service</filename></para>
|
||||
<para><filename>systemd-initctl.socket</filename></para>
|
||||
<para><filename>/usr/lib/systemd/systemd-initctl</filename></para>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<para><filename>systemd-initctl</filename> is a system service
|
||||
that implements compatibility with the
|
||||
<filename>/dev/initctl</filename> FIFO file system object, as
|
||||
implemented by the SysV init system.
|
||||
<filename>systemd-initctl</filename> is automatically activated on
|
||||
request and terminates itself when it is unused.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>See Also</title>
|
||||
<para><simplelist type="inline">
|
||||
<member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
||||
</simplelist></para>
|
||||
</refsect1>
|
||||
|
||||
</refentry>
|
@ -544,6 +544,18 @@
|
||||
<xi:include href="version-info.xml" xpointer="v250"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>LoaderTpm2ActivePcrBanks</varname></term>
|
||||
|
||||
<listitem><para>Hexadecimal string representation of a bitmask with values defined by the TCG EFI
|
||||
Protocol Specification for TPM 2.0 as EFI_TCG2_BOOT_HASH_ALG_*. If no TPM2 support or no active
|
||||
banks were detected, will be set to <constant>0</constant>. Set by the boot loader. Use
|
||||
<citerefentry><refentrytitle>systemd-analyze</refentrytitle><manvolnum>1</manvolnum></citerefentry>
|
||||
to view this data.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v258"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>LoaderImageIdentifier</varname></term>
|
||||
|
||||
|
@ -49,10 +49,6 @@
|
||||
<para>Note that compatibility is quite comprehensive but not 100%, for more details see <ulink
|
||||
url="https://systemd.io/INCOMPATIBILITIES">Compatibility with SysV</ulink>.</para>
|
||||
|
||||
<para>SysV runlevels have corresponding systemd targets
|
||||
(<filename>runlevel<replaceable>X</replaceable>.target</filename>). The wrapper unit that is generated
|
||||
will be wanted by those targets which correspond to runlevels for which the script is enabled.</para>
|
||||
|
||||
<para><command>systemd</command> does not support SysV scripts as part of early boot, so all wrapper
|
||||
units are ordered after <filename>basic.target</filename>.</para>
|
||||
|
||||
|
@ -17,26 +17,21 @@
|
||||
|
||||
<refnamediv>
|
||||
<refname>systemd-update-utmp.service</refname>
|
||||
<refname>systemd-update-utmp-runlevel.service</refname>
|
||||
<refname>systemd-update-utmp</refname>
|
||||
<refpurpose>Write audit and utmp updates at bootup, runlevel
|
||||
changes and shutdown</refpurpose>
|
||||
<refpurpose>Write audit and utmp updates at bootup and shutdown</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<para><filename>systemd-update-utmp.service</filename></para>
|
||||
<para><filename>systemd-update-utmp-runlevel.service</filename></para>
|
||||
<para><filename>/usr/lib/systemd/systemd-update-utmp</filename></para>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<para><filename>systemd-update-utmp-runlevel.service</filename> is
|
||||
a service that writes SysV runlevel changes to utmp and wtmp, as
|
||||
well as the audit logs, as they occur.
|
||||
<filename>systemd-update-utmp.service</filename> does the same for
|
||||
system reboots and shutdown requests.</para>
|
||||
<para>
|
||||
<filename>systemd-update-utmp.service</filename> is a service that writes system reboots and shutdown
|
||||
requests to utmp and wtmp, as well as the audit logs.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
|
@ -73,10 +73,6 @@
|
||||
<filename>remote-fs.target</filename>,
|
||||
<filename>rescue.target</filename>,
|
||||
<filename>rpcbind.target</filename>,
|
||||
<filename>runlevel2.target</filename>,
|
||||
<filename>runlevel3.target</filename>,
|
||||
<filename>runlevel4.target</filename>,
|
||||
<filename>runlevel5.target</filename>,
|
||||
<filename>shutdown.target</filename>,
|
||||
<filename>sigpwr.target</filename>,
|
||||
<filename>sleep.target</filename>,
|
||||
@ -627,9 +623,6 @@
|
||||
<citerefentry><refentrytitle>systemd-logind</refentrytitle><manvolnum>8</manvolnum></citerefentry>'s
|
||||
<command>org.freedesktop.login1.Manager.PowerOff</command> D-Bus method
|
||||
directly.</para>
|
||||
|
||||
<para><filename>runlevel0.target</filename> is an alias for
|
||||
this target unit, for compatibility with SysV.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
@ -646,9 +639,6 @@
|
||||
<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>
|
||||
@ -707,28 +697,11 @@
|
||||
<filename>multi-user.target</filename>, this target could be seen as
|
||||
<filename>single-user.target</filename>.</para>
|
||||
|
||||
<para><filename>runlevel1.target</filename> is an alias for this target unit, for
|
||||
compatibility with SysV.</para>
|
||||
|
||||
<para>Use the <literal>systemd.unit=rescue.target</literal> kernel command line option
|
||||
to boot into this mode. A short alias for this kernel command line option is
|
||||
<literal>1</literal>, for compatibility with SysV.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><filename>runlevel2.target</filename></term>
|
||||
<term><filename>runlevel3.target</filename></term>
|
||||
<term><filename>runlevel4.target</filename></term>
|
||||
<term><filename>runlevel5.target</filename></term>
|
||||
<listitem>
|
||||
<para>These are targets that are called whenever the SysV
|
||||
compatibility code asks for runlevel 2, 3, 4, 5,
|
||||
respectively. It is a good idea to make this an alias for
|
||||
(i.e. symlink to) <filename>graphical.target</filename>
|
||||
(for runlevel 5) or <filename>multi-user.target</filename>
|
||||
(the others).</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><filename>shutdown.target</filename></term>
|
||||
<listitem>
|
||||
|
@ -45,10 +45,7 @@
|
||||
for examples and descriptions of standard systemd targets.</para>
|
||||
|
||||
<para>Target units provide a more flexible replacement for SysV runlevels in the classic SysV init
|
||||
system. For compatibility reasons special target units such as <filename>runlevel3.target</filename>
|
||||
exist which are used by the SysV runlevel compatibility code in systemd, see
|
||||
<citerefentry><refentrytitle>systemd.special</refentrytitle><manvolnum>7</manvolnum></citerefentry> for
|
||||
details.</para>
|
||||
system.</para>
|
||||
|
||||
<para>Note that a target unit file must not be empty, lest it be considered a masked unit. It is
|
||||
recommended to provide a [Unit] section which includes informative <varname>Description=</varname> and
|
||||
|
151
man/telinit.xml
151
man/telinit.xml
@ -1,151 +0,0 @@
|
||||
<?xml version='1.0'?> <!--*-nxml-*-->
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
||||
<!-- SPDX-License-Identifier: LGPL-2.1-or-later -->
|
||||
|
||||
<refentry id="telinit" conditional='HAVE_SYSV_COMPAT'
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
|
||||
<refentryinfo>
|
||||
<title>telinit</title>
|
||||
<productname>systemd</productname>
|
||||
</refentryinfo>
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>telinit</refentrytitle>
|
||||
<manvolnum>8</manvolnum>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>telinit</refname>
|
||||
<refpurpose>Change SysV runlevel</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<cmdsynopsis>
|
||||
<command>telinit</command> <arg choice="opt" rep="repeat">OPTIONS</arg> <arg choice="req">COMMAND</arg>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<para><command>telinit</command> may be used to change the SysV
|
||||
system runlevel. Since the concept of SysV runlevels is obsolete
|
||||
the runlevel requests will be transparently translated into
|
||||
systemd unit activation requests.</para>
|
||||
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Options</title>
|
||||
|
||||
<para>The following options are understood:</para>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><option>--help</option></term>
|
||||
|
||||
<xi:include href="standard-options.xml" xpointer="help-text" />
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--no-wall</option></term>
|
||||
|
||||
<listitem><para>Do not send wall message before
|
||||
reboot/halt/power-off.</para></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
|
||||
<para>The following commands are understood:</para>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><command>0</command></term>
|
||||
|
||||
<listitem><para>Power-off the machine. This is translated into
|
||||
an activation request for <filename>poweroff.target</filename>
|
||||
and is equivalent to <command>systemctl
|
||||
poweroff</command>.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><command>6</command></term>
|
||||
|
||||
<listitem><para>Reboot the machine. This is translated into an
|
||||
activation request for <filename>reboot.target</filename> and
|
||||
is equivalent to <command>systemctl
|
||||
reboot</command>.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><command>2</command></term>
|
||||
<term><command>3</command></term>
|
||||
<term><command>4</command></term>
|
||||
<term><command>5</command></term>
|
||||
|
||||
<listitem><para>Change the SysV runlevel. This is translated
|
||||
into an activation request for
|
||||
<filename>runlevel2.target</filename>,
|
||||
<filename>runlevel3.target</filename>, … and is equivalent
|
||||
to <command>systemctl isolate runlevel2.target</command>,
|
||||
<command>systemctl isolate runlevel3.target</command>,
|
||||
…</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><command>1</command></term>
|
||||
<term><command>s</command></term>
|
||||
<term><command>S</command></term>
|
||||
|
||||
<listitem><para>Change into system rescue mode. This is
|
||||
translated into an activation request for
|
||||
<filename>rescue.target</filename> and is equivalent to
|
||||
<command>systemctl rescue</command>.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><command>q</command></term>
|
||||
<term><command>Q</command></term>
|
||||
|
||||
<listitem><para>Reload daemon configuration. This is
|
||||
equivalent to <command>systemctl
|
||||
daemon-reload</command>.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><command>u</command></term>
|
||||
<term><command>U</command></term>
|
||||
|
||||
<listitem><para>Serialize state, reexecute daemon and
|
||||
deserialize state again. This is equivalent to
|
||||
<command>systemctl daemon-reexec</command>.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Exit status</title>
|
||||
|
||||
<para>On success, 0 is returned, a non-zero failure
|
||||
code otherwise.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Notes</title>
|
||||
|
||||
<para>This is a legacy command available for compatibility only.
|
||||
It should not be used anymore, as the concept of runlevels is
|
||||
obsolete.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>See Also</title>
|
||||
<para><simplelist type="inline">
|
||||
<member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
||||
<member><citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
||||
<member><citerefentry project='man-pages'><refentrytitle>wall</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
||||
</simplelist></para>
|
||||
</refsect1>
|
||||
</refentry>
|
@ -344,6 +344,7 @@ conf.set10('ENABLE_FIRST_BOOT_FULL_PRESET', get_option('first-
|
||||
cc = meson.get_compiler('c')
|
||||
userspace_c_args = []
|
||||
userspace_c_ld_args = []
|
||||
userspace_sources = []
|
||||
meson_build_sh = find_program('tools/meson-build.sh')
|
||||
|
||||
want_tests = get_option('tests')
|
||||
@ -1963,9 +1964,7 @@ endif
|
||||
|
||||
#####################################################################
|
||||
|
||||
if get_option('b_coverage')
|
||||
userspace_c_args += ['-include', 'coverage.h']
|
||||
endif
|
||||
subdir('src/coverage')
|
||||
|
||||
#####################################################################
|
||||
|
||||
@ -1980,7 +1979,7 @@ jinja2_cmdline = [meson_render_jinja2, config_h]
|
||||
userspace = declare_dependency(
|
||||
compile_args : userspace_c_args,
|
||||
link_args : userspace_c_ld_args,
|
||||
sources : version_h,
|
||||
sources : userspace_sources,
|
||||
)
|
||||
|
||||
man_page_depends = []
|
||||
@ -2319,7 +2318,6 @@ subdir('src/hostname')
|
||||
subdir('src/hwdb')
|
||||
subdir('src/id128')
|
||||
subdir('src/import')
|
||||
subdir('src/initctl')
|
||||
subdir('src/integritysetup')
|
||||
subdir('src/journal')
|
||||
subdir('src/journal-remote')
|
||||
|
@ -5,5 +5,5 @@ Environment=
|
||||
GIT_URL=https://salsa.debian.org/systemd-team/systemd.git
|
||||
GIT_SUBDIR=debian
|
||||
GIT_BRANCH=debian/master
|
||||
GIT_COMMIT=cc380fbc8af2e17165623d16630b7fc3ab4291d0
|
||||
GIT_COMMIT=a8ad8e30e70c0b82ecb8fe016f2dde3a084236f0
|
||||
PKG_SUBDIR=debian
|
||||
|
@ -19,9 +19,10 @@ TS="${SOURCE_DATE_EPOCH:-$(date +%s)}"
|
||||
# disable manpage compression as the files cannot be found. Fix the issue by removing the compression
|
||||
# extension.
|
||||
#
|
||||
# TODO: remove manual cgroups-agent and pubring patches when the upstream spec is updated
|
||||
# TODO: remove patches for removal of cgroups-agent, renaming pubring file, and removal of sysv files
|
||||
# when the upstream spec is updated
|
||||
while read -r filelist; do
|
||||
sed 's/\.gz$//; /systemd-cgroups-agent/d; s/import-pubring.gpg/import-pubring.pgp/' "$filelist" >"/tmp/$(basename "$filelist")"
|
||||
sed -E 's/\.gz$//; /systemd-cgroups-agent/d; s/import-pubring.gpg/import-pubring.pgp/; /(initctl|runlevel|telinit)/ d' "$filelist" >"/tmp/$(basename "$filelist")"
|
||||
mount --bind "/tmp/$(basename "$filelist")" "$filelist"
|
||||
done < <(find "pkg/$PKG_SUBDIR${GIT_SUBDIR:+/$GIT_SUBDIR}" -name "files.*")
|
||||
|
||||
|
@ -2849,6 +2849,7 @@ static void export_loader_variables(
|
||||
EFI_LOADER_FEATURE_REPORT_URL |
|
||||
EFI_LOADER_FEATURE_TYPE1_UKI |
|
||||
EFI_LOADER_FEATURE_TYPE1_UKI_URL |
|
||||
EFI_LOADER_FEATURE_TPM2_ACTIVE_PCR_BANKS |
|
||||
0;
|
||||
|
||||
assert(loaded_image);
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include "device-path-util.h"
|
||||
#include "efi-efivars.h"
|
||||
#include "export-vars.h"
|
||||
#include "measure.h"
|
||||
#include "part-discovery.h"
|
||||
#include "url-discovery.h"
|
||||
#include "util.h"
|
||||
@ -51,4 +52,12 @@ void export_common_variables(EFI_LOADED_IMAGE_PROTOCOL *loaded_image) {
|
||||
s = xasprintf("UEFI %u.%02u", ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff);
|
||||
efivar_set_str16(MAKE_GUID_PTR(LOADER), u"LoaderFirmwareType", s, 0);
|
||||
}
|
||||
|
||||
/* ditto for LoaderTpm2ActivePcrBanks */
|
||||
if (efivar_get_raw(MAKE_GUID_PTR(LOADER), u"LoaderTpm2ActivePcrBanks", NULL, NULL) != EFI_SUCCESS) {
|
||||
uint32_t active_pcr_banks = tpm_get_active_pcr_banks();
|
||||
_cleanup_free_ char16_t *s = NULL;
|
||||
s = xasprintf("0x%08x", active_pcr_banks);
|
||||
efivar_set_str16(MAKE_GUID_PTR(LOADER), u"LoaderTpm2ActivePcrBanks", s, 0);
|
||||
}
|
||||
}
|
||||
|
@ -183,6 +183,24 @@ bool tpm_present(void) {
|
||||
return tcg2_interface_check();
|
||||
}
|
||||
|
||||
uint32_t tpm_get_active_pcr_banks(void) {
|
||||
uint32_t active_pcr_banks = 0;
|
||||
EFI_TCG2_PROTOCOL *tpm2;
|
||||
EFI_STATUS err;
|
||||
|
||||
tpm2 = tcg2_interface_check();
|
||||
if (!tpm2)
|
||||
return 0;
|
||||
|
||||
err = tpm2->GetActivePcrBanks(tpm2, &active_pcr_banks);
|
||||
if (err != EFI_SUCCESS) {
|
||||
log_warning_status(err, "Failed to get TPM2 active PCR banks, assuming none: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return active_pcr_banks;
|
||||
}
|
||||
|
||||
static EFI_STATUS tcg2_log_ipl_event(uint32_t pcrindex, EFI_PHYSICAL_ADDRESS buffer, size_t buffer_size, const char16_t *description, bool *ret_measured) {
|
||||
EFI_TCG2_PROTOCOL *tpm2;
|
||||
EFI_STATUS err = EFI_SUCCESS;
|
||||
|
@ -6,6 +6,7 @@
|
||||
#if ENABLE_TPM
|
||||
|
||||
bool tpm_present(void);
|
||||
uint32_t tpm_get_active_pcr_banks(void);
|
||||
|
||||
/* Routines for boot-time TPM PCR measurement as well as submitting an event log entry about it. The latter
|
||||
* can be done with two different event log record types. For old stuff we use EV_IPL (which is legacy, and
|
||||
@ -28,6 +29,10 @@ static inline bool tpm_present(void) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline uint32_t tpm_get_active_pcr_banks(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline EFI_STATUS tpm_log_ipl_event(uint32_t pcrindex, EFI_PHYSICAL_ADDRESS buffer, size_t buffer_size, const char16_t *description, bool *ret_measured) {
|
||||
if (ret_measured)
|
||||
*ret_measured = false;
|
||||
|
@ -79,7 +79,9 @@ struct EFI_TCG2_PROTOCOL {
|
||||
uint64_t DataToHashLen,
|
||||
EFI_TCG2_EVENT *EfiTcgEvent);
|
||||
void *SubmitCommand;
|
||||
void *GetActivePcrBanks;
|
||||
EFI_STATUS (EFIAPI *GetActivePcrBanks)(
|
||||
EFI_TCG2_PROTOCOL *This,
|
||||
uint32_t *ActivePcrBanks);
|
||||
void *SetActivePcrBanks;
|
||||
void *GetResultOfSetActivePcrBanks;
|
||||
};
|
||||
|
@ -413,6 +413,7 @@ int verb_status(int argc, char *argv[], void *userdata) {
|
||||
{ EFI_LOADER_FEATURE_REPORT_URL, "Loader reports network boot URL" },
|
||||
{ EFI_LOADER_FEATURE_TYPE1_UKI, "Support Type #1 uki field" },
|
||||
{ EFI_LOADER_FEATURE_TYPE1_UKI_URL, "Support Type #1 uki-url field" },
|
||||
{ EFI_LOADER_FEATURE_TPM2_ACTIVE_PCR_BANKS, "Loader reports TPM2 active PCR banks" },
|
||||
};
|
||||
static const struct {
|
||||
uint64_t flag;
|
||||
|
@ -1591,23 +1591,6 @@ static int fixup_environment(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void redirect_telinit(int argc, char *argv[]) {
|
||||
|
||||
/* This is compatibility support for SysV, where calling init as a user is identical to telinit. */
|
||||
|
||||
#if HAVE_SYSV_COMPAT
|
||||
if (getpid_cached() == 1)
|
||||
return;
|
||||
|
||||
if (!invoked_as(argv, "init"))
|
||||
return;
|
||||
|
||||
execv(SYSTEMCTL_BINARY_PATH, argv);
|
||||
log_error_errno(errno, "Failed to execute %s: %m", SYSTEMCTL_BINARY_PATH);
|
||||
exit(EXIT_FAILURE);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int become_shutdown(int objective, int retval) {
|
||||
static const char* const table[_MANAGER_OBJECTIVE_MAX] = {
|
||||
[MANAGER_EXIT] = "exit",
|
||||
@ -3041,9 +3024,6 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
assert_se(argc > 0 && !isempty(argv[0]));
|
||||
|
||||
/* SysV compatibility: redirect init → telinit */
|
||||
redirect_telinit(argc, argv);
|
||||
|
||||
/* Take timestamps early on */
|
||||
dual_timestamp_from_monotonic(&kernel_timestamp, 0);
|
||||
dual_timestamp_now(&userspace_timestamp);
|
||||
|
6
src/coverage/meson.build
Normal file
6
src/coverage/meson.build
Normal file
@ -0,0 +1,6 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
if get_option('b_coverage')
|
||||
userspace_c_args += ['-include', meson.current_source_dir() / 'coverage.h']
|
||||
userspace_sources += files('coverage.h')
|
||||
endif
|
@ -27,6 +27,7 @@
|
||||
#define EFI_LOADER_FEATURE_REPORT_URL (UINT64_C(1) << 15)
|
||||
#define EFI_LOADER_FEATURE_TYPE1_UKI (UINT64_C(1) << 16)
|
||||
#define EFI_LOADER_FEATURE_TYPE1_UKI_URL (UINT64_C(1) << 17)
|
||||
#define EFI_LOADER_FEATURE_TPM2_ACTIVE_PCR_BANKS (UINT64_C(1) << 18)
|
||||
|
||||
/* Features of the stub, i.e. systemd-stub */
|
||||
#define EFI_STUB_FEATURE_REPORT_BOOT_PARTITION (UINT64_C(1) << 0)
|
||||
|
@ -1,351 +0,0 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <ctype.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "sd-bus.h"
|
||||
#include "sd-daemon.h"
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "bus-error.h"
|
||||
#include "bus-locator.h"
|
||||
#include "bus-util.h"
|
||||
#include "constants.h"
|
||||
#include "daemon-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "initreq.h"
|
||||
#include "list.h"
|
||||
#include "log.h"
|
||||
#include "main-func.h"
|
||||
#include "reboot-util.h"
|
||||
#include "special.h"
|
||||
#include "time-util.h"
|
||||
|
||||
#define SERVER_FD_MAX 16
|
||||
#define TIMEOUT_MSEC ((int) (DEFAULT_EXIT_USEC/USEC_PER_MSEC))
|
||||
|
||||
typedef struct Fifo Fifo;
|
||||
|
||||
typedef struct Server {
|
||||
int epoll_fd;
|
||||
|
||||
LIST_HEAD(Fifo, fifos);
|
||||
unsigned n_fifos;
|
||||
|
||||
sd_bus *bus;
|
||||
|
||||
bool quit;
|
||||
} Server;
|
||||
|
||||
struct Fifo {
|
||||
Server *server;
|
||||
|
||||
int fd;
|
||||
|
||||
struct init_request buffer;
|
||||
size_t bytes_read;
|
||||
|
||||
LIST_FIELDS(Fifo, fifo);
|
||||
};
|
||||
|
||||
static const char *translate_runlevel(int runlevel, bool *isolate) {
|
||||
static const struct {
|
||||
const int runlevel;
|
||||
const char *special;
|
||||
bool isolate;
|
||||
} table[] = {
|
||||
{ '0', SPECIAL_POWEROFF_TARGET, false },
|
||||
{ '1', SPECIAL_RESCUE_TARGET, true },
|
||||
{ 's', SPECIAL_RESCUE_TARGET, true },
|
||||
{ 'S', SPECIAL_RESCUE_TARGET, true },
|
||||
{ '2', SPECIAL_MULTI_USER_TARGET, true },
|
||||
{ '3', SPECIAL_MULTI_USER_TARGET, true },
|
||||
{ '4', SPECIAL_MULTI_USER_TARGET, true },
|
||||
{ '5', SPECIAL_GRAPHICAL_TARGET, true },
|
||||
{ '6', SPECIAL_REBOOT_TARGET, false },
|
||||
};
|
||||
|
||||
assert(isolate);
|
||||
|
||||
FOREACH_ELEMENT(i, table)
|
||||
if (i->runlevel == runlevel) {
|
||||
*isolate = i->isolate;
|
||||
if (runlevel == '6' && kexec_loaded())
|
||||
return SPECIAL_KEXEC_TARGET;
|
||||
return i->special;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int change_runlevel(Server *s, int runlevel) {
|
||||
const char *target;
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
const char *mode;
|
||||
bool isolate = false;
|
||||
int r;
|
||||
|
||||
assert(s);
|
||||
|
||||
target = translate_runlevel(runlevel, &isolate);
|
||||
if (!target) {
|
||||
log_warning("Got request for unknown runlevel %c, ignoring.", runlevel);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (isolate)
|
||||
mode = "isolate";
|
||||
else
|
||||
mode = "replace-irreversibly";
|
||||
|
||||
log_debug("Requesting %s/start/%s", target, mode);
|
||||
|
||||
r = bus_call_method(s->bus, bus_systemd_mgr, "StartUnit", &error, NULL, "ss", target, mode);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to change runlevel: %s", bus_error_message(&error, r));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void request_process(Server *s, const struct init_request *req) {
|
||||
assert(s);
|
||||
assert(req);
|
||||
|
||||
if (req->magic != INIT_MAGIC) {
|
||||
log_error("Got initctl request with invalid magic. Ignoring.");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (req->cmd) {
|
||||
|
||||
case INIT_CMD_RUNLVL:
|
||||
if (!isprint(req->runlevel))
|
||||
log_error("Got invalid runlevel. Ignoring.");
|
||||
else
|
||||
switch (req->runlevel) {
|
||||
|
||||
/* we are async anyway, so just use kill for reexec/reload */
|
||||
case 'u':
|
||||
case 'U':
|
||||
if (kill(1, SIGTERM) < 0)
|
||||
log_error_errno(errno, "kill() failed: %m");
|
||||
|
||||
/* The bus connection will be
|
||||
* terminated if PID 1 is reexecuted,
|
||||
* hence let's just exit here, and
|
||||
* rely on that we'll be restarted on
|
||||
* the next request */
|
||||
s->quit = true;
|
||||
break;
|
||||
|
||||
case 'q':
|
||||
case 'Q':
|
||||
if (kill(1, SIGHUP) < 0)
|
||||
log_error_errno(errno, "kill() failed: %m");
|
||||
break;
|
||||
|
||||
default:
|
||||
(void) change_runlevel(s, req->runlevel);
|
||||
}
|
||||
return;
|
||||
|
||||
case INIT_CMD_POWERFAIL:
|
||||
case INIT_CMD_POWERFAILNOW:
|
||||
case INIT_CMD_POWEROK:
|
||||
log_warning("Received UPS/power initctl request. This is not implemented in systemd. Upgrade your UPS daemon!");
|
||||
return;
|
||||
|
||||
case INIT_CMD_CHANGECONS:
|
||||
log_warning("Received console change initctl request. This is not implemented in systemd.");
|
||||
return;
|
||||
|
||||
case INIT_CMD_SETENV:
|
||||
case INIT_CMD_UNSETENV:
|
||||
log_warning("Received environment initctl request. This is not implemented in systemd.");
|
||||
return;
|
||||
|
||||
default:
|
||||
log_warning("Received unknown initctl request. Ignoring.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static int fifo_process(Fifo *f) {
|
||||
ssize_t l;
|
||||
|
||||
assert(f);
|
||||
|
||||
errno = EIO;
|
||||
l = read(f->fd,
|
||||
((uint8_t*) &f->buffer) + f->bytes_read,
|
||||
sizeof(f->buffer) - f->bytes_read);
|
||||
if (l <= 0) {
|
||||
if (errno == EAGAIN)
|
||||
return 0;
|
||||
|
||||
return log_warning_errno(errno, "Failed to read from fifo: %m");
|
||||
}
|
||||
|
||||
f->bytes_read += l;
|
||||
assert(f->bytes_read <= sizeof(f->buffer));
|
||||
|
||||
if (f->bytes_read == sizeof(f->buffer)) {
|
||||
request_process(f->server, &f->buffer);
|
||||
f->bytes_read = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Fifo* fifo_free(Fifo *f) {
|
||||
if (!f)
|
||||
return NULL;
|
||||
|
||||
if (f->server) {
|
||||
assert(f->server->n_fifos > 0);
|
||||
f->server->n_fifos--;
|
||||
LIST_REMOVE(fifo, f->server->fifos, f);
|
||||
}
|
||||
|
||||
if (f->fd >= 0) {
|
||||
if (f->server)
|
||||
(void) epoll_ctl(f->server->epoll_fd, EPOLL_CTL_DEL, f->fd, NULL);
|
||||
|
||||
safe_close(f->fd);
|
||||
}
|
||||
|
||||
return mfree(f);
|
||||
}
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(Fifo*, fifo_free);
|
||||
|
||||
static void server_done(Server *s) {
|
||||
assert(s);
|
||||
|
||||
while (s->fifos)
|
||||
fifo_free(s->fifos);
|
||||
|
||||
s->epoll_fd = safe_close(s->epoll_fd);
|
||||
s->bus = sd_bus_flush_close_unref(s->bus);
|
||||
}
|
||||
|
||||
static int server_init(Server *s, unsigned n_sockets) {
|
||||
int r;
|
||||
|
||||
/* This function will leave s partially initialized on failure. Caller needs to clean up. */
|
||||
|
||||
assert(s);
|
||||
assert(n_sockets > 0);
|
||||
|
||||
s->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
|
||||
if (s->epoll_fd < 0)
|
||||
return log_error_errno(errno, "Failed to create epoll object: %m");
|
||||
|
||||
for (unsigned i = 0; i < n_sockets; i++) {
|
||||
_cleanup_(fifo_freep) Fifo *f = NULL;
|
||||
int fd = SD_LISTEN_FDS_START + i;
|
||||
|
||||
r = sd_is_fifo(fd, NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to determine file descriptor type: %m");
|
||||
if (!r)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Wrong file descriptor type.");
|
||||
|
||||
f = new0(Fifo, 1);
|
||||
if (!f)
|
||||
return log_oom();
|
||||
|
||||
struct epoll_event ev = {
|
||||
.events = EPOLLIN,
|
||||
.data.ptr = f,
|
||||
};
|
||||
|
||||
if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0)
|
||||
return log_error_errno(errno, "Failed to add fifo fd to epoll object: %m");
|
||||
|
||||
f->fd = fd;
|
||||
f->server = s;
|
||||
LIST_PREPEND(fifo, s->fifos, TAKE_PTR(f));
|
||||
s->n_fifos++;
|
||||
}
|
||||
|
||||
r = bus_connect_system_systemd(&s->bus);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to get D-Bus connection: %m");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int process_event(Server *s, struct epoll_event *ev) {
|
||||
int r;
|
||||
_cleanup_(fifo_freep) Fifo *f = NULL;
|
||||
|
||||
assert(s);
|
||||
assert(ev);
|
||||
|
||||
if (!(ev->events & EPOLLIN))
|
||||
return log_info_errno(SYNTHETIC_ERRNO(EIO),
|
||||
"Got invalid event from epoll. (3)");
|
||||
|
||||
f = (Fifo*) ev->data.ptr;
|
||||
r = fifo_process(f);
|
||||
if (r < 0)
|
||||
return log_info_errno(r, "Got error on fifo: %m");
|
||||
|
||||
TAKE_PTR(f);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int run(int argc, char *argv[]) {
|
||||
_cleanup_(server_done) Server server = { .epoll_fd = -EBADF };
|
||||
_unused_ _cleanup_(notify_on_cleanup) const char *notify_stop = NULL;
|
||||
int r, n;
|
||||
|
||||
if (argc > 1)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"This program does not take arguments.");
|
||||
|
||||
log_setup();
|
||||
|
||||
umask(0022);
|
||||
|
||||
n = sd_listen_fds(true);
|
||||
if (n < 0)
|
||||
return log_error_errno(n, "Failed to read listening file descriptors from environment: %m");
|
||||
|
||||
if (n <= 0 || n > SERVER_FD_MAX)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"No or too many file descriptors passed.");
|
||||
|
||||
r = server_init(&server, (unsigned) n);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
notify_stop = notify_start(NOTIFY_READY_MESSAGE, NOTIFY_STOPPING_MESSAGE);
|
||||
|
||||
while (!server.quit) {
|
||||
struct epoll_event event;
|
||||
int k;
|
||||
|
||||
k = epoll_wait(server.epoll_fd, &event, 1, TIMEOUT_MSEC);
|
||||
if (k < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
return log_error_errno(errno, "epoll_wait() failed: %m");
|
||||
}
|
||||
if (k == 0)
|
||||
break;
|
||||
|
||||
r = process_event(&server, &event);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_MAIN_FUNCTION(run);
|
@ -1,9 +0,0 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
executables += [
|
||||
libexec_template + {
|
||||
'name' : 'systemd-initctl',
|
||||
'conditions' : ['HAVE_SYSV_COMPAT'],
|
||||
'sources' : files('initctl.c'),
|
||||
},
|
||||
]
|
@ -10,6 +10,7 @@
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "log.h"
|
||||
#include "parse-util.h"
|
||||
#include "sort-util.h"
|
||||
#include "stat-util.h"
|
||||
#include "stdio-util.h"
|
||||
@ -516,6 +517,27 @@ int efi_get_boot_options(uint16_t **ret_options) {
|
||||
#endif
|
||||
}
|
||||
|
||||
#if ENABLE_EFI
|
||||
static int loader_has_tpm2(void) {
|
||||
_cleanup_free_ char *active_pcr_banks = NULL;
|
||||
uint32_t active_pcr_banks_value;
|
||||
int r;
|
||||
|
||||
r = efi_get_variable_string(EFI_LOADER_VARIABLE_STR("LoaderTpm2ActivePcrBanks"), &active_pcr_banks);
|
||||
if (r < 0) {
|
||||
if (r != -ENOENT)
|
||||
log_debug_errno(r, "Failed to read LoaderTpm2ActivePcrBanks variable: %m");
|
||||
return r;
|
||||
}
|
||||
|
||||
r = safe_atou32_full(active_pcr_banks, 16, &active_pcr_banks_value);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to parse LoaderTpm2ActivePcrBanks variable: %m");
|
||||
|
||||
return active_pcr_banks_value != 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool efi_has_tpm2(void) {
|
||||
#if ENABLE_EFI
|
||||
static int cache = -1;
|
||||
@ -530,9 +552,17 @@ bool efi_has_tpm2(void) {
|
||||
if (!is_efi_boot())
|
||||
return (cache = false);
|
||||
|
||||
/* Secondly, check if the loader told us, as that is the most accurate source of information
|
||||
* regarding the firmware's setup */
|
||||
r = loader_has_tpm2();
|
||||
if (r >= 0)
|
||||
return (cache = r);
|
||||
|
||||
/* Then, check if the ACPI table "TPM2" exists, which is the TPM2 event log table, see:
|
||||
* https://trustedcomputinggroup.org/wp-content/uploads/TCG_ACPIGeneralSpecification_v1.20_r8.pdf
|
||||
* This table exists whenever the firmware knows ACPI and is hooked up to TPM2. */
|
||||
* This table exists whenever the firmware knows ACPI and is hooked up to TPM2.
|
||||
* Note that in some cases, for example with EDK2 2025.2 with the default arm64 config, this ACPI
|
||||
* table is present even if TPM2 support is not enabled in the firmware. */
|
||||
if (access("/sys/firmware/acpi/tables/TPM2", F_OK) >= 0)
|
||||
return (cache = true);
|
||||
if (errno != ENOENT)
|
||||
|
@ -1,59 +0,0 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (C) 1995-2004 Miquel van Smoorenburg
|
||||
* Version: @(#)initreq.h 1.28 31-Mar-2004 MvS
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "forward.h"
|
||||
|
||||
#if defined(__FreeBSD_kernel__)
|
||||
# define INIT_FIFO "/etc/.initctl"
|
||||
#else
|
||||
# define INIT_FIFO "/dev/initctl"
|
||||
#endif
|
||||
|
||||
#define INIT_MAGIC 0x03091969
|
||||
#define INIT_CMD_START 0
|
||||
#define INIT_CMD_RUNLVL 1
|
||||
#define INIT_CMD_POWERFAIL 2
|
||||
#define INIT_CMD_POWERFAILNOW 3
|
||||
#define INIT_CMD_POWEROK 4
|
||||
#define INIT_CMD_BSD 5
|
||||
#define INIT_CMD_SETENV 6
|
||||
#define INIT_CMD_UNSETENV 7
|
||||
|
||||
#define INIT_CMD_CHANGECONS 12345
|
||||
/*
|
||||
* This is what BSD 4.4 uses when talking to init.
|
||||
* Linux doesn't use this right now.
|
||||
*/
|
||||
struct init_request_bsd {
|
||||
char gen_id[8]; /* Beats me.. telnetd uses "fe" */
|
||||
char tty_id[16]; /* Tty name minus /dev/tty */
|
||||
char host[HOST_NAME_MAX]; /* Hostname */
|
||||
char term_type[16]; /* Terminal type */
|
||||
int signal; /* Signal to send */
|
||||
int pid; /* Process to send to */
|
||||
char exec_name[128]; /* Program to execute */
|
||||
char reserved[128]; /* For future expansion. */
|
||||
};
|
||||
|
||||
/*
|
||||
* Because of legacy interfaces, "runlevel" and "sleeptime"
|
||||
* aren't in a separate struct in the union.
|
||||
*
|
||||
* The weird sizes are because init expects the whole
|
||||
* struct to be 384 bytes.
|
||||
*/
|
||||
struct init_request {
|
||||
int magic; /* Magic number */
|
||||
int cmd; /* What kind of request */
|
||||
int runlevel; /* Runlevel to change to */
|
||||
int sleeptime; /* Time between TERM and KILL */
|
||||
union {
|
||||
struct init_request_bsd bsd;
|
||||
char data[368];
|
||||
} i;
|
||||
};
|
@ -11,44 +11,6 @@
|
||||
#include "time-util.h"
|
||||
#include "utmp-wtmp.h"
|
||||
|
||||
int utmp_get_runlevel(int *runlevel, int *previous) {
|
||||
_unused_ _cleanup_(utxent_cleanup) bool utmpx = false;
|
||||
struct utmpx *found, lookup = { .ut_type = RUN_LVL };
|
||||
const char *e;
|
||||
|
||||
assert(runlevel);
|
||||
|
||||
/* If these values are set in the environment this takes
|
||||
* precedence. Presumably, sysvinit does this to work around a
|
||||
* race condition that would otherwise exist where we'd always
|
||||
* go to disk and hence might read runlevel data that might be
|
||||
* very new and not apply to the current script being executed. */
|
||||
|
||||
e = getenv("RUNLEVEL");
|
||||
if (!isempty(e)) {
|
||||
*runlevel = e[0];
|
||||
if (previous)
|
||||
*previous = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (utmpxname(UTMPX_FILE) < 0)
|
||||
return -errno;
|
||||
|
||||
utmpx = utxent_start();
|
||||
|
||||
found = getutxid(&lookup);
|
||||
if (!found)
|
||||
return -errno;
|
||||
|
||||
*runlevel = found->ut_pid & 0xFF;
|
||||
if (previous)
|
||||
*previous = (found->ut_pid >> 8) & 0xFF;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void init_timestamp(struct utmpx *store, usec_t t) {
|
||||
assert(store);
|
||||
|
||||
@ -237,33 +199,3 @@ int utmp_put_dead_process(const char *id, pid_t pid, int code, int status) {
|
||||
|
||||
return write_utmp_wtmp(&store, &store_wtmp);
|
||||
}
|
||||
|
||||
int utmp_put_runlevel(int runlevel, int previous) {
|
||||
struct utmpx store = {};
|
||||
int r;
|
||||
|
||||
assert(runlevel > 0);
|
||||
|
||||
if (previous <= 0) {
|
||||
/* Find the old runlevel automatically */
|
||||
|
||||
r = utmp_get_runlevel(&previous, NULL);
|
||||
if (r < 0) {
|
||||
if (r != -ESRCH)
|
||||
return r;
|
||||
|
||||
previous = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (previous == runlevel)
|
||||
return 0;
|
||||
|
||||
init_entry(&store, 0);
|
||||
|
||||
store.ut_type = RUN_LVL;
|
||||
store.ut_pid = (runlevel & 0xFF) | ((previous & 0xFF) << 8);
|
||||
strncpy(store.ut_user, "runlevel", sizeof(store.ut_user));
|
||||
|
||||
return write_entry_both(&store);
|
||||
}
|
||||
|
@ -6,11 +6,8 @@
|
||||
#if ENABLE_UTMP
|
||||
#include <utmpx.h>
|
||||
|
||||
int utmp_get_runlevel(int *runlevel, int *previous);
|
||||
|
||||
int utmp_put_shutdown(void);
|
||||
int utmp_put_reboot(usec_t timestamp);
|
||||
int utmp_put_runlevel(int runlevel, int previous);
|
||||
|
||||
int utmp_put_dead_process(const char *id, pid_t pid, int code, int status);
|
||||
int utmp_put_init_process(const char *id, pid_t pid, pid_t sid, const char *line, int ut_type, const char *user);
|
||||
@ -27,18 +24,12 @@ static inline void utxent_cleanup(bool *initialized) {
|
||||
|
||||
#else /* ENABLE_UTMP */
|
||||
|
||||
static inline int utmp_get_runlevel(int *runlevel, int *previous) {
|
||||
return -ESRCH;
|
||||
}
|
||||
static inline int utmp_put_shutdown(void) {
|
||||
return 0;
|
||||
}
|
||||
static inline int utmp_put_reboot(usec_t timestamp) {
|
||||
return 0;
|
||||
}
|
||||
static inline int utmp_put_runlevel(int runlevel, int previous) {
|
||||
return 0;
|
||||
}
|
||||
static inline int utmp_put_dead_process(const char *id, pid_t pid, int code, int status) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -32,9 +32,7 @@ systemctl_sources = files(
|
||||
)
|
||||
systemctl_extract_sources = files(
|
||||
'systemctl-compat-halt.c',
|
||||
'systemctl-compat-runlevel.c',
|
||||
'systemctl-compat-shutdown.c',
|
||||
'systemctl-compat-telinit.c',
|
||||
'systemctl-daemon-reload.c',
|
||||
'systemctl-logind.c',
|
||||
'systemctl-start-unit.c',
|
||||
@ -74,8 +72,7 @@ executables += [
|
||||
},
|
||||
]
|
||||
|
||||
foreach alias : (['halt', 'poweroff', 'reboot', 'shutdown'] +
|
||||
(conf.get('HAVE_SYSV_COMPAT') == 1 ? ['runlevel', 'telinit'] : []))
|
||||
foreach alias : ['halt', 'poweroff', 'reboot', 'shutdown']
|
||||
install_symlink(alias,
|
||||
pointing_to : sbin_to_bin + 'systemctl',
|
||||
install_dir : sbindir)
|
||||
|
@ -11,7 +11,6 @@
|
||||
#include "reboot-util.h"
|
||||
#include "systemctl.h"
|
||||
#include "systemctl-compat-halt.h"
|
||||
#include "systemctl-compat-telinit.h"
|
||||
#include "systemctl-logind.h"
|
||||
#include "systemctl-start-unit.h"
|
||||
#include "systemctl-util.h"
|
||||
@ -77,16 +76,11 @@ int halt_parse_argv(int argc, char *argv[]) {
|
||||
{}
|
||||
};
|
||||
|
||||
int c, r, runlevel;
|
||||
int c, r;
|
||||
|
||||
assert(argc >= 0);
|
||||
assert(argv);
|
||||
|
||||
/* called in sysvinit system as last command in shutdown/reboot so this is always forceful */
|
||||
if (utmp_get_runlevel(&runlevel, NULL) >= 0)
|
||||
if (IN_SET(runlevel, '0', '6'))
|
||||
arg_force = 2;
|
||||
|
||||
while ((c = getopt_long(argc, argv, "pfwdnih", options, NULL)) >= 0)
|
||||
switch (c) {
|
||||
|
||||
@ -176,7 +170,7 @@ int halt_main(void) {
|
||||
arg_no_block = true;
|
||||
|
||||
if (!arg_dry_run)
|
||||
return start_with_fallback();
|
||||
return verb_start(0, NULL, NULL);
|
||||
}
|
||||
|
||||
r = must_be_root();
|
||||
|
@ -1,81 +0,0 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <getopt.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "log.h"
|
||||
#include "pretty-print.h"
|
||||
#include "systemctl-compat-runlevel.h"
|
||||
#include "utmp-wtmp.h"
|
||||
|
||||
static int runlevel_help(void) {
|
||||
_cleanup_free_ char *link = NULL;
|
||||
int r;
|
||||
|
||||
r = terminal_urlify_man("runlevel", "8", &link);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
printf("%s [OPTIONS...]\n"
|
||||
"\n%sPrints the previous and current runlevel of the init system.%s\n"
|
||||
"\nOptions:\n"
|
||||
" --help Show this help\n"
|
||||
"\nSee the %s for details.\n",
|
||||
program_invocation_short_name,
|
||||
ansi_highlight(),
|
||||
ansi_normal(),
|
||||
link);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int runlevel_parse_argv(int argc, char *argv[]) {
|
||||
enum {
|
||||
ARG_HELP = 0x100,
|
||||
};
|
||||
|
||||
static const struct option options[] = {
|
||||
{ "help", no_argument, NULL, ARG_HELP },
|
||||
{}
|
||||
};
|
||||
|
||||
int c;
|
||||
|
||||
assert(argc >= 0);
|
||||
assert(argv);
|
||||
|
||||
while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0)
|
||||
switch (c) {
|
||||
|
||||
case ARG_HELP:
|
||||
return runlevel_help();
|
||||
|
||||
case '?':
|
||||
return -EINVAL;
|
||||
|
||||
default:
|
||||
assert_not_reached();
|
||||
}
|
||||
|
||||
if (optind < argc)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Too many arguments.");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int runlevel_main(void) {
|
||||
int r, runlevel, previous;
|
||||
|
||||
r = utmp_get_runlevel(&runlevel, &previous);
|
||||
if (r < 0) {
|
||||
puts("unknown");
|
||||
return r;
|
||||
}
|
||||
|
||||
printf("%c %c\n",
|
||||
previous <= 0 ? 'N' : previous,
|
||||
runlevel <= 0 ? 'N' : runlevel);
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
int runlevel_parse_argv(int argc, char *argv[]);
|
||||
|
||||
int runlevel_main(void);
|
@ -4,12 +4,15 @@
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "log.h"
|
||||
#include "parse-util.h"
|
||||
#include "pretty-print.h"
|
||||
#include "reboot-util.h"
|
||||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
#include "systemctl.h"
|
||||
#include "systemctl-compat-shutdown.h"
|
||||
#include "systemctl-sysv-compat.h"
|
||||
#include "systemctl-logind.h"
|
||||
#include "time-util.h"
|
||||
|
||||
static int shutdown_help(void) {
|
||||
_cleanup_free_ char *link = NULL;
|
||||
@ -47,6 +50,61 @@ static int shutdown_help(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_shutdown_time_spec(const char *t, usec_t *ret) {
|
||||
int r;
|
||||
|
||||
assert(t);
|
||||
assert(ret);
|
||||
|
||||
/* This parses SysV compat time spec. */
|
||||
|
||||
if (streq(t, "now"))
|
||||
*ret = 0;
|
||||
else if (!strchr(t, ':')) {
|
||||
uint64_t u;
|
||||
|
||||
if (safe_atou64(t, &u) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
*ret = now(CLOCK_REALTIME) + USEC_PER_MINUTE * u;
|
||||
} else {
|
||||
char *e = NULL;
|
||||
long hour, minute;
|
||||
|
||||
errno = 0;
|
||||
hour = strtol(t, &e, 10);
|
||||
if (errno > 0 || *e != ':' || hour < 0 || hour > 23)
|
||||
return -EINVAL;
|
||||
|
||||
minute = strtol(e+1, &e, 10);
|
||||
if (errno > 0 || *e != 0 || minute < 0 || minute > 59)
|
||||
return -EINVAL;
|
||||
|
||||
usec_t n = now(CLOCK_REALTIME);
|
||||
struct tm tm = {};
|
||||
|
||||
r = localtime_or_gmtime_usec(n, /* utc= */ false, &tm);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
tm.tm_hour = (int) hour;
|
||||
tm.tm_min = (int) minute;
|
||||
tm.tm_sec = 0;
|
||||
|
||||
usec_t s;
|
||||
r = mktime_or_timegm_usec(&tm, /* utc= */ false, &s);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
while (s <= n)
|
||||
s += USEC_PER_DAY;
|
||||
|
||||
*ret = s;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int shutdown_parse_argv(int argc, char *argv[]) {
|
||||
enum {
|
||||
ARG_HELP = 0x100,
|
||||
|
@ -1,156 +0,0 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <getopt.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "log.h"
|
||||
#include "pretty-print.h"
|
||||
#include "systemctl.h"
|
||||
#include "systemctl-compat-telinit.h"
|
||||
#include "systemctl-daemon-reload.h"
|
||||
#include "systemctl-start-unit.h"
|
||||
#include "systemctl-sysv-compat.h"
|
||||
|
||||
static int telinit_help(void) {
|
||||
_cleanup_free_ char *link = NULL;
|
||||
int r;
|
||||
|
||||
r = terminal_urlify_man("telinit", "8", &link);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
printf("%s [OPTIONS...] COMMAND\n\n"
|
||||
"%sSend control commands to the init daemon.%s\n"
|
||||
"\nCommands:\n"
|
||||
" 0 Power-off the machine\n"
|
||||
" 6 Reboot the machine\n"
|
||||
" 2, 3, 4, 5 Start runlevelX.target unit\n"
|
||||
" 1, s, S Enter rescue mode\n"
|
||||
" q, Q Reload init daemon configuration\n"
|
||||
" u, U Reexecute init daemon\n"
|
||||
"\nOptions:\n"
|
||||
" --help Show this help\n"
|
||||
" --no-wall Don't send wall message before halt/power-off/reboot\n"
|
||||
"\nSee the %s for details.\n",
|
||||
program_invocation_short_name,
|
||||
ansi_highlight(),
|
||||
ansi_normal(),
|
||||
link);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int telinit_parse_argv(int argc, char *argv[]) {
|
||||
enum {
|
||||
ARG_HELP = 0x100,
|
||||
ARG_NO_WALL
|
||||
};
|
||||
|
||||
static const struct option options[] = {
|
||||
{ "help", no_argument, NULL, ARG_HELP },
|
||||
{ "no-wall", no_argument, NULL, ARG_NO_WALL },
|
||||
{}
|
||||
};
|
||||
|
||||
static const struct {
|
||||
char from;
|
||||
enum action to;
|
||||
} table[] = {
|
||||
{ '0', ACTION_POWEROFF },
|
||||
{ '6', ACTION_REBOOT },
|
||||
{ '1', ACTION_RESCUE },
|
||||
{ '2', ACTION_RUNLEVEL2 },
|
||||
{ '3', ACTION_RUNLEVEL3 },
|
||||
{ '4', ACTION_RUNLEVEL4 },
|
||||
{ '5', ACTION_RUNLEVEL5 },
|
||||
{ 's', ACTION_RESCUE },
|
||||
{ 'S', ACTION_RESCUE },
|
||||
{ 'q', ACTION_RELOAD },
|
||||
{ 'Q', ACTION_RELOAD },
|
||||
{ 'u', ACTION_REEXEC },
|
||||
{ 'U', ACTION_REEXEC }
|
||||
};
|
||||
|
||||
unsigned i;
|
||||
int c;
|
||||
|
||||
assert(argc >= 0);
|
||||
assert(argv);
|
||||
|
||||
while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0)
|
||||
switch (c) {
|
||||
|
||||
case ARG_HELP:
|
||||
return telinit_help();
|
||||
|
||||
case ARG_NO_WALL:
|
||||
arg_no_wall = true;
|
||||
break;
|
||||
|
||||
case '?':
|
||||
return -EINVAL;
|
||||
|
||||
default:
|
||||
assert_not_reached();
|
||||
}
|
||||
|
||||
if (optind >= argc)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"%s: required argument missing.",
|
||||
program_invocation_short_name);
|
||||
|
||||
if (optind + 1 < argc)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Too many arguments.");
|
||||
|
||||
if (strlen(argv[optind]) != 1)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Expected single character argument.");
|
||||
|
||||
for (i = 0; i < ELEMENTSOF(table); i++)
|
||||
if (table[i].from == argv[optind][0])
|
||||
break;
|
||||
|
||||
if (i >= ELEMENTSOF(table))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Unknown command '%s'.", argv[optind]);
|
||||
|
||||
arg_action = table[i].to;
|
||||
|
||||
optind++;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int start_with_fallback(void) {
|
||||
int r;
|
||||
|
||||
/* First, try systemd via D-Bus. */
|
||||
r = verb_start(0, NULL, NULL);
|
||||
if (r == 0)
|
||||
return 0;
|
||||
|
||||
#if HAVE_SYSV_COMPAT
|
||||
/* Nothing else worked, so let's try /dev/initctl */
|
||||
if (talk_initctl(action_to_runlevel()) > 0)
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
return log_error_errno(r, "Failed to talk to init daemon: %m");
|
||||
}
|
||||
|
||||
int reload_with_fallback(void) {
|
||||
|
||||
assert(IN_SET(arg_action, ACTION_RELOAD, ACTION_REEXEC));
|
||||
|
||||
/* First, try systemd via D-Bus */
|
||||
if (daemon_reload(arg_action, /* graceful= */ true) > 0)
|
||||
return 0;
|
||||
|
||||
/* That didn't work, so let's try signals */
|
||||
if (kill(1, arg_action == ACTION_RELOAD ? SIGHUP : SIGTERM) < 0)
|
||||
return log_error_errno(errno, "kill() failed: %m");
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
int telinit_parse_argv(int argc, char *argv[]);
|
||||
int start_with_fallback(void);
|
||||
int reload_with_fallback(void);
|
@ -11,7 +11,6 @@
|
||||
#include "strv.h"
|
||||
#include "systemctl.h"
|
||||
#include "systemctl-is-active.h"
|
||||
#include "systemctl-sysv-compat.h"
|
||||
#include "systemctl-util.h"
|
||||
#include "unit-def.h"
|
||||
|
||||
|
@ -16,8 +16,6 @@
|
||||
#include "systemctl-cancel-job.h"
|
||||
#include "systemctl-clean-or-freeze.h"
|
||||
#include "systemctl-compat-halt.h"
|
||||
#include "systemctl-compat-runlevel.h"
|
||||
#include "systemctl-compat-telinit.h"
|
||||
#include "systemctl-daemon-reload.h"
|
||||
#include "systemctl-edit.h"
|
||||
#include "systemctl-enable.h"
|
||||
@ -214,19 +212,6 @@ static int run(int argc, char *argv[]) {
|
||||
r = halt_main();
|
||||
break;
|
||||
|
||||
case ACTION_RUNLEVEL2:
|
||||
case ACTION_RUNLEVEL3:
|
||||
case ACTION_RUNLEVEL4:
|
||||
case ACTION_RUNLEVEL5:
|
||||
case ACTION_RESCUE:
|
||||
r = start_with_fallback();
|
||||
break;
|
||||
|
||||
case ACTION_RELOAD:
|
||||
case ACTION_REEXEC:
|
||||
r = reload_with_fallback();
|
||||
break;
|
||||
|
||||
case ACTION_CANCEL_SHUTDOWN:
|
||||
r = logind_cancel_shutdown();
|
||||
break;
|
||||
@ -236,10 +221,9 @@ static int run(int argc, char *argv[]) {
|
||||
r = logind_show_shutdown();
|
||||
break;
|
||||
|
||||
case ACTION_RUNLEVEL:
|
||||
r = runlevel_main();
|
||||
break;
|
||||
|
||||
case ACTION_RESCUE:
|
||||
case ACTION_RELOAD:
|
||||
case ACTION_REEXEC:
|
||||
case ACTION_EXIT:
|
||||
case ACTION_SLEEP:
|
||||
case ACTION_SUSPEND:
|
||||
|
@ -48,7 +48,6 @@
|
||||
#include "systemctl.h"
|
||||
#include "systemctl-list-machines.h"
|
||||
#include "systemctl-show.h"
|
||||
#include "systemctl-sysv-compat.h"
|
||||
#include "systemctl-util.h"
|
||||
#include "terminal-util.h"
|
||||
#include "utf8.h"
|
||||
|
@ -232,10 +232,6 @@ const struct action_metadata action_table[_ACTION_MAX] = {
|
||||
[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" },
|
||||
[ACTION_RUNLEVEL5] = { SPECIAL_GRAPHICAL_TARGET, NULL, "isolate" },
|
||||
[ACTION_RESCUE] = { SPECIAL_RESCUE_TARGET, "rescue", "isolate" },
|
||||
[ACTION_EMERGENCY] = { SPECIAL_EMERGENCY_TARGET, "emergency", "isolate" },
|
||||
[ACTION_DEFAULT] = { SPECIAL_DEFAULT_TARGET, "default", "isolate" },
|
||||
|
@ -5,12 +5,8 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#include "env-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "initreq.h"
|
||||
#include "install.h"
|
||||
#include "io-util.h"
|
||||
#include "log.h"
|
||||
#include "parse-util.h"
|
||||
#include "path-lookup.h"
|
||||
#include "path-util.h"
|
||||
#include "process-util.h"
|
||||
@ -18,101 +14,6 @@
|
||||
#include "strv.h"
|
||||
#include "systemctl.h"
|
||||
#include "systemctl-sysv-compat.h"
|
||||
#include "time-util.h"
|
||||
|
||||
int talk_initctl(char rl) {
|
||||
#if HAVE_SYSV_COMPAT
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
const char *path;
|
||||
int r;
|
||||
|
||||
/* Try to switch to the specified SysV runlevel. Returns == 0 if the operation does not apply on this
|
||||
* system, and > 0 on success. */
|
||||
|
||||
if (rl == 0)
|
||||
return 0;
|
||||
|
||||
FOREACH_STRING(_path, "/run/initctl", "/dev/initctl") {
|
||||
path = _path;
|
||||
|
||||
fd = open(path, O_WRONLY|O_NONBLOCK|O_CLOEXEC|O_NOCTTY);
|
||||
if (fd < 0 && errno != ENOENT)
|
||||
return log_error_errno(errno, "Failed to open %s: %m", path);
|
||||
if (fd >= 0)
|
||||
break;
|
||||
}
|
||||
if (fd < 0)
|
||||
return 0;
|
||||
|
||||
struct init_request request = {
|
||||
.magic = INIT_MAGIC,
|
||||
.sleeptime = 0,
|
||||
.cmd = INIT_CMD_RUNLVL,
|
||||
.runlevel = rl,
|
||||
};
|
||||
|
||||
r = loop_write(fd, &request, sizeof(request));
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to write to %s: %m", path);
|
||||
|
||||
return 1;
|
||||
#else
|
||||
return -EOPNOTSUPP;
|
||||
#endif
|
||||
}
|
||||
|
||||
int parse_shutdown_time_spec(const char *t, usec_t *ret) {
|
||||
int r;
|
||||
|
||||
assert(t);
|
||||
assert(ret);
|
||||
|
||||
if (streq(t, "now"))
|
||||
*ret = 0;
|
||||
else if (!strchr(t, ':')) {
|
||||
uint64_t u;
|
||||
|
||||
if (safe_atou64(t, &u) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
*ret = now(CLOCK_REALTIME) + USEC_PER_MINUTE * u;
|
||||
} else {
|
||||
char *e = NULL;
|
||||
long hour, minute;
|
||||
|
||||
errno = 0;
|
||||
hour = strtol(t, &e, 10);
|
||||
if (errno > 0 || *e != ':' || hour < 0 || hour > 23)
|
||||
return -EINVAL;
|
||||
|
||||
minute = strtol(e+1, &e, 10);
|
||||
if (errno > 0 || *e != 0 || minute < 0 || minute > 59)
|
||||
return -EINVAL;
|
||||
|
||||
usec_t n = now(CLOCK_REALTIME);
|
||||
struct tm tm = {};
|
||||
|
||||
r = localtime_or_gmtime_usec(n, /* utc= */ false, &tm);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
tm.tm_hour = (int) hour;
|
||||
tm.tm_min = (int) minute;
|
||||
tm.tm_sec = 0;
|
||||
|
||||
usec_t s;
|
||||
r = mktime_or_timegm_usec(&tm, /* utc= */ false, &s);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
while (s <= n)
|
||||
s += USEC_PER_DAY;
|
||||
|
||||
*ret = s;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int enable_sysv_units(const char *verb, char **args) {
|
||||
int r = 0;
|
||||
@ -264,23 +165,3 @@ int enable_sysv_units(const char *verb, char **args) {
|
||||
#endif
|
||||
return r;
|
||||
}
|
||||
|
||||
int action_to_runlevel(void) {
|
||||
#if HAVE_SYSV_COMPAT
|
||||
static const char table[_ACTION_MAX] = {
|
||||
[ACTION_HALT] = '0',
|
||||
[ACTION_POWEROFF] = '0',
|
||||
[ACTION_REBOOT] = '6',
|
||||
[ACTION_RUNLEVEL2] = '2',
|
||||
[ACTION_RUNLEVEL3] = '3',
|
||||
[ACTION_RUNLEVEL4] = '4',
|
||||
[ACTION_RUNLEVEL5] = '5',
|
||||
[ACTION_RESCUE] = '1'
|
||||
};
|
||||
|
||||
assert(arg_action >= 0 && arg_action < _ACTION_MAX);
|
||||
return table[arg_action];
|
||||
#else
|
||||
return -EOPNOTSUPP;
|
||||
#endif
|
||||
}
|
||||
|
@ -1,35 +1,6 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include "forward.h"
|
||||
|
||||
int talk_initctl(char runlevel);
|
||||
|
||||
int parse_shutdown_time_spec(const char *t, usec_t *ret);
|
||||
|
||||
/* The init script exit codes for the LSB 'status' verb. (This is different from the 'start' verb, whose exit
|
||||
codes are defined in exit-status.h.)
|
||||
|
||||
0 program is running or service is OK
|
||||
1 program is dead and /var/run pid file exists
|
||||
2 program is dead and /var/lock lock file exists
|
||||
3 program is not running
|
||||
4 program or service status is unknown
|
||||
5-99 reserved for future LSB use
|
||||
100-149 reserved for distribution use
|
||||
150-199 reserved for application use
|
||||
200-254 reserved
|
||||
|
||||
https://refspecs.linuxbase.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/iniscrptact.html
|
||||
*/
|
||||
enum {
|
||||
EXIT_PROGRAM_RUNNING_OR_SERVICE_OK = 0,
|
||||
EXIT_PROGRAM_DEAD_AND_PID_EXISTS = 1,
|
||||
EXIT_PROGRAM_DEAD_AND_LOCK_FILE_EXISTS = 2,
|
||||
EXIT_PROGRAM_NOT_RUNNING = 3,
|
||||
EXIT_PROGRAM_OR_SERVICES_STATUS_UNKNOWN = 4,
|
||||
};
|
||||
|
||||
typedef enum SysVUnitEnableState {
|
||||
SYSV_UNIT_NOT_FOUND = 0,
|
||||
SYSV_UNIT_DISABLED,
|
||||
@ -37,5 +8,3 @@ typedef enum SysVUnitEnableState {
|
||||
} SysVUnitEnableState;
|
||||
|
||||
int enable_sysv_units(const char *verb, char **args);
|
||||
|
||||
int action_to_runlevel(void) _pure_;
|
||||
|
@ -3,6 +3,29 @@
|
||||
|
||||
#include "systemctl.h"
|
||||
|
||||
/* The init script exit codes for the LSB 'status' verb. (This is different from the 'start' verb, whose exit
|
||||
codes are defined in exit-status.h.)
|
||||
|
||||
0 program is running or service is OK
|
||||
1 program is dead and /var/run pid file exists
|
||||
2 program is dead and /var/lock lock file exists
|
||||
3 program is not running
|
||||
4 program or service status is unknown
|
||||
5-99 reserved for future LSB use
|
||||
100-149 reserved for distribution use
|
||||
150-199 reserved for application use
|
||||
200-254 reserved
|
||||
|
||||
https://refspecs.linuxbase.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/iniscrptact.html
|
||||
*/
|
||||
enum {
|
||||
EXIT_PROGRAM_RUNNING_OR_SERVICE_OK = 0,
|
||||
EXIT_PROGRAM_DEAD_AND_PID_EXISTS = 1,
|
||||
EXIT_PROGRAM_DEAD_AND_LOCK_FILE_EXISTS = 2,
|
||||
EXIT_PROGRAM_NOT_RUNNING = 3,
|
||||
EXIT_PROGRAM_OR_SERVICES_STATUS_UNKNOWN = 4,
|
||||
};
|
||||
|
||||
typedef enum BusFocus {
|
||||
BUS_FULL, /* The full bus indicated via --system or --user */
|
||||
BUS_MANAGER, /* The manager itself, possibly directly, possibly via the bus */
|
||||
|
@ -24,9 +24,7 @@
|
||||
#include "strv.h"
|
||||
#include "systemctl.h"
|
||||
#include "systemctl-compat-halt.h"
|
||||
#include "systemctl-compat-runlevel.h"
|
||||
#include "systemctl-compat-shutdown.h"
|
||||
#include "systemctl-compat-telinit.h"
|
||||
#include "systemctl-logind.h"
|
||||
#include "time-util.h"
|
||||
|
||||
@ -1124,28 +1122,6 @@ int systemctl_dispatch_parse_argv(int argc, char *argv[]) {
|
||||
} else if (invoked_as(argv, "shutdown")) {
|
||||
arg_action = ACTION_POWEROFF;
|
||||
return shutdown_parse_argv(argc, argv);
|
||||
|
||||
} else if (invoked_as(argv, "init")) {
|
||||
|
||||
/* Matches invocations as "init" as well as "telinit", which are synonymous when run
|
||||
* as PID != 1 on SysV.
|
||||
*
|
||||
* On SysV "telinit" was the official command to communicate with PID 1, but "init" would
|
||||
* redirect itself to "telinit" if called with PID != 1. We follow the same logic here still,
|
||||
* though we add one level of indirection, as we implement "telinit" in "systemctl". Hence,
|
||||
* for us if you invoke "init" you get "systemd", but it will execve() "systemctl"
|
||||
* immediately with argv[] unmodified if PID is != 1. If you invoke "telinit" you directly
|
||||
* get "systemctl". In both cases we shall do the same thing, which is why we do
|
||||
* invoked_as(argv, "init") here, as a quick way to match both.
|
||||
*
|
||||
* Also see redirect_telinit() in src/core/main.c. */
|
||||
|
||||
arg_action = _ACTION_INVALID; /* telinit_parse_argv() will figure out the actual action we'll execute */
|
||||
return telinit_parse_argv(argc, argv);
|
||||
|
||||
} else if (invoked_as(argv, "runlevel")) {
|
||||
arg_action = ACTION_RUNLEVEL;
|
||||
return runlevel_parse_argv(argc, argv);
|
||||
}
|
||||
|
||||
arg_action = ACTION_SYSTEMCTL;
|
||||
|
@ -16,16 +16,11 @@ enum action {
|
||||
ACTION_HIBERNATE,
|
||||
ACTION_HYBRID_SLEEP,
|
||||
ACTION_SUSPEND_THEN_HIBERNATE,
|
||||
ACTION_RUNLEVEL2,
|
||||
ACTION_RUNLEVEL3,
|
||||
ACTION_RUNLEVEL4,
|
||||
ACTION_RUNLEVEL5,
|
||||
ACTION_RESCUE,
|
||||
ACTION_EMERGENCY,
|
||||
ACTION_DEFAULT,
|
||||
ACTION_RELOAD,
|
||||
ACTION_REEXEC,
|
||||
ACTION_RUNLEVEL,
|
||||
ACTION_CANCEL_SHUTDOWN,
|
||||
ACTION_SHOW_SHUTDOWN,
|
||||
ACTION_SYSTEMCTL_SHOW_SHUTDOWN,
|
||||
|
@ -57,81 +57,6 @@ static int get_startup_monotonic_time(Context *c, usec_t *ret) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define MAX_ATTEMPTS 64u
|
||||
|
||||
static int get_current_runlevel(Context *c) {
|
||||
static const struct {
|
||||
const int runlevel;
|
||||
const char *special;
|
||||
} table[] = {
|
||||
/* The first target of this list that is active or has a job scheduled wins. We prefer
|
||||
* runlevels 5 and 3 here over the others, since these are the main runlevels used on Fedora.
|
||||
* It might make sense to change the order on some distributions. */
|
||||
{ '5', SPECIAL_GRAPHICAL_TARGET },
|
||||
{ '3', SPECIAL_MULTI_USER_TARGET },
|
||||
{ '1', SPECIAL_RESCUE_TARGET },
|
||||
};
|
||||
int r;
|
||||
|
||||
assert(c);
|
||||
|
||||
for (unsigned n_attempts = 0;;) {
|
||||
if (n_attempts++ > 0) {
|
||||
/* systemd might have dropped off momentarily, let's not make this an error,
|
||||
* and wait some random time. Let's pick a random time in the range 100ms…2000ms,
|
||||
* linearly scaled by the number of failed attempts. */
|
||||
c->bus = sd_bus_flush_close_unref(c->bus);
|
||||
|
||||
usec_t usec =
|
||||
UINT64_C(100) * USEC_PER_MSEC +
|
||||
random_u64_range(UINT64_C(1900) * USEC_PER_MSEC * n_attempts / MAX_ATTEMPTS);
|
||||
(void) usleep_safe(usec);
|
||||
}
|
||||
|
||||
if (!c->bus) {
|
||||
r = bus_connect_system_systemd(&c->bus);
|
||||
if (r == -ECONNREFUSED && n_attempts < 64) {
|
||||
log_debug_errno(r, "Failed to %s to system bus, retrying after a slight delay: %m",
|
||||
n_attempts <= 1 ? "connect" : "reconnect");
|
||||
continue;
|
||||
}
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to reconnect to system bus: %m");
|
||||
}
|
||||
|
||||
FOREACH_ELEMENT(e, table) {
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
_cleanup_free_ char *state = NULL, *path = NULL;
|
||||
|
||||
path = unit_dbus_path_from_name(e->special);
|
||||
if (!path)
|
||||
return log_oom();
|
||||
|
||||
r = sd_bus_get_property_string(
|
||||
c->bus,
|
||||
"org.freedesktop.systemd1",
|
||||
path,
|
||||
"org.freedesktop.systemd1.Unit",
|
||||
"ActiveState",
|
||||
&error,
|
||||
&state);
|
||||
if ((r == -ENOTCONN || bus_error_is_connection(&error)) &&
|
||||
n_attempts < MAX_ATTEMPTS) {
|
||||
log_debug_errno(r, "Failed to get state of %s, retrying after a slight delay: %s",
|
||||
e->special, bus_error_message(&error, r));
|
||||
break;
|
||||
}
|
||||
if (r < 0)
|
||||
return log_warning_errno(r, "Failed to get state of %s: %s", e->special, bus_error_message(&error, r));
|
||||
|
||||
if (STR_IN_SET(state, "active", "reloading"))
|
||||
return e->runlevel;
|
||||
}
|
||||
if (r >= 0)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int on_reboot(int argc, char *argv[], void *userdata) {
|
||||
Context *c = ASSERT_PTR(userdata);
|
||||
usec_t t = 0, boottime;
|
||||
@ -182,59 +107,10 @@ static int on_shutdown(int argc, char *argv[], void *userdata) {
|
||||
return q;
|
||||
}
|
||||
|
||||
static int on_runlevel(int argc, char *argv[], void *userdata) {
|
||||
Context *c = ASSERT_PTR(userdata);
|
||||
int r, q = 0, previous, runlevel;
|
||||
|
||||
/* We finished changing runlevel, so let's write the utmp record and send the audit msg. */
|
||||
|
||||
/* First, get last runlevel */
|
||||
r = utmp_get_runlevel(&previous, NULL);
|
||||
if (r < 0) {
|
||||
if (!IN_SET(r, -ESRCH, -ENOENT))
|
||||
return log_error_errno(r, "Failed to get the last runlevel from utmp: %m");
|
||||
|
||||
previous = 0;
|
||||
}
|
||||
|
||||
/* Secondly, get new runlevel */
|
||||
runlevel = get_current_runlevel(c);
|
||||
if (runlevel < 0)
|
||||
return runlevel;
|
||||
if (runlevel == 0) {
|
||||
log_warning("Failed to get the current runlevel, utmp update skipped.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (previous == runlevel)
|
||||
return 0;
|
||||
|
||||
#if HAVE_AUDIT
|
||||
if (c->audit_fd >= 0) {
|
||||
char s[STRLEN("old-level=_ new-level=_") + 1];
|
||||
|
||||
xsprintf(s, "old-level=%c new-level=%c",
|
||||
previous > 0 ? previous : 'N',
|
||||
runlevel);
|
||||
|
||||
if (audit_log_user_comm_message(c->audit_fd, AUDIT_SYSTEM_RUNLEVEL, s,
|
||||
"systemd-update-utmp", NULL, NULL, NULL, 1) < 0 && errno != EPERM)
|
||||
q = log_error_errno(errno, "Failed to send audit message: %m");
|
||||
}
|
||||
#endif
|
||||
|
||||
r = utmp_put_runlevel(runlevel, previous);
|
||||
if (r < 0 && !IN_SET(r, -ESRCH, -ENOENT))
|
||||
return log_error_errno(r, "Failed to write utmp record: %m");
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
static int run(int argc, char *argv[]) {
|
||||
static const Verb verbs[] = {
|
||||
{ "reboot", 1, 1, 0, on_reboot },
|
||||
{ "shutdown", 1, 1, 0, on_shutdown },
|
||||
{ "runlevel", 1, 1, 0, on_runlevel },
|
||||
{}
|
||||
};
|
||||
|
||||
|
@ -13,3 +13,4 @@ version_h = custom_target('version',
|
||||
vcs_tag ? '1' : '0',
|
||||
])
|
||||
version_include = include_directories('.')
|
||||
userspace_sources += [version_h]
|
||||
|
@ -45,19 +45,4 @@ systemctl daemon-reload
|
||||
# of systemd-analyze blame. See issue #27187.
|
||||
systemd-analyze blame
|
||||
|
||||
# Test for 'systemd-update-utmp runlevel' vs 'systemctl daemon-reexec'.
|
||||
# See issue #27163.
|
||||
# shellcheck disable=SC2034
|
||||
if [[ -x /usr/lib/systemd/systemd-update-utmp ]]; then
|
||||
for _ in {0..10}; do
|
||||
systemctl daemon-reexec &
|
||||
pid_reexec=$!
|
||||
# shellcheck disable=SC2034
|
||||
for _ in {0..10}; do
|
||||
SYSTEMD_LOG_LEVEL=debug /usr/lib/systemd/systemd-update-utmp runlevel
|
||||
done
|
||||
wait "$pid_reexec"
|
||||
done
|
||||
fi
|
||||
|
||||
touch /testok
|
||||
|
@ -1422,7 +1422,18 @@ testcase_unpriv_dir() {
|
||||
# Use an image owned by the foreign UID range first via direct mapping, and than via the managed uid logic
|
||||
systemd-dissect --shift "$root" foreign
|
||||
assert_eq "$(systemd-nspawn --pipe --register=no -D "$root" --private-users=pick --private-users-ownership=foreign bash -c 'echo foobar')" "foobar"
|
||||
assert_eq "$(systemd-nspawn --pipe --register=no -D "$root" --private-users=managed --private-network bash -c 'echo foobar')" "foobar"
|
||||
# FIXME:
|
||||
# Since 90fa161b5ba29d58953e9f08ddca49121b51efe6, --bind= or Bind= settings for coverage directory does
|
||||
# not work with managed mode:
|
||||
# ========
|
||||
# [ 158.105361] systemd-nspawn[3718]: Failed to open tree and set mount attributes: Operation not permitted
|
||||
# [ 158.105364] systemd-nspawn[3718]: Failed to clone /coverage: Operation not permitted
|
||||
# [ 158.118655] systemd-nspawn[3707]: (sd-namespace) failed with exit status 1.
|
||||
# ========
|
||||
# Let's tentatively skip the test case when running on coverage.
|
||||
if [[ -z "${COVERAGE_BUILD_DIR:-}" ]]; then
|
||||
assert_eq "$(systemd-nspawn --pipe --register=no -D "$root" --private-users=managed --private-network bash -c 'echo foobar')" "foobar"
|
||||
fi
|
||||
|
||||
# Test unprivileged operation
|
||||
chown testuser:testuser "$root/.."
|
||||
|
@ -63,10 +63,6 @@ os-release.xml ./refsect1[title="Options"]/refsect2[title="Presentation informat
|
||||
pam_systemd.xml ./refsect1[title="Options"]/variablelist/varlistentry[term="debug="]
|
||||
pam_systemd.xml ./refsect1[title="Environment"]/variablelist[1]/varlistentry[term="$XDG_SESSION_ID"]
|
||||
pam_systemd.xml ./refsect1[title="Environment"]/variablelist[1]/varlistentry[term="$XDG_RUNTIME_DIR"]
|
||||
runlevel.xml ./refsect1[title="Options"]/variablelist/varlistentry[term="--help"]
|
||||
runlevel.xml ./refsect1[title="Environment"]/variablelist/varlistentry[term="$RUNLEVEL"]
|
||||
runlevel.xml ./refsect1[title="Environment"]/variablelist/varlistentry[term="$PREVLEVEL"]
|
||||
runlevel.xml ./refsect1[title="Files"]/variablelist/varlistentry[term="/run/utmp"]
|
||||
shutdown.xml ./refsect1[title="Options"]/variablelist/varlistentry[term="--help"]
|
||||
shutdown.xml ./refsect1[title="Options"]/variablelist/varlistentry[term="-H"]
|
||||
shutdown.xml ./refsect1[title="Options"]/variablelist/varlistentry[term="-P"]
|
||||
@ -330,7 +326,6 @@ systemd.special.xml ./refsect1[title="Units managed by the system service manage
|
||||
systemd.special.xml ./refsect1[title="Units managed by the system service manager"]/refsect2[title="Special Passive System Units "]/variablelist/varlistentry[term="remote-fs-pre.target"]
|
||||
systemd.special.xml ./refsect1[title="Units managed by the system service manager"]/refsect2[title="Special System Units"]/variablelist/varlistentry[term="rescue.target"]
|
||||
systemd.special.xml ./refsect1[title="Units managed by the system service manager"]/refsect2[title="Special Passive System Units "]/variablelist/varlistentry[term="rpcbind.target"]
|
||||
systemd.special.xml ./refsect1[title="Units managed by the system service manager"]/refsect2[title="Special System Units"]/variablelist/varlistentry[term="runlevel2.target"]
|
||||
systemd.special.xml ./refsect1[title="Units managed by the system service manager"]/refsect2[title="Special System Units"]/variablelist/varlistentry[term="shutdown.target"]
|
||||
systemd.special.xml ./refsect1[title="Units managed by the system service manager"]/refsect2[title="Special System Units"]/variablelist/varlistentry[term="sigpwr.target"]
|
||||
systemd.special.xml ./refsect1[title="Units managed by the system service manager"]/refsect2[title="Special System Units"]/variablelist/varlistentry[term="sleep.target"]
|
||||
@ -404,15 +399,6 @@ systemd.xml ./refsect1[title="Kernel Command Line"]/variablelist/varlistentry[te
|
||||
systemd.xml ./refsect1[title="Kernel Command Line"]/variablelist/varlistentry[term="systemd.setenv="]
|
||||
systemd.xml ./refsect1[title="Files"]/variablelist/varlistentry[term="/run/systemd/notify"]
|
||||
systemd.xml ./refsect1[title="Files"]/variablelist/varlistentry[term="/run/systemd/private"]
|
||||
systemd.xml ./refsect1[title="Files"]/variablelist/varlistentry[term="/dev/initctl"]
|
||||
telinit.xml ./refsect1[title="Options"]/variablelist[1]/varlistentry[term="--help"]
|
||||
telinit.xml ./refsect1[title="Options"]/variablelist[1]/varlistentry[term="--no-wall"]
|
||||
telinit.xml ./refsect1[title="Options"]/variablelist[2]/varlistentry[term="0"]
|
||||
telinit.xml ./refsect1[title="Options"]/variablelist[2]/varlistentry[term="6"]
|
||||
telinit.xml ./refsect1[title="Options"]/variablelist[2]/varlistentry[term="2"]
|
||||
telinit.xml ./refsect1[title="Options"]/variablelist[2]/varlistentry[term="1"]
|
||||
telinit.xml ./refsect1[title="Options"]/variablelist[2]/varlistentry[term="q"]
|
||||
telinit.xml ./refsect1[title="Options"]/variablelist[2]/varlistentry[term="u"]
|
||||
tmpfiles.d.xml ./refsect1[title="Configuration File Format"]/refsect2[title="Type"]/variablelist/varlistentry[term="f"]
|
||||
tmpfiles.d.xml ./refsect1[title="Configuration File Format"]/refsect2[title="Type"]/variablelist/varlistentry[term="w"]
|
||||
tmpfiles.d.xml ./refsect1[title="Configuration File Format"]/refsect2[title="Type"]/variablelist/varlistentry[term="d"]
|
||||
|
@ -1,7 +1,5 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
with_runlevels = conf.get('HAVE_SYSV_COMPAT') == 1
|
||||
|
||||
units = [
|
||||
{ 'file' : 'basic.target' },
|
||||
{ 'file' : 'blockdev@.target' },
|
||||
@ -51,7 +49,7 @@ units = [
|
||||
},
|
||||
{
|
||||
'file' : 'graphical.target',
|
||||
'symlinks' : ['default.target'] + (with_runlevels ? ['runlevel5.target'] : []),
|
||||
'symlinks' : ['default.target'],
|
||||
},
|
||||
{ 'file' : 'halt.target' },
|
||||
{
|
||||
@ -144,20 +142,14 @@ units = [
|
||||
'conditions' : ['ENABLE_MACHINED'],
|
||||
},
|
||||
{ 'file' : 'modprobe@.service' },
|
||||
{
|
||||
'file' : 'multi-user.target',
|
||||
'symlinks' : with_runlevels ? ['runlevel2.target', 'runlevel3.target', 'runlevel4.target'] : [],
|
||||
},
|
||||
{ 'file' : 'multi-user.target' },
|
||||
{ 'file' : 'network-online.target' },
|
||||
{ 'file' : 'network-pre.target' },
|
||||
{ 'file' : 'network.target' },
|
||||
{ 'file' : 'nss-lookup.target' },
|
||||
{ 'file' : 'nss-user-lookup.target' },
|
||||
{ 'file' : 'paths.target' },
|
||||
{
|
||||
'file' : 'poweroff.target',
|
||||
'symlinks' : with_runlevels ? ['runlevel0.target'] : [],
|
||||
},
|
||||
{ 'file' : 'poweroff.target' },
|
||||
{ 'file' : 'printer.target' },
|
||||
{
|
||||
'file' : 'proc-sys-fs-binfmt_misc.automount',
|
||||
@ -182,7 +174,7 @@ units = [
|
||||
},
|
||||
{
|
||||
'file' : 'reboot.target',
|
||||
'symlinks' : ['ctrl-alt-del.target'] + (with_runlevels ? ['runlevel6.target'] : []),
|
||||
'symlinks' : ['ctrl-alt-del.target'],
|
||||
},
|
||||
{
|
||||
'file' : 'remote-cryptsetup.target',
|
||||
@ -202,10 +194,7 @@ units = [
|
||||
'symlinks' : ['initrd-root-device.target.wants/'],
|
||||
},
|
||||
{ 'file' : 'rescue.service.in' },
|
||||
{
|
||||
'file' : 'rescue.target',
|
||||
'symlinks' : with_runlevels ? ['runlevel1.target'] : [],
|
||||
},
|
||||
{ 'file' : 'rescue.target' },
|
||||
{ 'file' : 'rpcbind.target' },
|
||||
{ 'file' : 'serial-getty@.service.in' },
|
||||
{ 'file' : 'shutdown.target' },
|
||||
@ -412,15 +401,6 @@ units = [
|
||||
'conditions' : ['ENABLE_IMPORTD'],
|
||||
'symlinks' : ['sysinit.target.wants/'],
|
||||
},
|
||||
{
|
||||
'file' : 'systemd-initctl.service.in',
|
||||
'conditions' : ['HAVE_SYSV_COMPAT'],
|
||||
},
|
||||
{
|
||||
'file' : 'systemd-initctl.socket',
|
||||
'conditions' : ['HAVE_SYSV_COMPAT'],
|
||||
'symlinks' : ['sockets.target.wants/'],
|
||||
},
|
||||
{
|
||||
'file' : 'systemd-journal-catalog-update.service',
|
||||
'symlinks' : ['sysinit.target.wants/'],
|
||||
@ -827,11 +807,6 @@ units = [
|
||||
'file' : 'systemd-update-done.service.in',
|
||||
'symlinks' : ['sysinit.target.wants/'],
|
||||
},
|
||||
{
|
||||
'file' : 'systemd-update-utmp-runlevel.service.in',
|
||||
'conditions' : ['ENABLE_UTMP', 'HAVE_SYSV_COMPAT'],
|
||||
'symlinks' : ['multi-user.target.wants/', 'graphical.target.wants/', 'rescue.target.wants/'],
|
||||
},
|
||||
{
|
||||
'file' : 'systemd-update-utmp.service.in',
|
||||
'conditions' : ['ENABLE_UTMP'],
|
||||
@ -997,10 +972,4 @@ else
|
||||
dbussessionservicedir / 'org.freedesktop.systemd1.service'))
|
||||
endif
|
||||
|
||||
if conf.get('HAVE_SYSV_COMPAT') == 1
|
||||
foreach i : [1, 2, 3, 4, 5]
|
||||
install_emptydir(systemunitdir / 'runlevel@0@.target.wants'.format(i))
|
||||
endforeach
|
||||
endif
|
||||
|
||||
subdir('user')
|
||||
|
@ -1,19 +0,0 @@
|
||||
# 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=initctl Compatibility Daemon
|
||||
Documentation=man:systemd-initctl.service(8)
|
||||
DefaultDependencies=no
|
||||
|
||||
[Service]
|
||||
ExecStart={{LIBEXECDIR}}/systemd-initctl
|
||||
NoNewPrivileges=yes
|
||||
NotifyAccess=all
|
||||
SystemCallArchitectures=native
|
@ -1,19 +0,0 @@
|
||||
# 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=initctl Compatibility Named Pipe
|
||||
Documentation=man:systemd-initctl.socket(8)
|
||||
DefaultDependencies=no
|
||||
Before=sockets.target
|
||||
|
||||
[Socket]
|
||||
ListenFIFO=/run/initctl
|
||||
Symlinks=/dev/initctl
|
||||
SocketMode=0600
|
@ -1,25 +0,0 @@
|
||||
# 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=Record Runlevel Change in UTMP
|
||||
Documentation=man:systemd-update-utmp-runlevel.service(8) man:utmp(5)
|
||||
ConditionPathExists=!/etc/initrd-release
|
||||
|
||||
DefaultDependencies=no
|
||||
RequiresMountsFor=/var/log/wtmp
|
||||
Conflicts=shutdown.target
|
||||
Requisite=systemd-update-utmp.service
|
||||
After=systemd-update-utmp.service
|
||||
After=runlevel1.target runlevel2.target runlevel3.target runlevel4.target runlevel5.target
|
||||
Before=shutdown.target
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart={{LIBEXECDIR}}/systemd-update-utmp runlevel
|
Loading…
x
Reference in New Issue
Block a user