From b52a109ad38cd37b660ccd5394ff5c171a5e5355 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 19 Jul 2016 18:19:29 +0200 Subject: gpt-generator: use /efi as mount point for the ESP if it exists Let's make the EFI generator a bit smarter: if /efi exists it is used as mount point for the ESP, otherwise /boot is used. This should increase compatibility with distros which use legacy boot loaders that insist on having /boot as something that isn't the ESP. --- src/gpt-auto-generator/gpt-auto-generator.c | 41 ++++++++++++++++------------- 1 file changed, 22 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/gpt-auto-generator/gpt-auto-generator.c b/src/gpt-auto-generator/gpt-auto-generator.c index a4938a7c3a..dede86eabf 100644 --- a/src/gpt-auto-generator/gpt-auto-generator.c +++ b/src/gpt-auto-generator/gpt-auto-generator.c @@ -453,33 +453,37 @@ 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."); + log_debug("Not an EFI boot, ignoring the ESP."); 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; } @@ -488,7 +492,6 @@ static int add_boot(const char *what) { log_debug("EFI loader partition unknown."); return 0; } - if (r < 0) { log_error_errno(r, "Failed to read ESP partition UUID: %m"); return r; @@ -514,35 +517,35 @@ static int add_boot(const char *what) { (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."); + log_debug("Partition for %s is not a FAT filesystem, ignoring.", esp); return 0; } 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."); + log_debug_errno(errno, "Partition for %s does not have a UUID, ignoring.", esp); return 0; } if (sd_id128_from_string(uuid, &type_id) < 0) { - log_debug("Partition for /boot does not have a valid UUID, ignoring."); + log_debug("Partition for %s does not have a valid UUID, 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."); + log_debug("Partition for %s does not appear to be the partition we are booted from.", esp); return 0; } r = add_automount("boot", - what, - "/boot", - "vfat", - true, - "umask=0077", - "EFI System Partition Automount", - 120 * USEC_PER_SEC); + what, + esp, + "vfat", + true, + "umask=0077", + "EFI System Partition Automount", + 120 * USEC_PER_SEC); return r; } -- cgit v1.2.3-54-g00ecf From a6bc7db980532d294c29f1cd5654f03453519c92 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 19 Jul 2016 18:36:04 +0200 Subject: nspawn: if an ESP is part of the disk image to operate on, mount it to /efi or /boot Matching the behaviour of gpt-auto-generator, if we find an ESP while dissecting a container image, mount it to /efi or /boot if those dirs exist and are empty. This should enable us to run "bootctl" inside a container and do the right thing. --- src/nspawn/nspawn.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 48 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index e4be0a2251..befe342b02 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -1803,17 +1803,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; @@ -1831,6 +1832,7 @@ static int dissect_image( assert(root_device); assert(home_device); assert(srv_device); + assert(esp_device); assert(secondary); assert(arg_image); @@ -2044,6 +2046,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)) { @@ -2161,6 +2173,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."); @@ -2289,7 +2306,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); @@ -2312,6 +2330,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; } @@ -2785,6 +2824,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, @@ -2846,7 +2886,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; @@ -3449,7 +3490,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; @@ -3631,6 +3672,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; @@ -3805,6 +3847,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], -- cgit v1.2.3-54-g00ecf From 25579a43efcf5fdced4041427164e0852c035ab0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 19 Jul 2016 18:39:54 +0200 Subject: bootctl: minor coding style improvements --- src/boot/bootctl.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c index 7cb2259717..6e0c961527 100644 --- a/src/boot/bootctl.c +++ b/src/boot/bootctl.c @@ -46,6 +46,9 @@ #include "string-util.h" #include "util.h" +static const char *arg_path = "/boot"; +static bool arg_touch_variables = true; + 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; @@ -930,9 +933,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, @@ -1036,12 +1036,10 @@ static int bootctl_main(int argc, char*argv[]) { 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 = {}; + _cleanup_free_ char *fw_type = NULL, *fw_info = NULL, *loader = NULL, *loader_path = NULL; + sd_id128_t loader_part_uuid = SD_ID128_NULL; if (is_efi_boot()) { read_loader_efi_var("LoaderFirmwareType", &fw_type); -- cgit v1.2.3-54-g00ecf From c18532e031d2923e095a189999c289be13aea7b8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 19 Jul 2016 18:40:03 +0200 Subject: bootctl: fix error message check --- src/boot/bootctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c index 6e0c961527..f337eb6675 100644 --- a/src/boot/bootctl.c +++ b/src/boot/bootctl.c @@ -1049,7 +1049,7 @@ static int bootctl_main(int argc, char*argv[]) { if (loader_path) efi_tilt_backslashes(loader_path); r = efi_loader_get_device_part_uuid(&loader_part_uuid); - if (r < 0 && r == -ENOENT) + if (r < 0 && r != -ENOENT) log_warning_errno(r, "Failed to read EFI variable LoaderDevicePartUUID: %m"); printf("System:\n"); -- cgit v1.2.3-54-g00ecf From 2f2c539cd4af7ca526296adecff2a6f90d7d7b0c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 19 Jul 2016 20:19:20 +0200 Subject: bootctl: rework to use common verbs parsing, and add searching of ESP path This rearranges bootctl a bit, so that it uses the usual verbs parsing routines, and automatically searches the ESP in /boot, /efi or /boot/efi, thus increasing compatibility with mainstream distros that insist on /boot/efi. This also adds minimal support for running bootctl in a container environment: when run inside a container verification of the ESP via raw block device access, trusting the container manager to mount the ESP correctly. Moreover, EFI variables are not accessed when running in the container. --- man/bootctl.xml | 6 +- src/boot/bootctl.c | 342 ++++++++++++++++++++++++++++++++++------------------- 2 files changed, 224 insertions(+), 124 deletions(-) (limited to 'src') diff --git a/man/bootctl.xml b/man/bootctl.xml index 6e835c037f..82c162ee70 100644 --- a/man/bootctl.xml +++ b/man/bootctl.xml @@ -101,8 +101,10 @@ - - Path to the EFI system partition. The default is /boot. + + Path to the EFI System Partition (ESP). If not specified, /efi, + /boot, and /boot/efi are checked in turn. It is recommended to mount + the ESP to /boot, if possible. diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c index f337eb6675..8b2407f145 100644 --- a/src/boot/bootctl.c +++ b/src/boot/bootctl.c @@ -42,25 +42,52 @@ #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" -static const char *arg_path = "/boot"; +static char *arg_path = NULL; static bool arg_touch_variables = true; -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; +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) { + _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 (sfs.f_type != 0x4d44) { + + if (searching) + return -EADDRNOTAVAIL; + log_error("File system \"%s\" is not a FAT EFI System Partition (ESP) file system.", p); return -ENODEV; } @@ -83,6 +110,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(); @@ -120,7 +152,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; @@ -132,7 +163,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; @@ -144,7 +174,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; @@ -156,8 +185,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; @@ -169,7 +197,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); @@ -177,7 +207,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); @@ -185,11 +217,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; @@ -914,7 +985,8 @@ static int install_loader_config(const char *esp_path) { 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" @@ -948,7 +1020,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 +1029,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,147 +1063,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) { + r = find_esp(NULL, NULL, NULL, &uuid); + if (r < 0) + return r; - case ACTION_STATUS: { + 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; - 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"); + 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); - 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_equal(loader_part_uuid, SD_ID128_NULL)) - 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 (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_equal(loader_part_uuid, SD_ID128_NULL)) + 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 (r < 0) + return r; + + if (arg_touch_variables) + r = status_variables(); + + return r; +} - case ACTION_INSTALL: - case ACTION_UPDATE: - umask(0002); +static int verb_install(int argc, char *argv[], void *userdata) { - r = install_binaries(arg_path, arg_action == ACTION_INSTALL); + 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", + install); - 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; + return r; +} - case ACTION_REMOVE: - r = remove_binaries(arg_path); +static int verb_remove(int argc, char *argv[], void *userdata) { + sd_id128_t uuid = SD_ID128_NULL; + int 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; + 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; @@ -1137,5 +1234,6 @@ int main(int argc, char *argv[]) { r = bootctl_main(argc, argv); finish: + free(arg_path); return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; } -- cgit v1.2.3-54-g00ecf From 181ccb43ead439059d4302252870a77ff4441688 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 19 Jul 2016 20:26:24 +0200 Subject: bootctl: make use of STRV_FOREACH() where we can --- src/boot/bootctl.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c index 8b2407f145..d9c3897392 100644 --- a/src/boot/bootctl.c +++ b/src/boot/bootctl.c @@ -628,11 +628,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; } @@ -836,7 +836,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); -- cgit v1.2.3-54-g00ecf From 846b8fc30d52a63dd6a010e497aa80164fea31d8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 19 Jul 2016 20:43:54 +0200 Subject: bootctl: move toupper() implementation to string-util.h We already have tolower() calls there, hence let's unify this at one place. Also, update the code to only use ASCII operations, so that we don't end up being locale dependant. --- src/basic/string-util.c | 19 +++++++++++++++++++ src/basic/string-util.h | 3 +++ src/boot/bootctl.c | 11 +---------- 3 files changed, 23 insertions(+), 10 deletions(-) (limited to 'src') 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 d9c3897392..5c3e7a04a0 100644 --- a/src/boot/bootctl.c +++ b/src/boot/bootctl.c @@ -597,15 +597,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; @@ -654,7 +645,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) -- cgit v1.2.3-54-g00ecf From 5fa6c13c7bd6df488c0585608688a5feb8a03d5d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 19 Jul 2016 20:45:10 +0200 Subject: bootctl: use F_TYPE_EQUAL() to compare statfs' .f_type field After all, the field is kinda borked. --- src/boot/bootctl.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c index 5c3e7a04a0..9a24ecd6b2 100644 --- a/src/boot/bootctl.c +++ b/src/boot/bootctl.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -50,6 +51,7 @@ #include "util.h" #include "verbs.h" #include "virt.h" +#include "stat-util.h" static char *arg_path = NULL; static bool arg_touch_variables = true; @@ -83,7 +85,7 @@ static int verify_esp( return log_error_errno(errno, "Failed to check file system type of \"%s\": %m", p); } - if (sfs.f_type != 0x4d44) { + if (!F_TYPE_EQUAL(sfs.f_type, MSDOS_SUPER_MAGIC)) { if (searching) return -EADDRNOTAVAIL; -- cgit v1.2.3-54-g00ecf From db6d9faeb0179b15cf29e87bd20d29d6210142ef Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 19 Jul 2016 20:46:17 +0200 Subject: bootctl: clean up get_file_version() Make sure that we always initialize the return parameter on success, and that all errors result in an error message, not just some. --- src/boot/bootctl.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c index 9a24ecd6b2..ff14cff166 100644 --- a/src/boot/bootctl.c +++ b/src/boot/bootctl.c @@ -275,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) @@ -304,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; } -- cgit v1.2.3-54-g00ecf From f939cff715775553bb1ec903454acf0d95bf5023 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 19 Jul 2016 20:47:09 +0200 Subject: bootctl: various coding style updates --- src/boot/bootctl.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c index ff14cff166..9cbea5041e 100644 --- a/src/boot/bootctl.c +++ b/src/boot/bootctl.c @@ -416,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); @@ -438,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; @@ -820,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); @@ -941,8 +940,8 @@ 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) { -- cgit v1.2.3-54-g00ecf From d5ff6d6d341d56de725633a38e23778e58140b9e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 19 Jul 2016 20:48:22 +0200 Subject: bootctl: modernize install_loader_config() let's the proper APIs to read the machine ID, and properly check for all errors. --- src/boot/bootctl.c | 42 +++++++++++++++++------------------------- 1 file changed, 17 insertions(+), 25 deletions(-) (limited to 'src') diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c index 9cbea5041e..f0a88ab3ac 100644 --- a/src/boot/bootctl.c +++ b/src/boot/bootctl.c @@ -945,36 +945,28 @@ static int remove_variables(sd_id128_t uuid, const char *path, bool in_order) { } 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; } -- cgit v1.2.3-54-g00ecf From 5b8411a2aa2d986a0c7e995c57d01ed6e56e74da Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 19 Jul 2016 21:08:57 +0200 Subject: kernel-install: when searching for location to place kernel consider /efi With this change kernel-install will now first look for an existing kernel installation in /efi, /boot and /boot/efi. If none is found, /efi is used if it is a mount point, otherwise /boot/efi if it is one. If nothing of that worked /boot is used without further checking. This means /boot should be the default unless something was installed before or something else was explicitly mounted. --- src/kernel-install/kernel-install | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'src') 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" -- cgit v1.2.3-54-g00ecf From 7ba25ab5616339a8340117b85cbecd061c52d8cc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 21 Jul 2016 11:30:02 +0200 Subject: gpt-generator: relax EFI check a bit Previously, we'd not mount the ESP except on EFI boots, and only when the ESP used for booting matches the ESP we found. With this change on non-EFI boots we'll mount a discovered ESP anyway, and on EFI boots we'll only mount it if it matches the ESP we booted from. --- src/gpt-auto-generator/gpt-auto-generator.c | 107 ++++++++++++++-------------- 1 file changed, 53 insertions(+), 54 deletions(-) (limited to 'src') diff --git a/src/gpt-auto-generator/gpt-auto-generator.c b/src/gpt-auto-generator/gpt-auto-generator.c index dede86eabf..e4c913f2c4 100644 --- a/src/gpt-auto-generator/gpt-auto-generator.c +++ b/src/gpt-auto-generator/gpt-auto-generator.c @@ -450,19 +450,11 @@ 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 the ESP."); - return 0; - } - if (in_initrd()) { log_debug("In initrd, ignoring the ESP."); return 0; @@ -487,58 +479,67 @@ static int add_boot(const char *what) { return 0; } - r = efi_loader_get_device_part_uuid(&id); - if (r == -ENOENT) { - log_debug("EFI loader partition unknown."); - return 0; - } - if (r < 0) { - log_error_errno(r, "Failed to read ESP partition UUID: %m"); - return r; - } + 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; - 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"); - } + /* If this is an EFI boot, be extra careful, and only mount the ESP if it was the ESP used for booting. */ - 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) { + log_error_errno(r, "Failed to read ESP partition UUID: %m"); + return r; + } - 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 %s is not a FAT filesystem, ignoring.", esp); - 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 %s does not have a UUID, ignoring.", esp); - 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 %s does not have a valid UUID, ignoring.", esp); - 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 %s does not appear to be the partition we are booted from.", esp); - 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", + 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; + } + + 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", @@ -546,8 +547,6 @@ static int add_boot(const char *what) { "umask=0077", "EFI System Partition Automount", 120 * USEC_PER_SEC); - - return r; } #else static int add_boot(const char *what) { -- cgit v1.2.3-54-g00ecf