1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
7 #include <linux/magic.h>
15 #include "alloc-util.h"
16 #include "blkid-util.h"
18 #include "chase-symlinks.h"
20 #include "devnum-util.h"
21 #include "dirent-util.h"
22 #include "dissect-image.h"
24 #include "efi-loader.h"
33 #include "glyph-util.h"
34 #include "main-func.h"
36 #include "mount-util.h"
39 #include "parse-argument.h"
40 #include "parse-util.h"
41 #include "pretty-print.h"
42 #include "random-util.h"
44 #include "stat-util.h"
45 #include "stdio-util.h"
46 #include "string-table.h"
47 #include "string-util.h"
49 #include "sync-util.h"
50 #include "terminal-util.h"
51 #include "tmpfile-util.h"
52 #include "tmpfile-util-label.h"
53 #include "tpm2-util.h"
54 #include "umask-util.h"
60 /* EFI_BOOT_OPTION_DESCRIPTION_MAX sets the maximum length for the boot option description
61 * stored in NVRAM. The UEFI spec does not specify a minimum or maximum length for this
62 * string, but we limit the length to something reasonable to prevent from the firmware
63 * having to deal with a potentially too long string. */
64 #define EFI_BOOT_OPTION_DESCRIPTION_MAX ((size_t) 255)
66 static char *arg_esp_path
= NULL
;
67 static char *arg_xbootldr_path
= NULL
;
68 static bool arg_print_esp_path
= false;
69 static bool arg_print_dollar_boot_path
= false;
70 static bool arg_touch_variables
= true;
71 static PagerFlags arg_pager_flags
= 0;
72 static bool arg_graceful
= false;
73 static bool arg_quiet
= false;
74 static int arg_make_entry_directory
= false; /* tri-state: < 0 for automatic logic */
75 static sd_id128_t arg_machine_id
= SD_ID128_NULL
;
76 static char *arg_install_layout
= NULL
;
78 ARG_ENTRY_TOKEN_MACHINE_ID
,
79 ARG_ENTRY_TOKEN_OS_IMAGE_ID
,
80 ARG_ENTRY_TOKEN_OS_ID
,
81 ARG_ENTRY_TOKEN_LITERAL
,
83 } arg_entry_token_type
= ARG_ENTRY_TOKEN_AUTO
;
84 static char *arg_entry_token
= NULL
;
85 static JsonFormatFlags arg_json_format_flags
= JSON_FORMAT_OFF
;
86 static bool arg_arch_all
= false;
87 static char *arg_root
= NULL
;
88 static char *arg_image
= NULL
;
90 ARG_INSTALL_SOURCE_IMAGE
,
91 ARG_INSTALL_SOURCE_HOST
,
92 ARG_INSTALL_SOURCE_AUTO
,
93 } arg_install_source
= ARG_INSTALL_SOURCE_AUTO
;
94 static char *arg_efi_boot_option_description
= NULL
;
96 STATIC_DESTRUCTOR_REGISTER(arg_esp_path
, freep
);
97 STATIC_DESTRUCTOR_REGISTER(arg_xbootldr_path
, freep
);
98 STATIC_DESTRUCTOR_REGISTER(arg_install_layout
, freep
);
99 STATIC_DESTRUCTOR_REGISTER(arg_entry_token
, freep
);
100 STATIC_DESTRUCTOR_REGISTER(arg_root
, freep
);
101 STATIC_DESTRUCTOR_REGISTER(arg_image
, freep
);
102 STATIC_DESTRUCTOR_REGISTER(arg_efi_boot_option_description
, freep
);
104 static const char *arg_dollar_boot_path(void) {
105 /* $BOOT shall be the XBOOTLDR partition if it exists, and otherwise the ESP */
106 return arg_xbootldr_path
?: arg_esp_path
;
109 static const char *pick_efi_boot_option_description(void) {
110 return arg_efi_boot_option_description
?: "Linux Boot Manager";
113 static int acquire_esp(
114 bool unprivileged_mode
,
117 uint64_t *ret_pstart
,
119 sd_id128_t
*ret_uuid
,
125 /* Find the ESP, and log about errors. Note that find_esp_and_warn() will log in all error cases on
126 * its own, except for ENOKEY (which is good, we want to show our own message in that case,
127 * suggesting use of --esp-path=) and EACCESS (only when we request unprivileged mode; in this case
128 * we simply eat up the error here, so that --list and --status work too, without noise about
131 r
= find_esp_and_warn(arg_root
, arg_esp_path
, unprivileged_mode
, &np
, ret_part
, ret_pstart
, ret_psize
, ret_uuid
, ret_devid
);
134 return log_full_errno(arg_quiet
? LOG_DEBUG
: LOG_INFO
, r
,
135 "Couldn't find EFI system partition, skipping.");
137 return log_error_errno(r
,
138 "Couldn't find EFI system partition. It is recommended to mount it to /boot or /efi.\n"
139 "Alternatively, use --esp-path= to specify path to mount point.");
144 free_and_replace(arg_esp_path
, np
);
145 log_debug("Using EFI System Partition at %s.", arg_esp_path
);
150 static int acquire_xbootldr(
151 bool unprivileged_mode
,
152 sd_id128_t
*ret_uuid
,
158 r
= find_xbootldr_and_warn(arg_root
, arg_xbootldr_path
, unprivileged_mode
, &np
, ret_uuid
, ret_devid
);
160 log_debug_errno(r
, "Didn't find an XBOOTLDR partition, using the ESP as $BOOT.");
161 arg_xbootldr_path
= mfree(arg_xbootldr_path
);
164 *ret_uuid
= SD_ID128_NULL
;
172 free_and_replace(arg_xbootldr_path
, np
);
173 log_debug("Using XBOOTLDR partition at %s as $BOOT.", arg_xbootldr_path
);
178 static int load_etc_machine_id(void) {
181 r
= sd_id128_get_machine(&arg_machine_id
);
182 if (IN_SET(r
, -ENOENT
, -ENOMEDIUM
)) /* Not set or empty */
185 return log_error_errno(r
, "Failed to get machine-id: %m");
187 log_debug("Loaded machine ID %s from /etc/machine-id.", SD_ID128_TO_STRING(arg_machine_id
));
191 static int load_etc_machine_info(void) {
192 /* systemd v250 added support to store the kernel-install layout setting and the machine ID to use
193 * for setting up the ESP in /etc/machine-info. The newer /etc/kernel/entry-token file, as well as
194 * the $layout field in /etc/kernel/install.conf are better replacements for this though, hence this
195 * has been deprecated and is only returned for compatibility. */
196 _cleanup_free_
char *s
= NULL
, *layout
= NULL
;
199 r
= parse_env_file(NULL
, "/etc/machine-info",
200 "KERNEL_INSTALL_LAYOUT", &layout
,
201 "KERNEL_INSTALL_MACHINE_ID", &s
);
205 return log_error_errno(r
, "Failed to parse /etc/machine-info: %m");
209 log_notice("Read $KERNEL_INSTALL_MACHINE_ID from /etc/machine-info. "
210 "Please move it to /etc/kernel/entry-token.");
212 r
= sd_id128_from_string(s
, &arg_machine_id
);
214 return log_error_errno(r
, "Failed to parse KERNEL_INSTALL_MACHINE_ID=%s in /etc/machine-info: %m", s
);
216 log_debug("Loaded KERNEL_INSTALL_MACHINE_ID=%s from KERNEL_INSTALL_MACHINE_ID in /etc/machine-info.",
217 SD_ID128_TO_STRING(arg_machine_id
));
220 if (!isempty(layout
)) {
222 log_notice("Read $KERNEL_INSTALL_LAYOUT from /etc/machine-info. "
223 "Please move it to the layout= setting of /etc/kernel/install.conf.");
225 log_debug("KERNEL_INSTALL_LAYOUT=%s is specified in /etc/machine-info.", layout
);
226 free_and_replace(arg_install_layout
, layout
);
232 static int load_etc_kernel_install_conf(void) {
233 _cleanup_free_
char *layout
= NULL
;
236 r
= parse_env_file(NULL
, "/etc/kernel/install.conf",
241 return log_error_errno(r
, "Failed to parse /etc/kernel/install.conf: %m");
243 if (!isempty(layout
)) {
244 log_debug("layout=%s is specified in /etc/machine-info.", layout
);
245 free_and_replace(arg_install_layout
, layout
);
251 static int settle_entry_token(void) {
254 switch (arg_entry_token_type
) {
256 case ARG_ENTRY_TOKEN_AUTO
: {
257 _cleanup_free_
char *buf
= NULL
;
258 r
= read_one_line_file("/etc/kernel/entry-token", &buf
);
259 if (r
< 0 && r
!= -ENOENT
)
260 return log_error_errno(r
, "Failed to read /etc/kernel/entry-token: %m");
263 free_and_replace(arg_entry_token
, buf
);
264 arg_entry_token_type
= ARG_ENTRY_TOKEN_LITERAL
;
265 } else if (sd_id128_is_null(arg_machine_id
)) {
266 _cleanup_free_
char *id
= NULL
, *image_id
= NULL
;
268 r
= parse_os_release(NULL
,
269 "IMAGE_ID", &image_id
,
272 return log_error_errno(r
, "Failed to load /etc/os-release: %m");
274 if (!isempty(image_id
)) {
275 free_and_replace(arg_entry_token
, image_id
);
276 arg_entry_token_type
= ARG_ENTRY_TOKEN_OS_IMAGE_ID
;
277 } else if (!isempty(id
)) {
278 free_and_replace(arg_entry_token
, id
);
279 arg_entry_token_type
= ARG_ENTRY_TOKEN_OS_ID
;
281 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "No machine ID set, and /etc/os-release carries no ID=/IMAGE_ID= fields.");
283 r
= free_and_strdup_warn(&arg_entry_token
, SD_ID128_TO_STRING(arg_machine_id
));
287 arg_entry_token_type
= ARG_ENTRY_TOKEN_MACHINE_ID
;
293 case ARG_ENTRY_TOKEN_MACHINE_ID
:
294 if (sd_id128_is_null(arg_machine_id
))
295 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "No machine ID set.");
297 r
= free_and_strdup_warn(&arg_entry_token
, SD_ID128_TO_STRING(arg_machine_id
));
303 case ARG_ENTRY_TOKEN_OS_IMAGE_ID
: {
304 _cleanup_free_
char *buf
= NULL
;
306 r
= parse_os_release(NULL
, "IMAGE_ID", &buf
);
308 return log_error_errno(r
, "Failed to load /etc/os-release: %m");
311 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "IMAGE_ID= field not set in /etc/os-release.");
313 free_and_replace(arg_entry_token
, buf
);
317 case ARG_ENTRY_TOKEN_OS_ID
: {
318 _cleanup_free_
char *buf
= NULL
;
320 r
= parse_os_release(NULL
, "ID", &buf
);
322 return log_error_errno(r
, "Failed to load /etc/os-release: %m");
325 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "ID= field not set in /etc/os-release.");
327 free_and_replace(arg_entry_token
, buf
);
331 case ARG_ENTRY_TOKEN_LITERAL
:
332 assert(!isempty(arg_entry_token
)); /* already filled in by command line parser */
336 if (isempty(arg_entry_token
) || !(utf8_is_valid(arg_entry_token
) && string_is_safe(arg_entry_token
)))
337 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Selected entry token not valid: %s", arg_entry_token
);
339 log_debug("Using entry token: %s", arg_entry_token
);
343 static bool use_boot_loader_spec_type1(void) {
344 /* If the layout is not specified, or if it is set explicitly to "bls" we assume Boot Loader
345 * Specification Type #1 is the chosen format for our boot loader entries */
346 return !arg_install_layout
|| streq(arg_install_layout
, "bls");
349 static int settle_make_entry_directory(void) {
352 r
= load_etc_machine_id();
356 r
= load_etc_machine_info();
360 r
= load_etc_kernel_install_conf();
364 r
= settle_entry_token();
368 bool layout_type1
= use_boot_loader_spec_type1();
369 if (arg_make_entry_directory
< 0) { /* Automatic mode */
371 if (arg_entry_token
== ARG_ENTRY_TOKEN_MACHINE_ID
) {
372 r
= path_is_temporary_fs("/etc/machine-id");
374 return log_debug_errno(r
, "Couldn't determine whether /etc/machine-id is on a temporary file system: %m");
376 arg_make_entry_directory
= r
== 0;
378 arg_make_entry_directory
= true;
380 arg_make_entry_directory
= false;
383 if (arg_make_entry_directory
> 0 && !layout_type1
)
384 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
385 "KERNEL_INSTALL_LAYOUT=%s is configured, but Boot Loader Specification Type #1 entry directory creation was requested.",
391 /* search for "#### LoaderInfo: systemd-boot 218 ####" string inside the binary */
392 static int get_file_version(int fd
, char **v
) {
402 if (fstat(fd
, &st
) < 0)
403 return log_error_errno(errno
, "Failed to stat EFI binary: %m");
405 r
= stat_verify_regular(&st
);
407 return log_error_errno(r
, "EFI binary is not a regular file: %m");
409 if (st
.st_size
< 27 || file_offset_beyond_memory_size(st
.st_size
)) {
414 buf
= mmap(NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0);
415 if (buf
== MAP_FAILED
)
416 return log_error_errno(errno
, "Failed to memory map EFI binary: %m");
418 s
= mempmem_safe(buf
, st
.st_size
- 8, "#### LoaderInfo: ", 17);
422 e
= memmem_safe(s
, st
.st_size
- (s
- buf
), " ####", 5);
423 if (!e
|| e
- s
< 3) {
424 r
= log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Malformed version string.");
428 x
= strndup(s
, e
- s
);
436 (void) munmap(buf
, st
.st_size
);
441 static const char *get_efi_arch(void) {
442 /* Detect EFI firmware architecture of the running system. On mixed mode systems, it could be 32bit
443 * while the kernel is running in 64bit. */
446 _cleanup_free_
char *platform_size
= NULL
;
449 r
= read_one_line_file("/sys/firmware/efi/fw_platform_size", &platform_size
);
451 return EFI_MACHINE_TYPE_NAME
;
453 log_warning_errno(r
, "Error reading EFI firmware word size, assuming '%u': %m", __WORDSIZE
);
454 return EFI_MACHINE_TYPE_NAME
;
457 if (streq(platform_size
, "64"))
458 return EFI_MACHINE_TYPE_NAME
;
459 if (streq(platform_size
, "32"))
463 "Unknown EFI firmware word size '%s', using default word size '%u' instead.",
468 return EFI_MACHINE_TYPE_NAME
;
471 static int enumerate_binaries(
472 const char *esp_path
,
478 _cleanup_closedir_
DIR *d
= NULL
;
487 p
= prefix_roota(esp_path
, path
);
493 return log_error_errno(errno
, "Failed to read \"%s\": %m", p
);
496 FOREACH_DIRENT(de
, d
, break) {
497 _cleanup_free_
char *v
= NULL
;
498 _cleanup_close_
int fd
= -1;
500 if (!endswith_no_case(de
->d_name
, ".efi"))
503 if (prefix
&& !startswith_no_case(de
->d_name
, prefix
))
506 fd
= openat(dirfd(d
), de
->d_name
, O_RDONLY
|O_CLOEXEC
);
508 return log_error_errno(errno
, "Failed to open \"%s/%s\" for reading: %m", p
, de
->d_name
);
510 r
= get_file_version(fd
, &v
);
514 if (*previous
) { /* let's output the previous entry now, since now we know that there will be one more, and can draw the tree glyph properly */
516 *is_first
? "File:" : " ",
517 special_glyph(SPECIAL_GLYPH_TREE_BRANCH
), *previous
);
519 *previous
= mfree(*previous
);
522 /* Do not output this entry immediately, but store what should be printed in a state
523 * variable, because we only will know the tree glyph to print (branch or final edge) once we
524 * read one more entry */
526 r
= asprintf(previous
, "/%s/%s (%s%s%s)", path
, de
->d_name
, ansi_highlight(), v
, ansi_normal());
528 r
= asprintf(previous
, "/%s/%s", path
, de
->d_name
);
538 static int status_binaries(const char *esp_path
, sd_id128_t partition
) {
539 _cleanup_free_
char *last
= NULL
;
540 bool is_first
= true;
543 printf("%sAvailable Boot Loaders on ESP:%s\n", ansi_underline(), ansi_normal());
546 printf(" ESP: Cannot find or access mount point of ESP.\n\n");
550 printf(" ESP: %s", esp_path
);
551 if (!sd_id128_is_null(partition
))
552 printf(" (/dev/disk/by-partuuid/" SD_ID128_UUID_FORMAT_STR
")", SD_ID128_FORMAT_VAL(partition
));
555 r
= enumerate_binaries(esp_path
, "EFI/systemd", NULL
, &last
, &is_first
);
561 k
= enumerate_binaries(esp_path
, "EFI/BOOT", "boot", &last
, &is_first
);
567 if (last
) /* let's output the last entry now, since now we know that there will be no more, and can draw the tree glyph properly */
569 is_first
? "File:" : " ",
570 special_glyph(SPECIAL_GLYPH_TREE_RIGHT
), last
);
572 if (r
== 0 && !arg_quiet
)
573 log_info("systemd-boot not installed in ESP.");
574 if (k
== 0 && !arg_quiet
)
575 log_info("No default/fallback boot loader installed in ESP.");
581 static int print_efi_option(uint16_t id
, int *n_printed
, bool in_order
) {
582 _cleanup_free_
char *title
= NULL
;
583 _cleanup_free_
char *path
= NULL
;
584 sd_id128_t partition
;
590 r
= efi_get_boot_option(id
, &title
, &partition
, &path
, &active
);
592 return log_error_errno(r
, "Failed to read boot option %u: %m", id
);
594 /* print only configured entries with partition information */
595 if (!path
|| sd_id128_is_null(partition
)) {
596 log_debug("Ignoring boot entry %u without partition information.", id
);
600 efi_tilt_backslashes(path
);
602 if (*n_printed
== 0) /* Print section title before first entry */
603 printf("%sBoot Loaders Listed in EFI Variables:%s\n", ansi_underline(), ansi_normal());
605 printf(" Title: %s%s%s\n", ansi_highlight(), strna(title
), ansi_normal());
606 printf(" ID: 0x%04X\n", id
);
607 printf(" Status: %sactive%s\n", active
? "" : "in", in_order
? ", boot-order" : "");
608 printf(" Partition: /dev/disk/by-partuuid/" SD_ID128_UUID_FORMAT_STR
"\n",
609 SD_ID128_FORMAT_VAL(partition
));
610 printf(" File: %s%s\n", special_glyph(SPECIAL_GLYPH_TREE_RIGHT
), path
);
617 static int status_variables(void) {
618 _cleanup_free_
uint16_t *options
= NULL
, *order
= NULL
;
619 int n_options
, n_order
, n_printed
= 0;
621 n_options
= efi_get_boot_options(&options
);
622 if (n_options
== -ENOENT
)
623 return log_error_errno(n_options
,
624 "Failed to access EFI variables, efivarfs"
625 " needs to be available at /sys/firmware/efi/efivars/.");
627 return log_error_errno(n_options
, "Failed to read EFI boot entries: %m");
629 n_order
= efi_get_boot_order(&order
);
630 if (n_order
== -ENOENT
)
632 else if (n_order
< 0)
633 return log_error_errno(n_order
, "Failed to read EFI boot order: %m");
635 /* print entries in BootOrder first */
636 for (int i
= 0; i
< n_order
; i
++)
637 (void) print_efi_option(order
[i
], &n_printed
, /* in_order= */ true);
639 /* print remaining entries */
640 for (int i
= 0; i
< n_options
; i
++) {
641 for (int j
= 0; j
< n_order
; j
++)
642 if (options
[i
] == order
[j
])
645 (void) print_efi_option(options
[i
], &n_printed
, /* in_order= */ false);
652 printf("No boot loaders listed in EFI Variables.\n\n");
657 static int boot_config_load_and_select(
659 const char *esp_path
,
661 const char *xbootldr_path
,
662 dev_t xbootldr_devid
) {
666 /* If XBOOTLDR and ESP actually refer to the same block device, suppress XBOOTLDR, since it would
667 * find the same entries twice. */
668 bool same
= esp_path
&& xbootldr_path
&& devnum_set_and_equal(esp_devid
, xbootldr_devid
);
670 r
= boot_config_load(config
, esp_path
, same
? NULL
: xbootldr_path
);
675 _cleanup_strv_free_
char **efi_entries
= NULL
;
677 r
= efi_loader_get_entries(&efi_entries
);
678 if (r
== -ENOENT
|| ERRNO_IS_NOT_SUPPORTED(r
))
679 log_debug_errno(r
, "Boot loader reported no entries.");
681 log_warning_errno(r
, "Failed to determine entries reported by boot loader, ignoring: %m");
683 (void) boot_config_augment_from_loader(config
, efi_entries
, /* only_auto= */ false);
686 return boot_config_select_special_entries(config
, /* skip_efivars= */ !!arg_root
);
689 static int status_entries(
690 const BootConfig
*config
,
691 const char *esp_path
,
692 sd_id128_t esp_partition_uuid
,
693 const char *xbootldr_path
,
694 sd_id128_t xbootldr_partition_uuid
) {
696 sd_id128_t dollar_boot_partition_uuid
;
697 const char *dollar_boot_path
;
701 assert(esp_path
|| xbootldr_path
);
704 dollar_boot_path
= xbootldr_path
;
705 dollar_boot_partition_uuid
= xbootldr_partition_uuid
;
707 dollar_boot_path
= esp_path
;
708 dollar_boot_partition_uuid
= esp_partition_uuid
;
711 printf("%sBoot Loader Entries:%s\n"
712 " $BOOT: %s", ansi_underline(), ansi_normal(), dollar_boot_path
);
713 if (!sd_id128_is_null(dollar_boot_partition_uuid
))
714 printf(" (/dev/disk/by-partuuid/" SD_ID128_UUID_FORMAT_STR
")",
715 SD_ID128_FORMAT_VAL(dollar_boot_partition_uuid
));
718 if (config
->default_entry
< 0)
719 printf("%zu entries, no entry could be determined as default.\n", config
->n_entries
);
721 printf("%sDefault Boot Loader Entry:%s\n", ansi_underline(), ansi_normal());
724 boot_config_default_entry(config
),
725 /* show_as_default= */ false,
726 /* show_as_selected= */ false,
727 /* show_discovered= */ false);
729 /* < 0 is already logged by the function itself, let's just emit an extra warning if
730 the default entry is broken */
731 printf("\nWARNING: default boot entry is broken\n");
737 static int compare_product(const char *a
, const char *b
) {
746 return x
< y
? -1 : x
> y
? 1 : 0;
748 return strncmp(a
, b
, x
);
751 static int compare_version(const char *a
, const char *b
) {
755 a
+= strcspn(a
, " ");
757 b
+= strcspn(b
, " ");
760 return strverscmp_improved(a
, b
);
763 static int version_check(int fd_from
, const char *from
, int fd_to
, const char *to
) {
764 _cleanup_free_
char *a
= NULL
, *b
= NULL
;
767 assert(fd_from
>= 0);
772 r
= get_file_version(fd_from
, &a
);
776 return log_notice_errno(SYNTHETIC_ERRNO(EREMOTE
),
777 "Source file \"%s\" does not carry version information!",
780 r
= get_file_version(fd_to
, &b
);
783 if (r
== 0 || compare_product(a
, b
) != 0)
784 return log_notice_errno(SYNTHETIC_ERRNO(EREMOTE
),
785 "Skipping \"%s\", since it's owned by another boot loader.",
788 r
= compare_version(a
, b
);
789 log_debug("Comparing versions: \"%s\" %s \"%s", a
, comparison_operator(r
), b
);
791 return log_warning_errno(SYNTHETIC_ERRNO(ESTALE
),
792 "Skipping \"%s\", since newer boot loader version in place already.", to
);
794 return log_info_errno(SYNTHETIC_ERRNO(ESTALE
),
795 "Skipping \"%s\", since same boot loader version in place already.", to
);
800 static int copy_file_with_version_check(const char *from
, const char *to
, bool force
) {
801 _cleanup_close_
int fd_from
= -1, fd_to
= -1;
802 _cleanup_free_
char *t
= NULL
;
805 fd_from
= open(from
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
807 return log_error_errno(errno
, "Failed to open \"%s\" for reading: %m", from
);
810 fd_to
= open(to
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
813 return log_error_errno(errno
, "Failed to open \"%s\" for reading: %m", to
);
815 r
= version_check(fd_from
, from
, fd_to
, to
);
819 if (lseek(fd_from
, 0, SEEK_SET
) == (off_t
) -1)
820 return log_error_errno(errno
, "Failed to seek in \"%s\": %m", from
);
822 fd_to
= safe_close(fd_to
);
826 r
= tempfn_random(to
, NULL
, &t
);
830 RUN_WITH_UMASK(0000) {
831 fd_to
= open(t
, O_WRONLY
|O_CREAT
|O_CLOEXEC
|O_EXCL
|O_NOFOLLOW
, 0644);
833 return log_error_errno(errno
, "Failed to open \"%s\" for writing: %m", t
);
836 r
= copy_bytes(fd_from
, fd_to
, UINT64_MAX
, COPY_REFLINK
);
839 return log_error_errno(r
, "Failed to copy data from \"%s\" to \"%s\": %m", from
, t
);
842 (void) copy_times(fd_from
, fd_to
, 0);
844 r
= fsync_full(fd_to
);
846 (void) unlink_noerrno(t
);
847 return log_error_errno(r
, "Failed to copy data from \"%s\" to \"%s\": %m", from
, t
);
850 if (renameat(AT_FDCWD
, t
, AT_FDCWD
, to
) < 0) {
851 (void) unlink_noerrno(t
);
852 return log_error_errno(errno
, "Failed to rename \"%s\" to \"%s\": %m", t
, to
);
855 log_info("Copied \"%s\" to \"%s\".", from
, to
);
860 static int mkdir_one(const char *prefix
, const char *suffix
) {
861 _cleanup_free_
char *p
= NULL
;
863 p
= path_join(prefix
, suffix
);
864 if (mkdir(p
, 0700) < 0) {
866 return log_error_errno(errno
, "Failed to create \"%s\": %m", p
);
868 log_info("Created \"%s\".", p
);
873 static const char *const esp_subdirs
[] = {
874 /* The directories to place in the ESP */
882 static const char *const dollar_boot_subdirs
[] = {
883 /* The directories to place in the XBOOTLDR partition or the ESP, depending what exists */
885 "loader/entries", /* Type #1 entries */
887 "EFI/Linux", /* Type #2 entries */
891 static int create_subdirs(const char *root
, const char * const *subdirs
) {
894 STRV_FOREACH(i
, subdirs
) {
895 r
= mkdir_one(root
, *i
);
903 static int copy_one_file(const char *esp_path
, const char *name
, bool force
) {
904 char *root
= IN_SET(arg_install_source
, ARG_INSTALL_SOURCE_AUTO
, ARG_INSTALL_SOURCE_IMAGE
) ? arg_root
: NULL
;
905 _cleanup_free_
char *source_path
= NULL
, *dest_path
= NULL
, *p
= NULL
, *q
= NULL
;
910 dest_name
= strdupa_safe(name
);
911 s
= endswith_no_case(dest_name
, ".signed");
915 p
= path_join(BOOTLIBDIR
, name
);
919 r
= chase_symlinks(p
, root
, CHASE_PREFIX_ROOT
, &source_path
, NULL
);
920 /* If we had a root directory to try, we didn't find it and we are in auto mode, retry on the host */
921 if (r
== -ENOENT
&& root
&& arg_install_source
== ARG_INSTALL_SOURCE_AUTO
)
922 r
= chase_symlinks(p
, NULL
, CHASE_PREFIX_ROOT
, &source_path
, NULL
);
924 return log_error_errno(r
,
925 "Failed to resolve path %s%s%s: %m",
927 root
? " under directory " : "",
930 q
= path_join("/EFI/systemd/", dest_name
);
934 r
= chase_symlinks(q
, esp_path
, CHASE_PREFIX_ROOT
| CHASE_NONEXISTENT
, &dest_path
, NULL
);
936 return log_error_errno(r
, "Failed to resolve path %s under directory %s: %m", q
, esp_path
);
938 /* Note that if this fails we do the second copy anyway, but return this error code,
939 * so we stash it away in a separate variable. */
940 ret
= copy_file_with_version_check(source_path
, dest_path
, force
);
942 e
= startswith(dest_name
, "systemd-boot");
944 _cleanup_free_
char *default_dest_path
= NULL
;
947 /* Create the EFI default boot loader name (specified for removable devices) */
948 v
= strjoina("/EFI/BOOT/BOOT", e
);
949 ascii_strupper(strrchr(v
, '/') + 1);
951 r
= chase_symlinks(v
, esp_path
, CHASE_PREFIX_ROOT
| CHASE_NONEXISTENT
, &default_dest_path
, NULL
);
953 return log_error_errno(r
, "Failed to resolve path %s under directory %s: %m", v
, esp_path
);
955 r
= copy_file_with_version_check(source_path
, default_dest_path
, force
);
956 if (r
< 0 && ret
== 0)
963 static int install_binaries(const char *esp_path
, const char *arch
, bool force
) {
964 char *root
= IN_SET(arg_install_source
, ARG_INSTALL_SOURCE_AUTO
, ARG_INSTALL_SOURCE_IMAGE
) ? arg_root
: NULL
;
965 _cleanup_closedir_
DIR *d
= NULL
;
966 _cleanup_free_
char *path
= NULL
;
969 r
= chase_symlinks_and_opendir(BOOTLIBDIR
, root
, CHASE_PREFIX_ROOT
, &path
, &d
);
970 /* If we had a root directory to try, we didn't find it and we are in auto mode, retry on the host */
971 if (r
== -ENOENT
&& root
&& arg_install_source
== ARG_INSTALL_SOURCE_AUTO
)
972 r
= chase_symlinks_and_opendir(BOOTLIBDIR
, NULL
, CHASE_PREFIX_ROOT
, &path
, &d
);
974 return log_error_errno(r
, "Failed to open boot loader directory %s%s: %m", strempty(root
), BOOTLIBDIR
);
976 const char *suffix
= strjoina(arch
, ".efi");
977 const char *suffix_signed
= strjoina(arch
, ".efi.signed");
979 FOREACH_DIRENT(de
, d
, return log_error_errno(errno
, "Failed to read \"%s\": %m", path
)) {
982 if (!endswith_no_case(de
->d_name
, suffix
) && !endswith_no_case(de
->d_name
, suffix_signed
))
985 /* skip the .efi file, if there's a .signed version of it */
986 if (endswith_no_case(de
->d_name
, ".efi")) {
987 _cleanup_free_
const char *s
= strjoin(de
->d_name
, ".signed");
990 if (faccessat(dirfd(d
), s
, F_OK
, 0) >= 0)
994 k
= copy_one_file(esp_path
, de
->d_name
, force
);
995 /* Don't propagate an error code if no update necessary, installed version already equal or
996 * newer version, or other boot loader in place. */
997 if (arg_graceful
&& IN_SET(k
, -ESTALE
, -EREMOTE
))
1006 static bool same_entry(uint16_t id
, sd_id128_t uuid
, const char *path
) {
1007 _cleanup_free_
char *opath
= NULL
;
1011 r
= efi_get_boot_option(id
, NULL
, &ouuid
, &opath
, NULL
);
1014 if (!sd_id128_equal(uuid
, ouuid
))
1017 /* Some motherboards convert the path to uppercase under certain circumstances
1018 * (e.g. after booting into the Boot Menu in the ASUS ROG STRIX B350-F GAMING),
1019 * so use case-insensitive checking */
1020 if (!strcaseeq_ptr(path
, opath
))
1026 static int find_slot(sd_id128_t uuid
, const char *path
, uint16_t *id
) {
1027 _cleanup_free_
uint16_t *options
= NULL
;
1029 int n
= efi_get_boot_options(&options
);
1033 /* find already existing systemd-boot entry */
1034 for (int i
= 0; i
< n
; i
++)
1035 if (same_entry(options
[i
], uuid
, path
)) {
1040 /* find free slot in the sorted BootXXXX variable list */
1041 for (int i
= 0; i
< n
; i
++)
1042 if (i
!= options
[i
]) {
1047 /* use the next one */
1054 static int insert_into_order(uint16_t slot
, bool first
) {
1055 _cleanup_free_
uint16_t *order
= NULL
;
1059 n
= efi_get_boot_order(&order
);
1061 /* no entry, add us */
1062 return efi_set_boot_order(&slot
, 1);
1064 /* are we the first and only one? */
1065 if (n
== 1 && order
[0] == slot
)
1068 /* are we already in the boot order? */
1069 for (int i
= 0; i
< n
; i
++) {
1070 if (order
[i
] != slot
)
1073 /* we do not require to be the first one, all is fine */
1077 /* move us to the first slot */
1078 memmove(order
+ 1, order
, i
* sizeof(uint16_t));
1080 return efi_set_boot_order(order
, n
);
1084 t
= reallocarray(order
, n
+ 1, sizeof(uint16_t));
1089 /* add us to the top or end of the list */
1091 memmove(order
+ 1, order
, n
* sizeof(uint16_t));
1096 return efi_set_boot_order(order
, n
+ 1);
1099 static int remove_from_order(uint16_t slot
) {
1100 _cleanup_free_
uint16_t *order
= NULL
;
1103 n
= efi_get_boot_order(&order
);
1107 for (int i
= 0; i
< n
; i
++) {
1108 if (order
[i
] != slot
)
1112 memmove(order
+ i
, order
+ i
+1, (n
- i
) * sizeof(uint16_t));
1113 return efi_set_boot_order(order
, n
- 1);
1119 static int install_variables(const char *esp_path
,
1120 uint32_t part
, uint64_t pstart
, uint64_t psize
,
1121 sd_id128_t uuid
, const char *path
,
1128 log_info("Acting on %s, skipping EFI variable setup.",
1129 arg_image
? "image" : "root directory");
1133 if (!is_efi_boot()) {
1134 log_warning("Not booted with EFI, skipping EFI variable setup.");
1138 p
= prefix_roota(esp_path
, path
);
1139 if (access(p
, F_OK
) < 0) {
1140 if (errno
== ENOENT
)
1143 return log_error_errno(errno
, "Cannot access \"%s\": %m", p
);
1146 r
= find_slot(uuid
, path
, &slot
);
1148 return log_error_errno(r
,
1150 "Failed to access EFI variables. Is the \"efivarfs\" filesystem mounted?" :
1151 "Failed to determine current boot order: %m");
1153 if (first
|| r
== 0) {
1154 r
= efi_add_boot_option(slot
, pick_efi_boot_option_description(),
1155 part
, pstart
, psize
,
1158 return log_error_errno(r
, "Failed to create EFI Boot variable entry: %m");
1160 log_info("Created EFI boot entry \"%s\".", pick_efi_boot_option_description());
1163 return insert_into_order(slot
, first
);
1166 static int remove_boot_efi(const char *esp_path
) {
1167 _cleanup_closedir_
DIR *d
= NULL
;
1171 p
= prefix_roota(esp_path
, "/EFI/BOOT");
1174 if (errno
== ENOENT
)
1177 return log_error_errno(errno
, "Failed to open directory \"%s\": %m", p
);
1180 FOREACH_DIRENT(de
, d
, break) {
1181 _cleanup_close_
int fd
= -1;
1182 _cleanup_free_
char *v
= NULL
;
1184 if (!endswith_no_case(de
->d_name
, ".efi"))
1187 if (!startswith_no_case(de
->d_name
, "boot"))
1190 fd
= openat(dirfd(d
), de
->d_name
, O_RDONLY
|O_CLOEXEC
);
1192 return log_error_errno(errno
, "Failed to open \"%s/%s\" for reading: %m", p
, de
->d_name
);
1194 r
= get_file_version(fd
, &v
);
1197 if (r
> 0 && startswith(v
, "systemd-boot ")) {
1198 r
= unlinkat(dirfd(d
), de
->d_name
, 0);
1200 return log_error_errno(errno
, "Failed to remove \"%s/%s\": %m", p
, de
->d_name
);
1202 log_info("Removed \"%s/%s\".", p
, de
->d_name
);
1211 static int rmdir_one(const char *prefix
, const char *suffix
) {
1214 p
= prefix_roota(prefix
, suffix
);
1216 bool ignore
= IN_SET(errno
, ENOENT
, ENOTEMPTY
);
1218 log_full_errno(ignore
? LOG_DEBUG
: LOG_ERR
, errno
,
1219 "Failed to remove directory \"%s\": %m", p
);
1223 log_info("Removed \"%s\".", p
);
1228 static int remove_subdirs(const char *root
, const char *const *subdirs
) {
1231 /* We use recursion here to destroy the directories in reverse order. Which should be safe given how
1232 * short the array is. */
1234 if (!subdirs
[0]) /* A the end of the list */
1237 r
= remove_subdirs(root
, subdirs
+ 1);
1238 q
= rmdir_one(root
, subdirs
[0]);
1240 return r
< 0 ? r
: q
;
1243 static int remove_entry_directory(const char *root
) {
1245 assert(arg_make_entry_directory
>= 0);
1247 if (!arg_make_entry_directory
|| !arg_entry_token
)
1250 return rmdir_one(root
, arg_entry_token
);
1253 static int remove_binaries(const char *esp_path
) {
1257 p
= prefix_roota(esp_path
, "/EFI/systemd");
1258 r
= rm_rf(p
, REMOVE_ROOT
|REMOVE_PHYSICAL
);
1260 q
= remove_boot_efi(esp_path
);
1261 if (q
< 0 && r
== 0)
1267 static int remove_file(const char *root
, const char *file
) {
1273 p
= prefix_roota(root
, file
);
1274 if (unlink(p
) < 0) {
1275 log_full_errno(errno
== ENOENT
? LOG_DEBUG
: LOG_ERR
, errno
,
1276 "Failed to unlink file \"%s\": %m", p
);
1278 return errno
== ENOENT
? 0 : -errno
;
1281 log_info("Removed \"%s\".", p
);
1285 static int remove_variables(sd_id128_t uuid
, const char *path
, bool in_order
) {
1289 if (arg_root
|| !is_efi_boot())
1292 r
= find_slot(uuid
, path
, &slot
);
1296 r
= efi_remove_boot_option(slot
);
1301 return remove_from_order(slot
);
1306 static int remove_loader_variables(void) {
1309 /* Remove all persistent loader variables we define */
1312 EFI_LOADER_VARIABLE(LoaderConfigTimeout
),
1313 EFI_LOADER_VARIABLE(LoaderConfigTimeoutOneShot
),
1314 EFI_LOADER_VARIABLE(LoaderEntryDefault
),
1315 EFI_LOADER_VARIABLE(LoaderEntryOneShot
),
1316 EFI_LOADER_VARIABLE(LoaderSystemToken
)){
1320 q
= efi_set_variable(var
, NULL
, 0);
1324 log_warning_errno(q
, "Failed to remove EFI variable %s: %m", var
);
1328 log_info("Removed EFI variable %s.", var
);
1334 static int install_loader_config(const char *esp_path
) {
1335 _cleanup_(unlink_and_freep
) char *t
= NULL
;
1336 _cleanup_fclose_
FILE *f
= NULL
;
1340 assert(arg_make_entry_directory
>= 0);
1342 p
= prefix_roota(esp_path
, "/loader/loader.conf");
1343 if (access(p
, F_OK
) >= 0) /* Silently skip creation if the file already exists (early check) */
1346 r
= fopen_tmpfile_linkable(p
, O_WRONLY
|O_CLOEXEC
, &t
, &f
);
1348 return log_error_errno(r
, "Failed to open \"%s\" for writing: %m", p
);
1350 fprintf(f
, "#timeout 3\n"
1351 "#console-mode keep\n");
1353 if (arg_make_entry_directory
) {
1354 assert(arg_entry_token
);
1355 fprintf(f
, "default %s-*\n", arg_entry_token
);
1358 r
= flink_tmpfile(f
, t
, p
);
1360 return 0; /* Silently skip creation if the file exists now (recheck) */
1362 return log_error_errno(r
, "Failed to move \"%s\" into place: %m", p
);
1368 static int install_loader_specification(const char *root
) {
1369 _cleanup_(unlink_and_freep
) char *t
= NULL
;
1370 _cleanup_fclose_
FILE *f
= NULL
;
1371 _cleanup_free_
char *p
= NULL
;
1374 p
= path_join(root
, "/loader/entries.srel");
1378 if (access(p
, F_OK
) >= 0) /* Silently skip creation if the file already exists (early check) */
1381 r
= fopen_tmpfile_linkable(p
, O_WRONLY
|O_CLOEXEC
, &t
, &f
);
1383 return log_error_errno(r
, "Failed to open \"%s\" for writing: %m", p
);
1385 fprintf(f
, "type1\n");
1387 r
= flink_tmpfile(f
, t
, p
);
1389 return 0; /* Silently skip creation if the file exists now (recheck) */
1391 return log_error_errno(r
, "Failed to move \"%s\" into place: %m", p
);
1397 static int install_entry_directory(const char *root
) {
1399 assert(arg_make_entry_directory
>= 0);
1401 if (!arg_make_entry_directory
)
1404 assert(arg_entry_token
);
1405 return mkdir_one(root
, arg_entry_token
);
1408 static int install_entry_token(void) {
1411 assert(arg_make_entry_directory
>= 0);
1412 assert(arg_entry_token
);
1414 /* Let's save the used entry token in /etc/kernel/entry-token if we used it to create the entry
1415 * directory, or if anything else but the machine ID */
1417 if (!arg_make_entry_directory
&& arg_entry_token_type
== ARG_ENTRY_TOKEN_MACHINE_ID
)
1420 r
= write_string_file("/etc/kernel/entry-token", arg_entry_token
, WRITE_STRING_FILE_CREATE
|WRITE_STRING_FILE_ATOMIC
|WRITE_STRING_FILE_MKDIR_0755
);
1422 return log_error_errno(r
, "Failed to write entry token '%s' to /etc/kernel/entry-token", arg_entry_token
);
1427 static int help(int argc
, char *argv
[], void *userdata
) {
1428 _cleanup_free_
char *link
= NULL
;
1431 r
= terminal_urlify_man("bootctl", "1", &link
);
1435 printf("%1$s [OPTIONS...] COMMAND ...\n"
1436 "\n%5$sControl EFI firmware boot settings and manage boot loader.%6$s\n"
1437 "\n%3$sGeneric EFI Firmware/Boot Loader Commands:%4$s\n"
1438 " status Show status of installed boot loader and EFI variables\n"
1439 " reboot-to-firmware [BOOL]\n"
1440 " Query or set reboot-to-firmware EFI flag\n"
1441 " systemd-efi-options [STRING]\n"
1442 " Query or set system options string in EFI variable\n"
1443 "\n%3$sBoot Loader Specification Commands:%4$s\n"
1444 " list List boot loader entries\n"
1445 " set-default ID Set default boot loader entry\n"
1446 " set-oneshot ID Set default boot loader entry, for next boot only\n"
1447 " set-timeout SECONDS Set the menu timeout\n"
1448 " set-timeout-oneshot SECONDS\n"
1449 " Set the menu timeout for the next boot only\n"
1450 "\n%3$ssystemd-boot Commands:%4$s\n"
1451 " install Install systemd-boot to the ESP and EFI variables\n"
1452 " update Update systemd-boot in the ESP and EFI variables\n"
1453 " remove Remove systemd-boot from the ESP and EFI variables\n"
1454 " is-installed Test whether systemd-boot is installed in the ESP\n"
1455 " random-seed Initialize random seed in ESP and EFI variables\n"
1456 "\n%3$sOptions:%4$s\n"
1457 " -h --help Show this help\n"
1458 " --version Print version\n"
1459 " --esp-path=PATH Path to the EFI System Partition (ESP)\n"
1460 " --boot-path=PATH Path to the $BOOT partition\n"
1461 " --root=PATH Operate on an alternate filesystem root\n"
1462 " --image=PATH Operate on disk image as filesystem root\n"
1463 " --install-source=auto|image|host\n"
1464 " Where to pick files when using --root=/--image=\n"
1465 " -p --print-esp-path Print path to the EFI System Partition\n"
1466 " -x --print-boot-path Print path to the $BOOT partition\n"
1467 " --no-variables Don't touch EFI variables\n"
1468 " --no-pager Do not pipe output into a pager\n"
1469 " --graceful Don't fail when the ESP cannot be found or EFI\n"
1470 " variables cannot be written\n"
1471 " -q --quiet Suppress output\n"
1472 " --make-entry-directory=yes|no|auto\n"
1473 " Create $BOOT/ENTRY-TOKEN/ directory\n"
1474 " --entry-token=machine-id|os-id|os-image-id|auto|literal:…\n"
1475 " Entry token to use for this installation\n"
1476 " --json=pretty|short|off\n"
1477 " Generate JSON output\n"
1478 " --all-architectures\n"
1479 " Install all supported EFI architectures\n"
1480 " --efi-boot-option-description=DESCRIPTION\n"
1481 " Description of the entry in the boot option list\n"
1482 "\nSee the %2$s for details.\n",
1483 program_invocation_short_name
,
1493 static int parse_argv(int argc
, char *argv
[]) {
1495 ARG_ESP_PATH
= 0x100,
1504 ARG_MAKE_ENTRY_DIRECTORY
,
1508 ARG_EFI_BOOT_OPTION_DESCRIPTION
,
1511 static const struct option options
[] = {
1512 { "help", no_argument
, NULL
, 'h' },
1513 { "version", no_argument
, NULL
, ARG_VERSION
},
1514 { "esp-path", required_argument
, NULL
, ARG_ESP_PATH
},
1515 { "path", required_argument
, NULL
, ARG_ESP_PATH
}, /* Compatibility alias */
1516 { "boot-path", required_argument
, NULL
, ARG_BOOT_PATH
},
1517 { "root", required_argument
, NULL
, ARG_ROOT
},
1518 { "image", required_argument
, NULL
, ARG_IMAGE
},
1519 { "install-source", required_argument
, NULL
, ARG_INSTALL_SOURCE
},
1520 { "print-esp-path", no_argument
, NULL
, 'p' },
1521 { "print-path", no_argument
, NULL
, 'p' }, /* Compatibility alias */
1522 { "print-boot-path", no_argument
, NULL
, 'x' },
1523 { "no-variables", no_argument
, NULL
, ARG_NO_VARIABLES
},
1524 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
1525 { "graceful", no_argument
, NULL
, ARG_GRACEFUL
},
1526 { "quiet", no_argument
, NULL
, 'q' },
1527 { "make-entry-directory", required_argument
, NULL
, ARG_MAKE_ENTRY_DIRECTORY
},
1528 { "make-machine-id-directory", required_argument
, NULL
, ARG_MAKE_ENTRY_DIRECTORY
}, /* Compatibility alias */
1529 { "entry-token", required_argument
, NULL
, ARG_ENTRY_TOKEN
},
1530 { "json", required_argument
, NULL
, ARG_JSON
},
1531 { "all-architectures", no_argument
, NULL
, ARG_ARCH_ALL
},
1532 { "efi-boot-option-description", required_argument
, NULL
, ARG_EFI_BOOT_OPTION_DESCRIPTION
},
1542 while ((c
= getopt_long(argc
, argv
, "hpx", options
, NULL
)) >= 0)
1546 help(0, NULL
, NULL
);
1553 r
= free_and_strdup(&arg_esp_path
, optarg
);
1559 r
= free_and_strdup(&arg_xbootldr_path
, optarg
);
1565 r
= parse_path_argument(optarg
, /* suppress_root= */ true, &arg_root
);
1571 r
= parse_path_argument(optarg
, /* suppress_root= */ false, &arg_image
);
1576 case ARG_INSTALL_SOURCE
:
1577 if (streq(optarg
, "auto"))
1578 arg_install_source
= ARG_INSTALL_SOURCE_AUTO
;
1579 else if (streq(optarg
, "image"))
1580 arg_install_source
= ARG_INSTALL_SOURCE_IMAGE
;
1581 else if (streq(optarg
, "host"))
1582 arg_install_source
= ARG_INSTALL_SOURCE_HOST
;
1584 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1585 "Unexpected parameter for --install-source=: %s", optarg
);
1590 if (arg_print_dollar_boot_path
)
1591 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1592 "--print-boot-path/-x cannot be combined with --print-esp-path/-p");
1593 arg_print_esp_path
= true;
1597 if (arg_print_esp_path
)
1598 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1599 "--print-boot-path/-x cannot be combined with --print-esp-path/-p");
1600 arg_print_dollar_boot_path
= true;
1603 case ARG_NO_VARIABLES
:
1604 arg_touch_variables
= false;
1608 arg_pager_flags
|= PAGER_DISABLE
;
1612 arg_graceful
= true;
1619 case ARG_ENTRY_TOKEN
: {
1622 if (streq(optarg
, "machine-id")) {
1623 arg_entry_token_type
= ARG_ENTRY_TOKEN_MACHINE_ID
;
1624 arg_entry_token
= mfree(arg_entry_token
);
1625 } else if (streq(optarg
, "os-image-id")) {
1626 arg_entry_token_type
= ARG_ENTRY_TOKEN_OS_IMAGE_ID
;
1627 arg_entry_token
= mfree(arg_entry_token
);
1628 } else if (streq(optarg
, "os-id")) {
1629 arg_entry_token_type
= ARG_ENTRY_TOKEN_OS_ID
;
1630 arg_entry_token
= mfree(arg_entry_token
);
1631 } else if ((e
= startswith(optarg
, "literal:"))) {
1632 arg_entry_token_type
= ARG_ENTRY_TOKEN_LITERAL
;
1634 r
= free_and_strdup_warn(&arg_entry_token
, e
);
1638 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1639 "Unexpected parameter for --entry-token=: %s", optarg
);
1644 case ARG_MAKE_ENTRY_DIRECTORY
:
1645 if (streq(optarg
, "auto")) /* retained for backwards compatibility */
1646 arg_make_entry_directory
= -1; /* yes if machine-id is permanent */
1648 r
= parse_boolean_argument("--make-entry-directory=", optarg
, &b
);
1652 arg_make_entry_directory
= b
;
1657 r
= parse_json_argument(optarg
, &arg_json_format_flags
);
1663 arg_arch_all
= true;
1666 case ARG_EFI_BOOT_OPTION_DESCRIPTION
:
1667 if (isempty(optarg
) || !(string_is_safe(optarg
) && utf8_is_valid(optarg
))) {
1668 _cleanup_free_
char *escaped
= NULL
;
1670 escaped
= cescape(optarg
);
1671 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1672 "Invalid --efi-boot-option-description=: %s", strna(escaped
));
1674 if (strlen(optarg
) > EFI_BOOT_OPTION_DESCRIPTION_MAX
)
1675 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1676 "--efi-boot-option-description= too long: %zu > %zu", strlen(optarg
), EFI_BOOT_OPTION_DESCRIPTION_MAX
);
1677 r
= free_and_strdup_warn(&arg_efi_boot_option_description
, optarg
);
1686 assert_not_reached();
1689 if ((arg_root
|| arg_image
) && argv
[optind
] && !STR_IN_SET(argv
[optind
], "status", "list",
1690 "install", "update", "remove", "is-installed", "random-seed"))
1691 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1692 "Options --root= and --image= are not supported with verb %s.",
1695 if (arg_root
&& arg_image
)
1696 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Please specify either --root= or --image=, the combination of both is not supported.");
1698 if (arg_install_source
!= ARG_INSTALL_SOURCE_AUTO
&& !arg_root
&& !arg_image
)
1699 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "--install-from-host is only supported with --root= or --image=.");
1704 static void read_efi_var(const char *variable
, char **ret
) {
1707 r
= efi_get_variable_string(variable
, ret
);
1708 if (r
< 0 && r
!= -ENOENT
)
1709 log_warning_errno(r
, "Failed to read EFI variable %s: %m", variable
);
1712 static void print_yes_no_line(bool first
, bool good
, const char *name
) {
1714 first
? " Features: " : " ",
1715 COLOR_MARK_BOOL(good
),
1719 static int are_we_installed(const char *esp_path
) {
1722 /* Tests whether systemd-boot is installed. It's not obvious what to use as check here: we could
1723 * check EFI variables, we could check what binary /EFI/BOOT/BOOT*.EFI points to, or whether the
1724 * loader entries directory exists. Here we opted to check whether /EFI/systemd/ is non-empty, which
1725 * should be a suitable and very minimal check for a number of reasons:
1727 * → The check is architecture independent (i.e. we check if any systemd-boot loader is installed,
1728 * not a specific one.)
1730 * → It doesn't assume we are the only boot loader (i.e doesn't check if we own the main
1731 * /EFI/BOOT/BOOT*.EFI fallback binary.
1733 * → It specifically checks for systemd-boot, not for other boot loaders (which a check for
1734 * /boot/loader/entries would do). */
1736 _cleanup_free_
char *p
= path_join(esp_path
, "/EFI/systemd/");
1740 log_debug("Checking whether %s contains any files%s", p
, special_glyph(SPECIAL_GLYPH_ELLIPSIS
));
1741 r
= dir_is_empty(p
, /* ignore_hidden_or_backup= */ false);
1742 if (r
< 0 && r
!= -ENOENT
)
1743 return log_error_errno(r
, "Failed to check whether %s contains any files: %m", p
);
1748 static int verb_status(int argc
, char *argv
[], void *userdata
) {
1749 sd_id128_t esp_uuid
= SD_ID128_NULL
, xbootldr_uuid
= SD_ID128_NULL
;
1750 dev_t esp_devid
= 0, xbootldr_devid
= 0;
1753 r
= acquire_esp(/* unprivileged_mode= */ geteuid() != 0, /* graceful= */ false, NULL
, NULL
, NULL
, &esp_uuid
, &esp_devid
);
1754 if (arg_print_esp_path
) {
1755 if (r
== -EACCES
) /* If we couldn't acquire the ESP path, log about access errors (which is the only
1756 * error the find_esp_and_warn() won't log on its own) */
1757 return log_error_errno(r
, "Failed to determine ESP location: %m");
1764 r
= acquire_xbootldr(/* unprivileged_mode= */ geteuid() != 0, &xbootldr_uuid
, &xbootldr_devid
);
1765 if (arg_print_dollar_boot_path
) {
1767 return log_error_errno(r
, "Failed to determine XBOOTLDR partition: %m");
1771 const char *path
= arg_dollar_boot_path();
1773 return log_error_errno(SYNTHETIC_ERRNO(EACCES
), "Failed to determine XBOOTLDR location: %m");
1778 if (arg_print_esp_path
|| arg_print_dollar_boot_path
)
1781 r
= 0; /* If we couldn't determine the path, then don't consider that a problem from here on, just
1782 * show what we can show */
1784 pager_open(arg_pager_flags
);
1786 if (!arg_root
&& is_efi_boot()) {
1787 static const struct {
1790 } loader_flags
[] = {
1791 { EFI_LOADER_FEATURE_BOOT_COUNTING
, "Boot counting" },
1792 { EFI_LOADER_FEATURE_CONFIG_TIMEOUT
, "Menu timeout control" },
1793 { EFI_LOADER_FEATURE_CONFIG_TIMEOUT_ONE_SHOT
, "One-shot menu timeout control" },
1794 { EFI_LOADER_FEATURE_ENTRY_DEFAULT
, "Default entry control" },
1795 { EFI_LOADER_FEATURE_ENTRY_ONESHOT
, "One-shot entry control" },
1796 { EFI_LOADER_FEATURE_XBOOTLDR
, "Support for XBOOTLDR partition" },
1797 { EFI_LOADER_FEATURE_RANDOM_SEED
, "Support for passing random seed to OS" },
1798 { EFI_LOADER_FEATURE_LOAD_DRIVER
, "Load drop-in drivers" },
1799 { EFI_LOADER_FEATURE_SORT_KEY
, "Support Type #1 sort-key field" },
1800 { EFI_LOADER_FEATURE_SAVED_ENTRY
, "Support @saved pseudo-entry" },
1801 { EFI_LOADER_FEATURE_DEVICETREE
, "Support Type #1 devicetree field" },
1803 static const struct {
1807 { EFI_STUB_FEATURE_REPORT_BOOT_PARTITION
, "Stub sets ESP information" },
1808 { EFI_STUB_FEATURE_PICK_UP_CREDENTIALS
, "Picks up credentials from boot partition" },
1809 { EFI_STUB_FEATURE_PICK_UP_SYSEXTS
, "Picks up system extension images from boot partition" },
1810 { EFI_STUB_FEATURE_THREE_PCRS
, "Measures kernel+command line+sysexts" },
1812 _cleanup_free_
char *fw_type
= NULL
, *fw_info
= NULL
, *loader
= NULL
, *loader_path
= NULL
, *stub
= NULL
;
1813 sd_id128_t loader_part_uuid
= SD_ID128_NULL
;
1814 uint64_t loader_features
= 0, stub_features
= 0;
1818 read_efi_var(EFI_LOADER_VARIABLE(LoaderFirmwareType
), &fw_type
);
1819 read_efi_var(EFI_LOADER_VARIABLE(LoaderFirmwareInfo
), &fw_info
);
1820 read_efi_var(EFI_LOADER_VARIABLE(LoaderInfo
), &loader
);
1821 read_efi_var(EFI_LOADER_VARIABLE(StubInfo
), &stub
);
1822 read_efi_var(EFI_LOADER_VARIABLE(LoaderImageIdentifier
), &loader_path
);
1823 (void) efi_loader_get_features(&loader_features
);
1824 (void) efi_stub_get_features(&stub_features
);
1827 efi_tilt_backslashes(loader_path
);
1829 k
= efi_loader_get_device_part_uuid(&loader_part_uuid
);
1830 if (k
< 0 && k
!= -ENOENT
)
1831 r
= log_warning_errno(k
, "Failed to read EFI variable LoaderDevicePartUUID: %m");
1833 SecureBootMode secure
= efi_get_secure_boot_mode();
1834 printf("%sSystem:%s\n", ansi_underline(), ansi_normal());
1835 printf(" Firmware: %s%s (%s)%s\n", ansi_highlight(), strna(fw_type
), strna(fw_info
), ansi_normal());
1836 printf(" Firmware Arch: %s\n", get_efi_arch());
1837 printf(" Secure Boot: %sd (%s)\n",
1838 enable_disable(IN_SET(secure
, SECURE_BOOT_USER
, SECURE_BOOT_DEPLOYED
)),
1839 secure_boot_mode_to_string(secure
));
1842 printf(" TPM2 Support: %s%s%s\n",
1843 FLAGS_SET(s
, TPM2_SUPPORT_FIRMWARE
|TPM2_SUPPORT_DRIVER
) ? ansi_highlight_green() :
1844 (s
& (TPM2_SUPPORT_FIRMWARE
|TPM2_SUPPORT_DRIVER
)) != 0 ? ansi_highlight_red() : ansi_highlight_yellow(),
1845 FLAGS_SET(s
, TPM2_SUPPORT_FIRMWARE
|TPM2_SUPPORT_DRIVER
) ? "yes" :
1846 (s
& TPM2_SUPPORT_FIRMWARE
) ? "firmware only, driver unavailable" :
1847 (s
& TPM2_SUPPORT_DRIVER
) ? "driver only, firmware unavailable" : "no",
1850 k
= efi_get_reboot_to_firmware();
1852 printf(" Boot into FW: %sactive%s\n", ansi_highlight_yellow(), ansi_normal());
1854 printf(" Boot into FW: supported\n");
1855 else if (k
== -EOPNOTSUPP
)
1856 printf(" Boot into FW: not supported\n");
1859 printf(" Boot into FW: %sfailed%s (%m)\n", ansi_highlight_red(), ansi_normal());
1863 printf("%sCurrent Boot Loader:%s\n", ansi_underline(), ansi_normal());
1864 printf(" Product: %s%s%s\n", ansi_highlight(), strna(loader
), ansi_normal());
1866 for (size_t i
= 0; i
< ELEMENTSOF(loader_flags
); i
++)
1867 print_yes_no_line(i
== 0, FLAGS_SET(loader_features
, loader_flags
[i
].flag
), loader_flags
[i
].name
);
1869 sd_id128_t bootloader_esp_uuid
;
1870 bool have_bootloader_esp_uuid
= efi_loader_get_device_part_uuid(&bootloader_esp_uuid
) >= 0;
1872 print_yes_no_line(false, have_bootloader_esp_uuid
, "Boot loader sets ESP information");
1873 if (have_bootloader_esp_uuid
&& !sd_id128_is_null(esp_uuid
) &&
1874 !sd_id128_equal(esp_uuid
, bootloader_esp_uuid
))
1875 printf("WARNING: The boot loader reports a different ESP UUID than detected ("SD_ID128_UUID_FORMAT_STR
" vs. "SD_ID128_UUID_FORMAT_STR
")!\n",
1876 SD_ID128_FORMAT_VAL(bootloader_esp_uuid
),
1877 SD_ID128_FORMAT_VAL(esp_uuid
));
1880 printf(" Stub: %s\n", stub
);
1881 for (size_t i
= 0; i
< ELEMENTSOF(stub_flags
); i
++)
1882 print_yes_no_line(i
== 0, FLAGS_SET(stub_features
, stub_flags
[i
].flag
), stub_flags
[i
].name
);
1884 if (!sd_id128_is_null(loader_part_uuid
))
1885 printf(" ESP: /dev/disk/by-partuuid/" SD_ID128_UUID_FORMAT_STR
"\n",
1886 SD_ID128_FORMAT_VAL(loader_part_uuid
));
1888 printf(" ESP: n/a\n");
1889 printf(" File: %s%s\n", special_glyph(SPECIAL_GLYPH_TREE_RIGHT
), strna(loader_path
));
1892 printf("%sRandom Seed:%s\n", ansi_underline(), ansi_normal());
1893 have
= access(EFIVAR_PATH(EFI_LOADER_VARIABLE(LoaderRandomSeed
)), F_OK
) >= 0;
1894 printf(" Passed to OS: %s\n", yes_no(have
));
1895 have
= access(EFIVAR_PATH(EFI_LOADER_VARIABLE(LoaderSystemToken
)), F_OK
) >= 0;
1896 printf(" System Token: %s\n", have
? "set" : "not set");
1899 _cleanup_free_
char *p
= NULL
;
1901 p
= path_join(arg_esp_path
, "/loader/random-seed");
1905 have
= access(p
, F_OK
) >= 0;
1906 printf(" Exists: %s\n", yes_no(have
));
1911 printf("%sSystem:%s\n"
1912 "Not booted with EFI\n\n",
1913 ansi_underline(), ansi_normal());
1916 k
= status_binaries(arg_esp_path
, esp_uuid
);
1921 if (!arg_root
&& is_efi_boot()) {
1922 k
= status_variables();
1927 if (arg_esp_path
|| arg_xbootldr_path
) {
1928 _cleanup_(boot_config_free
) BootConfig config
= BOOT_CONFIG_NULL
;
1930 k
= boot_config_load_and_select(&config
,
1931 arg_esp_path
, esp_devid
,
1932 arg_xbootldr_path
, xbootldr_devid
);
1936 k
= status_entries(&config
,
1937 arg_esp_path
, esp_uuid
,
1938 arg_xbootldr_path
, xbootldr_uuid
);
1947 static int verb_list(int argc
, char *argv
[], void *userdata
) {
1948 _cleanup_(boot_config_free
) BootConfig config
= BOOT_CONFIG_NULL
;
1949 dev_t esp_devid
= 0, xbootldr_devid
= 0;
1952 /* If we lack privileges we invoke find_esp_and_warn() in "unprivileged mode" here, which does two
1953 * things: turn off logging about access errors and turn off potentially privileged device probing.
1954 * Here we're interested in the latter but not the former, hence request the mode, and log about
1957 r
= acquire_esp(/* unprivileged_mode= */ geteuid() != 0, /* graceful= */ false, NULL
, NULL
, NULL
, NULL
, &esp_devid
);
1958 if (r
== -EACCES
) /* We really need the ESP path for this call, hence also log about access errors */
1959 return log_error_errno(r
, "Failed to determine ESP location: %m");
1963 r
= acquire_xbootldr(/* unprivileged_mode= */ geteuid() != 0, NULL
, &xbootldr_devid
);
1965 return log_error_errno(r
, "Failed to determine XBOOTLDR partition: %m");
1969 r
= boot_config_load_and_select(&config
, arg_esp_path
, esp_devid
, arg_xbootldr_path
, xbootldr_devid
);
1973 if (config
.n_entries
== 0 && FLAGS_SET(arg_json_format_flags
, JSON_FORMAT_OFF
)) {
1974 log_info("No boot loader entries found.");
1978 pager_open(arg_pager_flags
);
1979 return show_boot_entries(&config
, arg_json_format_flags
);
1982 static int install_random_seed(const char *esp
) {
1983 _cleanup_(unlink_and_freep
) char *tmp
= NULL
;
1984 _cleanup_free_
void *buffer
= NULL
;
1985 _cleanup_free_
char *path
= NULL
;
1986 _cleanup_close_
int fd
= -1;
1987 size_t sz
, token_size
;
1993 path
= path_join(esp
, "/loader/random-seed");
1997 sz
= random_pool_size();
1999 buffer
= malloc(sz
);
2003 r
= crypto_random_bytes(buffer
, sz
);
2005 return log_error_errno(r
, "Failed to acquire random seed: %m");
2007 /* Normally create_subdirs() should already have created everything we need, but in case "bootctl
2008 * random-seed" is called we want to just create the minimum we need for it, and not the full
2010 r
= mkdir_parents(path
, 0755);
2012 return log_error_errno(r
, "Failed to create parent directory for %s: %m", path
);
2014 r
= tempfn_random(path
, "bootctl", &tmp
);
2018 fd
= open(tmp
, O_CREAT
|O_EXCL
|O_NOFOLLOW
|O_NOCTTY
|O_WRONLY
|O_CLOEXEC
, 0600);
2021 return log_error_errno(fd
, "Failed to open random seed file for writing: %m");
2024 n
= write(fd
, buffer
, sz
);
2026 return log_error_errno(errno
, "Failed to write random seed file: %m");
2027 if ((size_t) n
!= sz
)
2028 return log_error_errno(SYNTHETIC_ERRNO(EIO
), "Short write while writing random seed file.");
2030 if (rename(tmp
, path
) < 0)
2031 return log_error_errno(r
, "Failed to move random seed file into place: %m");
2035 log_info("Random seed file %s successfully written (%zu bytes).", path
, sz
);
2037 if (!arg_touch_variables
)
2040 if (!is_efi_boot()) {
2041 log_notice("Not booted with EFI, skipping EFI variable setup.");
2046 log_warning("Acting on %s, skipping EFI variable setup.",
2047 arg_image
? "image" : "root directory");
2051 r
= getenv_bool("SYSTEMD_WRITE_SYSTEM_TOKEN");
2054 log_warning_errno(r
, "Failed to parse $SYSTEMD_WRITE_SYSTEM_TOKEN, ignoring.");
2056 if (detect_vm() > 0) {
2057 /* Let's not write a system token if we detect we are running in a VM
2058 * environment. Why? Our default security model for the random seed uses the system
2059 * token as a mechanism to ensure we are not vulnerable to golden master sloppiness
2060 * issues, i.e. that people initialize the random seed file, then copy the image to
2061 * many systems and end up with the same random seed in each that is assumed to be
2062 * valid but in reality is the same for all machines. By storing a system token in
2063 * the EFI variable space we can make sure that even though the random seeds on disk
2064 * are all the same they will be different on each system under the assumption that
2065 * the EFI variable space is maintained separate from the random seed storage. That
2066 * is generally the case on physical systems, as the ESP is stored on persistent
2067 * storage, and the EFI variables in NVRAM. However in virtualized environments this
2068 * is generally not true: the EFI variable set is typically stored along with the
2069 * disk image itself. For example, using the OVMF EFI firmware the EFI variables are
2070 * stored in a file in the ESP itself. */
2072 log_notice("Not installing system token, since we are running in a virtualized environment.");
2075 } else if (r
== 0) {
2076 log_notice("Not writing system token, because $SYSTEMD_WRITE_SYSTEM_TOKEN is set to false.");
2080 r
= efi_get_variable(EFI_LOADER_VARIABLE(LoaderSystemToken
), NULL
, NULL
, &token_size
);
2082 log_debug_errno(r
, "LoaderSystemToken EFI variable is invalid (too short?), replacing.");
2085 return log_error_errno(r
, "Failed to test system token validity: %m");
2087 if (token_size
>= sz
) {
2088 /* Let's avoid writes if we can, and initialize this only once. */
2089 log_debug("System token already written, not updating.");
2093 log_debug("Existing system token size (%zu) does not match our expectations (%zu), replacing.", token_size
, sz
);
2096 r
= crypto_random_bytes(buffer
, sz
);
2098 return log_error_errno(r
, "Failed to acquire random seed: %m");
2100 /* Let's write this variable with an umask in effect, so that unprivileged users can't see the token
2101 * and possibly get identification information or too much insight into the kernel's entropy pool
2103 RUN_WITH_UMASK(0077) {
2104 r
= efi_set_variable(EFI_LOADER_VARIABLE(LoaderSystemToken
), buffer
, sz
);
2107 return log_error_errno(r
, "Failed to write 'LoaderSystemToken' EFI variable: %m");
2110 log_warning_errno(r
, "Unable to write 'LoaderSystemToken' EFI variable (firmware problem?), ignoring: %m");
2112 log_warning_errno(r
, "Unable to write 'LoaderSystemToken' EFI variable, ignoring: %m");
2114 log_info("Successfully initialized system token in EFI variable with %zu bytes.", sz
);
2120 static int sync_everything(void) {
2124 k
= syncfs_path(AT_FDCWD
, arg_esp_path
);
2126 ret
= log_error_errno(k
, "Failed to synchronize the ESP '%s': %m", arg_esp_path
);
2129 if (arg_xbootldr_path
) {
2130 k
= syncfs_path(AT_FDCWD
, arg_xbootldr_path
);
2132 ret
= log_error_errno(k
, "Failed to synchronize $BOOT '%s': %m", arg_xbootldr_path
);
2138 static int verb_install(int argc
, char *argv
[], void *userdata
) {
2139 sd_id128_t uuid
= SD_ID128_NULL
;
2140 uint64_t pstart
= 0, psize
= 0;
2142 bool install
, graceful
;
2145 /* Invoked for both "update" and "install" */
2147 install
= streq(argv
[0], "install");
2148 graceful
= !install
&& arg_graceful
; /* support graceful mode for updates */
2150 r
= acquire_esp(/* unprivileged_mode= */ false, graceful
, &part
, &pstart
, &psize
, &uuid
, NULL
);
2151 if (graceful
&& r
== -ENOKEY
)
2152 return 0; /* If --graceful is specified and we can't find an ESP, handle this cleanly */
2157 /* If we are updating, don't do anything if sd-boot wasn't actually installed. */
2158 r
= are_we_installed(arg_esp_path
);
2162 log_debug("Skipping update because sd-boot is not installed in the ESP.");
2167 r
= acquire_xbootldr(/* unprivileged_mode= */ false, NULL
, NULL
);
2171 r
= settle_make_entry_directory();
2175 const char *arch
= arg_arch_all
? "" : get_efi_arch();
2177 RUN_WITH_UMASK(0002) {
2179 /* Don't create any of these directories when we are just updating. When we update
2180 * we'll drop-in our files (unless there are newer ones already), but we won't create
2181 * the directories for them in the first place. */
2182 r
= create_subdirs(arg_esp_path
, esp_subdirs
);
2186 r
= create_subdirs(arg_dollar_boot_path(), dollar_boot_subdirs
);
2191 r
= install_binaries(arg_esp_path
, arch
, install
);
2196 r
= install_loader_config(arg_esp_path
);
2200 r
= install_entry_directory(arg_dollar_boot_path());
2204 r
= install_entry_token();
2208 r
= install_random_seed(arg_esp_path
);
2213 r
= install_loader_specification(arg_dollar_boot_path());
2218 (void) sync_everything();
2220 if (!arg_touch_variables
)
2224 log_info("Not changing EFI variables with --all-architectures.");
2228 char *path
= strjoina("/EFI/systemd/systemd-boot", arch
, ".efi");
2229 return install_variables(arg_esp_path
, part
, pstart
, psize
, uuid
, path
, install
);
2232 static int verb_remove(int argc
, char *argv
[], void *userdata
) {
2233 sd_id128_t uuid
= SD_ID128_NULL
;
2236 r
= acquire_esp(/* unprivileged_mode= */ false, /* graceful= */ false, NULL
, NULL
, NULL
, &uuid
, NULL
);
2240 r
= acquire_xbootldr(/* unprivileged_mode= */ false, NULL
, NULL
);
2244 r
= settle_make_entry_directory();
2248 r
= remove_binaries(arg_esp_path
);
2250 q
= remove_file(arg_esp_path
, "/loader/loader.conf");
2251 if (q
< 0 && r
>= 0)
2254 q
= remove_file(arg_esp_path
, "/loader/random-seed");
2255 if (q
< 0 && r
>= 0)
2258 q
= remove_file(arg_esp_path
, "/loader/entries.srel");
2259 if (q
< 0 && r
>= 0)
2262 q
= remove_subdirs(arg_esp_path
, esp_subdirs
);
2263 if (q
< 0 && r
>= 0)
2266 q
= remove_subdirs(arg_esp_path
, dollar_boot_subdirs
);
2267 if (q
< 0 && r
>= 0)
2270 q
= remove_entry_directory(arg_esp_path
);
2271 if (q
< 0 && r
>= 0)
2274 if (arg_xbootldr_path
) {
2275 /* Remove a subset of these also from the XBOOTLDR partition if it exists */
2277 q
= remove_file(arg_xbootldr_path
, "/loader/entries.srel");
2278 if (q
< 0 && r
>= 0)
2281 q
= remove_subdirs(arg_xbootldr_path
, dollar_boot_subdirs
);
2282 if (q
< 0 && r
>= 0)
2285 q
= remove_entry_directory(arg_xbootldr_path
);
2286 if (q
< 0 && r
>= 0)
2290 (void) sync_everything();
2292 if (!arg_touch_variables
)
2296 log_info("Not changing EFI variables with --all-architectures.");
2300 char *path
= strjoina("/EFI/systemd/systemd-boot", get_efi_arch(), ".efi");
2301 q
= remove_variables(uuid
, path
, true);
2302 if (q
< 0 && r
>= 0)
2305 q
= remove_loader_variables();
2306 if (q
< 0 && r
>= 0)
2312 static int verb_is_installed(int argc
, char *argv
[], void *userdata
) {
2315 r
= acquire_esp(/* privileged_mode= */ false,
2316 /* graceful= */ arg_graceful
,
2317 NULL
, NULL
, NULL
, NULL
, NULL
);
2321 r
= are_we_installed(arg_esp_path
);
2328 return EXIT_SUCCESS
;
2332 return EXIT_FAILURE
;
2336 static int parse_timeout(const char *arg1
, char16_t
**ret_timeout
, size_t *ret_timeout_size
) {
2337 char utf8
[DECIMAL_STR_MAX(usec_t
)];
2343 assert(ret_timeout
);
2344 assert(ret_timeout_size
);
2346 if (streq(arg1
, "menu-force"))
2347 timeout
= USEC_INFINITY
;
2348 else if (streq(arg1
, "menu-hidden"))
2351 r
= parse_time(arg1
, &timeout
, USEC_PER_SEC
);
2353 return log_error_errno(r
, "Failed to parse timeout '%s': %m", arg1
);
2354 if (timeout
!= USEC_INFINITY
&& timeout
> UINT32_MAX
* USEC_PER_SEC
)
2355 log_warning("Timeout is too long and will be treated as 'menu-force' instead.");
2358 xsprintf(utf8
, USEC_FMT
, MIN(timeout
/ USEC_PER_SEC
, UINT32_MAX
));
2360 encoded
= utf8_to_utf16(utf8
, strlen(utf8
));
2364 *ret_timeout
= encoded
;
2365 *ret_timeout_size
= char16_strlen(encoded
) * 2 + 2;
2369 static int parse_loader_entry_target_arg(const char *arg1
, char16_t
**ret_target
, size_t *ret_target_size
) {
2370 char16_t
*encoded
= NULL
;
2375 assert(ret_target_size
);
2377 if (streq(arg1
, "@current")) {
2378 r
= efi_get_variable(EFI_LOADER_VARIABLE(LoaderEntrySelected
), NULL
, (void *) ret_target
, ret_target_size
);
2380 return log_error_errno(r
, "Failed to get EFI variable 'LoaderEntrySelected': %m");
2382 } else if (streq(arg1
, "@oneshot")) {
2383 r
= efi_get_variable(EFI_LOADER_VARIABLE(LoaderEntryOneShot
), NULL
, (void *) ret_target
, ret_target_size
);
2385 return log_error_errno(r
, "Failed to get EFI variable 'LoaderEntryOneShot': %m");
2387 } else if (streq(arg1
, "@default")) {
2388 r
= efi_get_variable(EFI_LOADER_VARIABLE(LoaderEntryDefault
), NULL
, (void *) ret_target
, ret_target_size
);
2390 return log_error_errno(r
, "Failed to get EFI variable 'LoaderEntryDefault': %m");
2392 } else if (arg1
[0] == '@' && !streq(arg1
, "@saved"))
2393 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Unsupported special entry identifier: %s", arg1
);
2395 encoded
= utf8_to_utf16(arg1
, strlen(arg1
));
2399 *ret_target
= encoded
;
2400 *ret_target_size
= char16_strlen(encoded
) * 2 + 2;
2406 static int verb_set_efivar(int argc
, char *argv
[], void *userdata
) {
2410 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
),
2411 "Acting on %s, skipping EFI variable setup.",
2412 arg_image
? "image" : "root directory");
2415 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
),
2416 "Not booted with UEFI.");
2418 if (access(EFIVAR_PATH(EFI_LOADER_VARIABLE(LoaderInfo
)), F_OK
) < 0) {
2419 if (errno
== ENOENT
) {
2420 log_error_errno(errno
, "Not booted with a supported boot loader.");
2424 return log_error_errno(errno
, "Failed to detect whether boot loader supports '%s' operation: %m", argv
[0]);
2427 if (detect_container() > 0)
2428 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
),
2429 "'%s' operation not supported in a container.",
2432 if (!arg_touch_variables
)
2433 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
2434 "'%s' operation cannot be combined with --no-variables.",
2437 const char *variable
;
2438 int (* arg_parser
)(const char *, char16_t
**, size_t *);
2440 if (streq(argv
[0], "set-default")) {
2441 variable
= EFI_LOADER_VARIABLE(LoaderEntryDefault
);
2442 arg_parser
= parse_loader_entry_target_arg
;
2443 } else if (streq(argv
[0], "set-oneshot")) {
2444 variable
= EFI_LOADER_VARIABLE(LoaderEntryOneShot
);
2445 arg_parser
= parse_loader_entry_target_arg
;
2446 } else if (streq(argv
[0], "set-timeout")) {
2447 variable
= EFI_LOADER_VARIABLE(LoaderConfigTimeout
);
2448 arg_parser
= parse_timeout
;
2449 } else if (streq(argv
[0], "set-timeout-oneshot")) {
2450 variable
= EFI_LOADER_VARIABLE(LoaderConfigTimeoutOneShot
);
2451 arg_parser
= parse_timeout
;
2453 assert_not_reached();
2455 if (isempty(argv
[1])) {
2456 r
= efi_set_variable(variable
, NULL
, 0);
2457 if (r
< 0 && r
!= -ENOENT
)
2458 return log_error_errno(r
, "Failed to remove EFI variable '%s': %m", variable
);
2460 _cleanup_free_ char16_t
*value
= NULL
;
2461 size_t value_size
= 0;
2463 r
= arg_parser(argv
[1], &value
, &value_size
);
2466 r
= efi_set_variable(variable
, value
, value_size
);
2468 return log_error_errno(r
, "Failed to update EFI variable '%s': %m", variable
);
2474 static int verb_random_seed(int argc
, char *argv
[], void *userdata
) {
2477 r
= find_esp_and_warn(arg_root
, arg_esp_path
, false, &arg_esp_path
, NULL
, NULL
, NULL
, NULL
, NULL
);
2479 /* find_esp_and_warn() doesn't warn about ENOKEY, so let's do that on our own */
2481 return log_error_errno(r
, "Unable to find ESP.");
2483 log_notice("No ESP found, not initializing random seed.");
2489 r
= install_random_seed(arg_esp_path
);
2493 (void) sync_everything();
2497 static int verb_systemd_efi_options(int argc
, char *argv
[], void *userdata
) {
2501 _cleanup_free_
char *line
= NULL
, *new = NULL
;
2503 r
= systemd_efi_options_variable(&line
);
2505 log_debug("No SystemdOptions EFI variable present in cache.");
2507 return log_error_errno(r
, "Failed to read SystemdOptions EFI variable from cache: %m");
2511 r
= systemd_efi_options_efivarfs_if_newer(&new);
2512 if (r
== -ENODATA
) {
2514 log_notice("Note: SystemdOptions EFI variable has been removed since boot.");
2516 log_warning_errno(r
, "Failed to check SystemdOptions EFI variable in efivarfs, ignoring: %m");
2517 else if (new && !streq_ptr(line
, new))
2518 log_notice("Note: SystemdOptions EFI variable has been modified since boot. New value: %s",
2521 r
= efi_set_variable_string(EFI_SYSTEMD_VARIABLE(SystemdOptions
), argv
[1]);
2523 return log_error_errno(r
, "Failed to set SystemdOptions EFI variable: %m");
2529 static int verb_reboot_to_firmware(int argc
, char *argv
[], void *userdata
) {
2533 r
= efi_get_reboot_to_firmware();
2536 return EXIT_SUCCESS
; /* success */
2540 return 1; /* recognizable error #1 */
2542 if (r
== -EOPNOTSUPP
) {
2543 puts("not supported");
2544 return 2; /* recognizable error #2 */
2547 log_error_errno(r
, "Failed to query reboot-to-firmware state: %m");
2548 return 3; /* other kind of error */
2550 r
= parse_boolean(argv
[1]);
2552 return log_error_errno(r
, "Failed to parse argument: %s", argv
[1]);
2554 r
= efi_set_reboot_to_firmware(r
);
2556 return log_error_errno(r
, "Failed to set reboot-to-firmware option: %m");
2562 static int bootctl_main(int argc
, char *argv
[]) {
2563 static const Verb verbs
[] = {
2564 { "help", VERB_ANY
, VERB_ANY
, 0, help
},
2565 { "status", VERB_ANY
, 1, VERB_DEFAULT
, verb_status
},
2566 { "install", VERB_ANY
, 1, 0, verb_install
},
2567 { "update", VERB_ANY
, 1, 0, verb_install
},
2568 { "remove", VERB_ANY
, 1, 0, verb_remove
},
2569 { "is-installed", VERB_ANY
, 1, 0, verb_is_installed
},
2570 { "list", VERB_ANY
, 1, 0, verb_list
},
2571 { "set-default", 2, 2, 0, verb_set_efivar
},
2572 { "set-oneshot", 2, 2, 0, verb_set_efivar
},
2573 { "set-timeout", 2, 2, 0, verb_set_efivar
},
2574 { "set-timeout-oneshot", 2, 2, 0, verb_set_efivar
},
2575 { "random-seed", VERB_ANY
, 1, 0, verb_random_seed
},
2576 { "systemd-efi-options", VERB_ANY
, 2, 0, verb_systemd_efi_options
},
2577 { "reboot-to-firmware", VERB_ANY
, 2, 0, verb_reboot_to_firmware
},
2581 return dispatch_verb(argc
, argv
, verbs
, NULL
);
2584 static int run(int argc
, char *argv
[]) {
2585 _cleanup_(loop_device_unrefp
) LoopDevice
*loop_device
= NULL
;
2586 _cleanup_(decrypted_image_unrefp
) DecryptedImage
*decrypted_image
= NULL
;
2587 _cleanup_(umount_and_rmdir_and_freep
) char *unlink_dir
= NULL
;
2590 log_parse_environment();
2593 /* If we run in a container, automatically turn off EFI file system access */
2594 if (detect_container() > 0)
2595 arg_touch_variables
= false;
2597 r
= parse_argv(argc
, argv
);
2601 /* Open up and mount the image */
2605 r
= mount_image_privately_interactively(
2607 DISSECT_IMAGE_GENERIC_ROOT
|
2608 DISSECT_IMAGE_RELAX_VAR_CHECK
,
2615 arg_root
= strdup(unlink_dir
);
2620 return bootctl_main(argc
, argv
);
2623 DEFINE_MAIN_FUNCTION_WITH_POSITIVE_FAILURE(run
);