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", 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
);
439 (void) unlink_noerrno(t
);
440 return log_error_errno(errno
, "Failed to copy data from \"%s\" to \"%s\": %m", from
, t
);
443 r
= renameat(AT_FDCWD
, t
, AT_FDCWD
, to
);
445 (void) unlink_noerrno(t
);
446 return log_error_errno(errno
, "Failed to rename \"%s\" to \"%s\": %m", t
, to
);
449 log_info("Copied \"%s\" to \"%s\".", from
, to
);
454 static int mkdir_one(const char *prefix
, const char *suffix
) {
457 p
= strjoina(prefix
, "/", suffix
);
458 if (mkdir(p
, 0700) < 0) {
460 return log_error_errno(errno
, "Failed to create \"%s\": %m", p
);
462 log_info("Created \"%s\".", p
);
467 static const char *efi_subdirs
[] = {
476 static int create_dirs(const char *esp_path
) {
480 STRV_FOREACH(i
, efi_subdirs
) {
481 r
= mkdir_one(esp_path
, *i
);
489 static int copy_one_file(const char *esp_path
, const char *name
, bool force
) {
493 p
= strjoina(BOOTLIBDIR
"/", name
);
494 q
= strjoina(esp_path
, "/EFI/systemd/", name
);
495 r
= copy_file_with_version_check(p
, q
, force
);
497 if (startswith(name
, "systemd-boot")) {
501 /* Create the EFI default boot loader name (specified for removable devices) */
502 v
= strjoina(esp_path
, "/EFI/BOOT/BOOT",
503 name
+ STRLEN("systemd-boot"));
504 ascii_strupper(strrchr(v
, '/') + 1);
506 k
= copy_file_with_version_check(p
, v
, force
);
514 static int install_binaries(const char *esp_path
, bool force
) {
516 _cleanup_closedir_
DIR *d
= NULL
;
520 /* Don't create any of these directories when we are
521 * just updating. When we update we'll drop-in our
522 * files (unless there are newer ones already), but we
523 * won't create the directories for them in the first
525 r
= create_dirs(esp_path
);
530 d
= opendir(BOOTLIBDIR
);
532 return log_error_errno(errno
, "Failed to open \""BOOTLIBDIR
"\": %m
");
534 FOREACH_DIRENT(de, d, break) {
537 if (!endswith_no_case(de->d_name, ".efi
"))
540 k = copy_one_file(esp_path, de->d_name, force);
548 static bool same_entry(uint16_t id, const sd_id128_t uuid, const char *path) {
549 _cleanup_free_ char *opath = NULL;
553 r = efi_get_boot_option(id, NULL, &ouuid, &opath, NULL);
556 if (!sd_id128_equal(uuid, ouuid))
558 if (!streq_ptr(path, opath))
564 static int find_slot(sd_id128_t uuid, const char *path, uint16_t *id) {
565 _cleanup_free_ uint16_t *options = NULL;
568 n = efi_get_boot_options(&options);
572 /* find already existing systemd-boot entry */
573 for (i = 0; i < n; i++)
574 if (same_entry(options[i], uuid, path)) {
579 /* find free slot in the sorted BootXXXX variable list */
580 for (i = 0; i < n; i++)
581 if (i != options[i]) {
586 /* use the next one */
593 static int insert_into_order(uint16_t slot, bool first) {
594 _cleanup_free_ uint16_t *order = NULL;
598 n = efi_get_boot_order(&order);
600 /* no entry, add us */
601 return efi_set_boot_order(&slot, 1);
603 /* are we the first and only one? */
604 if (n == 1 && order[0] == slot)
607 /* are we already in the boot order? */
608 for (i = 0; i < n; i++) {
609 if (order[i] != slot)
612 /* we do not require to be the first one, all is fine */
616 /* move us to the first slot */
617 memmove(order + 1, order, i * sizeof(uint16_t));
619 return efi_set_boot_order(order, n);
623 t = realloc(order, (n + 1) * sizeof(uint16_t));
628 /* add us to the top or end of the list */
630 memmove(order + 1, order, n * sizeof(uint16_t));
635 return efi_set_boot_order(order, n + 1);
638 static int remove_from_order(uint16_t slot) {
639 _cleanup_free_ uint16_t *order = NULL;
642 n = efi_get_boot_order(&order);
646 for (i = 0; i < n; i++) {
647 if (order[i] != slot)
651 memmove(order + i, order + i+1, (n - i) * sizeof(uint16_t));
652 return efi_set_boot_order(order, n - 1);
658 static int install_variables(const char *esp_path,
659 uint32_t part, uint64_t pstart, uint64_t psize,
660 sd_id128_t uuid, const char *path,
666 if (!is_efi_boot()) {
667 log_warning("Not booted with EFI
, skipping EFI variable setup
.");
671 p = strjoina(esp_path, path);
672 if (access(p, F_OK) < 0) {
676 return log_error_errno(errno, "Cannot access
\"%s
\": %m
", p);
679 r = find_slot(uuid, path, &slot);
681 return log_error_errno(r,
683 "Failed to access EFI variables
. Is the
\"efivarfs
\" filesystem mounted
?" :
684 "Failed to determine current boot order
: %m
");
686 if (first || r == 0) {
687 r = efi_add_boot_option(slot, "Linux Boot Manager
",
691 return log_error_errno(r, "Failed to create EFI Boot variable entry
: %m
");
693 log_info("Created EFI boot entry
\"Linux Boot Manager
\".");
696 return insert_into_order(slot, first);
699 static int remove_boot_efi(const char *esp_path) {
701 _cleanup_closedir_ DIR *d = NULL;
705 p = strjoina(esp_path, "/EFI
/BOOT
");
711 return log_error_errno(errno, "Failed to open directory
\"%s
\": %m
", p);
714 FOREACH_DIRENT(de, d, break) {
715 _cleanup_close_ int fd = -1;
716 _cleanup_free_ char *v = NULL;
718 if (!endswith_no_case(de->d_name, ".efi
"))
721 if (!startswith_no_case(de->d_name, "boot
"))
724 fd = openat(dirfd(d), de->d_name, O_RDONLY|O_CLOEXEC);
726 return log_error_errno(errno, "Failed to open
\"%s
/%s
\" for reading
: %m
", p, de->d_name);
728 r = get_file_version(fd, &v);
731 if (r > 0 && startswith(v, "systemd
-boot
")) {
732 r = unlinkat(dirfd(d), de->d_name, 0);
734 return log_error_errno(errno, "Failed to remove
\"%s
/%s
\": %m
", p, de->d_name);
736 log_info("Removed
\"%s
/%s
\".", p, de->d_name);
745 static int rmdir_one(const char *prefix, const char *suffix) {
748 p = strjoina(prefix, "/", suffix);
750 if (!IN_SET(errno, ENOENT, ENOTEMPTY))
751 return log_error_errno(errno, "Failed to remove
\"%s
\": %m
", p);
753 log_info("Removed
\"%s
\".", p);
758 static int remove_binaries(const char *esp_path) {
763 p = strjoina(esp_path, "/EFI
/systemd
");
764 r = rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL);
766 q = remove_boot_efi(esp_path);
770 for (i = ELEMENTSOF(efi_subdirs)-1; i > 0; i--) {
771 q = rmdir_one(esp_path, efi_subdirs[i-1]);
779 static int remove_variables(sd_id128_t uuid, const char *path, bool in_order) {
786 r = find_slot(uuid, path, &slot);
790 r = efi_remove_boot_option(slot);
795 return remove_from_order(slot);
800 static int install_loader_config(const char *esp_path) {
802 char machine_string[SD_ID128_STRING_MAX];
803 _cleanup_(unlink_and_freep) char *t = NULL;
804 _cleanup_fclose_ FILE *f = NULL;
805 sd_id128_t machine_id;
809 r = sd_id128_get_machine(&machine_id);
811 return log_error_errno(r, "Failed to get machine id
: %m
");
813 p = strjoina(esp_path, "/loader
/loader
.conf
");
815 if (access(p, F_OK) >= 0) /* Silently skip creation if the file already exists (early check) */
818 fd = open_tmpfile_linkable(p, O_WRONLY|O_CLOEXEC, &t);
820 return log_error_errno(fd, "Failed to open
\"%s
\" for writing
: %m
", p);
822 f = fdopen(fd, "we
");
828 fprintf(f, "#timeout 3\n");
829 fprintf(f, "default %s-*\n", sd_id128_to_string(machine_id, machine_string));
831 r = fflush_sync_and_check(f);
833 return log_error_errno(r, "Failed to write \"%s\": %m", p);
835 r = link_tmpfile(fd, t, p);
837 return 0; /* Silently skip creation if the file exists now (recheck) */
839 return log_error_errno(r, "Failed to move \"%s\" into place: %m", p);
846 static int help(int argc, char *argv[], void *userdata) {
848 printf("%s [COMMAND] [OPTIONS...]\n"
850 "Install, update or remove the systemd-boot EFI boot manager.\n\n"
851 " -h --help Show this help\n"
852 " --version Print version\n"
853 " --path=PATH Path to the EFI System Partition (ESP)\n"
854 " -p --print-path Print path to the EFI partition\n"
855 " --no-variables Don't touch EFI variables\n"
858 " status Show status of installed systemd-boot and EFI variables\n"
859 " list List boot entries\n"
860 " install Install systemd-boot to the ESP and EFI variables\n"
861 " update Update systemd-boot in the ESP and EFI variables\n"
862 " remove Remove systemd-boot from the ESP and EFI variables\n",
863 program_invocation_short_name);
868 static int parse_argv(int argc, char *argv[]) {
875 static const struct option options[] = {
876 { "help", no_argument, NULL, 'h' },
877 { "version", no_argument, NULL, ARG_VERSION },
878 { "path", required_argument, NULL, ARG_PATH },
879 { "print-path", no_argument, NULL, 'p' },
880 { "no-variables", no_argument, NULL, ARG_NO_VARIABLES },
889 while ((c = getopt_long(argc, argv, "hp", options, NULL)) >= 0)
900 r = free_and_strdup(&arg_path, optarg);
906 arg_print_path = true;
909 case ARG_NO_VARIABLES:
910 arg_touch_variables = false;
917 assert_not_reached("Unknown option");
923 static void read_loader_efi_var(const char *name, char **var) {
926 r = efi_get_variable_string(EFI_VENDOR_LOADER, name, var);
927 if (r < 0 && r != -ENOENT)
928 log_warning_errno(r, "Failed to read EFI variable %s: %m", name);
931 static int verb_status(int argc, char *argv[], void *userdata) {
933 sd_id128_t uuid = SD_ID128_NULL;
936 r = acquire_esp(geteuid() != 0, NULL, NULL, NULL, &uuid);
938 if (arg_print_path) {
939 if (r == -EACCES) /* If we couldn't acquire the ESP path, log about access errors (which is the only
940 * error the
find_esp_and_warn() won
't log on its own) */
941 return log_error_errno(r, "Failed to determine ESP: %m");
949 r = 0; /* If we couldn't determine the path
, then don
't consider that a problem from here on, just show what we
953 _cleanup_free_ char *fw_type = NULL, *fw_info = NULL, *loader = NULL, *loader_path = NULL;
954 sd_id128_t loader_part_uuid = SD_ID128_NULL;
956 read_loader_efi_var("LoaderFirmwareType", &fw_type);
957 read_loader_efi_var("LoaderFirmwareInfo", &fw_info);
958 read_loader_efi_var("LoaderInfo", &loader);
959 read_loader_efi_var("LoaderImageIdentifier", &loader_path);
962 efi_tilt_backslashes(loader_path);
964 k = efi_loader_get_device_part_uuid(&loader_part_uuid);
965 if (k < 0 && k != -ENOENT)
966 r = log_warning_errno(k, "Failed to read EFI variable LoaderDevicePartUUID: %m");
969 printf(" Firmware: %s (%s)\n", strna(fw_type), strna(fw_info));
971 k = is_efi_secure_boot();
973 r = log_warning_errno(k, "Failed to query secure boot status: %m");
975 printf(" Secure Boot: %sd\n", enable_disable(k));
977 k = is_efi_secure_boot_setup_mode();
979 r = log_warning_errno(k, "Failed to query secure boot mode: %m");
981 printf(" Setup Mode: %s\n", k ? "setup" : "user");
984 printf("Current Loader:\n");
985 printf(" Product: %s\n", strna(loader));
986 if (!sd_id128_is_null(loader_part_uuid))
987 printf(" ESP: /dev/disk/by-partuuid/%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
988 SD_ID128_FORMAT_VAL(loader_part_uuid));
990 printf(" ESP: n/a\n");
991 printf(" File: %s%s\n", special_glyph(TREE_RIGHT), strna(loader_path));
994 printf("System:\n Not booted with EFI\n\n");
997 k = status_binaries(arg_path, uuid);
1002 if (is_efi_boot()) {
1003 k = status_variables();
1009 k = status_entries(arg_path, uuid);
1017 static int verb_list(int argc, char *argv[], void *userdata) {
1018 _cleanup_(boot_config_free) BootConfig config = {};
1019 sd_id128_t uuid = SD_ID128_NULL;
1023 /* If we lack privileges we invoke find_esp_and_warn() in "unprivileged mode" here, which does two things: turn
1024 * off logging about access errors and turn off potentially privileged device probing. Here we're interested in
1025 * the latter but
not the former
, hence request the mode
, and log about EACCES
. */
1027 r
= acquire_esp(geteuid() != 0, NULL
, NULL
, NULL
, &uuid
);
1028 if (r
== -EACCES
) /* We really need the ESP path for this call, hence also log about access errors */
1029 return log_error_errno(r
, "Failed to determine ESP: %m");
1033 r
= boot_entries_load_config(arg_path
, &config
);
1035 return log_error_errno(r
, "Failed to load bootspec config from \"%s/loader\": %m",
1038 printf("Available boot entries:\n");
1040 for (n
= 0; n
< config
.n_entries
; n
++) {
1041 const BootEntry
*e
= &config
.entries
[n
];
1043 printf(" title: %s%s%s%s%s%s\n",
1045 boot_entry_title(e
),
1047 ansi_highlight_green(),
1048 n
== (unsigned) config
.default_entry
? " (default)" : "",
1051 printf(" version: %s\n", e
->version
);
1053 printf(" machine-id: %s\n", e
->machine_id
);
1054 if (e
->architecture
)
1055 printf(" architecture: %s\n", e
->architecture
);
1057 printf(" linux: %s\n", e
->kernel
);
1058 if (!strv_isempty(e
->initrd
)) {
1059 _cleanup_free_
char *t
;
1061 t
= strv_join(e
->initrd
, " ");
1065 printf(" initrd: %s\n", t
);
1067 if (!strv_isempty(e
->options
)) {
1068 _cleanup_free_
char *t
;
1070 t
= strv_join(e
->options
, " ");
1074 printf(" options: %s\n", t
);
1077 printf(" devicetree: %s\n", e
->device_tree
);
1085 static int verb_install(int argc
, char *argv
[], void *userdata
) {
1087 sd_id128_t uuid
= SD_ID128_NULL
;
1088 uint64_t pstart
= 0, psize
= 0;
1093 r
= acquire_esp(false, &part
, &pstart
, &psize
, &uuid
);
1097 install
= streq(argv
[0], "install");
1099 RUN_WITH_UMASK(0002) {
1100 r
= install_binaries(arg_path
, install
);
1105 r
= install_loader_config(arg_path
);
1111 if (arg_touch_variables
)
1112 r
= install_variables(arg_path
,
1113 part
, pstart
, psize
, uuid
,
1114 "/EFI/systemd/systemd-boot" EFI_MACHINE_TYPE_NAME
".efi",
1120 static int verb_remove(int argc
, char *argv
[], void *userdata
) {
1121 sd_id128_t uuid
= SD_ID128_NULL
;
1124 r
= acquire_esp(false, NULL
, NULL
, NULL
, &uuid
);
1128 r
= remove_binaries(arg_path
);
1130 if (arg_touch_variables
) {
1133 q
= remove_variables(uuid
, "/EFI/systemd/systemd-boot" EFI_MACHINE_TYPE_NAME
".efi", true);
1134 if (q
< 0 && r
== 0)
1141 static int bootctl_main(int argc
, char *argv
[]) {
1143 static const Verb verbs
[] = {
1144 { "help", VERB_ANY
, VERB_ANY
, 0, help
},
1145 { "status", VERB_ANY
, 1, VERB_DEFAULT
, verb_status
},
1146 { "list", VERB_ANY
, 1, 0, verb_list
},
1147 { "install", VERB_ANY
, 1, VERB_MUST_BE_ROOT
, verb_install
},
1148 { "update", VERB_ANY
, 1, VERB_MUST_BE_ROOT
, verb_install
},
1149 { "remove", VERB_ANY
, 1, VERB_MUST_BE_ROOT
, verb_remove
},
1153 return dispatch_verb(argc
, argv
, verbs
, NULL
);
1156 int main(int argc
, char *argv
[]) {
1159 log_parse_environment();
1162 /* If we run in a container, automatically turn of EFI file system access */
1163 if (detect_container() > 0)
1164 arg_touch_variables
= false;
1166 r
= parse_argv(argc
, argv
);
1170 r
= bootctl_main(argc
, argv
);
1174 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;