summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2016-07-25 16:17:48 -0400
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2016-07-25 16:34:18 -0400
commite28973ee182434b59ff562c9b22823250c9fdb4c (patch)
treed4e147d1cab24575b3e5ce13d1571063b4da56c5
parent1a0b98c43797ce96e47b110a58f0b4c55f3256f5 (diff)
parent7ba25ab5616339a8340117b85cbecd061c52d8cc (diff)
Merge pull request #3757 from poettering/efi-search
-rw-r--r--man/bootctl.xml33
-rw-r--r--man/systemd-gpt-auto-generator.xml23
-rw-r--r--src/basic/string-util.c19
-rw-r--r--src/basic/string-util.h3
-rw-r--r--src/boot/bootctl.c448
-rw-r--r--src/gpt-auto-generator/gpt-auto-generator.c132
-rw-r--r--src/kernel-install/kernel-install11
-rw-r--r--src/nspawn/nspawn.c53
8 files changed, 438 insertions, 284 deletions
diff --git a/man/bootctl.xml b/man/bootctl.xml
index 6e835c037f..e2575a4751 100644
--- a/man/bootctl.xml
+++ b/man/bootctl.xml
@@ -47,16 +47,16 @@
<refsynopsisdiv>
<cmdsynopsis>
- <command>bootctl <arg choice="opt" rep="repeat">OPTIONS</arg>status</command>
+ <command>bootctl <arg choice="opt" rep="repeat">OPTIONS</arg> status</command>
</cmdsynopsis>
<cmdsynopsis>
- <command>bootctl <arg choice="opt" rep="repeat">OPTIONS</arg>update</command>
+ <command>bootctl <arg choice="opt" rep="repeat">OPTIONS</arg> update</command>
</cmdsynopsis>
<cmdsynopsis>
- <command>bootctl <arg choice="opt" rep="repeat">OPTIONS</arg>install</command>
+ <command>bootctl <arg choice="opt" rep="repeat">OPTIONS</arg> install</command>
</cmdsynopsis>
<cmdsynopsis>
- <command>bootctl <arg choice="opt" rep="repeat">OPTIONS</arg>remove</command>
+ <command>bootctl <arg choice="opt" rep="repeat">OPTIONS</arg> remove</command>
</cmdsynopsis>
</refsynopsisdiv>
@@ -71,19 +71,14 @@
currently installed versions of the boot loader binaries and
all current EFI boot variables.</para>
- <para><command>bootctl update</command> updates all installed
- versions of systemd-boot, if the current version is newer than the
- version installed in the EFI system partition. This also includes
- the EFI default/fallback loader at /EFI/BOOT/BOOT*.EFI. A
- systemd-boot entry in the EFI boot variables is created if there
- is no current entry. The created entry will be added to the end of
- the boot order list.</para>
+ <para><command>bootctl update</command> updates all installed versions of systemd-boot, if the current version is
+ newer than the version installed in the EFI system partition. This also includes the EFI default/fallback loader at
+ <filename>/EFI/BOOT/BOOT*.EFI</filename>. A systemd-boot entry in the EFI boot variables is created if there is no
+ current entry. The created entry will be added to the end of the boot order list.</para>
- <para><command>bootctl install</command> installs systemd-boot into
- the EFI system partition. A copy of systemd-boot will be stored as
- the EFI default/fallback loader at /EFI/BOOT/BOOT*.EFI. A systemd-boot
- entry in the EFI boot variables is created and added to the top
- of the boot order list.</para>
+ <para><command>bootctl install</command> installs systemd-boot into the EFI system partition. A copy of
+ systemd-boot will be stored as the EFI default/fallback loader at <filename>/EFI/BOOT/BOOT*.EFI</filename>. A
+ systemd-boot entry in the EFI boot variables is created and added to the top of the boot order list.</para>
<para><command>bootctl remove</command> removes all installed
versions of systemd-boot from the EFI system partition, and removes
@@ -101,8 +96,10 @@
<xi:include href="standard-options.xml" xpointer="help" />
<xi:include href="standard-options.xml" xpointer="version" />
<varlistentry>
- <term><option>--path</option></term>
- <listitem><para>Path to the EFI system partition. The default is /boot.</para></listitem>
+ <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>
</varlistentry>
<varlistentry>
diff --git a/man/systemd-gpt-auto-generator.xml b/man/systemd-gpt-auto-generator.xml
index e890c4dce2..d26206710f 100644
--- a/man/systemd-gpt-auto-generator.xml
+++ b/man/systemd-gpt-auto-generator.xml
@@ -137,6 +137,11 @@
<entry>Swap</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>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>
</tbody>
</tgroup>
</table>
@@ -150,16 +155,14 @@
<filename>/etc/crypttab</filename> with a different device mapper
device name.</para>
- <para>Mount and automount units for the EFI System Partition (ESP),
- mounting it to <filename>/boot</filename>, are generated on EFI
- systems where the boot loader communicates the used ESP to the operating
- system. Since this generator creates an automount unit, the mount will
- only be activated on-demand, when accessed. On systems where
- <filename>/boot</filename> 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> 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>, 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>When using this generator in conjunction with btrfs file
systems, make sure to set the correct default subvolumes on them,
diff --git a/src/basic/string-util.c b/src/basic/string-util.c
index 293a15f9c0..e9856b90d3 100644
--- a/src/basic/string-util.c
+++ b/src/basic/string-util.c
@@ -323,6 +323,14 @@ char ascii_tolower(char x) {
return x;
}
+char ascii_toupper(char x) {
+
+ if (x >= 'a' && x <= 'z')
+ return x - 'a' + 'A';
+
+ return x;
+}
+
char *ascii_strlower(char *t) {
char *p;
@@ -334,6 +342,17 @@ char *ascii_strlower(char *t) {
return t;
}
+char *ascii_strupper(char *t) {
+ char *p;
+
+ assert(t);
+
+ for (p = t; *p; p++)
+ *p = ascii_toupper(*p);
+
+ return t;
+}
+
char *ascii_strlower_n(char *t, size_t n) {
size_t i;
diff --git a/src/basic/string-util.h b/src/basic/string-util.h
index 1209e1e2e1..b75aba63c2 100644
--- a/src/basic/string-util.h
+++ b/src/basic/string-util.h
@@ -137,6 +137,9 @@ char ascii_tolower(char x);
char *ascii_strlower(char *s);
char *ascii_strlower_n(char *s, size_t n);
+char ascii_toupper(char x);
+char *ascii_strupper(char *s);
+
int ascii_strcasecmp_n(const char *a, const char *b, size_t n);
int ascii_strcasecmp_nn(const char *a, size_t n, const char *b, size_t m);
diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c
index 37fa049ecf..ff8c7a38dd 100644
--- a/src/boot/bootctl.c
+++ b/src/boot/bootctl.c
@@ -26,6 +26,7 @@
#include <ftw.h>
#include <getopt.h>
#include <limits.h>
+#include <linux/magic.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
@@ -42,22 +43,53 @@
#include "fd-util.h"
#include "fileio.h"
#include "locale-util.h"
+#include "parse-util.h"
#include "rm-rf.h"
#include "string-util.h"
+#include "strv.h"
+#include "umask-util.h"
#include "util.h"
+#include "verbs.h"
+#include "virt.h"
+#include "stat-util.h"
+
+static char *arg_path = NULL;
+static bool arg_touch_variables = true;
+
+static int verify_esp(
+ bool searching,
+ const char *p,
+ uint32_t *ret_part,
+ uint64_t *ret_pstart,
+ uint64_t *ret_psize,
+ sd_id128_t *ret_uuid) {
-static int verify_esp(const char *p, uint32_t *part, uint64_t *pstart, uint64_t *psize, sd_id128_t *uuid) {
- struct statfs sfs;
- struct stat st, st2;
- _cleanup_free_ char *t = NULL;
_cleanup_blkid_free_probe_ blkid_probe b = NULL;
- int r;
+ _cleanup_free_ char *t = NULL;
+ uint64_t pstart = 0, psize = 0;
+ struct stat st, st2;
const char *v, *t2;
+ struct statfs sfs;
+ sd_id128_t uuid = SD_ID128_NULL;
+ uint32_t part = 0;
+ int r;
+
+ assert(p);
+
+ if (statfs(p, &sfs) < 0) {
+
+ /* If we are searching for the mount point, don't generate a log message if we can't find the path */
+ if (errno == ENOENT && searching)
+ return -ENOENT;
- if (statfs(p, &sfs) < 0)
return log_error_errno(errno, "Failed to check file system type of \"%s\": %m", p);
+ }
+
+ if (!F_TYPE_EQUAL(sfs.f_type, MSDOS_SUPER_MAGIC)) {
+
+ if (searching)
+ return -EADDRNOTAVAIL;
- if (sfs.f_type != 0x4d44) {
log_error("File system \"%s\" is not a FAT EFI System Partition (ESP) file system.", p);
return -ENODEV;
}
@@ -80,6 +112,11 @@ static int verify_esp(const char *p, uint32_t *part, uint64_t *pstart, uint64_t
return -ENODEV;
}
+ /* In a container we don't have access to block devices, skip this part of the verification, we trust the
+ * container manager set everything up correctly on its own. */
+ if (detect_container() > 0)
+ goto finish;
+
r = asprintf(&t, "/dev/block/%u:%u", major(st.st_dev), minor(st.st_dev));
if (r < 0)
return log_oom();
@@ -117,7 +154,6 @@ static int verify_esp(const char *p, uint32_t *part, uint64_t *pstart, uint64_t
r = errno ? -errno : -EIO;
return log_error_errno(r, "Failed to probe file system type \"%s\": %m", p);
}
-
if (!streq(v, "vfat")) {
log_error("File system \"%s\" is not FAT.", p);
return -ENODEV;
@@ -129,7 +165,6 @@ static int verify_esp(const char *p, uint32_t *part, uint64_t *pstart, uint64_t
r = errno ? -errno : -EIO;
return log_error_errno(r, "Failed to probe partition scheme \"%s\": %m", p);
}
-
if (!streq(v, "gpt")) {
log_error("File system \"%s\" is not on a GPT partition table.", p);
return -ENODEV;
@@ -141,7 +176,6 @@ static int verify_esp(const char *p, uint32_t *part, uint64_t *pstart, uint64_t
r = errno ? -errno : -EIO;
return log_error_errno(r, "Failed to probe partition type UUID \"%s\": %m", p);
}
-
if (!streq(v, "c12a7328-f81f-11d2-ba4b-00a0c93ec93b")) {
log_error("File system \"%s\" has wrong type for an EFI System Partition (ESP).", p);
return -ENODEV;
@@ -153,8 +187,7 @@ static int verify_esp(const char *p, uint32_t *part, uint64_t *pstart, uint64_t
r = errno ? -errno : -EIO;
return log_error_errno(r, "Failed to probe partition entry UUID \"%s\": %m", p);
}
-
- r = sd_id128_from_string(v, uuid);
+ r = sd_id128_from_string(v, &uuid);
if (r < 0) {
log_error("Partition \"%s\" has invalid UUID \"%s\".", p, v);
return -EIO;
@@ -166,7 +199,9 @@ static int verify_esp(const char *p, uint32_t *part, uint64_t *pstart, uint64_t
r = errno ? -errno : -EIO;
return log_error_errno(r, "Failed to probe partition number \"%s\": m", p);
}
- *part = strtoul(v, NULL, 10);
+ r = safe_atou32(v, &part);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse PART_ENTRY_NUMBER field.");
errno = 0;
r = blkid_probe_lookup_value(b, "PART_ENTRY_OFFSET", &v, NULL);
@@ -174,7 +209,9 @@ static int verify_esp(const char *p, uint32_t *part, uint64_t *pstart, uint64_t
r = errno ? -errno : -EIO;
return log_error_errno(r, "Failed to probe partition offset \"%s\": %m", p);
}
- *pstart = strtoul(v, NULL, 10);
+ r = safe_atou64(v, &pstart);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse PART_ENTRY_OFFSET field.");
errno = 0;
r = blkid_probe_lookup_value(b, "PART_ENTRY_SIZE", &v, NULL);
@@ -182,11 +219,50 @@ static int verify_esp(const char *p, uint32_t *part, uint64_t *pstart, uint64_t
r = errno ? -errno : -EIO;
return log_error_errno(r, "Failed to probe partition size \"%s\": %m", p);
}
- *psize = strtoul(v, NULL, 10);
+ r = safe_atou64(v, &psize);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse PART_ENTRY_SIZE field.");
+
+finish:
+ if (ret_part)
+ *ret_part = part;
+ if (ret_pstart)
+ *ret_pstart = pstart;
+ if (ret_psize)
+ *ret_psize = psize;
+ if (ret_uuid)
+ *ret_uuid = uuid;
return 0;
}
+static int find_esp(uint32_t *part, uint64_t *pstart, uint64_t *psize, sd_id128_t *uuid) {
+ const char *path;
+ int r;
+
+ if (arg_path)
+ return verify_esp(false, arg_path, part, pstart, psize, uuid);
+
+ FOREACH_STRING(path, "/efi", "/boot", "/boot/efi") {
+
+ r = verify_esp(true, path, part, pstart, psize, uuid);
+ if (IN_SET(r, -ENOENT, -EADDRNOTAVAIL)) /* This one is not it */
+ continue;
+ if (r < 0)
+ return r;
+
+ arg_path = strdup(path);
+ if (!arg_path)
+ return log_oom();
+
+ log_info("Using EFI System Parition at %s.", path);
+ return 0;
+ }
+
+ log_error("Couldn't find EFI system partition. It is recommended to mount it to /boot. Alternatively, use --path= to specify path to mount point.");
+ return -ENOENT;
+}
+
/* search for "#### LoaderInfo: systemd-boot 218 ####" string inside the binary */
static int get_file_version(int fd, char **v) {
struct stat st;
@@ -199,14 +275,16 @@ static int get_file_version(int fd, char **v) {
assert(v);
if (fstat(fd, &st) < 0)
- return -errno;
+ return log_error_errno(errno, "Failed to stat EFI binary: %m");
- if (st.st_size < 27)
+ if (st.st_size < 27) {
+ *v = NULL;
return 0;
+ }
buf = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
if (buf == MAP_FAILED)
- return -errno;
+ return log_error_errno(errno, "Failed to memory map EFI binary: %m");
s = memmem(buf, st.st_size - 8, "#### LoaderInfo: ", 17);
if (!s)
@@ -228,7 +306,7 @@ static int get_file_version(int fd, char **v) {
r = 1;
finish:
- munmap(buf, st.st_size);
+ (void) munmap(buf, st.st_size);
*v = x;
return r;
}
@@ -338,9 +416,10 @@ static int status_variables(void) {
n_options = efi_get_boot_options(&options);
if (n_options == -ENOENT)
- return log_error_errno(ENOENT, "Failed to access EFI variables, efivarfs"
+ return log_error_errno(n_options,
+ "Failed to access EFI variables, efivarfs"
" needs to be available at /sys/firmware/efi/efivars/.");
- else if (n_options < 0)
+ if (n_options < 0)
return log_error_errno(n_options, "Failed to read EFI boot entries: %m");
n_order = efi_get_boot_order(&order);
@@ -360,11 +439,9 @@ static int status_variables(void) {
for (j = 0; j < n_order; j++)
if (options[i] == order[j])
- goto next;
+ continue;
print_efi_option(options[i], false);
- next:
- continue;
}
return 0;
@@ -523,15 +600,6 @@ error:
return r;
}
-static char* strupper(char *s) {
- char *p;
-
- for (p = s; *p; p++)
- *p = toupper(*p);
-
- return s;
-}
-
static int mkdir_one(const char *prefix, const char *suffix) {
char *p;
@@ -554,11 +622,11 @@ static const char *efi_subdirs[] = {
};
static int create_dirs(const char *esp_path) {
+ const char **i;
int r;
- unsigned i;
- for (i = 0; i < ELEMENTSOF(efi_subdirs); i++) {
- r = mkdir_one(esp_path, efi_subdirs[i]);
+ STRV_FOREACH(i, efi_subdirs) {
+ r = mkdir_one(esp_path, *i);
if (r < 0)
return r;
}
@@ -580,7 +648,7 @@ static int copy_one_file(const char *esp_path, const char *name, bool force) {
/* Create the EFI default boot loader name (specified for removable devices) */
v = strjoina(esp_path, "/EFI/BOOT/BOOT", name + strlen("systemd-boot"));
- strupper(strrchr(v, '/') + 1);
+ ascii_strupper(strrchr(v, '/') + 1);
k = copy_file(p, v, force);
if (k < 0 && r == 0)
@@ -751,8 +819,8 @@ static int install_variables(const char *esp_path,
if (access(p, F_OK) < 0) {
if (errno == ENOENT)
return 0;
- else
- return log_error_errno(errno, "Cannot access \"%s\": %m", p);
+
+ return log_error_errno(errno, "Cannot access \"%s\": %m", p);
}
r = find_slot(uuid, path, &slot);
@@ -762,7 +830,7 @@ static int install_variables(const char *esp_path,
"Failed to access EFI variables. Is the \"efivarfs\" filesystem mounted?" :
"Failed to determine current boot order: %m");
- if (first || r == false) {
+ if (first || r == 0) {
r = efi_add_boot_option(slot, "Linux Boot Manager",
part, pstart, psize,
uuid, path);
@@ -872,46 +940,39 @@ static int remove_variables(sd_id128_t uuid, const char *path, bool in_order) {
if (in_order)
return remove_from_order(slot);
- else
- return 0;
+
+ return 0;
}
static int install_loader_config(const char *esp_path) {
- char *p;
- char line[64];
- char *machine = NULL;
- _cleanup_fclose_ FILE *f = NULL, *g = NULL;
- f = fopen("/etc/machine-id", "re");
- if (!f)
- return errno == ENOENT ? 0 : -errno;
+ _cleanup_fclose_ FILE *f = NULL;
+ char machine_string[SD_ID128_STRING_MAX];
+ sd_id128_t machine_id;
+ const char *p;
+ int r;
- if (fgets(line, sizeof(line), f) != NULL) {
- char *s;
+ r = sd_id128_get_machine(&machine_id);
+ if (r < 0)
+ return log_error_errno(r, "Failed to get machine did: %m");
- s = strchr(line, '\n');
- if (s)
- s[0] = '\0';
- if (strlen(line) == 32)
- machine = line;
- }
+ p = strjoina(esp_path, "/loader/loader.conf");
+ f = fopen(p, "wxe");
+ if (!f)
+ return log_error_errno(errno, "Failed to open loader.conf for writing: %m");
- if (!machine)
- return -ESRCH;
+ fprintf(f, "#timeout 3\n");
+ fprintf(f, "default %s-*\n", sd_id128_to_string(machine_id, machine_string));
- p = strjoina(esp_path, "/loader/loader.conf");
- g = fopen(p, "wxe");
- if (g) {
- fprintf(g, "#timeout 3\n");
- fprintf(g, "default %s-*\n", machine);
- if (ferror(g))
- return log_error_errno(EIO, "Failed to write \"%s\": %m", p);
- }
+ r = fflush_and_check(f);
+ if (r < 0)
+ return log_error_errno(r, "Failed to write \"%s\": %m", p);
return 0;
}
-static int help(void) {
+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"
@@ -930,9 +991,6 @@ static int help(void) {
return 0;
}
-static const char *arg_path = "/boot";
-static bool arg_touch_variables = true;
-
static int parse_argv(int argc, char *argv[]) {
enum {
ARG_PATH = 0x100,
@@ -948,7 +1006,7 @@ static int parse_argv(int argc, char *argv[]) {
{ NULL, 0, NULL, 0 }
};
- int c;
+ int c, r;
assert(argc >= 0);
assert(argv);
@@ -957,14 +1015,16 @@ static int parse_argv(int argc, char *argv[]) {
switch (c) {
case 'h':
- help();
+ help(0, NULL, NULL);
return 0;
case ARG_VERSION:
return version();
case ARG_PATH:
- arg_path = optarg;
+ r = free_and_strdup(&arg_path, optarg);
+ if (r < 0)
+ return log_oom();
break;
case ARG_NO_VARIABLES:
@@ -989,149 +1049,170 @@ static void read_loader_efi_var(const char *name, char **var) {
log_warning_errno(r, "Failed to read EFI variable %s: %m", name);
}
-static int bootctl_main(int argc, char*argv[]) {
- enum action {
- ACTION_STATUS,
- ACTION_INSTALL,
- ACTION_UPDATE,
- ACTION_REMOVE
- } arg_action = ACTION_STATUS;
- static const struct {
- const char* verb;
- enum action action;
- } verbs[] = {
- { "status", ACTION_STATUS },
- { "install", ACTION_INSTALL },
- { "update", ACTION_UPDATE },
- { "remove", ACTION_REMOVE },
- };
+static int must_be_root(void) {
- sd_id128_t uuid = {};
- uint32_t part = 0;
- uint64_t pstart = 0, psize = 0;
- int r, q;
+ if (geteuid() == 0)
+ return 0;
- if (argv[optind]) {
- unsigned i;
+ log_error("Need to be root.");
+ return -EPERM;
+}
- for (i = 0; i < ELEMENTSOF(verbs); i++) {
- if (!streq(argv[optind], verbs[i].verb))
- continue;
- arg_action = verbs[i].action;
- break;
- }
- if (i >= ELEMENTSOF(verbs)) {
- log_error("Unknown operation \"%s\"", argv[optind]);
- return -EINVAL;
- }
- }
+static int verb_status(int argc, char *argv[], void *userdata) {
- if (geteuid() != 0)
- return log_error_errno(EPERM, "Need to be root.");
+ sd_id128_t uuid = SD_ID128_NULL;
+ int r;
- r = verify_esp(arg_path, &part, &pstart, &psize, &uuid);
- if (r == -ENODEV && !arg_path)
- log_notice("You might want to use --path= to indicate the path to your ESP, in case it is not mounted on /boot.");
+ r = must_be_root();
if (r < 0)
return r;
- switch (arg_action) {
- case ACTION_STATUS: {
- _cleanup_free_ char *fw_type = NULL;
- _cleanup_free_ char *fw_info = NULL;
- _cleanup_free_ char *loader = NULL;
- _cleanup_free_ char *loader_path = NULL;
- sd_id128_t loader_part_uuid = {};
-
- if (is_efi_boot()) {
- read_loader_efi_var("LoaderFirmwareType", &fw_type);
- read_loader_efi_var("LoaderFirmwareInfo", &fw_info);
- read_loader_efi_var("LoaderInfo", &loader);
- read_loader_efi_var("LoaderImageIdentifier", &loader_path);
- if (loader_path)
- efi_tilt_backslashes(loader_path);
- r = efi_loader_get_device_part_uuid(&loader_part_uuid);
- if (r < 0 && r == -ENOENT)
- log_warning_errno(r, "Failed to read EFI variable LoaderDevicePartUUID: %m");
-
- printf("System:\n");
- printf(" Firmware: %s (%s)\n", strna(fw_type), strna(fw_info));
-
- r = is_efi_secure_boot();
- if (r < 0)
- log_warning_errno(r, "Failed to query secure boot status: %m");
- else
- printf(" Secure Boot: %s\n", r ? "enabled" : "disabled");
+ r = find_esp(NULL, NULL, NULL, &uuid);
+ if (r < 0)
+ return r;
- r = is_efi_secure_boot_setup_mode();
- if (r < 0)
- log_warning_errno(r, "Failed to query secure boot mode: %m");
- else
- printf(" Setup Mode: %s\n", r ? "setup" : "user");
- printf("\n");
-
- printf("Loader:\n");
- printf(" Product: %s\n", strna(loader));
- if (!sd_id128_is_null(loader_part_uuid))
- printf(" Partition: /dev/disk/by-partuuid/%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
- SD_ID128_FORMAT_VAL(loader_part_uuid));
- else
- printf(" Partition: n/a\n");
- printf(" File: %s%s\n", special_glyph(TREE_RIGHT), strna(loader_path));
- printf("\n");
- } else
- printf("System:\n Not booted with EFI\n");
-
- r = status_binaries(arg_path, uuid);
+ if (is_efi_boot()) {
+ _cleanup_free_ char *fw_type = NULL, *fw_info = NULL, *loader = NULL, *loader_path = NULL;
+ sd_id128_t loader_part_uuid = SD_ID128_NULL;
+
+ read_loader_efi_var("LoaderFirmwareType", &fw_type);
+ read_loader_efi_var("LoaderFirmwareInfo", &fw_info);
+ read_loader_efi_var("LoaderInfo", &loader);
+ read_loader_efi_var("LoaderImageIdentifier", &loader_path);
+
+ if (loader_path)
+ efi_tilt_backslashes(loader_path);
+
+ r = efi_loader_get_device_part_uuid(&loader_part_uuid);
+ if (r < 0 && r != -ENOENT)
+ log_warning_errno(r, "Failed to read EFI variable LoaderDevicePartUUID: %m");
+
+ printf("System:\n");
+ printf(" Firmware: %s (%s)\n", strna(fw_type), strna(fw_info));
+
+ r = is_efi_secure_boot();
if (r < 0)
- return r;
+ log_warning_errno(r, "Failed to query secure boot status: %m");
+ else
+ printf(" Secure Boot: %s\n", r ? "enabled" : "disabled");
- if (arg_touch_variables)
- r = status_variables();
- break;
- }
+ r = is_efi_secure_boot_setup_mode();
+ if (r < 0)
+ log_warning_errno(r, "Failed to query secure boot mode: %m");
+ else
+ printf(" Setup Mode: %s\n", r ? "setup" : "user");
+ printf("\n");
+
+ printf("Loader:\n");
+ printf(" Product: %s\n", strna(loader));
+ if (!sd_id128_is_null(loader_part_uuid))
+ printf(" Partition: /dev/disk/by-partuuid/%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
+ SD_ID128_FORMAT_VAL(loader_part_uuid));
+ else
+ printf(" Partition: n/a\n");
+ printf(" File: %s%s\n", special_glyph(TREE_RIGHT), strna(loader_path));
+ printf("\n");
+ } else
+ printf("System:\n Not booted with EFI\n");
- case ACTION_INSTALL:
- case ACTION_UPDATE:
- umask(0002);
+ r = status_binaries(arg_path, uuid);
+ if (r < 0)
+ return r;
+
+ if (arg_touch_variables)
+ r = status_variables();
- r = install_binaries(arg_path, arg_action == ACTION_INSTALL);
+ return r;
+}
+
+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;
+ bool install;
+ int r;
+
+ r = must_be_root();
+ if (r < 0)
+ return r;
+
+ r = find_esp(&part, &pstart, &psize, &uuid);
+ if (r < 0)
+ return r;
+
+ install = streq(argv[0], "install");
+
+ RUN_WITH_UMASK(0002) {
+ r = install_binaries(arg_path, install);
if (r < 0)
return r;
- if (arg_action == ACTION_INSTALL) {
+ if (install) {
r = install_loader_config(arg_path);
if (r < 0)
return r;
}
+ }
- if (arg_touch_variables)
- r = install_variables(arg_path,
- part, pstart, psize, uuid,
- "/EFI/systemd/systemd-boot" EFI_MACHINE_TYPE_NAME ".efi",
- arg_action == ACTION_INSTALL);
- break;
+ if (arg_touch_variables)
+ r = install_variables(arg_path,
+ part, pstart, psize, uuid,
+ "/EFI/systemd/systemd-boot" EFI_MACHINE_TYPE_NAME ".efi",
+ install);
- case ACTION_REMOVE:
- r = remove_binaries(arg_path);
+ return r;
+}
- if (arg_touch_variables) {
- q = remove_variables(uuid, "/EFI/systemd/systemd-boot" EFI_MACHINE_TYPE_NAME ".efi", true);
- if (q < 0 && r == 0)
- r = q;
- }
- break;
+static int verb_remove(int argc, char *argv[], void *userdata) {
+ sd_id128_t uuid = SD_ID128_NULL;
+ int r;
+
+ r = must_be_root();
+ if (r < 0)
+ return r;
+
+ r = find_esp(NULL, NULL, NULL, &uuid);
+ if (r < 0)
+ return r;
+
+ r = remove_binaries(arg_path);
+
+ 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)
+ r = q;
}
return r;
}
+static int bootctl_main(int argc, char *argv[]) {
+
+ static const Verb verbs[] = {
+ { "help", VERB_ANY, VERB_ANY, 0, help },
+ { "status", VERB_ANY, 1, VERB_DEFAULT, verb_status },
+ { "install", VERB_ANY, 1, 0, verb_install },
+ { "update", VERB_ANY, 1, 0, verb_install },
+ { "remove", VERB_ANY, 1, 0, verb_remove },
+ {}
+ };
+
+ return dispatch_verb(argc, argv, verbs, NULL);
+}
+
int main(int argc, char *argv[]) {
int r;
log_parse_environment();
log_open();
+ /* If we run in a container, automatically turn of EFI file system access */
+ if (detect_container() > 0)
+ arg_touch_variables = false;
+
r = parse_argv(argc, argv);
if (r <= 0)
goto finish;
@@ -1139,5 +1220,6 @@ int main(int argc, char *argv[]) {
r = bootctl_main(argc, argv);
finish:
+ free(arg_path);
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
diff --git a/src/gpt-auto-generator/gpt-auto-generator.c b/src/gpt-auto-generator/gpt-auto-generator.c
index 39355de953..6cc1aad705 100644
--- a/src/gpt-auto-generator/gpt-auto-generator.c
+++ b/src/gpt-auto-generator/gpt-auto-generator.c
@@ -450,99 +450,101 @@ static int add_automount(
}
static int add_boot(const char *what) {
- _cleanup_blkid_free_probe_ blkid_probe b = NULL;
- const char *fstype = NULL, *uuid = NULL;
- sd_id128_t id, type_id;
+ const char *esp;
int r;
assert(what);
- if (!is_efi_boot()) {
- log_debug("Not an EFI boot, ignoring /boot.");
- return 0;
- }
-
if (in_initrd()) {
- log_debug("In initrd, ignoring /boot.");
+ log_debug("In initrd, ignoring the ESP.");
return 0;
}
if (detect_container() > 0) {
- log_debug("In a container, ignoring /boot.");
+ log_debug("In a container, ignoring the ESP.");
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";
+
/* We create an .automount which is not overridden by the .mount from the fstab generator. */
- if (fstab_is_mount_point("/boot")) {
- log_debug("/boot specified in fstab, ignoring.");
+ if (fstab_is_mount_point(esp)) {
+ log_debug("%s specified in fstab, ignoring.", esp);
return 0;
}
- if (path_is_busy("/boot")) {
- log_debug("/boot already populated, ignoring.");
+ if (path_is_busy(esp)) {
+ log_debug("%s already populated, ignoring.", esp);
return 0;
}
- r = efi_loader_get_device_part_uuid(&id);
- if (r == -ENOENT) {
- log_debug("EFI loader partition unknown.");
- return 0;
- }
+ if (is_efi_boot()) {
+ _cleanup_blkid_free_probe_ blkid_probe b = NULL;
+ const char *fstype = NULL, *uuid_string = NULL;
+ sd_id128_t loader_uuid, part_uuid;
- if (r < 0)
- return log_error_errno(r, "Failed to read ESP partition UUID: %m");
+ /* If this is an EFI boot, be extra careful, and only mount the ESP if it was the ESP used for booting. */
- errno = 0;
- b = blkid_new_probe_from_filename(what);
- if (!b) {
- if (errno == 0)
- return log_oom();
- return log_error_errno(errno, "Failed to allocate prober: %m");
- }
-
- blkid_probe_enable_partitions(b, 1);
- blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
+ r = efi_loader_get_device_part_uuid(&loader_uuid);
+ if (r == -ENOENT) {
+ log_debug("EFI loader partition unknown.");
+ return 0;
+ }
+ if (r < 0)
+ return log_error_errno(r, "Failed to read ESP partition UUID: %m");
- errno = 0;
- r = blkid_do_safeprobe(b);
- if (r == -2 || r == 1) /* no result or uncertain */
- return 0;
- else if (r != 0)
- return log_error_errno(errno ?: EIO, "Failed to probe %s: %m", what);
+ errno = 0;
+ b = blkid_new_probe_from_filename(what);
+ if (!b) {
+ if (errno == 0)
+ return log_oom();
+ return log_error_errno(errno, "Failed to allocate prober: %m");
+ }
- (void) blkid_probe_lookup_value(b, "TYPE", &fstype, NULL);
- if (!streq_ptr(fstype, "vfat")) {
- log_debug("Partition for /boot is not a FAT filesystem, ignoring.");
- return 0;
- }
+ blkid_probe_enable_partitions(b, 1);
+ blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
- errno = 0;
- r = blkid_probe_lookup_value(b, "PART_ENTRY_UUID", &uuid, NULL);
- if (r != 0) {
- log_debug_errno(errno, "Partition for /boot does not have a UUID, ignoring.");
- return 0;
- }
+ errno = 0;
+ r = blkid_do_safeprobe(b);
+ if (r == -2 || r == 1) /* no result or uncertain */
+ return 0;
+ else if (r != 0)
+ return log_error_errno(errno ?: EIO, "Failed to probe %s: %m", what);
- if (sd_id128_from_string(uuid, &type_id) < 0) {
- log_debug("Partition for /boot does not have a valid UUID, ignoring.");
- return 0;
- }
+ (void) blkid_probe_lookup_value(b, "TYPE", &fstype, NULL);
+ if (!streq_ptr(fstype, "vfat")) {
+ log_debug("Partition for %s is not a FAT filesystem, ignoring.", esp);
+ return 0;
+ }
- if (!sd_id128_equal(type_id, id)) {
- log_debug("Partition for /boot does not appear to be the partition we are booted from.");
- return 0;
- }
+ errno = 0;
+ r = blkid_probe_lookup_value(b, "PART_ENTRY_UUID", &uuid_string, NULL);
+ if (r != 0) {
+ log_debug_errno(errno, "Partition for %s does not have a UUID, ignoring.", esp);
+ return 0;
+ }
- r = add_automount("boot",
- what,
- "/boot",
- "vfat",
- true,
- "umask=0077",
- "EFI System Partition Automount",
- 120 * USEC_PER_SEC);
+ if (sd_id128_from_string(uuid_string, &part_uuid) < 0) {
+ log_debug("Partition for %s does not have a valid UUID, ignoring.", esp);
+ return 0;
+ }
- return r;
+ if (!sd_id128_equal(part_uuid, loader_uuid)) {
+ log_debug("Partition for %s does not appear to be the partition we are booted from.", esp);
+ return 0;
+ }
+ } else
+ log_debug("Not an EFI boot, skipping ESP check.");
+
+ return add_automount("boot",
+ what,
+ esp,
+ "vfat",
+ true,
+ "umask=0077",
+ "EFI System Partition Automount",
+ 120 * USEC_PER_SEC);
}
#else
static int add_boot(const char *what) {
diff --git a/src/kernel-install/kernel-install b/src/kernel-install/kernel-install
index 1159dc384d..c66bcfc092 100644
--- a/src/kernel-install/kernel-install
+++ b/src/kernel-install/kernel-install
@@ -86,10 +86,15 @@ if [[ ! $COMMAND ]] || [[ ! $KERNEL_VERSION ]]; then
exit 1
fi
-if [[ -d /boot/loader/entries ]] || [[ -d /boot/$MACHINE_ID ]]; then
+if [[ -d /efi/loader/entries ]] || [[ -d /efi/$MACHINE_ID ]]; then
+ BOOT_DIR_ABS="/efi/$MACHINE_ID/$KERNEL_VERSION"
+elif [[ -d /boot/loader/entries ]] || [[ -d /boot/$MACHINE_ID ]]; then
BOOT_DIR_ABS="/boot/$MACHINE_ID/$KERNEL_VERSION"
-elif [[ -d /boot/efi/loader/entries ]] || [[ -d /boot/efi/$MACHINE_ID ]] \
- || mountpoint -q /boot/efi; then
+elif [[ -d /boot/efi/loader/entries ]] || [[ -d /boot/efi/$MACHINE_ID ]]; then
+ BOOT_DIR_ABS="/boot/efi/$MACHINE_ID/$KERNEL_VERSION"
+elif mountpoint -q /efi; then
+ BOOT_DIR_ABS="/efi/$MACHINE_ID/$KERNEL_VERSION"
+elif mountpoint -q /boot/efi; then
BOOT_DIR_ABS="/boot/efi/$MACHINE_ID/$KERNEL_VERSION"
else
BOOT_DIR_ABS="/boot/$MACHINE_ID/$KERNEL_VERSION"
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index d5093a6d17..f8a43d89a2 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -1794,17 +1794,18 @@ static int dissect_image(
char **root_device, bool *root_device_rw,
char **home_device, bool *home_device_rw,
char **srv_device, bool *srv_device_rw,
+ char **esp_device,
bool *secondary) {
#ifdef HAVE_BLKID
- int home_nr = -1, srv_nr = -1;
+ int home_nr = -1, srv_nr = -1, esp_nr = -1;
#ifdef GPT_ROOT_NATIVE
int root_nr = -1;
#endif
#ifdef GPT_ROOT_SECONDARY
int secondary_root_nr = -1;
#endif
- _cleanup_free_ char *home = NULL, *root = NULL, *secondary_root = NULL, *srv = NULL, *generic = NULL;
+ _cleanup_free_ char *home = NULL, *root = NULL, *secondary_root = NULL, *srv = NULL, *esp = NULL, *generic = NULL;
_cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
_cleanup_udev_device_unref_ struct udev_device *d = NULL;
_cleanup_blkid_free_probe_ blkid_probe b = NULL;
@@ -1822,6 +1823,7 @@ static int dissect_image(
assert(root_device);
assert(home_device);
assert(srv_device);
+ assert(esp_device);
assert(secondary);
assert(arg_image);
@@ -2035,6 +2037,16 @@ static int dissect_image(
r = free_and_strdup(&srv, node);
if (r < 0)
return log_oom();
+ } else if (sd_id128_equal(type_id, GPT_ESP)) {
+
+ if (esp && nr >= esp_nr)
+ continue;
+
+ esp_nr = nr;
+
+ r = free_and_strdup(&esp, node);
+ if (r < 0)
+ return log_oom();
}
#ifdef GPT_ROOT_NATIVE
else if (sd_id128_equal(type_id, GPT_ROOT_NATIVE)) {
@@ -2152,6 +2164,11 @@ static int dissect_image(
*srv_device_rw = srv_rw;
}
+ if (esp) {
+ *esp_device = esp;
+ esp = NULL;
+ }
+
return 0;
#else
log_error("--image= is not supported, compiled without blkid support.");
@@ -2284,7 +2301,8 @@ static int mount_devices(
const char *where,
const char *root_device, bool root_device_rw,
const char *home_device, bool home_device_rw,
- const char *srv_device, bool srv_device_rw) {
+ const char *srv_device, bool srv_device_rw,
+ const char *esp_device) {
int r;
assert(where);
@@ -2307,6 +2325,27 @@ static int mount_devices(
return log_error_errno(r, "Failed to mount server data directory: %m");
}
+ if (esp_device) {
+ const char *mp, *x;
+
+ /* Mount the ESP to /efi if it exists and is empty. If it doesn't exist, use /boot instead. */
+
+ mp = "/efi";
+ x = strjoina(arg_directory, mp);
+ r = dir_is_empty(x);
+ if (r == -ENOENT) {
+ mp = "/boot";
+ x = strjoina(arg_directory, mp);
+ r = dir_is_empty(x);
+ }
+
+ if (r > 0) {
+ r = mount_device(esp_device, arg_directory, mp, true);
+ if (r < 0)
+ return log_error_errno(r, "Failed to mount ESP: %m");
+ }
+ }
+
return 0;
}
@@ -2795,6 +2834,7 @@ static int outer_child(
const char *root_device, bool root_device_rw,
const char *home_device, bool home_device_rw,
const char *srv_device, bool srv_device_rw,
+ const char *esp_device,
bool interactive,
bool secondary,
int pid_socket,
@@ -2856,7 +2896,8 @@ static int outer_child(
r = mount_devices(directory,
root_device, root_device_rw,
home_device, home_device_rw,
- srv_device, srv_device_rw);
+ srv_device, srv_device_rw,
+ esp_device);
if (r < 0)
return r;
@@ -3461,7 +3502,7 @@ static int load_settings(void) {
int main(int argc, char *argv[]) {
- _cleanup_free_ char *device_path = NULL, *root_device = NULL, *home_device = NULL, *srv_device = NULL, *console = NULL;
+ _cleanup_free_ char *device_path = NULL, *root_device = NULL, *home_device = NULL, *srv_device = NULL, *esp_device = NULL, *console = NULL;
bool root_device_rw = true, home_device_rw = true, srv_device_rw = true;
_cleanup_close_ int master = -1, image_fd = -1;
_cleanup_fdset_free_ FDSet *fds = NULL;
@@ -3643,6 +3684,7 @@ int main(int argc, char *argv[]) {
&root_device, &root_device_rw,
&home_device, &home_device_rw,
&srv_device, &srv_device_rw,
+ &esp_device,
&secondary);
if (r < 0)
goto finish;
@@ -3817,6 +3859,7 @@ int main(int argc, char *argv[]) {
root_device, root_device_rw,
home_device, home_device_rw,
srv_device, srv_device_rw,
+ esp_device,
interactive,
secondary,
pid_socket_pair[1],