Merge pull request #11701 from poettering/discover-bls
sd-boot,bootctl,gpt-auto: support Extended Boot Loader Partition
This commit is contained in:
@@ -51,8 +51,6 @@ Features:
|
||||
* When logind.conf contains HandleLidSwitch=suspend-then-hibernate and we can't
|
||||
hibernate because the swap partition isn't large enough, still suspend
|
||||
|
||||
* bootctl: implement Type #2 boot loader entry discovery
|
||||
|
||||
* bootctl,sd-boot: actually honour the "architecture" key
|
||||
|
||||
* when a socket unit is spawned with an AF_UNIX path in /var/run, complain and
|
||||
@@ -90,23 +88,17 @@ Features:
|
||||
show state of these flags, and optionally trigger such a factory reset on
|
||||
next boot by setting the flag.
|
||||
|
||||
* sd-boot: search drop-ins in $BOOT, too
|
||||
|
||||
* sd-boot: add "oneshot boot timeout" variable support
|
||||
|
||||
* sd-boot: automatically load EFI modules from some drop-in dir, so that people
|
||||
can add in file system drivers and such
|
||||
|
||||
* esp generator: also mount $BOOT if found
|
||||
|
||||
* sd-boot: optionally, show boot menu when previous default boot item has
|
||||
non-zero "tries done" count
|
||||
|
||||
* logind: add "boot into bootmenu" API, and possibly even "boot into windows"
|
||||
and "boot into macos".
|
||||
|
||||
* bootspec.c: also enumerate EFI unified kernel images.
|
||||
|
||||
* maybe set a special xattr on cgroups that have delegate=yes set, to make it
|
||||
easy to mark cut points
|
||||
|
||||
|
||||
@@ -42,9 +42,9 @@ Everything described below is located on a placeholder file system `$BOOT`. The
|
||||
* If the OS is installed on a disk with MBR disk label, and a partition with the MBR type id of 0xEA already exists it should be used as `$BOOT`.
|
||||
* Otherwise, if the OS is installed on a disk with MBR disk label, a new partition with MBR type id of 0xEA shall be created, of a suitable size (let's say 500MB), and it should be used as `$BOOT`.
|
||||
* On disks with GPT disk labels
|
||||
* If the OS is installed on a disk with GPT disk label, and a partition with the GPT type GUID of bc13c2ff-59e6-4262-a352-b275fd6f7172 already exists, it should be used as `$BOOT`.
|
||||
* Otherwise, if the OS is installed on a disk with GPT disk label, and an ESP partition (i.e. with the GPT type UID of c12a7328-f81f-11d2-ba4b-00a0c93ec93b) already exists and is large enough (let's say 250MB) and otherwise qualifies, it should be used as `$BOOT`.
|
||||
* Otherwise, if the OS is installed on a disk with GPT disk label, and if the ESP partition already exists but is too small, a new suitably sized (let's say 500MB) partition with GPT type GUID of bc13c2ff-59e6-4262-a352-b275fd6f7172 shall be created and it should be used as `$BOOT`.
|
||||
* If the OS is installed on a disk with GPT disk label, and a partition with the GPT type GUID of `bc13c2ff-59e6-4262-a352-b275fd6f7172` already exists, it should be used as `$BOOT`.
|
||||
* Otherwise, if the OS is installed on a disk with GPT disk label, and an ESP partition (i.e. with the GPT type UID of `c12a7328-f81f-11d2-ba4b-00a0c93ec93b`) already exists and is large enough (let's say 250MB`) and otherwise qualifies, it should be used as `$BOOT`.
|
||||
* Otherwise, if the OS is installed on a disk with GPT disk label, and if the ESP partition already exists but is too small, a new suitably sized (let's say 500MB) partition with GPT type GUID of `bc13c2ff-59e6-4262-a352-b275fd6f7172` shall be created and it should be used as `$BOOT`.
|
||||
* Otherwise, if the OS is installed on a disk with GPT disk label, and no ESP partition exists yet, a new suitably sized (let's say 500MB) ESP should be created and should be used as `$BOOT`.
|
||||
|
||||
This placeholder file system shall be determined during _installation time_, and an fstab entry may be created. It should be mounted to either `/boot/` or `/efi/`. Additional locations like `/boot/efi/`, with `/boot/` being a separate file system, might be supported by implementations. This is not recommended because the mounting of `$BOOT` is then dependent on and requires the mounting of the intermediate file system.
|
||||
|
||||
+34
-15
@@ -46,18 +46,34 @@
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><option>--path=</option></term>
|
||||
<listitem><para>Path to the EFI System Partition (ESP). If not specified, <filename>/efi</filename>,
|
||||
<filename>/boot</filename>, and <filename>/boot/efi</filename> are checked in turn. It is recommended to mount
|
||||
the ESP to <filename>/boot</filename>, if possible.</para></listitem>
|
||||
<term><option>--esp-path=</option></term>
|
||||
<listitem><para>Path to the EFI System Partition (ESP). If not specified, <filename>/efi/</filename>,
|
||||
<filename>/boot/</filename>, and <filename>/boot/efi</filename> are checked in turn. It is recommended to mount
|
||||
the ESP to <filename>/efi/</filename>, if possible.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--boot-path=</option></term>
|
||||
<listitem><para>Path to the Extended Boot Loader partition, as defined in the <ulink
|
||||
url="https://systemd.io/BOOT_LOADER_SPECIFICATION">Boot Loader Specification</ulink>. If not
|
||||
specified, <filename>/boot/</filename> are checked. It is recommended to mount the Extended Boot
|
||||
Loader partition to <filename>/boot/</filename>, if possible.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>-p</option></term>
|
||||
<term><option>--print-path</option></term>
|
||||
<listitem><para>This option modifies the behaviour of <command>status</command>.
|
||||
Just print the path to the EFI System Partition (ESP) to standard output and
|
||||
exit.</para></listitem>
|
||||
<term><option>--print-esp-path</option></term>
|
||||
<listitem><para>This option modifies the behaviour of <command>status</command>. Prints only the
|
||||
path to the EFI System Partition (ESP) to standard output and exits.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--print-boot-path</option></term>
|
||||
<listitem><para>This option modifies the behaviour of <command>status</command>. Prints only the
|
||||
path to the Extended Boot Loader partition if it exists, and the path to the ESP otherwise to
|
||||
standard output and exit. This command is useful to determine where to place boot loader entries, as
|
||||
they are preferably placed in the Extended Boot Loader partition if it exists and in the ESP
|
||||
otherwise.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
@@ -87,10 +103,10 @@
|
||||
<varlistentry>
|
||||
<term><option>install</option></term>
|
||||
|
||||
<listitem><para>Installs systemd-boot into the EFI system partition. A copy of <command>systemd-boot</command>
|
||||
will be stored as the EFI default/fallback loader at
|
||||
<filename><replaceable>ESP</replaceable>/EFI/BOOT/BOOT*.EFI</filename>. The boot loader is then added to the
|
||||
top of the firmware's boot loader list.</para></listitem>
|
||||
<listitem><para>Installs <command>systemd-boot</command> into the EFI system partition. A copy of
|
||||
<command>systemd-boot</command> will be stored as the EFI default/fallback loader at
|
||||
<filename><replaceable>ESP</replaceable>/EFI/BOOT/BOOT*.EFI</filename>. The boot loader is then added
|
||||
to the top of the firmware's boot loader list.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
@@ -138,9 +154,12 @@
|
||||
|
||||
<refsect1>
|
||||
<title>Environment</title>
|
||||
<para>If <varname>$SYSTEMD_RELAX_ESP_CHECKS=1</varname> is set the validation checks for the ESP are relaxed, and
|
||||
the path specified with <option>--path=</option> may refer to any kind of file system on any kind of
|
||||
partition.</para>
|
||||
<para>If <varname>$SYSTEMD_RELAX_ESP_CHECKS=1</varname> is set the validation checks for the ESP are
|
||||
relaxed, and the path specified with <option>--esp-path=</option> may refer to any kind of file system on
|
||||
any kind of partition.</para>
|
||||
|
||||
<para>Similarly, <varname>$SYSTEMD_RELAX_XBOOTLDR_CHECKS=1</varname> turns off some validation checks for
|
||||
the Extended Boot Loader partition.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
|
||||
+34
-28
@@ -25,27 +25,28 @@
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<para><command>systemd-boot</command> (short: <command>sd-boot</command>) is a simple UEFI boot manager. It
|
||||
provides a graphical menu to select the entry to boot and an editor for the kernel command line. systemd-boot
|
||||
supports systems with UEFI firmware only.</para>
|
||||
<para><command>systemd-boot</command> (short: <command>sd-boot</command>) is a simple UEFI boot
|
||||
manager. It provides a graphical menu to select the entry to boot and an editor for the kernel command
|
||||
line. <command>systemd-boot</command> supports systems with UEFI firmware only.</para>
|
||||
|
||||
<para>systemd-boot loads boot entry information from the EFI system partition (ESP), usually mounted at
|
||||
<filename>/boot</filename>, <filename>/efi</filename>, or <filename>/boot/efi</filename> during OS
|
||||
runtime. Configuration file fragments, kernels, initrds and other EFI images to boot generally need to reside on
|
||||
the ESP. Linux kernels must be built with <option>CONFIG_EFI_STUB</option> to be able to be directly executed as an
|
||||
EFI image. During boot systemd-boot automatically assembles a list of boot entries from the following
|
||||
sources:</para>
|
||||
<filename>/efi/</filename>, <filename>/boot/</filename>, or <filename>/boot/efi/</filename> during OS
|
||||
runtime, as well as from the Extended Boot Loader partition if it exists (usually mounted to
|
||||
<filename>/boot/</filename>). Configuration file fragments, kernels, initrds and other EFI images to boot
|
||||
generally need to reside on the ESP or the Extended Boot Loader partition. Linux kernels must be built
|
||||
with <option>CONFIG_EFI_STUB</option> to be able to be directly executed as an EFI image. During boot
|
||||
systemd-boot automatically assembles a list of boot entries from the following sources:</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem><para>Boot entries defined with <ulink
|
||||
url="https://systemd.io/BOOT_LOADER_SPECIFICATION">Boot Loader
|
||||
Specification</ulink> description files located in <filename>/loader/entries/</filename> on the ESP. These
|
||||
usually describe Linux kernel images with associated initrd images, but alternatively may also describe
|
||||
arbitrary other EFI executables.</para></listitem>
|
||||
url="https://systemd.io/BOOT_LOADER_SPECIFICATION">Boot Loader Specification</ulink> description files
|
||||
located in <filename>/loader/entries/</filename> on the ESP and the Extended Boot Loader
|
||||
Partition. These usually describe Linux kernel images with associated initrd images, but alternatively
|
||||
may also describe arbitrary other EFI executables.</para></listitem>
|
||||
|
||||
<listitem><para>Unified kernel images following the <ulink
|
||||
url="https://systemd.io/BOOT_LOADER_SPECIFICATION">Boot Loader
|
||||
Specification</ulink>, as executable EFI binaries in <filename>/EFI/Linux/</filename> on the ESP.
|
||||
url="https://systemd.io/BOOT_LOADER_SPECIFICATION">Boot Loader Specification</ulink>, as executable EFI
|
||||
binaries in <filename>/EFI/Linux/</filename> on the ESP and the Extended Boot Loader Partition.
|
||||
</para></listitem>
|
||||
|
||||
<listitem><para>The Microsoft Windows EFI boot manager, if installed</para></listitem>
|
||||
@@ -57,10 +58,12 @@
|
||||
<listitem><para>A reboot into the UEFI firmware setup option, if supported by the firmware</para></listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para><citerefentry><refentrytitle>kernel-install</refentrytitle><manvolnum>8</manvolnum></citerefentry> may be
|
||||
used to copy kernel images onto the ESP and to generate description files compliant with the Boot Loader
|
||||
Specification. <citerefentry><refentrytitle>bootctl</refentrytitle><manvolnum>1</manvolnum></citerefentry> may be
|
||||
used from a running system to locate the ESP, list available entries, and install systemd-boot itself.</para>
|
||||
<para><citerefentry><refentrytitle>kernel-install</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||
may be used to copy kernel images onto the ESP or the Extended Boot Loader Partition and to generate
|
||||
description files compliant with the Boot Loader
|
||||
Specification. <citerefentry><refentrytitle>bootctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
|
||||
may be used from a running system to locate the ESP and the Extended Boot Loader Partition, list
|
||||
available entries, and install <command>systemd-boot</command> itself.</para>
|
||||
|
||||
<para>systemd-boot will provide information about the time spent in UEFI firmware using the <ulink
|
||||
url="https://systemd.io/BOOT_LOADER_INTERFACE">Boot Loader Interface</ulink>. This information can be displayed
|
||||
@@ -224,16 +227,19 @@
|
||||
<refsect1>
|
||||
<title>Files</title>
|
||||
|
||||
<para>The files systemd-boot reads generally reside on the UEFI ESP which is usually mounted to
|
||||
<filename>/boot/</filename>, <filename>/efi/</filename> or <filename>/boot/efi</filename> during OS
|
||||
runtime. systemd-boot reads runtime configuration such as the boot timeout and default entry from
|
||||
<filename>/loader/loader.conf</filename> on the ESP (in combination with data read from EFI variables). See
|
||||
<citerefentry><refentrytitle>loader.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>. Boot entry
|
||||
description files following the <ulink
|
||||
url="https://systemd.io/BOOT_LOADER_SPECIFICATION">Boot Loader
|
||||
Specification</ulink> are read from <filename>/loader/entries/</filename> on the ESP. Unified kernel boot entries
|
||||
following the <ulink url="https://systemd.io/BOOT_LOADER_SPECIFICATION">Boot
|
||||
Loader Specification</ulink> are read from <filename>/EFI/Linux/</filename> on the ESP.</para>
|
||||
<para>The files <command>systemd-boot</command> processes generally reside on the UEFI ESP which is
|
||||
usually mounted to <filename>/efi/</filename>, <filename>/boot/</filename> or
|
||||
<filename>/boot/efi/</filename> during OS runtime. It also processes files on the Extended Boot Loader
|
||||
partition which is typically mounted to <filename>/boot/</filename>, if it
|
||||
exists. <command>systemd-boot</command> reads runtime configuration such as the boot timeout and default
|
||||
entry from <filename>/loader/loader.conf</filename> on the ESP (in combination with data read from EFI
|
||||
variables). See
|
||||
<citerefentry><refentrytitle>loader.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>. Boot
|
||||
entry description files following the <ulink url="https://systemd.io/BOOT_LOADER_SPECIFICATION">Boot
|
||||
Loader Specification</ulink> are read from <filename>/loader/entries/</filename> on the ESP and the
|
||||
Extended Boot Loader partition. Unified kernel boot entries following the <ulink
|
||||
url="https://systemd.io/BOOT_LOADER_SPECIFICATION">Boot Loader Specification</ulink> are read from
|
||||
<filename>/EFI/Linux/</filename> on the ESP and the Extended Boot Loader partition.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
|
||||
@@ -32,22 +32,18 @@
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<para><filename>systemd-gpt-auto-generator</filename> is a unit
|
||||
generator that automatically discovers root,
|
||||
<filename>/home</filename>, <filename>/srv</filename> and swap
|
||||
partitions and creates mount and swap units for them, based on the
|
||||
partition type GUIDs of GUID partition tables (GPT),
|
||||
see <ulink url="http://www.uefi.org/specifications">UEFI Specification</ulink>, chapter 5.
|
||||
It implements the <ulink
|
||||
url="https://www.freedesktop.org/wiki/Specifications/DiscoverablePartitionsSpec/">Discoverable
|
||||
Partitions Specification</ulink>. Note that this generator has no
|
||||
effect on non-GPT systems, or where the directories under the
|
||||
mount points are already non-empty. Also, on systems where the
|
||||
units are explicitly configured (for example, listed in
|
||||
<citerefentry
|
||||
project='man-pages'><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>),
|
||||
the units this generator creates are overridden, but additional
|
||||
implicit dependencies might be created.</para>
|
||||
<para><filename>systemd-gpt-auto-generator</filename> is a unit generator that automatically discovers
|
||||
root, <filename>/home/</filename>, <filename>/srv/</filename>, the EFI System Partition, the Extended
|
||||
Boot Loader Partition and swap partitions and creates mount and swap units for them, based on the
|
||||
partition type GUIDs of GUID partition tables (GPT), see <ulink
|
||||
url="http://www.uefi.org/specifications">UEFI Specification</ulink>, chapter 5. It implements the <ulink
|
||||
url="https://www.freedesktop.org/wiki/Specifications/DiscoverablePartitionsSpec/">Discoverable Partitions
|
||||
Specification</ulink>. Note that this generator has no effect on non-GPT systems, and on specific mount
|
||||
points that are directories already containing files. Also, on systems where the units are explicitly
|
||||
configured (for example, listed in <citerefentry
|
||||
project='man-pages'><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>), the
|
||||
units this generator creates are overridden, but additional implicit dependencies might be
|
||||
created.</para>
|
||||
|
||||
<para>This generator will only look for root partitions on the
|
||||
same physical disk the EFI System Partition (ESP) is located on.
|
||||
@@ -70,11 +66,13 @@
|
||||
<tgroup cols='3' align='left' colsep='1' rowsep='1'>
|
||||
<colspec colname="guid" />
|
||||
<colspec colname="name" />
|
||||
<colspec colname="where" />
|
||||
<colspec colname="explanation" />
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Partition Type GUID</entry>
|
||||
<entry>Name</entry>
|
||||
<entry>Mount Point</entry>
|
||||
<entry>Explanation</entry>
|
||||
</row>
|
||||
</thead>
|
||||
@@ -82,48 +80,63 @@
|
||||
<row>
|
||||
<entry>44479540-f297-41b2-9af7-d131d5f0458a</entry>
|
||||
<entry><filename>Root Partition (x86)</filename></entry>
|
||||
<entry><filename>/</filename></entry>
|
||||
<entry>On 32-bit x86 systems, the first x86 root partition on the disk the EFI ESP is located on is mounted to the root directory <filename>/</filename>.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>4f68bce3-e8cd-4db1-96e7-fbcaf984b709</entry>
|
||||
<entry><filename>Root Partition (x86-64)</filename></entry>
|
||||
<entry><filename>/</filename></entry>
|
||||
<entry>On 64-bit x86 systems, the first x86-64 root partition on the disk the EFI ESP is located on is mounted to the root directory <filename>/</filename>.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>69dad710-2ce4-4e3c-b16c-21a1d49abed3</entry>
|
||||
<entry><filename>Root Partition (32-bit ARM)</filename></entry>
|
||||
<entry><filename>/</filename></entry>
|
||||
<entry>On 32-bit ARM systems, the first ARM root partition on the disk the EFI ESP is located on is mounted to the root directory <filename>/</filename>.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>b921b045-1df0-41c3-af44-4c6f280d3fae</entry>
|
||||
<entry><filename>Root Partition (64-bit ARM)</filename></entry>
|
||||
<entry><filename>/</filename></entry>
|
||||
<entry>On 64-bit ARM systems, the first ARM root partition on the disk the EFI ESP is located on is mounted to the root directory <filename>/</filename>.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>993d8d3d-f80e-4225-855a-9daf8ed7ea97</entry>
|
||||
<entry><filename>Root Partition (Itanium/IA-64)</filename></entry>
|
||||
<entry><filename>/</filename></entry>
|
||||
<entry>On Itanium systems, the first Itanium root partition on the disk the EFI ESP is located on is mounted to the root directory <filename>/</filename>.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>933ac7e1-2eb4-4f13-b844-0e14e2aef915</entry>
|
||||
<entry>Home Partition</entry>
|
||||
<entry><filename>/home/</filename></entry>
|
||||
<entry>The first home partition on the disk the root partition is located on is mounted to <filename>/home</filename>.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>3b8f8425-20e0-4f3b-907f-1a25a76f98e8</entry>
|
||||
<entry>Server Data Partition</entry>
|
||||
<entry><filename>/srv/</filename></entry>
|
||||
<entry>The first server data partition on the disk the root partition is located on is mounted to <filename>/srv</filename>.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>0657fd6d-a4ab-43c4-84e5-0933c84b4f4f</entry>
|
||||
<entry>Swap</entry>
|
||||
<entry>n/a</entry>
|
||||
<entry>All swap partitions located on the disk the root partition is located on are enabled.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>c12a7328-f81f-11d2-ba4b-00a0c93ec93b</entry>
|
||||
<entry>EFI System Partition (ESP)</entry>
|
||||
<entry><filename>/efi/</filename> or <filename>/boot/</filename></entry>
|
||||
<entry>The first ESP located on the disk the root partition is located on is mounted to <filename>/boot</filename> or <filename>/efi</filename>, see below.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>bc13c2ff-59e6-4262-a352-b275fd6f7172</entry>
|
||||
<entry>Extended Boot Loader Partition</entry>
|
||||
<entry><filename>/boot/</filename></entry>
|
||||
<entry>The first Extended Boot Loader Partition is mounted to <filename>/boot</filename>, see below.</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
@@ -149,44 +162,49 @@
|
||||
<row>
|
||||
<entry><constant>GPT_FLAG_READ_ONLY</constant></entry>
|
||||
<entry>0x1000000000000000</entry>
|
||||
<entry><filename>/</filename>, <filename>/srv</filename>, <filename>/home</filename></entry>
|
||||
<entry><filename>/</filename>, <filename>/home/</filename>, <filename>/srv/</filename>, Extended Boot Loader Partition</entry>
|
||||
<entry>Partition is mounted read-only</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><constant>GPT_FLAG_NO_AUTO</constant></entry>
|
||||
<entry>0x8000000000000000</entry>
|
||||
<entry><filename>/</filename>, <filename>/srv</filename>, <filename>/home</filename></entry>
|
||||
<entry><filename>/</filename>, <filename>/home/</filename>, <filename>/srv/</filename>, Extended Boot Loader Partition</entry>
|
||||
<entry>Partition is not mounted automatically</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><constant>GPT_FLAG_NO_BLOCK_IO_PROTOCOL</constant></entry>
|
||||
<entry>0x0000000000000002</entry>
|
||||
<entry>ESP</entry>
|
||||
<entry>EFI System Partition (ESP)</entry>
|
||||
<entry>Partition is not mounted automatically</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
|
||||
<para>The <filename>/home</filename> and <filename>/srv</filename>
|
||||
partitions may be encrypted in LUKS format. In this case, a device
|
||||
mapper device is set up under the names
|
||||
<filename>/dev/mapper/home</filename> and
|
||||
<filename>/dev/mapper/srv</filename>. Note that this might create
|
||||
conflicts if the same partition is listed in
|
||||
<filename>/etc/crypttab</filename> with a different device mapper
|
||||
device name.</para>
|
||||
<para>The <filename>/home/</filename> and <filename>/srv/</filename> partitions may be encrypted in LUKS
|
||||
format. In this case, a device mapper device is set up under the names
|
||||
<filename>/dev/mapper/home</filename> and <filename>/dev/mapper/srv</filename>. Note that this might
|
||||
create conflicts if the same partition is listed in <filename>/etc/crypttab</filename> with a different
|
||||
device mapper device name.</para>
|
||||
|
||||
<para>Mount and automount units for the EFI System Partition (ESP) are generated on EFI systems. The ESP is mounted
|
||||
to <filename>/boot</filename>, unless a mount point directory <filename>/efi</filename> exists, in which case it is
|
||||
mounted there. Since this generator creates an automount unit, the mount will only be activated on-demand, when
|
||||
accessed. On systems where <filename>/boot</filename> (or <filename>/efi</filename> if it exists) is an explicitly
|
||||
configured mount (for example, listed in <citerefentry
|
||||
project='man-pages'><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>) or where the
|
||||
<filename>/boot</filename> (or <filename>/efi</filename>) mount point is non-empty, no mount units are
|
||||
generated.</para>
|
||||
<para>Mount and automount units for the EFI System Partition (ESP) are generated on EFI systems. The ESP
|
||||
is mounted to <filename>/boot/</filename> (except if an Extended Boot Loader partition exists, see
|
||||
below), unless a mount point directory <filename>/efi/</filename> exists, in which case it is mounted
|
||||
there. Since this generator creates an automount unit, the mount will only be activated on-demand, when
|
||||
accessed. On systems where <filename>/boot/</filename> (or <filename>/efi/</filename> if it exists) is an
|
||||
explicitly configured mount (for example, listed in <citerefentry
|
||||
project='man-pages'><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>) or where
|
||||
the <filename>/boot/</filename> (or <filename>/efi/</filename>) mount point is non-empty, no mount units
|
||||
are generated.</para>
|
||||
|
||||
<para>If the disk contains an Extended Boot Loader partition, as defined in the <ulink
|
||||
url="https://systemd.io/BOOT_LOADER_SPECIFICATION">Boot Loader Specification</ulink>, it is made
|
||||
available at <filename>/boot</filename> (by means of an automount point, similar to the ESP, see
|
||||
above). If both an EFI System Partition and an Extended Boot Loader partition exist the latter is
|
||||
preferably mounted to <filename>/boot/</filename>. Make sure to create both <filename>/efi/</filename>
|
||||
and <filename>/boot/</filename> to ensure both partitions are mounted.</para>
|
||||
|
||||
<para>When using this generator in conjunction with btrfs file
|
||||
systems, make sure to set the correct default subvolumes on them,
|
||||
|
||||
@@ -95,3 +95,7 @@ EOF
|
||||
mkdir -p "$DESTDIR"/boot/efi/EFI/systemd "$DESTDIR"/boot/efi/EFI/BOOT
|
||||
cp "$DESTDIR"/usr/lib/systemd/boot/efi/systemd-bootx64.efi "$DESTDIR"/boot/efi/EFI/systemd/systemd-bootx64.efi
|
||||
cp "$DESTDIR"/usr/lib/systemd/boot/efi/systemd-bootx64.efi "$DESTDIR"/boot/efi/EFI/BOOT/bootx64.efi
|
||||
|
||||
mkdir -p "$DESTDIR"/efi/EFI/systemd "$DESTDIR"/efi/EFI/BOOT
|
||||
cp "$DESTDIR"/usr/lib/systemd/boot/efi/systemd-bootx64.efi "$DESTDIR"/efi/EFI/systemd/systemd-bootx64.efi
|
||||
cp "$DESTDIR"/usr/lib/systemd/boot/efi/systemd-bootx64.efi "$DESTDIR"/efi/EFI/BOOT/bootx64.efi
|
||||
|
||||
@@ -559,6 +559,6 @@ int write_env_file(const char *fname, char **l) {
|
||||
r = -errno;
|
||||
}
|
||||
|
||||
unlink(p);
|
||||
(void) unlink(p);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -1330,6 +1330,21 @@ int fsync_path_at(int at_fd, const char *path) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int syncfs_path(int atfd, const char *path) {
|
||||
_cleanup_close_ int fd = -1;
|
||||
|
||||
assert(path);
|
||||
|
||||
fd = openat(atfd, path, O_CLOEXEC|O_RDONLY|O_NONBLOCK);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
|
||||
if (syncfs(fd) < 0)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int open_parent(const char *path, int flags, mode_t mode) {
|
||||
_cleanup_free_ char *parent = NULL;
|
||||
int fd;
|
||||
|
||||
@@ -108,4 +108,6 @@ int unlinkat_deallocate(int fd, const char *name, int flags);
|
||||
int fsync_directory_of_file(int fd);
|
||||
int fsync_path_at(int at_fd, const char *path);
|
||||
|
||||
int syncfs_path(int atfd, const char *path);
|
||||
|
||||
int open_parent(const char *path, int flags, mode_t mode);
|
||||
|
||||
+118
-77
@@ -16,9 +16,9 @@
|
||||
#include "verbs.h"
|
||||
#include "virt.h"
|
||||
|
||||
static char *arg_path = NULL;
|
||||
static char **arg_path = NULL;
|
||||
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_path, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_path, strv_freep);
|
||||
|
||||
static int help(int argc, char *argv[], void *userdata) {
|
||||
|
||||
@@ -27,7 +27,7 @@ static int help(int argc, char *argv[], void *userdata) {
|
||||
"Mark the boot process as good or bad.\n\n"
|
||||
" -h --help Show this help\n"
|
||||
" --version Print version\n"
|
||||
" --path=PATH Path to the EFI System Partition (ESP)\n"
|
||||
" --path=PATH Path to the $BOOT partition (may be used multiple times)\n"
|
||||
"\n"
|
||||
"Commands:\n"
|
||||
" good Mark this boot as good\n"
|
||||
@@ -67,7 +67,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
return version();
|
||||
|
||||
case ARG_PATH:
|
||||
r = free_and_strdup(&arg_path, optarg);
|
||||
r = strv_extend(&arg_path, optarg);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
break;
|
||||
@@ -82,20 +82,42 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int acquire_esp(void) {
|
||||
_cleanup_free_ char *np = NULL;
|
||||
static int acquire_path(void) {
|
||||
_cleanup_free_ char *esp_path = NULL, *xbootldr_path = NULL;
|
||||
char **a;
|
||||
int r;
|
||||
|
||||
r = find_esp_and_warn(arg_path, false, &np, NULL, NULL, NULL, NULL);
|
||||
if (r == -ENOKEY) /* find_esp_and_warn() doesn't warn in this one error case, but in all others */
|
||||
return log_error_errno(r,
|
||||
"Couldn't find EFI system partition. It is recommended to mount it to /boot or /efi.\n"
|
||||
"Alternatively, use --path= to specify path to mount point.");
|
||||
if (r < 0)
|
||||
if (!strv_isempty(arg_path))
|
||||
return 0;
|
||||
|
||||
r = find_esp_and_warn(NULL, false, &esp_path, NULL, NULL, NULL, NULL);
|
||||
if (r < 0 && r != -ENOKEY) /* ENOKEY means not found, and is the only error the function won't log about on its own */
|
||||
return r;
|
||||
|
||||
free_and_replace(arg_path, np);
|
||||
log_debug("Using EFI System Partition at %s.", arg_path);
|
||||
r = find_xbootldr_and_warn(NULL, false, &xbootldr_path, NULL);
|
||||
if (r < 0 && r != -ENOKEY)
|
||||
return r;
|
||||
|
||||
if (!esp_path && !xbootldr_path)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ENOENT),
|
||||
"Couldn't find $BOOT partition. It is recommended to mount it to /boot.\n"
|
||||
"Alternatively, use --path= to specify path to mount point.");
|
||||
|
||||
if (esp_path)
|
||||
a = strv_new(esp_path, xbootldr_path);
|
||||
else
|
||||
a = strv_new(xbootldr_path);
|
||||
if (!a)
|
||||
return log_oom();
|
||||
|
||||
strv_free_and_replace(arg_path, a);
|
||||
|
||||
if (DEBUG_LOGGING) {
|
||||
_cleanup_free_ char *j;
|
||||
|
||||
j = strv_join(arg_path, ":");
|
||||
log_debug("Using %s as boot loader drop-in search path.", j);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -282,10 +304,9 @@ static const char *skip_slash(const char *path) {
|
||||
}
|
||||
|
||||
static int verb_status(int argc, char *argv[], void *userdata) {
|
||||
|
||||
_cleanup_free_ char *path = NULL, *prefix = NULL, *suffix = NULL, *good = NULL, *bad = NULL;
|
||||
_cleanup_close_ int fd = -1;
|
||||
uint64_t left, done;
|
||||
char **p;
|
||||
int r;
|
||||
|
||||
r = acquire_boot_count_path(&path, &prefix, &left, &done, &suffix);
|
||||
@@ -296,7 +317,7 @@ static int verb_status(int argc, char *argv[], void *userdata) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = acquire_esp();
|
||||
r = acquire_path();
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -308,50 +329,61 @@ static int verb_status(int argc, char *argv[], void *userdata) {
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
log_debug("Booted file: %s%s\n"
|
||||
"The same modified for 'good': %s%s\n"
|
||||
"The same modified for 'bad': %s%s\n",
|
||||
arg_path, path,
|
||||
arg_path, good,
|
||||
arg_path, bad);
|
||||
log_debug("Booted file: %s\n"
|
||||
"The same modified for 'good': %s\n"
|
||||
"The same modified for 'bad': %s\n",
|
||||
path,
|
||||
good,
|
||||
bad);
|
||||
|
||||
log_debug("Tries left: %" PRIu64"\n"
|
||||
"Tries done: %" PRIu64"\n",
|
||||
left, done);
|
||||
|
||||
fd = open(arg_path, O_DIRECTORY|O_CLOEXEC|O_RDONLY);
|
||||
if (fd < 0)
|
||||
return log_error_errno(errno, "Failed to open ESP '%s': %m", arg_path);
|
||||
STRV_FOREACH(p, arg_path) {
|
||||
_cleanup_close_ int fd = -1;
|
||||
|
||||
if (faccessat(fd, skip_slash(path), F_OK, 0) >= 0) {
|
||||
puts("indeterminate");
|
||||
return 0;
|
||||
fd = open(*p, O_DIRECTORY|O_CLOEXEC|O_RDONLY);
|
||||
if (fd < 0) {
|
||||
if (errno == ENOENT)
|
||||
continue;
|
||||
|
||||
return log_error_errno(errno, "Failed to open $BOOT partition '%s': %m", *p);
|
||||
}
|
||||
|
||||
if (faccessat(fd, skip_slash(path), F_OK, 0) >= 0) {
|
||||
puts("indeterminate");
|
||||
return 0;
|
||||
}
|
||||
if (errno != ENOENT)
|
||||
return log_error_errno(errno, "Failed to check if '%s' exists: %m", path);
|
||||
|
||||
if (faccessat(fd, skip_slash(good), F_OK, 0) >= 0) {
|
||||
puts("good");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (errno != ENOENT)
|
||||
return log_error_errno(errno, "Failed to check if '%s' exists: %m", good);
|
||||
|
||||
if (faccessat(fd, skip_slash(bad), F_OK, 0) >= 0) {
|
||||
puts("bad");
|
||||
return 0;
|
||||
}
|
||||
if (errno != ENOENT)
|
||||
return log_error_errno(errno, "Failed to check if '%s' exists: %m", bad);
|
||||
|
||||
/* We didn't find any of the three? If so, let's try the next directory, before we give up. */
|
||||
}
|
||||
if (errno != ENOENT)
|
||||
return log_error_errno(errno, "Failed to check if '%s' exists: %m", path);
|
||||
|
||||
if (faccessat(fd, skip_slash(good), F_OK, 0) >= 0) {
|
||||
puts("good");
|
||||
return 0;
|
||||
}
|
||||
if (errno != ENOENT)
|
||||
return log_error_errno(errno, "Failed to check if '%s' exists: %m", good);
|
||||
|
||||
if (faccessat(fd, skip_slash(bad), F_OK, 0) >= 0) {
|
||||
puts("bad");
|
||||
return 0;
|
||||
}
|
||||
if (errno != ENOENT)
|
||||
return log_error_errno(errno, "Failed to check if '%s' exists: %m", bad);
|
||||
|
||||
return log_error_errno(errno, "Couldn't determine boot state: %m");
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EBUSY), "Couldn't determine boot state: %m");
|
||||
}
|
||||
|
||||
static int verb_set(int argc, char *argv[], void *userdata) {
|
||||
_cleanup_free_ char *path = NULL, *prefix = NULL, *suffix = NULL, *good = NULL, *bad = NULL, *parent = NULL;
|
||||
const char *target, *source1, *source2;
|
||||
_cleanup_close_ int fd = -1;
|
||||
uint64_t done;
|
||||
char **p;
|
||||
int r;
|
||||
|
||||
r = acquire_boot_count_path(&path, &prefix, NULL, &done, &suffix);
|
||||
@@ -360,7 +392,7 @@ static int verb_set(int argc, char *argv[], void *userdata) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = acquire_esp();
|
||||
r = acquire_path();
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -372,10 +404,6 @@ static int verb_set(int argc, char *argv[], void *userdata) {
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
fd = open(arg_path, O_DIRECTORY|O_CLOEXEC|O_RDONLY);
|
||||
if (fd < 0)
|
||||
return log_error_errno(errno, "Failed to open ESP '%s': %m", arg_path);
|
||||
|
||||
/* Figure out what rename to what */
|
||||
if (streq(argv[0], "good")) {
|
||||
target = good;
|
||||
@@ -392,45 +420,58 @@ static int verb_set(int argc, char *argv[], void *userdata) {
|
||||
source2 = bad;
|
||||
}
|
||||
|
||||
r = rename_noreplace(fd, skip_slash(source1), fd, skip_slash(target));
|
||||
if (r == -EEXIST)
|
||||
goto exists;
|
||||
else if (r == -ENOENT) {
|
||||
STRV_FOREACH(p, arg_path) {
|
||||
_cleanup_close_ int fd = -1;
|
||||
|
||||
r = rename_noreplace(fd, skip_slash(source2), fd, skip_slash(target));
|
||||
fd = open(*p, O_DIRECTORY|O_CLOEXEC|O_RDONLY);
|
||||
if (fd < 0)
|
||||
return log_error_errno(errno, "Failed to open $BOOT partition '%s': %m", *p);
|
||||
|
||||
r = rename_noreplace(fd, skip_slash(source1), fd, skip_slash(target));
|
||||
if (r == -EEXIST)
|
||||
goto exists;
|
||||
else if (r == -ENOENT) {
|
||||
|
||||
if (access(target, F_OK) >= 0) /* Hmm, if we can't find either source file, maybe the destination already exists? */
|
||||
r = rename_noreplace(fd, skip_slash(source2), fd, skip_slash(target));
|
||||
if (r == -EEXIST)
|
||||
goto exists;
|
||||
else if (r == -ENOENT) {
|
||||
|
||||
if (faccessat(fd, skip_slash(target), F_OK, 0) >= 0) /* Hmm, if we can't find either source file, maybe the destination already exists? */
|
||||
goto exists;
|
||||
|
||||
if (errno != ENOENT)
|
||||
return log_error_errno(errno, "Failed to determine if %s already exists: %m", target);
|
||||
|
||||
/* We found none of the snippets here, try the next directory */
|
||||
continue;
|
||||
} else if (r < 0)
|
||||
return log_error_errno(r, "Failed to rename '%s' to '%s': %m", source2, target);
|
||||
else
|
||||
log_debug("Successfully renamed '%s' to '%s'.", source2, target);
|
||||
|
||||
return log_error_errno(r, "Can't find boot counter source file for '%s': %m", target);
|
||||
} else if (r < 0)
|
||||
return log_error_errno(r, "Failed to rename '%s' to '%s': %m", source2, target);
|
||||
return log_error_errno(r, "Failed to rename '%s' to '%s': %m", source1, target);
|
||||
else
|
||||
log_debug("Successfully renamed '%s' to '%s'.", source2, target);
|
||||
log_debug("Successfully renamed '%s' to '%s'.", source1, target);
|
||||
|
||||
} else if (r < 0)
|
||||
return log_error_errno(r, "Failed to rename '%s' to '%s': %m", source1, target);
|
||||
else
|
||||
log_debug("Successfully renamed '%s' to '%s'.", source1, target);
|
||||
/* First, fsync() the directory these files are located in */
|
||||
parent = dirname_malloc(target);
|
||||
if (!parent)
|
||||
return log_oom();
|
||||
|
||||
/* First, fsync() the directory these files are located in */
|
||||
parent = dirname_malloc(path);
|
||||
if (!parent)
|
||||
return log_oom();
|
||||
r = fsync_path_at(fd, skip_slash(parent));
|
||||
if (r < 0)
|
||||
log_debug_errno(errno, "Failed to synchronize image directory, ignoring: %m");
|
||||
|
||||
r = fsync_path_at(fd, skip_slash(parent));
|
||||
if (r < 0)
|
||||
log_debug_errno(errno, "Failed to synchronize image directory, ignoring: %m");
|
||||
/* Secondly, syncfs() the whole file system these files are located in */
|
||||
if (syncfs(fd) < 0)
|
||||
log_debug_errno(errno, "Failed to synchronize $BOOT partition, ignoring: %m");
|
||||
|
||||
/* Secondly, syncfs() the whole file system these files are located in */
|
||||
if (syncfs(fd) < 0)
|
||||
log_debug_errno(errno, "Failed to synchronize ESP, ignoring: %m");
|
||||
|
||||
log_info("Marked boot as '%s'. (Boot attempt counter is at %" PRIu64".)", argv[0], done);
|
||||
log_info("Marked boot as '%s'. (Boot attempt counter is at %" PRIu64".)", argv[0], done);
|
||||
}
|
||||
|
||||
log_error_errno(SYNTHETIC_ERRNO(EBUSY), "Can't find boot counter source file for '%s': %m", target);
|
||||
return 1;
|
||||
|
||||
exists:
|
||||
|
||||
+272
-122
@@ -45,12 +45,20 @@
|
||||
#include "verbs.h"
|
||||
#include "virt.h"
|
||||
|
||||
static char *arg_path = NULL;
|
||||
static bool arg_print_path = false;
|
||||
static char *arg_esp_path = NULL;
|
||||
static char *arg_xbootldr_path = NULL;
|
||||
static bool arg_print_esp_path = false;
|
||||
static bool arg_print_dollar_boot_path = false;
|
||||
static bool arg_touch_variables = true;
|
||||
static PagerFlags arg_pager_flags = 0;
|
||||
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_path, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_esp_path, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_xbootldr_path, freep);
|
||||
|
||||
static const char *arg_dollar_boot_path(void) {
|
||||
/* $BOOT shall be the XBOOTLDR partition if it exists, and otherwise the ESP */
|
||||
return arg_xbootldr_path ?: arg_esp_path;
|
||||
}
|
||||
|
||||
static int acquire_esp(
|
||||
bool unprivileged_mode,
|
||||
@@ -62,24 +70,44 @@ static int acquire_esp(
|
||||
char *np;
|
||||
int r;
|
||||
|
||||
/* Find the ESP, and log about errors. Note that find_esp_and_warn() will log in all error cases on its own,
|
||||
* except for ENOKEY (which is good, we want to show our own message in that case, suggesting use of --path=)
|
||||
* and EACCESS (only when we request unprivileged mode; in this case we simply eat up the error here, so that
|
||||
* --list and --status work too, without noise about this). */
|
||||
/* Find the ESP, and log about errors. Note that find_esp_and_warn() will log in all error cases on
|
||||
* its own, except for ENOKEY (which is good, we want to show our own message in that case,
|
||||
* suggesting use of --esp-path=) and EACCESS (only when we request unprivileged mode; in this case
|
||||
* we simply eat up the error here, so that --list and --status work too, without noise about
|
||||
* this). */
|
||||
|
||||
r = find_esp_and_warn(arg_path, unprivileged_mode, &np, ret_part, ret_pstart, ret_psize, ret_uuid);
|
||||
r = find_esp_and_warn(arg_esp_path, unprivileged_mode, &np, ret_part, ret_pstart, ret_psize, ret_uuid);
|
||||
if (r == -ENOKEY)
|
||||
return log_error_errno(r,
|
||||
"Couldn't find EFI system partition. It is recommended to mount it to /boot or /efi.\n"
|
||||
"Alternatively, use --path= to specify path to mount point.");
|
||||
"Alternatively, use --esp-path= to specify path to mount point.");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
free_and_replace(arg_path, np);
|
||||
free_and_replace(arg_esp_path, np);
|
||||
log_debug("Using EFI System Partition at %s.", arg_esp_path);
|
||||
|
||||
log_debug("Using EFI System Partition at %s.", arg_path);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
static int acquire_xbootldr(bool unprivileged_mode, sd_id128_t *ret_uuid) {
|
||||
char *np;
|
||||
int r;
|
||||
|
||||
r = find_xbootldr_and_warn(arg_xbootldr_path, unprivileged_mode, &np, ret_uuid);
|
||||
if (r == -ENOKEY) {
|
||||
log_debug_errno(r, "Didn't find an XBOOTLDR partition, using the ESP as $BOOT.");
|
||||
if (ret_uuid)
|
||||
*ret_uuid = SD_ID128_NULL;
|
||||
return 0;
|
||||
}
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
free_and_replace(arg_xbootldr_path, np);
|
||||
log_debug("Using XBOOTLDR partition at %s as $BOOT.", arg_xbootldr_path);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* search for "#### LoaderInfo: systemd-boot 218 ####" string inside the binary */
|
||||
@@ -96,6 +124,10 @@ static int get_file_version(int fd, char **v) {
|
||||
if (fstat(fd, &st) < 0)
|
||||
return log_error_errno(errno, "Failed to stat EFI binary: %m");
|
||||
|
||||
r = stat_verify_regular(&st);
|
||||
if (r < 0)
|
||||
return log_error_errno(errno, "EFI binary is not a regular file: %m");
|
||||
|
||||
if (st.st_size < 27) {
|
||||
*v = NULL;
|
||||
return 0;
|
||||
@@ -112,8 +144,7 @@ static int get_file_version(int fd, char **v) {
|
||||
|
||||
e = memmem(s, st.st_size - (s - buf), " ####", 5);
|
||||
if (!e || e - s < 3) {
|
||||
log_error("Malformed version string.");
|
||||
r = -EINVAL;
|
||||
r = log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Malformed version string.");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
@@ -131,10 +162,13 @@ finish:
|
||||
}
|
||||
|
||||
static int enumerate_binaries(const char *esp_path, const char *path, const char *prefix) {
|
||||
char *p;
|
||||
_cleanup_closedir_ DIR *d = NULL;
|
||||
struct dirent *de;
|
||||
int r = 0, c = 0;
|
||||
int c = 0, r;
|
||||
char *p;
|
||||
|
||||
assert(esp_path);
|
||||
assert(path);
|
||||
|
||||
p = strjoina(esp_path, "/", path);
|
||||
d = opendir(p);
|
||||
@@ -146,8 +180,8 @@ static int enumerate_binaries(const char *esp_path, const char *path, const char
|
||||
}
|
||||
|
||||
FOREACH_DIRENT(de, d, break) {
|
||||
_cleanup_close_ int fd = -1;
|
||||
_cleanup_free_ char *v = NULL;
|
||||
_cleanup_close_ int fd = -1;
|
||||
|
||||
if (!endswith_no_case(de->d_name, ".efi"))
|
||||
continue;
|
||||
@@ -166,6 +200,7 @@ static int enumerate_binaries(const char *esp_path, const char *path, const char
|
||||
printf(" File: %s/%s/%s (%s%s%s)\n", special_glyph(SPECIAL_GLYPH_TREE_RIGHT), path, de->d_name, ansi_highlight(), v, ansi_normal());
|
||||
else
|
||||
printf(" File: %s/%s/%s\n", special_glyph(SPECIAL_GLYPH_TREE_RIGHT), path, de->d_name);
|
||||
|
||||
c++;
|
||||
}
|
||||
|
||||
@@ -188,20 +223,22 @@ static int status_binaries(const char *esp_path, sd_id128_t partition) {
|
||||
printf("\n");
|
||||
|
||||
r = enumerate_binaries(esp_path, "EFI/systemd", NULL);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
if (r == 0)
|
||||
log_info("systemd-boot not installed in ESP.");
|
||||
else if (r < 0)
|
||||
return r;
|
||||
|
||||
r = enumerate_binaries(esp_path, "EFI/BOOT", "boot");
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
if (r == 0)
|
||||
log_info("No default/fallback boot loader installed in ESP.");
|
||||
else if (r < 0)
|
||||
return r;
|
||||
|
||||
r = 0;
|
||||
|
||||
finish:
|
||||
printf("\n");
|
||||
|
||||
return 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
static int print_efi_option(uint16_t id, bool in_order) {
|
||||
@@ -316,11 +353,34 @@ static int boot_entry_show(const BootEntry *e, bool show_as_default) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int status_entries(const char *esp_path, sd_id128_t partition) {
|
||||
static int status_entries(
|
||||
const char *esp_path,
|
||||
sd_id128_t esp_partition_uuid,
|
||||
const char *xbootldr_path,
|
||||
sd_id128_t xbootldr_partition_uuid) {
|
||||
|
||||
_cleanup_(boot_config_free) BootConfig config = {};
|
||||
sd_id128_t dollar_boot_partition_uuid;
|
||||
const char *dollar_boot_path;
|
||||
int r;
|
||||
|
||||
r = boot_entries_load_config(esp_path, &config);
|
||||
assert(esp_path || xbootldr_path);
|
||||
|
||||
if (xbootldr_path) {
|
||||
dollar_boot_path = xbootldr_path;
|
||||
dollar_boot_partition_uuid = xbootldr_partition_uuid;
|
||||
} else {
|
||||
dollar_boot_path = esp_path;
|
||||
dollar_boot_partition_uuid = esp_partition_uuid;
|
||||
}
|
||||
|
||||
printf("Boot Loader Entries:\n"
|
||||
" $BOOT: %s", dollar_boot_path);
|
||||
if (!sd_id128_is_null(dollar_boot_partition_uuid))
|
||||
printf(" (/dev/disk/by-partuuid/%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x)", SD_ID128_FORMAT_VAL(dollar_boot_partition_uuid));
|
||||
printf("\n\n");
|
||||
|
||||
r = boot_entries_load_config(esp_path, xbootldr_path, &config);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -386,10 +446,8 @@ static int version_check(int fd_from, const char *from, int fd_to, const char *t
|
||||
"Skipping \"%s\", since it's owned by another boot loader.",
|
||||
to);
|
||||
|
||||
if (compare_version(a, b) < 0) {
|
||||
log_warning("Skipping \"%s\", since a newer boot loader version exists already.", to);
|
||||
return -ESTALE;
|
||||
}
|
||||
if (compare_version(a, b) < 0)
|
||||
return log_warning_errno(SYNTHETIC_ERRNO(ESTALE), "Skipping \"%s\", since a newer boot loader version exists already.", to);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -468,20 +526,21 @@ static int mkdir_one(const char *prefix, const char *suffix) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *efi_subdirs[] = {
|
||||
static const char *const esp_subdirs[] = {
|
||||
"EFI",
|
||||
"EFI/systemd",
|
||||
"EFI/BOOT",
|
||||
"loader",
|
||||
"loader/entries",
|
||||
/* Note that "/loader/entries" is not listed here, since it should be placed in $BOOT, which might
|
||||
* not necessarily be the ESP */
|
||||
NULL
|
||||
};
|
||||
|
||||
static int create_dirs(const char *esp_path) {
|
||||
const char **i;
|
||||
static int create_esp_subdirs(const char *esp_path) {
|
||||
const char *const *i;
|
||||
int r;
|
||||
|
||||
STRV_FOREACH(i, efi_subdirs) {
|
||||
STRV_FOREACH(i, esp_subdirs) {
|
||||
r = mkdir_one(esp_path, *i);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -520,22 +579,11 @@ static int install_binaries(const char *esp_path, bool force) {
|
||||
_cleanup_closedir_ DIR *d = NULL;
|
||||
int r = 0;
|
||||
|
||||
if (force) {
|
||||
/* Don't create any of these directories when we are
|
||||
* just updating. When we update we'll drop-in our
|
||||
* files (unless there are newer ones already), but we
|
||||
* won't create the directories for them in the first
|
||||
* place. */
|
||||
r = create_dirs(esp_path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
d = opendir(BOOTLIBDIR);
|
||||
if (!d)
|
||||
return log_error_errno(errno, "Failed to open \""BOOTLIBDIR"\": %m");
|
||||
|
||||
FOREACH_DIRENT(de, d, break) {
|
||||
FOREACH_DIRENT(de, d, return log_error_errno(errno, "Failed to read \""BOOTLIBDIR"\": %m")) {
|
||||
int k;
|
||||
|
||||
if (!endswith_no_case(de->d_name, ".efi"))
|
||||
@@ -751,18 +799,36 @@ static int rmdir_one(const char *prefix, const char *suffix) {
|
||||
|
||||
p = strjoina(prefix, "/", suffix);
|
||||
if (rmdir(p) < 0) {
|
||||
if (!IN_SET(errno, ENOENT, ENOTEMPTY))
|
||||
return log_error_errno(errno, "Failed to remove \"%s\": %m", p);
|
||||
bool ignore = IN_SET(errno, ENOENT, ENOTEMPTY);
|
||||
|
||||
log_full_errno(ignore ? LOG_DEBUG : LOG_ERR, errno,
|
||||
"Failed to remove directory \"%s\": %m", p);
|
||||
if (!ignore)
|
||||
return -errno;
|
||||
} else
|
||||
log_info("Removed \"%s\".", p);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int remove_esp_subdirs(const char *esp_path) {
|
||||
size_t i;
|
||||
int r = 0;
|
||||
|
||||
for (i = ELEMENTSOF(esp_subdirs)-1; i > 0; i--) {
|
||||
int q;
|
||||
|
||||
q = rmdir_one(esp_path, esp_subdirs[i-1]);
|
||||
if (q < 0 && r >= 0)
|
||||
r = q;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int remove_binaries(const char *esp_path) {
|
||||
char *p;
|
||||
int r, q;
|
||||
unsigned i;
|
||||
|
||||
p = strjoina(esp_path, "/EFI/systemd");
|
||||
r = rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL);
|
||||
@@ -771,15 +837,31 @@ static int remove_binaries(const char *esp_path) {
|
||||
if (q < 0 && r == 0)
|
||||
r = q;
|
||||
|
||||
for (i = ELEMENTSOF(efi_subdirs)-1; i > 0; i--) {
|
||||
q = rmdir_one(esp_path, efi_subdirs[i-1]);
|
||||
if (q < 0 && r == 0)
|
||||
r = q;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int remove_loader_config(const char *esp_path) {
|
||||
const char *p;
|
||||
|
||||
assert(esp_path);
|
||||
|
||||
p = strjoina(esp_path, "/loader/loader.conf");
|
||||
if (unlink(p) < 0) {
|
||||
log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_ERR, errno, "Failed to unlink file \"%s\": %m", p);
|
||||
if (errno != ENOENT)
|
||||
return -errno;
|
||||
} else
|
||||
log_info("Removed \"%s\".", p);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int remove_entries_directory(const char *dollar_boot_path) {
|
||||
assert(dollar_boot_path);
|
||||
|
||||
return rmdir_one(dollar_boot_path, "/loader/entries");
|
||||
}
|
||||
|
||||
static int remove_variables(sd_id128_t uuid, const char *path, bool in_order) {
|
||||
uint16_t slot;
|
||||
int r;
|
||||
@@ -802,7 +884,6 @@ static int remove_variables(sd_id128_t uuid, const char *path, bool in_order) {
|
||||
}
|
||||
|
||||
static int install_loader_config(const char *esp_path) {
|
||||
|
||||
char machine_string[SD_ID128_STRING_MAX];
|
||||
_cleanup_(unlink_and_freep) char *t = NULL;
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
@@ -810,15 +891,14 @@ static int install_loader_config(const char *esp_path) {
|
||||
const char *p;
|
||||
int r, fd;
|
||||
|
||||
p = strjoina(esp_path, "/loader/loader.conf");
|
||||
if (access(p, F_OK) >= 0) /* Silently skip creation if the file already exists (early check) */
|
||||
return 0;
|
||||
|
||||
r = sd_id128_get_machine(&machine_id);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to get machine id: %m");
|
||||
|
||||
p = strjoina(esp_path, "/loader/loader.conf");
|
||||
|
||||
if (access(p, F_OK) >= 0) /* Silently skip creation if the file already exists (early check) */
|
||||
return 0;
|
||||
|
||||
fd = open_tmpfile_linkable(p, O_WRONLY|O_CLOEXEC, &t);
|
||||
if (fd < 0)
|
||||
return log_error_errno(fd, "Failed to open \"%s\" for writing: %m", p);
|
||||
@@ -844,10 +924,15 @@ static int install_loader_config(const char *esp_path) {
|
||||
return log_error_errno(r, "Failed to move \"%s\" into place: %m", p);
|
||||
|
||||
t = mfree(t);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int install_entries_directory(const char *dollar_boot_path) {
|
||||
assert(dollar_boot_path);
|
||||
|
||||
return mkdir_one(dollar_boot_path, "/loader/entries");
|
||||
}
|
||||
|
||||
static int help(int argc, char *argv[], void *userdata) {
|
||||
_cleanup_free_ char *link = NULL;
|
||||
int r;
|
||||
@@ -858,21 +943,23 @@ static int help(int argc, char *argv[], void *userdata) {
|
||||
|
||||
printf("%s [COMMAND] [OPTIONS...]\n\n"
|
||||
"Install, update or remove the systemd-boot EFI boot manager.\n\n"
|
||||
" -h --help Show this help\n"
|
||||
" --version Print version\n"
|
||||
" --path=PATH Path to the EFI System Partition (ESP)\n"
|
||||
" -p --print-path Print path to the EFI partition\n"
|
||||
" --no-variables Don't touch EFI variables\n"
|
||||
" --no-pager Do not pipe output into a pager\n"
|
||||
" -h --help Show this help\n"
|
||||
" --version Print version\n"
|
||||
" --esp-path=PATH Path to the EFI System Partition (ESP)\n"
|
||||
" --boot-path=PATH Path to the $BOOT partition\n"
|
||||
" -p --print-esp-path Print path to the EFI System Partition\n"
|
||||
" --print-boot-path Print path to the $BOOT partition\n"
|
||||
" --no-variables Don't touch EFI variables\n"
|
||||
" --no-pager Do not pipe output into a pager\n"
|
||||
"\nBoot Loader Commands:\n"
|
||||
" status Show status of installed systemd-boot and EFI variables\n"
|
||||
" install Install systemd-boot to the ESP and EFI variables\n"
|
||||
" update Update systemd-boot in the ESP and EFI variables\n"
|
||||
" remove Remove systemd-boot from the ESP and EFI variables\n"
|
||||
" status Show status of installed systemd-boot and EFI variables\n"
|
||||
" install Install systemd-boot to the ESP and EFI variables\n"
|
||||
" update Update systemd-boot in the ESP and EFI variables\n"
|
||||
" remove Remove systemd-boot from the ESP and EFI variables\n"
|
||||
"\nBoot Loader Entries Commands:\n"
|
||||
" list List boot loader entries\n"
|
||||
" set-default ID Set default boot loader entry\n"
|
||||
" set-oneshot ID Set default boot loader entry, for next boot only\n"
|
||||
" list List boot loader entries\n"
|
||||
" set-default ID Set default boot loader entry\n"
|
||||
" set-oneshot ID Set default boot loader entry, for next boot only\n"
|
||||
"\nSee the %s for details.\n"
|
||||
, program_invocation_short_name
|
||||
, link);
|
||||
@@ -882,19 +969,25 @@ static int help(int argc, char *argv[], void *userdata) {
|
||||
|
||||
static int parse_argv(int argc, char *argv[]) {
|
||||
enum {
|
||||
ARG_PATH = 0x100,
|
||||
ARG_ESP_PATH = 0x100,
|
||||
ARG_BOOT_PATH,
|
||||
ARG_PRINT_BOOT_PATH,
|
||||
ARG_VERSION,
|
||||
ARG_NO_VARIABLES,
|
||||
ARG_NO_PAGER,
|
||||
};
|
||||
|
||||
static const struct option options[] = {
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "version", no_argument, NULL, ARG_VERSION },
|
||||
{ "path", required_argument, NULL, ARG_PATH },
|
||||
{ "print-path", no_argument, NULL, 'p' },
|
||||
{ "no-variables", no_argument, NULL, ARG_NO_VARIABLES },
|
||||
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "version", no_argument, NULL, ARG_VERSION },
|
||||
{ "esp-path", required_argument, NULL, ARG_ESP_PATH },
|
||||
{ "path", required_argument, NULL, ARG_ESP_PATH }, /* Compatibility alias */
|
||||
{ "boot-path", required_argument, NULL, ARG_BOOT_PATH },
|
||||
{ "print-esp-path", no_argument, NULL, 'p' },
|
||||
{ "print-path", no_argument, NULL, 'p' }, /* Compatibility alias */
|
||||
{ "print-boot-path", no_argument, NULL, ARG_PRINT_BOOT_PATH },
|
||||
{ "no-variables", no_argument, NULL, ARG_NO_VARIABLES },
|
||||
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
|
||||
{}
|
||||
};
|
||||
|
||||
@@ -913,14 +1006,24 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
case ARG_VERSION:
|
||||
return version();
|
||||
|
||||
case ARG_PATH:
|
||||
r = free_and_strdup(&arg_path, optarg);
|
||||
case ARG_ESP_PATH:
|
||||
r = free_and_strdup(&arg_esp_path, optarg);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
break;
|
||||
|
||||
case ARG_BOOT_PATH:
|
||||
r = free_and_strdup(&arg_xbootldr_path, optarg);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
arg_print_path = true;
|
||||
arg_print_esp_path = true;
|
||||
break;
|
||||
|
||||
case ARG_PRINT_BOOT_PATH:
|
||||
arg_print_dollar_boot_path = true;
|
||||
break;
|
||||
|
||||
case ARG_NO_VARIABLES:
|
||||
@@ -950,23 +1053,33 @@ static void read_loader_efi_var(const char *name, char **var) {
|
||||
}
|
||||
|
||||
static int verb_status(int argc, char *argv[], void *userdata) {
|
||||
|
||||
sd_id128_t uuid = SD_ID128_NULL;
|
||||
sd_id128_t esp_uuid = SD_ID128_NULL, xbootldr_uuid = SD_ID128_NULL;
|
||||
int r, k;
|
||||
|
||||
r = acquire_esp(geteuid() != 0, NULL, NULL, NULL, &uuid);
|
||||
|
||||
if (arg_print_path) {
|
||||
r = acquire_esp(geteuid() != 0, NULL, NULL, NULL, &esp_uuid);
|
||||
if (arg_print_esp_path) {
|
||||
if (r == -EACCES) /* If we couldn't acquire the ESP path, log about access errors (which is the only
|
||||
* error the find_esp_and_warn() won't log on its own) */
|
||||
return log_error_errno(r, "Failed to determine ESP: %m");
|
||||
return log_error_errno(r, "Failed to determine ESP location: %m");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
puts(arg_path);
|
||||
return 0;
|
||||
puts(arg_esp_path);
|
||||
}
|
||||
|
||||
r = acquire_xbootldr(geteuid() != 0, &xbootldr_uuid);
|
||||
if (arg_print_dollar_boot_path) {
|
||||
if (r == -EACCES)
|
||||
return log_error_errno(r, "Failed to determine XBOOTLDR location: %m");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
puts(arg_dollar_boot_path());
|
||||
}
|
||||
|
||||
if (arg_print_esp_path || arg_print_dollar_boot_path)
|
||||
return 0;
|
||||
|
||||
r = 0; /* If we couldn't determine the path, then don't consider that a problem from here on, just show what we
|
||||
* can show */
|
||||
|
||||
@@ -1037,8 +1150,8 @@ static int verb_status(int argc, char *argv[], void *userdata) {
|
||||
} else
|
||||
printf("System:\n Not booted with EFI\n\n");
|
||||
|
||||
if (arg_path) {
|
||||
k = status_binaries(arg_path, uuid);
|
||||
if (arg_esp_path) {
|
||||
k = status_binaries(arg_esp_path, esp_uuid);
|
||||
if (k < 0)
|
||||
r = k;
|
||||
}
|
||||
@@ -1049,8 +1162,8 @@ static int verb_status(int argc, char *argv[], void *userdata) {
|
||||
r = k;
|
||||
}
|
||||
|
||||
if (arg_path) {
|
||||
k = status_entries(arg_path, uuid);
|
||||
if (arg_esp_path || arg_xbootldr_path) {
|
||||
k = status_entries(arg_esp_path, esp_uuid, arg_xbootldr_path, xbootldr_uuid);
|
||||
if (k < 0)
|
||||
r = k;
|
||||
}
|
||||
@@ -1061,20 +1174,25 @@ static int verb_status(int argc, char *argv[], void *userdata) {
|
||||
static int verb_list(int argc, char *argv[], void *userdata) {
|
||||
_cleanup_(boot_config_free) BootConfig config = {};
|
||||
_cleanup_free_ char **found_by_loader = NULL;
|
||||
sd_id128_t uuid = SD_ID128_NULL;
|
||||
int r;
|
||||
|
||||
/* If we lack privileges we invoke find_esp_and_warn() in "unprivileged mode" here, which does two things: turn
|
||||
* off logging about access errors and turn off potentially privileged device probing. Here we're interested in
|
||||
* the latter but not the former, hence request the mode, and log about EACCES. */
|
||||
|
||||
r = acquire_esp(geteuid() != 0, NULL, NULL, NULL, &uuid);
|
||||
r = acquire_esp(geteuid() != 0, NULL, NULL, NULL, NULL);
|
||||
if (r == -EACCES) /* We really need the ESP path for this call, hence also log about access errors */
|
||||
return log_error_errno(r, "Failed to determine ESP: %m");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = boot_entries_load_config(arg_path, &config);
|
||||
r = acquire_xbootldr(geteuid() != 0, NULL);
|
||||
if (r == -EACCES)
|
||||
return log_error_errno(r, "Failed to determine XBOOTLDR partition: %m");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = boot_entries_load_config(arg_esp_path, arg_xbootldr_path, &config);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -1114,24 +1232,25 @@ static int verb_list(int argc, char *argv[], void *userdata) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sync_esp(void) {
|
||||
_cleanup_close_ int fd = -1;
|
||||
static int sync_everything(void) {
|
||||
int ret = 0, k;
|
||||
|
||||
if (!arg_path)
|
||||
return 0;
|
||||
if (arg_esp_path) {
|
||||
k = syncfs_path(AT_FDCWD, arg_esp_path);
|
||||
if (k < 0)
|
||||
ret = log_error_errno(k, "Failed to synchronize the ESP '%s': %m", arg_esp_path);
|
||||
}
|
||||
|
||||
fd = open(arg_path, O_CLOEXEC|O_DIRECTORY|O_RDONLY);
|
||||
if (fd < 0)
|
||||
return log_error_errno(errno, "Couldn't open ESP '%s' for synchronization: %m", arg_path);
|
||||
if (arg_xbootldr_path) {
|
||||
k = syncfs_path(AT_FDCWD, arg_xbootldr_path);
|
||||
if (k < 0)
|
||||
ret = log_error_errno(k, "Failed to synchronize $BOOT '%s': %m", arg_xbootldr_path);
|
||||
}
|
||||
|
||||
if (syncfs(fd) < 0)
|
||||
return log_error_errno(errno, "Failed to synchronize the ESP '%s': %m", arg_path);
|
||||
|
||||
return 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int verb_install(int argc, char *argv[], void *userdata) {
|
||||
|
||||
sd_id128_t uuid = SD_ID128_NULL;
|
||||
uint64_t pstart = 0, psize = 0;
|
||||
uint32_t part = 0;
|
||||
@@ -1142,24 +1261,41 @@ static int verb_install(int argc, char *argv[], void *userdata) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = acquire_xbootldr(false, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
install = streq(argv[0], "install");
|
||||
|
||||
RUN_WITH_UMASK(0002) {
|
||||
r = install_binaries(arg_path, install);
|
||||
if (install) {
|
||||
/* Don't create any of these directories when we are just updating. When we update
|
||||
* we'll drop-in our files (unless there are newer ones already), but we won't create
|
||||
* the directories for them in the first place. */
|
||||
r = create_esp_subdirs(arg_esp_path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = install_binaries(arg_esp_path, install);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (install) {
|
||||
r = install_loader_config(arg_path);
|
||||
r = install_loader_config(arg_esp_path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = install_entries_directory(arg_dollar_boot_path());
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
(void) sync_esp();
|
||||
(void) sync_everything();
|
||||
|
||||
if (arg_touch_variables)
|
||||
r = install_variables(arg_path,
|
||||
r = install_variables(arg_esp_path,
|
||||
part, pstart, psize, uuid,
|
||||
"/EFI/systemd/systemd-boot" EFI_MACHINE_TYPE_NAME ".efi",
|
||||
install);
|
||||
@@ -1169,21 +1305,35 @@ static int verb_install(int argc, char *argv[], void *userdata) {
|
||||
|
||||
static int verb_remove(int argc, char *argv[], void *userdata) {
|
||||
sd_id128_t uuid = SD_ID128_NULL;
|
||||
int r;
|
||||
int r, q;
|
||||
|
||||
r = acquire_esp(false, NULL, NULL, NULL, &uuid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = remove_binaries(arg_path);
|
||||
r = acquire_xbootldr(false, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
(void) sync_esp();
|
||||
r = remove_binaries(arg_esp_path);
|
||||
|
||||
q = remove_loader_config(arg_esp_path);
|
||||
if (q < 0 && r >= 0)
|
||||
r = q;
|
||||
|
||||
q = remove_entries_directory(arg_dollar_boot_path());
|
||||
if (q < 0 && r >= 0)
|
||||
r = q;
|
||||
|
||||
q = remove_esp_subdirs(arg_esp_path);
|
||||
if (q < 0 && r >= 0)
|
||||
r = q;
|
||||
|
||||
(void) sync_everything();
|
||||
|
||||
if (arg_touch_variables) {
|
||||
int q;
|
||||
|
||||
q = remove_variables(uuid, "/EFI/systemd/systemd-boot" EFI_MACHINE_TYPE_NAME ".efi", true);
|
||||
if (q < 0 && r == 0)
|
||||
if (q < 0 && r >= 0)
|
||||
r = q;
|
||||
}
|
||||
|
||||
|
||||
+197
-5
@@ -1,9 +1,11 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||
|
||||
#include <efi.h>
|
||||
#include <efigpt.h>
|
||||
#include <efilib.h>
|
||||
|
||||
#include "console.h"
|
||||
#include "crc32.h"
|
||||
#include "disk.h"
|
||||
#include "graphics.h"
|
||||
#include "linux.h"
|
||||
@@ -1316,7 +1318,7 @@ static VOID config_entry_add_from_file(
|
||||
entry->loader = stra_to_path(value);
|
||||
|
||||
/* do not add an entry for ourselves */
|
||||
if (StriCmp(entry->loader, loaded_image_path) == 0) {
|
||||
if (loaded_image_path && StriCmp(entry->loader, loaded_image_path) == 0) {
|
||||
entry->type = LOADER_UNDEFINED;
|
||||
break;
|
||||
}
|
||||
@@ -1836,7 +1838,7 @@ static VOID config_entry_add_osx(Config *config) {
|
||||
|
||||
static VOID config_entry_add_linux(
|
||||
Config *config,
|
||||
EFI_LOADED_IMAGE *loaded_image,
|
||||
EFI_HANDLE *device,
|
||||
EFI_FILE *root_dir) {
|
||||
|
||||
EFI_FILE_HANDLE linux_dir;
|
||||
@@ -1926,7 +1928,7 @@ static VOID config_entry_add_linux(
|
||||
conf = PoolPrint(L"%s-%s", os_id, os_version ? : os_build);
|
||||
path = PoolPrint(L"\\EFI\\Linux\\%s", f->FileName);
|
||||
|
||||
entry = config_entry_add_loader(config, loaded_image->DeviceHandle, LOADER_LINUX, conf, 'l', os_name, path);
|
||||
entry = config_entry_add_loader(config, device, LOADER_LINUX, conf, 'l', os_name, path);
|
||||
|
||||
FreePool(content);
|
||||
content = NULL;
|
||||
@@ -1955,6 +1957,193 @@ static VOID config_entry_add_linux(
|
||||
uefi_call_wrapper(linux_dir->Close, 1, linux_dir);
|
||||
}
|
||||
|
||||
/* Note that this is in GUID format, i.e. the first 32bit, and the following pair of 16bit are byteswapped. */
|
||||
static const UINT8 xbootldr_guid[16] = {
|
||||
0xff, 0xc2, 0x13, 0xbc, 0xe6, 0x59, 0x62, 0x42, 0xa3, 0x52, 0xb2, 0x75, 0xfd, 0x6f, 0x71, 0x72
|
||||
};
|
||||
|
||||
EFI_DEVICE_PATH *path_parent(EFI_DEVICE_PATH *path, EFI_DEVICE_PATH *node) {
|
||||
EFI_DEVICE_PATH *parent;
|
||||
UINTN len;
|
||||
|
||||
len = (UINT8*) NextDevicePathNode(node) - (UINT8*) path;
|
||||
parent = (EFI_DEVICE_PATH*) AllocatePool(len + sizeof(EFI_DEVICE_PATH));
|
||||
CopyMem(parent, path, len);
|
||||
CopyMem((UINT8*) parent + len, EndDevicePath, sizeof(EFI_DEVICE_PATH));
|
||||
|
||||
return parent;
|
||||
}
|
||||
|
||||
static VOID config_load_xbootldr(
|
||||
Config *config,
|
||||
EFI_HANDLE *device) {
|
||||
|
||||
EFI_DEVICE_PATH *partition_path, *node, *disk_path, *copy;
|
||||
UINT32 found_partition_number = (UINT32) -1;
|
||||
UINT64 found_partition_start = (UINT64) -1;
|
||||
UINT64 found_partition_size = (UINT64) -1;
|
||||
UINT8 found_partition_signature[16] = {};
|
||||
EFI_HANDLE new_device;
|
||||
EFI_FILE *root_dir;
|
||||
EFI_STATUS r;
|
||||
|
||||
partition_path = DevicePathFromHandle(device);
|
||||
if (!partition_path)
|
||||
return;
|
||||
|
||||
for (node = partition_path; !IsDevicePathEnd(node); node = NextDevicePathNode(node)) {
|
||||
EFI_HANDLE disk_handle;
|
||||
EFI_BLOCK_IO *block_io;
|
||||
EFI_DEVICE_PATH *p;
|
||||
UINTN nr;
|
||||
|
||||
/* First, Let's look for the SCSI/SATA/USB/… device path node, i.e. one above the media
|
||||
* devices */
|
||||
if (DevicePathType(node) != MESSAGING_DEVICE_PATH)
|
||||
continue;
|
||||
|
||||
/* Determine the device path one level up */
|
||||
disk_path = path_parent(partition_path, node);
|
||||
p = disk_path;
|
||||
r = uefi_call_wrapper(BS->LocateDevicePath, 3, &BlockIoProtocol, &p, &disk_handle);
|
||||
if (EFI_ERROR(r))
|
||||
continue;
|
||||
|
||||
r = uefi_call_wrapper(BS->HandleProtocol, 3, disk_handle, &BlockIoProtocol, (VOID **)&block_io);
|
||||
if (EFI_ERROR(r))
|
||||
continue;
|
||||
|
||||
/* Filter out some block devices early. (We only care about block devices that aren't
|
||||
* partitions themselves — we look for GPT partition tables to parse after all —, and only
|
||||
* those which contain a medium and have at least 2 blocks.) */
|
||||
if (block_io->Media->LogicalPartition ||
|
||||
!block_io->Media->MediaPresent ||
|
||||
block_io->Media->LastBlock <= 1)
|
||||
continue;
|
||||
|
||||
/* Try both copies of the GPT header, in case one is corrupted */
|
||||
for (nr = 0; nr < 2; nr++) {
|
||||
_cleanup_freepool_ EFI_PARTITION_ENTRY* entries = NULL;
|
||||
union {
|
||||
EFI_PARTITION_TABLE_HEADER gpt_header;
|
||||
uint8_t space[((sizeof(EFI_PARTITION_TABLE_HEADER) + 511) / 512) * 512];
|
||||
} gpt_header_buffer;
|
||||
UINT64 where;
|
||||
UINTN i, sz;
|
||||
UINT32 c;
|
||||
|
||||
if (nr == 0)
|
||||
where = 1; /* Read the first copy at LBA 1 */
|
||||
else
|
||||
where = block_io->Media->LastBlock; /* Read the second copy at the very last LBA of this block device */
|
||||
|
||||
/* Read the GPT header */
|
||||
r = uefi_call_wrapper(block_io->ReadBlocks, 5, block_io, block_io->Media->MediaId, where, sizeof(gpt_header_buffer), &gpt_header_buffer);
|
||||
if (EFI_ERROR(r))
|
||||
continue;
|
||||
|
||||
/* Some superficial validation of the GPT header */
|
||||
if (CompareMem(&gpt_header_buffer.gpt_header.Header.Signature, "EFI PART", sizeof(gpt_header_buffer.gpt_header.Header.Signature)) != 0)
|
||||
continue;
|
||||
|
||||
if (gpt_header_buffer.gpt_header.Header.HeaderSize < 92 || gpt_header_buffer.gpt_header.Header.HeaderSize > 512)
|
||||
continue;
|
||||
|
||||
if (gpt_header_buffer.gpt_header.Header.Revision != 0x00010000U)
|
||||
continue;
|
||||
|
||||
/* Calculate CRC check */
|
||||
c = ~crc32_exclude_offset((UINT32) -1, (const UINT8*) &gpt_header_buffer, gpt_header_buffer.gpt_header.Header.HeaderSize,
|
||||
OFFSETOF(EFI_PARTITION_TABLE_HEADER, Header.CRC32), sizeof(gpt_header_buffer.gpt_header.Header.CRC32));
|
||||
if (c != gpt_header_buffer.gpt_header.Header.CRC32)
|
||||
continue;
|
||||
|
||||
if (gpt_header_buffer.gpt_header.MyLBA != where)
|
||||
continue;
|
||||
|
||||
if (gpt_header_buffer.gpt_header.SizeOfPartitionEntry < sizeof(EFI_PARTITION_ENTRY))
|
||||
continue;
|
||||
|
||||
if (gpt_header_buffer.gpt_header.NumberOfPartitionEntries <= 0 || gpt_header_buffer.gpt_header.NumberOfPartitionEntries > 1024)
|
||||
continue;
|
||||
|
||||
/* Now load the GPT entry table */
|
||||
sz = ((gpt_header_buffer.gpt_header.SizeOfPartitionEntry * gpt_header_buffer.gpt_header.NumberOfPartitionEntries + 511) / 512) * 512;
|
||||
entries = AllocatePool(sz);
|
||||
|
||||
r = uefi_call_wrapper(block_io->ReadBlocks, 5, block_io, block_io->Media->MediaId, gpt_header_buffer.gpt_header.PartitionEntryLBA, sz, entries);
|
||||
if (EFI_ERROR(r))
|
||||
continue;
|
||||
|
||||
/* Calculate CRC of entries array, too */
|
||||
c = ~crc32((UINT32) -1, entries, sz);
|
||||
if (c != gpt_header_buffer.gpt_header.PartitionEntryArrayCRC32)
|
||||
continue;
|
||||
|
||||
for (i = 0; i < gpt_header_buffer.gpt_header.NumberOfPartitionEntries; i++) {
|
||||
EFI_PARTITION_ENTRY *entry;
|
||||
|
||||
entry = (EFI_PARTITION_ENTRY*) ((UINT8*) entries + gpt_header_buffer.gpt_header.SizeOfPartitionEntry * i);
|
||||
|
||||
if (CompareMem(&entry->PartitionTypeGUID, xbootldr_guid, 16) == 0) {
|
||||
UINT64 end;
|
||||
|
||||
/* Let's use memcpy(), in case the structs are not aligned (they really should be though) */
|
||||
CopyMem(&found_partition_start, &entry->StartingLBA, sizeof(found_partition_start));
|
||||
CopyMem(&end, &entry->EndingLBA, sizeof(end));
|
||||
|
||||
if (end < found_partition_start) /* Bogus? */
|
||||
continue;
|
||||
|
||||
found_partition_size = end - found_partition_start + 1;
|
||||
CopyMem(found_partition_signature, &entry->UniquePartitionGUID, sizeof(found_partition_signature));
|
||||
|
||||
found_partition_number = i + 1;
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
|
||||
break; /* This GPT was fully valid, but we didn't find what we are looking for. This
|
||||
* means there's no reason to check the second copy of the GPT header */
|
||||
}
|
||||
}
|
||||
|
||||
return; /* Not found */
|
||||
|
||||
found:
|
||||
copy = DuplicateDevicePath(partition_path);
|
||||
|
||||
/* Patch in the data we found */
|
||||
for (node = copy; !IsDevicePathEnd(node); node = NextDevicePathNode(node)) {
|
||||
HARDDRIVE_DEVICE_PATH *hd;
|
||||
|
||||
if (DevicePathType(node) != MEDIA_DEVICE_PATH)
|
||||
continue;
|
||||
|
||||
if (DevicePathSubType(node) != MEDIA_HARDDRIVE_DP)
|
||||
continue;
|
||||
|
||||
hd = (HARDDRIVE_DEVICE_PATH*) node;
|
||||
hd->PartitionNumber = found_partition_number;
|
||||
hd->PartitionStart = found_partition_start;
|
||||
hd->PartitionSize = found_partition_size;
|
||||
CopyMem(hd->Signature, found_partition_signature, sizeof(hd->Signature));
|
||||
hd->MBRType = MBR_TYPE_EFI_PARTITION_TABLE_HEADER;
|
||||
hd->SignatureType = SIGNATURE_TYPE_GUID;
|
||||
}
|
||||
|
||||
r = uefi_call_wrapper(BS->LocateDevicePath, 3, &BlockIoProtocol, ©, &new_device);
|
||||
if (EFI_ERROR(r))
|
||||
return;
|
||||
|
||||
root_dir = LibOpenRoot(new_device);
|
||||
if (!root_dir)
|
||||
return;
|
||||
|
||||
config_entry_add_linux(config, new_device, root_dir);
|
||||
config_load_entries(config, new_device, root_dir, NULL);
|
||||
}
|
||||
|
||||
static EFI_STATUS image_start(
|
||||
EFI_HANDLE parent_image,
|
||||
const Config *config,
|
||||
@@ -2121,7 +2310,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
|
||||
|
||||
root_dir = LibOpenRoot(loaded_image->DeviceHandle);
|
||||
if (!root_dir) {
|
||||
Print(L"Unable to open root directory: %r ", err);
|
||||
Print(L"Unable to open root directory.");
|
||||
uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
|
||||
return EFI_LOAD_ERROR;
|
||||
}
|
||||
@@ -2142,11 +2331,14 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
|
||||
config_load_defaults(&config, root_dir);
|
||||
|
||||
/* scan /EFI/Linux/ directory */
|
||||
config_entry_add_linux(&config, loaded_image, root_dir);
|
||||
config_entry_add_linux(&config, loaded_image->DeviceHandle, root_dir);
|
||||
|
||||
/* scan /loader/entries/\*.conf files */
|
||||
config_load_entries(&config, loaded_image->DeviceHandle, root_dir, loaded_image_path);
|
||||
|
||||
/* Similar, but on any XBOOTLDR partition */
|
||||
config_load_xbootldr(&config, loaded_image->DeviceHandle);
|
||||
|
||||
/* sort entries after version number */
|
||||
config_sort_entries(&config);
|
||||
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
/* This is copied from util-linux, which in turn copied in the version from Gary S. Brown */
|
||||
|
||||
/*
|
||||
* COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or
|
||||
* code or tables extracted from it, as desired without restriction.
|
||||
*
|
||||
* First, the polynomial itself and its table of feedback terms. The
|
||||
* polynomial is
|
||||
* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0
|
||||
*
|
||||
* Note that we take it "backwards" and put the highest-order term in
|
||||
* the lowest-order bit. The X^32 term is "implied"; the LSB is the
|
||||
* X^31 term, etc. The X^0 term (usually shown as "+1") results in
|
||||
* the MSB being 1.
|
||||
*
|
||||
* Note that the usual hardware shift register implementation, which
|
||||
* is what we're using (we're merely optimizing it by doing eight-bit
|
||||
* chunks at a time) shifts bits into the lowest-order term. In our
|
||||
* implementation, that means shifting towards the right. Why do we
|
||||
* do it this way? Because the calculated CRC must be transmitted in
|
||||
* order from highest-order term to lowest-order term. UARTs transmit
|
||||
* characters in order from LSB to MSB. By storing the CRC this way,
|
||||
* we hand it to the UART in the order low-byte to high-byte; the UART
|
||||
* sends each low-bit to high-bit; and the result is transmission bit
|
||||
* by bit from highest- to lowest-order term without requiring any bit
|
||||
* shuffling on our part. Reception works similarly.
|
||||
*
|
||||
* The feedback terms table consists of 256, 32-bit entries. Notes
|
||||
*
|
||||
* The table can be generated at runtime if desired; code to do so
|
||||
* is shown later. It might not be obvious, but the feedback
|
||||
* terms simply represent the results of eight shift/xor opera-
|
||||
* tions for all combinations of data and CRC register values.
|
||||
*
|
||||
* The values must be right-shifted by eight bits by the "updcrc"
|
||||
* logic; the shift must be unsigned (bring in zeroes). On some
|
||||
* hardware you could probably optimize the shift in assembler by
|
||||
* using byte-swap instructions.
|
||||
* polynomial $edb88320
|
||||
*
|
||||
*/
|
||||
|
||||
#include "crc32.h"
|
||||
|
||||
static const UINT32 crc32_tab[] = {
|
||||
0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
|
||||
0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
|
||||
0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
|
||||
0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
|
||||
0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
|
||||
0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
|
||||
0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
|
||||
0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
|
||||
0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
|
||||
0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
|
||||
0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
|
||||
0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
|
||||
0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
|
||||
0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
|
||||
0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
|
||||
0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
|
||||
0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
|
||||
0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
|
||||
0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
|
||||
0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
|
||||
0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
|
||||
0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
|
||||
0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
|
||||
0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
|
||||
0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
|
||||
0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
|
||||
0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
|
||||
0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
|
||||
0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
|
||||
0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
|
||||
0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
|
||||
0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
|
||||
0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
|
||||
0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
|
||||
0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
|
||||
0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
|
||||
0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
|
||||
0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
|
||||
0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
|
||||
0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
|
||||
0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
|
||||
0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
|
||||
0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
|
||||
0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
|
||||
0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
|
||||
0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
|
||||
0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
|
||||
0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
|
||||
0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
|
||||
0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
|
||||
0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
|
||||
0x2d02ef8dL
|
||||
};
|
||||
|
||||
static inline UINT32 crc32_add_char(UINT32 crc, UINT8 c) {
|
||||
return crc32_tab[(crc ^ c) & 0xff] ^ (crc >> 8);
|
||||
}
|
||||
|
||||
/*
|
||||
* This a generic crc32() function, it takes seed as an argument,
|
||||
* and does __not__ xor at the end. Then individual users can do
|
||||
* whatever they need.
|
||||
*/
|
||||
UINT32 crc32(UINT32 seed, const VOID *buf, UINTN len) {
|
||||
const UINT8 *p = buf;
|
||||
UINT32 crc = seed;
|
||||
|
||||
while (len > 0) {
|
||||
crc = crc32_add_char(crc, *p++);
|
||||
len--;
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
UINT32 crc32_exclude_offset(
|
||||
UINT32 seed,
|
||||
const VOID *buf,
|
||||
UINTN len,
|
||||
UINTN exclude_off,
|
||||
UINTN exclude_len) {
|
||||
|
||||
const UINT8 *p = buf;
|
||||
UINT32 crc = seed;
|
||||
UINTN i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
UINT8 x = *p++;
|
||||
|
||||
if (i >= exclude_off && i < exclude_off + exclude_len)
|
||||
x = 0;
|
||||
|
||||
crc = crc32_add_char(crc, x);
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||
#pragma once
|
||||
|
||||
#include <efi.h>
|
||||
#include <efilib.h>
|
||||
|
||||
UINT32 crc32(UINT32 seed, const VOID *buf, UINTN len);
|
||||
UINT32 crc32_exclude_offset(UINT32 seed, const VOID *buf, UINTN len, UINTN exclude_off, UINTN exclude_len);
|
||||
@@ -2,14 +2,15 @@
|
||||
|
||||
efi_headers = files('''
|
||||
console.h
|
||||
crc32.h
|
||||
disk.h
|
||||
graphics.h
|
||||
linux.h
|
||||
measure.h
|
||||
pe.h
|
||||
shim.h
|
||||
splash.h
|
||||
util.h
|
||||
shim.h
|
||||
'''.split())
|
||||
|
||||
common_sources = '''
|
||||
@@ -24,6 +25,7 @@ systemd_boot_sources = '''
|
||||
boot.c
|
||||
console.c
|
||||
shim.c
|
||||
crc32.c
|
||||
'''.split()
|
||||
|
||||
stub_sources = '''
|
||||
|
||||
+8
-7
@@ -87,12 +87,13 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
|
||||
#endif
|
||||
}
|
||||
|
||||
/* export the device path this image is started from */
|
||||
if (disk_get_part_uuid(loaded_image->DeviceHandle, uuid) == EFI_SUCCESS)
|
||||
efivar_set(L"LoaderDevicePartUUID", uuid, FALSE);
|
||||
/* Export the device path this image is started from, if it's not set yet */
|
||||
if (efivar_get_raw(&loader_guid, L"LoaderDevicePartUUID", NULL, NULL) != EFI_SUCCESS)
|
||||
if (disk_get_part_uuid(loaded_image->DeviceHandle, uuid) == EFI_SUCCESS)
|
||||
efivar_set(L"LoaderDevicePartUUID", uuid, FALSE);
|
||||
|
||||
/* if LoaderImageIdentifier is not set, assume the image with this stub was loaded directly from UEFI */
|
||||
if (efivar_get_raw(&global_guid, L"LoaderImageIdentifier", &b, &size) != EFI_SUCCESS) {
|
||||
if (efivar_get_raw(&loader_guid, L"LoaderImageIdentifier", NULL, NULL) != EFI_SUCCESS) {
|
||||
_cleanup_freepool_ CHAR16 *s;
|
||||
|
||||
s = DevicePathToStr(loaded_image->FilePath);
|
||||
@@ -100,7 +101,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
|
||||
}
|
||||
|
||||
/* if LoaderFirmwareInfo is not set, let's set it */
|
||||
if (efivar_get_raw(&global_guid, L"LoaderFirmwareInfo", &b, &size) != EFI_SUCCESS) {
|
||||
if (efivar_get_raw(&loader_guid, L"LoaderFirmwareInfo", NULL, NULL) != EFI_SUCCESS) {
|
||||
_cleanup_freepool_ CHAR16 *s;
|
||||
|
||||
s = PoolPrint(L"%s %d.%02d", ST->FirmwareVendor, ST->FirmwareRevision >> 16, ST->FirmwareRevision & 0xffff);
|
||||
@@ -108,7 +109,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
|
||||
}
|
||||
|
||||
/* ditto for LoaderFirmwareType */
|
||||
if (efivar_get_raw(&global_guid, L"LoaderFirmwareType", &b, &size) != EFI_SUCCESS) {
|
||||
if (efivar_get_raw(&loader_guid, L"LoaderFirmwareType", NULL, NULL) != EFI_SUCCESS) {
|
||||
_cleanup_freepool_ CHAR16 *s;
|
||||
|
||||
s = PoolPrint(L"UEFI %d.%02d", ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff);
|
||||
@@ -116,7 +117,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
|
||||
}
|
||||
|
||||
/* add StubInfo */
|
||||
if (efivar_get_raw(&global_guid, L"StubInfo", &b, &size) != EFI_SUCCESS)
|
||||
if (efivar_get_raw(&loader_guid, L"StubInfo", NULL, NULL) != EFI_SUCCESS)
|
||||
efivar_set(L"StubInfo", L"systemd-stub " GIT_VERSION, FALSE);
|
||||
|
||||
if (szs[3] > 0)
|
||||
|
||||
+8
-3
@@ -117,6 +117,9 @@ EFI_STATUS efivar_get(const CHAR16 *name, CHAR16 **value) {
|
||||
if ((size % 2) != 0)
|
||||
return EFI_INVALID_PARAMETER;
|
||||
|
||||
if (!value)
|
||||
return EFI_SUCCESS;
|
||||
|
||||
/* Return buffer directly if it happens to be NUL terminated already */
|
||||
if (size >= 2 && buf[size-2] == 0 && buf[size-1] == 0) {
|
||||
*value = (CHAR16*) buf;
|
||||
@@ -141,7 +144,7 @@ EFI_STATUS efivar_get_int(const CHAR16 *name, UINTN *i) {
|
||||
EFI_STATUS err;
|
||||
|
||||
err = efivar_get(name, &val);
|
||||
if (!EFI_ERROR(err))
|
||||
if (!EFI_ERROR(err) && i)
|
||||
*i = Atoi(val);
|
||||
|
||||
return err;
|
||||
@@ -159,8 +162,10 @@ EFI_STATUS efivar_get_raw(const EFI_GUID *vendor, const CHAR16 *name, CHAR8 **bu
|
||||
|
||||
err = uefi_call_wrapper(RT->GetVariable, 5, (CHAR16*) name, (EFI_GUID *)vendor, NULL, &l, buf);
|
||||
if (!EFI_ERROR(err)) {
|
||||
*buffer = buf;
|
||||
buf = NULL;
|
||||
|
||||
if (buffer)
|
||||
*buffer = TAKE_PTR(buf);
|
||||
|
||||
if (size)
|
||||
*size = l;
|
||||
}
|
||||
|
||||
@@ -55,3 +55,10 @@ const EFI_GUID loader_guid;
|
||||
|
||||
#define UINTN_MAX (~(UINTN)0)
|
||||
#define INTN_MAX ((INTN)(UINTN_MAX>>1))
|
||||
|
||||
#define TAKE_PTR(ptr) \
|
||||
({ \
|
||||
typeof(ptr) _ptr_ = (ptr); \
|
||||
(ptr) = NULL; \
|
||||
_ptr_; \
|
||||
})
|
||||
|
||||
@@ -322,7 +322,6 @@ static int add_swap(const char *path) {
|
||||
return generator_add_symlink(arg_dest, SPECIAL_SWAP_TARGET, "wants", name);
|
||||
}
|
||||
|
||||
#if ENABLE_EFI
|
||||
static int add_automount(
|
||||
const char *id,
|
||||
const char *what,
|
||||
@@ -384,8 +383,43 @@ static int add_automount(
|
||||
return generator_add_symlink(arg_dest, SPECIAL_LOCAL_FS_TARGET, "wants", unit);
|
||||
}
|
||||
|
||||
static int add_esp(DissectedPartition *p) {
|
||||
const char *esp;
|
||||
static int add_xbootldr(DissectedPartition *p) {
|
||||
int r;
|
||||
|
||||
assert(p);
|
||||
|
||||
if (in_initrd()) {
|
||||
log_debug("In initrd, ignoring the XBOOTLDR partition.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = fstab_is_mount_point("/boot");
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse fstab: %m");
|
||||
if (r > 0) {
|
||||
log_debug("/boot specified in fstab, ignoring XBOOTLDR partition.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = path_is_busy("/boot");
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r > 0)
|
||||
return 0;
|
||||
|
||||
return add_automount("boot",
|
||||
p->node,
|
||||
"/boot",
|
||||
p->fstype,
|
||||
true,
|
||||
"umask=0077",
|
||||
"Boot Loader Partition",
|
||||
120 * USEC_PER_SEC);
|
||||
}
|
||||
|
||||
#if ENABLE_EFI
|
||||
static int add_esp(DissectedPartition *p, bool has_xbootldr) {
|
||||
const char *esp_path = NULL, *id = NULL;
|
||||
int r;
|
||||
|
||||
assert(p);
|
||||
@@ -395,21 +429,37 @@ static int add_esp(DissectedPartition *p) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If /efi exists we'll use that. Otherwise we'll use /boot, as that's usually the better choice */
|
||||
esp = access("/efi/", F_OK) >= 0 ? "/efi" : "/boot";
|
||||
/* If /efi exists we'll use that. Otherwise we'll use /boot, as that's usually the better choice, but
|
||||
* only if there's no explicit XBOOTLDR partition around. */
|
||||
if (access("/efi", F_OK) < 0) {
|
||||
if (errno != ENOENT)
|
||||
return log_error_errno(errno, "Failed to determine whether /efi exists: %m");
|
||||
|
||||
/* Use /boot as fallback, but only if there's no XBOOTLDR partition */
|
||||
if (!has_xbootldr) {
|
||||
esp_path = "/boot";
|
||||
id = "boot";
|
||||
}
|
||||
}
|
||||
if (!esp_path)
|
||||
esp_path = "/efi";
|
||||
if (!id)
|
||||
id = "efi";
|
||||
|
||||
/* We create an .automount which is not overridden by the .mount from the fstab generator. */
|
||||
r = fstab_is_mount_point(esp);
|
||||
r = fstab_is_mount_point(esp_path);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse fstab: %m");
|
||||
if (r > 0) {
|
||||
log_debug("%s specified in fstab, ignoring.", esp);
|
||||
log_debug("%s specified in fstab, ignoring.", esp_path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = path_is_busy(esp);
|
||||
if (r != 0)
|
||||
return r < 0 ? r : 0;
|
||||
r = path_is_busy(esp_path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r > 0)
|
||||
return 0;
|
||||
|
||||
if (is_efi_boot()) {
|
||||
sd_id128_t loader_uuid;
|
||||
@@ -425,15 +475,15 @@ static int add_esp(DissectedPartition *p) {
|
||||
return log_error_errno(r, "Failed to read ESP partition UUID: %m");
|
||||
|
||||
if (!sd_id128_equal(p->uuid, loader_uuid)) {
|
||||
log_debug("Partition for %s does not appear to be the partition we are booted from.", esp);
|
||||
log_debug("Partition for %s does not appear to be the partition we are booted from.", p->node);
|
||||
return 0;
|
||||
}
|
||||
} else
|
||||
log_debug("Not an EFI boot, skipping ESP check.");
|
||||
|
||||
return add_automount("boot",
|
||||
return add_automount(id,
|
||||
p->node,
|
||||
esp,
|
||||
esp_path,
|
||||
p->fstype,
|
||||
true,
|
||||
"umask=0077",
|
||||
@@ -441,7 +491,7 @@ static int add_esp(DissectedPartition *p) {
|
||||
120 * USEC_PER_SEC);
|
||||
}
|
||||
#else
|
||||
static int add_esp(DissectedPartition *p) {
|
||||
static int add_esp(DissectedPartition *p, bool has_xbootldr) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@@ -569,8 +619,14 @@ static int enumerate_partitions(dev_t devnum) {
|
||||
r = k;
|
||||
}
|
||||
|
||||
if (m->partitions[PARTITION_XBOOTLDR].found) {
|
||||
k = add_xbootldr(m->partitions + PARTITION_XBOOTLDR);
|
||||
if (k < 0)
|
||||
r = k;
|
||||
}
|
||||
|
||||
if (m->partitions[PARTITION_ESP].found) {
|
||||
k = add_esp(m->partitions + PARTITION_ESP);
|
||||
k = add_esp(m->partitions + PARTITION_ESP, m->partitions[PARTITION_XBOOTLDR].found);
|
||||
if (k < 0)
|
||||
r = k;
|
||||
}
|
||||
|
||||
+799
-135
File diff suppressed because it is too large
Load Diff
@@ -10,7 +10,8 @@
|
||||
|
||||
typedef struct BootEntry {
|
||||
char *id; /* This is the file basename without extension */
|
||||
char *path; /* This is the full path to the file */
|
||||
char *path; /* This is the full path to the drop-in file */
|
||||
char *root; /* The root path in which the drop-in was found, i.e. to which 'kernel', 'efi' and 'initrd' are relative */
|
||||
char *title;
|
||||
char *show_title;
|
||||
char *version;
|
||||
@@ -40,12 +41,13 @@ typedef struct BootConfig {
|
||||
} BootConfig;
|
||||
|
||||
void boot_config_free(BootConfig *config);
|
||||
int boot_entries_load_config(const char *esp_path, BootConfig *config);
|
||||
int boot_entries_load_config(const char *esp_path, const char *xbootldr_path, BootConfig *config);
|
||||
|
||||
static inline const char* boot_entry_title(const BootEntry *entry) {
|
||||
return entry->show_title ?: entry->title ?: entry->id;
|
||||
}
|
||||
|
||||
int find_esp_and_warn(const char *path, bool unprivileged_mode, char **ret_path, uint32_t *ret_part, uint64_t *ret_pstart, uint64_t *ret_psize, sd_id128_t *ret_uuid);
|
||||
int find_xbootldr_and_warn(const char *path, bool unprivileged_mode, char **ret_path,sd_id128_t *ret_uuid);
|
||||
|
||||
int find_default_boot_entry(const char *esp_path, char **esp_where, BootConfig *config, const BootEntry **e);
|
||||
int find_default_boot_entry(const char *esp_path, const char *xbootldr_path, BootConfig *config, const BootEntry **e);
|
||||
|
||||
+76
-28
@@ -343,10 +343,8 @@ int dissect_image(
|
||||
|
||||
errno = 0;
|
||||
r = blkid_do_safeprobe(b);
|
||||
if (IN_SET(r, -2, 1)) {
|
||||
log_debug("Failed to identify any partition table.");
|
||||
return -ENOPKG;
|
||||
}
|
||||
if (IN_SET(r, -2, 1))
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(ENOPKG), "Failed to identify any partition table.");
|
||||
if (r != 0)
|
||||
return -errno ?: -EIO;
|
||||
|
||||
@@ -497,6 +495,14 @@ int dissect_image(
|
||||
|
||||
designator = PARTITION_ESP;
|
||||
fstype = "vfat";
|
||||
|
||||
} else if (sd_id128_equal(type_id, GPT_XBOOTLDR)) {
|
||||
|
||||
if (pflags & GPT_FLAG_NO_AUTO)
|
||||
continue;
|
||||
|
||||
designator = PARTITION_XBOOTLDR;
|
||||
rw = !(pflags & GPT_FLAG_READ_ONLY);
|
||||
}
|
||||
#ifdef GPT_ROOT_NATIVE
|
||||
else if (sd_id128_equal(type_id, GPT_ROOT_NATIVE)) {
|
||||
@@ -612,21 +618,53 @@ int dissect_image(
|
||||
|
||||
} else if (is_mbr) {
|
||||
|
||||
if (pflags != 0x80) /* Bootable flag */
|
||||
continue;
|
||||
switch (blkid_partition_get_type(pp)) {
|
||||
|
||||
if (blkid_partition_get_type(pp) != 0x83) /* Linux partition */
|
||||
continue;
|
||||
case 0x83: /* Linux partition */
|
||||
|
||||
if (generic_node)
|
||||
multiple_generic = true;
|
||||
else {
|
||||
generic_nr = nr;
|
||||
generic_rw = true;
|
||||
generic_node = strdup(node);
|
||||
if (!generic_node)
|
||||
if (pflags != 0x80) /* Bootable flag */
|
||||
continue;
|
||||
|
||||
if (generic_node)
|
||||
multiple_generic = true;
|
||||
else {
|
||||
generic_nr = nr;
|
||||
generic_rw = true;
|
||||
generic_node = strdup(node);
|
||||
if (!generic_node)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 0xEA: { /* Boot Loader Spec extended $BOOT partition */
|
||||
_cleanup_free_ char *n = NULL;
|
||||
sd_id128_t id = SD_ID128_NULL;
|
||||
const char *sid;
|
||||
|
||||
/* First one wins */
|
||||
if (m->partitions[PARTITION_XBOOTLDR].found)
|
||||
continue;
|
||||
|
||||
sid = blkid_partition_get_uuid(pp);
|
||||
if (sid)
|
||||
(void) sd_id128_from_string(sid, &id);
|
||||
|
||||
n = strdup(node);
|
||||
if (!n)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
m->partitions[PARTITION_XBOOTLDR] = (DissectedPartition) {
|
||||
.found = true,
|
||||
.partno = nr,
|
||||
.rw = true,
|
||||
.architecture = _ARCHITECTURE_INVALID,
|
||||
.node = TAKE_PTR(n),
|
||||
.uuid = id,
|
||||
};
|
||||
|
||||
break;
|
||||
}}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -819,11 +857,15 @@ static int mount_partition(
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return mount_verbose(LOG_DEBUG, node, p, fstype, MS_NODEV|(rw ? 0 : MS_RDONLY), options);
|
||||
r = mount_verbose(LOG_DEBUG, node, p, fstype, MS_NODEV|(rw ? 0 : MS_RDONLY), options);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dissected_image_mount(DissectedImage *m, const char *where, uid_t uid_shift, DissectImageFlags flags) {
|
||||
int r;
|
||||
int r, boot_mounted;
|
||||
|
||||
assert(m);
|
||||
assert(where);
|
||||
@@ -856,21 +898,26 @@ int dissected_image_mount(DissectedImage *m, const char *where, uid_t uid_shift,
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
boot_mounted = mount_partition(m->partitions + PARTITION_XBOOTLDR, where, "/boot", uid_shift, flags);
|
||||
if (boot_mounted < 0)
|
||||
return boot_mounted;
|
||||
|
||||
if (m->partitions[PARTITION_ESP].found) {
|
||||
const char *mp;
|
||||
/* Mount the ESP to /efi if it exists. If it doesn't exist, use /boot instead, but only if it
|
||||
* exists and is empty, and we didn't already mount the XBOOTLDR partition into it. */
|
||||
|
||||
/* Mount the ESP to /efi if it exists and is empty. If it doesn't exist, use /boot instead. */
|
||||
r = chase_symlinks("/efi", where, CHASE_PREFIX_ROOT, NULL);
|
||||
if (r >= 0) {
|
||||
r = mount_partition(m->partitions + PARTITION_ESP, where, "/efi", uid_shift, flags);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
FOREACH_STRING(mp, "/efi", "/boot") {
|
||||
} else if (boot_mounted <= 0) {
|
||||
_cleanup_free_ char *p = NULL;
|
||||
|
||||
r = chase_symlinks(mp, where, CHASE_PREFIX_ROOT, &p);
|
||||
if (r < 0)
|
||||
continue;
|
||||
|
||||
r = dir_is_empty(p);
|
||||
if (r > 0) {
|
||||
r = mount_partition(m->partitions + PARTITION_ESP, where, mp, uid_shift, flags);
|
||||
r = chase_symlinks("/boot", where, CHASE_PREFIX_ROOT, &p);
|
||||
if (r >= 0 && dir_is_empty(p) > 0) {
|
||||
r = mount_partition(m->partitions + PARTITION_ESP, where, "/boot", uid_shift, flags);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
@@ -1499,6 +1546,7 @@ static const char *const partition_designator_table[] = {
|
||||
[PARTITION_HOME] = "home",
|
||||
[PARTITION_SRV] = "srv",
|
||||
[PARTITION_ESP] = "esp",
|
||||
[PARTITION_XBOOTLDR] = "xbootldr",
|
||||
[PARTITION_SWAP] = "swap",
|
||||
[PARTITION_ROOT_VERITY] = "root-verity",
|
||||
[PARTITION_ROOT_SECONDARY_VERITY] = "root-secondary-verity",
|
||||
|
||||
@@ -29,6 +29,7 @@ enum {
|
||||
PARTITION_HOME,
|
||||
PARTITION_SRV,
|
||||
PARTITION_ESP,
|
||||
PARTITION_XBOOTLDR,
|
||||
PARTITION_SWAP,
|
||||
PARTITION_ROOT_VERITY, /* verity data for the PARTITION_ROOT partition */
|
||||
PARTITION_ROOT_SECONDARY_VERITY, /* verity data for the PARTITION_ROOT_SECONDARY partition */
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#define GPT_ROOT_ARM_64 SD_ID128_MAKE(b9,21,b0,45,1d,f0,41,c3,af,44,4c,6f,28,0d,3f,ae)
|
||||
#define GPT_ROOT_IA64 SD_ID128_MAKE(99,3d,8d,3d,f8,0e,42,25,85,5a,9d,af,8e,d7,ea,97)
|
||||
#define GPT_ESP SD_ID128_MAKE(c1,2a,73,28,f8,1f,11,d2,ba,4b,00,a0,c9,3e,c9,3b)
|
||||
#define GPT_XBOOTLDR SD_ID128_MAKE(bc,13,c2,ff,59,e6,42,62,a3,52,b2,75,fd,6f,71,72)
|
||||
#define GPT_SWAP SD_ID128_MAKE(06,57,fd,6d,a4,ab,43,c4,84,e5,09,33,c8,4b,4f,4f)
|
||||
#define GPT_HOME SD_ID128_MAKE(93,3a,c7,e1,2e,b4,4f,13,b8,44,0e,14,e2,ae,f9,15)
|
||||
#define GPT_SRV SD_ID128_MAKE(3b,8f,84,25,20,e0,4f,3b,90,7f,1a,25,a7,6f,98,e8)
|
||||
|
||||
@@ -117,6 +117,7 @@ shared_sources = files('''
|
||||
pager.h
|
||||
path-lookup.c
|
||||
path-lookup.h
|
||||
pe-header.h
|
||||
pretty-print.c
|
||||
pretty-print.h
|
||||
ptyfwd.c
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
#pragma once
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "macro.h"
|
||||
#include "sparse-endian.h"
|
||||
|
||||
struct DosFileHeader {
|
||||
uint8_t Magic[2];
|
||||
le16_t LastSize;
|
||||
le16_t nBlocks;
|
||||
le16_t nReloc;
|
||||
le16_t HdrSize;
|
||||
le16_t MinAlloc;
|
||||
le16_t MaxAlloc;
|
||||
le16_t ss;
|
||||
le16_t sp;
|
||||
le16_t Checksum;
|
||||
le16_t ip;
|
||||
le16_t cs;
|
||||
le16_t RelocPos;
|
||||
le16_t nOverlay;
|
||||
le16_t reserved[4];
|
||||
le16_t OEMId;
|
||||
le16_t OEMInfo;
|
||||
le16_t reserved2[10];
|
||||
le32_t ExeHeader;
|
||||
} _packed_;
|
||||
|
||||
#define PE_HEADER_MACHINE_I386 0x014cU
|
||||
#define PE_HEADER_MACHINE_X64 0x8664U
|
||||
|
||||
struct PeFileHeader {
|
||||
le16_t Machine;
|
||||
le16_t NumberOfSections;
|
||||
le32_t TimeDateStamp;
|
||||
le32_t PointerToSymbolTable;
|
||||
le32_t NumberOfSymbols;
|
||||
le16_t SizeOfOptionalHeader;
|
||||
le16_t Characteristics;
|
||||
} _packed_;
|
||||
|
||||
struct PeHeader {
|
||||
uint8_t Magic[4];
|
||||
struct PeFileHeader FileHeader;
|
||||
} _packed_;
|
||||
|
||||
struct PeSectionHeader {
|
||||
uint8_t Name[8];
|
||||
le32_t VirtualSize;
|
||||
le32_t VirtualAddress;
|
||||
le32_t SizeOfRawData;
|
||||
le32_t PointerToRawData;
|
||||
le32_t PointerToRelocations;
|
||||
le32_t PointerToLinenumbers;
|
||||
le16_t NumberOfRelocations;
|
||||
le16_t NumberOfLinenumbers;
|
||||
le32_t Characteristics;
|
||||
} _packed_;
|
||||
+14
-10
@@ -134,7 +134,6 @@ static const char *arg_kill_who = NULL;
|
||||
static int arg_signal = SIGTERM;
|
||||
static char *arg_root = NULL;
|
||||
static usec_t arg_when = 0;
|
||||
static char *arg_esp_path = NULL;
|
||||
static char *argv_cmdline = NULL;
|
||||
static enum action {
|
||||
ACTION_SYSTEMCTL,
|
||||
@@ -3519,7 +3518,7 @@ static int prepare_firmware_setup(void) {
|
||||
|
||||
static int load_kexec_kernel(void) {
|
||||
_cleanup_(boot_config_free) BootConfig config = {};
|
||||
_cleanup_free_ char *where = NULL, *kernel = NULL, *initrd = NULL, *options = NULL;
|
||||
_cleanup_free_ char *kernel = NULL, *initrd = NULL, *options = NULL;
|
||||
const BootEntry *e;
|
||||
pid_t pid;
|
||||
int r;
|
||||
@@ -3532,21 +3531,27 @@ static int load_kexec_kernel(void) {
|
||||
if (access(KEXEC, X_OK) < 0)
|
||||
return log_error_errno(errno, KEXEC" is not available: %m");
|
||||
|
||||
r = find_default_boot_entry(arg_esp_path, &where, &config, &e);
|
||||
r = find_default_boot_entry(NULL, NULL, &config, &e);
|
||||
if (r == -ENOKEY) /* find_default_boot_entry() doesn't warn about this case */
|
||||
return log_error_errno(r, "Cannot find the ESP partition mount point.");
|
||||
if (r < 0)
|
||||
/* But it logs about all these cases, hence don't log here again */
|
||||
return r;
|
||||
|
||||
if (strv_length(e->initrd) > 1) {
|
||||
log_error("Boot entry specifies multiple initrds, which is not supported currently.");
|
||||
return -EINVAL;
|
||||
if (strv_length(e->initrd) > 1)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Boot entry specifies multiple initrds, which is not supported currently.");
|
||||
|
||||
kernel = path_join(e->root, e->kernel);
|
||||
if (!kernel)
|
||||
return log_oom();
|
||||
|
||||
if (!strv_isempty(e->initrd)) {
|
||||
initrd = path_join(e->root, *e->initrd);
|
||||
if (!initrd)
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
kernel = path_join(where, e->kernel);
|
||||
if (!strv_isempty(e->initrd))
|
||||
initrd = path_join(where, *e->initrd);
|
||||
options = strv_join(e->options, " ");
|
||||
if (!options)
|
||||
return log_oom();
|
||||
@@ -8814,7 +8819,6 @@ finish:
|
||||
|
||||
strv_free(arg_wall);
|
||||
free(arg_root);
|
||||
free(arg_esp_path);
|
||||
|
||||
/* Note that we return r here, not 0, so that we can implement the LSB-like return codes */
|
||||
return r;
|
||||
|
||||
Reference in New Issue
Block a user