1
0
mirror of https://github.com/systemd/systemd synced 2026-04-22 23:15:20 +02:00

Compare commits

..

10 Commits

Author SHA1 Message Date
Frantisek Sumsal
34c4dff4d2 time-util: support parsing OUTPUT_SHORT and OUTPUT_SHORT_PRECISE timestamps
so we can feed journalctl the localized syslog-style timestamps it shows
by default, e.g.:

```
$ LANG=cs_CZ.utf-8 build-san/journalctl -b --no-hostname | head -n1
led 30 22:13:54 systemd-journald[981]: System Journal (/var/log/journal/1588e1d9d0b74acdbaada907b163b837) is 4.1G, max 4.0G, 0B free.
$ LANG=cs_CZ.utf-8 build-san/journalctl --no-hostname --since 'led 30 22:13:54' -n1
led 30 22:13:54 systemd-journald[981]: System Journal (/var/log/journal/1588e1d9d0b74acdbaada907b163b837) is 4.1G, max 4.0G, 0B free.
$ LANG=cs_CZ.utf-8 build-san/journalctl --no-hostname --since 'led 30 22:13:54.9999' -n1
led 30 22:13:58 rsyslogd[1300]: imjournal: journal files changed, reloading...  [v8.2102.0-4.fc35 try https://www.rsyslog.com/e/0 ]
```

Resolves: #15899
2022-03-12 17:18:08 +00:00
Luca Boccassi
1627f158fc
Merge pull request #22463 from poettering/kernel-install-propagate-machine-id
kernel-install: clean-up machine-id handling
2022-03-12 17:17:28 +00:00
Lennart Poettering
5e9c57d2e2 NEWS: add NEWS entry highlighting what the "entry-token" logic means for "gold image" builders 2022-03-11 11:39:34 +01:00
Lennart Poettering
f337f903df bootctl: update to new kernel-install semantics
This makes a bunch of closely related changes:

