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"
43 #include "dirent-util.h"
48 #include "locale-util.h"
49 #include "parse-util.h"
51 #include "stat-util.h"
52 #include "string-util.h"
54 #include "terminal-util.h"
55 #include "umask-util.h"
60 static char *arg_path
= NULL
;
61 static bool arg_print_path
= false;
62 static bool arg_touch_variables
= true;
64 static int acquire_esp(
65 bool unprivileged_mode
,
69 sd_id128_t
*ret_uuid
) {
74 /* Find the ESP, and log about errors. Note that find_esp_and_warn() will log in all error cases on its own,
75 * except for ENOKEY (which is good, we want to show our own message in that case, suggesting use of --path=)
76 * and EACCESS (only when we request unprivileged mode; in this case we simply eat up the error here, so that
77 * --list and --status work too, without noise about this). */
79 r
= find_esp_and_warn(arg_path
, unprivileged_mode
, &np
, ret_part
, ret_pstart
, ret_psize
, ret_uuid
);
81 return log_error_errno(r
,
82 "Couldn't find EFI system partition. It is recommended to mount it to /boot or /efi.\n"
83 "Alternatively, use --path= to specify path to mount point.");
87 free_and_replace(arg_path
, np
);
89 log_debug("Using EFI System Partition at %s.", arg_path
);
94 /* search for "#### LoaderInfo: systemd-boot 218 ####" string inside the binary */
95 static int get_file_version(int fd
, char **v
) {
105 if (fstat(fd
, &st
) < 0)
106 return log_error_errno(errno
, "Failed to stat EFI binary: %m");
108 if (st
.st_size
< 27) {
113 buf
= mmap(NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0);
114 if (buf
== MAP_FAILED
)
115 return log_error_errno(errno
, "Failed to memory map EFI binary: %m");
117 s
= memmem(buf
, st
.st_size
- 8, "#### LoaderInfo: ", 17);
122 e
= memmem(s
, st
.st_size
- (s
- buf
), " ####", 5);
123 if (!e
|| e
- s
< 3) {
124 log_error("Malformed version string.");
129 x
= strndup(s
, e
- s
);
137 (void) munmap(buf
, st
.st_size
);
142 static int enumerate_binaries(const char *esp_path
, const char *path
, const char *prefix
) {
144 _cleanup_closedir_
DIR *d
= NULL
;
148 p
= strjoina(esp_path
, "/", path
);
154 return log_error_errno(errno
, "Failed to read \"%s\": %m", p
);
157 FOREACH_DIRENT(de
, d
, break) {
158 _cleanup_close_
int fd
= -1;
159 _cleanup_free_
char *v
= NULL
;
161 if (!endswith_no_case(de
->d_name
, ".efi"))
164 if (prefix
&& !startswith_no_case(de
->d_name
, prefix
))
167 fd
= openat(dirfd(d
), de
->d_name
, O_RDONLY
|O_CLOEXEC
);
169 return log_error_errno(errno
, "Failed to open \"%s/%s\" for reading: %m", p
, de
->d_name
);
171 r
= get_file_version(fd
, &v
);
175 printf(" File: %s/%s/%s (%s)\n", special_glyph(TREE_RIGHT
), path
, de
->d_name
, v
);
177 printf(" File: %s/%s/%s\n", special_glyph(TREE_RIGHT
), path
, de
->d_name
);
184 static int status_binaries(const char *esp_path
, sd_id128_t partition
) {
187 printf("Boot Loader Binaries:\n");
190 printf(" ESP: Cannot find or access mount point of ESP.\n\n");
194 printf(" ESP: %s", esp_path
);
195 if (!sd_id128_is_null(partition
))
196 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
));
199 r
= enumerate_binaries(esp_path
, "EFI/systemd", NULL
);
201 log_error("systemd-boot not installed in ESP.");
205 r
= enumerate_binaries(esp_path
, "EFI/BOOT", "boot");
207 log_error("No default/fallback boot loader installed in ESP.");
216 static int print_efi_option(uint16_t id
, bool in_order
) {
217 _cleanup_free_
char *title
= NULL
;
218 _cleanup_free_
char *path
= NULL
;
219 sd_id128_t partition
;
223 r
= efi_get_boot_option(id
, &title
, &partition
, &path
, &active
);
227 /* print only configured entries with partition information */
228 if (!path
|| sd_id128_is_null(partition
))
231 efi_tilt_backslashes(path
);
233 printf(" Title: %s\n", strna(title
));
234 printf(" ID: 0x%04X\n", id
);
235 printf(" Status: %sactive%s\n", active
? "" : "in", in_order
? ", boot-order" : "");
236 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
));
237 printf(" File: %s%s\n", special_glyph(TREE_RIGHT
), path
);
243 static int status_variables(void) {
244 int n_options
, n_order
;
245 _cleanup_free_
uint16_t *options
= NULL
, *order
= NULL
;
248 n_options
= efi_get_boot_options(&options
);
249 if (n_options
== -ENOENT
)
250 return log_error_errno(n_options
,
251 "Failed to access EFI variables, efivarfs"
252 " needs to be available at /sys/firmware/efi/efivars/.");
254 return log_error_errno(n_options
, "Failed to read EFI boot entries: %m");
256 n_order
= efi_get_boot_order(&order
);
257 if (n_order
== -ENOENT
)
259 else if (n_order
< 0)
260 return log_error_errno(n_order
, "Failed to read EFI boot order.");
262 /* print entries in BootOrder first */
263 printf("Boot Loader Entries in EFI Variables:\n");
264 for (i
= 0; i
< n_order
; i
++)
265 print_efi_option(order
[i
], true);
267 /* print remaining entries */
268 for (i
= 0; i
< n_options
; i
++) {
271 for (j
= 0; j
< n_order
; j
++)
272 if (options
[i
] == order
[j
])
275 print_efi_option(options
[i
], false);
284 static int status_entries(const char *esp_path
, sd_id128_t partition
) {
287 _cleanup_(boot_config_free
) BootConfig config
= {};
289 printf("Default Boot Entry:\n");
291 r
= boot_entries_load_config(esp_path
, &config
);
293 return log_error_errno(r
, "Failed to load bootspec config from \"%s/loader\": %m",
296 if (config
.default_entry
< 0)
297 printf("%zu entries, no entry suitable as default", config
.n_entries
);
299 const BootEntry
*e
= &config
.entries
[config
.default_entry
];
301 printf(" title: %s\n", boot_entry_title(e
));
303 printf(" version: %s\n", e
->version
);
305 printf(" linux: %s\n", e
->kernel
);
306 if (!strv_isempty(e
->initrd
)) {
307 _cleanup_free_
char *t
;
309 t
= strv_join(e
->initrd
, " ");
313 printf(" initrd: %s\n", t
);
315 if (!strv_isempty(e
->options
)) {
316 _cleanup_free_
char *t
;
318 t
= strv_join(e
->options
, " ");
322 printf(" options: %s\n", t
);
325 printf(" devicetree: %s\n", e
->device_tree
);
332 static int compare_product(const char *a
, const char *b
) {
341 return x
< y
? -1 : x
> y
? 1 : 0;
343 return strncmp(a
, b
, x
);
346 static int compare_version(const char *a
, const char *b
) {
350 a
+= strcspn(a
, " ");
352 b
+= strcspn(b
, " ");
355 return strverscmp(a
, b
);
358 static int version_check(int fd_from
, const char *from
, int fd_to
, const char *to
) {
359 _cleanup_free_
char *a
= NULL
, *b
= NULL
;
362 assert(fd_from
>= 0);
367 r
= get_file_version(fd_from
, &a
);
371 log_error("Source file \"%s\" does not carry version information!", from
);
375 r
= get_file_version(fd_to
, &b
);
378 if (r
== 0 || compare_product(a
, b
) != 0) {
379 log_notice("Skipping \"%s\", since it's owned by another boot loader.", to
);
383 if (compare_version(a
, b
) < 0) {
384 log_warning("Skipping \"%s\", since a newer boot loader version exists already.", to
);
391 static int copy_file_with_version_check(const char *from
, const char *to
, bool force
) {
392 _cleanup_close_
int fd_from
= -1, fd_to
= -1;
393 _cleanup_free_
char *t
= NULL
;
396 fd_from
= open(from
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
398 return log_error_errno(errno
, "Failed to open \"%s\" for reading: %m", from
);
401 fd_to
= open(to
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
403 if (errno
!= -ENOENT
)
404 return log_error_errno(errno
, "Failed to open \"%s\" for reading: %m", to
);
406 r
= version_check(fd_from
, from
, fd_to
, to
);
410 if (lseek(fd_from
, 0, SEEK_SET
) == (off_t
) -1)
411 return log_error_errno(errno
, "Failed to seek in \%s\": %m", from
);
413 fd_to
= safe_close(fd_to
);
417 r
= tempfn_random(to
, NULL
, &t
);
421 RUN_WITH_UMASK(0000) {
422 fd_to
= open(t
, O_WRONLY
|O_CREAT
|O_CLOEXEC
|O_EXCL
|O_NOFOLLOW
, 0644);
424 return log_error_errno(errno
, "Failed to open \"%s\" for writing: %m", t
);
427 r
= copy_bytes(fd_from
, fd_to
, (uint64_t) -1, COPY_REFLINK
);
430 return log_error_errno(r
, "Failed to copy data from \"%s\" to \"%s\": %m", from
, t
);
433 (void) copy_times(fd_from
, fd_to
);
437 (void) unlink_noerrno(t
);
438 return log_error_errno(errno
, "Failed to copy data from \"%s\" to \"%s\": %m", from
, t
);
441 r
= renameat(AT_FDCWD
, t
, AT_FDCWD
, to
);
443 (void) unlink_noerrno(t
);
444 return log_error_errno(errno
, "Failed to rename \"%s\" to \"%s\": %m", t
, to
);
447 log_info("Copied \"%s\" to \"%s\".", from
, to
);
452 static int mkdir_one(const char *prefix
, const char *suffix
) {
455 p
= strjoina(prefix
, "/", suffix
);
456 if (mkdir(p
, 0700) < 0) {
458 return log_error_errno(errno
, "Failed to create \"%s\": %m", p
);
460 log_info("Created \"%s\".", p
);
465 static const char *efi_subdirs
[] = {
474 static int create_dirs(const char *esp_path
) {
478 STRV_FOREACH(i
, efi_subdirs
) {
479 r
= mkdir_one(esp_path
, *i
);
487 static int copy_one_file(const char *esp_path
, const char *name
, bool force
) {
491 p
= strjoina(BOOTLIBDIR
"/", name
);
492 q
= strjoina(esp_path
, "/EFI/systemd/", name
);
493 r
= copy_file_with_version_check(p
, q
, force
);
495 if (startswith(name
, "systemd-boot")) {
499 /* Create the EFI default boot loader name (specified for removable devices) */
500 v
= strjoina(esp_path
, "/EFI/BOOT/BOOT",
501 name
+ STRLEN("systemd-boot"));
502 ascii_strupper(strrchr(v
, '/') + 1);
504 k
= copy_file_with_version_check(p
, v
, force
);
512 static int install_binaries(const char *esp_path
, bool force
) {
514 _cleanup_closedir_
DIR *d
= NULL
;
518 /* Don't create any of these directories when we are
519 * just updating. When we update we'll drop-in our
520 * files (unless there are newer ones already), but we
521 * won't create the directories for them in the first
523 r
= create_dirs(esp_path
);
528 d
= opendir(BOOTLIBDIR
);
530 return log_error_errno(errno
, "Failed to open \""BOOTLIBDIR
"\": %m
");
532 FOREACH_DIRENT(de, d, break) {
535 if (!endswith_no_case(de->d_name, ".efi
"))
538 k = copy_one_file(esp_path, de->d_name, force);
546 static bool same_entry(uint16_t id, const sd_id128_t uuid, const char *path) {
547 _cleanup_free_ char *opath = NULL;
551 r = efi_get_boot_option(id, NULL, &ouuid, &opath, NULL);
554 if (!sd_id128_equal(uuid, ouuid))
556 if (!streq_ptr(path, opath))
562 static int find_slot(sd_id128_t uuid, const char *path, uint16_t *id) {
563 _cleanup_free_ uint16_t *options = NULL;
566 n = efi_get_boot_options(&options);
570 /* find already existing systemd-boot entry */
571 for (i = 0; i < n; i++)
572 if (same_entry(options[i], uuid, path)) {
577 /* find free slot in the sorted BootXXXX variable list */
578 for (i = 0; i < n; i++)
579 if (i != options[i]) {
584 /* use the next one */
591 static int insert_into_order(uint16_t slot, bool first) {
592 _cleanup_free_ uint16_t *order = NULL;
596 n = efi_get_boot_order(&order);
598 /* no entry, add us */
599 return efi_set_boot_order(&slot, 1);
601 /* are we the first and only one? */
602 if (n == 1 && order[0] == slot)
605 /* are we already in the boot order? */
606 for (i = 0; i < n; i++) {
607 if (order[i] != slot)
610 /* we do not require to be the first one, all is fine */
614 /* move us to the first slot */
615 memmove(order + 1, order, i * sizeof(uint16_t));
617 return efi_set_boot_order(order, n);
621 t = realloc(order, (n + 1) * sizeof(uint16_t));
626 /* add us to the top or end of the list */
628 memmove(order + 1, order, n * sizeof(uint16_t));
633 return efi_set_boot_order(order, n + 1);
636 static int remove_from_order(uint16_t slot) {
637 _cleanup_free_ uint16_t *order = NULL;
640 n = efi_get_boot_order(&order);
644 for (i = 0; i < n; i++) {
645 if (order[i] != slot)
649 memmove(order + i, order + i+1, (n - i) * sizeof(uint16_t));
650 return efi_set_boot_order(order, n - 1);
656 static int install_variables(const char *esp_path,
657 uint32_t part, uint64_t pstart, uint64_t psize,
658 sd_id128_t uuid, const char *path,
664 if (!is_efi_boot()) {
665 log_warning("Not booted with EFI
, skipping EFI variable setup
.");
669 p = strjoina(esp_path, path);
670 if (access(p, F_OK) < 0) {
674 return log_error_errno(errno, "Cannot access
\"%s
\": %m
", p);
677 r = find_slot(uuid, path, &slot);
679 return log_error_errno(r,
681 "Failed to access EFI variables
. Is the
\"efivarfs
\" filesystem mounted
?" :
682 "Failed to determine current boot order
: %m
");
684 if (first || r == 0) {
685 r = efi_add_boot_option(slot, "Linux Boot Manager
",
689 return log_error_errno(r, "Failed to create EFI Boot variable entry
: %m
");
691 log_info("Created EFI boot entry
\"Linux Boot Manager
\".");
694 return insert_into_order(slot, first);
697 static int remove_boot_efi(const char *esp_path) {
699 _cleanup_closedir_ DIR *d = NULL;
703 p = strjoina(esp_path, "/EFI
/BOOT
");
709 return log_error_errno(errno, "Failed to open directory
\"%s
\": %m
", p);
712 FOREACH_DIRENT(de, d, break) {
713 _cleanup_close_ int fd = -1;
714 _cleanup_free_ char *v = NULL;
716 if (!endswith_no_case(de->d_name, ".efi
"))
719 if (!startswith_no_case(de->d_name, "boot
"))
722 fd = openat(dirfd(d), de->d_name, O_RDONLY|O_CLOEXEC);
724 return log_error_errno(errno, "Failed to open
\"%s
/%s
\" for reading
: %m
", p, de->d_name);
726 r = get_file_version(fd, &v);
729 if (r > 0 && startswith(v, "systemd
-boot
")) {
730 r = unlinkat(dirfd(d), de->d_name, 0);
732 return log_error_errno(errno, "Failed to remove
\"%s
/%s
\": %m
", p, de->d_name);
734 log_info("Removed
\"%s
/%s
\".", p, de->d_name);
743 static int rmdir_one(const char *prefix, const char *suffix) {
746 p = strjoina(prefix, "/", suffix);
748 if (!IN_SET(errno, ENOENT, ENOTEMPTY))
749 return log_error_errno(errno, "Failed to remove
\"%s
\": %m
", p);
751 log_info("Removed
\"%s
\".", p);
756 static int remove_binaries(const char *esp_path) {
761 p = strjoina(esp_path, "/EFI
/systemd
");
762 r = rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL);
764 q = remove_boot_efi(esp_path);
768 for (i = ELEMENTSOF(efi_subdirs)-1; i > 0; i--) {
769 q = rmdir_one(esp_path, efi_subdirs[i-1]);
777 static int remove_variables(sd_id128_t uuid, const char *path, bool in_order) {
784 r = find_slot(uuid, path, &slot);
788 r = efi_remove_boot_option(slot);
793 return remove_from_order(slot);
798 static int install_loader_config(const char *esp_path) {
800 char machine_string[SD_ID128_STRING_MAX];
801 _cleanup_(unlink_and_freep) char *t = NULL;
802 _cleanup_fclose_ FILE *f = NULL;
803 sd_id128_t machine_id;
807 r = sd_id128_get_machine(&machine_id);
809 return log_error_errno(r, "Failed to get machine id
: %m
");
811 p = strjoina(esp_path, "/loader
/loader
.conf
");
813 if (access(p, F_OK) >= 0) /* Silently skip creation if the file already exists (early check) */
816 fd = open_tmpfile_linkable(p, O_WRONLY|O_CLOEXEC, &t);
818 return log_error_errno(fd, "Failed to open
\"%s
\" for writing
: %m
", p);
820 f = fdopen(fd, "we
");
826 fprintf(f, "#timeout 3\n");
827 fprintf(f, "default %s-*\n", sd_id128_to_string(machine_id, machine_string));
829 r = fflush_sync_and_check(f);
831 return log_error_errno(r, "Failed to write \"%s\": %m", p);
833 r = link_tmpfile(fd, t, p);
835 return 0; /* Silently skip creation if the file exists now (recheck) */
837 return log_error_errno(r, "Failed to move \"%s\" into place: %m", p);
844 static int help(int argc, char *argv[], void *userdata) {
846 printf("%s [COMMAND] [OPTIONS...]\n"
848 "Install, update or remove the systemd-boot EFI boot manager.\n\n"
849 " -h --help Show this help\n"
850 " --version Print version\n"
851 " --path=PATH Path to the EFI System Partition (ESP)\n"
852 " -p --print-path Print path to the EFI partition\n"
853 " --no-variables Don't touch EFI variables\n"
856 " status Show status of installed systemd-boot and EFI variables\n"
857 " list List boot entries\n"
858 " install Install systemd-boot to the ESP and EFI variables\n"
859 " update Update systemd-boot in the ESP and EFI variables\n"
860 " remove Remove systemd-boot from the ESP and EFI variables\n",
861 program_invocation_short_name);
866 static int parse_argv(int argc, char *argv[]) {
873 static const struct option options[] = {
874 { "help", no_argument, NULL, 'h' },
875 { "version", no_argument, NULL, ARG_VERSION },
876 { "path", required_argument, NULL, ARG_PATH },
877 { "print-path", no_argument, NULL, 'p' },
878 { "no-variables", no_argument, NULL, ARG_NO_VARIABLES },
887 while ((c = getopt_long(argc, argv, "hp", options, NULL)) >= 0)
898 r = free_and_strdup(&arg_path, optarg);
904 arg_print_path = true;
907 case ARG_NO_VARIABLES:
908 arg_touch_variables = false;
915 assert_not_reached("Unknown option");
921 static void read_loader_efi_var(const char *name, char **var) {
924 r = efi_get_variable_string(EFI_VENDOR_LOADER, name, var);
925 if (r < 0 && r != -ENOENT)
926 log_warning_errno(r, "Failed to read EFI variable %s: %m", name);
929 static int verb_status(int argc, char *argv[], void *userdata) {
931 sd_id128_t uuid = SD_ID128_NULL;
934 r = acquire_esp(geteuid() != 0, NULL, NULL, NULL, &uuid);
936 if (arg_print_path) {
937 if (r == -EACCES) /* If we couldn't acquire the ESP path, log about access errors (which is the only
938 * error the
find_esp_and_warn() won
't log on its own) */
939 return log_error_errno(r, "Failed to determine ESP: %m");
947 r = 0; /* If we couldn't determine the path
, then don
't consider that a problem from here on, just show what we
951 _cleanup_free_ char *fw_type = NULL, *fw_info = NULL, *loader = NULL, *loader_path = NULL;
952 sd_id128_t loader_part_uuid = SD_ID128_NULL;
954 read_loader_efi_var("LoaderFirmwareType", &fw_type);
955 read_loader_efi_var("LoaderFirmwareInfo", &fw_info);
956 read_loader_efi_var("LoaderInfo", &loader);
957 read_loader_efi_var("LoaderImageIdentifier", &loader_path);
960 efi_tilt_backslashes(loader_path);
962 k = efi_loader_get_device_part_uuid(&loader_part_uuid);
963 if (k < 0 && k != -ENOENT)
964 r = log_warning_errno(k, "Failed to read EFI variable LoaderDevicePartUUID: %m");
967 printf(" Firmware: %s (%s)\n", strna(fw_type), strna(fw_info));
969 k = is_efi_secure_boot();
971 r = log_warning_errno(k, "Failed to query secure boot status: %m");
973 printf(" Secure Boot: %sd\n", enable_disable(k));
975 k = is_efi_secure_boot_setup_mode();
977 r = log_warning_errno(k, "Failed to query secure boot mode: %m");
979 printf(" Setup Mode: %s\n", k ? "setup" : "user");
982 printf("Current Loader:\n");
983 printf(" Product: %s\n", strna(loader));
984 if (!sd_id128_is_null(loader_part_uuid))
985 printf(" ESP: /dev/disk/by-partuuid/%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
986 SD_ID128_FORMAT_VAL(loader_part_uuid));
988 printf(" ESP: n/a\n");
989 printf(" File: %s%s\n", special_glyph(TREE_RIGHT), strna(loader_path));
992 printf("System:\n Not booted with EFI\n\n");
995 k = status_binaries(arg_path, uuid);
1000 if (is_efi_boot()) {
1001 k = status_variables();
1007 k = status_entries(arg_path, uuid);
1015 static int verb_list(int argc, char *argv[], void *userdata) {
1016 _cleanup_(boot_config_free) BootConfig config = {};
1017 sd_id128_t uuid = SD_ID128_NULL;
1021 /* If we lack privileges we invoke find_esp_and_warn() in "unprivileged mode" here, which does two things: turn
1022 * off logging about access errors and turn off potentially privileged device probing. Here we're interested in
1023 * the latter but
not the former
, hence request the mode
, and log about EACCES
. */
1025 r
= acquire_esp(geteuid() != 0, NULL
, NULL
, NULL
, &uuid
);
1026 if (r
== -EACCES
) /* We really need the ESP path for this call, hence also log about access errors */
1027 return log_error_errno(r
, "Failed to determine ESP: %m");
1031 r
= boot_entries_load_config(arg_path
, &config
);
1033 return log_error_errno(r
, "Failed to load bootspec config from \"%s/loader\": %m",
1036 printf("Available boot entries:\n");
1038 for (n
= 0; n
< config
.n_entries
; n
++) {
1039 const BootEntry
*e
= &config
.entries
[n
];
1041 printf(" title: %s%s%s%s%s%s\n",
1043 boot_entry_title(e
),
1045 ansi_highlight_green(),
1046 n
== (unsigned) config
.default_entry
? " (default)" : "",
1049 printf(" version: %s\n", e
->version
);
1051 printf(" machine-id: %s\n", e
->machine_id
);
1052 if (e
->architecture
)
1053 printf(" architecture: %s\n", e
->architecture
);
1055 printf(" linux: %s\n", e
->kernel
);
1056 if (!strv_isempty(e
->initrd
)) {
1057 _cleanup_free_
char *t
;
1059 t
= strv_join(e
->initrd
, " ");
1063 printf(" initrd: %s\n", t
);
1065 if (!strv_isempty(e
->options
)) {
1066 _cleanup_free_
char *t
;
1068 t
= strv_join(e
->options
, " ");
1072 printf(" options: %s\n", t
);
1075 printf(" devicetree: %s\n", e
->device_tree
);
1083 static int verb_install(int argc
, char *argv
[], void *userdata
) {
1085 sd_id128_t uuid
= SD_ID128_NULL
;
1086 uint64_t pstart
= 0, psize
= 0;
1091 r
= acquire_esp(false, &part
, &pstart
, &psize
, &uuid
);
1095 install
= streq(argv
[0], "install");
1097 RUN_WITH_UMASK(0002) {
1098 r
= install_binaries(arg_path
, install
);
1103 r
= install_loader_config(arg_path
);
1109 if (arg_touch_variables
)
1110 r
= install_variables(arg_path
,
1111 part
, pstart
, psize
, uuid
,
1112 "/EFI/systemd/systemd-boot" EFI_MACHINE_TYPE_NAME
".efi",
1118 static int verb_remove(int argc
, char *argv
[], void *userdata
) {
1119 sd_id128_t uuid
= SD_ID128_NULL
;
1122 r
= acquire_esp(false, NULL
, NULL
, NULL
, &uuid
);
1126 r
= remove_binaries(arg_path
);
1128 if (arg_touch_variables
) {
1131 q
= remove_variables(uuid
, "/EFI/systemd/systemd-boot" EFI_MACHINE_TYPE_NAME
".efi", true);
1132 if (q
< 0 && r
== 0)
1139 static int bootctl_main(int argc
, char *argv
[]) {
1141 static const Verb verbs
[] = {
1142 { "help", VERB_ANY
, VERB_ANY
, 0, help
},
1143 { "status", VERB_ANY
, 1, VERB_DEFAULT
, verb_status
},
1144 { "list", VERB_ANY
, 1, 0, verb_list
},
1145 { "install", VERB_ANY
, 1, VERB_MUST_BE_ROOT
, verb_install
},
1146 { "update", VERB_ANY
, 1, VERB_MUST_BE_ROOT
, verb_install
},
1147 { "remove", VERB_ANY
, 1, VERB_MUST_BE_ROOT
, verb_remove
},
1151 return dispatch_verb(argc
, argv
, verbs
, NULL
);
1154 int main(int argc
, char *argv
[]) {
1157 log_parse_environment();
1160 /* If we run in a container, automatically turn of EFI file system access */
1161 if (detect_container() > 0)
1162 arg_touch_variables
= false;
1164 r
= parse_argv(argc
, argv
);
1168 r
= bootctl_main(argc
, argv
);
1172 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;