1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2013-2015 Kay Sievers
6 Copyright 2013 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
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
;
82 /* Non-root user can run only `bootctl status`, then if error occured in the following, it does not cause any issues.
83 * So, let's silence the error messages. */
84 quiet
= (geteuid() != 0);
86 if (statfs(p
, &sfs
) < 0) {
88 /* If we are searching for the mount point, don't generate a log message if we can't find the path */
89 if (errno
== ENOENT
&& searching
)
92 return log_full_errno(quiet
&& errno
== EACCES
? LOG_DEBUG
: LOG_ERR
, errno
,
93 "Failed to check file system type of \"%s\": %m", p
);
96 if (!F_TYPE_EQUAL(sfs
.f_type
, MSDOS_SUPER_MAGIC
)) {
99 return -EADDRNOTAVAIL
;
101 log_error("File system \"%s\" is not a FAT EFI System Partition (ESP) file system.", p
);
105 if (stat(p
, &st
) < 0)
106 return log_full_errno(quiet
&& errno
== EACCES
? LOG_DEBUG
: LOG_ERR
, errno
,
107 "Failed to determine block device node of \"%s\": %m", p
);
109 if (major(st
.st_dev
) == 0) {
110 log_error("Block device node of %p is invalid.", p
);
114 t2
= strjoina(p
, "/..");
117 return log_full_errno(quiet
&& errno
== EACCES
? LOG_DEBUG
: LOG_ERR
, errno
,
118 "Failed to determine block device node of parent of \"%s\": %m", p
);
120 if (st
.st_dev
== st2
.st_dev
) {
121 log_error("Directory \"%s\" is not the root of the EFI System Partition (ESP) file system.", p
);
125 /* In a container we don't have access to block devices, skip this part of the verification, we trust the
126 * container manager set everything up correctly on its own. Also skip the following verification for non-root user. */
127 if (detect_container() > 0 || geteuid() != 0)
130 r
= asprintf(&t
, "/dev/block/%u:%u", major(st
.st_dev
), minor(st
.st_dev
));
135 b
= blkid_new_probe_from_filename(t
);
137 return log_error_errno(errno
?: ENOMEM
, "Failed to open file system \"%s\": %m", p
);
139 blkid_probe_enable_superblocks(b
, 1);
140 blkid_probe_set_superblocks_flags(b
, BLKID_SUBLKS_TYPE
);
141 blkid_probe_enable_partitions(b
, 1);
142 blkid_probe_set_partitions_flags(b
, BLKID_PARTS_ENTRY_DETAILS
);
145 r
= blkid_do_safeprobe(b
);
147 log_error("File system \"%s\" is ambiguous.", p
);
150 log_error("File system \"%s\" does not contain a label.", p
);
153 return log_error_errno(errno
?: EIO
, "Failed to probe file system \"%s\": %m", p
);
156 r
= blkid_probe_lookup_value(b
, "TYPE", &v
, NULL
);
158 return log_error_errno(errno
?: EIO
, "Failed to probe file system type \"%s\": %m", p
);
159 if (!streq(v
, "vfat")) {
160 log_error("File system \"%s\" is not FAT.", p
);
165 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_SCHEME", &v
, NULL
);
167 return log_error_errno(errno
?: EIO
, "Failed to probe partition scheme \"%s\": %m", p
);
168 if (!streq(v
, "gpt")) {
169 log_error("File system \"%s\" is not on a GPT partition table.", p
);
174 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_TYPE", &v
, NULL
);
176 return log_error_errno(errno
?: EIO
, "Failed to probe partition type UUID \"%s\": %m", p
);
177 if (!streq(v
, "c12a7328-f81f-11d2-ba4b-00a0c93ec93b")) {
178 log_error("File system \"%s\" has wrong type for an EFI System Partition (ESP).", p
);
183 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_UUID", &v
, NULL
);
185 return log_error_errno(errno
?: EIO
, "Failed to probe partition entry UUID \"%s\": %m", p
);
186 r
= sd_id128_from_string(v
, &uuid
);
188 log_error("Partition \"%s\" has invalid UUID \"%s\".", p
, v
);
193 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_NUMBER", &v
, NULL
);
195 return log_error_errno(errno
?: EIO
, "Failed to probe partition number \"%s\": m", p
);
196 r
= safe_atou32(v
, &part
);
198 return log_error_errno(r
, "Failed to parse PART_ENTRY_NUMBER field.");
201 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_OFFSET", &v
, NULL
);
203 return log_error_errno(errno
?: EIO
, "Failed to probe partition offset \"%s\": %m", p
);
204 r
= safe_atou64(v
, &pstart
);
206 return log_error_errno(r
, "Failed to parse PART_ENTRY_OFFSET field.");
209 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_SIZE", &v
, NULL
);
211 return log_error_errno(errno
?: EIO
, "Failed to probe partition size \"%s\": %m", p
);
212 r
= safe_atou64(v
, &psize
);
214 return log_error_errno(r
, "Failed to parse PART_ENTRY_SIZE field.");
220 *ret_pstart
= pstart
;
229 static int find_esp(uint32_t *part
, uint64_t *pstart
, uint64_t *psize
, sd_id128_t
*uuid
) {
234 return verify_esp(false, arg_path
, part
, pstart
, psize
, uuid
);
236 FOREACH_STRING(path
, "/efi", "/boot", "/boot/efi") {
238 r
= verify_esp(true, path
, part
, pstart
, psize
, uuid
);
239 if (IN_SET(r
, -ENOENT
, -EADDRNOTAVAIL
)) /* This one is not it */
244 arg_path
= strdup(path
);
248 log_info("Using EFI System Partition at %s.", path
);
252 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.");
256 /* search for "#### LoaderInfo: systemd-boot 218 ####" string inside the binary */
257 static int get_file_version(int fd
, char **v
) {
267 if (fstat(fd
, &st
) < 0)
268 return log_error_errno(errno
, "Failed to stat EFI binary: %m");
270 if (st
.st_size
< 27) {
275 buf
= mmap(NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0);
276 if (buf
== MAP_FAILED
)
277 return log_error_errno(errno
, "Failed to memory map EFI binary: %m");
279 s
= memmem(buf
, st
.st_size
- 8, "#### LoaderInfo: ", 17);
284 e
= memmem(s
, st
.st_size
- (s
- buf
), " ####", 5);
285 if (!e
|| e
- s
< 3) {
286 log_error("Malformed version string.");
291 x
= strndup(s
, e
- s
);
299 (void) munmap(buf
, st
.st_size
);
304 static int enumerate_binaries(const char *esp_path
, const char *path
, const char *prefix
) {
306 _cleanup_closedir_
DIR *d
= NULL
;
310 p
= strjoina(esp_path
, "/", path
);
316 return log_error_errno(errno
, "Failed to read \"%s\": %m", p
);
319 FOREACH_DIRENT(de
, d
, break) {
320 _cleanup_close_
int fd
= -1;
321 _cleanup_free_
char *v
= NULL
;
323 if (!endswith_no_case(de
->d_name
, ".efi"))
326 if (prefix
&& !startswith_no_case(de
->d_name
, prefix
))
329 fd
= openat(dirfd(d
), de
->d_name
, O_RDONLY
|O_CLOEXEC
);
331 return log_error_errno(errno
, "Failed to open \"%s/%s\" for reading: %m", p
, de
->d_name
);
333 r
= get_file_version(fd
, &v
);
337 printf(" File: %s/%s/%s (%s)\n", special_glyph(TREE_RIGHT
), path
, de
->d_name
, v
);
339 printf(" File: %s/%s/%s\n", special_glyph(TREE_RIGHT
), path
, de
->d_name
);
346 static int status_binaries(const char *esp_path
, sd_id128_t partition
) {
349 printf("Boot Loader Binaries:\n");
352 printf(" ESP: Cannot find or access mount point of ESP.\n\n");
356 printf(" ESP: %s", esp_path
);
357 if (!sd_id128_is_null(partition
))
358 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
));
361 r
= enumerate_binaries(esp_path
, "EFI/systemd", NULL
);
363 log_error("systemd-boot not installed in ESP.");
367 r
= enumerate_binaries(esp_path
, "EFI/BOOT", "boot");
369 log_error("No default/fallback boot loader installed in ESP.");
378 static int print_efi_option(uint16_t id
, bool in_order
) {
379 _cleanup_free_
char *title
= NULL
;
380 _cleanup_free_
char *path
= NULL
;
381 sd_id128_t partition
;
385 r
= efi_get_boot_option(id
, &title
, &partition
, &path
, &active
);
389 /* print only configured entries with partition information */
390 if (!path
|| sd_id128_is_null(partition
))
393 efi_tilt_backslashes(path
);
395 printf(" Title: %s\n", strna(title
));
396 printf(" ID: 0x%04X\n", id
);
397 printf(" Status: %sactive%s\n", active
? "" : "in", in_order
? ", boot-order" : "");
398 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
));
399 printf(" File: %s%s\n", special_glyph(TREE_RIGHT
), path
);
405 static int status_variables(void) {
406 int n_options
, n_order
;
407 _cleanup_free_
uint16_t *options
= NULL
, *order
= NULL
;
410 n_options
= efi_get_boot_options(&options
);
411 if (n_options
== -ENOENT
)
412 return log_error_errno(n_options
,
413 "Failed to access EFI variables, efivarfs"
414 " needs to be available at /sys/firmware/efi/efivars/.");
416 return log_error_errno(n_options
, "Failed to read EFI boot entries: %m");
418 n_order
= efi_get_boot_order(&order
);
419 if (n_order
== -ENOENT
)
421 else if (n_order
< 0)
422 return log_error_errno(n_order
, "Failed to read EFI boot order.");
424 /* print entries in BootOrder first */
425 printf("Boot Loader Entries in EFI Variables:\n");
426 for (i
= 0; i
< n_order
; i
++)
427 print_efi_option(order
[i
], true);
429 /* print remaining entries */
430 for (i
= 0; i
< n_options
; i
++) {
433 for (j
= 0; j
< n_order
; j
++)
434 if (options
[i
] == order
[j
])
437 print_efi_option(options
[i
], false);
446 static int compare_product(const char *a
, const char *b
) {
455 return x
< y
? -1 : x
> y
? 1 : 0;
457 return strncmp(a
, b
, x
);
460 static int compare_version(const char *a
, const char *b
) {
464 a
+= strcspn(a
, " ");
466 b
+= strcspn(b
, " ");
469 return strverscmp(a
, b
);
472 static int version_check(int fd_from
, const char *from
, int fd_to
, const char *to
) {
473 _cleanup_free_
char *a
= NULL
, *b
= NULL
;
476 assert(fd_from
>= 0);
481 r
= get_file_version(fd_from
, &a
);
485 log_error("Source file \"%s\" does not carry version information!", from
);
489 r
= get_file_version(fd_to
, &b
);
492 if (r
== 0 || compare_product(a
, b
) != 0) {
493 log_notice("Skipping \"%s\", since it's owned by another boot loader.", to
);
497 if (compare_version(a
, b
) < 0) {
498 log_warning("Skipping \"%s\", since a newer boot loader version exists already.", to
);
505 static int copy_file_with_version_check(const char *from
, const char *to
, bool force
) {
506 _cleanup_close_
int fd_from
= -1, fd_to
= -1;
507 _cleanup_free_
char *t
= NULL
;
510 fd_from
= open(from
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
512 return log_error_errno(errno
, "Failed to open \"%s\" for reading: %m", from
);
515 fd_to
= open(to
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
517 if (errno
!= -ENOENT
)
518 return log_error_errno(errno
, "Failed to open \"%s\" for reading: %m", to
);
520 r
= version_check(fd_from
, from
, fd_to
, to
);
524 if (lseek(fd_from
, 0, SEEK_SET
) == (off_t
) -1)
525 return log_error_errno(errno
, "Failed to seek in \%s\": %m", from
);
527 fd_to
= safe_close(fd_to
);
531 r
= tempfn_random(to
, NULL
, &t
);
535 RUN_WITH_UMASK(0000) {
536 fd_to
= open(t
, O_WRONLY
|O_CREAT
|O_CLOEXEC
|O_EXCL
|O_NOFOLLOW
, 0644);
538 return log_error_errno(errno
, "Failed to open \"%s\" for writing: %m", t
);
541 r
= copy_bytes(fd_from
, fd_to
, (uint64_t) -1, COPY_REFLINK
);
544 return log_error_errno(r
, "Failed to copy data from \"%s\" to \"%s\": %m", from
, t
);
547 (void) copy_times(fd_from
, fd_to
);
551 (void) unlink_noerrno(t
);
552 return log_error_errno(errno
, "Failed to copy data from \"%s\" to \"%s\": %m", from
, t
);
555 r
= renameat(AT_FDCWD
, t
, AT_FDCWD
, to
);
557 (void) unlink_noerrno(t
);
558 return log_error_errno(errno
, "Failed to rename \"%s\" to \"%s\": %m", t
, to
);
561 log_info("Copied \"%s\" to \"%s\".", from
, to
);
566 static int mkdir_one(const char *prefix
, const char *suffix
) {
569 p
= strjoina(prefix
, "/", suffix
);
570 if (mkdir(p
, 0700) < 0) {
572 return log_error_errno(errno
, "Failed to create \"%s\": %m", p
);
574 log_info("Created \"%s\".", p
);
579 static const char *efi_subdirs
[] = {
588 static int create_dirs(const char *esp_path
) {
592 STRV_FOREACH(i
, efi_subdirs
) {
593 r
= mkdir_one(esp_path
, *i
);
601 static int copy_one_file(const char *esp_path
, const char *name
, bool force
) {
605 p
= strjoina(BOOTLIBDIR
"/", name
);
606 q
= strjoina(esp_path
, "/EFI/systemd/", name
);
607 r
= copy_file_with_version_check(p
, q
, force
);
609 if (startswith(name
, "systemd-boot")) {
613 /* Create the EFI default boot loader name (specified for removable devices) */
614 v
= strjoina(esp_path
, "/EFI/BOOT/BOOT", name
+ strlen("systemd-boot"));
615 ascii_strupper(strrchr(v
, '/') + 1);
617 k
= copy_file_with_version_check(p
, v
, force
);
625 static int install_binaries(const char *esp_path
, bool force
) {
627 _cleanup_closedir_
DIR *d
= NULL
;
631 /* Don't create any of these directories when we are
632 * just updating. When we update we'll drop-in our
633 * files (unless there are newer ones already), but we
634 * won't create the directories for them in the first
636 r
= create_dirs(esp_path
);
641 d
= opendir(BOOTLIBDIR
);
643 return log_error_errno(errno
, "Failed to open \""BOOTLIBDIR
"\": %m
");
645 FOREACH_DIRENT(de, d, break) {
648 if (!endswith_no_case(de->d_name, ".efi
"))
651 k = copy_one_file(esp_path, de->d_name, force);
659 static bool same_entry(uint16_t id, const sd_id128_t uuid, const char *path) {
660 _cleanup_free_ char *opath = NULL;
664 r = efi_get_boot_option(id, NULL, &ouuid, &opath, NULL);
667 if (!sd_id128_equal(uuid, ouuid))
669 if (!streq_ptr(path, opath))
675 static int find_slot(sd_id128_t uuid, const char *path, uint16_t *id) {
676 _cleanup_free_ uint16_t *options = NULL;
679 n = efi_get_boot_options(&options);
683 /* find already existing systemd-boot entry */
684 for (i = 0; i < n; i++)
685 if (same_entry(options[i], uuid, path)) {
690 /* find free slot in the sorted BootXXXX variable list */
691 for (i = 0; i < n; i++)
692 if (i != options[i]) {
697 /* use the next one */
704 static int insert_into_order(uint16_t slot, bool first) {
705 _cleanup_free_ uint16_t *order = NULL;
709 n = efi_get_boot_order(&order);
711 /* no entry, add us */
712 return efi_set_boot_order(&slot, 1);
714 /* are we the first and only one? */
715 if (n == 1 && order[0] == slot)
718 /* are we already in the boot order? */
719 for (i = 0; i < n; i++) {
720 if (order[i] != slot)
723 /* we do not require to be the first one, all is fine */
727 /* move us to the first slot */
728 memmove(order + 1, order, i * sizeof(uint16_t));
730 return efi_set_boot_order(order, n);
734 t = realloc(order, (n + 1) * sizeof(uint16_t));
739 /* add us to the top or end of the list */
741 memmove(order + 1, order, n * sizeof(uint16_t));
746 return efi_set_boot_order(order, n + 1);
749 static int remove_from_order(uint16_t slot) {
750 _cleanup_free_ uint16_t *order = NULL;
753 n = efi_get_boot_order(&order);
757 for (i = 0; i < n; i++) {
758 if (order[i] != slot)
762 memmove(order + i, order + i+1, (n - i) * sizeof(uint16_t));
763 return efi_set_boot_order(order, n - 1);
769 static int install_variables(const char *esp_path,
770 uint32_t part, uint64_t pstart, uint64_t psize,
771 sd_id128_t uuid, const char *path,
777 if (!is_efi_boot()) {
778 log_warning("Not booted with EFI
, skipping EFI variable setup
.");
782 p = strjoina(esp_path, path);
783 if (access(p, F_OK) < 0) {
787 return log_error_errno(errno, "Cannot access
\"%s
\": %m
", p);
790 r = find_slot(uuid, path, &slot);
792 return log_error_errno(r,
794 "Failed to access EFI variables
. Is the
\"efivarfs
\" filesystem mounted
?" :
795 "Failed to determine current boot order
: %m
");
797 if (first || r == 0) {
798 r = efi_add_boot_option(slot, "Linux Boot Manager
",
802 return log_error_errno(r, "Failed to create EFI Boot variable entry
: %m
");
804 log_info("Created EFI boot entry
\"Linux Boot Manager
\".");
807 return insert_into_order(slot, first);
810 static int remove_boot_efi(const char *esp_path) {
812 _cleanup_closedir_ DIR *d = NULL;
816 p = strjoina(esp_path, "/EFI
/BOOT
");
822 return log_error_errno(errno, "Failed to open directory
\"%s
\": %m
", p);
825 FOREACH_DIRENT(de, d, break) {
826 _cleanup_close_ int fd = -1;
827 _cleanup_free_ char *v = NULL;
829 if (!endswith_no_case(de->d_name, ".efi
"))
832 if (!startswith_no_case(de->d_name, "boot
"))
835 fd = openat(dirfd(d), de->d_name, O_RDONLY|O_CLOEXEC);
837 return log_error_errno(errno, "Failed to open
\"%s
/%s
\" for reading
: %m
", p, de->d_name);
839 r = get_file_version(fd, &v);
842 if (r > 0 && startswith(v, "systemd
-boot
")) {
843 r = unlinkat(dirfd(d), de->d_name, 0);
845 return log_error_errno(errno, "Failed to remove
\"%s
/%s
\": %m
", p, de->d_name);
847 log_info("Removed
\"%s
/%s
\".", p, de->d_name);
856 static int rmdir_one(const char *prefix, const char *suffix) {
859 p = strjoina(prefix, "/", suffix);
861 if (!IN_SET(errno, ENOENT, ENOTEMPTY))
862 return log_error_errno(errno, "Failed to remove
\"%s
\": %m
", p);
864 log_info("Removed
\"%s
\".", p);
869 static int remove_binaries(const char *esp_path) {
874 p = strjoina(esp_path, "/EFI
/systemd
");
875 r = rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL);
877 q = remove_boot_efi(esp_path);
881 for (i = ELEMENTSOF(efi_subdirs)-1; i > 0; i--) {
882 q = rmdir_one(esp_path, efi_subdirs[i-1]);
890 static int remove_variables(sd_id128_t uuid, const char *path, bool in_order) {
897 r = find_slot(uuid, path, &slot);
901 r = efi_remove_boot_option(slot);
906 return remove_from_order(slot);
911 static int install_loader_config(const char *esp_path) {
913 char machine_string[SD_ID128_STRING_MAX];
914 _cleanup_(unlink_and_freep) char *t = NULL;
915 _cleanup_fclose_ FILE *f = NULL;
916 sd_id128_t machine_id;
920 r = sd_id128_get_machine(&machine_id);
922 return log_error_errno(r, "Failed to get machine id
: %m
");
924 p = strjoina(esp_path, "/loader
/loader
.conf
");
926 if (access(p, F_OK) >= 0) /* Silently skip creation if the file already exists (early check) */
929 fd = open_tmpfile_linkable(p, O_WRONLY|O_CLOEXEC, &t);
931 return log_error_errno(fd, "Failed to open
\"%s
\" for writing
: %m
", p);
933 f = fdopen(fd, "we
");
939 fprintf(f, "#timeout 3\n");
940 fprintf(f, "default %s-*\n", sd_id128_to_string(machine_id, machine_string));
942 r = fflush_sync_and_check(f);
944 return log_error_errno(r, "Failed to write \"%s\": %m", p);
946 r = link_tmpfile(fd, t, p);
948 return 0; /* Silently skip creation if the file exists now (recheck) */
950 return log_error_errno(r, "Failed to move \"%s\" into place: %m", p);
957 static int help(int argc, char *argv[], void *userdata) {
959 printf("%s [COMMAND] [OPTIONS...]\n"
961 "Install, update or remove the systemd-boot EFI boot manager.\n\n"
962 " -h --help Show this help\n"
963 " --version Print version\n"
964 " --path=PATH Path to the EFI System Partition (ESP)\n"
965 " --no-variables Don't touch EFI variables\n"
968 " status Show status of installed systemd-boot and EFI variables\n"
969 " install Install systemd-boot to the ESP and EFI variables\n"
970 " update Update systemd-boot in the ESP and EFI variables\n"
971 " remove Remove systemd-boot from the ESP and EFI variables\n",
972 program_invocation_short_name);
977 static int parse_argv(int argc, char *argv[]) {
984 static const struct option options[] = {
985 { "help", no_argument, NULL, 'h' },
986 { "version", no_argument, NULL, ARG_VERSION },
987 { "path", required_argument, NULL, ARG_PATH },
988 { "no-variables", no_argument, NULL, ARG_NO_VARIABLES },
997 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
1001 help(0, NULL, NULL);
1008 r = free_and_strdup(&arg_path, optarg);
1013 case ARG_NO_VARIABLES:
1014 arg_touch_variables = false;
1021 assert_not_reached("Unknown option");
1027 static void read_loader_efi_var(const char *name, char **var) {
1030 r = efi_get_variable_string(EFI_VENDOR_LOADER, name, var);
1031 if (r < 0 && r != -ENOENT)
1032 log_warning_errno(r, "Failed to read EFI variable %s: %m", name);
1035 static int must_be_root(void) {
1040 log_error("Need to be root.");
1044 static int verb_status(int argc, char *argv[], void *userdata) {
1046 sd_id128_t uuid = SD_ID128_NULL;
1049 r2 = find_esp(NULL, NULL, NULL, &uuid);
1051 if (is_efi_boot()) {
1052 _cleanup_free_ char *fw_type = NULL, *fw_info = NULL, *loader = NULL, *loader_path = NULL;
1053 sd_id128_t loader_part_uuid = SD_ID128_NULL;
1055 read_loader_efi_var("LoaderFirmwareType", &fw_type);
1056 read_loader_efi_var("LoaderFirmwareInfo", &fw_info);
1057 read_loader_efi_var("LoaderInfo", &loader);
1058 read_loader_efi_var("LoaderImageIdentifier", &loader_path);
1061 efi_tilt_backslashes(loader_path);
1063 r = efi_loader_get_device_part_uuid(&loader_part_uuid);
1064 if (r < 0 && r != -ENOENT)
1065 r2 = log_warning_errno(r, "Failed to read EFI variable LoaderDevicePartUUID: %m");
1067 printf("System:\n");
1068 printf(" Firmware: %s (%s)\n", strna(fw_type), strna(fw_info));
1070 r = is_efi_secure_boot();
1072 r2 = log_warning_errno(r, "Failed to query secure boot status: %m");
1074 printf(" Secure Boot: %sd\n", enable_disable(r));
1076 r = is_efi_secure_boot_setup_mode();
1078 r2 = log_warning_errno(r, "Failed to query secure boot mode: %m");
1080 printf(" Setup Mode: %s\n", r ? "setup" : "user");
1083 printf("Current Loader:\n");
1084 printf(" Product: %s\n", strna(loader));
1085 if (!sd_id128_is_null(loader_part_uuid))
1086 printf(" ESP: /dev/disk/by-partuuid/%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
1087 SD_ID128_FORMAT_VAL(loader_part_uuid));
1089 printf(" ESP: n/a\n");
1090 printf(" File: %s%s\n", special_glyph(TREE_RIGHT), strna(loader_path));
1093 printf("System:\n Not booted with EFI\n\n");
1095 r = status_binaries(arg_path, uuid);
1099 if (is_efi_boot()) {
1100 r = status_variables();
1108 static int verb_install(int argc, char *argv[], void *userdata) {
1110 sd_id128_t uuid = SD_ID128_NULL;
1111 uint64_t pstart = 0, psize = 0;
1120 r = find_esp(&part, &pstart, &psize, &uuid);
1124 install = streq(argv[0], "install");
1126 RUN_WITH_UMASK(0002) {
1127 r = install_binaries(arg_path, install);
1132 r = install_loader_config(arg_path);
1138 if (arg_touch_variables)
1139 r = install_variables(arg_path,
1140 part, pstart, psize, uuid,
1141 "/EFI/systemd/systemd-boot" EFI_MACHINE_TYPE_NAME ".efi",
1147 static int verb_remove(int argc, char *argv[], void *userdata) {
1148 sd_id128_t uuid = SD_ID128_NULL;
1155 r = find_esp(NULL, NULL, NULL, &uuid);
1159 r = remove_binaries(arg_path);
1161 if (arg_touch_variables) {
1164 q = remove_variables(uuid, "/EFI/systemd/systemd-boot" EFI_MACHINE_TYPE_NAME ".efi", true);
1165 if (q < 0 && r == 0)
1172 static int bootctl_main(int argc, char *argv[]) {
1174 static const Verb verbs[] = {
1175 { "help", VERB_ANY, VERB_ANY, 0, help },
1176 { "status", VERB_ANY, 1, VERB_DEFAULT, verb_status },
1177 { "install", VERB_ANY, 1, 0, verb_install },
1178 { "update", VERB_ANY, 1, 0, verb_install },
1179 { "remove", VERB_ANY, 1, 0, verb_remove },
1183 return dispatch_verb(argc, argv, verbs, NULL);
1186 int main(int argc, char *argv[]) {
1189 log_parse_environment();
1192 /* If we run in a container, automatically turn of EFI file system access */
1193 if (detect_container() > 0)
1194 arg_touch_variables = false;
1196 r = parse_argv(argc, argv);
1200 r = bootctl_main(argc, argv);
1204 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;