Merge pull request #11701 from poettering/discover-bls

sd-boot,bootctl,gpt-auto: support Extended Boot Loader Partition
This commit is contained in:
Lennart Poettering
2019-03-01 15:02:09 +01:00
committed by GitHub
27 changed files with 1936 additions and 496 deletions
-8
View File
@@ -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
+3 -3
View File
@@ -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
View File
@@ -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
View File
@@ -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>
+53 -35
View File
@@ -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,
+4
View File
@@ -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
+1 -1
View File
@@ -559,6 +559,6 @@ int write_env_file(const char *fname, char **l) {
r = -errno;
}
unlink(p);
(void) unlink(p);
return r;
}
+15
View File
@@ -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;
+2
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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, &copy, &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);
+142
View File
@@ -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;
}
+8
View File
@@ -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);
+3 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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;
}
+7
View File
@@ -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_; \
})
+71 -15
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+5 -3
View File
@@ -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
View File
@@ -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",
+1
View File
@@ -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 */
+1
View File
@@ -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)
+1
View File
@@ -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
+59
View File
@@ -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
View File
@@ -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;