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", name
+ strlen("systemd-boot"));
501 ascii_strupper(strrchr(v
, '/') + 1);
503 k
= copy_file_with_version_check(p
, v
, force
);
511 static int install_binaries(const char *esp_path
, bool force
) {
513 _cleanup_closedir_
DIR *d
= NULL
;
517 /* Don't create any of these directories when we are
518 * just updating. When we update we'll drop-in our
519 * files (unless there are newer ones already), but we
520 * won't create the directories for them in the first
522 r
= create_dirs(esp_path
);
527 d
= opendir(BOOTLIBDIR
);
529 return log_error_errno(errno
, "Failed to open \""BOOTLIBDIR
"\": %m
");
531 FOREACH_DIRENT(de, d, break) {
534 if (!endswith_no_case(de->d_name, ".efi
"))
537 k = copy_one_file(esp_path, de->d_name, force);
545 static bool same_entry(uint16_t id, const sd_id128_t uuid, const char *path) {
546 _cleanup_free_ char *opath = NULL;
550 r = efi_get_boot_option(id, NULL, &ouuid, &opath, NULL);
553 if (!sd_id128_equal(uuid, ouuid))
555 if (!streq_ptr(path, opath))
561 static int find_slot(sd_id128_t uuid, const char *path, uint16_t *id) {
562 _cleanup_free_ uint16_t *options = NULL;
565 n = efi_get_boot_options(&options);
569 /* find already existing systemd-boot entry */
570 for (i = 0; i < n; i++)
571 if (same_entry(options[i], uuid, path)) {
576 /* find free slot in the sorted BootXXXX variable list */
577 for (i = 0; i < n; i++)
578 if (i != options[i]) {
583 /* use the next one */
590 static int insert_into_order(uint16_t slot, bool first) {
591 _cleanup_free_ uint16_t *order = NULL;
595 n = efi_get_boot_order(&order);
597 /* no entry, add us */
598 return efi_set_boot_order(&slot, 1);
600 /* are we the first and only one? */
601 if (n == 1 && order[0] == slot)
604 /* are we already in the boot order? */
605 for (i = 0; i < n; i++) {
606 if (order[i] != slot)
609 /* we do not require to be the first one, all is fine */
613 /* move us to the first slot */
614 memmove(order + 1, order, i * sizeof(uint16_t));
616 return efi_set_boot_order(order, n);
620 t = realloc(order, (n + 1) * sizeof(uint16_t));
625 /* add us to the top or end of the list */
627 memmove(order + 1, order, n * sizeof(uint16_t));
632 return efi_set_boot_order(order, n + 1);
635 static int remove_from_order(uint16_t slot) {
636 _cleanup_free_ uint16_t *order = NULL;
639 n = efi_get_boot_order(&order);
643 for (i = 0; i < n; i++) {
644 if (order[i] != slot)
648 memmove(order + i, order + i+1, (n - i) * sizeof(uint16_t));
649 return efi_set_boot_order(order, n - 1);
655 static int install_variables(const char *esp_path,
656 uint32_t part, uint64_t pstart, uint64_t psize,
657 sd_id128_t uuid, const char *path,
663 if (!is_efi_boot()) {
664 log_warning("Not booted with EFI
, skipping EFI variable setup
.");
668 p = strjoina(esp_path, path);
669 if (access(p, F_OK) < 0) {
673 return log_error_errno(errno, "Cannot access
\"%s
\": %m
", p);
676 r = find_slot(uuid, path, &slot);
678 return log_error_errno(r,
680 "Failed to access EFI variables
. Is the
\"efivarfs
\" filesystem mounted
?" :
681 "Failed to determine current boot order
: %m
");
683 if (first || r == 0) {
684 r = efi_add_boot_option(slot, "Linux Boot Manager
",
688 return log_error_errno(r, "Failed to create EFI Boot variable entry
: %m
");
690 log_info("Created EFI boot entry
\"Linux Boot Manager
\".");
693 return insert_into_order(slot, first);
696 static int remove_boot_efi(const char *esp_path) {
698 _cleanup_closedir_ DIR *d = NULL;
702 p = strjoina(esp_path, "/EFI
/BOOT
");
708 return log_error_errno(errno, "Failed to open directory
\"%s
\": %m
", p);
711 FOREACH_DIRENT(de, d, break) {
712 _cleanup_close_ int fd = -1;
713 _cleanup_free_ char *v = NULL;
715 if (!endswith_no_case(de->d_name, ".efi
"))
718 if (!startswith_no_case(de->d_name, "boot
"))
721 fd = openat(dirfd(d), de->d_name, O_RDONLY|O_CLOEXEC);
723 return log_error_errno(errno, "Failed to open
\"%s
/%s
\" for reading
: %m
", p, de->d_name);
725 r = get_file_version(fd, &v);
728 if (r > 0 && startswith(v, "systemd
-boot
")) {
729 r = unlinkat(dirfd(d), de->d_name, 0);
731 return log_error_errno(errno, "Failed to remove
\"%s
/%s
\": %m
", p, de->d_name);
733 log_info("Removed
\"%s
/%s
\".", p, de->d_name);
742 static int rmdir_one(const char *prefix, const char *suffix) {
745 p = strjoina(prefix, "/", suffix);
747 if (!IN_SET(errno, ENOENT, ENOTEMPTY))
748 return log_error_errno(errno, "Failed to remove
\"%s
\": %m
", p);
750 log_info("Removed
\"%s
\".", p);
755 static int remove_binaries(const char *esp_path) {
760 p = strjoina(esp_path, "/EFI
/systemd
");
761 r = rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL);
763 q = remove_boot_efi(esp_path);
767 for (i = ELEMENTSOF(efi_subdirs)-1; i > 0; i--) {
768 q = rmdir_one(esp_path, efi_subdirs[i-1]);
776 static int remove_variables(sd_id128_t uuid, const char *path, bool in_order) {
783 r = find_slot(uuid, path, &slot);
787 r = efi_remove_boot_option(slot);
792 return remove_from_order(slot);
797 static int install_loader_config(const char *esp_path) {
799 char machine_string[SD_ID128_STRING_MAX];
800 _cleanup_(unlink_and_freep) char *t = NULL;
801 _cleanup_fclose_ FILE *f = NULL;
802 sd_id128_t machine_id;
806 r = sd_id128_get_machine(&machine_id);
808 return log_error_errno(r, "Failed to get machine id
: %m
");
810 p = strjoina(esp_path, "/loader
/loader
.conf
");
812 if (access(p, F_OK) >= 0) /* Silently skip creation if the file already exists (early check) */
815 fd = open_tmpfile_linkable(p, O_WRONLY|O_CLOEXEC, &t);
817 return log_error_errno(fd, "Failed to open
\"%s
\" for writing
: %m
", p);
819 f = fdopen(fd, "we
");
825 fprintf(f, "#timeout 3\n");
826 fprintf(f, "default %s-*\n", sd_id128_to_string(machine_id, machine_string));
828 r = fflush_sync_and_check(f);
830 return log_error_errno(r, "Failed to write \"%s\": %m", p);
832 r = link_tmpfile(fd, t, p);
834 return 0; /* Silently skip creation if the file exists now (recheck) */
836 return log_error_errno(r, "Failed to move \"%s\" into place: %m", p);
843 static int help(int argc, char *argv[], void *userdata) {
845 printf("%s [COMMAND] [OPTIONS...]\n"
847 "Install, update or remove the systemd-boot EFI boot manager.\n\n"
848 " -h --help Show this help\n"
849 " --version Print version\n"
850 " --path=PATH Path to the EFI System Partition (ESP)\n"
851 " -p --print-path Print path to the EFI partition\n"
852 " --no-variables Don't touch EFI variables\n"
855 " status Show status of installed systemd-boot and EFI variables\n"
856 " list List boot entries\n"
857 " install Install systemd-boot to the ESP and EFI variables\n"
858 " update Update systemd-boot in the ESP and EFI variables\n"
859 " remove Remove systemd-boot from the ESP and EFI variables\n",
860 program_invocation_short_name);
865 static int parse_argv(int argc, char *argv[]) {
872 static const struct option options[] = {
873 { "help", no_argument, NULL, 'h' },
874 { "version", no_argument, NULL, ARG_VERSION },
875 { "path", required_argument, NULL, ARG_PATH },
876 { "print-path", no_argument, NULL, 'p' },
877 { "no-variables", no_argument, NULL, ARG_NO_VARIABLES },
886 while ((c = getopt_long(argc, argv, "hp", options, NULL)) >= 0)
897 r = free_and_strdup(&arg_path, optarg);
903 arg_print_path = true;
906 case ARG_NO_VARIABLES:
907 arg_touch_variables = false;
914 assert_not_reached("Unknown option");
920 static void read_loader_efi_var(const char *name, char **var) {
923 r = efi_get_variable_string(EFI_VENDOR_LOADER, name, var);
924 if (r < 0 && r != -ENOENT)
925 log_warning_errno(r, "Failed to read EFI variable %s: %m", name);
928 static int verb_status(int argc, char *argv[], void *userdata) {
930 sd_id128_t uuid = SD_ID128_NULL;
933 r = acquire_esp(geteuid() != 0, NULL, NULL, NULL, &uuid);
935 if (arg_print_path) {
936 if (r == -EACCES) /* If we couldn't acquire the ESP path, log about access errors (which is the only
937 * error the
find_esp_and_warn() won
't log on its own) */
938 return log_error_errno(r, "Failed to determine ESP: %m");
946 r = 0; /* If we couldn't determine the path
, then don
't consider that a problem from here on, just show what we
950 _cleanup_free_ char *fw_type = NULL, *fw_info = NULL, *loader = NULL, *loader_path = NULL;
951 sd_id128_t loader_part_uuid = SD_ID128_NULL;
953 read_loader_efi_var("LoaderFirmwareType", &fw_type);
954 read_loader_efi_var("LoaderFirmwareInfo", &fw_info);
955 read_loader_efi_var("LoaderInfo", &loader);
956 read_loader_efi_var("LoaderImageIdentifier", &loader_path);
959 efi_tilt_backslashes(loader_path);
961 k = efi_loader_get_device_part_uuid(&loader_part_uuid);
962 if (k < 0 && k != -ENOENT)
963 r = log_warning_errno(k, "Failed to read EFI variable LoaderDevicePartUUID: %m");
966 printf(" Firmware: %s (%s)\n", strna(fw_type), strna(fw_info));
968 k = is_efi_secure_boot();
970 r = log_warning_errno(k, "Failed to query secure boot status: %m");
972 printf(" Secure Boot: %sd\n", enable_disable(k));
974 k = is_efi_secure_boot_setup_mode();
976 r = log_warning_errno(k, "Failed to query secure boot mode: %m");
978 printf(" Setup Mode: %s\n", k ? "setup" : "user");
981 printf("Current Loader:\n");
982 printf(" Product: %s\n", strna(loader));
983 if (!sd_id128_is_null(loader_part_uuid))
984 printf(" ESP: /dev/disk/by-partuuid/%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
985 SD_ID128_FORMAT_VAL(loader_part_uuid));
987 printf(" ESP: n/a\n");
988 printf(" File: %s%s\n", special_glyph(TREE_RIGHT), strna(loader_path));
991 printf("System:\n Not booted with EFI\n\n");
994 k = status_binaries(arg_path, uuid);
1000 k = status_variables();
1006 k = status_entries(arg_path, uuid);
1014 static int verb_list(int argc, char *argv[], void *userdata) {
1015 _cleanup_(boot_config_free) BootConfig config = {};
1016 sd_id128_t uuid = SD_ID128_NULL;
1020 /* If we lack privileges we invoke find_esp_and_warn() in "unprivileged mode" here, which does two things: turn
1021 * off logging about access errors and turn off potentially privileged device probing. Here we're interested in
1022 * the latter but
not the former
, hence request the mode
, and log about EACCES
. */
1024 r
= acquire_esp(geteuid() != 0, NULL
, NULL
, NULL
, &uuid
);
1025 if (r
== -EACCES
) /* We really need the ESP path for this call, hence also log about access errors */
1026 return log_error_errno(r
, "Failed to determine ESP: %m");
1030 r
= boot_entries_load_config(arg_path
, &config
);
1032 return log_error_errno(r
, "Failed to load bootspec config from \"%s/loader\": %m",
1035 printf("Available boot entries:\n");
1037 for (n
= 0; n
< config
.n_entries
; n
++) {
1038 const BootEntry
*e
= &config
.entries
[n
];
1040 printf(" title: %s%s%s%s%s%s\n",
1042 boot_entry_title(e
),
1044 ansi_highlight_green(),
1045 n
== config
.default_entry
? " (default)" : "",
1048 printf(" version: %s\n", e
->version
);
1050 printf(" machine-id: %s\n", e
->machine_id
);
1051 if (e
->architecture
)
1052 printf(" architecture: %s\n", e
->architecture
);
1054 printf(" linux: %s\n", e
->kernel
);
1055 if (!strv_isempty(e
->initrd
)) {
1056 _cleanup_free_
char *t
;
1058 t
= strv_join(e
->initrd
, " ");
1062 printf(" initrd: %s\n", t
);
1064 if (!strv_isempty(e
->options
)) {
1065 _cleanup_free_
char *t
;
1067 t
= strv_join(e
->options
, " ");
1071 printf(" options: %s\n", t
);
1074 printf(" devicetree: %s\n", e
->device_tree
);
1082 static int verb_install(int argc
, char *argv
[], void *userdata
) {
1084 sd_id128_t uuid
= SD_ID128_NULL
;
1085 uint64_t pstart
= 0, psize
= 0;
1090 r
= acquire_esp(false, &part
, &pstart
, &psize
, &uuid
);
1094 install
= streq(argv
[0], "install");
1096 RUN_WITH_UMASK(0002) {
1097 r
= install_binaries(arg_path
, install
);
1102 r
= install_loader_config(arg_path
);
1108 if (arg_touch_variables
)
1109 r
= install_variables(arg_path
,
1110 part
, pstart
, psize
, uuid
,
1111 "/EFI/systemd/systemd-boot" EFI_MACHINE_TYPE_NAME
".efi",
1117 static int verb_remove(int argc
, char *argv
[], void *userdata
) {
1118 sd_id128_t uuid
= SD_ID128_NULL
;
1121 r
= acquire_esp(false, NULL
, NULL
, NULL
, &uuid
);
1125 r
= remove_binaries(arg_path
);
1127 if (arg_touch_variables
) {
1130 q
= remove_variables(uuid
, "/EFI/systemd/systemd-boot" EFI_MACHINE_TYPE_NAME
".efi", true);
1131 if (q
< 0 && r
== 0)
1138 static int bootctl_main(int argc
, char *argv
[]) {
1140 static const Verb verbs
[] = {
1141 { "help", VERB_ANY
, VERB_ANY
, 0, help
},
1142 { "status", VERB_ANY
, 1, VERB_DEFAULT
, verb_status
},
1143 { "list", VERB_ANY
, 1, 0, verb_list
},
1144 { "install", VERB_ANY
, 1, VERB_MUST_BE_ROOT
, verb_install
},
1145 { "update", VERB_ANY
, 1, VERB_MUST_BE_ROOT
, verb_install
},
1146 { "remove", VERB_ANY
, 1, VERB_MUST_BE_ROOT
, verb_remove
},
1150 return dispatch_verb(argc
, argv
, verbs
, NULL
);
1153 int main(int argc
, char *argv
[]) {
1156 log_parse_environment();
1159 /* If we run in a container, automatically turn of EFI file system access */
1160 if (detect_container() > 0)
1161 arg_touch_variables
= false;
1163 r
= parse_argv(argc
, argv
);
1167 r
= bootctl_main(argc
, argv
);
1171 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;