2 This file is part of systemd.
4 Copyright 2013-2015 Kay Sievers
5 Copyright 2013 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 #include <blkid/blkid.h>
29 #include <linux/magic.h>
36 #include <sys/statfs.h>
39 #include "alloc-util.h"
40 #include "blkid-util.h"
42 #include "dirent-util.h"
47 #include "locale-util.h"
48 #include "parse-util.h"
50 #include "stat-util.h"
51 #include "string-util.h"
53 #include "umask-util.h"
58 static char *arg_path
= NULL
;
59 static bool arg_touch_variables
= true;
61 static int verify_esp(
67 sd_id128_t
*ret_uuid
) {
69 _cleanup_blkid_free_probe_ blkid_probe b
= NULL
;
70 _cleanup_free_
char *t
= NULL
;
71 uint64_t pstart
= 0, psize
= 0;
75 sd_id128_t uuid
= SD_ID128_NULL
;
81 if (statfs(p
, &sfs
) < 0) {
83 /* If we are searching for the mount point, don't generate a log message if we can't find the path */
84 if (errno
== ENOENT
&& searching
)
87 return log_error_errno(errno
, "Failed to check file system type of \"%s\": %m", p
);
90 if (!F_TYPE_EQUAL(sfs
.f_type
, MSDOS_SUPER_MAGIC
)) {
93 return -EADDRNOTAVAIL
;
95 log_error("File system \"%s\" is not a FAT EFI System Partition (ESP) file system.", p
);
100 return log_error_errno(errno
, "Failed to determine block device node of \"%s\": %m", p
);
102 if (major(st
.st_dev
) == 0) {
103 log_error("Block device node of %p is invalid.", p
);
107 t2
= strjoina(p
, "/..");
110 return log_error_errno(errno
, "Failed to determine block device node of parent of \"%s\": %m", p
);
112 if (st
.st_dev
== st2
.st_dev
) {
113 log_error("Directory \"%s\" is not the root of the EFI System Partition (ESP) file system.", p
);
117 /* In a container we don't have access to block devices, skip this part of the verification, we trust the
118 * container manager set everything up correctly on its own. */
119 if (detect_container() > 0)
122 r
= asprintf(&t
, "/dev/block/%u:%u", major(st
.st_dev
), minor(st
.st_dev
));
127 b
= blkid_new_probe_from_filename(t
);
129 return log_error_errno(errno
?: ENOMEM
, "Failed to open file system \"%s\": %m", p
);
131 blkid_probe_enable_superblocks(b
, 1);
132 blkid_probe_set_superblocks_flags(b
, BLKID_SUBLKS_TYPE
);
133 blkid_probe_enable_partitions(b
, 1);
134 blkid_probe_set_partitions_flags(b
, BLKID_PARTS_ENTRY_DETAILS
);
137 r
= blkid_do_safeprobe(b
);
139 log_error("File system \"%s\" is ambiguous.", p
);
142 log_error("File system \"%s\" does not contain a label.", p
);
145 return log_error_errno(errno
?: EIO
, "Failed to probe file system \"%s\": %m", p
);
148 r
= blkid_probe_lookup_value(b
, "TYPE", &v
, NULL
);
150 return log_error_errno(errno
?: EIO
, "Failed to probe file system type \"%s\": %m", p
);
151 if (!streq(v
, "vfat")) {
152 log_error("File system \"%s\" is not FAT.", p
);
157 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_SCHEME", &v
, NULL
);
159 return log_error_errno(errno
?: EIO
, "Failed to probe partition scheme \"%s\": %m", p
);
160 if (!streq(v
, "gpt")) {
161 log_error("File system \"%s\" is not on a GPT partition table.", p
);
166 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_TYPE", &v
, NULL
);
168 return log_error_errno(errno
?: EIO
, "Failed to probe partition type UUID \"%s\": %m", p
);
169 if (!streq(v
, "c12a7328-f81f-11d2-ba4b-00a0c93ec93b")) {
170 log_error("File system \"%s\" has wrong type for an EFI System Partition (ESP).", p
);
175 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_UUID", &v
, NULL
);
177 return log_error_errno(errno
?: EIO
, "Failed to probe partition entry UUID \"%s\": %m", p
);
178 r
= sd_id128_from_string(v
, &uuid
);
180 log_error("Partition \"%s\" has invalid UUID \"%s\".", p
, v
);
185 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_NUMBER", &v
, NULL
);
187 return log_error_errno(errno
?: EIO
, "Failed to probe partition number \"%s\": m", p
);
188 r
= safe_atou32(v
, &part
);
190 return log_error_errno(r
, "Failed to parse PART_ENTRY_NUMBER field.");
193 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_OFFSET", &v
, NULL
);
195 return log_error_errno(errno
?: EIO
, "Failed to probe partition offset \"%s\": %m", p
);
196 r
= safe_atou64(v
, &pstart
);
198 return log_error_errno(r
, "Failed to parse PART_ENTRY_OFFSET field.");
201 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_SIZE", &v
, NULL
);
203 return log_error_errno(errno
?: EIO
, "Failed to probe partition size \"%s\": %m", p
);
204 r
= safe_atou64(v
, &psize
);
206 return log_error_errno(r
, "Failed to parse PART_ENTRY_SIZE field.");
212 *ret_pstart
= pstart
;
221 static int find_esp(uint32_t *part
, uint64_t *pstart
, uint64_t *psize
, sd_id128_t
*uuid
) {
226 return verify_esp(false, arg_path
, part
, pstart
, psize
, uuid
);
228 FOREACH_STRING(path
, "/efi", "/boot", "/boot/efi") {
230 r
= verify_esp(true, path
, part
, pstart
, psize
, uuid
);
231 if (IN_SET(r
, -ENOENT
, -EADDRNOTAVAIL
)) /* This one is not it */
236 arg_path
= strdup(path
);
240 log_info("Using EFI System Partition at %s.", path
);
244 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.");
248 /* search for "#### LoaderInfo: systemd-boot 218 ####" string inside the binary */
249 static int get_file_version(int fd
, char **v
) {
259 if (fstat(fd
, &st
) < 0)
260 return log_error_errno(errno
, "Failed to stat EFI binary: %m");
262 if (st
.st_size
< 27) {
267 buf
= mmap(NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0);
268 if (buf
== MAP_FAILED
)
269 return log_error_errno(errno
, "Failed to memory map EFI binary: %m");
271 s
= memmem(buf
, st
.st_size
- 8, "#### LoaderInfo: ", 17);
276 e
= memmem(s
, st
.st_size
- (s
- buf
), " ####", 5);
277 if (!e
|| e
- s
< 3) {
278 log_error("Malformed version string.");
283 x
= strndup(s
, e
- s
);
291 (void) munmap(buf
, st
.st_size
);
296 static int enumerate_binaries(const char *esp_path
, const char *path
, const char *prefix
) {
298 _cleanup_closedir_
DIR *d
= NULL
;
302 p
= strjoina(esp_path
, "/", path
);
308 return log_error_errno(errno
, "Failed to read \"%s\": %m", p
);
311 FOREACH_DIRENT(de
, d
, break) {
312 _cleanup_close_
int fd
= -1;
313 _cleanup_free_
char *v
= NULL
;
315 if (!endswith_no_case(de
->d_name
, ".efi"))
318 if (prefix
&& !startswith_no_case(de
->d_name
, prefix
))
321 fd
= openat(dirfd(d
), de
->d_name
, O_RDONLY
|O_CLOEXEC
);
323 return log_error_errno(errno
, "Failed to open \"%s/%s\" for reading: %m", p
, de
->d_name
);
325 r
= get_file_version(fd
, &v
);
329 printf(" File: %s/%s/%s (%s)\n", special_glyph(TREE_RIGHT
), path
, de
->d_name
, v
);
331 printf(" File: %s/%s/%s\n", special_glyph(TREE_RIGHT
), path
, de
->d_name
);
338 static int status_binaries(const char *esp_path
, sd_id128_t partition
) {
341 printf("Boot Loader Binaries:\n");
343 printf(" ESP: /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(partition
));
345 r
= enumerate_binaries(esp_path
, "EFI/systemd", NULL
);
347 log_error("systemd-boot not installed in ESP.");
351 r
= enumerate_binaries(esp_path
, "EFI/BOOT", "boot");
353 log_error("No default/fallback boot loader installed in ESP.");
362 static int print_efi_option(uint16_t id
, bool in_order
) {
363 _cleanup_free_
char *title
= NULL
;
364 _cleanup_free_
char *path
= NULL
;
365 sd_id128_t partition
;
369 r
= efi_get_boot_option(id
, &title
, &partition
, &path
, &active
);
373 /* print only configured entries with partition information */
374 if (!path
|| sd_id128_is_null(partition
))
377 efi_tilt_backslashes(path
);
379 printf(" Title: %s\n", strna(title
));
380 printf(" ID: 0x%04X\n", id
);
381 printf(" Status: %sactive%s\n", active
? "" : "in", in_order
? ", boot-order" : "");
382 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(partition
));
383 printf(" File: %s%s\n", special_glyph(TREE_RIGHT
), path
);
389 static int status_variables(void) {
390 int n_options
, n_order
;
391 _cleanup_free_
uint16_t *options
= NULL
, *order
= NULL
;
394 if (!is_efi_boot()) {
395 log_notice("Not booted with EFI, not showing EFI variables.");
399 n_options
= efi_get_boot_options(&options
);
400 if (n_options
== -ENOENT
)
401 return log_error_errno(n_options
,
402 "Failed to access EFI variables, efivarfs"
403 " needs to be available at /sys/firmware/efi/efivars/.");
405 return log_error_errno(n_options
, "Failed to read EFI boot entries: %m");
407 n_order
= efi_get_boot_order(&order
);
408 if (n_order
== -ENOENT
)
410 else if (n_order
< 0)
411 return log_error_errno(n_order
, "Failed to read EFI boot order.");
413 /* print entries in BootOrder first */
414 printf("Boot Loader Entries in EFI Variables:\n");
415 for (i
= 0; i
< n_order
; i
++)
416 print_efi_option(order
[i
], true);
418 /* print remaining entries */
419 for (i
= 0; i
< n_options
; i
++) {
422 for (j
= 0; j
< n_order
; j
++)
423 if (options
[i
] == order
[j
])
426 print_efi_option(options
[i
], false);
435 static int compare_product(const char *a
, const char *b
) {
444 return x
< y
? -1 : x
> y
? 1 : 0;
446 return strncmp(a
, b
, x
);
449 static int compare_version(const char *a
, const char *b
) {
453 a
+= strcspn(a
, " ");
455 b
+= strcspn(b
, " ");
458 return strverscmp(a
, b
);
461 static int version_check(int fd_from
, const char *from
, int fd_to
, const char *to
) {
462 _cleanup_free_
char *a
= NULL
, *b
= NULL
;
465 assert(fd_from
>= 0);
470 r
= get_file_version(fd_from
, &a
);
474 log_error("Source file \"%s\" does not carry version information!", from
);
478 r
= get_file_version(fd_to
, &b
);
481 if (r
== 0 || compare_product(a
, b
) != 0) {
482 log_notice("Skipping \"%s\", since it's owned by another boot loader.", to
);
486 if (compare_version(a
, b
) < 0) {
487 log_warning("Skipping \"%s\", since a newer boot loader version exists already.", to
);
494 static int copy_file_with_version_check(const char *from
, const char *to
, bool force
) {
495 _cleanup_close_
int fd_from
= -1, fd_to
= -1;
496 _cleanup_free_
char *t
= NULL
;
499 fd_from
= open(from
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
501 return log_error_errno(errno
, "Failed to open \"%s\" for reading: %m", from
);
504 fd_to
= open(to
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
506 if (errno
!= -ENOENT
)
507 return log_error_errno(errno
, "Failed to open \"%s\" for reading: %m", to
);
509 r
= version_check(fd_from
, from
, fd_to
, to
);
513 if (lseek(fd_from
, 0, SEEK_SET
) == (off_t
) -1)
514 return log_error_errno(errno
, "Failed to seek in \%s\": %m", from
);
516 fd_to
= safe_close(fd_to
);
520 r
= tempfn_random(to
, NULL
, &t
);
524 RUN_WITH_UMASK(0000) {
525 fd_to
= open(t
, O_WRONLY
|O_CREAT
|O_CLOEXEC
|O_EXCL
|O_NOFOLLOW
, 0644);
527 return log_error_errno(errno
, "Failed to open \"%s\" for writing: %m", t
);
530 r
= copy_bytes(fd_from
, fd_to
, (uint64_t) -1, COPY_REFLINK
);
533 return log_error_errno(errno
, "Failed to copy data from \"%s\" to \"%s\": %m", from
, t
);
536 (void) copy_times(fd_from
, fd_to
);
538 r
= renameat(AT_FDCWD
, t
, AT_FDCWD
, to
);
540 (void) unlink_noerrno(t
);
541 return log_error_errno(errno
, "Failed to rename \"%s\" to \"%s\": %m", t
, to
);
544 log_info("Copied \"%s\" to \"%s\".", from
, to
);
549 static int mkdir_one(const char *prefix
, const char *suffix
) {
552 p
= strjoina(prefix
, "/", suffix
);
553 if (mkdir(p
, 0700) < 0) {
555 return log_error_errno(errno
, "Failed to create \"%s\": %m", p
);
557 log_info("Created \"%s\".", p
);
562 static const char *efi_subdirs
[] = {
571 static int create_dirs(const char *esp_path
) {
575 STRV_FOREACH(i
, efi_subdirs
) {
576 r
= mkdir_one(esp_path
, *i
);
584 static int copy_one_file(const char *esp_path
, const char *name
, bool force
) {
588 p
= strjoina(BOOTLIBDIR
"/", name
);
589 q
= strjoina(esp_path
, "/EFI/systemd/", name
);
590 r
= copy_file_with_version_check(p
, q
, force
);
592 if (startswith(name
, "systemd-boot")) {
596 /* Create the EFI default boot loader name (specified for removable devices) */
597 v
= strjoina(esp_path
, "/EFI/BOOT/BOOT", name
+ strlen("systemd-boot"));
598 ascii_strupper(strrchr(v
, '/') + 1);
600 k
= copy_file_with_version_check(p
, v
, force
);
608 static int install_binaries(const char *esp_path
, bool force
) {
610 _cleanup_closedir_
DIR *d
= NULL
;
614 /* Don't create any of these directories when we are
615 * just updating. When we update we'll drop-in our
616 * files (unless there are newer ones already), but we
617 * won't create the directories for them in the first
619 r
= create_dirs(esp_path
);
624 d
= opendir(BOOTLIBDIR
);
626 return log_error_errno(errno
, "Failed to open \""BOOTLIBDIR
"\": %m
");
628 FOREACH_DIRENT(de, d, break) {
631 if (!endswith_no_case(de->d_name, ".efi
"))
634 k = copy_one_file(esp_path, de->d_name, force);
642 static bool same_entry(uint16_t id, const sd_id128_t uuid, const char *path) {
643 _cleanup_free_ char *opath = NULL;
647 r = efi_get_boot_option(id, NULL, &ouuid, &opath, NULL);
650 if (!sd_id128_equal(uuid, ouuid))
652 if (!streq_ptr(path, opath))
658 static int find_slot(sd_id128_t uuid, const char *path, uint16_t *id) {
659 _cleanup_free_ uint16_t *options = NULL;
662 n = efi_get_boot_options(&options);
666 /* find already existing systemd-boot entry */
667 for (i = 0; i < n; i++)
668 if (same_entry(options[i], uuid, path)) {
673 /* find free slot in the sorted BootXXXX variable list */
674 for (i = 0; i < n; i++)
675 if (i != options[i]) {
680 /* use the next one */
687 static int insert_into_order(uint16_t slot, bool first) {
688 _cleanup_free_ uint16_t *order = NULL;
692 n = efi_get_boot_order(&order);
694 /* no entry, add us */
695 return efi_set_boot_order(&slot, 1);
697 /* are we the first and only one? */
698 if (n == 1 && order[0] == slot)
701 /* are we already in the boot order? */
702 for (i = 0; i < n; i++) {
703 if (order[i] != slot)
706 /* we do not require to be the first one, all is fine */
710 /* move us to the first slot */
711 memmove(order + 1, order, i * sizeof(uint16_t));
713 return efi_set_boot_order(order, n);
717 t = realloc(order, (n + 1) * sizeof(uint16_t));
722 /* add us to the top or end of the list */
724 memmove(order + 1, order, n * sizeof(uint16_t));
729 return efi_set_boot_order(order, n + 1);
732 static int remove_from_order(uint16_t slot) {
733 _cleanup_free_ uint16_t *order = NULL;
736 n = efi_get_boot_order(&order);
740 for (i = 0; i < n; i++) {
741 if (order[i] != slot)
745 memmove(order + i, order + i+1, (n - i) * sizeof(uint16_t));
746 return efi_set_boot_order(order, n - 1);
752 static int install_variables(const char *esp_path,
753 uint32_t part, uint64_t pstart, uint64_t psize,
754 sd_id128_t uuid, const char *path,
760 if (!is_efi_boot()) {
761 log_warning("Not booted with EFI
, skipping EFI variable setup
.");
765 p = strjoina(esp_path, path);
766 if (access(p, F_OK) < 0) {
770 return log_error_errno(errno, "Cannot access
\"%s
\": %m
", p);
773 r = find_slot(uuid, path, &slot);
775 return log_error_errno(r,
777 "Failed to access EFI variables
. Is the
\"efivarfs
\" filesystem mounted
?" :
778 "Failed to determine current boot order
: %m
");
780 if (first || r == 0) {
781 r = efi_add_boot_option(slot, "Linux Boot Manager
",
785 return log_error_errno(r, "Failed to create EFI Boot variable entry
: %m
");
787 log_info("Created EFI boot entry
\"Linux Boot Manager
\".");
790 return insert_into_order(slot, first);
793 static int remove_boot_efi(const char *esp_path) {
795 _cleanup_closedir_ DIR *d = NULL;
799 p = strjoina(esp_path, "/EFI
/BOOT
");
805 return log_error_errno(errno, "Failed to open directory
\"%s
\": %m
", p);
808 FOREACH_DIRENT(de, d, break) {
809 _cleanup_close_ int fd = -1;
810 _cleanup_free_ char *v = NULL;
812 if (!endswith_no_case(de->d_name, ".efi
"))
815 if (!startswith_no_case(de->d_name, "boot
"))
818 fd = openat(dirfd(d), de->d_name, O_RDONLY|O_CLOEXEC);
820 return log_error_errno(errno, "Failed to open
\"%s
/%s
\" for reading
: %m
", p, de->d_name);
822 r = get_file_version(fd, &v);
825 if (r > 0 && startswith(v, "systemd
-boot
")) {
826 r = unlinkat(dirfd(d), de->d_name, 0);
828 return log_error_errno(errno, "Failed to remove
\"%s
/%s
\": %m
", p, de->d_name);
830 log_info("Removed
\"%s
/%s
\".", p, de->d_name);
839 static int rmdir_one(const char *prefix, const char *suffix) {
842 p = strjoina(prefix, "/", suffix);
844 if (!IN_SET(errno, ENOENT, ENOTEMPTY))
845 return log_error_errno(errno, "Failed to remove
\"%s
\": %m
", p);
847 log_info("Removed
\"%s
\".", p);
852 static int remove_binaries(const char *esp_path) {
857 p = strjoina(esp_path, "/EFI
/systemd
");
858 r = rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL);
860 q = remove_boot_efi(esp_path);
864 for (i = ELEMENTSOF(efi_subdirs)-1; i > 0; i--) {
865 q = rmdir_one(esp_path, efi_subdirs[i-1]);
873 static int remove_variables(sd_id128_t uuid, const char *path, bool in_order) {
880 r = find_slot(uuid, path, &slot);
884 r = efi_remove_boot_option(slot);
889 return remove_from_order(slot);
894 static int install_loader_config(const char *esp_path) {
896 char machine_string[SD_ID128_STRING_MAX];
897 _cleanup_(unlink_and_freep) char *t = NULL;
898 _cleanup_fclose_ FILE *f = NULL;
899 sd_id128_t machine_id;
903 r = sd_id128_get_machine(&machine_id);
905 return log_error_errno(r, "Failed to get machine did
: %m
");
907 p = strjoina(esp_path, "/loader
/loader
.conf
");
909 if (access(p, F_OK) >= 0) /* Silently skip creation if the file already exists (early check) */
912 fd = open_tmpfile_linkable(p, O_WRONLY|O_CLOEXEC, &t);
914 return log_error_errno(fd, "Failed to open
\"%s
\" for writing
: %m
", p);
916 f = fdopen(fd, "we
");
922 fprintf(f, "#timeout 3\n");
923 fprintf(f, "default %s-*\n", sd_id128_to_string(machine_id, machine_string));
925 r = fflush_and_check(f);
927 return log_error_errno(r, "Failed to write \"%s\": %m", p);
929 r = link_tmpfile(fd, t, p);
931 return 0; /* Silently skip creation if the file exists now (recheck) */
933 return log_error_errno(r, "Failed to move \"%s\" into place: %m", p);
940 static int help(int argc, char *argv[], void *userdata) {
942 printf("%s [COMMAND] [OPTIONS...]\n"
944 "Install, update or remove the systemd-boot EFI boot manager.\n\n"
945 " -h --help Show this help\n"
946 " --version Print version\n"
947 " --path=PATH Path to the EFI System Partition (ESP)\n"
948 " --no-variables Don't touch EFI variables\n"
951 " status Show status of installed systemd-boot and EFI variables\n"
952 " install Install systemd-boot to the ESP and EFI variables\n"
953 " update Update systemd-boot in the ESP and EFI variables\n"
954 " remove Remove systemd-boot from the ESP and EFI variables\n",
955 program_invocation_short_name);
960 static int parse_argv(int argc, char *argv[]) {
967 static const struct option options[] = {
968 { "help", no_argument, NULL, 'h' },
969 { "version", no_argument, NULL, ARG_VERSION },
970 { "path", required_argument, NULL, ARG_PATH },
971 { "no-variables", no_argument, NULL, ARG_NO_VARIABLES },
980 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
991 r = free_and_strdup(&arg_path, optarg);
996 case ARG_NO_VARIABLES:
997 arg_touch_variables = false;
1004 assert_not_reached("Unknown option");
1010 static void read_loader_efi_var(const char *name, char **var) {
1013 r = efi_get_variable_string(EFI_VENDOR_LOADER, name, var);
1014 if (r < 0 && r != -ENOENT)
1015 log_warning_errno(r, "Failed to read EFI variable %s: %m", name);
1018 static int must_be_root(void) {
1023 log_error("Need to be root.");
1027 static int verb_status(int argc, char *argv[], void *userdata) {
1029 sd_id128_t uuid = SD_ID128_NULL;
1036 r = find_esp(NULL, NULL, NULL, &uuid);
1040 if (is_efi_boot()) {
1041 _cleanup_free_ char *fw_type = NULL, *fw_info = NULL, *loader = NULL, *loader_path = NULL;
1042 sd_id128_t loader_part_uuid = SD_ID128_NULL;
1044 read_loader_efi_var("LoaderFirmwareType", &fw_type);
1045 read_loader_efi_var("LoaderFirmwareInfo", &fw_info);
1046 read_loader_efi_var("LoaderInfo", &loader);
1047 read_loader_efi_var("LoaderImageIdentifier", &loader_path);
1050 efi_tilt_backslashes(loader_path);
1052 r = efi_loader_get_device_part_uuid(&loader_part_uuid);
1053 if (r < 0 && r != -ENOENT)
1054 log_warning_errno(r, "Failed to read EFI variable LoaderDevicePartUUID: %m");
1056 printf("System:\n");
1057 printf(" Firmware: %s (%s)\n", strna(fw_type), strna(fw_info));
1059 r = is_efi_secure_boot();
1061 log_warning_errno(r, "Failed to query secure boot status: %m");
1063 printf(" Secure Boot: %sd\n", enable_disable(r));
1065 r = is_efi_secure_boot_setup_mode();
1067 log_warning_errno(r, "Failed to query secure boot mode: %m");
1069 printf(" Setup Mode: %s\n", r ? "setup" : "user");
1072 printf("Loader:\n");
1073 printf(" Product: %s\n", strna(loader));
1074 if (!sd_id128_is_null(loader_part_uuid))
1075 printf(" Partition: /dev/disk/by-partuuid/%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
1076 SD_ID128_FORMAT_VAL(loader_part_uuid));
1078 printf(" Partition: n/a\n");
1079 printf(" File: %s%s\n", special_glyph(TREE_RIGHT), strna(loader_path));
1082 printf("System:\n Not booted with EFI\n");
1084 r = status_binaries(arg_path, uuid);
1088 if (arg_touch_variables)
1089 r = status_variables();
1094 static int verb_install(int argc, char *argv[], void *userdata) {
1096 sd_id128_t uuid = SD_ID128_NULL;
1097 uint64_t pstart = 0, psize = 0;
1106 r = find_esp(&part, &pstart, &psize, &uuid);
1110 install = streq(argv[0], "install");
1112 RUN_WITH_UMASK(0002) {
1113 r = install_binaries(arg_path, install);
1118 r = install_loader_config(arg_path);
1124 if (arg_touch_variables)
1125 r = install_variables(arg_path,
1126 part, pstart, psize, uuid,
1127 "/EFI/systemd/systemd-boot" EFI_MACHINE_TYPE_NAME ".efi",
1133 static int verb_remove(int argc, char *argv[], void *userdata) {
1134 sd_id128_t uuid = SD_ID128_NULL;
1141 r = find_esp(NULL, NULL, NULL, &uuid);
1145 r = remove_binaries(arg_path);
1147 if (arg_touch_variables) {
1150 q = remove_variables(uuid, "/EFI/systemd/systemd-boot" EFI_MACHINE_TYPE_NAME ".efi", true);
1151 if (q < 0 && r == 0)
1158 static int bootctl_main(int argc, char *argv[]) {
1160 static const Verb verbs[] = {
1161 { "help", VERB_ANY, VERB_ANY, 0, help },
1162 { "status", VERB_ANY, 1, VERB_DEFAULT, verb_status },
1163 { "install", VERB_ANY, 1, 0, verb_install },
1164 { "update", VERB_ANY, 1, 0, verb_install },
1165 { "remove", VERB_ANY, 1, 0, verb_remove },
1169 return dispatch_verb(argc, argv, verbs, NULL);
1172 int main(int argc, char *argv[]) {
1175 log_parse_environment();
1178 /* If we run in a container, automatically turn of EFI file system access */
1179 if (detect_container() > 0)
1180 arg_touch_variables = false;
1182 r = parse_argv(argc, argv);
1186 r = bootctl_main(argc, argv);
1190 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;