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/>.
28 #include <linux/magic.h>
35 #include <sys/statfs.h>
38 #include "alloc-util.h"
39 #include "blkid-util.h"
41 #include "dirent-util.h"
46 #include "locale-util.h"
47 #include "parse-util.h"
49 #include "stat-util.h"
50 #include "string-util.h"
52 #include "umask-util.h"
57 static char *arg_path
= NULL
;
58 static bool arg_touch_variables
= true;
60 static int verify_esp(
66 sd_id128_t
*ret_uuid
) {
68 _cleanup_blkid_free_probe_ blkid_probe b
= NULL
;
69 _cleanup_free_
char *t
= NULL
;
70 uint64_t pstart
= 0, psize
= 0;
74 sd_id128_t uuid
= SD_ID128_NULL
;
81 /* Non-root user can run only `bootctl status`, then if error occured in the following, it does not cause any issues.
82 * So, let's silence the error messages. */
83 quiet
= (geteuid() != 0);
85 if (statfs(p
, &sfs
) < 0) {
87 /* If we are searching for the mount point, don't generate a log message if we can't find the path */
88 if (errno
== ENOENT
&& searching
)
91 return log_full_errno(quiet
&& errno
== EACCES
? LOG_DEBUG
: LOG_ERR
, errno
,
92 "Failed to check file system type of \"%s\": %m", p
);
95 if (!F_TYPE_EQUAL(sfs
.f_type
, MSDOS_SUPER_MAGIC
)) {
98 return -EADDRNOTAVAIL
;
100 log_error("File system \"%s\" is not a FAT EFI System Partition (ESP) file system.", p
);
104 if (stat(p
, &st
) < 0)
105 return log_full_errno(quiet
&& errno
== EACCES
? LOG_DEBUG
: LOG_ERR
, errno
,
106 "Failed to determine block device node of \"%s\": %m", p
);
108 if (major(st
.st_dev
) == 0) {
109 log_error("Block device node of %p is invalid.", p
);
113 t2
= strjoina(p
, "/..");
116 return log_full_errno(quiet
&& errno
== EACCES
? LOG_DEBUG
: LOG_ERR
, errno
,
117 "Failed to determine block device node of parent of \"%s\": %m", p
);
119 if (st
.st_dev
== st2
.st_dev
) {
120 log_error("Directory \"%s\" is not the root of the EFI System Partition (ESP) file system.", p
);
124 /* In a container we don't have access to block devices, skip this part of the verification, we trust the
125 * container manager set everything up correctly on its own. Also skip the following verification for non-root user. */
126 if (detect_container() > 0 || geteuid() != 0)
129 r
= asprintf(&t
, "/dev/block/%u:%u", major(st
.st_dev
), minor(st
.st_dev
));
134 b
= blkid_new_probe_from_filename(t
);
136 return log_error_errno(errno
?: ENOMEM
, "Failed to open file system \"%s\": %m", p
);
138 blkid_probe_enable_superblocks(b
, 1);
139 blkid_probe_set_superblocks_flags(b
, BLKID_SUBLKS_TYPE
);
140 blkid_probe_enable_partitions(b
, 1);
141 blkid_probe_set_partitions_flags(b
, BLKID_PARTS_ENTRY_DETAILS
);
144 r
= blkid_do_safeprobe(b
);
146 log_error("File system \"%s\" is ambiguous.", p
);
149 log_error("File system \"%s\" does not contain a label.", p
);
152 return log_error_errno(errno
?: EIO
, "Failed to probe file system \"%s\": %m", p
);
155 r
= blkid_probe_lookup_value(b
, "TYPE", &v
, NULL
);
157 return log_error_errno(errno
?: EIO
, "Failed to probe file system type \"%s\": %m", p
);
158 if (!streq(v
, "vfat")) {
159 log_error("File system \"%s\" is not FAT.", p
);
164 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_SCHEME", &v
, NULL
);
166 return log_error_errno(errno
?: EIO
, "Failed to probe partition scheme \"%s\": %m", p
);
167 if (!streq(v
, "gpt")) {
168 log_error("File system \"%s\" is not on a GPT partition table.", p
);
173 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_TYPE", &v
, NULL
);
175 return log_error_errno(errno
?: EIO
, "Failed to probe partition type UUID \"%s\": %m", p
);
176 if (!streq(v
, "c12a7328-f81f-11d2-ba4b-00a0c93ec93b")) {
177 log_error("File system \"%s\" has wrong type for an EFI System Partition (ESP).", p
);
182 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_UUID", &v
, NULL
);
184 return log_error_errno(errno
?: EIO
, "Failed to probe partition entry UUID \"%s\": %m", p
);
185 r
= sd_id128_from_string(v
, &uuid
);
187 log_error("Partition \"%s\" has invalid UUID \"%s\".", p
, v
);
192 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_NUMBER", &v
, NULL
);
194 return log_error_errno(errno
?: EIO
, "Failed to probe partition number \"%s\": m", p
);
195 r
= safe_atou32(v
, &part
);
197 return log_error_errno(r
, "Failed to parse PART_ENTRY_NUMBER field.");
200 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_OFFSET", &v
, NULL
);
202 return log_error_errno(errno
?: EIO
, "Failed to probe partition offset \"%s\": %m", p
);
203 r
= safe_atou64(v
, &pstart
);
205 return log_error_errno(r
, "Failed to parse PART_ENTRY_OFFSET field.");
208 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_SIZE", &v
, NULL
);
210 return log_error_errno(errno
?: EIO
, "Failed to probe partition size \"%s\": %m", p
);
211 r
= safe_atou64(v
, &psize
);
213 return log_error_errno(r
, "Failed to parse PART_ENTRY_SIZE field.");
219 *ret_pstart
= pstart
;
228 static int find_esp(uint32_t *part
, uint64_t *pstart
, uint64_t *psize
, sd_id128_t
*uuid
) {
233 return verify_esp(false, arg_path
, part
, pstart
, psize
, uuid
);
235 FOREACH_STRING(path
, "/efi", "/boot", "/boot/efi") {
237 r
= verify_esp(true, path
, part
, pstart
, psize
, uuid
);
238 if (IN_SET(r
, -ENOENT
, -EADDRNOTAVAIL
)) /* This one is not it */
243 arg_path
= strdup(path
);
247 log_info("Using EFI System Partition at %s.", path
);
251 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.");
255 /* search for "#### LoaderInfo: systemd-boot 218 ####" string inside the binary */
256 static int get_file_version(int fd
, char **v
) {
266 if (fstat(fd
, &st
) < 0)
267 return log_error_errno(errno
, "Failed to stat EFI binary: %m");
269 if (st
.st_size
< 27) {
274 buf
= mmap(NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0);
275 if (buf
== MAP_FAILED
)
276 return log_error_errno(errno
, "Failed to memory map EFI binary: %m");
278 s
= memmem(buf
, st
.st_size
- 8, "#### LoaderInfo: ", 17);
283 e
= memmem(s
, st
.st_size
- (s
- buf
), " ####", 5);
284 if (!e
|| e
- s
< 3) {
285 log_error("Malformed version string.");
290 x
= strndup(s
, e
- s
);
298 (void) munmap(buf
, st
.st_size
);
303 static int enumerate_binaries(const char *esp_path
, const char *path
, const char *prefix
) {
305 _cleanup_closedir_
DIR *d
= NULL
;
309 p
= strjoina(esp_path
, "/", path
);
315 return log_error_errno(errno
, "Failed to read \"%s\": %m", p
);
318 FOREACH_DIRENT(de
, d
, break) {
319 _cleanup_close_
int fd
= -1;
320 _cleanup_free_
char *v
= NULL
;
322 if (!endswith_no_case(de
->d_name
, ".efi"))
325 if (prefix
&& !startswith_no_case(de
->d_name
, prefix
))
328 fd
= openat(dirfd(d
), de
->d_name
, O_RDONLY
|O_CLOEXEC
);
330 return log_error_errno(errno
, "Failed to open \"%s/%s\" for reading: %m", p
, de
->d_name
);
332 r
= get_file_version(fd
, &v
);
336 printf(" File: %s/%s/%s (%s)\n", special_glyph(TREE_RIGHT
), path
, de
->d_name
, v
);
338 printf(" File: %s/%s/%s\n", special_glyph(TREE_RIGHT
), path
, de
->d_name
);
345 static int status_binaries(const char *esp_path
, sd_id128_t partition
) {
348 printf("Boot Loader Binaries:\n");
351 printf(" ESP: Cannot find or access mount point of ESP.\n\n");
355 printf(" ESP: %s", esp_path
);
356 if (!sd_id128_is_null(partition
))
357 printf(" (/dev/disk/by-partuuid/%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x)", SD_ID128_FORMAT_VAL(partition
));
360 r
= enumerate_binaries(esp_path
, "EFI/systemd", NULL
);
362 log_error("systemd-boot not installed in ESP.");
366 r
= enumerate_binaries(esp_path
, "EFI/BOOT", "boot");
368 log_error("No default/fallback boot loader installed in ESP.");
377 static int print_efi_option(uint16_t id
, bool in_order
) {
378 _cleanup_free_
char *title
= NULL
;
379 _cleanup_free_
char *path
= NULL
;
380 sd_id128_t partition
;
384 r
= efi_get_boot_option(id
, &title
, &partition
, &path
, &active
);
388 /* print only configured entries with partition information */
389 if (!path
|| sd_id128_is_null(partition
))
392 efi_tilt_backslashes(path
);
394 printf(" Title: %s\n", strna(title
));
395 printf(" ID: 0x%04X\n", id
);
396 printf(" Status: %sactive%s\n", active
? "" : "in", in_order
? ", boot-order" : "");
397 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
));
398 printf(" File: %s%s\n", special_glyph(TREE_RIGHT
), path
);
404 static int status_variables(void) {
405 int n_options
, n_order
;
406 _cleanup_free_
uint16_t *options
= NULL
, *order
= NULL
;
409 n_options
= efi_get_boot_options(&options
);
410 if (n_options
== -ENOENT
)
411 return log_error_errno(n_options
,
412 "Failed to access EFI variables, efivarfs"
413 " needs to be available at /sys/firmware/efi/efivars/.");
415 return log_error_errno(n_options
, "Failed to read EFI boot entries: %m");
417 n_order
= efi_get_boot_order(&order
);
418 if (n_order
== -ENOENT
)
420 else if (n_order
< 0)
421 return log_error_errno(n_order
, "Failed to read EFI boot order.");
423 /* print entries in BootOrder first */
424 printf("Boot Loader Entries in EFI Variables:\n");
425 for (i
= 0; i
< n_order
; i
++)
426 print_efi_option(order
[i
], true);
428 /* print remaining entries */
429 for (i
= 0; i
< n_options
; i
++) {
432 for (j
= 0; j
< n_order
; j
++)
433 if (options
[i
] == order
[j
])
436 print_efi_option(options
[i
], false);
445 static int compare_product(const char *a
, const char *b
) {
454 return x
< y
? -1 : x
> y
? 1 : 0;
456 return strncmp(a
, b
, x
);
459 static int compare_version(const char *a
, const char *b
) {
463 a
+= strcspn(a
, " ");
465 b
+= strcspn(b
, " ");
468 return strverscmp(a
, b
);
471 static int version_check(int fd_from
, const char *from
, int fd_to
, const char *to
) {
472 _cleanup_free_
char *a
= NULL
, *b
= NULL
;
475 assert(fd_from
>= 0);
480 r
= get_file_version(fd_from
, &a
);
484 log_error("Source file \"%s\" does not carry version information!", from
);
488 r
= get_file_version(fd_to
, &b
);
491 if (r
== 0 || compare_product(a
, b
) != 0) {
492 log_notice("Skipping \"%s\", since it's owned by another boot loader.", to
);
496 if (compare_version(a
, b
) < 0) {
497 log_warning("Skipping \"%s\", since a newer boot loader version exists already.", to
);
504 static int copy_file_with_version_check(const char *from
, const char *to
, bool force
) {
505 _cleanup_close_
int fd_from
= -1, fd_to
= -1;
506 _cleanup_free_
char *t
= NULL
;
509 fd_from
= open(from
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
511 return log_error_errno(errno
, "Failed to open \"%s\" for reading: %m", from
);
514 fd_to
= open(to
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
516 if (errno
!= -ENOENT
)
517 return log_error_errno(errno
, "Failed to open \"%s\" for reading: %m", to
);
519 r
= version_check(fd_from
, from
, fd_to
, to
);
523 if (lseek(fd_from
, 0, SEEK_SET
) == (off_t
) -1)
524 return log_error_errno(errno
, "Failed to seek in \%s\": %m", from
);
526 fd_to
= safe_close(fd_to
);
530 r
= tempfn_random(to
, NULL
, &t
);
534 RUN_WITH_UMASK(0000) {
535 fd_to
= open(t
, O_WRONLY
|O_CREAT
|O_CLOEXEC
|O_EXCL
|O_NOFOLLOW
, 0644);
537 return log_error_errno(errno
, "Failed to open \"%s\" for writing: %m", t
);
540 r
= copy_bytes(fd_from
, fd_to
, (uint64_t) -1, COPY_REFLINK
);
543 return log_error_errno(r
, "Failed to copy data from \"%s\" to \"%s\": %m", from
, t
);
546 (void) copy_times(fd_from
, fd_to
);
550 (void) unlink_noerrno(t
);
551 return log_error_errno(errno
, "Failed to copy data from \"%s\" to \"%s\": %m", from
, t
);
554 r
= renameat(AT_FDCWD
, t
, AT_FDCWD
, to
);
556 (void) unlink_noerrno(t
);
557 return log_error_errno(errno
, "Failed to rename \"%s\" to \"%s\": %m", t
, to
);
560 log_info("Copied \"%s\" to \"%s\".", from
, to
);
565 static int mkdir_one(const char *prefix
, const char *suffix
) {
568 p
= strjoina(prefix
, "/", suffix
);
569 if (mkdir(p
, 0700) < 0) {
571 return log_error_errno(errno
, "Failed to create \"%s\": %m", p
);
573 log_info("Created \"%s\".", p
);
578 static const char *efi_subdirs
[] = {
587 static int create_dirs(const char *esp_path
) {
591 STRV_FOREACH(i
, efi_subdirs
) {
592 r
= mkdir_one(esp_path
, *i
);
600 static int copy_one_file(const char *esp_path
, const char *name
, bool force
) {
604 p
= strjoina(BOOTLIBDIR
"/", name
);
605 q
= strjoina(esp_path
, "/EFI/systemd/", name
);
606 r
= copy_file_with_version_check(p
, q
, force
);
608 if (startswith(name
, "systemd-boot")) {
612 /* Create the EFI default boot loader name (specified for removable devices) */
613 v
= strjoina(esp_path
, "/EFI/BOOT/BOOT", name
+ strlen("systemd-boot"));
614 ascii_strupper(strrchr(v
, '/') + 1);
616 k
= copy_file_with_version_check(p
, v
, force
);
624 static int install_binaries(const char *esp_path
, bool force
) {
626 _cleanup_closedir_
DIR *d
= NULL
;
630 /* Don't create any of these directories when we are
631 * just updating. When we update we'll drop-in our
632 * files (unless there are newer ones already), but we
633 * won't create the directories for them in the first
635 r
= create_dirs(esp_path
);
640 d
= opendir(BOOTLIBDIR
);
642 return log_error_errno(errno
, "Failed to open \""BOOTLIBDIR
"\": %m
");
644 FOREACH_DIRENT(de, d, break) {
647 if (!endswith_no_case(de->d_name, ".efi
"))
650 k = copy_one_file(esp_path, de->d_name, force);
658 static bool same_entry(uint16_t id, const sd_id128_t uuid, const char *path) {
659 _cleanup_free_ char *opath = NULL;
663 r = efi_get_boot_option(id, NULL, &ouuid, &opath, NULL);
666 if (!sd_id128_equal(uuid, ouuid))
668 if (!streq_ptr(path, opath))
674 static int find_slot(sd_id128_t uuid, const char *path, uint16_t *id) {
675 _cleanup_free_ uint16_t *options = NULL;
678 n = efi_get_boot_options(&options);
682 /* find already existing systemd-boot entry */
683 for (i = 0; i < n; i++)
684 if (same_entry(options[i], uuid, path)) {
689 /* find free slot in the sorted BootXXXX variable list */
690 for (i = 0; i < n; i++)
691 if (i != options[i]) {
696 /* use the next one */
703 static int insert_into_order(uint16_t slot, bool first) {
704 _cleanup_free_ uint16_t *order = NULL;
708 n = efi_get_boot_order(&order);
710 /* no entry, add us */
711 return efi_set_boot_order(&slot, 1);
713 /* are we the first and only one? */
714 if (n == 1 && order[0] == slot)
717 /* are we already in the boot order? */
718 for (i = 0; i < n; i++) {
719 if (order[i] != slot)
722 /* we do not require to be the first one, all is fine */
726 /* move us to the first slot */
727 memmove(order + 1, order, i * sizeof(uint16_t));
729 return efi_set_boot_order(order, n);
733 t = realloc(order, (n + 1) * sizeof(uint16_t));
738 /* add us to the top or end of the list */
740 memmove(order + 1, order, n * sizeof(uint16_t));
745 return efi_set_boot_order(order, n + 1);
748 static int remove_from_order(uint16_t slot) {
749 _cleanup_free_ uint16_t *order = NULL;
752 n = efi_get_boot_order(&order);
756 for (i = 0; i < n; i++) {
757 if (order[i] != slot)
761 memmove(order + i, order + i+1, (n - i) * sizeof(uint16_t));
762 return efi_set_boot_order(order, n - 1);
768 static int install_variables(const char *esp_path,
769 uint32_t part, uint64_t pstart, uint64_t psize,
770 sd_id128_t uuid, const char *path,
776 if (!is_efi_boot()) {
777 log_warning("Not booted with EFI
, skipping EFI variable setup
.");
781 p = strjoina(esp_path, path);
782 if (access(p, F_OK) < 0) {
786 return log_error_errno(errno, "Cannot access
\"%s
\": %m
", p);
789 r = find_slot(uuid, path, &slot);
791 return log_error_errno(r,
793 "Failed to access EFI variables
. Is the
\"efivarfs
\" filesystem mounted
?" :
794 "Failed to determine current boot order
: %m
");
796 if (first || r == 0) {
797 r = efi_add_boot_option(slot, "Linux Boot Manager
",
801 return log_error_errno(r, "Failed to create EFI Boot variable entry
: %m
");
803 log_info("Created EFI boot entry
\"Linux Boot Manager
\".");
806 return insert_into_order(slot, first);
809 static int remove_boot_efi(const char *esp_path) {
811 _cleanup_closedir_ DIR *d = NULL;
815 p = strjoina(esp_path, "/EFI
/BOOT
");
821 return log_error_errno(errno, "Failed to open directory
\"%s
\": %m
", p);
824 FOREACH_DIRENT(de, d, break) {
825 _cleanup_close_ int fd = -1;
826 _cleanup_free_ char *v = NULL;
828 if (!endswith_no_case(de->d_name, ".efi
"))
831 if (!startswith_no_case(de->d_name, "boot
"))
834 fd = openat(dirfd(d), de->d_name, O_RDONLY|O_CLOEXEC);
836 return log_error_errno(errno, "Failed to open
\"%s
/%s
\" for reading
: %m
", p, de->d_name);
838 r = get_file_version(fd, &v);
841 if (r > 0 && startswith(v, "systemd
-boot
")) {
842 r = unlinkat(dirfd(d), de->d_name, 0);
844 return log_error_errno(errno, "Failed to remove
\"%s
/%s
\": %m
", p, de->d_name);
846 log_info("Removed
\"%s
/%s
\".", p, de->d_name);
855 static int rmdir_one(const char *prefix, const char *suffix) {
858 p = strjoina(prefix, "/", suffix);
860 if (!IN_SET(errno, ENOENT, ENOTEMPTY))
861 return log_error_errno(errno, "Failed to remove
\"%s
\": %m
", p);
863 log_info("Removed
\"%s
\".", p);
868 static int remove_binaries(const char *esp_path) {
873 p = strjoina(esp_path, "/EFI
/systemd
");
874 r = rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL);
876 q = remove_boot_efi(esp_path);
880 for (i = ELEMENTSOF(efi_subdirs)-1; i > 0; i--) {
881 q = rmdir_one(esp_path, efi_subdirs[i-1]);
889 static int remove_variables(sd_id128_t uuid, const char *path, bool in_order) {
896 r = find_slot(uuid, path, &slot);
900 r = efi_remove_boot_option(slot);
905 return remove_from_order(slot);
910 static int install_loader_config(const char *esp_path) {
912 char machine_string[SD_ID128_STRING_MAX];
913 _cleanup_(unlink_and_freep) char *t = NULL;
914 _cleanup_fclose_ FILE *f = NULL;
915 sd_id128_t machine_id;
919 r = sd_id128_get_machine(&machine_id);
921 return log_error_errno(r, "Failed to get machine id
: %m
");
923 p = strjoina(esp_path, "/loader
/loader
.conf
");
925 if (access(p, F_OK) >= 0) /* Silently skip creation if the file already exists (early check) */
928 fd = open_tmpfile_linkable(p, O_WRONLY|O_CLOEXEC, &t);
930 return log_error_errno(fd, "Failed to open
\"%s
\" for writing
: %m
", p);
932 f = fdopen(fd, "we
");
938 fprintf(f, "#timeout 3\n");
939 fprintf(f, "default %s-*\n", sd_id128_to_string(machine_id, machine_string));
941 r = fflush_sync_and_check(f);
943 return log_error_errno(r, "Failed to write \"%s\": %m", p);
945 r = link_tmpfile(fd, t, p);
947 return 0; /* Silently skip creation if the file exists now (recheck) */
949 return log_error_errno(r, "Failed to move \"%s\" into place: %m", p);
956 static int help(int argc, char *argv[], void *userdata) {
958 printf("%s [COMMAND] [OPTIONS...]\n"
960 "Install, update or remove the systemd-boot EFI boot manager.\n\n"
961 " -h --help Show this help\n"
962 " --version Print version\n"
963 " --path=PATH Path to the EFI System Partition (ESP)\n"
964 " --no-variables Don't touch EFI variables\n"
967 " status Show status of installed systemd-boot and EFI variables\n"
968 " install Install systemd-boot to the ESP and EFI variables\n"
969 " update Update systemd-boot in the ESP and EFI variables\n"
970 " remove Remove systemd-boot from the ESP and EFI variables\n",
971 program_invocation_short_name);
976 static int parse_argv(int argc, char *argv[]) {
983 static const struct option options[] = {
984 { "help", no_argument, NULL, 'h' },
985 { "version", no_argument, NULL, ARG_VERSION },
986 { "path", required_argument, NULL, ARG_PATH },
987 { "no-variables", no_argument, NULL, ARG_NO_VARIABLES },
996 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
1000 help(0, NULL, NULL);
1007 r = free_and_strdup(&arg_path, optarg);
1012 case ARG_NO_VARIABLES:
1013 arg_touch_variables = false;
1020 assert_not_reached("Unknown option");
1026 static void read_loader_efi_var(const char *name, char **var) {
1029 r = efi_get_variable_string(EFI_VENDOR_LOADER, name, var);
1030 if (r < 0 && r != -ENOENT)
1031 log_warning_errno(r, "Failed to read EFI variable %s: %m", name);
1034 static int must_be_root(void) {
1039 log_error("Need to be root.");
1043 static int verb_status(int argc, char *argv[], void *userdata) {
1045 sd_id128_t uuid = SD_ID128_NULL;
1048 r2 = find_esp(NULL, NULL, NULL, &uuid);
1050 if (is_efi_boot()) {
1051 _cleanup_free_ char *fw_type = NULL, *fw_info = NULL, *loader = NULL, *loader_path = NULL;
1052 sd_id128_t loader_part_uuid = SD_ID128_NULL;
1054 read_loader_efi_var("LoaderFirmwareType", &fw_type);
1055 read_loader_efi_var("LoaderFirmwareInfo", &fw_info);
1056 read_loader_efi_var("LoaderInfo", &loader);
1057 read_loader_efi_var("LoaderImageIdentifier", &loader_path);
1060 efi_tilt_backslashes(loader_path);
1062 r = efi_loader_get_device_part_uuid(&loader_part_uuid);
1063 if (r < 0 && r != -ENOENT)
1064 r2 = log_warning_errno(r, "Failed to read EFI variable LoaderDevicePartUUID: %m");
1066 printf("System:\n");
1067 printf(" Firmware: %s (%s)\n", strna(fw_type), strna(fw_info));
1069 r = is_efi_secure_boot();
1071 r2 = log_warning_errno(r, "Failed to query secure boot status: %m");
1073 printf(" Secure Boot: %sd\n", enable_disable(r));
1075 r = is_efi_secure_boot_setup_mode();
1077 r2 = log_warning_errno(r, "Failed to query secure boot mode: %m");
1079 printf(" Setup Mode: %s\n", r ? "setup" : "user");
1082 printf("Current Loader:\n");
1083 printf(" Product: %s\n", strna(loader));
1084 if (!sd_id128_is_null(loader_part_uuid))
1085 printf(" ESP: /dev/disk/by-partuuid/%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
1086 SD_ID128_FORMAT_VAL(loader_part_uuid));
1088 printf(" ESP: n/a\n");
1089 printf(" File: %s%s\n", special_glyph(TREE_RIGHT), strna(loader_path));
1092 printf("System:\n Not booted with EFI\n\n");
1094 r = status_binaries(arg_path, uuid);
1098 if (is_efi_boot()) {
1099 r = status_variables();
1107 static int verb_install(int argc, char *argv[], void *userdata) {
1109 sd_id128_t uuid = SD_ID128_NULL;
1110 uint64_t pstart = 0, psize = 0;
1119 r = find_esp(&part, &pstart, &psize, &uuid);
1123 install = streq(argv[0], "install");
1125 RUN_WITH_UMASK(0002) {
1126 r = install_binaries(arg_path, install);
1131 r = install_loader_config(arg_path);
1137 if (arg_touch_variables)
1138 r = install_variables(arg_path,
1139 part, pstart, psize, uuid,
1140 "/EFI/systemd/systemd-boot" EFI_MACHINE_TYPE_NAME ".efi",
1146 static int verb_remove(int argc, char *argv[], void *userdata) {
1147 sd_id128_t uuid = SD_ID128_NULL;
1154 r = find_esp(NULL, NULL, NULL, &uuid);
1158 r = remove_binaries(arg_path);
1160 if (arg_touch_variables) {
1163 q = remove_variables(uuid, "/EFI/systemd/systemd-boot" EFI_MACHINE_TYPE_NAME ".efi", true);
1164 if (q < 0 && r == 0)
1171 static int bootctl_main(int argc, char *argv[]) {
1173 static const Verb verbs[] = {
1174 { "help", VERB_ANY, VERB_ANY, 0, help },
1175 { "status", VERB_ANY, 1, VERB_DEFAULT, verb_status },
1176 { "install", VERB_ANY, 1, 0, verb_install },
1177 { "update", VERB_ANY, 1, 0, verb_install },
1178 { "remove", VERB_ANY, 1, 0, verb_remove },
1182 return dispatch_verb(argc, argv, verbs, NULL);
1185 int main(int argc, char *argv[]) {
1188 log_parse_environment();
1191 /* If we run in a container, automatically turn of EFI file system access */
1192 if (detect_container() > 0)
1193 arg_touch_variables = false;
1195 r = parse_argv(argc, argv);
1199 r = bootctl_main(argc, argv);
1203 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;