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 static char *arg_esp_path
= NULL
;
61 static char *arg_xbootldr_path
= NULL
;
62 static bool arg_print_esp_path
= false;
63 static bool arg_print_dollar_boot_path
= false;
64 static bool arg_touch_variables
= true;
65 static PagerFlags arg_pager_flags
= 0;
66 static bool arg_graceful
= false;
67 static bool arg_quiet
= false;
68 static int arg_make_entry_directory
= false; /* tri-state: < 0 for automatic logic */
69 static sd_id128_t arg_machine_id
= SD_ID128_NULL
;
70 static char *arg_install_layout
= NULL
;
72 ARG_ENTRY_TOKEN_MACHINE_ID
,
73 ARG_ENTRY_TOKEN_OS_IMAGE_ID
,
74 ARG_ENTRY_TOKEN_OS_ID
,
75 ARG_ENTRY_TOKEN_LITERAL
,
77 } arg_entry_token_type
= ARG_ENTRY_TOKEN_AUTO
;
78 static char *arg_entry_token
= NULL
;
79 static JsonFormatFlags arg_json_format_flags
= JSON_FORMAT_OFF
;
80 static bool arg_arch_all
= false;
81 static char *arg_root
= NULL
;
82 static char *arg_image
= NULL
;
84 ARG_INSTALL_SOURCE_IMAGE
,
85 ARG_INSTALL_SOURCE_HOST
,
86 ARG_INSTALL_SOURCE_AUTO
,
87 } arg_install_source
= ARG_INSTALL_SOURCE_AUTO
;
89 STATIC_DESTRUCTOR_REGISTER(arg_esp_path
, freep
);
90 STATIC_DESTRUCTOR_REGISTER(arg_xbootldr_path
, freep
);
91 STATIC_DESTRUCTOR_REGISTER(arg_install_layout
, freep
);
92 STATIC_DESTRUCTOR_REGISTER(arg_entry_token
, freep
);
93 STATIC_DESTRUCTOR_REGISTER(arg_root
, freep
);
94 STATIC_DESTRUCTOR_REGISTER(arg_image
, freep
);
96 static const char *arg_dollar_boot_path(void) {
97 /* $BOOT shall be the XBOOTLDR partition if it exists, and otherwise the ESP */
98 return arg_xbootldr_path
?: arg_esp_path
;
101 static int acquire_esp(
102 bool unprivileged_mode
,
105 uint64_t *ret_pstart
,
107 sd_id128_t
*ret_uuid
,
113 /* Find the ESP, and log about errors. Note that find_esp_and_warn() will log in all error cases on
114 * its own, except for ENOKEY (which is good, we want to show our own message in that case,
115 * suggesting use of --esp-path=) and EACCESS (only when we request unprivileged mode; in this case
116 * we simply eat up the error here, so that --list and --status work too, without noise about
119 r
= find_esp_and_warn(arg_root
, arg_esp_path
, unprivileged_mode
, &np
, ret_part
, ret_pstart
, ret_psize
, ret_uuid
, ret_devid
);
122 return log_full_errno(arg_quiet
? LOG_DEBUG
: LOG_INFO
, r
,
123 "Couldn't find EFI system partition, skipping.");
125 return log_error_errno(r
,
126 "Couldn't find EFI system partition. It is recommended to mount it to /boot or /efi.\n"
127 "Alternatively, use --esp-path= to specify path to mount point.");
132 free_and_replace(arg_esp_path
, np
);
133 log_debug("Using EFI System Partition at %s.", arg_esp_path
);
138 static int acquire_xbootldr(
139 bool unprivileged_mode
,
140 sd_id128_t
*ret_uuid
,
146 r
= find_xbootldr_and_warn(arg_root
, arg_xbootldr_path
, unprivileged_mode
, &np
, ret_uuid
, ret_devid
);
148 log_debug_errno(r
, "Didn't find an XBOOTLDR partition, using the ESP as $BOOT.");
149 arg_xbootldr_path
= mfree(arg_xbootldr_path
);
152 *ret_uuid
= SD_ID128_NULL
;
160 free_and_replace(arg_xbootldr_path
, np
);
161 log_debug("Using XBOOTLDR partition at %s as $BOOT.", arg_xbootldr_path
);
166 static int load_etc_machine_id(void) {
169 r
= sd_id128_get_machine(&arg_machine_id
);
170 if (IN_SET(r
, -ENOENT
, -ENOMEDIUM
)) /* Not set or empty */
173 return log_error_errno(r
, "Failed to get machine-id: %m");
175 log_debug("Loaded machine ID %s from /etc/machine-id.", SD_ID128_TO_STRING(arg_machine_id
));
179 static int load_etc_machine_info(void) {
180 /* systemd v250 added support to store the kernel-install layout setting and the machine ID to use
181 * for setting up the ESP in /etc/machine-info. The newer /etc/kernel/entry-token file, as well as
182 * the $layout field in /etc/kernel/install.conf are better replacements for this though, hence this
183 * has been deprecated and is only returned for compatibility. */
184 _cleanup_free_
char *s
= NULL
, *layout
= NULL
;
187 r
= parse_env_file(NULL
, "/etc/machine-info",
188 "KERNEL_INSTALL_LAYOUT", &layout
,
189 "KERNEL_INSTALL_MACHINE_ID", &s
);
193 return log_error_errno(r
, "Failed to parse /etc/machine-info: %m");
197 log_notice("Read $KERNEL_INSTALL_MACHINE_ID from /etc/machine-info. "
198 "Please move it to /etc/kernel/entry-token.");
200 r
= sd_id128_from_string(s
, &arg_machine_id
);
202 return log_error_errno(r
, "Failed to parse KERNEL_INSTALL_MACHINE_ID=%s in /etc/machine-info: %m", s
);
204 log_debug("Loaded KERNEL_INSTALL_MACHINE_ID=%s from KERNEL_INSTALL_MACHINE_ID in /etc/machine-info.",
205 SD_ID128_TO_STRING(arg_machine_id
));
208 if (!isempty(layout
)) {
210 log_notice("Read $KERNEL_INSTALL_LAYOUT from /etc/machine-info. "
211 "Please move it to the layout= setting of /etc/kernel/install.conf.");
213 log_debug("KERNEL_INSTALL_LAYOUT=%s is specified in /etc/machine-info.", layout
);
214 free_and_replace(arg_install_layout
, layout
);
220 static int load_etc_kernel_install_conf(void) {
221 _cleanup_free_
char *layout
= NULL
;
224 r
= parse_env_file(NULL
, "/etc/kernel/install.conf",
229 return log_error_errno(r
, "Failed to parse /etc/kernel/install.conf: %m");
231 if (!isempty(layout
)) {
232 log_debug("layout=%s is specified in /etc/machine-info.", layout
);
233 free_and_replace(arg_install_layout
, layout
);
239 static int settle_entry_token(void) {
242 switch (arg_entry_token_type
) {
244 case ARG_ENTRY_TOKEN_AUTO
: {
245 _cleanup_free_
char *buf
= NULL
;
246 r
= read_one_line_file("/etc/kernel/entry-token", &buf
);
247 if (r
< 0 && r
!= -ENOENT
)
248 return log_error_errno(r
, "Failed to read /etc/kernel/entry-token: %m");
251 free_and_replace(arg_entry_token
, buf
);
252 arg_entry_token_type
= ARG_ENTRY_TOKEN_LITERAL
;
253 } else if (sd_id128_is_null(arg_machine_id
)) {
254 _cleanup_free_
char *id
= NULL
, *image_id
= NULL
;
256 r
= parse_os_release(NULL
,
257 "IMAGE_ID", &image_id
,
260 return log_error_errno(r
, "Failed to load /etc/os-release: %m");
262 if (!isempty(image_id
)) {
263 free_and_replace(arg_entry_token
, image_id
);
264 arg_entry_token_type
= ARG_ENTRY_TOKEN_OS_IMAGE_ID
;
265 } else if (!isempty(id
)) {
266 free_and_replace(arg_entry_token
, id
);
267 arg_entry_token_type
= ARG_ENTRY_TOKEN_OS_ID
;
269 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "No machine ID set, and /etc/os-release carries no ID=/IMAGE_ID= fields.");
271 r
= free_and_strdup_warn(&arg_entry_token
, SD_ID128_TO_STRING(arg_machine_id
));
275 arg_entry_token_type
= ARG_ENTRY_TOKEN_MACHINE_ID
;
281 case ARG_ENTRY_TOKEN_MACHINE_ID
:
282 if (sd_id128_is_null(arg_machine_id
))
283 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "No machine ID set.");
285 r
= free_and_strdup_warn(&arg_entry_token
, SD_ID128_TO_STRING(arg_machine_id
));
291 case ARG_ENTRY_TOKEN_OS_IMAGE_ID
: {
292 _cleanup_free_
char *buf
= NULL
;
294 r
= parse_os_release(NULL
, "IMAGE_ID", &buf
);
296 return log_error_errno(r
, "Failed to load /etc/os-release: %m");
299 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "IMAGE_ID= field not set in /etc/os-release.");
301 free_and_replace(arg_entry_token
, buf
);
305 case ARG_ENTRY_TOKEN_OS_ID
: {
306 _cleanup_free_
char *buf
= NULL
;
308 r
= parse_os_release(NULL
, "ID", &buf
);
310 return log_error_errno(r
, "Failed to load /etc/os-release: %m");
313 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "ID= field not set in /etc/os-release.");
315 free_and_replace(arg_entry_token
, buf
);
319 case ARG_ENTRY_TOKEN_LITERAL
:
320 assert(!isempty(arg_entry_token
)); /* already filled in by command line parser */
324 if (isempty(arg_entry_token
) || !string_is_safe(arg_entry_token
))
325 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Selected entry token not valid: %s", arg_entry_token
);
327 log_debug("Using entry token: %s", arg_entry_token
);
331 static bool use_boot_loader_spec_type1(void) {
332 /* If the layout is not specified, or if it is set explicitly to "bls" we assume Boot Loader
333 * Specification Type #1 is the chosen format for our boot loader entries */
334 return !arg_install_layout
|| streq(arg_install_layout
, "bls");
337 static int settle_make_entry_directory(void) {
340 r
= load_etc_machine_id();
344 r
= load_etc_machine_info();
348 r
= load_etc_kernel_install_conf();
352 r
= settle_entry_token();
356 bool layout_type1
= use_boot_loader_spec_type1();
357 if (arg_make_entry_directory
< 0) { /* Automatic mode */
359 if (arg_entry_token
== ARG_ENTRY_TOKEN_MACHINE_ID
) {
360 r
= path_is_temporary_fs("/etc/machine-id");
362 return log_debug_errno(r
, "Couldn't determine whether /etc/machine-id is on a temporary file system: %m");
364 arg_make_entry_directory
= r
== 0;
366 arg_make_entry_directory
= true;
368 arg_make_entry_directory
= false;
371 if (arg_make_entry_directory
> 0 && !layout_type1
)
372 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
373 "KERNEL_INSTALL_LAYOUT=%s is configured, but Boot Loader Specification Type #1 entry directory creation was requested.",
379 /* search for "#### LoaderInfo: systemd-boot 218 ####" string inside the binary */
380 static int get_file_version(int fd
, char **v
) {
390 if (fstat(fd
, &st
) < 0)
391 return log_error_errno(errno
, "Failed to stat EFI binary: %m");
393 r
= stat_verify_regular(&st
);
395 return log_error_errno(r
, "EFI binary is not a regular file: %m");
397 if (st
.st_size
< 27 || file_offset_beyond_memory_size(st
.st_size
)) {
402 buf
= mmap(NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0);
403 if (buf
== MAP_FAILED
)
404 return log_error_errno(errno
, "Failed to memory map EFI binary: %m");
406 s
= mempmem_safe(buf
, st
.st_size
- 8, "#### LoaderInfo: ", 17);
410 e
= memmem_safe(s
, st
.st_size
- (s
- buf
), " ####", 5);
411 if (!e
|| e
- s
< 3) {
412 r
= log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Malformed version string.");
416 x
= strndup(s
, e
- s
);
424 (void) munmap(buf
, st
.st_size
);
429 static const char *get_efi_arch(void) {
430 /* Detect EFI firmware architecture of the running system. On mixed mode systems, it could be 32bit
431 * while the kernel is running in 64bit. */
434 _cleanup_free_
char *platform_size
= NULL
;
437 r
= read_one_line_file("/sys/firmware/efi/fw_platform_size", &platform_size
);
439 return EFI_MACHINE_TYPE_NAME
;
441 log_warning_errno(r
, "Error reading EFI firmware word size, assuming '%u': %m", __WORDSIZE
);
442 return EFI_MACHINE_TYPE_NAME
;
445 if (streq(platform_size
, "64"))
446 return EFI_MACHINE_TYPE_NAME
;
447 if (streq(platform_size
, "32"))
451 "Unknown EFI firmware word size '%s', using default word size '%u' instead.",
456 return EFI_MACHINE_TYPE_NAME
;
459 static int enumerate_binaries(const char *esp_path
, const char *path
, const char *prefix
) {
460 _cleanup_closedir_
DIR *d
= NULL
;
467 p
= prefix_roota(esp_path
, path
);
473 return log_error_errno(errno
, "Failed to read \"%s\": %m", p
);
476 FOREACH_DIRENT(de
, d
, break) {
477 _cleanup_free_
char *v
= NULL
;
478 _cleanup_close_
int fd
= -1;
480 if (!endswith_no_case(de
->d_name
, ".efi"))
483 if (prefix
&& !startswith_no_case(de
->d_name
, prefix
))
486 fd
= openat(dirfd(d
), de
->d_name
, O_RDONLY
|O_CLOEXEC
);
488 return log_error_errno(errno
, "Failed to open \"%s/%s\" for reading: %m", p
, de
->d_name
);
490 r
= get_file_version(fd
, &v
);
494 printf(" File: %s/%s/%s (%s%s%s)\n", special_glyph(SPECIAL_GLYPH_TREE_RIGHT
), path
, de
->d_name
, ansi_highlight(), v
, ansi_normal());
496 printf(" File: %s/%s/%s\n", special_glyph(SPECIAL_GLYPH_TREE_RIGHT
), path
, de
->d_name
);
504 static int status_binaries(const char *esp_path
, sd_id128_t partition
) {
507 printf("Available Boot Loaders on ESP:\n");
510 printf(" ESP: Cannot find or access mount point of ESP.\n\n");
514 printf(" ESP: %s", esp_path
);
515 if (!sd_id128_is_null(partition
))
516 printf(" (/dev/disk/by-partuuid/" SD_ID128_UUID_FORMAT_STR
")", SD_ID128_FORMAT_VAL(partition
));
519 r
= enumerate_binaries(esp_path
, "EFI/systemd", NULL
);
522 if (r
== 0 && !arg_quiet
)
523 log_info("systemd-boot not installed in ESP.");
525 r
= enumerate_binaries(esp_path
, "EFI/BOOT", "boot");
528 if (r
== 0 && !arg_quiet
)
529 log_info("No default/fallback boot loader installed in ESP.");
538 static int print_efi_option(uint16_t id
, bool in_order
) {
539 _cleanup_free_
char *title
= NULL
;
540 _cleanup_free_
char *path
= NULL
;
541 sd_id128_t partition
;
545 r
= efi_get_boot_option(id
, &title
, &partition
, &path
, &active
);
549 /* print only configured entries with partition information */
550 if (!path
|| sd_id128_is_null(partition
))
553 efi_tilt_backslashes(path
);
555 printf(" Title: %s%s%s\n", ansi_highlight(), strna(title
), ansi_normal());
556 printf(" ID: 0x%04X\n", id
);
557 printf(" Status: %sactive%s\n", active
? "" : "in", in_order
? ", boot-order" : "");
558 printf(" Partition: /dev/disk/by-partuuid/" SD_ID128_UUID_FORMAT_STR
"\n",
559 SD_ID128_FORMAT_VAL(partition
));
560 printf(" File: %s%s\n", special_glyph(SPECIAL_GLYPH_TREE_RIGHT
), path
);
566 static int status_variables(void) {
567 _cleanup_free_
uint16_t *options
= NULL
, *order
= NULL
;
568 int n_options
, n_order
;
570 n_options
= efi_get_boot_options(&options
);
571 if (n_options
== -ENOENT
)
572 return log_error_errno(n_options
,
573 "Failed to access EFI variables, efivarfs"
574 " needs to be available at /sys/firmware/efi/efivars/.");
576 return log_error_errno(n_options
, "Failed to read EFI boot entries: %m");
578 n_order
= efi_get_boot_order(&order
);
579 if (n_order
== -ENOENT
)
581 else if (n_order
< 0)
582 return log_error_errno(n_order
, "Failed to read EFI boot order: %m");
584 /* print entries in BootOrder first */
585 printf("Boot Loaders Listed in EFI Variables:\n");
586 for (int i
= 0; i
< n_order
; i
++)
587 print_efi_option(order
[i
], true);
589 /* print remaining entries */
590 for (int i
= 0; i
< n_options
; i
++) {
591 for (int j
= 0; j
< n_order
; j
++)
592 if (options
[i
] == order
[j
])
595 print_efi_option(options
[i
], false);
604 static int boot_config_load_and_select(
606 const char *esp_path
,
608 const char *xbootldr_path
,
609 dev_t xbootldr_devid
) {
613 /* If XBOOTLDR and ESP actually refer to the same block device, suppress XBOOTLDR, since it would
614 * find the same entries twice. */
615 bool same
= esp_path
&& xbootldr_path
&& devnum_set_and_equal(esp_devid
, xbootldr_devid
);
617 r
= boot_config_load(config
, esp_path
, same
? NULL
: xbootldr_path
);
622 _cleanup_strv_free_
char **efi_entries
= NULL
;
624 r
= efi_loader_get_entries(&efi_entries
);
625 if (r
== -ENOENT
|| ERRNO_IS_NOT_SUPPORTED(r
))
626 log_debug_errno(r
, "Boot loader reported no entries.");
628 log_warning_errno(r
, "Failed to determine entries reported by boot loader, ignoring: %m");
630 (void) boot_config_augment_from_loader(config
, efi_entries
, /* only_auto= */ false);
633 return boot_config_select_special_entries(config
, /* skip_efivars= */ !!arg_root
);
636 static int status_entries(
637 const BootConfig
*config
,
638 const char *esp_path
,
639 sd_id128_t esp_partition_uuid
,
640 const char *xbootldr_path
,
641 sd_id128_t xbootldr_partition_uuid
) {
643 sd_id128_t dollar_boot_partition_uuid
;
644 const char *dollar_boot_path
;
648 assert(esp_path
|| xbootldr_path
);
651 dollar_boot_path
= xbootldr_path
;
652 dollar_boot_partition_uuid
= xbootldr_partition_uuid
;
654 dollar_boot_path
= esp_path
;
655 dollar_boot_partition_uuid
= esp_partition_uuid
;
658 printf("Boot Loader Entries:\n"
659 " $BOOT: %s", dollar_boot_path
);
660 if (!sd_id128_is_null(dollar_boot_partition_uuid
))
661 printf(" (/dev/disk/by-partuuid/" SD_ID128_UUID_FORMAT_STR
")",
662 SD_ID128_FORMAT_VAL(dollar_boot_partition_uuid
));
665 if (config
->default_entry
< 0)
666 printf("%zu entries, no entry could be determined as default.\n", config
->n_entries
);
668 printf("Default Boot Loader Entry:\n");
671 boot_config_default_entry(config
),
672 /* show_as_default= */ false,
673 /* show_as_selected= */ false,
674 /* show_discovered= */ false);
676 /* < 0 is already logged by the function itself, let's just emit an extra warning if
677 the default entry is broken */
678 printf("\nWARNING: default boot entry is broken\n");
684 static int compare_product(const char *a
, const char *b
) {
693 return x
< y
? -1 : x
> y
? 1 : 0;
695 return strncmp(a
, b
, x
);
698 static int compare_version(const char *a
, const char *b
) {
702 a
+= strcspn(a
, " ");
704 b
+= strcspn(b
, " ");
707 return strverscmp_improved(a
, b
);
710 static int version_check(int fd_from
, const char *from
, int fd_to
, const char *to
) {
711 _cleanup_free_
char *a
= NULL
, *b
= NULL
;
714 assert(fd_from
>= 0);
719 r
= get_file_version(fd_from
, &a
);
723 return log_notice_errno(SYNTHETIC_ERRNO(EREMOTE
),
724 "Source file \"%s\" does not carry version information!",
727 r
= get_file_version(fd_to
, &b
);
730 if (r
== 0 || compare_product(a
, b
) != 0)
731 return log_notice_errno(SYNTHETIC_ERRNO(EREMOTE
),
732 "Skipping \"%s\", since it's owned by another boot loader.",
735 r
= compare_version(a
, b
);
736 log_debug("Comparing versions: \"%s\" %s \"%s", a
, comparison_operator(r
), b
);
738 return log_warning_errno(SYNTHETIC_ERRNO(ESTALE
),
739 "Skipping \"%s\", since newer boot loader version in place already.", to
);
741 return log_info_errno(SYNTHETIC_ERRNO(ESTALE
),
742 "Skipping \"%s\", since same boot loader version in place already.", to
);
747 static int copy_file_with_version_check(const char *from
, const char *to
, bool force
) {
748 _cleanup_close_
int fd_from
= -1, fd_to
= -1;
749 _cleanup_free_
char *t
= NULL
;
752 fd_from
= open(from
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
754 return log_error_errno(errno
, "Failed to open \"%s\" for reading: %m", from
);
757 fd_to
= open(to
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
760 return log_error_errno(errno
, "Failed to open \"%s\" for reading: %m", to
);
762 r
= version_check(fd_from
, from
, fd_to
, to
);
766 if (lseek(fd_from
, 0, SEEK_SET
) == (off_t
) -1)
767 return log_error_errno(errno
, "Failed to seek in \"%s\": %m", from
);
769 fd_to
= safe_close(fd_to
);
773 r
= tempfn_random(to
, NULL
, &t
);
777 RUN_WITH_UMASK(0000) {
778 fd_to
= open(t
, O_WRONLY
|O_CREAT
|O_CLOEXEC
|O_EXCL
|O_NOFOLLOW
, 0644);
780 return log_error_errno(errno
, "Failed to open \"%s\" for writing: %m", t
);
783 r
= copy_bytes(fd_from
, fd_to
, UINT64_MAX
, COPY_REFLINK
);
786 return log_error_errno(r
, "Failed to copy data from \"%s\" to \"%s\": %m", from
, t
);
789 (void) copy_times(fd_from
, fd_to
, 0);
791 r
= fsync_full(fd_to
);
793 (void) unlink_noerrno(t
);
794 return log_error_errno(r
, "Failed to copy data from \"%s\" to \"%s\": %m", from
, t
);
797 if (renameat(AT_FDCWD
, t
, AT_FDCWD
, to
) < 0) {
798 (void) unlink_noerrno(t
);
799 return log_error_errno(errno
, "Failed to rename \"%s\" to \"%s\": %m", t
, to
);
802 log_info("Copied \"%s\" to \"%s\".", from
, to
);
807 static int mkdir_one(const char *prefix
, const char *suffix
) {
808 _cleanup_free_
char *p
= NULL
;
810 p
= path_join(prefix
, suffix
);
811 if (mkdir(p
, 0700) < 0) {
813 return log_error_errno(errno
, "Failed to create \"%s\": %m", p
);
815 log_info("Created \"%s\".", p
);
820 static const char *const esp_subdirs
[] = {
821 /* The directories to place in the ESP */
829 static const char *const dollar_boot_subdirs
[] = {
830 /* The directories to place in the XBOOTLDR partition or the ESP, depending what exists */
832 "loader/entries", /* Type #1 entries */
834 "EFI/Linux", /* Type #2 entries */
838 static int create_subdirs(const char *root
, const char * const *subdirs
) {
841 STRV_FOREACH(i
, subdirs
) {
842 r
= mkdir_one(root
, *i
);
850 static int copy_one_file(const char *esp_path
, const char *name
, bool force
) {
851 char *root
= IN_SET(arg_install_source
, ARG_INSTALL_SOURCE_AUTO
, ARG_INSTALL_SOURCE_IMAGE
) ? arg_root
: NULL
;
852 _cleanup_free_
char *source_path
= NULL
, *dest_path
= NULL
, *p
= NULL
, *q
= NULL
;
857 dest_name
= strdupa_safe(name
);
858 s
= endswith_no_case(dest_name
, ".signed");
862 p
= path_join(BOOTLIBDIR
, name
);
866 r
= chase_symlinks(p
, root
, CHASE_PREFIX_ROOT
, &source_path
, NULL
);
867 /* If we had a root directory to try, we didn't find it and we are in auto mode, retry on the host */
868 if (r
== -ENOENT
&& root
&& arg_install_source
== ARG_INSTALL_SOURCE_AUTO
)
869 r
= chase_symlinks(p
, NULL
, CHASE_PREFIX_ROOT
, &source_path
, NULL
);
871 return log_error_errno(r
,
872 "Failed to resolve path %s%s%s: %m",
874 root
? " under directory " : "",
877 q
= path_join("/EFI/systemd/", dest_name
);
881 r
= chase_symlinks(q
, esp_path
, CHASE_PREFIX_ROOT
| CHASE_NONEXISTENT
, &dest_path
, NULL
);
883 return log_error_errno(r
, "Failed to resolve path %s under directory %s: %m", q
, esp_path
);
885 /* Note that if this fails we do the second copy anyway, but return this error code,
886 * so we stash it away in a separate variable. */
887 ret
= copy_file_with_version_check(source_path
, dest_path
, force
);
889 e
= startswith(dest_name
, "systemd-boot");
891 _cleanup_free_
char *default_dest_path
= NULL
;
894 /* Create the EFI default boot loader name (specified for removable devices) */
895 v
= strjoina("/EFI/BOOT/BOOT", e
);
896 ascii_strupper(strrchr(v
, '/') + 1);
898 r
= chase_symlinks(v
, esp_path
, CHASE_PREFIX_ROOT
| CHASE_NONEXISTENT
, &default_dest_path
, NULL
);
900 return log_error_errno(r
, "Failed to resolve path %s under directory %s: %m", v
, esp_path
);
902 r
= copy_file_with_version_check(source_path
, default_dest_path
, force
);
903 if (r
< 0 && ret
== 0)
910 static int install_binaries(const char *esp_path
, const char *arch
, bool force
) {
911 char *root
= IN_SET(arg_install_source
, ARG_INSTALL_SOURCE_AUTO
, ARG_INSTALL_SOURCE_IMAGE
) ? arg_root
: NULL
;
912 _cleanup_closedir_
DIR *d
= NULL
;
913 _cleanup_free_
char *path
= NULL
;
916 r
= chase_symlinks_and_opendir(BOOTLIBDIR
, root
, CHASE_PREFIX_ROOT
, &path
, &d
);
917 /* If we had a root directory to try, we didn't find it and we are in auto mode, retry on the host */
918 if (r
== -ENOENT
&& root
&& arg_install_source
== ARG_INSTALL_SOURCE_AUTO
)
919 r
= chase_symlinks_and_opendir(BOOTLIBDIR
, NULL
, CHASE_PREFIX_ROOT
, &path
, &d
);
921 return log_error_errno(r
, "Failed to open boot loader directory %s%s: %m", root
?: "", BOOTLIBDIR
);
923 const char *suffix
= strjoina(arch
, ".efi");
924 const char *suffix_signed
= strjoina(arch
, ".efi.signed");
926 FOREACH_DIRENT(de
, d
, return log_error_errno(errno
, "Failed to read \"%s\": %m", path
)) {
929 if (!endswith_no_case(de
->d_name
, suffix
) && !endswith_no_case(de
->d_name
, suffix_signed
))
932 /* skip the .efi file, if there's a .signed version of it */
933 if (endswith_no_case(de
->d_name
, ".efi")) {
934 _cleanup_free_
const char *s
= strjoin(de
->d_name
, ".signed");
937 if (faccessat(dirfd(d
), s
, F_OK
, 0) >= 0)
941 k
= copy_one_file(esp_path
, de
->d_name
, force
);
942 /* Don't propagate an error code if no update necessary, installed version already equal or
943 * newer version, or other boot loader in place. */
944 if (arg_graceful
&& IN_SET(k
, -ESTALE
, -EREMOTE
))
953 static bool same_entry(uint16_t id
, sd_id128_t uuid
, const char *path
) {
954 _cleanup_free_
char *opath
= NULL
;
958 r
= efi_get_boot_option(id
, NULL
, &ouuid
, &opath
, NULL
);
961 if (!sd_id128_equal(uuid
, ouuid
))
964 /* Some motherboards convert the path to uppercase under certain circumstances
965 * (e.g. after booting into the Boot Menu in the ASUS ROG STRIX B350-F GAMING),
966 * so use case-insensitive checking */
967 if (!strcaseeq_ptr(path
, opath
))
973 static int find_slot(sd_id128_t uuid
, const char *path
, uint16_t *id
) {
974 _cleanup_free_
uint16_t *options
= NULL
;
976 int n
= efi_get_boot_options(&options
);
980 /* find already existing systemd-boot entry */
981 for (int i
= 0; i
< n
; i
++)
982 if (same_entry(options
[i
], uuid
, path
)) {
987 /* find free slot in the sorted BootXXXX variable list */
988 for (int i
= 0; i
< n
; i
++)
989 if (i
!= options
[i
]) {
994 /* use the next one */
1001 static int insert_into_order(uint16_t slot
, bool first
) {
1002 _cleanup_free_
uint16_t *order
= NULL
;
1006 n
= efi_get_boot_order(&order
);
1008 /* no entry, add us */
1009 return efi_set_boot_order(&slot
, 1);
1011 /* are we the first and only one? */
1012 if (n
== 1 && order
[0] == slot
)
1015 /* are we already in the boot order? */
1016 for (int i
= 0; i
< n
; i
++) {
1017 if (order
[i
] != slot
)
1020 /* we do not require to be the first one, all is fine */
1024 /* move us to the first slot */
1025 memmove(order
+ 1, order
, i
* sizeof(uint16_t));
1027 return efi_set_boot_order(order
, n
);
1031 t
= reallocarray(order
, n
+ 1, sizeof(uint16_t));
1036 /* add us to the top or end of the list */
1038 memmove(order
+ 1, order
, n
* sizeof(uint16_t));
1043 return efi_set_boot_order(order
, n
+ 1);
1046 static int remove_from_order(uint16_t slot
) {
1047 _cleanup_free_
uint16_t *order
= NULL
;
1050 n
= efi_get_boot_order(&order
);
1054 for (int i
= 0; i
< n
; i
++) {
1055 if (order
[i
] != slot
)
1059 memmove(order
+ i
, order
+ i
+1, (n
- i
) * sizeof(uint16_t));
1060 return efi_set_boot_order(order
, n
- 1);
1066 static int install_variables(const char *esp_path
,
1067 uint32_t part
, uint64_t pstart
, uint64_t psize
,
1068 sd_id128_t uuid
, const char *path
,
1075 log_info("Acting on %s, skipping EFI variable setup.",
1076 arg_image
? "image" : "root directory");
1080 if (!is_efi_boot()) {
1081 log_warning("Not booted with EFI, skipping EFI variable setup.");
1085 p
= prefix_roota(esp_path
, path
);
1086 if (access(p
, F_OK
) < 0) {
1087 if (errno
== ENOENT
)
1090 return log_error_errno(errno
, "Cannot access \"%s\": %m", p
);
1093 r
= find_slot(uuid
, path
, &slot
);
1095 return log_error_errno(r
,
1097 "Failed to access EFI variables. Is the \"efivarfs\" filesystem mounted?" :
1098 "Failed to determine current boot order: %m");
1100 if (first
|| r
== 0) {
1101 r
= efi_add_boot_option(slot
, "Linux Boot Manager",
1102 part
, pstart
, psize
,
1105 return log_error_errno(r
, "Failed to create EFI Boot variable entry: %m");
1107 log_info("Created EFI boot entry \"Linux Boot Manager\".");
1110 return insert_into_order(slot
, first
);
1113 static int remove_boot_efi(const char *esp_path
) {
1114 _cleanup_closedir_
DIR *d
= NULL
;
1118 p
= prefix_roota(esp_path
, "/EFI/BOOT");
1121 if (errno
== ENOENT
)
1124 return log_error_errno(errno
, "Failed to open directory \"%s\": %m", p
);
1127 FOREACH_DIRENT(de
, d
, break) {
1128 _cleanup_close_
int fd
= -1;
1129 _cleanup_free_
char *v
= NULL
;
1131 if (!endswith_no_case(de
->d_name
, ".efi"))
1134 if (!startswith_no_case(de
->d_name
, "boot"))
1137 fd
= openat(dirfd(d
), de
->d_name
, O_RDONLY
|O_CLOEXEC
);
1139 return log_error_errno(errno
, "Failed to open \"%s/%s\" for reading: %m", p
, de
->d_name
);
1141 r
= get_file_version(fd
, &v
);
1144 if (r
> 0 && startswith(v
, "systemd-boot ")) {
1145 r
= unlinkat(dirfd(d
), de
->d_name
, 0);
1147 return log_error_errno(errno
, "Failed to remove \"%s/%s\": %m", p
, de
->d_name
);
1149 log_info("Removed \"%s/%s\".", p
, de
->d_name
);
1158 static int rmdir_one(const char *prefix
, const char *suffix
) {
1161 p
= prefix_roota(prefix
, suffix
);
1163 bool ignore
= IN_SET(errno
, ENOENT
, ENOTEMPTY
);
1165 log_full_errno(ignore
? LOG_DEBUG
: LOG_ERR
, errno
,
1166 "Failed to remove directory \"%s\": %m", p
);
1170 log_info("Removed \"%s\".", p
);
1175 static int remove_subdirs(const char *root
, const char *const *subdirs
) {
1178 /* We use recursion here to destroy the directories in reverse order. Which should be safe given how
1179 * short the array is. */
1181 if (!subdirs
[0]) /* A the end of the list */
1184 r
= remove_subdirs(root
, subdirs
+ 1);
1185 q
= rmdir_one(root
, subdirs
[0]);
1187 return r
< 0 ? r
: q
;
1190 static int remove_entry_directory(const char *root
) {
1192 assert(arg_make_entry_directory
>= 0);
1194 if (!arg_make_entry_directory
|| !arg_entry_token
)
1197 return rmdir_one(root
, arg_entry_token
);
1200 static int remove_binaries(const char *esp_path
) {
1204 p
= prefix_roota(esp_path
, "/EFI/systemd");
1205 r
= rm_rf(p
, REMOVE_ROOT
|REMOVE_PHYSICAL
);
1207 q
= remove_boot_efi(esp_path
);
1208 if (q
< 0 && r
== 0)
1214 static int remove_file(const char *root
, const char *file
) {
1220 p
= prefix_roota(root
, file
);
1221 if (unlink(p
) < 0) {
1222 log_full_errno(errno
== ENOENT
? LOG_DEBUG
: LOG_ERR
, errno
,
1223 "Failed to unlink file \"%s\": %m", p
);
1225 return errno
== ENOENT
? 0 : -errno
;
1228 log_info("Removed \"%s\".", p
);
1232 static int remove_variables(sd_id128_t uuid
, const char *path
, bool in_order
) {
1236 if (arg_root
|| !is_efi_boot())
1239 r
= find_slot(uuid
, path
, &slot
);
1243 r
= efi_remove_boot_option(slot
);
1248 return remove_from_order(slot
);
1253 static int remove_loader_variables(void) {
1256 /* Remove all persistent loader variables we define */
1259 EFI_LOADER_VARIABLE(LoaderConfigTimeout
),
1260 EFI_LOADER_VARIABLE(LoaderConfigTimeoutOneShot
),
1261 EFI_LOADER_VARIABLE(LoaderEntryDefault
),
1262 EFI_LOADER_VARIABLE(LoaderEntryOneShot
),
1263 EFI_LOADER_VARIABLE(LoaderSystemToken
)){
1267 q
= efi_set_variable(var
, NULL
, 0);
1271 log_warning_errno(q
, "Failed to remove EFI variable %s: %m", var
);
1275 log_info("Removed EFI variable %s.", var
);
1281 static int install_loader_config(const char *esp_path
) {
1282 _cleanup_(unlink_and_freep
) char *t
= NULL
;
1283 _cleanup_fclose_
FILE *f
= NULL
;
1287 assert(arg_make_entry_directory
>= 0);
1289 p
= prefix_roota(esp_path
, "/loader/loader.conf");
1290 if (access(p
, F_OK
) >= 0) /* Silently skip creation if the file already exists (early check) */
1293 r
= fopen_tmpfile_linkable(p
, O_WRONLY
|O_CLOEXEC
, &t
, &f
);
1295 return log_error_errno(r
, "Failed to open \"%s\" for writing: %m", p
);
1297 fprintf(f
, "#timeout 3\n"
1298 "#console-mode keep\n");
1300 if (arg_make_entry_directory
) {
1301 assert(arg_entry_token
);
1302 fprintf(f
, "default %s-*\n", arg_entry_token
);
1305 r
= flink_tmpfile(f
, t
, p
);
1307 return 0; /* Silently skip creation if the file exists now (recheck) */
1309 return log_error_errno(r
, "Failed to move \"%s\" into place: %m", p
);
1315 static int install_loader_specification(const char *root
) {
1316 _cleanup_(unlink_and_freep
) char *t
= NULL
;
1317 _cleanup_fclose_
FILE *f
= NULL
;
1318 _cleanup_free_
char *p
= NULL
;
1321 p
= path_join(root
, "/loader/entries.srel");
1325 if (access(p
, F_OK
) >= 0) /* Silently skip creation if the file already exists (early check) */
1328 r
= fopen_tmpfile_linkable(p
, O_WRONLY
|O_CLOEXEC
, &t
, &f
);
1330 return log_error_errno(r
, "Failed to open \"%s\" for writing: %m", p
);
1332 fprintf(f
, "type1\n");
1334 r
= flink_tmpfile(f
, t
, p
);
1336 return 0; /* Silently skip creation if the file exists now (recheck) */
1338 return log_error_errno(r
, "Failed to move \"%s\" into place: %m", p
);
1344 static int install_entry_directory(const char *root
) {
1346 assert(arg_make_entry_directory
>= 0);
1348 if (!arg_make_entry_directory
)
1351 assert(arg_entry_token
);
1352 return mkdir_one(root
, arg_entry_token
);
1355 static int install_entry_token(void) {
1358 assert(arg_make_entry_directory
>= 0);
1359 assert(arg_entry_token
);
1361 /* Let's save the used entry token in /etc/kernel/entry-token if we used it to create the entry
1362 * directory, or if anything else but the machine ID */
1364 if (!arg_make_entry_directory
&& arg_entry_token_type
== ARG_ENTRY_TOKEN_MACHINE_ID
)
1367 r
= write_string_file("/etc/kernel/entry-token", arg_entry_token
, WRITE_STRING_FILE_CREATE
|WRITE_STRING_FILE_ATOMIC
|WRITE_STRING_FILE_MKDIR_0755
);
1369 return log_error_errno(r
, "Failed to write entry token '%s' to /etc/kernel/entry-token", arg_entry_token
);
1374 static int help(int argc
, char *argv
[], void *userdata
) {
1375 _cleanup_free_
char *link
= NULL
;
1378 r
= terminal_urlify_man("bootctl", "1", &link
);
1382 printf("%1$s [OPTIONS...] COMMAND ...\n"
1383 "\n%5$sControl EFI firmware boot settings and manage boot loader.%6$s\n"
1384 "\n%3$sGeneric EFI Firmware/Boot Loader Commands:%4$s\n"
1385 " status Show status of installed boot loader and EFI variables\n"
1386 " reboot-to-firmware [BOOL]\n"
1387 " Query or set reboot-to-firmware EFI flag\n"
1388 " systemd-efi-options [STRING]\n"
1389 " Query or set system options string in EFI variable\n"
1390 "\n%3$sBoot Loader Specification Commands:%4$s\n"
1391 " list List boot loader entries\n"
1392 " set-default ID Set default boot loader entry\n"
1393 " set-oneshot ID Set default boot loader entry, for next boot only\n"
1394 " set-timeout SECONDS Set the menu timeout\n"
1395 " set-timeout-oneshot SECONDS\n"
1396 " Set the menu timeout for the next boot only\n"
1397 "\n%3$ssystemd-boot Commands:%4$s\n"
1398 " install Install systemd-boot to the ESP and EFI variables\n"
1399 " update Update systemd-boot in the ESP and EFI variables\n"
1400 " remove Remove systemd-boot from the ESP and EFI variables\n"
1401 " is-installed Test whether systemd-boot is installed in the ESP\n"
1402 " random-seed Initialize random seed in ESP and EFI variables\n"
1403 "\n%3$sOptions:%4$s\n"
1404 " -h --help Show this help\n"
1405 " --version Print version\n"
1406 " --esp-path=PATH Path to the EFI System Partition (ESP)\n"
1407 " --boot-path=PATH Path to the $BOOT partition\n"
1408 " --root=PATH Operate on an alternate filesystem root\n"
1409 " --image=PATH Operate on disk image as filesystem root\n"
1410 " --install-source=auto|image|host\n"
1411 " Where to pick files when using --root=/--image=\n"
1412 " -p --print-esp-path Print path to the EFI System Partition\n"
1413 " -x --print-boot-path Print path to the $BOOT partition\n"
1414 " --no-variables Don't touch EFI variables\n"
1415 " --no-pager Do not pipe output into a pager\n"
1416 " --graceful Don't fail when the ESP cannot be found or EFI\n"
1417 " variables cannot be written\n"
1418 " -q --quiet Suppress output\n"
1419 " --make-entry-directory=yes|no|auto\n"
1420 " Create $BOOT/ENTRY-TOKEN/ directory\n"
1421 " --entry-token=machine-id|os-id|os-image-id|auto|literal:…\n"
1422 " Entry token to use for this installation\n"
1423 " --json=pretty|short|off\n"
1424 " Generate JSON output\n"
1425 " --all-architectures\n"
1426 " Install all supported EFI architectures\n"
1427 "\nSee the %2$s for details.\n",
1428 program_invocation_short_name
,
1438 static int parse_argv(int argc
, char *argv
[]) {
1440 ARG_ESP_PATH
= 0x100,
1449 ARG_MAKE_ENTRY_DIRECTORY
,
1455 static const struct option options
[] = {
1456 { "help", no_argument
, NULL
, 'h' },
1457 { "version", no_argument
, NULL
, ARG_VERSION
},
1458 { "esp-path", required_argument
, NULL
, ARG_ESP_PATH
},
1459 { "path", required_argument
, NULL
, ARG_ESP_PATH
}, /* Compatibility alias */
1460 { "boot-path", required_argument
, NULL
, ARG_BOOT_PATH
},
1461 { "root", required_argument
, NULL
, ARG_ROOT
},
1462 { "image", required_argument
, NULL
, ARG_IMAGE
},
1463 { "install-source", required_argument
, NULL
, ARG_INSTALL_SOURCE
},
1464 { "print-esp-path", no_argument
, NULL
, 'p' },
1465 { "print-path", no_argument
, NULL
, 'p' }, /* Compatibility alias */
1466 { "print-boot-path", no_argument
, NULL
, 'x' },
1467 { "no-variables", no_argument
, NULL
, ARG_NO_VARIABLES
},
1468 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
1469 { "graceful", no_argument
, NULL
, ARG_GRACEFUL
},
1470 { "quiet", no_argument
, NULL
, 'q' },
1471 { "make-entry-directory", required_argument
, NULL
, ARG_MAKE_ENTRY_DIRECTORY
},
1472 { "make-machine-id-directory", required_argument
, NULL
, ARG_MAKE_ENTRY_DIRECTORY
}, /* Compatibility alias */
1473 { "entry-token", required_argument
, NULL
, ARG_ENTRY_TOKEN
},
1474 { "json", required_argument
, NULL
, ARG_JSON
},
1475 { "all-architectures", no_argument
, NULL
, ARG_ARCH_ALL
},
1485 while ((c
= getopt_long(argc
, argv
, "hpx", options
, NULL
)) >= 0)
1489 help(0, NULL
, NULL
);
1496 r
= free_and_strdup(&arg_esp_path
, optarg
);
1502 r
= free_and_strdup(&arg_xbootldr_path
, optarg
);
1508 r
= parse_path_argument(optarg
, /* suppress_root= */ true, &arg_root
);
1514 r
= parse_path_argument(optarg
, /* suppress_root= */ false, &arg_image
);
1519 case ARG_INSTALL_SOURCE
:
1520 if (streq(optarg
, "auto"))
1521 arg_install_source
= ARG_INSTALL_SOURCE_AUTO
;
1522 else if (streq(optarg
, "image"))
1523 arg_install_source
= ARG_INSTALL_SOURCE_IMAGE
;
1524 else if (streq(optarg
, "host"))
1525 arg_install_source
= ARG_INSTALL_SOURCE_HOST
;
1527 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1528 "Unexpected parameter for --install-source=: %s", optarg
);
1533 if (arg_print_dollar_boot_path
)
1534 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1535 "--print-boot-path/-x cannot be combined with --print-esp-path/-p");
1536 arg_print_esp_path
= true;
1540 if (arg_print_esp_path
)
1541 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1542 "--print-boot-path/-x cannot be combined with --print-esp-path/-p");
1543 arg_print_dollar_boot_path
= true;
1546 case ARG_NO_VARIABLES
:
1547 arg_touch_variables
= false;
1551 arg_pager_flags
|= PAGER_DISABLE
;
1555 arg_graceful
= true;
1562 case ARG_ENTRY_TOKEN
: {
1565 if (streq(optarg
, "machine-id")) {
1566 arg_entry_token_type
= ARG_ENTRY_TOKEN_MACHINE_ID
;
1567 arg_entry_token
= mfree(arg_entry_token
);
1568 } else if (streq(optarg
, "os-image-id")) {
1569 arg_entry_token_type
= ARG_ENTRY_TOKEN_OS_IMAGE_ID
;
1570 arg_entry_token
= mfree(arg_entry_token
);
1571 } else if (streq(optarg
, "os-id")) {
1572 arg_entry_token_type
= ARG_ENTRY_TOKEN_OS_ID
;
1573 arg_entry_token
= mfree(arg_entry_token
);
1574 } else if ((e
= startswith(optarg
, "literal:"))) {
1575 arg_entry_token_type
= ARG_ENTRY_TOKEN_LITERAL
;
1577 r
= free_and_strdup_warn(&arg_entry_token
, e
);
1581 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1582 "Unexpected parameter for --entry-token=: %s", optarg
);
1587 case ARG_MAKE_ENTRY_DIRECTORY
:
1588 if (streq(optarg
, "auto")) /* retained for backwards compatibility */
1589 arg_make_entry_directory
= -1; /* yes if machine-id is permanent */
1591 r
= parse_boolean_argument("--make-entry-directory=", optarg
, &b
);
1595 arg_make_entry_directory
= b
;
1600 r
= parse_json_argument(optarg
, &arg_json_format_flags
);
1606 arg_arch_all
= true;
1613 assert_not_reached();
1616 if ((arg_root
|| arg_image
) && argv
[optind
] && !STR_IN_SET(argv
[optind
], "status", "list",
1617 "install", "update", "remove", "is-installed", "random-seed"))
1618 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1619 "Options --root= and --image= are not supported with verb %s.",
1622 if (arg_root
&& arg_image
)
1623 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Please specify either --root= or --image=, the combination of both is not supported.");
1625 if (arg_install_source
!= ARG_INSTALL_SOURCE_AUTO
&& !arg_root
&& !arg_image
)
1626 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "--install-from-host is only supported with --root= or --image=.");
1631 static void read_efi_var(const char *variable
, char **ret
) {
1634 r
= efi_get_variable_string(variable
, ret
);
1635 if (r
< 0 && r
!= -ENOENT
)
1636 log_warning_errno(r
, "Failed to read EFI variable %s: %m", variable
);
1639 static void print_yes_no_line(bool first
, bool good
, const char *name
) {
1641 first
? " Features: " : " ",
1642 COLOR_MARK_BOOL(good
),
1646 static int are_we_installed(const char *esp_path
) {
1649 /* Tests whether systemd-boot is installed. It's not obvious what to use as check here: we could
1650 * check EFI variables, we could check what binary /EFI/BOOT/BOOT*.EFI points to, or whether the
1651 * loader entries directory exists. Here we opted to check whether /EFI/systemd/ is non-empty, which
1652 * should be a suitable and very minimal check for a number of reasons:
1654 * → The check is architecture independent (i.e. we check if any systemd-boot loader is installed,
1655 * not a specific one.)
1657 * → It doesn't assume we are the only boot loader (i.e doesn't check if we own the main
1658 * /EFI/BOOT/BOOT*.EFI fallback binary.
1660 * → It specifically checks for systemd-boot, not for other boot loaders (which a check for
1661 * /boot/loader/entries would do). */
1663 _cleanup_free_
char *p
= path_join(esp_path
, "/EFI/systemd/");
1667 log_debug("Checking whether %s contains any files%s", p
, special_glyph(SPECIAL_GLYPH_ELLIPSIS
));
1668 r
= dir_is_empty(p
, /* ignore_hidden_or_backup= */ false);
1669 if (r
< 0 && r
!= -ENOENT
)
1670 return log_error_errno(r
, "Failed to check whether %s contains any files: %m", p
);
1675 static int verb_status(int argc
, char *argv
[], void *userdata
) {
1676 sd_id128_t esp_uuid
= SD_ID128_NULL
, xbootldr_uuid
= SD_ID128_NULL
;
1677 dev_t esp_devid
= 0, xbootldr_devid
= 0;
1680 r
= acquire_esp(/* unprivileged_mode= */ geteuid() != 0, /* graceful= */ false, NULL
, NULL
, NULL
, &esp_uuid
, &esp_devid
);
1681 if (arg_print_esp_path
) {
1682 if (r
== -EACCES
) /* If we couldn't acquire the ESP path, log about access errors (which is the only
1683 * error the find_esp_and_warn() won't log on its own) */
1684 return log_error_errno(r
, "Failed to determine ESP location: %m");
1691 r
= acquire_xbootldr(/* unprivileged_mode= */ geteuid() != 0, &xbootldr_uuid
, &xbootldr_devid
);
1692 if (arg_print_dollar_boot_path
) {
1694 return log_error_errno(r
, "Failed to determine XBOOTLDR partition: %m");
1698 const char *path
= arg_dollar_boot_path();
1700 return log_error_errno(SYNTHETIC_ERRNO(EACCES
), "Failed to determine XBOOTLDR location: %m");
1705 if (arg_print_esp_path
|| arg_print_dollar_boot_path
)
1708 r
= 0; /* If we couldn't determine the path, then don't consider that a problem from here on, just
1709 * show what we can show */
1711 pager_open(arg_pager_flags
);
1713 if (!arg_root
&& is_efi_boot()) {
1714 static const struct {
1718 { EFI_LOADER_FEATURE_BOOT_COUNTING
, "Boot counting" },
1719 { EFI_LOADER_FEATURE_CONFIG_TIMEOUT
, "Menu timeout control" },
1720 { EFI_LOADER_FEATURE_CONFIG_TIMEOUT_ONE_SHOT
, "One-shot menu timeout control" },
1721 { EFI_LOADER_FEATURE_ENTRY_DEFAULT
, "Default entry control" },
1722 { EFI_LOADER_FEATURE_ENTRY_ONESHOT
, "One-shot entry control" },
1723 { EFI_LOADER_FEATURE_XBOOTLDR
, "Support for XBOOTLDR partition" },
1724 { EFI_LOADER_FEATURE_RANDOM_SEED
, "Support for passing random seed to OS" },
1725 { EFI_LOADER_FEATURE_LOAD_DRIVER
, "Load drop-in drivers" },
1727 _cleanup_free_
char *fw_type
= NULL
, *fw_info
= NULL
, *loader
= NULL
, *loader_path
= NULL
, *stub
= NULL
;
1728 sd_id128_t loader_part_uuid
= SD_ID128_NULL
;
1729 uint64_t loader_features
= 0;
1733 read_efi_var(EFI_LOADER_VARIABLE(LoaderFirmwareType
), &fw_type
);
1734 read_efi_var(EFI_LOADER_VARIABLE(LoaderFirmwareInfo
), &fw_info
);
1735 read_efi_var(EFI_LOADER_VARIABLE(LoaderInfo
), &loader
);
1736 read_efi_var(EFI_LOADER_VARIABLE(StubInfo
), &stub
);
1737 read_efi_var(EFI_LOADER_VARIABLE(LoaderImageIdentifier
), &loader_path
);
1738 (void) efi_loader_get_features(&loader_features
);
1741 efi_tilt_backslashes(loader_path
);
1743 k
= efi_loader_get_device_part_uuid(&loader_part_uuid
);
1744 if (k
< 0 && k
!= -ENOENT
)
1745 r
= log_warning_errno(k
, "Failed to read EFI variable LoaderDevicePartUUID: %m");
1747 SecureBootMode secure
= efi_get_secure_boot_mode();
1748 printf("System:\n");
1749 printf(" Firmware: %s%s (%s)%s\n", ansi_highlight(), strna(fw_type
), strna(fw_info
), ansi_normal());
1750 printf(" Firmware Arch: %s\n", get_efi_arch());
1751 printf(" Secure Boot: %sd (%s)\n",
1752 enable_disable(IN_SET(secure
, SECURE_BOOT_USER
, SECURE_BOOT_DEPLOYED
)),
1753 secure_boot_mode_to_string(secure
));
1756 printf(" TPM2 Support: %s%s%s\n",
1757 FLAGS_SET(s
, TPM2_SUPPORT_FIRMWARE
|TPM2_SUPPORT_DRIVER
) ? ansi_highlight_green() :
1758 (s
& (TPM2_SUPPORT_FIRMWARE
|TPM2_SUPPORT_DRIVER
)) != 0 ? ansi_highlight_red() : ansi_highlight_yellow(),
1759 FLAGS_SET(s
, TPM2_SUPPORT_FIRMWARE
|TPM2_SUPPORT_DRIVER
) ? "yes" :
1760 (s
& TPM2_SUPPORT_FIRMWARE
) ? "firmware only, driver unavailable" :
1761 (s
& TPM2_SUPPORT_DRIVER
) ? "driver only, firmware unavailable" : "no",
1764 k
= efi_get_reboot_to_firmware();
1766 printf(" Boot into FW: %sactive%s\n", ansi_highlight_yellow(), ansi_normal());
1768 printf(" Boot into FW: supported\n");
1769 else if (k
== -EOPNOTSUPP
)
1770 printf(" Boot into FW: not supported\n");
1773 printf(" Boot into FW: %sfailed%s (%m)\n", ansi_highlight_red(), ansi_normal());
1777 printf("Current Boot Loader:\n");
1778 printf(" Product: %s%s%s\n", ansi_highlight(), strna(loader
), ansi_normal());
1780 for (size_t i
= 0; i
< ELEMENTSOF(flags
); i
++)
1781 print_yes_no_line(i
== 0, FLAGS_SET(loader_features
, flags
[i
].flag
), flags
[i
].name
);
1783 sd_id128_t bootloader_esp_uuid
;
1784 bool have_bootloader_esp_uuid
= efi_loader_get_device_part_uuid(&bootloader_esp_uuid
) >= 0;
1786 print_yes_no_line(false, have_bootloader_esp_uuid
, "Boot loader sets ESP information");
1787 if (have_bootloader_esp_uuid
&& !sd_id128_is_null(esp_uuid
) &&
1788 !sd_id128_equal(esp_uuid
, bootloader_esp_uuid
))
1789 printf("WARNING: The boot loader reports a different ESP UUID than detected ("SD_ID128_UUID_FORMAT_STR
" vs. "SD_ID128_UUID_FORMAT_STR
")!\n",
1790 SD_ID128_FORMAT_VAL(bootloader_esp_uuid
),
1791 SD_ID128_FORMAT_VAL(esp_uuid
));
1794 printf(" Stub: %s\n", stub
);
1795 if (!sd_id128_is_null(loader_part_uuid
))
1796 printf(" ESP: /dev/disk/by-partuuid/" SD_ID128_UUID_FORMAT_STR
"\n",
1797 SD_ID128_FORMAT_VAL(loader_part_uuid
));
1799 printf(" ESP: n/a\n");
1800 printf(" File: %s%s\n", special_glyph(SPECIAL_GLYPH_TREE_RIGHT
), strna(loader_path
));
1803 printf("Random Seed:\n");
1804 have
= access(EFIVAR_PATH(EFI_LOADER_VARIABLE(LoaderRandomSeed
)), F_OK
) >= 0;
1805 printf(" Passed to OS: %s\n", yes_no(have
));
1806 have
= access(EFIVAR_PATH(EFI_LOADER_VARIABLE(LoaderSystemToken
)), F_OK
) >= 0;
1807 printf(" System Token: %s\n", have
? "set" : "not set");
1810 _cleanup_free_
char *p
= NULL
;
1812 p
= path_join(arg_esp_path
, "/loader/random-seed");
1816 have
= access(p
, F_OK
) >= 0;
1817 printf(" Exists: %s\n", yes_no(have
));
1822 printf("System:\n Not booted with EFI\n\n");
1825 k
= status_binaries(arg_esp_path
, esp_uuid
);
1830 if (!arg_root
&& is_efi_boot()) {
1831 k
= status_variables();
1836 if (arg_esp_path
|| arg_xbootldr_path
) {
1837 _cleanup_(boot_config_free
) BootConfig config
= BOOT_CONFIG_NULL
;
1839 k
= boot_config_load_and_select(&config
,
1840 arg_esp_path
, esp_devid
,
1841 arg_xbootldr_path
, xbootldr_devid
);
1845 k
= status_entries(&config
,
1846 arg_esp_path
, esp_uuid
,
1847 arg_xbootldr_path
, xbootldr_uuid
);
1856 static int verb_list(int argc
, char *argv
[], void *userdata
) {
1857 _cleanup_(boot_config_free
) BootConfig config
= BOOT_CONFIG_NULL
;
1858 dev_t esp_devid
= 0, xbootldr_devid
= 0;
1861 /* If we lack privileges we invoke find_esp_and_warn() in "unprivileged mode" here, which does two
1862 * things: turn off logging about access errors and turn off potentially privileged device probing.
1863 * Here we're interested in the latter but not the former, hence request the mode, and log about
1866 r
= acquire_esp(/* unprivileged_mode= */ geteuid() != 0, /* graceful= */ false, NULL
, NULL
, NULL
, NULL
, &esp_devid
);
1867 if (r
== -EACCES
) /* We really need the ESP path for this call, hence also log about access errors */
1868 return log_error_errno(r
, "Failed to determine ESP location: %m");
1872 r
= acquire_xbootldr(/* unprivileged_mode= */ geteuid() != 0, NULL
, &xbootldr_devid
);
1874 return log_error_errno(r
, "Failed to determine XBOOTLDR partition: %m");
1878 r
= boot_config_load_and_select(&config
, arg_esp_path
, esp_devid
, arg_xbootldr_path
, xbootldr_devid
);
1882 if (config
.n_entries
== 0 && FLAGS_SET(arg_json_format_flags
, JSON_FORMAT_OFF
)) {
1883 log_info("No boot loader entries found.");
1887 pager_open(arg_pager_flags
);
1888 return show_boot_entries(&config
, arg_json_format_flags
);
1891 static int install_random_seed(const char *esp
) {
1892 _cleanup_(unlink_and_freep
) char *tmp
= NULL
;
1893 _cleanup_free_
void *buffer
= NULL
;
1894 _cleanup_free_
char *path
= NULL
;
1895 _cleanup_close_
int fd
= -1;
1896 size_t sz
, token_size
;
1902 path
= path_join(esp
, "/loader/random-seed");
1906 sz
= random_pool_size();
1908 buffer
= malloc(sz
);
1912 r
= crypto_random_bytes(buffer
, sz
);
1914 return log_error_errno(r
, "Failed to acquire random seed: %m");
1916 /* Normally create_subdirs() should already have created everything we need, but in case "bootctl
1917 * random-seed" is called we want to just create the minimum we need for it, and not the full
1919 r
= mkdir_parents(path
, 0755);
1921 return log_error_errno(r
, "Failed to create parent directory for %s: %m", path
);
1923 r
= tempfn_random(path
, "bootctl", &tmp
);
1927 fd
= open(tmp
, O_CREAT
|O_EXCL
|O_NOFOLLOW
|O_NOCTTY
|O_WRONLY
|O_CLOEXEC
, 0600);
1930 return log_error_errno(fd
, "Failed to open random seed file for writing: %m");
1933 n
= write(fd
, buffer
, sz
);
1935 return log_error_errno(errno
, "Failed to write random seed file: %m");
1936 if ((size_t) n
!= sz
)
1937 return log_error_errno(SYNTHETIC_ERRNO(EIO
), "Short write while writing random seed file.");
1939 if (rename(tmp
, path
) < 0)
1940 return log_error_errno(r
, "Failed to move random seed file into place: %m");
1944 log_info("Random seed file %s successfully written (%zu bytes).", path
, sz
);
1946 if (!arg_touch_variables
)
1949 if (!is_efi_boot()) {
1950 log_notice("Not booted with EFI, skipping EFI variable setup.");
1955 log_warning("Acting on %s, skipping EFI variable setup.",
1956 arg_image
? "image" : "root directory");
1960 r
= getenv_bool("SYSTEMD_WRITE_SYSTEM_TOKEN");
1963 log_warning_errno(r
, "Failed to parse $SYSTEMD_WRITE_SYSTEM_TOKEN, ignoring.");
1965 if (detect_vm() > 0) {
1966 /* Let's not write a system token if we detect we are running in a VM
1967 * environment. Why? Our default security model for the random seed uses the system
1968 * token as a mechanism to ensure we are not vulnerable to golden master sloppiness
1969 * issues, i.e. that people initialize the random seed file, then copy the image to
1970 * many systems and end up with the same random seed in each that is assumed to be
1971 * valid but in reality is the same for all machines. By storing a system token in
1972 * the EFI variable space we can make sure that even though the random seeds on disk
1973 * are all the same they will be different on each system under the assumption that
1974 * the EFI variable space is maintained separate from the random seed storage. That
1975 * is generally the case on physical systems, as the ESP is stored on persistent
1976 * storage, and the EFI variables in NVRAM. However in virtualized environments this
1977 * is generally not true: the EFI variable set is typically stored along with the
1978 * disk image itself. For example, using the OVMF EFI firmware the EFI variables are
1979 * stored in a file in the ESP itself. */
1981 log_notice("Not installing system token, since we are running in a virtualized environment.");
1984 } else if (r
== 0) {
1985 log_notice("Not writing system token, because $SYSTEMD_WRITE_SYSTEM_TOKEN is set to false.");
1989 r
= efi_get_variable(EFI_LOADER_VARIABLE(LoaderSystemToken
), NULL
, NULL
, &token_size
);
1991 log_debug_errno(r
, "LoaderSystemToken EFI variable is invalid (too short?), replacing.");
1994 return log_error_errno(r
, "Failed to test system token validity: %m");
1996 if (token_size
>= sz
) {
1997 /* Let's avoid writes if we can, and initialize this only once. */
1998 log_debug("System token already written, not updating.");
2002 log_debug("Existing system token size (%zu) does not match our expectations (%zu), replacing.", token_size
, sz
);
2005 r
= crypto_random_bytes(buffer
, sz
);
2007 return log_error_errno(r
, "Failed to acquire random seed: %m");
2009 /* Let's write this variable with an umask in effect, so that unprivileged users can't see the token
2010 * and possibly get identification information or too much insight into the kernel's entropy pool
2012 RUN_WITH_UMASK(0077) {
2013 r
= efi_set_variable(EFI_LOADER_VARIABLE(LoaderSystemToken
), buffer
, sz
);
2016 return log_error_errno(r
, "Failed to write 'LoaderSystemToken' EFI variable: %m");
2019 log_warning_errno(r
, "Unable to write 'LoaderSystemToken' EFI variable (firmware problem?), ignoring: %m");
2021 log_warning_errno(r
, "Unable to write 'LoaderSystemToken' EFI variable, ignoring: %m");
2023 log_info("Successfully initialized system token in EFI variable with %zu bytes.", sz
);
2029 static int sync_everything(void) {
2033 k
= syncfs_path(AT_FDCWD
, arg_esp_path
);
2035 ret
= log_error_errno(k
, "Failed to synchronize the ESP '%s': %m", arg_esp_path
);
2038 if (arg_xbootldr_path
) {
2039 k
= syncfs_path(AT_FDCWD
, arg_xbootldr_path
);
2041 ret
= log_error_errno(k
, "Failed to synchronize $BOOT '%s': %m", arg_xbootldr_path
);
2047 static int verb_install(int argc
, char *argv
[], void *userdata
) {
2048 sd_id128_t uuid
= SD_ID128_NULL
;
2049 uint64_t pstart
= 0, psize
= 0;
2051 bool install
, graceful
;
2054 /* Invoked for both "update" and "install" */
2056 install
= streq(argv
[0], "install");
2057 graceful
= !install
&& arg_graceful
; /* support graceful mode for updates */
2059 r
= acquire_esp(/* unprivileged_mode= */ false, graceful
, &part
, &pstart
, &psize
, &uuid
, NULL
);
2060 if (graceful
&& r
== -ENOKEY
)
2061 return 0; /* If --graceful is specified and we can't find an ESP, handle this cleanly */
2066 /* If we are updating, don't do anything if sd-boot wasn't actually installed. */
2067 r
= are_we_installed(arg_esp_path
);
2071 log_debug("Skipping update because sd-boot is not installed in the ESP.");
2076 r
= acquire_xbootldr(/* unprivileged_mode= */ false, NULL
, NULL
);
2080 r
= settle_make_entry_directory();
2084 const char *arch
= arg_arch_all
? "" : get_efi_arch();
2086 RUN_WITH_UMASK(0002) {
2088 /* Don't create any of these directories when we are just updating. When we update
2089 * we'll drop-in our files (unless there are newer ones already), but we won't create
2090 * the directories for them in the first place. */
2091 r
= create_subdirs(arg_esp_path
, esp_subdirs
);
2095 r
= create_subdirs(arg_dollar_boot_path(), dollar_boot_subdirs
);
2100 r
= install_binaries(arg_esp_path
, arch
, install
);
2105 r
= install_loader_config(arg_esp_path
);
2109 r
= install_entry_directory(arg_dollar_boot_path());
2113 r
= install_entry_token();
2117 r
= install_random_seed(arg_esp_path
);
2122 r
= install_loader_specification(arg_dollar_boot_path());
2127 (void) sync_everything();
2129 if (!arg_touch_variables
)
2133 log_info("Not changing EFI variables with --all-architectures.");
2137 char *path
= strjoina("/EFI/systemd/systemd-boot", arch
, ".efi");
2138 return install_variables(arg_esp_path
, part
, pstart
, psize
, uuid
, path
, install
);
2141 static int verb_remove(int argc
, char *argv
[], void *userdata
) {
2142 sd_id128_t uuid
= SD_ID128_NULL
;
2145 r
= acquire_esp(/* unprivileged_mode= */ false, /* graceful= */ false, NULL
, NULL
, NULL
, &uuid
, NULL
);
2149 r
= acquire_xbootldr(/* unprivileged_mode= */ false, NULL
, NULL
);
2153 r
= settle_make_entry_directory();
2157 r
= remove_binaries(arg_esp_path
);
2159 q
= remove_file(arg_esp_path
, "/loader/loader.conf");
2160 if (q
< 0 && r
>= 0)
2163 q
= remove_file(arg_esp_path
, "/loader/random-seed");
2164 if (q
< 0 && r
>= 0)
2167 q
= remove_file(arg_esp_path
, "/loader/entries.srel");
2168 if (q
< 0 && r
>= 0)
2171 q
= remove_subdirs(arg_esp_path
, esp_subdirs
);
2172 if (q
< 0 && r
>= 0)
2175 q
= remove_subdirs(arg_esp_path
, dollar_boot_subdirs
);
2176 if (q
< 0 && r
>= 0)
2179 q
= remove_entry_directory(arg_esp_path
);
2180 if (q
< 0 && r
>= 0)
2183 if (arg_xbootldr_path
) {
2184 /* Remove a subset of these also from the XBOOTLDR partition if it exists */
2186 q
= remove_file(arg_xbootldr_path
, "/loader/entries.srel");
2187 if (q
< 0 && r
>= 0)
2190 q
= remove_subdirs(arg_xbootldr_path
, dollar_boot_subdirs
);
2191 if (q
< 0 && r
>= 0)
2194 q
= remove_entry_directory(arg_xbootldr_path
);
2195 if (q
< 0 && r
>= 0)
2199 (void) sync_everything();
2201 if (!arg_touch_variables
)
2205 log_info("Not changing EFI variables with --all-architectures.");
2209 char *path
= strjoina("/EFI/systemd/systemd-boot", get_efi_arch(), ".efi");
2210 q
= remove_variables(uuid
, path
, true);
2211 if (q
< 0 && r
>= 0)
2214 q
= remove_loader_variables();
2215 if (q
< 0 && r
>= 0)
2221 static int verb_is_installed(int argc
, char *argv
[], void *userdata
) {
2224 r
= acquire_esp(/* privileged_mode= */ false,
2225 /* graceful= */ arg_graceful
,
2226 NULL
, NULL
, NULL
, NULL
, NULL
);
2230 r
= are_we_installed(arg_esp_path
);
2237 return EXIT_SUCCESS
;
2241 return EXIT_FAILURE
;
2245 static int parse_timeout(const char *arg1
, char16_t
**ret_timeout
, size_t *ret_timeout_size
) {
2246 char utf8
[DECIMAL_STR_MAX(usec_t
)];
2252 assert(ret_timeout
);
2253 assert(ret_timeout_size
);
2255 if (streq(arg1
, "menu-force"))
2256 timeout
= USEC_INFINITY
;
2257 else if (streq(arg1
, "menu-hidden"))
2260 r
= parse_time(arg1
, &timeout
, USEC_PER_SEC
);
2262 return log_error_errno(r
, "Failed to parse timeout '%s': %m", arg1
);
2263 if (timeout
!= USEC_INFINITY
&& timeout
> UINT32_MAX
* USEC_PER_SEC
)
2264 log_warning("Timeout is too long and will be treated as 'menu-force' instead.");
2267 xsprintf(utf8
, USEC_FMT
, MIN(timeout
/ USEC_PER_SEC
, UINT32_MAX
));
2269 encoded
= utf8_to_utf16(utf8
, strlen(utf8
));
2273 *ret_timeout
= encoded
;
2274 *ret_timeout_size
= char16_strlen(encoded
) * 2 + 2;
2278 static int parse_loader_entry_target_arg(const char *arg1
, char16_t
**ret_target
, size_t *ret_target_size
) {
2279 char16_t
*encoded
= NULL
;
2284 assert(ret_target_size
);
2286 if (streq(arg1
, "@current")) {
2287 r
= efi_get_variable(EFI_LOADER_VARIABLE(LoaderEntrySelected
), NULL
, (void *) ret_target
, ret_target_size
);
2289 return log_error_errno(r
, "Failed to get EFI variable 'LoaderEntrySelected': %m");
2291 } else if (streq(arg1
, "@oneshot")) {
2292 r
= efi_get_variable(EFI_LOADER_VARIABLE(LoaderEntryOneShot
), NULL
, (void *) ret_target
, ret_target_size
);
2294 return log_error_errno(r
, "Failed to get EFI variable 'LoaderEntryOneShot': %m");
2296 } else if (streq(arg1
, "@default")) {
2297 r
= efi_get_variable(EFI_LOADER_VARIABLE(LoaderEntryDefault
), NULL
, (void *) ret_target
, ret_target_size
);
2299 return log_error_errno(r
, "Failed to get EFI variable 'LoaderEntryDefault': %m");
2301 } else if (arg1
[0] == '@' && !streq(arg1
, "@saved"))
2302 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Unsupported special entry identifier: %s", arg1
);
2304 encoded
= utf8_to_utf16(arg1
, strlen(arg1
));
2308 *ret_target
= encoded
;
2309 *ret_target_size
= char16_strlen(encoded
) * 2 + 2;
2315 static int verb_set_efivar(int argc
, char *argv
[], void *userdata
) {
2319 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
),
2320 "Acting on %s, skipping EFI variable setup.",
2321 arg_image
? "image" : "root directory");
2324 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
),
2325 "Not booted with UEFI.");
2327 if (access(EFIVAR_PATH(EFI_LOADER_VARIABLE(LoaderInfo
)), F_OK
) < 0) {
2328 if (errno
== ENOENT
) {
2329 log_error_errno(errno
, "Not booted with a supported boot loader.");
2333 return log_error_errno(errno
, "Failed to detect whether boot loader supports '%s' operation: %m", argv
[0]);
2336 if (detect_container() > 0)
2337 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
),
2338 "'%s' operation not supported in a container.",
2341 if (!arg_touch_variables
)
2342 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
2343 "'%s' operation cannot be combined with --no-variables.",
2346 const char *variable
;
2347 int (* arg_parser
)(const char *, char16_t
**, size_t *);
2349 if (streq(argv
[0], "set-default")) {
2350 variable
= EFI_LOADER_VARIABLE(LoaderEntryDefault
);
2351 arg_parser
= parse_loader_entry_target_arg
;
2352 } else if (streq(argv
[0], "set-oneshot")) {
2353 variable
= EFI_LOADER_VARIABLE(LoaderEntryOneShot
);
2354 arg_parser
= parse_loader_entry_target_arg
;
2355 } else if (streq(argv
[0], "set-timeout")) {
2356 variable
= EFI_LOADER_VARIABLE(LoaderConfigTimeout
);
2357 arg_parser
= parse_timeout
;
2358 } else if (streq(argv
[0], "set-timeout-oneshot")) {
2359 variable
= EFI_LOADER_VARIABLE(LoaderConfigTimeoutOneShot
);
2360 arg_parser
= parse_timeout
;
2362 assert_not_reached();
2364 if (isempty(argv
[1])) {
2365 r
= efi_set_variable(variable
, NULL
, 0);
2366 if (r
< 0 && r
!= -ENOENT
)
2367 return log_error_errno(r
, "Failed to remove EFI variable '%s': %m", variable
);
2369 _cleanup_free_ char16_t
*value
= NULL
;
2370 size_t value_size
= 0;
2372 r
= arg_parser(argv
[1], &value
, &value_size
);
2375 r
= efi_set_variable(variable
, value
, value_size
);
2377 return log_error_errno(r
, "Failed to update EFI variable '%s': %m", variable
);
2383 static int verb_random_seed(int argc
, char *argv
[], void *userdata
) {
2386 r
= find_esp_and_warn(arg_root
, arg_esp_path
, false, &arg_esp_path
, NULL
, NULL
, NULL
, NULL
, NULL
);
2388 /* find_esp_and_warn() doesn't warn about ENOKEY, so let's do that on our own */
2390 return log_error_errno(r
, "Unable to find ESP.");
2392 log_notice("No ESP found, not initializing random seed.");
2398 r
= install_random_seed(arg_esp_path
);
2402 (void) sync_everything();
2406 static int verb_systemd_efi_options(int argc
, char *argv
[], void *userdata
) {
2410 _cleanup_free_
char *line
= NULL
, *new = NULL
;
2412 r
= systemd_efi_options_variable(&line
);
2414 log_debug("No SystemdOptions EFI variable present in cache.");
2416 return log_error_errno(r
, "Failed to read SystemdOptions EFI variable from cache: %m");
2420 r
= systemd_efi_options_efivarfs_if_newer(&new);
2421 if (r
== -ENODATA
) {
2423 log_notice("Note: SystemdOptions EFI variable has been removed since boot.");
2425 log_warning_errno(r
, "Failed to check SystemdOptions EFI variable in efivarfs, ignoring: %m");
2426 else if (new && !streq_ptr(line
, new))
2427 log_notice("Note: SystemdOptions EFI variable has been modified since boot. New value: %s",
2430 r
= efi_set_variable_string(EFI_SYSTEMD_VARIABLE(SystemdOptions
), argv
[1]);
2432 return log_error_errno(r
, "Failed to set SystemdOptions EFI variable: %m");
2438 static int verb_reboot_to_firmware(int argc
, char *argv
[], void *userdata
) {
2442 r
= efi_get_reboot_to_firmware();
2445 return EXIT_SUCCESS
; /* success */
2449 return 1; /* recognizable error #1 */
2451 if (r
== -EOPNOTSUPP
) {
2452 puts("not supported");
2453 return 2; /* recognizable error #2 */
2456 log_error_errno(r
, "Failed to query reboot-to-firmware state: %m");
2457 return 3; /* other kind of error */
2459 r
= parse_boolean(argv
[1]);
2461 return log_error_errno(r
, "Failed to parse argument: %s", argv
[1]);
2463 r
= efi_set_reboot_to_firmware(r
);
2465 return log_error_errno(r
, "Failed to set reboot-to-firmware option: %m");
2471 static int bootctl_main(int argc
, char *argv
[]) {
2472 static const Verb verbs
[] = {
2473 { "help", VERB_ANY
, VERB_ANY
, 0, help
},
2474 { "status", VERB_ANY
, 1, VERB_DEFAULT
, verb_status
},
2475 { "install", VERB_ANY
, 1, 0, verb_install
},
2476 { "update", VERB_ANY
, 1, 0, verb_install
},
2477 { "remove", VERB_ANY
, 1, 0, verb_remove
},
2478 { "is-installed", VERB_ANY
, 1, 0, verb_is_installed
},
2479 { "list", VERB_ANY
, 1, 0, verb_list
},
2480 { "set-default", 2, 2, 0, verb_set_efivar
},
2481 { "set-oneshot", 2, 2, 0, verb_set_efivar
},
2482 { "set-timeout", 2, 2, 0, verb_set_efivar
},
2483 { "set-timeout-oneshot", 2, 2, 0, verb_set_efivar
},
2484 { "random-seed", VERB_ANY
, 1, 0, verb_random_seed
},
2485 { "systemd-efi-options", VERB_ANY
, 2, 0, verb_systemd_efi_options
},
2486 { "reboot-to-firmware", VERB_ANY
, 2, 0, verb_reboot_to_firmware
},
2490 return dispatch_verb(argc
, argv
, verbs
, NULL
);
2493 static int run(int argc
, char *argv
[]) {
2494 _cleanup_(loop_device_unrefp
) LoopDevice
*loop_device
= NULL
;
2495 _cleanup_(decrypted_image_unrefp
) DecryptedImage
*decrypted_image
= NULL
;
2496 _cleanup_(umount_and_rmdir_and_freep
) char *unlink_dir
= NULL
;
2499 log_parse_environment();
2502 /* If we run in a container, automatically turn off EFI file system access */
2503 if (detect_container() > 0)
2504 arg_touch_variables
= false;
2506 r
= parse_argv(argc
, argv
);
2510 /* Open up and mount the image */
2514 r
= mount_image_privately_interactively(
2516 DISSECT_IMAGE_GENERIC_ROOT
|
2517 DISSECT_IMAGE_RELAX_VAR_CHECK
,
2524 arg_root
= strdup(unlink_dir
);
2529 return bootctl_main(argc
, argv
);
2532 DEFINE_MAIN_FUNCTION_WITH_POSITIVE_FAILURE(run
);