1. The "entry-token" concept already introduced in kernel-install is now
   made use of. i.e. specifically there's a new option --entry-token=
   that can be used to explicitly select by which ID to identify boot
   loader entries: the machine ID, or some OS ID (ID= or IMAGE_ID= from
   /etc/os-release, or even some completely different string. The
   selected string is then persisted to /etc/kernel/entry-token, so that
   kernel-install can find it there.

2. The --make-machine-id-directory= switch is renamed to
   --make-entry-directory= since after all it's not necessarily the
   machine ID the dir is named after, but can be any other string as
   selected by the entry token.

3. This drops all code to make automatic changes to /etc/machine-info.
   Specifically, the KERNEL_INSTALL_MACHINE_ID= field is now more
   generically implemented in /etc/kernel/entry-token described above,
   hence no need to place it at two locations. And the
   KERNEL_INSTALL_LAYOUT= field is not configurable by user switch or
   similar anyway in bootctl, but only read from
   /etc/kernel/install.conf, and hence copying it from one configuration
   file to another appears unnecessary, the second copy is fully
   redundant. Note that this just drops writing these fields, they'll
   still be honoured when already set.
2022-03-11 11:39:34 +01:00
Lennart Poettering
fe81e346c8 man: document recent changes
This drops documentation of KERNEL_INSTALL_MACHINE_ID as machine-info
field (though we'll still read it for compat).

This updates the kernel-install man page to always say "ENTRY-TOKEN"
instead of "MACHINE-ID" where appropriate, to clear the confusion up
between the two.

This also tries to fix how we denote env vars (always prefix with $ and
without = suffix), and other vars (without $ but with = suffix)

Other fixes.
2022-03-11 11:39:34 +01:00
Lennart Poettering
c73cf41844 kernel-install: add new "inspect" verb, showing paths and parameters we discovered 2022-03-11 11:39:34 +01:00
Lennart Poettering
6637cf9db6 kernel-install: search harder for kernel image/initrd drop-in dir
If not explicitly configured, let's search a bit harder for the
ENTRY_TOKEN, and let's try the machine ID, the IMAGE_ID and ID fields of
/etc/os-release and finally "Default", all below potential $XBOOTLDR.
2022-03-11 11:34:34 +01:00
Lennart Poettering
953b61004c kernel-install: only generate systemd.boot_id= in kernel command line if used for naming the boot loader spec files/dirs
Now that we can distinguish the naming of the boot loader spec
dirs/files and the machine ID let's tweak the logic for suffixing the
kernel cmdline with systemd.boot_id=: let's only do that when we
actually need the boot ID for naming these dirs/files. If we don't,
let's not bother.

This should be beneficial for "golden" images that shall not carry any
machine IDs at all, i.e acquire their identity only once the final
userspace is actually reached.
2022-03-11 11:34:34 +01:00
Lennart Poettering
3907044ffa kernel-install: add a new $ENTRY_TOKEN variable for naming boot entries
This cleans up naming of boot loader spec boot entries a bit (i.e. the
naming of the .conf snippet files, and the directory in $BOOT where the
kernel images and initrds are placed), and isolates it from the actual machine
ID concept.

Previously there was a sinlge concept for both things, because typically
the entries are just named after the machine ID. However one could also
use a different identifier, i.e. not a 128bit ID in which cases issues
pop up everywhere. For example, the "machine-id" field in the generated
snippets would not be a machine ID anymore, and the newly added
systemd.machine_id= kernel parameter would possibly get passed invalid
data.

Hence clean this up:

$MACHINE_ID → always a valid 128bit ID.

$ENTRY_TOKEN → usually the $MACHINE_ID but can be any other string too.
This is used to name the directory to put kernels/initrds in. It's also
used for naming the *.conf snippets that implement the Boot Loader Type
1 spec.
2022-03-11 11:34:34 +01:00
Lennart Poettering
11ce3ea2f2 kernel-install: don't try to persist used machine ID locally
This reworks the how machine ID used by the boot loader spec snippet
generation logic. Instead of persisting it automatically to /etc/ we'll
append it via systemd.machined_id= to the kernel command line, and thus
persist it in the generated boot loader spec snippets instead. This has
nice benefits:

  1. We do not collide with read-only root
  2. The machine ID remains stable across factory reset, so that we can
     safely recognize the path in $BOOT we drop our kernel images in
     again, i.e. kernel updates will work correctly and safely across
     kernel factory resets.
  3. Previously regular systems had different machine IDs while in
     initrd and after booting into the host system. With this change
     they will now have the same.

This then drops implicit persisting of KERNEL_INSTALL_MACHINE_ID, as its
unnecessary then. The field is still honoured though, for compat
reasons.

This also drops the "Default" fallback previously used, as it actually
is without effect, the randomized ID generation already took precedence
in all cases. This means $MACHNE_ID/KERNEL_INSTALL_MACHINE_ID are now
guaranteed to look like a proper machine ID, which is useful for us,
given you need it that way to be able to pass it to the
systemd.machine_id= kernel command line option.
2022-03-11 11:34:34 +01:00
9 changed files with 499 additions and 257 deletions

43
NEWS
View File

@ -21,13 +21,42 @@ CHANGES WITH 251:
for breaking backward compatibility instead, as nobody should be
affected, given the state of the current interface.
* Service monitor environment variables will only be passed to OnFailure=/OnSuccess=
handlers if exactly one unit lists the handler unit as OnFailure=/OnSuccess=.
Therefore, $MONITOR_METADATA is no longer used, and instead separate
variables are used: $MONITOR_SERVICE_RESULT, $MONITOR_EXIT_CODE,
$MONITOR_EXIT_STATUS, $MONITOR_INVOCATION_ID and $MONITOR_UNIT.
For cases when a single handler needs to watch multiple units, use a
templated handler.
* Service monitor environment variables will only be passed to
OnFailure=/OnSuccess= handlers if exactly one unit lists the handler
unit as OnFailure=/OnSuccess=. Therefore, $MONITOR_METADATA is no
longer used, and instead separate variables are used:
$MONITOR_SERVICE_RESULT, $MONITOR_EXIT_CODE, $MONITOR_EXIT_STATUS,
$MONITOR_INVOCATION_ID and $MONITOR_UNIT. For cases when a single
handler needs to watch multiple units, use a templated handler.
* kernel-install's and bootctl's Boot Loader Specification Type #1
entry generation logic has been reworked. The user may now pick
explicitly by which "token" string to name the installation's boot
entries, through the new /etc/kernel/entry-token file or the new
--entry-token= switch to bootctl. By default — as before — the
entries are named after the local machine ID. However, in "golden
image" environments, where the machine ID shall be initialized on
first boot (as opposed to at installation time before first boot) the
machine ID is not be available at build time to name the entry
after. In this case the the --entry-token= switch to bootctl (or the
/etc/kernel/entry-token file) may be used to override the "token" to
identify the entry by, and use another ID, for example the IMAGE_ID=
or ID= fields from /etc/os-release. This will make the OS images
independent of any machine ID, and ensure that the images will not
carry any identifiable information before first boot, but on the
other hand means that multiple parallel installations of the very
same image on the same disk cannot be supported. Summary: if you are
building golden images that shall acquire identity information
exclusively on first boot, make sure to both remove /etc/machine-id
*and* to write /etc/kernel/entry-token to the value of the IMAGE_ID
or ID field of /etc/os-release or another suitable identifier before
deploying the image.
* The --make-machine-id-directory= switch to bootctl has been replaced
by --make-entry-directory=, given that the entry directory is not
necessarily named after the machine ID, but after some other suitable
ID as selected via --entry-token= described above. The old name of
the option is still understood to maximize compatibility.
* Services with Restart=always and a failing ExecCondition= will no longer
be restarted, to bring ExecCondition= in line with Condition*= settings.

View File

@ -258,23 +258,60 @@
</varlistentry>
<varlistentry>
<term><option>--make-machine-id-directory=yes|no</option></term>
<listitem><para>Control creation and deletion of the top-level machine ID directory on the file
system containing boot loader entries (i.e. beneath the file system returned by the
<option>--print-boot-path</option> option, see above) during <option>install</option> and
<option>remove</option>, respectively. Defaults to <literal>no</literal>. See
<term><option>--make-entry-directory=yes|no</option></term>
<listitem><para>Controls creation and deletion of the <ulink
url="https://systemd.io/BOOT_LOADER_SPECIFICATION">Boot Loader Specification</ulink> Type #1 entry
directory on the file system containing resources such as kernel images and initial RAM disk images
during <option>install</option> and <option>remove</option>, respectively. The directory is named
after the entry token, as specified with <option>--entry-token=</option> parameter described below,
and is placed immediately below the <varname>$BOOT</varname> root directory (i.e. beneath the file
system returned by the <option>--print-boot-path</option> option, see above). Defaults to
<literal>no</literal>.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--entry-token=</option></term>
<listitem><para>Controls how to name and identify boot loader entries for this OS
installation. Accepted during <option>install</option>, and takes one of <literal>auto</literal>,
<literal>machine-id</literal>, <literal>os-id</literal>, <literal>os-image-id</literal> or an
arbitrary string prefixed by <literal>literal:</literal> as argument.</para>
<para>If set to <option>machine-id</option> the entries are named after the machine ID of the running
system (e.g. <literal>b0e793a9baf14b5fa13ecbe84ff637ac</literal>). See
<citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
details about the machine ID concept and file.</para>
<para>Overriding this may be desirable to hide the machine ID from the (unencrypted) ESP, configure a
<citerefentry><refentrytitle>kernel-install</refentrytitle><manvolnum>8</manvolnum></citerefentry>
script, or, conversely, commit a transient machine ID.</para>
<para>If set to <option>os-id</option> the entries are named after the OS ID of the running system,
i.e. the <varname>ID=</varname> field of
<citerefentry><refentrytitle>os-release</refentrytitle><manvolnum>5</manvolnum></citerefentry>
(e.g. <literal>fedora</literal>). Similar, if set to <option>os-image-id</option> the entries are
named after the OS image ID of the running system, i.e. the <varname>IMAGE_ID=</varname> field of
<filename>os-release</filename> (e.g. <literal>vendorx-cashier-system</literal>).</para>
<para>The top-level machine ID directory is useful to allow smooth multi-boot installations: each
installed OS instance will have a different machine ID and thus a separate directory to place its
boot-time resources in. If this feature is turned off with this option, care needs to be taken that
multiple OS instances do not place conflicting files on the shared ESP and Extended Boot Loader
Partitions, or that multiple OS instances are not possible.</para></listitem>
<para>If set to <option>auto</option> (the default), the <filename>/etc/kernel/entry-token</filename>
file will be read if it exists, and the stored value used. Otherwise if the local machine ID is
initialized it is used. Otherwise <varname>IMAGE_ID=</varname> from <filename>os-release</filename>
will be used, if set. Otherwise, <varname>ID=</varname> from <filename>os-release</filename> will be
used, if set.</para>
<para>Unless set to <literal>machine-id</literal>, or when
<option>--make-entry-directory=yes</option> is used the selected token string is written to a file
<filename>/etc/kernel/entry-token</filename>, to ensure it will be used for future entries. This file
is also read by
<citerefentry><refentrytitle>kernel-install</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
in order to identify under which name to generate boot loader entries for newly installed kernels, or
to determine the entry names for removing old ones.</para>
<para>Using the machine ID for naming the entries is generally preferable, however there are cases
where using the other identifiers is a good option. Specifically: if the identification data that the
machine ID entails shall not be stored on the (unencrypted) <varname>$BOOT</varname> partition, or if
the ID shall be generated on first boot and is not known when the entries are prepared. Note that
using the machine ID has the benefit that multiple parallel installations of the same OS can coexist
on the same medium, and they can update their boot loader entries independently. When using another
identifier (such as the OS ID or the OS image ID), parallel installations of the same OS would try to
use the same entry name. To support parallel installations, the installer must use a different entry
token when adding a second installation.</para></listitem>
</varlistentry>
<xi:include href="standard-options.xml" xpointer="no-pager"/>

View File

@ -39,21 +39,21 @@
<filename>/boot/</filename>, <filename>/efi/</filename>, or <filename>/boot/efi/</filename>, see below.
</para>
<para><command>kernel-install</command> will execute the files
located in the directory <filename>/usr/lib/kernel/install.d/</filename>
and the local administration directory <filename>/etc/kernel/install.d/</filename>.
All files are collectively sorted and executed in lexical order, regardless of the directory in
which they live. However, files with identical filenames replace each other.
Files in <filename>/etc/kernel/install.d/</filename> take precedence over files with the same name
in <filename>/usr/lib/kernel/install.d/</filename>. This can be used to override a system-supplied
executables with a local file if needed; a symbolic link in <filename>/etc/kernel/install.d/</filename>
with the same name as an executable in <filename>/usr/lib/kernel/install.d/</filename>,
pointing to <filename>/dev/null</filename>, disables the executable entirely. Executables must have the
extension <literal>.install</literal>; other extensions are ignored.</para>
<para><command>kernel-install</command> will run the executable files ("plugins") located in the
directory <filename>/usr/lib/kernel/install.d/</filename> and the local administration directory
<filename>/etc/kernel/install.d/</filename>. All files are collectively sorted and executed in lexical
order, regardless of the directory in which they live. However, files with identical filenames replace
each other. Files in <filename>/etc/kernel/install.d/</filename> take precedence over files with the
same name in <filename>/usr/lib/kernel/install.d/</filename>. This can be used to override a
system-supplied executables with a local file if needed; a symbolic link in
<filename>/etc/kernel/install.d/</filename> with the same name as an executable in
<filename>/usr/lib/kernel/install.d/</filename>, pointing to <filename>/dev/null</filename>, disables the
executable entirely. Executables must have the extension <literal>.install</literal>; other extensions
are ignored.</para>
<para>An executable should return <constant>0</constant> on success. It may also
return <constant>77</constant> to cause the whole operation to terminate
(executables later in lexical order will be skipped).</para>
<para>An executable placed in these directories should return <constant>0</constant> on success. It may
also return <constant>77</constant> to cause the whole operation to terminate (executables later in
lexical order will be skipped).</para>
</refsect1>
<refsect1>
@ -64,37 +64,45 @@
<term><command>add <replaceable>KERNEL-VERSION</replaceable> <replaceable>KERNEL-IMAGE</replaceable> [<replaceable>INITRD-FILE</replaceable> ...]</command></term>
<listitem>
<para>This command expects a kernel version string and a path to a kernel image file as
arguments. <command>kernel-install</command> calls the executables from
<filename>/usr/lib/kernel/install.d/*.install</filename> and
<filename>/etc/kernel/install.d/*.install</filename> with the following arguments:
arguments. Optionally, one or more initial RAM disk images may be specified as well (note that
plugins might generate additional ones). <command>kernel-install</command> calls the executable
files from <filename>/usr/lib/kernel/install.d/*.install</filename> and
<filename>/etc/kernel/install.d/*.install</filename> (i.e. the plugins) with the following
arguments:</para>
<programlisting>add <replaceable>KERNEL-VERSION</replaceable> <filename>$BOOT/<replaceable>MACHINE-ID</replaceable>/<replaceable>KERNEL-VERSION</replaceable>/</filename> <replaceable>KERNEL-IMAGE</replaceable> [<replaceable>INITRD-FILE</replaceable> ...]</programlisting>
</para>
<programlisting>add <replaceable>KERNEL-VERSION</replaceable> <filename>$BOOT/<replaceable>ENTRY-TOKEN</replaceable>/<replaceable>KERNEL-VERSION</replaceable>/</filename> <replaceable>KERNEL-IMAGE</replaceable> [<replaceable>INITRD-FILE</replaceable> ...]</programlisting>
<para>The third argument directly refers to the path where to place kernel images, initial RAM disk
images and other resources for <ulink url="https://systemd.io/BOOT_LOADER_SPECIFICATION">Boot
Loader Specification</ulink> Type #1 entries (the "entry directory"). If other boot loader schemes
are used the parameter may be ignored. The <replaceable>ENTRY-TOKEN</replaceable> string is
typically the machine ID and is supposed to identify the local installation on the system. For
details see below.</para>
<para>Two default plugins execute the following operations in this case:</para>
<itemizedlist>
<listitem><para><command>kernel-install</command> creates
<filename>$BOOT/<replaceable>MACHINE-ID</replaceable>/<replaceable>KERNEL-VERSION</replaceable></filename>,
if enabled (see <varname>$KERNEL_INSTALL_LAYOUT=</varname>).</para></listitem>
<filename>$BOOT/<replaceable>ENTRY-TOKEN</replaceable>/<replaceable>KERNEL-VERSION</replaceable></filename>,
if enabled (see <varname>$KERNEL_INSTALL_LAYOUT</varname>).</para></listitem>
<listitem><para><filename>50-depmod.install</filename> runs
<citerefentry project='man-pages'><refentrytitle>depmod</refentrytitle><manvolnum>8</manvolnum></citerefentry> for the
<replaceable>KERNEL-VERSION</replaceable>.</para></listitem>
<listitem><para><filename>90-loaderentry.install</filename>
copies <replaceable>KERNEL-IMAGE</replaceable> to
<filename>$BOOT/<replaceable>MACHINE-ID</replaceable>/<replaceable>KERNEL-VERSION</replaceable>/linux</filename>.
<listitem><para><filename>90-loaderentry.install</filename> copies
<replaceable>KERNEL-IMAGE</replaceable> to
<filename>$BOOT/<replaceable>ENTRY-TOKEN</replaceable>/<replaceable>KERNEL-VERSION</replaceable>/linux</filename>.
If <replaceable>INITRD-FILE</replaceable>s are provided, it also copies them to
<filename>$BOOT/<replaceable>MACHINE-ID</replaceable>/<replaceable>KERNEL_VERSION</replaceable>/<replaceable>INITRD-FILE</replaceable></filename>.
<filename>$BOOT/<replaceable>ENTRY-TOKEN</replaceable>/<replaceable>KERNEL_VERSION</replaceable>/<replaceable>INITRD-FILE</replaceable></filename>.
It also creates a boot loader entry according to the <ulink
url="https://systemd.io/BOOT_LOADER_SPECIFICATION">Boot Loader Specification</ulink> in
<filename>$BOOT/loader/entries/<replaceable>MACHINE-ID</replaceable>-<replaceable>KERNEL-VERSION</replaceable>.conf</filename>.
url="https://systemd.io/BOOT_LOADER_SPECIFICATION">Boot Loader Specification</ulink> (Type #1) in
<filename>$BOOT/loader/entries/<replaceable>ENTRY-TOKEN</replaceable>-<replaceable>KERNEL-VERSION</replaceable>.conf</filename>.
The title of the entry is the <replaceable>PRETTY_NAME</replaceable> parameter specified in
<filename>/etc/os-release</filename> or <filename>/usr/lib/os-release</filename> (if the former is
missing), or "Linux <replaceable>KERNEL-VERSION</replaceable>", if unset.</para>
<filename>/etc/os-release</filename> or <filename>/usr/lib/os-release</filename> (if the former
is missing), or "Linux <replaceable>KERNEL-VERSION</replaceable>", if unset.</para>
<para>If <varname>$KERNEL_INSTALL_LAYOUT=</varname> is not "bls", this plugin does nothing.</para></listitem>
<para>If <varname>$KERNEL_INSTALL_LAYOUT</varname> is not "bls", this plugin does nothing.</para></listitem>
</itemizedlist>
</listitem>
</varlistentry>
@ -104,13 +112,13 @@
<para>This command expects a kernel version string as single argument. This calls executables from
<filename>/usr/lib/kernel/install.d/*.install</filename> and
<filename>/etc/kernel/install.d/*.install</filename> with the following arguments:
<programlisting>remove <replaceable>KERNEL-VERSION</replaceable> <filename>$BOOT/<replaceable>MACHINE-ID</replaceable>/<replaceable>KERNEL-VERSION</replaceable>/</filename></programlisting>
</para>
<para>Afterwards, <command>kernel-install</command> removes the directory
<filename>$BOOT/<replaceable>MACHINE-ID</replaceable>/<replaceable>KERNEL-VERSION</replaceable>/</filename>
and its contents.</para>
<programlisting>remove <replaceable>KERNEL-VERSION</replaceable> <filename>$BOOT/<replaceable>ENTRY-TOKEN</replaceable>/<replaceable>KERNEL-VERSION</replaceable>/</filename></programlisting>
<para>Afterwards, <command>kernel-install</command> removes the entry directory
<filename>$BOOT/<replaceable>ENTRY-TOKEN</replaceable>/<replaceable>KERNEL-VERSION</replaceable>/</filename>
and its contents, if it exists.</para>
<para>Two default plugins execute the following operations in this case:</para>
@ -118,14 +126,18 @@
<listitem><para><filename>50-depmod.install</filename> removes the files generated by <command>depmod</command> for this kernel again.</para></listitem>
<listitem><para><filename>90-loaderentry.install</filename> removes the file
<filename>$BOOT/loader/entries/<replaceable>MACHINE-ID</replaceable>-<replaceable>KERNEL-VERSION</replaceable>.conf</filename>.</para></listitem>
<listitem><para><command>kernel-install</command> removes
<filename>$BOOT/<replaceable>MACHINE-ID</replaceable>/<replaceable>KERNEL-VERSION</replaceable></filename>,
if enabled (see <varname>$KERNEL_INSTALL_LAYOUT=</varname>).</para></listitem>
<filename>$BOOT/loader/entries/<replaceable>ENTRY-TOKEN</replaceable>-<replaceable>KERNEL-VERSION</replaceable>.conf</filename>.</para></listitem>
</itemizedlist>
</listitem>
</varlistentry>
<varlistentry>
<term><command>inspect</command></term>
<listitem>
<para>Shows the various paths and parameters configured or auto-detected. In particular shows the
values of the various <varname>$KERNEL_INSTALL_*</varname> environment variables listed
below.</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
@ -135,9 +147,9 @@
<para>The partition where the kernels and <ulink url="https://systemd.io/BOOT_LOADER_SPECIFICATION">Boot
Loader Specification</ulink> snippets are located is called <varname>$BOOT</varname>.
<command>kernel-install</command> determines the location of this partition by checking
<filename>/efi/</filename>, <filename>/boot/</filename>, and <filename>/boot/efi/</filename>
in turn. The first location where <filename>$BOOT/loader/entries/</filename> or
<filename>$BOOT/$MACHINE_ID/</filename> exists is used.</para>
<filename>/efi/</filename>, <filename>/boot/</filename>, and <filename>/boot/efi/</filename> in turn. The
first location where <filename>$BOOT/loader/entries/</filename> or
<filename>$BOOT/<replaceable>ENTRY-TOKEN</replaceable>/</filename> exists is used.</para>
</refsect1>
<refsect1>
@ -163,36 +175,57 @@
<para>If <option>--verbose</option> is used, <varname>$KERNEL_INSTALL_VERBOSE=1</varname> will be set for
the plugins. They may output additional logs in this case.</para>
<para>If <varname>MACHINE_ID=</varname> is set and not empty, it will be used as <replaceable>MACHINE-ID</replaceable>,
overriding any automatic detection attempts. The value must be a valid machine ID (32 hexadecimal characters).</para>
<para>If <varname>$MACHINE_ID</varname> is set and not empty when <command>kernel-install</command> is
invoked, it will be used as <replaceable>MACHINE-ID</replaceable>, overriding any automatic detection
attempts. The value must be a valid machine ID (32 hexadecimal characters).</para>
<para><varname>KERNEL_INSTALL_MACHINE_ID=</varname> is set for the plugins to the desired <replaceable>MACHINE-ID</replaceable>
either 32 hexadecimal characters or the special value <literal>Default</literal>.</para>
<para><varname>KERNEL_INSTALL_BOOT_ROOT=</varname> is set for the plugins to the root directory (mount point, usually) of the hierarchy
where boot-loader entries, kernel images, and associated resources should be placed. Can be overridden by setting <varname>BOOT_ROOT=</varname>.</para>
<para><varname>$KERNEL_INSTALL_MACHINE_ID</varname> is set for the plugins to the desired
<replaceable>MACHINE-ID</replaceable> to use. It's always a 128bit ID, and typically the ID from
<filename>/etc/machine-id</filename> or the one passed in via <varname>$MACHINE_ID</varname>. (If no
machine ID was specified via these methods it might be generated randomly by
<command>kernel-install</command>, in which case it only applies to this invocation.)</para>
<para><varname>KERNEL_INSTALL_LAYOUT=bls|other|...</varname> is set for the plugins to specify the installation layout.
Defaults to <option>bls</option> if <filename>$BOOT/<replaceable>MACHINE-ID</replaceable></filename> exists, or <option>other</option> otherwise.
Additional layout names may be defined by convention. If a plugin uses a special layout,
it's encouraged to declare its own layout name and configure <varname>layout=</varname> in <filename>install.conf</filename> upon initial installation.</para>
<para><varname>$KERNEL_INSTALL_ENTRY_TOKEN</varname> is set for the plugins to the desired entry "token"
to use. It's an identifier that shall be used to identify the local installation, and is often the
machine ID, i.e. same as <varname>$KERNEL_INSTALL_MACHINE_ID</varname>, but might also be a different
type of identifier, for example a fixed string or the <varname>ID=</varname>,
<varname>IMAGE_ID=</varname> values from <filename>/etc/os-release</filename>. The string passed here
will be used to name Boot Loader Specification entries, or the directories the kernel image and initial
RAM disk images are placed into. Note that while oftentimes
<varname>$KERNEL_INSTALL_ENTRY_TOKEN</varname> and <varname>$KERNEL_INSTALL_MACHINE_ID</varname> are set
to the same value, the latter is guaranteed to be a valid 32 character ID in lowercase hexadecimals while
the former can be any short string. The entry token to use is read from
<filename>/etc/kernel/entry-token</filename>, if it exists. Otherwise a few possible candidates below the
<varname>$BOOT</varname> are searched for Boot Loader Specification Type 1 entry directories, and if
found the entry token is derived from that. If that is not successful the machine ID is used as
fallback.</para>
<para><varname>KERNEL_INSTALL_INITRD_GENERATOR=...</varname> is set for plugins to select the initrd generator.
This should be configured as <varname>initrd_generator=</varname> in <filename>install.conf</filename>.
</para>
<para><varname>$KERNEL_INSTALL_BOOT_ROOT</varname> is set for the plugins to the absolute path of the
root directory (mount point, usually) of the hierarchy where boot loader entries, kernel images, and
associated resources should be placed. This usually is the path where the XBOOTLDR partition or the ESP
(EFI System Partition) are mounted, and also conceptually referred to as <varname>$BOOT</varname>. Can be
overridden by setting <varname>$BOOT_ROOT</varname>.</para>
<para><varname>KERNEL_INSTALL_STAGING_AREA=...</varname> is set for plugins to a path to a directory.
Plugins may drop files in that directory, and they will be installed as part of the loader entry, based
on the file name and extension.</para>
<para><varname>$KERNEL_INSTALL_LAYOUT=bls|other|...</varname> is set for the plugins to specify the
installation layout. Defaults to <option>bls</option> if
<filename>$BOOT/<replaceable>ENTRY-TOKEN</replaceable></filename> exists, or <option>other</option>
otherwise. Additional layout names may be defined by convention. If a plugin uses a special layout, it's
encouraged to declare its own layout name and configure <varname>layout=</varname> in
<filename>install.conf</filename> upon initial installation. The following values are currently
understood:</para>
<variablelist>
<varlistentry>
<term>bls</term>
<listitem>
<para>Standard <ulink url="https://systemd.io/BOOT_LOADER_SPECIFICATION">Boot Loader Specification</ulink> layout,
compatible with <citerefentry><refentrytitle>systemd-boot</refentrytitle><manvolnum>7</manvolnum></citerefentry>: entries in
<filename>$BOOT/loader/entries/<replaceable>MACHINE-ID</replaceable>-<replaceable>KERNEL-VERSION</replaceable>[+<replaceable>TRIES</replaceable>].conf</filename>,
kernel and initrds under <filename>$BOOT/<replaceable>MACHINE-ID</replaceable>/<replaceable>KERNEL-VERSION</replaceable>/</filename></para>
<para>Provided by <filename>90-loaderentry.install</filename>.</para>
<para>Standard <ulink url="https://systemd.io/BOOT_LOADER_SPECIFICATION">Boot Loader
Specification</ulink> Type #1 layout, compatible with
<citerefentry><refentrytitle>systemd-boot</refentrytitle><manvolnum>7</manvolnum></citerefentry>:
entries in
<filename>$BOOT/loader/entries/<replaceable>ENTRY-TOKEN</replaceable>-<replaceable>KERNEL-VERSION</replaceable>[+<replaceable>TRIES</replaceable>].conf</filename>,
kernel and initrds under
<filename>$BOOT/<replaceable>ENTRY-TOKEN</replaceable>/<replaceable>KERNEL-VERSION</replaceable>/</filename></para>
<para>Implemented by <filename>90-loaderentry.install</filename>.</para>
</listitem>
</varlistentry>
<varlistentry>
@ -202,6 +235,15 @@
</listitem>
</varlistentry>
</variablelist>
<para><varname>$KERNEL_INSTALL_INITRD_GENERATOR</varname> is set for plugins to select the initrd
generator. This should be configured as <varname>initrd_generator=</varname> in
<filename>install.conf</filename>.
</para>
<para><varname>$KERNEL_INSTALL_STAGING_AREA</varname> is set for plugins to a path to a directory.
Plugins may drop files in that directory, and they will be installed as part of the loader entry, based
on the file name and extension.</para>
</refsect1>
<refsect1>
@ -249,25 +291,21 @@
</varlistentry>
<varlistentry>
<term>
<filename>/etc/machine-id</filename>
<filename>/etc/kernel/entry-token</filename>
</term>
<listitem>
<para>The content of this file specifies the machine identification
<replaceable>MACHINE-ID</replaceable>. If <filename>/etc/machine-id</filename>
cannot be read or is temporary (backed by a file on <constant>tmpfs</constant>),
<command>kernel-install</command> will use <literal>Default</literal> instead.</para>
<para>If this file exists it is read and used as "entry token" for this system, i.e. is used for
naming Boot Loader Specification entries, see
<varname>$KERNEL_INSTALL_ENTRY_TOKEN</varname> above for details.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<filename>/etc/machine-info</filename>
<filename>/etc/machine-id</filename>
</term>
<listitem>
<para>If this file contains the <varname>KERNEL_INSTALL_MACHINE_ID</varname> variable,
<command>kernel-install</command> will use it as <replaceable>MACHINE-ID</replaceable> instead of
the contents of <filename>/etc/machine-id</filename>. If the variable is not found in
<filename>/etc/machine-info</filename>, <command>kernel-install</command> will try to save the
machine ID it uses to install to <varname>$BOOT</varname> to this file.</para>
<para>The content of this file specifies the machine identification
<replaceable>MACHINE-ID</replaceable>.</para>
</listitem>
</varlistentry>
<varlistentry>
@ -275,9 +313,9 @@
<filename>/etc/os-release</filename>
<filename>/usr/lib/os-release</filename>
</term>
<listitem>
<listitem>
<para>Read by <filename>90-loaderentry.install</filename>.
If available, <varname>PRETTY_NAME</varname> is read from these files and used as the title of the boot menu entry.
If available, <varname>PRETTY_NAME=</varname> is read from these files and used as the title of the boot menu entry.
Otherwise, <literal>Linux <replaceable>KERNEL-VERSION</replaceable></literal> will be used.</para>
</listitem>
</varlistentry>

View File

@ -129,17 +129,6 @@
</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>KERNEL_INSTALL_MACHINE_ID=</varname></term>
<listitem><para>Specifies the installation-specific installation directory
<command>kernel-install</command> should use. The value must be a valid machine ID (32 hexadecimal
characters). This would generally be the original machine-id that was used when the boot loader
entries for this installation were first added. When not set, the current value of
<citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry>
will be used.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>VENDOR=</varname></term>

View File

@ -798,6 +798,16 @@ static int parse_timestamp_impl(const char *t, usec_t *usec, bool with_tz) {
goto from_tm;
}
/* Support OUTPUT_SHORT and OUTPUT_SHORT_PRECISE formats */
tm = copy;
k = strptime(t, "%b %d %H:%M:%S", &tm);
if (k) {
if (*k == '.')
goto parse_usec;
else if (*k == 0)
goto from_tm;
}
tm = copy;
k = strptime(t, "%y-%m-%d %H:%M", &tm);
if (k && *k == 0) {

View File

@ -28,6 +28,7 @@
#include "glyph-util.h"
#include "main-func.h"
#include "mkdir.h"
#include "os-util.h"
#include "pager.h"
#include "parse-argument.h"
#include "parse-util.h"
@ -56,13 +57,22 @@ static bool arg_print_dollar_boot_path = false;
static bool arg_touch_variables = true;
static PagerFlags arg_pager_flags = 0;
static bool arg_graceful = false;
static int arg_make_machine_id_directory = 0;
static int arg_make_entry_directory = false; /* tri-state: < 0 for automatic logic */
static sd_id128_t arg_machine_id = SD_ID128_NULL;
static char *arg_install_layout = NULL;
static enum {
ARG_ENTRY_TOKEN_MACHINE_ID,
ARG_ENTRY_TOKEN_OS_IMAGE_ID,
ARG_ENTRY_TOKEN_OS_ID,
ARG_ENTRY_TOKEN_LITERAL,
ARG_ENTRY_TOKEN_AUTO,
} arg_entry_token_type = ARG_ENTRY_TOKEN_AUTO;
static char *arg_entry_token = NULL;
STATIC_DESTRUCTOR_REGISTER(arg_esp_path, freep);
STATIC_DESTRUCTOR_REGISTER(arg_xbootldr_path, freep);
STATIC_DESTRUCTOR_REGISTER(arg_install_layout, freep);
STATIC_DESTRUCTOR_REGISTER(arg_entry_token, freep);
static const char *arg_dollar_boot_path(void) {
/* $BOOT shall be the XBOOTLDR partition if it exists, and otherwise the ESP */
@ -170,32 +180,133 @@ static int load_install_machine_id_and_layout(void) {
return 0;
}
static int settle_install_machine_id(void) {
static int settle_entry_token(void) {
int r;
switch (arg_entry_token_type) {
case ARG_ENTRY_TOKEN_AUTO: {
_cleanup_free_ char *buf = NULL;
r = read_one_line_file("/etc/kernel/entry-token", &buf);
if (r < 0 && r != -ENOENT)
return log_error_errno(r, "Failed to read /etc/kernel/entry-token: %m");
if (!isempty(buf)) {
free_and_replace(arg_entry_token, buf);
arg_entry_token_type = ARG_ENTRY_TOKEN_LITERAL;
} else if (sd_id128_is_null(arg_machine_id)) {
_cleanup_free_ char *id = NULL, *image_id = NULL;
r = parse_os_release(NULL,
"IMAGE_ID", &image_id,
"ID", &id);
if (r < 0)
return log_error_errno(r, "Failed to load /etc/os-release: %m");
if (!isempty(image_id)) {
free_and_replace(arg_entry_token, image_id);
arg_entry_token_type = ARG_ENTRY_TOKEN_OS_IMAGE_ID;
} else if (!isempty(id)) {
free_and_replace(arg_entry_token, id);
arg_entry_token_type = ARG_ENTRY_TOKEN_OS_ID;
} else
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No machine ID set, and /etc/os-release carries no ID=/IMAGE_ID= fields.");
} else {
r = free_and_strdup_warn(&arg_entry_token, SD_ID128_TO_STRING(arg_machine_id));
if (r < 0)
return r;
arg_entry_token_type = ARG_ENTRY_TOKEN_MACHINE_ID;
}
break;
}
case ARG_ENTRY_TOKEN_MACHINE_ID:
if (sd_id128_is_null(arg_machine_id))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No machine ID set.");
r = free_and_strdup_warn(&arg_entry_token, SD_ID128_TO_STRING(arg_machine_id));
if (r < 0)
return r;
break;
case ARG_ENTRY_TOKEN_OS_IMAGE_ID: {
_cleanup_free_ char *buf = NULL;
r = parse_os_release(NULL, "IMAGE_ID", &buf);
if (r < 0)
return log_error_errno(r, "Failed to load /etc/os-release: %m");
if (isempty(buf))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "IMAGE_ID= field not set in /etc/os-release.");
free_and_replace(arg_entry_token, buf);
break;
}
case ARG_ENTRY_TOKEN_OS_ID: {
_cleanup_free_ char *buf = NULL;
r = parse_os_release(NULL, "ID", &buf);
if (r < 0)
return log_error_errno(r, "Failed to load /etc/os-release: %m");
if (isempty(buf))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "ID= field not set in /etc/os-release.");
free_and_replace(arg_entry_token, buf);
break;
}
case ARG_ENTRY_TOKEN_LITERAL:
assert(!isempty(arg_entry_token)); /* already filled in by command line parser */
break;
}
if (isempty(arg_entry_token) || !string_is_safe(arg_entry_token))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Selected entry token not valid: %s", arg_entry_token);
log_debug("Using entry token: %s", arg_entry_token);
return 0;
}
static bool use_boot_loader_spec_type1(void) {
/* If the layout is not specified, or if it is set explicitly to "bls" we assume Boot Loader
* Specification Type #1 is the chosen format for our boot loader entries */
return !arg_install_layout || streq(arg_install_layout, "bls");
}
static int settle_make_entry_directory(void) {
int r;
r = load_install_machine_id_and_layout();
if (r < 0)
return r;
bool layout_non_bls = arg_install_layout && !streq(arg_install_layout, "bls");
if (arg_make_machine_id_directory < 0) {
if (layout_non_bls || sd_id128_is_null(arg_machine_id))
arg_make_machine_id_directory = 0;
else {
r = path_is_temporary_fs("/etc/machine-id");
if (r < 0)
return log_debug_errno(r, "Couldn't determine whether /etc/machine-id is on a temporary file system: %m");
arg_make_machine_id_directory = r == 0;
}
r = settle_entry_token();
if (r < 0)
return r;
bool layout_type1 = use_boot_loader_spec_type1();
if (arg_make_entry_directory < 0) { /* Automatic mode */
if (layout_type1) {
if (arg_entry_token == ARG_ENTRY_TOKEN_MACHINE_ID) {
r = path_is_temporary_fs("/etc/machine-id");
if (r < 0)
return log_debug_errno(r, "Couldn't determine whether /etc/machine-id is on a temporary file system: %m");
arg_make_entry_directory = r == 0;
} else
arg_make_entry_directory = true;
} else
arg_make_entry_directory = false;
}
if (arg_make_machine_id_directory > 0 && sd_id128_is_null(arg_machine_id))
if (arg_make_entry_directory > 0 && !layout_type1)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Machine ID not found, but bls directory creation was requested.");
if (arg_make_machine_id_directory > 0 && layout_non_bls)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"KERNEL_INSTALL_LAYOUT=%s is configured, but bls directory creation was requested.",
"KERNEL_INSTALL_LAYOUT=%s is configured, but Boot Loader Specification Type #1 entry directory creation was requested.",
arg_install_layout);
return 0;
@ -1039,14 +1150,14 @@ static int remove_subdirs(const char *root, const char *const *subdirs) {
return r < 0 ? r : q;
}
static int remove_machine_id_directory(const char *root) {
static int remove_entry_directory(const char *root) {
assert(root);
assert(arg_make_machine_id_directory >= 0);
assert(arg_make_entry_directory >= 0);
if (!arg_make_machine_id_directory || sd_id128_is_null(arg_machine_id))
if (!arg_make_entry_directory || !arg_entry_token)
return 0;
return rmdir_one(root, SD_ID128_TO_STRING(arg_machine_id));
return rmdir_one(root, arg_entry_token);
}
static int remove_binaries(const char *esp_path) {
@ -1138,7 +1249,7 @@ static int install_loader_config(const char *esp_path) {
const char *p;
int r;
assert(arg_make_machine_id_directory >= 0);
assert(arg_make_entry_directory >= 0);
p = prefix_roota(esp_path, "/loader/loader.conf");
if (access(p, F_OK) >= 0) /* Silently skip creation if the file already exists (early check) */
@ -1155,9 +1266,9 @@ static int install_loader_config(const char *esp_path) {
fprintf(f, "#timeout 3\n"
"#console-mode keep\n");
if (arg_make_machine_id_directory) {
assert(!sd_id128_is_null(arg_machine_id));
fprintf(f, "default %s-*\n", SD_ID128_TO_STRING(arg_machine_id));
if (arg_make_entry_directory) {
assert(arg_entry_token);
fprintf(f, "default %s-*\n", arg_entry_token);
}
r = fflush_sync_and_check(f);
@ -1174,100 +1285,33 @@ static int install_loader_config(const char *esp_path) {
return 1;
}
static int install_machine_id_directory(const char *root) {
static int install_entry_directory(const char *root) {
assert(root);
assert(arg_make_machine_id_directory >= 0);
assert(arg_make_entry_directory >= 0);
if (!arg_make_machine_id_directory)
if (!arg_make_entry_directory)
return 0;
assert(!sd_id128_is_null(arg_machine_id));
return mkdir_one(root, SD_ID128_TO_STRING(arg_machine_id));
assert(arg_entry_token);
return mkdir_one(root, arg_entry_token);
}
static int install_machine_info_config(void) {
_cleanup_free_ char *contents = NULL;
size_t length;
bool need_install_layout = true, need_machine_id;
static int install_entry_token(void) {
int r;
assert(arg_make_machine_id_directory >= 0);
assert(arg_make_entry_directory >= 0);
assert(arg_entry_token);
/* We only want to save the machine-id if we created any directories using it. */
need_machine_id = arg_make_machine_id_directory;
/* Let's save the used entry token in /etc/kernel/entry-token if we used it to create the entry
* directory, or if anything else but the machine ID */
_cleanup_fclose_ FILE *orig = fopen("/etc/machine-info", "re");
if (!orig && errno != ENOENT)
return log_error_errno(errno, "Failed to open /etc/machine-info: %m");
if (!arg_make_entry_directory && arg_entry_token_type == ARG_ENTRY_TOKEN_MACHINE_ID)
return 0;
if (orig) {
_cleanup_free_ char *install_layout = NULL, *machine_id = NULL;
r = parse_env_file(orig, "/etc/machine-info",
"KERNEL_INSTALL_LAYOUT", &install_layout,
"KERNEL_INSTALL_MACHINE_ID", &machine_id);
if (r < 0)
return log_error_errno(r, "Failed to parse /etc/machine-info: %m");
rewind(orig);
if (!isempty(install_layout))
need_install_layout = false;
if (!isempty(machine_id))
need_machine_id = false;
if (!need_install_layout && !need_machine_id) {
log_debug("/etc/machine-info already has KERNEL_INSTALL_MACHINE_ID=%s and KERNEL_INSTALL_LAYOUT=%s.",
machine_id, install_layout);
return 0;
}
r = read_full_stream(orig, &contents, &length);
if (r < 0)
return log_error_errno(r, "Failed to read /etc/machine-info: %m");
}
_cleanup_(unlink_and_freep) char *dst_tmp = NULL;
_cleanup_fclose_ FILE *dst = NULL;
r = fopen_temporary_label("/etc/machine-info", /* The path for which to the look up the label */
"/etc/machine-info", /* Where we want the file actually to end up */
&dst, /* The temporary file we write to */
&dst_tmp);
r = write_string_file("/etc/kernel/entry-token", arg_entry_token, WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC|WRITE_STRING_FILE_MKDIR_0755);
if (r < 0)
return log_debug_errno(r, "Failed to open temporary copy of /etc/machine-info: %m");
return log_error_errno(r, "Failed to write entry token '%s' to /etc/kernel/entry-token", arg_entry_token);
if (contents)
fwrite_unlocked(contents, 1, length, dst);
bool no_newline = !contents || contents[length - 1] == '\n';
if (need_install_layout) {
const char *line = "\nKERNEL_INSTALL_LAYOUT=bls\n" + no_newline;
fwrite_unlocked(line, 1, strlen(line), dst);
no_newline = false;
}
const char *mid_string = SD_ID128_TO_STRING(arg_machine_id);
if (need_machine_id)
fprintf(dst, "%sKERNEL_INSTALL_MACHINE_ID=%s\n",
no_newline ? "" : "\n",
mid_string);
r = fflush_and_check(dst);
if (r < 0)
return log_error_errno(r, "Failed to write temporary copy of /etc/machine-info: %m");
if (fchmod(fileno(dst), 0644) < 0)
return log_debug_errno(errno, "Failed to fchmod %s: %m", dst_tmp);
if (rename(dst_tmp, "/etc/machine-info") < 0)
return log_error_errno(errno, "Failed to replace /etc/machine-info: %m");
log_info("%s /etc/machine-info with%s%s%s",
orig ? "Updated" : "Created",
need_install_layout ? " KERNEL_INSTALL_LAYOUT=bls" : "",
need_machine_id ? " KERNEL_INSTALL_MACHINE_ID=" : "",
need_machine_id ? mid_string : "");
return 0;
}
@ -1311,8 +1355,10 @@ static int help(int argc, char *argv[], void *userdata) {
" --no-pager Do not pipe output into a pager\n"
" --graceful Don't fail when the ESP cannot be found or EFI\n"
" variables cannot be written\n"
" --make-machine-id-directory=yes|no|auto\n"
" Create $BOOT/$MACHINE_ID\n"
" --make-entry-directory=yes|no|auto\n"
" Create $BOOT/ENTRY-TOKEN/ directory\n"
" --entry-token=machine-id|os-id|os-image-id|auto|literal:…\n"
" Entry token to use for this installation\n"
"\nSee the %2$s for details.\n",
program_invocation_short_name,
link,
@ -1332,7 +1378,8 @@ static int parse_argv(int argc, char *argv[]) {
ARG_NO_VARIABLES,
ARG_NO_PAGER,
ARG_GRACEFUL,
ARG_MAKE_MACHINE_ID_DIRECTORY,
ARG_MAKE_ENTRY_DIRECTORY,
ARG_ENTRY_TOKEN,
};
static const struct option options[] = {
@ -1347,7 +1394,9 @@ static int parse_argv(int argc, char *argv[]) {
{ "no-variables", no_argument, NULL, ARG_NO_VARIABLES },
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
{ "graceful", no_argument, NULL, ARG_GRACEFUL },
{ "make-machine-id-directory", required_argument, NULL, ARG_MAKE_MACHINE_ID_DIRECTORY },
{ "make-entry-directory", required_argument, NULL, ARG_MAKE_ENTRY_DIRECTORY },
{ "make-machine-id-directory", required_argument, NULL, ARG_MAKE_ENTRY_DIRECTORY }, /* Compatibility alias */
{ "entry-token", required_argument, NULL, ARG_ENTRY_TOKEN },
{}
};
@ -1405,14 +1454,40 @@ static int parse_argv(int argc, char *argv[]) {
arg_graceful = true;
break;
case ARG_MAKE_MACHINE_ID_DIRECTORY:
if (streq(optarg, "auto")) /* retained for backwards compatibility */
arg_make_machine_id_directory = -1; /* yes if machine-id is permanent */
else {
r = parse_boolean_argument("--make-machine-id-directory=", optarg, &b);
case ARG_ENTRY_TOKEN: {
const char *e;
if (streq(optarg, "machine-id")) {
arg_entry_token_type = ARG_ENTRY_TOKEN_MACHINE_ID;
arg_entry_token = mfree(arg_entry_token);
} else if (streq(optarg, "os-image-id")) {
arg_entry_token_type = ARG_ENTRY_TOKEN_OS_IMAGE_ID;
arg_entry_token = mfree(arg_entry_token);
} else if (streq(optarg, "os-id")) {
arg_entry_token_type = ARG_ENTRY_TOKEN_OS_ID;
arg_entry_token = mfree(arg_entry_token);
} else if ((e = startswith(optarg, "literal:"))) {
arg_entry_token_type = ARG_ENTRY_TOKEN_LITERAL;
r = free_and_strdup_warn(&arg_entry_token, e);
if (r < 0)
return r;
arg_make_machine_id_directory = b;
} else
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Unexpected parameter for --entry-token=: %s", optarg);
break;
}
case ARG_MAKE_ENTRY_DIRECTORY:
if (streq(optarg, "auto")) /* retained for backwards compatibility */
arg_make_entry_directory = -1; /* yes if machine-id is permanent */
else {
r = parse_boolean_argument("--make-entry-directory=", optarg, &b);
if (r < 0)
return r;
arg_make_entry_directory = b;
}
break;
@ -1881,7 +1956,7 @@ static int verb_install(int argc, char *argv[], void *userdata) {
if (r < 0)
return r;
r = settle_install_machine_id();
r = settle_make_entry_directory();
if (r < 0)
return r;
@ -1908,11 +1983,11 @@ static int verb_install(int argc, char *argv[], void *userdata) {
if (r < 0)
return r;
r = install_machine_id_directory(arg_dollar_boot_path());
r = install_entry_directory(arg_dollar_boot_path());
if (r < 0)
return r;
r = install_machine_info_config();
r = install_entry_token();
if (r < 0)
return r;
@ -1945,7 +2020,7 @@ static int verb_remove(int argc, char *argv[], void *userdata) {
if (r < 0)
return r;
r = settle_install_machine_id();
r = settle_make_entry_directory();
if (r < 0)
return r;
@ -1967,7 +2042,7 @@ static int verb_remove(int argc, char *argv[], void *userdata) {
if (q < 0 && r >= 0)
r = q;
q = remove_machine_id_directory(arg_esp_path);
q = remove_entry_directory(arg_esp_path);
if (q < 0 && r >= 0)
r = 1;
@ -1977,7 +2052,7 @@ static int verb_remove(int argc, char *argv[], void *userdata) {
if (q < 0 && r >= 0)
r = q;
q = remove_machine_id_directory(arg_xbootldr_path);
q = remove_entry_directory(arg_xbootldr_path);
if (q < 0 && r >= 0)
r = q;
}

View File

@ -29,6 +29,7 @@ INITRD_OPTIONS_SHIFT=4
[ "$KERNEL_INSTALL_LAYOUT" = "bls" ] || exit 0
MACHINE_ID="$KERNEL_INSTALL_MACHINE_ID"
ENTRY_TOKEN="$KERNEL_INSTALL_ENTRY_TOKEN"
BOOT_ROOT="$KERNEL_INSTALL_BOOT_ROOT"
BOOT_MNT="$(stat -c %m "$BOOT_ROOT")"
@ -41,10 +42,10 @@ fi
case "$COMMAND" in
remove)
[ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && \
echo "Removing $BOOT_ROOT/loader/entries/$MACHINE_ID-$KERNEL_VERSION*.conf"
echo "Removing $BOOT_ROOT/loader/entries/$ENTRY_TOKEN-$KERNEL_VERSION*.conf"
exec rm -f \
"$BOOT_ROOT/loader/entries/$MACHINE_ID-$KERNEL_VERSION.conf" \
"$BOOT_ROOT/loader/entries/$MACHINE_ID-$KERNEL_VERSION+"*".conf"
"$BOOT_ROOT/loader/entries/$ENTRY_TOKEN-$KERNEL_VERSION.conf" \
"$BOOT_ROOT/loader/entries/$ENTRY_TOKEN-$KERNEL_VERSION+"*".conf"
;;
add)
;;
@ -68,17 +69,26 @@ elif [ -r /usr/lib/kernel/cmdline ]; then
else
BOOT_OPTIONS="$(tr -s "$IFS" '\n' </proc/cmdline | grep -ve '^BOOT_IMAGE=' -e '^initrd=' | tr '\n' ' ')"
fi
BOOT_OPTIONS="${BOOT_OPTIONS% }"
# If the boot entries are named after the machine ID, then suffix the kernel
# command line with the machine ID we use, so that the machine ID remains
# stable, even during factory reset, in the initrd (where the system's machine
# ID is not directly accessible yet), and if the root file system is volatile.
if [ "$ENTRY_TOKEN" = "$MACHINE_ID" ]; then
BOOT_OPTIONS="$BOOT_OPTIONS systemd.machine_id=$MACHINE_ID"
fi
if [ -r /etc/kernel/tries ]; then
read -r TRIES </etc/kernel/tries
if ! echo "$TRIES" | grep -q '^[0-9][0-9]*$'; then
echo "/etc/kernel/tries does not contain an integer." >&2
exit 1
fi
LOADER_ENTRY="$BOOT_ROOT/loader/entries/$MACHINE_ID-$KERNEL_VERSION+$TRIES.conf"
LOADER_ENTRY="$BOOT_ROOT/loader/entries/$ENTRY_TOKEN-$KERNEL_VERSION+$TRIES.conf"
else
LOADER_ENTRY="$BOOT_ROOT/loader/entries/$MACHINE_ID-$KERNEL_VERSION.conf"
LOADER_ENTRY="$BOOT_ROOT/loader/entries/$ENTRY_TOKEN-$KERNEL_VERSION.conf"
fi
if ! [ -d "$ENTRY_DIR_ABS" ]; then
@ -116,7 +126,10 @@ mkdir -p "${LOADER_ENTRY%/*}" || {
{
echo "title $PRETTY_NAME"
echo "version $KERNEL_VERSION"
echo "machine-id $MACHINE_ID"
if [ "$ENTRY_TOKEN" = "$MACHINE_ID" ]; then
# See similar logic above for the systemd.machine_id= kernel command line option
echo "machine-id $MACHINE_ID"
fi
echo "options $BOOT_OPTIONS"
echo "linux $ENTRY_DIR/linux"

View File

@ -25,6 +25,7 @@ usage()
echo "Usage:"
echo " $0 [OPTIONS...] add KERNEL-VERSION KERNEL-IMAGE [INITRD-FILE ...]"
echo " $0 [OPTIONS...] remove KERNEL-VERSION"
echo " $0 [OPTIONS...] inspect"
echo "Options:"
echo " -h, --help Print this help"
echo " -v, --verbose Increase verbosity"
@ -72,13 +73,17 @@ else
[ $# -ge 1 ] && shift
fi
if [ $# -lt 1 ]; then
echo "Error: not enough arguments" >&2
exit 1
fi
if [ "$COMMAND" = "inspect" ]; then
KERNEL_VERSION=""
else
if [ $# -lt 1 ]; then
echo "Error: not enough arguments" >&2
exit 1
fi
KERNEL_VERSION="$1"
shift
KERNEL_VERSION="$1"
shift
fi
layout=
initrd_generator=
@ -89,44 +94,75 @@ elif [ -r "/usr/lib/kernel/install.conf" ]; then
. /usr/lib/kernel/install.conf
fi
# Prefer to use an existing machine ID from /etc/machine-info or /etc/machine-id. If we're using the machine
# ID /etc/machine-id, try to persist it in /etc/machine-info. If no machine ID is found, try to generate
# a new machine ID in /etc/machine-info. If that fails, use "Default".
[ -z "$MACHINE_ID" ] && [ -r /etc/machine-info ] && . /etc/machine-info && MACHINE_ID="$KERNEL_INSTALL_MACHINE_ID"
[ -z "$MACHINE_ID" ] && [ -r /etc/machine-id ] && read -r MACHINE_ID </etc/machine-id
[ -n "$MACHINE_ID" ] && [ -z "$KERNEL_INSTALL_MACHINE_ID" ] && echo "KERNEL_INSTALL_MACHINE_ID=$MACHINE_ID" >>/etc/machine-info
[ -z "$MACHINE_ID" ] && NEW_MACHINE_ID="$(systemd-id128 new)" && echo "KERNEL_INSTALL_MACHINE_ID=$NEW_MACHINE_ID" >>/etc/machine-info
[ -z "$MACHINE_ID" ] && [ -r /etc/machine-info ] && . /etc/machine-info && MACHINE_ID="$KERNEL_INSTALL_MACHINE_ID"
[ -z "$MACHINE_ID" ] && MACHINE_ID="Default"
# If /etc/machine-id is initialized we'll use it, otherwise we'll use a freshly
# generated one. If the user configured an explicit machine ID to use in
# /etc/machine-info to use for our purpose, we'll use that instead (for
# compatibility).
[ -z "$MACHINE_ID" ] && [ -r /etc/machine-info ] && . /etc/machine-info && MACHINE_ID="$KERNEL_INSTALL_MACHINE_ID"
[ -z "$MACHINE_ID" ] && [ -r /etc/machine-id ] && read -r MACHINE_ID </etc/machine-id
[ -z "$MACHINE_ID" ] && MACHINE_ID="$(systemd-id128 new)"
[ -z "$BOOT_ROOT" ] && for suff in "$MACHINE_ID" "loader/entries"; do
for pref in "/efi" "/boot" "/boot/efi" ; do
# Now that we determined the machine ID to use, let's determine the "token" for
# the boot loader entry to generate. We use that for naming the directory below
# $BOOT where we want to place the kernel/initrd and related resources, as well
# for naming the .conf boot loader spec entry. Typically this is just the
# machine ID, but it can be anything else, too, if we are told so.
[ -z "$ENTRY_TOKEN" ] && [ -r /etc/kernel/entry-token ] && read -r ENTRY_TOKEN </etc/kernel/entry-token
if [ -z "$ENTRY_TOKEN" ]; then
# If not configured explicitly, then use a few candidates: the machine ID,
# the IMAGE_ID= and ID= fields from /etc/os-release and finally the fixed
# string "Default"
ENTRY_TOKEN_SEARCH="$MACHINE_ID"
[ -r /etc/os-release ] && . /etc/os-release
[ -n "$IMAGE_ID" ] && ENTRY_TOKEN_SEARCH="$ENTRY_TOKEN_SEARCH $IMAGE_ID"
[ -n "$ID" ] && ENTRY_TOKEN_SEARCH="$ENTRY_TOKEN_SEARCH $ID"
ENTRY_TOKEN_SEARCH="$ENTRY_TOKEN_SEARCH Default"
else
ENTRY_TOKEN_SEARCH="$ENTRY_TOKEN"
fi
# NB: The $MACHINE_ID is guaranteed to be a valid machine ID, but
# $ENTRY_TOKEN can be any string that fits into a VFAT filename, though
# typically is just the machine ID.
[ -z "$BOOT_ROOT" ] && for suff in $ENTRY_TOKEN_SEARCH; do
for pref in "/efi" "/boot" "/boot/efi"; do
if [ -d "$pref/$suff" ]; then
BOOT_ROOT="$pref"
ENTRY_TOKEN="$suff"
break 2
fi
done
done
[ -z "$BOOT_ROOT" ] && for pref in "/efi" "/boot" "/boot/efi"; do
if [ -d "$pref/loader/entries" ]; then
BOOT_ROOT="$pref"
break
fi
done
[ -z "$BOOT_ROOT" ] && for pref in "/efi" "/boot/efi"; do
if mountpoint -q "$pref"; then
BOOT_ROOT="$pref"
break
fi
done
[ -z "$BOOT_ROOT" ] && BOOT_ROOT="/boot"
[ -z "$ENTRY_TOKEN" ] && ENTRY_TOKEN="$MACHINE_ID"
if [ -z "$layout" ]; then
# Administrative decision: if not present, some scripts generate into /boot.
if [ -d "$BOOT_ROOT/$MACHINE_ID" ]; then
if [ -d "$BOOT_ROOT/$ENTRY_TOKEN" ]; then
layout="bls"
else
layout="other"
fi
fi
ENTRY_DIR_ABS="$BOOT_ROOT/$MACHINE_ID/$KERNEL_VERSION"
ENTRY_DIR_ABS="$BOOT_ROOT/$ENTRY_TOKEN/$KERNEL_VERSION"
# Provide a directory where to store generated initrds
cleanup() {
@ -138,6 +174,7 @@ trap cleanup EXIT
KERNEL_INSTALL_STAGING_AREA="$(mktemp -d -t -p /tmp kernel-install.staging.XXXXXXX)"
export KERNEL_INSTALL_MACHINE_ID="$MACHINE_ID"
export KERNEL_INSTALL_ENTRY_TOKEN="$ENTRY_TOKEN"
export KERNEL_INSTALL_BOOT_ROOT="$BOOT_ROOT"
export KERNEL_INSTALL_LAYOUT="$layout"
export KERNEL_INSTALL_INITRD_GENERATOR="$initrd_generator"
@ -170,7 +207,7 @@ case "$COMMAND" in
fi
if [ "$MAKE_ENTRY_DIR_ABS" -eq 0 ]; then
# Compatibility with earlier versions that used the presence of $BOOT_ROOT/$MACHINE_ID
# Compatibility with earlier versions that used the presence of $BOOT_ROOT/$ENTRY_TOKEN
# to signal to 00-entry-directory to create $ENTRY_DIR_ABS
# to serve as the indication to use or to not use the BLS
if [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ]; then
@ -205,6 +242,18 @@ case "$COMMAND" in
fi
;;
inspect)
echo "KERNEL_INSTALL_MACHINE_ID: $KERNEL_INSTALL_MACHINE_ID"
echo "KERNEL_INSTALL_ENTRY_TOKEN: $KERNEL_INSTALL_ENTRY_TOKEN"
echo "KERNEL_INSTALL_BOOT_ROOT: $KERNEL_INSTALL_BOOT_ROOT"
echo "KERNEL_INSTALL_LAYOUT: $KERNEL_INSTALL_LAYOUT"
echo "KERNEL_INSTALL_INITRD_GENERATOR: $KERNEL_INSTALL_INITRD_GENERATOR"
echo "ENTRY_DIR_ABS: $KERNEL_INSTALL_BOOT_ROOT/$ENTRY_TOKEN/\$KERNEL_VERSION"
# Assert that ENTRY_DIR_ABS actually matches what we are printing here
[ "${ENTRY_DIR_ABS%/*}" = "$KERNEL_INSTALL_BOOT_ROOT/$ENTRY_TOKEN" ] || { echo "Assertion didn't pass." >&2; exit 1; }
;;
*)
echo "Error: unknown command '$COMMAND'" >&2
exit 1

View File

@ -73,6 +73,8 @@ int main(int argc, char *argv[]) {
test_one("12-10-03 12:13");
test_one("2012-12-30 18:42");
test_one("2012-10-02");
test_one("Mar 12 12:01:01");
test_one("Mar 12 12:01:01.687197");
test_one("Tue 2012-10-02");
test_one("yesterday");
test_one("today");