]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
bootctl: update/list/remove all instances of systemd-boot in /EFI/BOOT
authorDaan De Meyer <daan.j.demeyer@gmail.com>
Sun, 10 Dec 2023 21:44:25 +0000 (22:44 +0100)
committerLuca Boccassi <luca.boccassi@gmail.com>
Wed, 20 Dec 2023 12:56:02 +0000 (13:56 +0100)
systemd-boot might be installed in /EFI/BOOT under more names than
just /EFI/BOOT/BOOTX64.efi. The prime example is shim which loads
its second stage binary from /EFI/BOOT/grubx64.efi. To accomodate
use cases where systemd-boot is installed as /EFI/BOOT/grubx64.efi,
let's always check the entire /EFI/BOOT directory for binaries that
identify as systemd-boot and list/update/remove those as well.

Let's keep this somewhat generic though and not install ourselves as
grubx64.efi since that would mean having to check for shim which is
a can of worms we probably don't want to open.

src/boot/bootctl-install.c
src/boot/bootctl-status.c

index bacbbb293903b4c9886b2ca10c25caef75320157..d1bd3c681c7c1ec5db5ed10281ecb38388f55c5a 100644 (file)
@@ -318,6 +318,46 @@ static int create_subdirs(const char *root, const char * const *subdirs) {
         return 0;
 }
 
+static int update_efi_boot_binaries(const char *esp_path, const char *source_path) {
+        _cleanup_closedir_ DIR *d = NULL;
+        _cleanup_free_ char *p = NULL;
+        int r, ret = 0;
+
+        r = chase_and_opendir("/EFI/BOOT", esp_path, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, &p, &d);
+        if (r == -ENOENT)
+                return 0;
+        if (r < 0)
+                return log_error_errno(r, "Failed to open directory \"%s/EFI/BOOT\": %m", esp_path);
+
+        FOREACH_DIRENT(de, d, break) {
+                _cleanup_close_ int fd = -EBADF;
+                _cleanup_free_ char *v = NULL;
+
+                if (!endswith_no_case(de->d_name, ".efi"))
+                        continue;
+
+                fd = openat(dirfd(d), de->d_name, O_RDONLY|O_CLOEXEC);
+                if (fd < 0)
+                        return log_error_errno(errno, "Failed to open \"%s/%s\" for reading: %m", p, de->d_name);
+
+                r = get_file_version(fd, &v);
+                if (r == -ESRCH)
+                        continue;  /* No version information */
+                if (r < 0)
+                        return r;
+                if (startswith(v, "systemd-boot ")) {
+                        _cleanup_free_ char *dest_path = NULL;
+
+                        dest_path = path_join(p, de->d_name);
+                        if (!dest_path)
+                                return log_oom();
+
+                        RET_GATHER(ret, copy_file_with_version_check(source_path, dest_path, /* force = */ false));
+                }
+        }
+
+        return ret;
+}
 
 static int copy_one_file(const char *esp_path, const char *name, bool force) {
         char *root = IN_SET(arg_install_source, ARG_INSTALL_SOURCE_AUTO, ARG_INSTALL_SOURCE_IMAGE) ? arg_root : NULL;
@@ -371,9 +411,12 @@ static int copy_one_file(const char *esp_path, const char *name, bool force) {
                 if (r < 0)
                         return log_error_errno(r, "Failed to resolve path %s under directory %s: %m", v, esp_path);
 
-                r = copy_file_with_version_check(source_path, default_dest_path, force);
-                if (r < 0 && ret == 0)
-                        ret = r;
+                RET_GATHER(ret, copy_file_with_version_check(source_path, default_dest_path, force));
+
+                /* If we were installed under any other name in /EFI/BOOT, make sure we update those binaries
+                 * as well. */
+                if (!force)
+                        RET_GATHER(ret, update_efi_boot_binaries(esp_path, source_path));
         }
 
         return ret;
@@ -845,9 +888,6 @@ static int remove_boot_efi(const char *esp_path) {
                 if (!endswith_no_case(de->d_name, ".efi"))
                         continue;
 
-                if (!startswith_no_case(de->d_name, "boot"))
-                        continue;
-
                 fd = openat(dirfd(d), de->d_name, O_RDONLY|O_CLOEXEC);
                 if (fd < 0)
                         return log_error_errno(errno, "Failed to open \"%s/%s\" for reading: %m", p, de->d_name);
index 16b2eaed072bf852f69f5fdba52b495a3b56c9a6..c8041c4bd1f4c67e3ad791d97769de8094232940 100644 (file)
@@ -187,7 +187,6 @@ static int status_variables(void) {
 static int enumerate_binaries(
                 const char *esp_path,
                 const char *path,
-                const char *prefix,
                 char **previous,
                 bool *is_first) {
 
@@ -213,9 +212,6 @@ static int enumerate_binaries(
                 if (!endswith_no_case(de->d_name, ".efi"))
                         continue;
 
-                if (prefix && !startswith_no_case(de->d_name, prefix))
-                        continue;
-
                 filename = path_join(p, de->d_name);
                 if (!filename)
                         return log_oom();
@@ -272,11 +268,11 @@ static int status_binaries(const char *esp_path, sd_id128_t partition) {
                 printf(" (/dev/disk/by-partuuid/" SD_ID128_UUID_FORMAT_STR ")", SD_ID128_FORMAT_VAL(partition));
         printf("\n");
 
-        r = enumerate_binaries(esp_path, "EFI/systemd", NULL, &last, &is_first);
+        r = enumerate_binaries(esp_path, "EFI/systemd", &last, &is_first);
         if (r < 0)
                 goto fail;
 
-        k = enumerate_binaries(esp_path, "EFI/BOOT", "boot", &last, &is_first);
+        k = enumerate_binaries(esp_path, "EFI/BOOT", &last, &is_first);
         if (k < 0) {
                 r = k;
                 goto fail;