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>
41 #include "alloc-util.h"
42 #include "blkid-util.h"
45 #include "dirent-util.h"
50 #include "locale-util.h"
51 #include "parse-util.h"
53 #include "stat-util.h"
54 #include "string-util.h"
56 #include "terminal-util.h"
57 #include "umask-util.h"
62 static char *arg_path
= NULL
;
63 static bool arg_print_path
= false;
64 static bool arg_touch_variables
= true;
66 static int acquire_esp(
67 bool unprivileged_mode
,
71 sd_id128_t
*ret_uuid
) {
76 /* Find the ESP, and log about errors. Note that find_esp_and_warn() will log in all error cases on its own,
77 * except for ENOKEY (which is good, we want to show our own message in that case, suggesting use of --path=)
78 * and EACCESS (only when we request unprivileged mode; in this case we simply eat up the error here, so that
79 * --list and --status work too, without noise about this). */
81 r
= find_esp_and_warn(arg_path
, unprivileged_mode
, &np
, ret_part
, ret_pstart
, ret_psize
, ret_uuid
);
83 return log_error_errno(r
,
84 "Couldn't find EFI system partition. It is recommended to mount it to /boot or /efi.\n"
85 "Alternatively, use --path= to specify path to mount point.");
89 free_and_replace(arg_path
, np
);
91 log_debug("Using EFI System Partition at %s.", arg_path
);
96 /* search for "#### LoaderInfo: systemd-boot 218 ####" string inside the binary */
97 static int get_file_version(int fd
, char **v
) {
107 if (fstat(fd
, &st
) < 0)
108 return log_error_errno(errno
, "Failed to stat EFI binary: %m");
110 if (st
.st_size
< 27) {
115 buf
= mmap(NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0);
116 if (buf
== MAP_FAILED
)
117 return log_error_errno(errno
, "Failed to memory map EFI binary: %m");
119 s
= memmem(buf
, st
.st_size
- 8, "#### LoaderInfo: ", 17);
124 e
= memmem(s
, st
.st_size
- (s
- buf
), " ####", 5);
125 if (!e
|| e
- s
< 3) {
126 log_error("Malformed version string.");
131 x
= strndup(s
, e
- s
);
139 (void) munmap(buf
, st
.st_size
);
144 static int enumerate_binaries(const char *esp_path
, const char *path
, const char *prefix
) {
146 _cleanup_closedir_
DIR *d
= NULL
;
150 p
= strjoina(esp_path
, "/", path
);
156 return log_error_errno(errno
, "Failed to read \"%s\": %m", p
);
159 FOREACH_DIRENT(de
, d
, break) {
160 _cleanup_close_
int fd
= -1;
161 _cleanup_free_
char *v
= NULL
;
163 if (!endswith_no_case(de
->d_name
, ".efi"))
166 if (prefix
&& !startswith_no_case(de
->d_name
, prefix
))
169 fd
= openat(dirfd(d
), de
->d_name
, O_RDONLY
|O_CLOEXEC
);
171 return log_error_errno(errno
, "Failed to open \"%s/%s\" for reading: %m", p
, de
->d_name
);
173 r
= get_file_version(fd
, &v
);
177 printf(" File: %s/%s/%s (%s)\n", special_glyph(TREE_RIGHT
), path
, de
->d_name
, v
);
179 printf(" File: %s/%s/%s\n", special_glyph(TREE_RIGHT
), path
, de
->d_name
);
186 static int status_binaries(const char *esp_path
, sd_id128_t partition
) {
189 printf("Boot Loader Binaries:\n");
192 printf(" ESP: Cannot find or access mount point of ESP.\n\n");
196 printf(" ESP: %s", esp_path
);
197 if (!sd_id128_is_null(partition
))
198 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
));
201 r
= enumerate_binaries(esp_path
, "EFI/systemd", NULL
);
203 log_error("systemd-boot not installed in ESP.");
207 r
= enumerate_binaries(esp_path
, "EFI/BOOT", "boot");
209 log_error("No default/fallback boot loader installed in ESP.");
218 static int print_efi_option(uint16_t id
, bool in_order
) {
219 _cleanup_free_
char *title
= NULL
;
220 _cleanup_free_
char *path
= NULL
;
221 sd_id128_t partition
;
225 r
= efi_get_boot_option(id
, &title
, &partition
, &path
, &active
);
229 /* print only configured entries with partition information */
230 if (!path
|| sd_id128_is_null(partition
))
233 efi_tilt_backslashes(path
);
235 printf(" Title: %s\n", strna(title
));
236 printf(" ID: 0x%04X\n", id
);
237 printf(" Status: %sactive%s\n", active
? "" : "in", in_order
? ", boot-order" : "");
238 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
));
239 printf(" File: %s%s\n", special_glyph(TREE_RIGHT
), path
);
245 static int status_variables(void) {
246 int n_options
, n_order
;
247 _cleanup_free_
uint16_t *options
= NULL
, *order
= NULL
;
250 n_options
= efi_get_boot_options(&options
);
251 if (n_options
== -ENOENT
)
252 return log_error_errno(n_options
,
253 "Failed to access EFI variables, efivarfs"
254 " needs to be available at /sys/firmware/efi/efivars/.");
256 return log_error_errno(n_options
, "Failed to read EFI boot entries: %m");
258 n_order
= efi_get_boot_order(&order
);
259 if (n_order
== -ENOENT
)
261 else if (n_order
< 0)
262 return log_error_errno(n_order
, "Failed to read EFI boot order.");
264 /* print entries in BootOrder first */
265 printf("Boot Loader Entries in EFI Variables:\n");
266 for (i
= 0; i
< n_order
; i
++)
267 print_efi_option(order
[i
], true);
269 /* print remaining entries */
270 for (i
= 0; i
< n_options
; i
++) {
273 for (j
= 0; j
< n_order
; j
++)
274 if (options
[i
] == order
[j
])
277 print_efi_option(options
[i
], false);
286 static int status_entries(const char *esp_path
, sd_id128_t partition
) {
289 _cleanup_(boot_config_free
) BootConfig config
= {};
291 printf("Default Boot Entry:\n");
293 r
= boot_entries_load_config(esp_path
, &config
);
295 return log_error_errno(r
, "Failed to load bootspec config from \"%s/loader\": %m",
298 if (config
.default_entry
< 0)
299 printf("%zu entries, no entry suitable as default\n", config
.n_entries
);
301 const BootEntry
*e
= &config
.entries
[config
.default_entry
];
303 printf(" title: %s\n", boot_entry_title(e
));
305 printf(" version: %s\n", e
->version
);
307 printf(" linux: %s\n", e
->kernel
);
308 if (!strv_isempty(e
->initrd
)) {
309 _cleanup_free_
char *t
;
311 t
= strv_join(e
->initrd
, " ");
315 printf(" initrd: %s\n", t
);
317 if (!strv_isempty(e
->options
)) {
318 _cleanup_free_
char *t
;
320 t
= strv_join(e
->options
, " ");
324 printf(" options: %s\n", t
);
327 printf(" devicetree: %s\n", e
->device_tree
);
334 static int compare_product(const char *a
, const char *b
) {
343 return x
< y
? -1 : x
> y
? 1 : 0;
345 return strncmp(a
, b
, x
);
348 static int compare_version(const char *a
, const char *b
) {
352 a
+= strcspn(a
, " ");
354 b
+= strcspn(b
, " ");
357 return strverscmp(a
, b
);
360 static int version_check(int fd_from
, const char *from
, int fd_to
, const char *to
) {
361 _cleanup_free_
char *a
= NULL
, *b
= NULL
;
364 assert(fd_from
>= 0);
369 r
= get_file_version(fd_from
, &a
);
373 log_error("Source file \"%s\" does not carry version information!", from
);
377 r
= get_file_version(fd_to
, &b
);
380 if (r
== 0 || compare_product(a
, b
) != 0) {
381 log_notice("Skipping \"%s\", since it's owned by another boot loader.", to
);
385 if (compare_version(a
, b
) < 0) {
386 log_warning("Skipping \"%s\", since a newer boot loader version exists already.", to
);
393 static int copy_file_with_version_check(const char *from
, const char *to
, bool force
) {
394 _cleanup_close_
int fd_from
= -1, fd_to
= -1;
395 _cleanup_free_
char *t
= NULL
;
398 fd_from
= open(from
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
400 return log_error_errno(errno
, "Failed to open \"%s\" for reading: %m", from
);
403 fd_to
= open(to
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
405 if (errno
!= -ENOENT
)
406 return log_error_errno(errno
, "Failed to open \"%s\" for reading: %m", to
);
408 r
= version_check(fd_from
, from
, fd_to
, to
);
412 if (lseek(fd_from
, 0, SEEK_SET
) == (off_t
) -1)
413 return log_error_errno(errno
, "Failed to seek in \"%s\": %m", from
);
415 fd_to
= safe_close(fd_to
);
419 r
= tempfn_random(to
, NULL
, &t
);
423 RUN_WITH_UMASK(0000) {
424 fd_to
= open(t
, O_WRONLY
|O_CREAT
|O_CLOEXEC
|O_EXCL
|O_NOFOLLOW
, 0644);
426 return log_error_errno(errno
, "Failed to open \"%s\" for writing: %m", t
);
429 r
= copy_bytes(fd_from
, fd_to
, (uint64_t) -1, COPY_REFLINK
);
432 return log_error_errno(r
, "Failed to copy data from \"%s\" to \"%s\": %m", from
, t
);
435 (void) copy_times(fd_from
, fd_to
);
437 if (fsync(fd_to
) < 0) {
438 (void) unlink_noerrno(t
);
439 return log_error_errno(errno
, "Failed to copy data from \"%s\" to \"%s\": %m", from
, t
);
442 (void) fsync_directory_of_file(fd_to
);
444 r
= renameat(AT_FDCWD
, t
, AT_FDCWD
, to
);
446 (void) unlink_noerrno(t
);
447 return log_error_errno(errno
, "Failed to rename \"%s\" to \"%s\": %m", t
, to
);
450 log_info("Copied \"%s\" to \"%s\".", from
, to
);
455 static int mkdir_one(const char *prefix
, const char *suffix
) {
458 p
= strjoina(prefix
, "/", suffix
);
459 if (mkdir(p
, 0700) < 0) {
461 return log_error_errno(errno
, "Failed to create \"%s\": %m", p
);
463 log_info("Created \"%s\".", p
);
468 static const char *efi_subdirs
[] = {
477 static int create_dirs(const char *esp_path
) {
481 STRV_FOREACH(i
, efi_subdirs
) {
482 r
= mkdir_one(esp_path
, *i
);
490 static int copy_one_file(const char *esp_path
, const char *name
, bool force
) {
494 p
= strjoina(BOOTLIBDIR
"/", name
);
495 q
= strjoina(esp_path
, "/EFI/systemd/", name
);
496 r
= copy_file_with_version_check(p
, q
, force
);
498 if (startswith(name
, "systemd-boot")) {
502 /* Create the EFI default boot loader name (specified for removable devices) */
503 v
= strjoina(esp_path
, "/EFI/BOOT/BOOT",
504 name
+ STRLEN("systemd-boot"));
505 ascii_strupper(strrchr(v
, '/') + 1);
507 k
= copy_file_with_version_check(p
, v
, force
);
515 static int install_binaries(const char *esp_path
, bool force
) {
517 _cleanup_closedir_
DIR *d
= NULL
;
521 /* Don't create any of these directories when we are
522 * just updating. When we update we'll drop-in our
523 * files (unless there are newer ones already), but we
524 * won't create the directories for them in the first
526 r
= create_dirs(esp_path
);
531 d
= opendir(BOOTLIBDIR
);
533 return log_error_errno(errno
, "Failed to open \""BOOTLIBDIR
"\": %m
");
535 FOREACH_DIRENT(de, d, break) {
538 if (!endswith_no_case(de->d_name, ".efi
"))
541 k = copy_one_file(esp_path, de->d_name, force);
549 static bool same_entry(uint16_t id, const sd_id128_t uuid, const char *path) {
550 _cleanup_free_ char *opath = NULL;
554 r = efi_get_boot_option(id, NULL, &ouuid, &opath, NULL);
557 if (!sd_id128_equal(uuid, ouuid))
559 if (!streq_ptr(path, opath))
565 static int find_slot(sd_id128_t uuid, const char *path, uint16_t *id) {
566 _cleanup_free_ uint16_t *options = NULL;
569 n = efi_get_boot_options(&options);
573 /* find already existing systemd-boot entry */
574 for (i = 0; i < n; i++)
575 if (same_entry(options[i], uuid, path)) {
580 /* find free slot in the sorted BootXXXX variable list */
581 for (i = 0; i < n; i++)
582 if (i != options[i]) {
587 /* use the next one */
594 static int insert_into_order(uint16_t slot, bool first) {
595 _cleanup_free_ uint16_t *order = NULL;
599 n = efi_get_boot_order(&order);
601 /* no entry, add us */
602 return efi_set_boot_order(&slot, 1);
604 /* are we the first and only one? */
605 if (n == 1 && order[0] == slot)
608 /* are we already in the boot order? */
609 for (i = 0; i < n; i++) {
610 if (order[i] != slot)
613 /* we do not require to be the first one, all is fine */
617 /* move us to the first slot */
618 memmove(order + 1, order, i * sizeof(uint16_t));
620 return efi_set_boot_order(order, n);
624 t = realloc(order, (n + 1) * sizeof(uint16_t));
629 /* add us to the top or end of the list */
631 memmove(order + 1, order, n * sizeof(uint16_t));
636 return efi_set_boot_order(order, n + 1);
639 static int remove_from_order(uint16_t slot) {
640 _cleanup_free_ uint16_t *order = NULL;
643 n = efi_get_boot_order(&order);
647 for (i = 0; i < n; i++) {
648 if (order[i] != slot)
652 memmove(order + i, order + i+1, (n - i) * sizeof(uint16_t));
653 return efi_set_boot_order(order, n - 1);
659 static int install_variables(const char *esp_path,
660 uint32_t part, uint64_t pstart, uint64_t psize,
661 sd_id128_t uuid, const char *path,
667 if (!is_efi_boot()) {
668 log_warning("Not booted with EFI
, skipping EFI variable setup
.");
672 p = strjoina(esp_path, path);
673 if (access(p, F_OK) < 0) {
677 return log_error_errno(errno, "Cannot access
\"%s
\": %m
", p);
680 r = find_slot(uuid, path, &slot);
682 return log_error_errno(r,
684 "Failed to access EFI variables
. Is the
\"efivarfs
\" filesystem mounted
?" :
685 "Failed to determine current boot order
: %m
");
687 if (first || r == 0) {
688 r = efi_add_boot_option(slot, "Linux Boot Manager
",
692 return log_error_errno(r, "Failed to create EFI Boot variable entry
: %m
");
694 log_info("Created EFI boot entry
\"Linux Boot Manager
\".");
697 return insert_into_order(slot, first);
700 static int remove_boot_efi(const char *esp_path) {
702 _cleanup_closedir_ DIR *d = NULL;
706 p = strjoina(esp_path, "/EFI
/BOOT
");
712 return log_error_errno(errno, "Failed to open directory
\"%s
\": %m
", p);
715 FOREACH_DIRENT(de, d, break) {
716 _cleanup_close_ int fd = -1;
717 _cleanup_free_ char *v = NULL;
719 if (!endswith_no_case(de->d_name, ".efi
"))
722 if (!startswith_no_case(de->d_name, "boot
"))
725 fd = openat(dirfd(d), de->d_name, O_RDONLY|O_CLOEXEC);
727 return log_error_errno(errno, "Failed to open
\"%s
/%s
\" for reading
: %m
", p, de->d_name);
729 r = get_file_version(fd, &v);
732 if (r > 0 && startswith(v, "systemd
-boot
")) {
733 r = unlinkat(dirfd(d), de->d_name, 0);
735 return log_error_errno(errno, "Failed to remove
\"%s
/%s
\": %m
", p, de->d_name);
737 log_info("Removed
\"%s
/%s
\".", p, de->d_name);
746 static int rmdir_one(const char *prefix, const char *suffix) {
749 p = strjoina(prefix, "/", suffix);
751 if (!IN_SET(errno, ENOENT, ENOTEMPTY))
752 return log_error_errno(errno, "Failed to remove
\"%s
\": %m
", p);
754 log_info("Removed
\"%s
\".", p);
759 static int remove_binaries(const char *esp_path) {
764 p = strjoina(esp_path, "/EFI
/systemd
");
765 r = rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL);
767 q = remove_boot_efi(esp_path);
771 for (i = ELEMENTSOF(efi_subdirs)-1; i > 0; i--) {
772 q = rmdir_one(esp_path, efi_subdirs[i-1]);
780 static int remove_variables(sd_id128_t uuid, const char *path, bool in_order) {
787 r = find_slot(uuid, path, &slot);
791 r = efi_remove_boot_option(slot);
796 return remove_from_order(slot);
801 static int install_loader_config(const char *esp_path) {
803 char machine_string[SD_ID128_STRING_MAX];
804 _cleanup_(unlink_and_freep) char *t = NULL;
805 _cleanup_fclose_ FILE *f = NULL;
806 sd_id128_t machine_id;
810 r = sd_id128_get_machine(&machine_id);
812 return log_error_errno(r, "Failed to get machine id
: %m
");
814 p = strjoina(esp_path, "/loader
/loader
.conf
");
816 if (access(p, F_OK) >= 0) /* Silently skip creation if the file already exists (early check) */
819 fd = open_tmpfile_linkable(p, O_WRONLY|O_CLOEXEC, &t);
821 return log_error_errno(fd, "Failed to open
\"%s
\" for writing
: %m
", p);
823 f = fdopen(fd, "we
");
829 fprintf(f, "#timeout 3\n");
830 fprintf(f, "#console-mode keep\n");
831 fprintf(f, "default %s-*\n", sd_id128_to_string(machine_id, machine_string));
833 r = fflush_sync_and_check(f);
835 return log_error_errno(r, "Failed to write \"%s\": %m", p);
837 r = link_tmpfile(fd, t, p);
839 return 0; /* Silently skip creation if the file exists now (recheck) */
841 return log_error_errno(r, "Failed to move \"%s\" into place: %m", p);
848 static int help(int argc, char *argv[], void *userdata) {
850 printf("%s [COMMAND] [OPTIONS...]\n"
852 "Install, update or remove the systemd-boot EFI boot manager.\n\n"
853 " -h --help Show this help\n"
854 " --version Print version\n"
855 " --path=PATH Path to the EFI System Partition (ESP)\n"
856 " -p --print-path Print path to the EFI partition\n"
857 " --no-variables Don't touch EFI variables\n"
860 " status Show status of installed systemd-boot and EFI variables\n"
861 " list List boot entries\n"
862 " install Install systemd-boot to the ESP and EFI variables\n"
863 " update Update systemd-boot in the ESP and EFI variables\n"
864 " remove Remove systemd-boot from the ESP and EFI variables\n",
865 program_invocation_short_name);
870 static int parse_argv(int argc, char *argv[]) {
877 static const struct option options[] = {
878 { "help", no_argument, NULL, 'h' },
879 { "version", no_argument, NULL, ARG_VERSION },
880 { "path", required_argument, NULL, ARG_PATH },
881 { "print-path", no_argument, NULL, 'p' },
882 { "no-variables", no_argument, NULL, ARG_NO_VARIABLES },
891 while ((c = getopt_long(argc, argv, "hp", options, NULL)) >= 0)
902 r = free_and_strdup(&arg_path, optarg);
908 arg_print_path = true;
911 case ARG_NO_VARIABLES:
912 arg_touch_variables = false;
919 assert_not_reached("Unknown option");
925 static void read_loader_efi_var(const char *name, char **var) {
928 r = efi_get_variable_string(EFI_VENDOR_LOADER, name, var);
929 if (r < 0 && r != -ENOENT)
930 log_warning_errno(r, "Failed to read EFI variable %s: %m", name);
933 static int verb_status(int argc, char *argv[], void *userdata) {
935 sd_id128_t uuid = SD_ID128_NULL;
938 r = acquire_esp(geteuid() != 0, NULL, NULL, NULL, &uuid);
940 if (arg_print_path) {
941 if (r == -EACCES) /* If we couldn't acquire the ESP path, log about access errors (which is the only
942 * error the
find_esp_and_warn() won
't log on its own) */
943 return log_error_errno(r, "Failed to determine ESP: %m");
951 r = 0; /* If we couldn't determine the path
, then don
't consider that a problem from here on, just show what we
955 _cleanup_free_ char *fw_type = NULL, *fw_info = NULL, *loader = NULL, *loader_path = NULL, *stub = NULL;
956 sd_id128_t loader_part_uuid = SD_ID128_NULL;
958 read_loader_efi_var("LoaderFirmwareType", &fw_type);
959 read_loader_efi_var("LoaderFirmwareInfo", &fw_info);
960 read_loader_efi_var("LoaderInfo", &loader);
961 read_loader_efi_var("StubInfo", &stub);
962 read_loader_efi_var("LoaderImageIdentifier", &loader_path);
965 efi_tilt_backslashes(loader_path);
967 k = efi_loader_get_device_part_uuid(&loader_part_uuid);
968 if (k < 0 && k != -ENOENT)
969 r = log_warning_errno(k, "Failed to read EFI variable LoaderDevicePartUUID: %m");
972 printf(" Firmware: %s (%s)\n", strna(fw_type), strna(fw_info));
974 k = is_efi_secure_boot();
976 r = log_warning_errno(k, "Failed to query secure boot status: %m");
978 printf(" Secure Boot: %sd\n", enable_disable(k));
980 k = is_efi_secure_boot_setup_mode();
982 r = log_warning_errno(k, "Failed to query secure boot mode: %m");
984 printf(" Setup Mode: %s\n", k ? "setup" : "user");
987 printf("Current Loader:\n");
988 printf(" Product: %s\n", strna(loader));
990 printf(" Stub: %s\n", stub);
991 if (!sd_id128_is_null(loader_part_uuid))
992 printf(" ESP: /dev/disk/by-partuuid/%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
993 SD_ID128_FORMAT_VAL(loader_part_uuid));
995 printf(" ESP: n/a\n");
996 printf(" File: %s%s\n", special_glyph(TREE_RIGHT), strna(loader_path));
999 printf("System:\n Not booted with EFI\n\n");
1002 k = status_binaries(arg_path, uuid);
1007 if (is_efi_boot()) {
1008 k = status_variables();
1014 k = status_entries(arg_path, uuid);
1022 static int verb_list(int argc, char *argv[], void *userdata) {
1023 _cleanup_(boot_config_free) BootConfig config = {};
1024 sd_id128_t uuid = SD_ID128_NULL;
1028 /* If we lack privileges we invoke find_esp_and_warn() in "unprivileged mode" here, which does two things: turn
1029 * off logging about access errors and turn off potentially privileged device probing. Here we're interested in
1030 * the latter but
not the former
, hence request the mode
, and log about EACCES
. */
1032 r
= acquire_esp(geteuid() != 0, NULL
, NULL
, NULL
, &uuid
);
1033 if (r
== -EACCES
) /* We really need the ESP path for this call, hence also log about access errors */
1034 return log_error_errno(r
, "Failed to determine ESP: %m");
1038 r
= boot_entries_load_config(arg_path
, &config
);
1040 return log_error_errno(r
, "Failed to load bootspec config from \"%s/loader\": %m",
1043 printf("Available boot entries:\n");
1045 for (n
= 0; n
< config
.n_entries
; n
++) {
1046 const BootEntry
*e
= &config
.entries
[n
];
1048 printf(" title: %s%s%s%s%s%s\n",
1050 boot_entry_title(e
),
1052 ansi_highlight_green(),
1053 n
== (unsigned) config
.default_entry
? " (default)" : "",
1056 printf(" version: %s\n", e
->version
);
1058 printf(" machine-id: %s\n", e
->machine_id
);
1059 if (e
->architecture
)
1060 printf(" architecture: %s\n", e
->architecture
);
1062 printf(" linux: %s\n", e
->kernel
);
1063 if (!strv_isempty(e
->initrd
)) {
1064 _cleanup_free_
char *t
;
1066 t
= strv_join(e
->initrd
, " ");
1070 printf(" initrd: %s\n", t
);
1072 if (!strv_isempty(e
->options
)) {
1073 _cleanup_free_
char *t
;
1075 t
= strv_join(e
->options
, " ");
1079 printf(" options: %s\n", t
);
1082 printf(" devicetree: %s\n", e
->device_tree
);
1090 static int verb_install(int argc
, char *argv
[], void *userdata
) {
1092 sd_id128_t uuid
= SD_ID128_NULL
;
1093 uint64_t pstart
= 0, psize
= 0;
1098 r
= acquire_esp(false, &part
, &pstart
, &psize
, &uuid
);
1102 install
= streq(argv
[0], "install");
1104 RUN_WITH_UMASK(0002) {
1105 r
= install_binaries(arg_path
, install
);
1110 r
= install_loader_config(arg_path
);
1116 if (arg_touch_variables
)
1117 r
= install_variables(arg_path
,
1118 part
, pstart
, psize
, uuid
,
1119 "/EFI/systemd/systemd-boot" EFI_MACHINE_TYPE_NAME
".efi",
1125 static int verb_remove(int argc
, char *argv
[], void *userdata
) {
1126 sd_id128_t uuid
= SD_ID128_NULL
;
1129 r
= acquire_esp(false, NULL
, NULL
, NULL
, &uuid
);
1133 r
= remove_binaries(arg_path
);
1135 if (arg_touch_variables
) {
1138 q
= remove_variables(uuid
, "/EFI/systemd/systemd-boot" EFI_MACHINE_TYPE_NAME
".efi", true);
1139 if (q
< 0 && r
== 0)
1146 static int bootctl_main(int argc
, char *argv
[]) {
1148 static const Verb verbs
[] = {
1149 { "help", VERB_ANY
, VERB_ANY
, 0, help
},
1150 { "status", VERB_ANY
, 1, VERB_DEFAULT
, verb_status
},
1151 { "list", VERB_ANY
, 1, 0, verb_list
},
1152 { "install", VERB_ANY
, 1, VERB_MUST_BE_ROOT
, verb_install
},
1153 { "update", VERB_ANY
, 1, VERB_MUST_BE_ROOT
, verb_install
},
1154 { "remove", VERB_ANY
, 1, VERB_MUST_BE_ROOT
, verb_remove
},
1158 return dispatch_verb(argc
, argv
, verbs
, NULL
);
1161 int main(int argc
, char *argv
[]) {
1164 log_parse_environment();
1167 /* If we run in a container, automatically turn of EFI file system access */
1168 if (detect_container() > 0)
1169 arg_touch_variables
= false;
1171 r
= parse_argv(argc
, argv
);
1175 r
= bootctl_main(argc
, argv
);
1179 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;