Compare commits

...

12 Commits

Author SHA1 Message Date
nkraetzschmar a8c1edfc34
Merge 76e563900e into 92033d8fba 2024-11-27 15:00:36 +01:00
Lennart Poettering 92033d8fba man: split systemd.conf(5) into multiple sections
No changes in wording, let's just make a very long man page a bit more
digestable by adding sections, and then reordering settings to fit into
them.
2024-11-27 21:51:32 +09:00
Lennart Poettering 209a9e7bf3 Update TODO 2024-11-27 13:06:18 +01:00
Luca Boccassi 0abaa5be10
bootspec fixups (#34959) 2024-11-27 10:55:32 +00:00
Zbigniew Jędrzejewski-Szmek ef20d06da6
ukify: Switch to JSON HWID description format (#35208)
Fixes #35176
2024-11-27 09:50:41 +01:00
Adrian Vovk f2751d757f
bootspec: Look at /loader/addons in XBOOTLDR
The bootspec util-lib's handling of global addons didn't previously
match the behavior of sd-stub, and this commit corrects that.

First, bootspec didn't load global addons from the XBOOTLDR dir, but the
stub does. So, bootspec now enumerates addons in XBOOTLDR, not just ESP

Second, the stub only loads resources (including addons) from the
partition that it was found on. Thus, we must keep track of which
partition the global addons come from, and which partition each boot
entry comes from. In other words: global addons found on the ESP will
NOT apply to UKIs found in XBOOTLDR, and bootspec now reflects that.
2024-11-26 22:25:29 -05:00
Adrian Vovk ef370a3c30
bootspec: Fixup loading of local addons for UKIs
Follow-up for 59b3df9
2024-11-26 16:33:11 -05:00
Adrian Vovk e2501a851e
bootspec: Fixup memory leak
This would previously leak memory: the array was deleted but contents
inside of the array were not
2024-11-26 16:33:10 -05:00
Adrian Vovk 5a10a9a3bb
sd-stub: Fixup typo & measurement order
A previous commit accidentally reversed the measurement order of the
confext initrds and sysext initrds via a minor typo. This commit fixes
the typo and restores the original measurement order

Follow-up: ac32323
2024-11-26 16:33:09 -05:00
anonymix007 098e44d03c man: Document ukify --hwids= and --devicetree-auto= options 2024-11-22 13:31:19 +03:00
anonymix007 cf331f1c9b ukify: Switch to JSON HWID description format 2024-11-22 00:42:47 +03:00
nkraetzschmar 76e563900e boot: add reboot-on-error config option
Enabling this option will cause the system to reboot in case the selected
entry fails to load.
2024-11-14 13:06:42 +01:00
12 changed files with 558 additions and 467 deletions

3
TODO
View File

@ -129,6 +129,9 @@ Deprecations and removals:
Features:
* our logging tools should look for $DEBUG_INVOCATION and consider equivalent
to $SYSTEMD_LOG_LEVEL=debug
* Teach systemd-ssh-generator to generated an /run/issue.d/ drop-in telling
users how to connect to the system via the AF_VSOCK, as per:
https://github.com/systemd/systemd/issues/35071#issuecomment-2462803142

View File

@ -399,6 +399,14 @@ sbvarsign --attr "${attr}" --key KEK.key --cert KEK.pem --output db.auth db db.e
<xi:include href="version-info.xml" xpointer="v251"/></listitem>
</varlistentry>
<varlistentry>
<term>reboot-on-error</term>
<listitem><para>Takes a boolean argument. Enable or disable (the default) auto reboot in case the selected entry fails to start.</para>
<xi:include href="version-info.xml" xpointer="v257"/></listitem>
</varlistentry>
</variablelist>
</refsect1>

View File

@ -64,11 +64,9 @@
<refsect1>
<title>Options</title>
<para>All options are configured in the
[Manager] section:</para>
<para>All options are configured in the [Manager] section:</para>
<variablelist class='config-directives'>
<varlistentry>
<term><varname>LogColor=</varname></term>
<term><varname>LogLevel=</varname></term>
@ -105,6 +103,65 @@
<xi:include href="version-info.xml" xpointer="v232"/></listitem>
</varlistentry>
<varlistentry>
<term><varname>StatusUnitFormat=</varname></term>
<listitem><para>Takes <option>name</option>, <option>description</option> or
<option>combined</option> as the value. If <option>name</option>, the system manager will use unit
names in status messages (e.g. <literal>systemd-journald.service</literal>), instead of the longer
and more informative descriptions set with <varname>Description=</varname> (e.g. <literal>Journal
Logging Service</literal>). If <option>combined</option>, the system manager will use both unit names
and descriptions in status messages (e.g. <literal>systemd-journald.service - Journal Logging
Service</literal>).</para>
<para>See
<citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
details about unit names and <varname>Description=</varname>.</para>
<xi:include href="version-info.xml" xpointer="v243"/></listitem>
</varlistentry>
<varlistentry>
<term><varname>DefaultTimerAccuracySec=</varname></term>
<listitem><para>Sets the default accuracy of timer units. This
controls the global default for the
<varname>AccuracySec=</varname> setting of timer units, see
<citerefentry><refentrytitle>systemd.timer</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for details. <varname>AccuracySec=</varname> set in individual
units override the global default for the specific unit.
Defaults to 1min. Note that the accuracy of timer units is
also affected by the configured timer slack for PID 1, see
<varname>TimerSlackNSec=</varname> above.</para>
<xi:include href="version-info.xml" xpointer="v212"/></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>Resource Management</title>
<variablelist class='config-directives'>
<varlistentry>
<term><varname>TimerSlackNSec=</varname></term>
<listitem><para>Sets the timer slack in nanoseconds for PID 1,
which is inherited by all executed processes, unless
overridden individually, for example with the
<varname>TimerSlackNSec=</varname> setting in service units
(for details see
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>).
The timer slack controls the accuracy of wake-ups triggered by
system timers. See
<citerefentry><refentrytitle>prctl</refentrytitle><manvolnum>2</manvolnum></citerefentry>
for more information. Note that in contrast to most other time
span definitions this parameter takes an integer value in
nano-seconds if no unit is specified. The usual time units are
understood too.</para>
<xi:include href="version-info.xml" xpointer="v198"/></listitem>
</varlistentry>
<varlistentry>
<term><varname>CPUAffinity=</varname></term>
@ -143,355 +200,6 @@
<xi:include href="version-info.xml" xpointer="v243"/></listitem>
</varlistentry>
<varlistentry>
<term><varname>RuntimeWatchdogSec=</varname></term>
<term><varname>RebootWatchdogSec=</varname></term>
<term><varname>KExecWatchdogSec=</varname></term>
<listitem><para>Configure the hardware watchdog at runtime and at reboot. Takes a timeout value in
seconds (or in other time units if suffixed with <literal>ms</literal>, <literal>min</literal>,
<literal>h</literal>, <literal>d</literal>, <literal>w</literal>), or the special strings
<literal>off</literal> or <literal>default</literal>. If set to <literal>off</literal>
(alternatively: <literal>0</literal>) the watchdog logic is disabled: no watchdog device is opened,
configured, or pinged. If set to the special string <literal>default</literal> the watchdog is opened
and pinged in regular intervals, but the timeout is not changed from the default. If set to any other
time value the watchdog timeout is configured to the specified value (or a value close to it,
depending on hardware capabilities).</para>
<para>If <varname>RuntimeWatchdogSec=</varname> is set to a non-zero value, the watchdog hardware
(<filename>/dev/watchdog0</filename> or the path specified with <varname>WatchdogDevice=</varname> or
the kernel option <varname>systemd.watchdog-device=</varname>) will be programmed to automatically
reboot the system if it is not contacted within the specified timeout interval. The system manager
will ensure to contact it at least once in half the specified timeout interval. This feature requires
a hardware watchdog device to be present, as it is commonly the case in embedded and server
systems. Not all hardware watchdogs allow configuration of all possible reboot timeout values, in
which case the closest available timeout is picked.</para>
<para><varname>RebootWatchdogSec=</varname> may be used to configure the hardware watchdog when the
system is asked to reboot. It works as a safety net to ensure that the reboot takes place even if a
clean reboot attempt times out. Note that the <varname>RebootWatchdogSec=</varname> timeout applies
only to the second phase of the reboot, i.e. after all regular services are already terminated, and
after the system and service manager process (PID 1) got replaced by the
<filename>systemd-shutdown</filename> binary, see system
<citerefentry><refentrytitle>bootup</refentrytitle><manvolnum>7</manvolnum></citerefentry> for
details. During the first phase of the shutdown operation the system and service manager remains
running and hence <varname>RuntimeWatchdogSec=</varname> is still honoured. In order to define a
timeout on this first phase of system shutdown, configure <varname>JobTimeoutSec=</varname> and
<varname>JobTimeoutAction=</varname> in the [Unit] section of the
<filename>shutdown.target</filename> unit. By default <varname>RuntimeWatchdogSec=</varname> defaults
to 0 (off), and <varname>RebootWatchdogSec=</varname> to 10min.</para>
<para><varname>KExecWatchdogSec=</varname> may be used to additionally enable the watchdog when kexec
is being executed rather than when rebooting. Note that if the kernel does not reset the watchdog on
kexec (depending on the specific hardware and/or driver), in this case the watchdog might not get
disabled after kexec succeeds and thus the system might get rebooted, unless
<varname>RuntimeWatchdogSec=</varname> is also enabled at the same time. For this reason it is
recommended to enable <varname>KExecWatchdogSec=</varname> only if
<varname>RuntimeWatchdogSec=</varname> is also enabled.</para>
<para>These settings have no effect if a hardware watchdog is not available.</para>
<xi:include href="version-info.xml" xpointer="v198"/></listitem>
</varlistentry>
<varlistentry>
<term><varname>RuntimeWatchdogPreSec=</varname></term>
<listitem><para>Configure the hardware watchdog device pre-timeout value.
Takes a timeout value in seconds (or in other time units similar to
<varname>RuntimeWatchdogSec=</varname>). A watchdog pre-timeout is a
notification generated by the watchdog before the watchdog reset might
occur in the event the watchdog has not been serviced. This notification
is handled by the kernel and can be configured to take an action (i.e.
generate a kernel panic) using <varname>RuntimeWatchdogPreGovernor=</varname>.
Not all watchdog hardware or drivers support generating a pre-timeout and
depending on the state of the system, the kernel may be unable to take the
configured action before the watchdog reboot. The watchdog will be configured
to generate the pre-timeout event at the amount of time specified by
<varname>RuntimeWatchdogPreSec=</varname> before the runtime watchdog timeout
(set by <varname>RuntimeWatchdogSec=</varname>). For example, if the we have
<varname>RuntimeWatchdogSec=30</varname> and
<varname>RuntimeWatchdogPreSec=10</varname>, then the pre-timeout event
will occur if the watchdog has not pinged for 20s (10s before the
watchdog would fire). By default, <varname>RuntimeWatchdogPreSec=</varname>
defaults to 0 (off). The value set for <varname>RuntimeWatchdogPreSec=</varname>
must be smaller than the timeout value for <varname>RuntimeWatchdogSec=</varname>.
This setting has no effect if a hardware watchdog is not available or the
hardware watchdog does not support a pre-timeout and will be ignored by the
kernel if the setting is greater than the actual watchdog timeout.</para>
<xi:include href="version-info.xml" xpointer="v251"/></listitem>
</varlistentry>
<varlistentry>
<term><varname>RuntimeWatchdogPreGovernor=</varname></term>
<listitem><para>Configure the action taken by the hardware watchdog device
when the pre-timeout expires. The default action for the pre-timeout event
depends on the kernel configuration, but it is usually to log a kernel
message. For a list of valid actions available for a given watchdog device,
check the content of the
<filename>/sys/class/watchdog/watchdog<replaceable>X</replaceable>/pretimeout_available_governors</filename>
file. Typically, available governor types are <varname>noop</varname> and <varname>panic</varname>.
Availability, names and functionality might vary depending on the specific device driver
in use. If the <filename>pretimeout_available_governors</filename> sysfs file is empty,
the governor might be built as a kernel module and might need to be manually loaded
(e.g. <varname>pretimeout_noop.ko</varname>), or the watchdog device might not support
pre-timeouts.</para>
<xi:include href="version-info.xml" xpointer="v251"/></listitem>
</varlistentry>
<varlistentry>
<term><varname>WatchdogDevice=</varname></term>
<listitem><para>Configure the hardware watchdog device that the
runtime and shutdown watchdog timers will open and use. Defaults
to <filename>/dev/watchdog0</filename>. This setting has no
effect if a hardware watchdog is not available.</para>
<xi:include href="version-info.xml" xpointer="v236"/></listitem>
</varlistentry>
<varlistentry>
<term><varname>CapabilityBoundingSet=</varname></term>
<listitem><para>Controls which capabilities to include in the
capability bounding set for PID 1 and its children. See
<citerefentry project='man-pages'><refentrytitle>capabilities</refentrytitle><manvolnum>7</manvolnum></citerefentry>
for details. Takes a whitespace-separated list of capability
names as read by
<citerefentry project='mankier'><refentrytitle>cap_from_name</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
Capabilities listed will be included in the bounding set, all
others are removed. If the list of capabilities is prefixed
with ~, all but the listed capabilities will be included, the
effect of the assignment inverted. Note that this option also
affects the respective capabilities in the effective,
permitted and inheritable capability sets. The capability
bounding set may also be individually configured for units
using the <varname>CapabilityBoundingSet=</varname> directive
for units, but note that capabilities dropped for PID 1 cannot
be regained in individual units, they are lost for
good.</para>
<xi:include href="version-info.xml" xpointer="v198"/></listitem>
</varlistentry>
<varlistentry>
<term><varname>NoNewPrivileges=</varname></term>
<listitem><para>Takes a boolean argument. If true, ensures that PID 1
and all its children can never gain new privileges through
<citerefentry project='man-pages'><refentrytitle>execve</refentrytitle><manvolnum>2</manvolnum></citerefentry>
(e.g. via setuid or setgid bits, or filesystem capabilities).
Defaults to false. General purpose distributions commonly rely
on executables with setuid or setgid bits and will thus not
function properly with this option enabled. Individual units
cannot disable this option.
Also see <ulink url="https://docs.kernel.org/userspace-api/no_new_privs.html">No New Privileges Flag</ulink>.
</para>
<xi:include href="version-info.xml" xpointer="v239"/></listitem>
</varlistentry>
<varlistentry>
<term><varname>ProtectSystem=</varname></term>
<listitem><para>Takes a boolean argument or the string <literal>auto</literal>. If set to true this
will remount <filename>/usr/</filename> read-only. If set to <literal>auto</literal> (the default)
and running in an initrd equivalent to true, otherwise false. This implements a restricted subset of
the per-unit setting of the same name, see
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
details: currently, the <literal>full</literal> or <literal>strict</literal> values are not
supported.</para>
<xi:include href="version-info.xml" xpointer="v256"/></listitem>
</varlistentry>
<varlistentry>
<term><varname>SystemCallArchitectures=</varname></term>
<listitem><para>Takes a space-separated list of architecture
identifiers. Selects from which architectures system calls may
be invoked on this system. This may be used as an effective
way to disable invocation of non-native binaries system-wide,
for example to prohibit execution of 32-bit x86 binaries on
64-bit x86-64 systems. This option operates system-wide, and
acts similar to the
<varname>SystemCallArchitectures=</varname> setting of unit
files, see
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for details. This setting defaults to the empty list, in which
case no filtering of system calls based on architecture is
applied. Known architecture identifiers are
<literal>x86</literal>, <literal>x86-64</literal>,
<literal>x32</literal>, <literal>arm</literal> and the special
identifier <literal>native</literal>. The latter implicitly
maps to the native architecture of the system (or more
specifically, the architecture the system manager was compiled
for). Set this setting to <literal>native</literal> to
prohibit execution of any non-native binaries. When a binary
executes a system call of an architecture that is not listed
in this setting, it will be immediately terminated with the
SIGSYS signal.</para>
<xi:include href="version-info.xml" xpointer="v209"/></listitem>
</varlistentry>
<varlistentry>
<term><varname>TimerSlackNSec=</varname></term>
<listitem><para>Sets the timer slack in nanoseconds for PID 1,
which is inherited by all executed processes, unless
overridden individually, for example with the
<varname>TimerSlackNSec=</varname> setting in service units
(for details see
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>).
The timer slack controls the accuracy of wake-ups triggered by
system timers. See
<citerefentry><refentrytitle>prctl</refentrytitle><manvolnum>2</manvolnum></citerefentry>
for more information. Note that in contrast to most other time
span definitions this parameter takes an integer value in
nano-seconds if no unit is specified. The usual time units are
understood too.</para>
<xi:include href="version-info.xml" xpointer="v198"/></listitem>
</varlistentry>
<varlistentry>
<term><varname>StatusUnitFormat=</varname></term>
<listitem><para>Takes <option>name</option>, <option>description</option> or
<option>combined</option> as the value. If <option>name</option>, the system manager will use unit
names in status messages (e.g. <literal>systemd-journald.service</literal>), instead of the longer
and more informative descriptions set with <varname>Description=</varname> (e.g. <literal>Journal
Logging Service</literal>). If <option>combined</option>, the system manager will use both unit names
and descriptions in status messages (e.g. <literal>systemd-journald.service - Journal Logging
Service</literal>).</para>
<para>See
<citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
details about unit names and <varname>Description=</varname>.</para>
<xi:include href="version-info.xml" xpointer="v243"/></listitem>
</varlistentry>
<varlistentry>
<term><varname>DefaultTimerAccuracySec=</varname></term>
<listitem><para>Sets the default accuracy of timer units. This
controls the global default for the
<varname>AccuracySec=</varname> setting of timer units, see
<citerefentry><refentrytitle>systemd.timer</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for details. <varname>AccuracySec=</varname> set in individual
units override the global default for the specific unit.
Defaults to 1min. Note that the accuracy of timer units is
also affected by the configured timer slack for PID 1, see
<varname>TimerSlackNSec=</varname> above.</para>
<xi:include href="version-info.xml" xpointer="v212"/></listitem>
</varlistentry>
<varlistentry>
<term><varname>DefaultTimeoutStartSec=</varname></term>
<term><varname>DefaultTimeoutStopSec=</varname></term>
<term><varname>DefaultTimeoutAbortSec=</varname></term>
<term><varname>DefaultRestartSec=</varname></term>
<listitem><para>Configures the default timeouts for starting, stopping and aborting of units, as well
as the default time to sleep between automatic restarts of units, as configured per-unit in
<varname>TimeoutStartSec=</varname>, <varname>TimeoutStopSec=</varname>,
<varname>TimeoutAbortSec=</varname> and <varname>RestartSec=</varname> (for services, see
<citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for details on the per-unit settings). For non-service units,
<varname>DefaultTimeoutStartSec=</varname> sets the default <varname>TimeoutSec=</varname> value.
</para>
<para><varname>DefaultTimeoutStartSec=</varname> and <varname>DefaultTimeoutStopSec=</varname>
default to &DEFAULT_TIMEOUT; in the system manager and &DEFAULT_USER_TIMEOUT; in the user manager.
<varname>DefaultTimeoutAbortSec=</varname> is not set by default so that all units fall back to
<varname>TimeoutStopSec=</varname>. <varname>DefaultRestartSec=</varname> defaults to 100 ms.
</para>
<xi:include href="version-info.xml" xpointer="v209"/></listitem>
</varlistentry>
<varlistentry>
<term><varname>DefaultDeviceTimeoutSec=</varname></term>
<listitem><para>Configures the default timeout for waiting for devices. It can be changed per
device via the <varname>x-systemd.device-timeout=</varname> option in <filename>/etc/fstab</filename>
and <filename>/etc/crypttab</filename> (see
<citerefentry><refentrytitle>systemd.mount</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>crypttab</refentrytitle><manvolnum>5</manvolnum></citerefentry>).
Defaults to &DEFAULT_TIMEOUT; in the system manager and &DEFAULT_USER_TIMEOUT; in the user manager.
</para>
<xi:include href="version-info.xml" xpointer="v252"/></listitem>
</varlistentry>
<varlistentry>
<term><varname>DefaultStartLimitIntervalSec=</varname></term>
<term><varname>DefaultStartLimitBurst=</varname></term>
<listitem><para>Configure the default unit start rate
limiting, as configured per-service by
<varname>StartLimitIntervalSec=</varname> and
<varname>StartLimitBurst=</varname>. See
<citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for details on the per-service settings.
<varname>DefaultStartLimitIntervalSec=</varname> defaults to
10s. <varname>DefaultStartLimitBurst=</varname> defaults to
5.</para>
<xi:include href="version-info.xml" xpointer="v209"/></listitem>
</varlistentry>
<varlistentry>
<term><varname>DefaultEnvironment=</varname></term>
<listitem><para>Configures environment variables passed to all executed processes. Takes a
space-separated list of variable assignments. See <citerefentry
project='man-pages'><refentrytitle>environ</refentrytitle><manvolnum>7</manvolnum></citerefentry> for
details about environment variables.</para>
<para>Simple <literal>%</literal>-specifier expansion is supported, see below for a list of supported
specifiers.</para>
<para>Example:
<programlisting>DefaultEnvironment="VAR1=word1 word2" VAR2=word3 "VAR3=word 5 6"</programlisting>
Sets three variables
<literal>VAR1</literal>,
<literal>VAR2</literal>,
<literal>VAR3</literal>.</para>
<xi:include href="version-info.xml" xpointer="v205"/></listitem>
</varlistentry>
<varlistentry>
<term><varname>ManagerEnvironment=</varname></term>
<listitem><para>Takes the same arguments as <varname>DefaultEnvironment=</varname>, see above. Sets
environment variables for the manager process itself. These variables are inherited by processes
spawned by user managers, but not the system manager - use <varname>DefaultEnvironment=</varname>
for that. Note that these variables are merged into the existing environment block. In particular, in
case of the system manager, this includes variables set by the kernel based on the kernel command line.
As with <varname>DefaultEnvironment=</varname>, this environment block is internal, and changes are not
reflected in the manager's <filename>/proc/PID/environ</filename>.</para>
<para>Setting environment variables for the manager process may be useful to modify its behaviour.
See <ulink url="https://systemd.io/ENVIRONMENT">Known Environment Variables</ulink> for a
descriptions of some variables understood by <command>systemd</command>.</para>
<para>Simple <literal>%</literal>-specifier expansion is supported, see below for a list of supported
specifiers.</para>
<xi:include href="version-info.xml" xpointer="v248"/>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>DefaultCPUAccounting=</varname></term>
<term><varname>DefaultMemoryAccounting=</varname></term>
@ -608,6 +316,227 @@
<xi:include href="version-info.xml" xpointer="v250"/></listitem>
</varlistentry>
<varlistentry>
<term><varname>DefaultMemoryPressureWatch=</varname></term>
<term><varname>DefaultMemoryPressureThresholdSec=</varname></term>
<listitem><para>Configures the default settings for the per-unit
<varname>MemoryPressureWatch=</varname> and <varname>MemoryPressureThresholdSec=</varname>
settings. See
<citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for details. Defaults to <literal>auto</literal> and <literal>200ms</literal>, respectively. This
also sets the memory pressure monitoring threshold for the service manager itself.</para>
<xi:include href="version-info.xml" xpointer="v254"/></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>Hardware Watchdog</title>
<variablelist class='config-directives'>
<varlistentry>
<term><varname>RuntimeWatchdogSec=</varname></term>
<term><varname>RebootWatchdogSec=</varname></term>
<term><varname>KExecWatchdogSec=</varname></term>
<listitem><para>Configure the hardware watchdog at runtime and at reboot. Takes a timeout value in
seconds (or in other time units if suffixed with <literal>ms</literal>, <literal>min</literal>,
<literal>h</literal>, <literal>d</literal>, <literal>w</literal>), or the special strings
<literal>off</literal> or <literal>default</literal>. If set to <literal>off</literal>
(alternatively: <literal>0</literal>) the watchdog logic is disabled: no watchdog device is opened,
configured, or pinged. If set to the special string <literal>default</literal> the watchdog is opened
and pinged in regular intervals, but the timeout is not changed from the default. If set to any other
time value the watchdog timeout is configured to the specified value (or a value close to it,
depending on hardware capabilities).</para>
<para>If <varname>RuntimeWatchdogSec=</varname> is set to a non-zero value, the watchdog hardware
(<filename>/dev/watchdog0</filename> or the path specified with <varname>WatchdogDevice=</varname> or
the kernel option <varname>systemd.watchdog-device=</varname>) will be programmed to automatically
reboot the system if it is not contacted within the specified timeout interval. The system manager
will ensure to contact it at least once in half the specified timeout interval. This feature requires
a hardware watchdog device to be present, as it is commonly the case in embedded and server
systems. Not all hardware watchdogs allow configuration of all possible reboot timeout values, in
which case the closest available timeout is picked.</para>
<para><varname>RebootWatchdogSec=</varname> may be used to configure the hardware watchdog when the
system is asked to reboot. It works as a safety net to ensure that the reboot takes place even if a
clean reboot attempt times out. Note that the <varname>RebootWatchdogSec=</varname> timeout applies
only to the second phase of the reboot, i.e. after all regular services are already terminated, and
after the system and service manager process (PID 1) got replaced by the
<filename>systemd-shutdown</filename> binary, see system
<citerefentry><refentrytitle>bootup</refentrytitle><manvolnum>7</manvolnum></citerefentry> for
details. During the first phase of the shutdown operation the system and service manager remains
running and hence <varname>RuntimeWatchdogSec=</varname> is still honoured. In order to define a
timeout on this first phase of system shutdown, configure <varname>JobTimeoutSec=</varname> and
<varname>JobTimeoutAction=</varname> in the [Unit] section of the
<filename>shutdown.target</filename> unit. By default <varname>RuntimeWatchdogSec=</varname> defaults
to 0 (off), and <varname>RebootWatchdogSec=</varname> to 10min.</para>
<para><varname>KExecWatchdogSec=</varname> may be used to additionally enable the watchdog when kexec
is being executed rather than when rebooting. Note that if the kernel does not reset the watchdog on
kexec (depending on the specific hardware and/or driver), in this case the watchdog might not get
disabled after kexec succeeds and thus the system might get rebooted, unless
<varname>RuntimeWatchdogSec=</varname> is also enabled at the same time. For this reason it is
recommended to enable <varname>KExecWatchdogSec=</varname> only if
<varname>RuntimeWatchdogSec=</varname> is also enabled.</para>
<para>These settings have no effect if a hardware watchdog is not available.</para>
<xi:include href="version-info.xml" xpointer="v198"/></listitem>
</varlistentry>
<varlistentry>
<term><varname>RuntimeWatchdogPreSec=</varname></term>
<listitem><para>Configure the hardware watchdog device pre-timeout value.
Takes a timeout value in seconds (or in other time units similar to
<varname>RuntimeWatchdogSec=</varname>). A watchdog pre-timeout is a
notification generated by the watchdog before the watchdog reset might
occur in the event the watchdog has not been serviced. This notification
is handled by the kernel and can be configured to take an action (i.e.
generate a kernel panic) using <varname>RuntimeWatchdogPreGovernor=</varname>.
Not all watchdog hardware or drivers support generating a pre-timeout and
depending on the state of the system, the kernel may be unable to take the
configured action before the watchdog reboot. The watchdog will be configured
to generate the pre-timeout event at the amount of time specified by
<varname>RuntimeWatchdogPreSec=</varname> before the runtime watchdog timeout
(set by <varname>RuntimeWatchdogSec=</varname>). For example, if the we have
<varname>RuntimeWatchdogSec=30</varname> and
<varname>RuntimeWatchdogPreSec=10</varname>, then the pre-timeout event
will occur if the watchdog has not pinged for 20s (10s before the
watchdog would fire). By default, <varname>RuntimeWatchdogPreSec=</varname>
defaults to 0 (off). The value set for <varname>RuntimeWatchdogPreSec=</varname>
must be smaller than the timeout value for <varname>RuntimeWatchdogSec=</varname>.
This setting has no effect if a hardware watchdog is not available or the
hardware watchdog does not support a pre-timeout and will be ignored by the
kernel if the setting is greater than the actual watchdog timeout.</para>
<xi:include href="version-info.xml" xpointer="v251"/></listitem>
</varlistentry>
<varlistentry>
<term><varname>RuntimeWatchdogPreGovernor=</varname></term>
<listitem><para>Configure the action taken by the hardware watchdog device
when the pre-timeout expires. The default action for the pre-timeout event
depends on the kernel configuration, but it is usually to log a kernel
message. For a list of valid actions available for a given watchdog device,
check the content of the
<filename>/sys/class/watchdog/watchdog<replaceable>X</replaceable>/pretimeout_available_governors</filename>
file. Typically, available governor types are <varname>noop</varname> and <varname>panic</varname>.
Availability, names and functionality might vary depending on the specific device driver
in use. If the <filename>pretimeout_available_governors</filename> sysfs file is empty,
the governor might be built as a kernel module and might need to be manually loaded
(e.g. <varname>pretimeout_noop.ko</varname>), or the watchdog device might not support
pre-timeouts.</para>
<xi:include href="version-info.xml" xpointer="v251"/></listitem>
</varlistentry>
<varlistentry>
<term><varname>WatchdogDevice=</varname></term>
<listitem><para>Configure the hardware watchdog device that the
runtime and shutdown watchdog timers will open and use. Defaults
to <filename>/dev/watchdog0</filename>. This setting has no
effect if a hardware watchdog is not available.</para>
<xi:include href="version-info.xml" xpointer="v236"/></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>Security</title>
<variablelist class='config-directives'>
<varlistentry>
<term><varname>CapabilityBoundingSet=</varname></term>
<listitem><para>Controls which capabilities to include in the
capability bounding set for PID 1 and its children. See
<citerefentry project='man-pages'><refentrytitle>capabilities</refentrytitle><manvolnum>7</manvolnum></citerefentry>
for details. Takes a whitespace-separated list of capability
names as read by
<citerefentry project='mankier'><refentrytitle>cap_from_name</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
Capabilities listed will be included in the bounding set, all
others are removed. If the list of capabilities is prefixed
with ~, all but the listed capabilities will be included, the
effect of the assignment inverted. Note that this option also
affects the respective capabilities in the effective,
permitted and inheritable capability sets. The capability
bounding set may also be individually configured for units
using the <varname>CapabilityBoundingSet=</varname> directive
for units, but note that capabilities dropped for PID 1 cannot
be regained in individual units, they are lost for
good.</para>
<xi:include href="version-info.xml" xpointer="v198"/></listitem>
</varlistentry>
<varlistentry>
<term><varname>NoNewPrivileges=</varname></term>
<listitem><para>Takes a boolean argument. If true, ensures that PID 1
and all its children can never gain new privileges through
<citerefentry project='man-pages'><refentrytitle>execve</refentrytitle><manvolnum>2</manvolnum></citerefentry>
(e.g. via setuid or setgid bits, or filesystem capabilities).
Defaults to false. General purpose distributions commonly rely
on executables with setuid or setgid bits and will thus not
function properly with this option enabled. Individual units
cannot disable this option.
Also see <ulink url="https://docs.kernel.org/userspace-api/no_new_privs.html">No New Privileges Flag</ulink>.
</para>
<xi:include href="version-info.xml" xpointer="v239"/></listitem>
</varlistentry>
<varlistentry>
<term><varname>ProtectSystem=</varname></term>
<listitem><para>Takes a boolean argument or the string <literal>auto</literal>. If set to true this
will remount <filename>/usr/</filename> read-only. If set to <literal>auto</literal> (the default)
and running in an initrd equivalent to true, otherwise false. This implements a restricted subset of
the per-unit setting of the same name, see
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
details: currently, the <literal>full</literal> or <literal>strict</literal> values are not
supported.</para>
<xi:include href="version-info.xml" xpointer="v256"/></listitem>
</varlistentry>
<varlistentry>
<term><varname>SystemCallArchitectures=</varname></term>
<listitem><para>Takes a space-separated list of architecture
identifiers. Selects from which architectures system calls may
be invoked on this system. This may be used as an effective
way to disable invocation of non-native binaries system-wide,
for example to prohibit execution of 32-bit x86 binaries on
64-bit x86-64 systems. This option operates system-wide, and
acts similar to the
<varname>SystemCallArchitectures=</varname> setting of unit
files, see
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for details. This setting defaults to the empty list, in which
case no filtering of system calls based on architecture is
applied. Known architecture identifiers are
<literal>x86</literal>, <literal>x86-64</literal>,
<literal>x32</literal>, <literal>arm</literal> and the special
identifier <literal>native</literal>. The latter implicitly
maps to the native architecture of the system (or more
specifically, the architecture the system manager was compiled
for). Set this setting to <literal>native</literal> to
prohibit execution of any non-native binaries. When a binary
executes a system call of an architecture that is not listed
in this setting, it will be immediately terminated with the
SIGSYS signal.</para>
<xi:include href="version-info.xml" xpointer="v209"/></listitem>
</varlistentry>
<varlistentry>
<term><varname>DefaultSmackProcessLabel=</varname></term>
@ -621,6 +550,67 @@
<xi:include href="version-info.xml" xpointer="v252"/></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>Timeouts and Rate Limits</title>
<variablelist class='config-directives'>
<varlistentry>
<term><varname>DefaultTimeoutStartSec=</varname></term>
<term><varname>DefaultTimeoutStopSec=</varname></term>
<term><varname>DefaultTimeoutAbortSec=</varname></term>
<term><varname>DefaultRestartSec=</varname></term>
<listitem><para>Configures the default timeouts for starting, stopping and aborting of units, as well
as the default time to sleep between automatic restarts of units, as configured per-unit in
<varname>TimeoutStartSec=</varname>, <varname>TimeoutStopSec=</varname>,
<varname>TimeoutAbortSec=</varname> and <varname>RestartSec=</varname> (for services, see
<citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for details on the per-unit settings). For non-service units,
<varname>DefaultTimeoutStartSec=</varname> sets the default <varname>TimeoutSec=</varname> value.
</para>
<para><varname>DefaultTimeoutStartSec=</varname> and <varname>DefaultTimeoutStopSec=</varname>
default to &DEFAULT_TIMEOUT; in the system manager and &DEFAULT_USER_TIMEOUT; in the user manager.
<varname>DefaultTimeoutAbortSec=</varname> is not set by default so that all units fall back to
<varname>TimeoutStopSec=</varname>. <varname>DefaultRestartSec=</varname> defaults to 100 ms.
</para>
<xi:include href="version-info.xml" xpointer="v209"/></listitem>
</varlistentry>
<varlistentry>
<term><varname>DefaultDeviceTimeoutSec=</varname></term>
<listitem><para>Configures the default timeout for waiting for devices. It can be changed per
device via the <varname>x-systemd.device-timeout=</varname> option in <filename>/etc/fstab</filename>
and <filename>/etc/crypttab</filename> (see
<citerefentry><refentrytitle>systemd.mount</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>crypttab</refentrytitle><manvolnum>5</manvolnum></citerefentry>).
Defaults to &DEFAULT_TIMEOUT; in the system manager and &DEFAULT_USER_TIMEOUT; in the user manager.
</para>
<xi:include href="version-info.xml" xpointer="v252"/></listitem>
</varlistentry>
<varlistentry>
<term><varname>DefaultStartLimitIntervalSec=</varname></term>
<term><varname>DefaultStartLimitBurst=</varname></term>
<listitem><para>Configure the default unit start rate
limiting, as configured per-service by
<varname>StartLimitIntervalSec=</varname> and
<varname>StartLimitBurst=</varname>. See
<citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for details on the per-service settings.
<varname>DefaultStartLimitIntervalSec=</varname> defaults to
10s. <varname>DefaultStartLimitBurst=</varname> defaults to
5.</para>
<xi:include href="version-info.xml" xpointer="v209"/></listitem>
</varlistentry>
<varlistentry>
<term><varname>ReloadLimitIntervalSec=</varname></term>
@ -635,19 +625,56 @@
<xi:include href="version-info.xml" xpointer="v253"/></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>Environment</title>
<variablelist class='config-directives'>
<varlistentry>
<term><varname>ManagerEnvironment=</varname></term>
<listitem><para>Takes the same arguments as <varname>DefaultEnvironment=</varname>, see above. Sets
environment variables for the manager process itself. These variables are inherited by processes
spawned by user managers, but not the system manager - use <varname>DefaultEnvironment=</varname>
for that. Note that these variables are merged into the existing environment block. In particular, in
case of the system manager, this includes variables set by the kernel based on the kernel command line.
As with <varname>DefaultEnvironment=</varname>, this environment block is internal, and changes are not
reflected in the manager's <filename>/proc/PID/environ</filename>.</para>
<para>Setting environment variables for the manager process may be useful to modify its behaviour.
See <ulink url="https://systemd.io/ENVIRONMENT">Known Environment Variables</ulink> for a
descriptions of some variables understood by <command>systemd</command>.</para>
<para>Simple <literal>%</literal>-specifier expansion is supported, see below for a list of supported
specifiers.</para>
<xi:include href="version-info.xml" xpointer="v248"/>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>DefaultMemoryPressureWatch=</varname></term>
<term><varname>DefaultMemoryPressureThresholdSec=</varname></term>
<term><varname>DefaultEnvironment=</varname></term>
<listitem><para>Configures the default settings for the per-unit
<varname>MemoryPressureWatch=</varname> and <varname>MemoryPressureThresholdSec=</varname>
settings. See
<citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for details. Defaults to <literal>auto</literal> and <literal>200ms</literal>, respectively. This
also sets the memory pressure monitoring threshold for the service manager itself.</para>
<listitem><para>Configures environment variables passed to all executed processes. Takes a
space-separated list of variable assignments. See <citerefentry
project='man-pages'><refentrytitle>environ</refentrytitle><manvolnum>7</manvolnum></citerefentry> for
details about environment variables.</para>
<xi:include href="version-info.xml" xpointer="v254"/></listitem>
<para>Simple <literal>%</literal>-specifier expansion is supported, see below for a list of supported
specifiers.</para>
<para>Example:
<programlisting>DefaultEnvironment="VAR1=word1 word2" VAR2=word3 "VAR3=word 5 6"</programlisting>
Sets three variables
<literal>VAR1</literal>,
<literal>VAR2</literal>,
<literal>VAR3</literal>.</para>
<xi:include href="version-info.xml" xpointer="v205"/></listitem>
</varlistentry>
</variablelist>
</refsect1>

View File

@ -71,6 +71,8 @@
<varname>Cmdline=</varname>/<option>--cmdline=</option>,
<varname>OSRelease=</varname>/<option>--os-release=</option>,
<varname>DeviceTree=</varname>/<option>--devicetree=</option>,
<varname>DeviceTreeAuto=</varname>/<option>--devicetree-auto=</option>,
<varname>HWIDs=</varname>/<option>--hwids=</option>,
<varname>Splash=</varname>/<option>--splash=</option>,
<varname>PCRPKey=</varname>/<option>--pcrpkey=</option>,
<varname>Uname=</varname>/<option>--uname=</option>,
@ -374,6 +376,35 @@
<xi:include href="version-info.xml" xpointer="v253"/></listitem>
</varlistentry>
<varlistentry>
<term><varname>DeviceTreeAuto=<replaceable>PATH</replaceable>...</varname></term>
<term><option>--devicetree-auto=<replaceable>PATH</replaceable></option></term>
<listitem><para>Zero or more automatically selectable DeviceTree files. In the configuration file, items are separated by
whitespace. Each DeviceTree will be in a separate <literal>.dtbauto</literal> section.</para>
<xi:include href="version-info.xml" xpointer="v257"/></listitem>
</varlistentry>
<varlistentry>
<term><varname>HWIDs=<replaceable>PATH</replaceable></varname></term>
<term><option>--hwids=<replaceable>PATH</replaceable></option></term>
<listitem><para>The hardware ID device table (the <literal>.hwids</literal> section). The argument is a
path to a directory with JSON HWID device description files. Each file needs to contain a single JSON object with a <literal>name</literal>, <literal>compatible</literal> and <literal>hwids</literal> keys. The <literal>name</literal> and <literal>compatible</literal> keys must have string values and the <literal>hwids</literal> key must have a list of strings as value, where the strings must be valid UUIDs that represent CHIDs/HWIDs.
Example:
<programlisting><xi:include href="ukify_hwid.json.example" parse="text" /></programlisting>
Here <literal>Example Laptop 16 Gen 7</literal> is the device <literal>name</literal> (as defined by the manufacturer),
<literal>example,laptop-16-g7</literal> is the <literal>compatible</literal> (as defined by the kernel) and <literal>hwids</literal>
is an array of CHIDs/HWIDs (extracted i.e. from <command>fwupdtool hwids</command> output).
If not specified, the section will not be present. It is recommended to specify this parameter if automatically
selectable DeviceTrees are to be used.
</para>
<xi:include href="version-info.xml" xpointer="v257"/></listitem>
</varlistentry>
<varlistentry>
<term><varname>Uname=<replaceable>VERSION</replaceable></varname></term>
<term><option>--uname=<replaceable>VERSION</replaceable></option></term>

View File

@ -0,0 +1,8 @@
{
"name": "Example Laptop 16 Gen 7",
"compatible": "example,laptop-16-g7",
"hwids": [
"5dc05bf4-01f6-4089-b464-a08c47ea9295",
"3e3f8f3c-2003-46f2-811c-85554f7d5952"
]
}

View File

@ -97,6 +97,7 @@ typedef struct {
bool auto_poweroff;
bool auto_reboot;
bool reboot_for_bitlocker;
bool reboot_on_err;
secure_boot_enroll secure_boot_enroll;
bool force_menu;
bool use_saved_entry;
@ -538,6 +539,7 @@ static void print_status(Config *config, char16_t *loaded_image_path) {
printf(" auto-reboot: %ls\n", yes_no(config->auto_reboot));
printf(" beep: %ls\n", yes_no(config->beep));
printf(" reboot-for-bitlocker: %ls\n", yes_no(config->reboot_for_bitlocker));
printf(" reboot-on-error: %ls\n", yes_no(config->reboot_on_err));
switch (config->secure_boot_enroll) {
case ENROLL_OFF:
@ -1276,6 +1278,10 @@ static void config_defaults_load_from_file(Config *config, char *content) {
log_error("Error parsing 'reboot-for-bitlocker' config option, ignoring: %s",
value);
} else if (streq8(key, "reboot-on-error")) {
if (!parse_boolean(value, &config->reboot_on_err))
log_error("Error parsing 'reboot-on-error' config option, ignoring: %s", value);
} else if (streq8(key, "secure-boot-enroll")) {
if (streq8(value, "manual"))
config->secure_boot_enroll = ENROLL_MANUAL;
@ -2946,8 +2952,12 @@ static EFI_STATUS run(EFI_HANDLE image) {
(void) process_random_seed(root_dir);
err = image_start(image, entry);
if (err != EFI_SUCCESS)
return err;
if (err != EFI_SUCCESS) {
if (config.reboot_on_err)
reboot_system();
else
return err;
}
menu = true;
config.timeout_sec = 0;

View File

@ -858,7 +858,7 @@ static void generate_sidecar_initrds(
/* access_mode= */ 0444,
/* tpm_pcr= */ TPM2_PCR_SYSEXTS,
u"System extension initrd",
initrds + INITRD_CONFEXT,
initrds + INITRD_SYSEXT,
&m) == EFI_SUCCESS)
combine_measured_flag(sysext_measured, m);
@ -871,7 +871,7 @@ static void generate_sidecar_initrds(
/* access_mode= */ 0444,
/* tpm_pcr= */ TPM2_PCR_KERNEL_CONFIG,
u"Configuration extension initrd",
initrds + INITRD_SYSEXT,
initrds + INITRD_CONFEXT,
&m) == EFI_SUCCESS)
combine_measured_flag(confext_measured, m);
}

View File

@ -92,7 +92,6 @@ static int status_entries(
r = show_boot_entry(
boot_config_default_entry(config),
&config->global_addons,
/* show_as_default= */ false,
/* show_as_selected= */ false,
/* show_discovered= */ false);

View File

@ -55,7 +55,7 @@ static int json_dispatch_entries(const char *name, sd_json_variant *variant, sd_
_cleanup_fclose_ FILE *f = NULL;
assert_se(f = data_to_file((const uint8_t*) data, len));
assert_se(boot_config_load_type1(config, f, "/", "/entries", id) != -ENOMEM);
assert_se(boot_config_load_type1(config, f, "/", BOOT_ENTRY_ESP, "/entries", id) != -ENOMEM);
}
}

View File

@ -44,6 +44,22 @@ static const char* const boot_entry_type_json_table[_BOOT_ENTRY_TYPE_MAX] = {
DEFINE_STRING_TABLE_LOOKUP_TO_STRING(boot_entry_type_json, BootEntryType);
static const char* const boot_entry_source_table[_BOOT_ENTRY_SOURCE_MAX] = {
[BOOT_ENTRY_ESP] = "EFI System Partition",
[BOOT_ENTRY_XBOOTLDR] = "Extended Boot Loader Partition",
};
DEFINE_STRING_TABLE_LOOKUP_TO_STRING(boot_entry_source, BootEntrySource);
static const char* const boot_entry_source_json_table[_BOOT_ENTRY_SOURCE_MAX] = {
[BOOT_ENTRY_ESP] = "esp",
[BOOT_ENTRY_XBOOTLDR] = "xbootldr",
};
DEFINE_STRING_TABLE_LOOKUP_TO_STRING(boot_entry_source_json, BootEntrySource);
static void boot_entry_addons_done(BootEntryAddons *addons);
static void boot_entry_free(BootEntry *entry) {
assert(entry);
@ -59,7 +75,7 @@ static void boot_entry_free(BootEntry *entry) {
free(entry->machine_id);
free(entry->architecture);
strv_free(entry->options);
free(entry->local_addons.items);
boot_entry_addons_done(&entry->local_addons);
free(entry->kernel);
free(entry->efi);
strv_free(entry->initrd);
@ -283,11 +299,12 @@ nothing:
static int boot_entry_load_type1(
FILE *f,
const char *root,
const BootEntrySource source,
const char *dir,
const char *fname,
BootEntry *entry) {
_cleanup_(boot_entry_free) BootEntry tmp = BOOT_ENTRY_INIT(BOOT_ENTRY_CONF);
_cleanup_(boot_entry_free) BootEntry tmp = BOOT_ENTRY_INIT(BOOT_ENTRY_CONF, source);
char *c;
int r;
@ -393,6 +410,7 @@ int boot_config_load_type1(
BootConfig *config,
FILE *f,
const char *root,
const BootEntrySource source,
const char *dir,
const char *fname) {
int r;
@ -406,10 +424,14 @@ int boot_config_load_type1(
if (!GREEDY_REALLOC0(config->entries, config->n_entries + 1))
return log_oom();
r = boot_entry_load_type1(f, root, dir, fname, config->entries + config->n_entries);
BootEntry *entry = config->entries + config->n_entries;
r = boot_entry_load_type1(f, root, source, dir, fname, entry);
if (r < 0)
return r;
entry->global_addons = &config->global_addons[source];
config->n_entries++;
return 0;
}
@ -426,7 +448,9 @@ void boot_config_free(BootConfig *config) {
FOREACH_ARRAY(i, config->entries, config->n_entries)
boot_entry_free(i);
free(config->entries);
free(config->global_addons.items);
FOREACH_ARRAY(i, config->global_addons, _BOOT_ENTRY_SOURCE_MAX)
boot_entry_addons_done(i);
set_free(config->inodes_seen);
}
@ -592,6 +616,7 @@ static int config_check_inode_relevant_and_unseen(BootConfig *config, int fd, co
static int boot_entries_find_type1(
BootConfig *config,
const char *root,
const BootEntrySource source,
const char *dir) {
_cleanup_free_ DirectoryEntries *dentries = NULL;
@ -635,7 +660,7 @@ static int boot_entries_find_type1(
if (r == 0) /* inode already seen or otherwise not relevant */
continue;
r = boot_config_load_type1(config, f, root, full, de->d_name);
r = boot_config_load_type1(config, f, root, source, full, de->d_name);
if (r == -ENOMEM) /* ignore all other errors */
return log_oom();
}
@ -645,6 +670,7 @@ static int boot_entries_find_type1(
static int boot_entry_load_unified(
const char *root,
const BootEntrySource source,
const char *path,
unsigned profile,
const char *osrelease_text,
@ -717,7 +743,7 @@ static int boot_entry_load_unified(
if (r < 0)
return log_error_errno(r, "Failed to extract file name from '%s': %m", path);
_cleanup_(boot_entry_free) BootEntry tmp = BOOT_ENTRY_INIT(BOOT_ENTRY_UNIFIED);
_cleanup_(boot_entry_free) BootEntry tmp = BOOT_ENTRY_INIT(BOOT_ENTRY_UNIFIED, source);
r = boot_filename_extract_tries(fname, &tmp.id, &tmp.tries_left, &tmp.tries_done);
if (r < 0)
@ -1130,18 +1156,21 @@ static int boot_entries_find_unified_addons(
static int boot_entries_find_unified_global_addons(
BootConfig *config,
const char *root,
const char *d_name) {
const char *d_name,
BootEntryAddons *ret_addons) {
int r;
_cleanup_closedir_ DIR *d = NULL;
assert(ret_addons);
r = chase_and_opendir(root, NULL, CHASE_PROHIBIT_SYMLINKS, NULL, &d);
if (r == -ENOENT)
return 0;
if (r < 0)
return log_error_errno(r, "Failed to open '%s/%s': %m", root, d_name);
return boot_entries_find_unified_addons(config, dirfd(d), d_name, root, &config->global_addons);
return boot_entries_find_unified_addons(config, dirfd(d), d_name, root, ret_addons);
}
static int boot_entries_find_unified_local_addons(
@ -1165,6 +1194,7 @@ static int boot_entries_find_unified_local_addons(
static int boot_entries_find_unified(
BootConfig *config,
const char *root,
BootEntrySource source,
const char *dir) {
_cleanup_closedir_ DIR *d = NULL;
@ -1212,16 +1242,21 @@ static int boot_entries_find_unified(
if (r < 0)
continue;
if (!GREEDY_REALLOC0(config->entries, config->n_entries + 2))
if (!GREEDY_REALLOC0(config->entries, config->n_entries + 1))
return log_oom();
if (boot_entry_load_unified(root, j, p, osrelease, profile, cmdline, config->entries + config->n_entries) < 0)
BootEntry *entry = config->entries + config->n_entries;
if (boot_entry_load_unified(root, source, j, p, osrelease, profile, cmdline, config->entries + config->n_entries) < 0)
continue;
config->n_entries++;
/* look for .efi.extra.d */
(void) boot_entries_find_unified_local_addons(config, dirfd(d), de->d_name, full, config->entries + config->n_entries);
(void) boot_entries_find_unified_local_addons(config, dirfd(d), de->d_name, full, entry);
/* Set up the backpointer, so that we can find the global addons */
entry->global_addons = &config->global_addons[source];
config->n_entries++;
}
}
@ -1438,32 +1473,37 @@ int boot_config_load(
int r;
assert(config);
config->global_addons = (BootEntryAddons) {};
if (esp_path) {
r = boot_loader_read_conf_path(config, esp_path, "/loader/loader.conf");
if (r < 0)
return r;
r = boot_entries_find_type1(config, esp_path, "/loader/entries");
r = boot_entries_find_type1(config, esp_path, BOOT_ENTRY_ESP, "/loader/entries");
if (r < 0)
return r;
r = boot_entries_find_unified(config, esp_path, "/EFI/Linux/");
r = boot_entries_find_unified(config, esp_path, BOOT_ENTRY_ESP, "/EFI/Linux/");
if (r < 0)
return r;
r = boot_entries_find_unified_global_addons(config, esp_path, "/loader/addons/");
r = boot_entries_find_unified_global_addons(config, esp_path, "/loader/addons/",
&config->global_addons[BOOT_ENTRY_ESP]);
if (r < 0)
return r;
}
if (xbootldr_path) {
r = boot_entries_find_type1(config, xbootldr_path, "/loader/entries");
r = boot_entries_find_type1(config, xbootldr_path, BOOT_ENTRY_XBOOTLDR, "/loader/entries");
if (r < 0)
return r;
r = boot_entries_find_unified(config, xbootldr_path, "/EFI/Linux/");
r = boot_entries_find_unified(config, xbootldr_path, BOOT_ENTRY_XBOOTLDR, "/EFI/Linux/");
if (r < 0)
return r;
r = boot_entries_find_unified_global_addons(config, xbootldr_path, "/loader/addons/",
&config->global_addons[BOOT_ENTRY_XBOOTLDR]);
if (r < 0)
return r;
}
@ -1518,6 +1558,7 @@ int boot_config_augment_from_loader(
char **found_by_loader,
bool only_auto) {
static const BootEntryAddons no_addons = (BootEntryAddons) {};
static const char *const title_table[] = {
/* Pretty names for a few well-known automatically discovered entries. */
"auto-osx", "macOS",
@ -1575,6 +1616,7 @@ int boot_config_augment_from_loader(
.reported_by_loader = true,
.tries_left = UINT_MAX,
.tries_done = UINT_MAX,
.global_addons = &no_addons,
};
}
@ -1646,9 +1688,7 @@ static int indent_embedded_newlines(char *cmdline, char **ret_cmdline) {
return 0;
}
static int print_cmdline(
const BootEntry *e,
const BootEntryAddons *global_arr) {
static int print_cmdline(const BootEntry *e) {
_cleanup_free_ char *options = NULL, *combined_cmdline = NULL, *t2 = NULL;
@ -1670,7 +1710,7 @@ static int print_cmdline(
return log_oom();
}
FOREACH_ARRAY(addon, global_arr->items, global_arr->n_items) {
FOREACH_ARRAY(addon, e->global_addons->items, e->global_addons->n_items) {
print_addon(addon, "global-addon");
if (!strextend(&t2, " ", addon->cmdline))
return log_oom();
@ -1718,7 +1758,6 @@ static int json_addon(
static int json_cmdline(
const BootEntry *e,
const BootEntryAddons *global_arr,
const char *def_cmdline,
sd_json_variant **v) {
@ -1734,7 +1773,7 @@ static int json_cmdline(
return log_oom();
}
FOREACH_ARRAY(addon, global_arr->items, global_arr->n_items) {
FOREACH_ARRAY(addon, e->global_addons->items, e->global_addons->n_items) {
r = json_addon(addon, "globalAddon", &addons_array);
if (r < 0)
return r;
@ -1761,7 +1800,6 @@ static int json_cmdline(
int show_boot_entry(
const BootEntry *e,
const BootEntryAddons *global_addons,
bool show_as_default,
bool show_as_selected,
bool show_reported) {
@ -1821,7 +1859,9 @@ int show_boot_entry(
if (e->type == BOOT_ENTRY_CONF)
(void) terminal_urlify_path(e->path, text, &link);
printf(" source: %s\n", link ?: text ?: e->path);
printf(" source: %s (on the %s)\n",
link ?: text ?: e->path,
boot_entry_source_to_string(e->source));
}
if (e->tries_left != UINT_MAX) {
printf(" tries: %u left", e->tries_left);
@ -1851,7 +1891,7 @@ int show_boot_entry(
*s,
&status);
r = print_cmdline(e, global_addons);
r = print_cmdline(e);
if (r < 0)
return r;
@ -1892,6 +1932,7 @@ int boot_entry_to_json(const BootConfig *c, size_t i, sd_json_variant **ret) {
r = sd_json_variant_merge_objectbo(
&v,
SD_JSON_BUILD_PAIR("type", SD_JSON_BUILD_STRING(boot_entry_type_json_to_string(e->type))),
SD_JSON_BUILD_PAIR("source", SD_JSON_BUILD_STRING(boot_entry_source_json_to_string(e->source))),
SD_JSON_BUILD_PAIR_CONDITION(!!e->id, "id", SD_JSON_BUILD_STRING(e->id)),
SD_JSON_BUILD_PAIR_CONDITION(!!e->path, "path", SD_JSON_BUILD_STRING(e->path)),
SD_JSON_BUILD_PAIR_CONDITION(!!e->root, "root", SD_JSON_BUILD_STRING(e->root)),
@ -1923,7 +1964,7 @@ int boot_entry_to_json(const BootConfig *c, size_t i, sd_json_variant **ret) {
if (r < 0)
return log_oom();
r = json_cmdline(e, &c->global_addons, opts, &v);
r = json_cmdline(e, opts, &v);
if (r < 0)
return log_oom();
@ -1956,7 +1997,6 @@ int show_boot_entries(const BootConfig *config, sd_json_format_flags_t json_form
for (size_t n = 0; n < config->n_entries; n++) {
r = show_boot_entry(
config->entries + n,
&config->global_addons,
/* show_as_default= */ n == (size_t) config->default_entry,
/* show_as_selected= */ n == (size_t) config->selected_entry,
/* show_discovered= */ true);

View File

@ -21,6 +21,13 @@ typedef enum BootEntryType {
_BOOT_ENTRY_TYPE_INVALID = -EINVAL,
} BootEntryType;
typedef enum BootEntrySource {
BOOT_ENTRY_ESP,
BOOT_ENTRY_XBOOTLDR,
_BOOT_ENTRY_SOURCE_MAX,
_BOOT_ENTRY_SOURCE_INVALID = -EINVAL,
} BootEntrySource;
typedef struct BootEntryAddon {
char *location;
char *cmdline;
@ -31,10 +38,9 @@ typedef struct BootEntryAddons {
size_t n_items;
} BootEntryAddons;
BootEntryAddon* boot_entry_addon_free(BootEntryAddon *t);
typedef struct BootEntry {
BootEntryType type;
BootEntrySource source;
bool reported_by_loader;
char *id; /* This is the file basename (including extension!) */
char *id_old; /* Old-style ID, for deduplication purposes. */
@ -49,6 +55,7 @@ typedef struct BootEntry {
char *architecture;
char **options;
BootEntryAddons local_addons;
const BootEntryAddons *global_addons; /* Backpointer into the BootConfig; we don't own this here */
char *kernel; /* linux is #defined to 1, yikes! */
char *efi;
char **initrd;
@ -59,9 +66,10 @@ typedef struct BootEntry {
unsigned profile;
} BootEntry;
#define BOOT_ENTRY_INIT(t) \
#define BOOT_ENTRY_INIT(t, s) \
{ \
.type = (t), \
.source = (s), \
.tries_left = UINT_MAX, \
.tries_done = UINT_MAX, \
}
@ -76,7 +84,7 @@ typedef struct BootConfig {
BootEntry *entries;
size_t n_entries;
BootEntryAddons global_addons;
BootEntryAddons global_addons[_BOOT_ENTRY_SOURCE_MAX];
ssize_t default_entry;
ssize_t selected_entry;
@ -93,6 +101,9 @@ typedef struct BootConfig {
const char* boot_entry_type_to_string(BootEntryType);
const char* boot_entry_type_json_to_string(BootEntryType);
const char* boot_entry_source_to_string(BootEntrySource);
const char* boot_entry_source_json_to_string(BootEntrySource);
BootEntry* boot_config_find_entry(BootConfig *config, const char *id);
static inline const BootEntry* boot_config_default_entry(const BootConfig *config) {
@ -113,6 +124,7 @@ int boot_config_load_type1(
BootConfig *config,
FILE *f,
const char *root,
const BootEntrySource source,
const char *dir,
const char *id);
@ -131,7 +143,6 @@ static inline const char* boot_entry_title(const BootEntry *entry) {
int show_boot_entry(
const BootEntry *e,
const BootEntryAddons *global_addons,
bool show_as_default,
bool show_as_selected,
bool show_reported);

View File

@ -42,6 +42,7 @@ import subprocess
import sys
import tempfile
import textwrap
import uuid
from collections.abc import Iterable, Iterator, Sequence
from hashlib import sha256
from pathlib import Path
@ -1013,14 +1014,9 @@ def merge_sbat(input_pe: list[Path], input_text: list[str]) -> str:
)
# Keep in sync with EFI_GUID (src/boot/efi.h)
# uint32_t Data1, uint16_t Data2, uint16_t Data3, uint8_t Data4[8]
EFI_GUID = tuple[int, int, int, tuple[int, int, int, int, int, int, int, int]]
EFI_GUID_STRUCT_SIZE = 4 + 2 + 2 + 1 * 8
# Keep in sync with Device (DEVICE_TYPE_DEVICETREE) from src/boot/chid.h
# uint32_t descriptor, EFI_GUID chid, uint32_t name_offset, uint32_t compatible_offset
DEVICE_STRUCT_SIZE = 4 + EFI_GUID_STRUCT_SIZE + 4 + 4
DEVICE_STRUCT_SIZE = 4 + 16 + 4 + 4
NULL_DEVICE = b'\0' * DEVICE_STRUCT_SIZE
DEVICE_TYPE_DEVICETREE = 1
@ -1029,29 +1025,21 @@ def device_make_descriptor(device_type: int, size: int) -> int:
return (size) | (device_type << 28)
def pack_device(offsets: dict[str, int], name: str, compatible: str, chids: list[EFI_GUID]) -> bytes:
DEVICETREE_DESCRIPTOR = device_make_descriptor(DEVICE_TYPE_DEVICETREE, DEVICE_STRUCT_SIZE)
def pack_device(offsets: dict[str, int], name: str, compatible: str, chids: set[uuid.UUID]) -> bytes:
data = b''
for data1, data2, data3, data4 in chids:
data += struct.pack(
'<IIHH8BII',
device_make_descriptor(DEVICE_TYPE_DEVICETREE, DEVICE_STRUCT_SIZE),
data1,
data2,
data3,
*data4,
offsets[name],
offsets[compatible],
)
for chid in sorted(chids):
data += struct.pack('<I', DEVICETREE_DESCRIPTOR)
data += chid.bytes_le
data += struct.pack('<II', offsets[name], offsets[compatible])
assert len(data) == DEVICE_STRUCT_SIZE * len(chids)
return data
def hex_pairs_list(string: str) -> list[int]:
return [int(string[i : i + 2], 16) for i in range(0, len(string), 2)]
def pack_strings(strings: set[str], base: int) -> tuple[bytes, dict[str, int]]:
blob = b''
offsets = {}
@ -1064,56 +1052,22 @@ def pack_strings(strings: set[str], base: int) -> tuple[bytes, dict[str, int]]:
def parse_hwid_dir(path: Path) -> bytes:
hwid_files = path.rglob('*.txt')
hwid_files = path.rglob('*.json')
strings: set[str] = set()
devices: collections.defaultdict[tuple[str, str], list[EFI_GUID]] = collections.defaultdict(list)
uuid_regexp = re.compile(
r'\{[0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}\}', re.I
)
devices: collections.defaultdict[tuple[str, str], set[uuid.UUID]] = collections.defaultdict(set)
for hwid_file in hwid_files:
content = hwid_file.open().readlines()
data = json.loads(hwid_file.read_text(encoding='UTF-8'))
data: dict[str, str] = {
'Manufacturer': '',
'Family': '',
'Compatible': '',
}
uuids: list[EFI_GUID] = []
for line in content:
for k in data:
if line.startswith(k):
data[k] = line.split(':')[1].strip()
break
else:
uuid = uuid_regexp.match(line)
if uuid is not None:
d1, d2, d3, d4, d5 = uuid.group(0)[1:-1].split('-')
data1 = int(d1, 16)
data2 = int(d2, 16)
data3 = int(d3, 16)
data4 = cast(
tuple[int, int, int, int, int, int, int, int],
tuple(hex_pairs_list(d4) + hex_pairs_list(d5)),
)
uuids.append((data1, data2, data3, data4))
for k, v in data.items():
if not v:
for k in ['name', 'compatible', 'hwids']:
if k not in data:
raise ValueError(f'hwid description file "{hwid_file}" does not contain "{k}"')
name = data['Manufacturer'] + ' ' + data['Family']
compatible = data['Compatible']
strings |= {data['name'], data['compatible']}
strings |= set([name, compatible])
# (compatible, name) pair uniquely identifies the device
devices[(compatible, name)] += uuids
# (name, compatible) pair uniquely identifies the device
devices[(data['name'], data['compatible'])] |= {uuid.UUID(u) for u in data['hwids']}
total_device_structs = 1
for dev, uuids in devices.items():
@ -1122,7 +1076,7 @@ def parse_hwid_dir(path: Path) -> bytes:
strings_blob, offsets = pack_strings(strings, total_device_structs * DEVICE_STRUCT_SIZE)
devices_blob = b''
for (compatible, name), uuids in devices.items():
for (name, compatible), uuids in devices.items():
devices_blob += pack_device(offsets, name, compatible, uuids)
devices_blob += NULL_DEVICE