1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013-2015 Kay Sievers
7 Copyright 2013 Lennart Poettering
9 systemd is free software; you can redistribute it and/or modify it
10 under the terms of the GNU Lesser General Public License as published by
11 the Free Software Foundation; either version 2.1 of the License, or
12 (at your option) any later version.
14 systemd is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Lesser General Public License for more details.
19 You should have received a copy of the GNU Lesser General Public License
20 along with systemd; If not, see <http://www.gnu.org/licenses/>.
24 #include <blkid/blkid.h>
37 #include <sys/statfs.h>
40 #include "alloc-util.h"
41 #include "blkid-util.h"
45 #include "locale-util.h"
47 #include "string-util.h"
50 static int verify_esp(const char *p
, uint32_t *part
, uint64_t *pstart
, uint64_t *psize
, sd_id128_t
*uuid
) {
53 _cleanup_free_
char *t
= NULL
;
54 _cleanup_blkid_free_probe_ blkid_probe b
= NULL
;
58 if (statfs(p
, &sfs
) < 0)
59 return log_error_errno(errno
, "Failed to check file system type of \"%s\": %m", p
);
61 if (sfs
.f_type
!= 0x4d44) {
62 log_error("File system \"%s\" is not a FAT EFI System Partition (ESP) file system.", p
);
67 return log_error_errno(errno
, "Failed to determine block device node of \"%s\": %m", p
);
69 if (major(st
.st_dev
) == 0) {
70 log_error("Block device node of %p is invalid.", p
);
74 t2
= strjoina(p
, "/..");
77 return log_error_errno(errno
, "Failed to determine block device node of parent of \"%s\": %m", p
);
79 if (st
.st_dev
== st2
.st_dev
) {
80 log_error("Directory \"%s\" is not the root of the EFI System Partition (ESP) file system.", p
);
84 r
= asprintf(&t
, "/dev/block/%u:%u", major(st
.st_dev
), minor(st
.st_dev
));
89 b
= blkid_new_probe_from_filename(t
);
94 return log_error_errno(errno
, "Failed to open file system \"%s\": %m", p
);
97 blkid_probe_enable_superblocks(b
, 1);
98 blkid_probe_set_superblocks_flags(b
, BLKID_SUBLKS_TYPE
);
99 blkid_probe_enable_partitions(b
, 1);
100 blkid_probe_set_partitions_flags(b
, BLKID_PARTS_ENTRY_DETAILS
);
103 r
= blkid_do_safeprobe(b
);
105 log_error("File system \"%s\" is ambigious.", p
);
108 log_error("File system \"%s\" does not contain a label.", p
);
111 r
= errno
? -errno
: -EIO
;
112 return log_error_errno(r
, "Failed to probe file system \"%s\": %m", p
);
116 r
= blkid_probe_lookup_value(b
, "TYPE", &v
, NULL
);
118 r
= errno
? -errno
: -EIO
;
119 return log_error_errno(r
, "Failed to probe file system type \"%s\": %m", p
);
122 if (!streq(v
, "vfat")) {
123 log_error("File system \"%s\" is not FAT.", p
);
128 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_SCHEME", &v
, NULL
);
130 r
= errno
? -errno
: -EIO
;
131 return log_error_errno(r
, "Failed to probe partition scheme \"%s\": %m", p
);
134 if (!streq(v
, "gpt")) {
135 log_error("File system \"%s\" is not on a GPT partition table.", p
);
140 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_TYPE", &v
, NULL
);
142 r
= errno
? -errno
: -EIO
;
143 return log_error_errno(r
, "Failed to probe partition type UUID \"%s\": %m", p
);
146 if (!streq(v
, "c12a7328-f81f-11d2-ba4b-00a0c93ec93b")) {
147 log_error("File system \"%s\" has wrong type for an EFI System Partition (ESP).", p
);
152 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_UUID", &v
, NULL
);
154 r
= errno
? -errno
: -EIO
;
155 return log_error_errno(r
, "Failed to probe partition entry UUID \"%s\": %m", p
);
158 r
= sd_id128_from_string(v
, uuid
);
160 log_error("Partition \"%s\" has invalid UUID \"%s\".", p
, v
);
165 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_NUMBER", &v
, NULL
);
167 r
= errno
? -errno
: -EIO
;
168 return log_error_errno(r
, "Failed to probe partition number \"%s\": m", p
);
170 *part
= strtoul(v
, NULL
, 10);
173 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_OFFSET", &v
, NULL
);
175 r
= errno
? -errno
: -EIO
;
176 return log_error_errno(r
, "Failed to probe partition offset \"%s\": %m", p
);
178 *pstart
= strtoul(v
, NULL
, 10);
181 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_SIZE", &v
, NULL
);
183 r
= errno
? -errno
: -EIO
;
184 return log_error_errno(r
, "Failed to probe partition size \"%s\": %m", p
);
186 *psize
= strtoul(v
, NULL
, 10);
191 /* search for "#### LoaderInfo: systemd-boot 218 ####" string inside the binary */
192 static int get_file_version(int fd
, char **v
) {
202 if (fstat(fd
, &st
) < 0)
208 buf
= mmap(NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0);
209 if (buf
== MAP_FAILED
)
212 s
= memmem(buf
, st
.st_size
- 8, "#### LoaderInfo: ", 17);
217 e
= memmem(s
, st
.st_size
- (s
- buf
), " ####", 5);
218 if (!e
|| e
- s
< 3) {
219 log_error("Malformed version string.");
224 x
= strndup(s
, e
- s
);
232 munmap(buf
, st
.st_size
);
237 static int enumerate_binaries(const char *esp_path
, const char *path
, const char *prefix
) {
239 _cleanup_closedir_
DIR *d
= NULL
;
243 p
= strjoina(esp_path
, "/", path
);
249 return log_error_errno(errno
, "Failed to read \"%s\": %m", p
);
252 while ((de
= readdir(d
))) {
253 _cleanup_close_
int fd
= -1;
254 _cleanup_free_
char *v
= NULL
;
256 if (de
->d_name
[0] == '.')
259 if (!endswith_no_case(de
->d_name
, ".efi"))
262 if (prefix
&& !startswith_no_case(de
->d_name
, prefix
))
265 fd
= openat(dirfd(d
), de
->d_name
, O_RDONLY
|O_CLOEXEC
);
267 return log_error_errno(errno
, "Failed to open \"%s/%s\" for reading: %m", p
, de
->d_name
);
269 r
= get_file_version(fd
, &v
);
273 printf(" File: %s/%s/%s (%s)\n", draw_special_char(DRAW_TREE_RIGHT
), path
, de
->d_name
, v
);
275 printf(" File: %s/%s/%s\n", draw_special_char(DRAW_TREE_RIGHT
), path
, de
->d_name
);
282 static int status_binaries(const char *esp_path
, sd_id128_t partition
) {
285 printf("Boot Loader Binaries:\n");
287 printf(" ESP: /dev/disk/by-partuuid/%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n", SD_ID128_FORMAT_VAL(partition
));
289 r
= enumerate_binaries(esp_path
, "EFI/systemd", NULL
);
291 log_error("systemd-boot not installed in ESP.");
295 r
= enumerate_binaries(esp_path
, "EFI/Boot", "boot");
297 log_error("No default/fallback boot loader installed in ESP.");
306 static int print_efi_option(uint16_t id
, bool in_order
) {
307 _cleanup_free_
char *title
= NULL
;
308 _cleanup_free_
char *path
= NULL
;
309 sd_id128_t partition
;
313 r
= efi_get_boot_option(id
, &title
, &partition
, &path
, &active
);
317 /* print only configured entries with partition information */
318 if (!path
|| sd_id128_equal(partition
, SD_ID128_NULL
))
321 efi_tilt_backslashes(path
);
323 printf(" Title: %s\n", strna(title
));
324 printf(" ID: 0x%04X\n", id
);
325 printf(" Status: %sactive%s\n", active
? "" : "in", in_order
? ", boot-order" : "");
326 printf(" Partition: /dev/disk/by-partuuid/%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n", SD_ID128_FORMAT_VAL(partition
));
327 printf(" File: %s%s\n", draw_special_char(DRAW_TREE_RIGHT
), path
);
333 static int status_variables(void) {
334 int n_options
, n_order
;
335 _cleanup_free_
uint16_t *options
= NULL
, *order
= NULL
;
338 if (!is_efi_boot()) {
339 log_notice("Not booted with EFI, not showing EFI variables.");
343 n_options
= efi_get_boot_options(&options
);
344 if (n_options
== -ENOENT
)
345 return log_error_errno(ENOENT
, "Failed to access EFI variables, efivarfs"
346 " needs to be available at /sys/firmware/efi/efivars/.");
347 else if (n_options
< 0)
348 return log_error_errno(n_options
, "Failed to read EFI boot entries: %m");
350 n_order
= efi_get_boot_order(&order
);
351 if (n_order
== -ENOENT
)
353 else if (n_order
< 0)
354 return log_error_errno(n_order
, "Failed to read EFI boot order.");
356 /* print entries in BootOrder first */
357 printf("Boot Loader Entries in EFI Variables:\n");
358 for (i
= 0; i
< n_order
; i
++)
359 print_efi_option(order
[i
], true);
361 /* print remaining entries */
362 for (i
= 0; i
< n_options
; i
++) {
365 for (j
= 0; j
< n_order
; j
++)
366 if (options
[i
] == order
[j
])
369 print_efi_option(options
[i
], false);
377 static int compare_product(const char *a
, const char *b
) {
386 return x
< y
? -1 : x
> y
? 1 : 0;
388 return strncmp(a
, b
, x
);
391 static int compare_version(const char *a
, const char *b
) {
395 a
+= strcspn(a
, " ");
397 b
+= strcspn(b
, " ");
400 return strverscmp(a
, b
);
403 static int version_check(int fd
, const char *from
, const char *to
) {
404 _cleanup_free_
char *a
= NULL
, *b
= NULL
;
405 _cleanup_close_
int fd2
= -1;
412 r
= get_file_version(fd
, &a
);
416 log_error("Source file \"%s\" does not carry version information!", from
);
420 fd2
= open(to
, O_RDONLY
|O_CLOEXEC
);
425 return log_error_errno(errno
, "Failed to open \"%s\" for reading: %m", to
);
428 r
= get_file_version(fd2
, &b
);
431 if (r
== 0 || compare_product(a
, b
) != 0) {
432 log_notice("Skipping \"%s\", since it's owned by another boot loader.", to
);
436 if (compare_version(a
, b
) < 0) {
437 log_warning("Skipping \"%s\", since a newer boot loader version exists already.", to
);
444 static int copy_file(const char *from
, const char *to
, bool force
) {
445 _cleanup_fclose_
FILE *f
= NULL
, *g
= NULL
;
448 struct timespec t
[2];
454 f
= fopen(from
, "re");
456 return log_error_errno(errno
, "Failed to open \"%s\" for reading: %m", from
);
459 /* If this is an update, then let's compare versions first */
460 r
= version_check(fileno(f
), from
, to
);
465 p
= strjoina(to
, "~");
468 /* Directory doesn't exist yet? Then let's skip this... */
469 if (!force
&& errno
== ENOENT
)
472 return log_error_errno(errno
, "Failed to open \"%s\" for writing: %m", to
);
478 uint8_t buf
[32*1024];
480 k
= fread(buf
, 1, sizeof(buf
), f
);
482 r
= log_error_errno(EIO
, "Failed to read \"%s\": %m", from
);
489 fwrite(buf
, 1, k
, g
);
491 r
= log_error_errno(EIO
, "Failed to write \"%s\": %m", to
);
496 r
= fflush_and_check(g
);
498 log_error_errno(r
, "Failed to write \"%s\": %m", to
);
502 r
= fstat(fileno(f
), &st
);
504 r
= log_error_errno(errno
, "Failed to get file timestamps of \"%s\": %m", from
);
511 r
= futimens(fileno(g
), t
);
513 r
= log_error_errno(errno
, "Failed to set file timestamps on \"%s\": %m", p
);
517 if (rename(p
, to
) < 0) {
518 r
= log_error_errno(errno
, "Failed to rename \"%s\" to \"%s\": %m", p
, to
);
522 log_info("Copied \"%s\" to \"%s\".", from
, to
);
530 static char* strupper(char *s
) {
539 static int mkdir_one(const char *prefix
, const char *suffix
) {
542 p
= strjoina(prefix
, "/", suffix
);
543 if (mkdir(p
, 0700) < 0) {
545 return log_error_errno(errno
, "Failed to create \"%s\": %m", p
);
547 log_info("Created \"%s\".", p
);
552 static const char *efi_subdirs
[] = {
560 static int create_dirs(const char *esp_path
) {
564 for (i
= 0; i
< ELEMENTSOF(efi_subdirs
); i
++) {
565 r
= mkdir_one(esp_path
, efi_subdirs
[i
]);
573 static int copy_one_file(const char *esp_path
, const char *name
, bool force
) {
577 p
= strjoina(BOOTLIBDIR
"/", name
);
578 q
= strjoina(esp_path
, "/EFI/systemd/", name
);
579 r
= copy_file(p
, q
, force
);
581 if (startswith(name
, "systemd-boot")) {
585 /* Create the EFI default boot loader name (specified for removable devices) */
586 v
= strjoina(esp_path
, "/EFI/Boot/BOOT", name
+ strlen("systemd-boot"));
587 strupper(strrchr(v
, '/') + 1);
589 k
= copy_file(p
, v
, force
);
597 static int install_binaries(const char *esp_path
, bool force
) {
599 _cleanup_closedir_
DIR *d
= NULL
;
603 /* Don't create any of these directories when we are
604 * just updating. When we update we'll drop-in our
605 * files (unless there are newer ones already), but we
606 * won't create the directories for them in the first
608 r
= create_dirs(esp_path
);
613 d
= opendir(BOOTLIBDIR
);
615 return log_error_errno(errno
, "Failed to open \""BOOTLIBDIR
"\": %m
");
617 while ((de = readdir(d))) {
620 if (de->d_name[0] == '.')
623 if (!endswith_no_case(de->d_name, ".efi
"))
626 k = copy_one_file(esp_path, de->d_name, force);
634 static bool same_entry(uint16_t id, const sd_id128_t uuid, const char *path) {
635 _cleanup_free_ char *opath = NULL;
639 r = efi_get_boot_option(id, NULL, &ouuid, &opath, NULL);
642 if (!sd_id128_equal(uuid, ouuid))
644 if (!streq_ptr(path, opath))
650 static int find_slot(sd_id128_t uuid, const char *path, uint16_t *id) {
651 _cleanup_free_ uint16_t *options = NULL;
654 n = efi_get_boot_options(&options);
658 /* find already existing systemd-boot entry */
659 for (i = 0; i < n; i++)
660 if (same_entry(options[i], uuid, path)) {
665 /* find free slot in the sorted BootXXXX variable list */
666 for (i = 0; i < n; i++)
667 if (i != options[i]) {
672 /* use the next one */
679 static int insert_into_order(uint16_t slot, bool first) {
680 _cleanup_free_ uint16_t *order = NULL;
684 n = efi_get_boot_order(&order);
686 /* no entry, add us */
687 return efi_set_boot_order(&slot, 1);
689 /* are we the first and only one? */
690 if (n == 1 && order[0] == slot)
693 /* are we already in the boot order? */
694 for (i = 0; i < n; i++) {
695 if (order[i] != slot)
698 /* we do not require to be the first one, all is fine */
702 /* move us to the first slot */
703 memmove(order + 1, order, i * sizeof(uint16_t));
705 return efi_set_boot_order(order, n);
709 t = realloc(order, (n + 1) * sizeof(uint16_t));
714 /* add us to the top or end of the list */
716 memmove(order + 1, order, n * sizeof(uint16_t));
721 return efi_set_boot_order(order, n + 1);
724 static int remove_from_order(uint16_t slot) {
725 _cleanup_free_ uint16_t *order = NULL;
728 n = efi_get_boot_order(&order);
732 for (i = 0; i < n; i++) {
733 if (order[i] != slot)
737 memmove(order + i, order + i+1, (n - i) * sizeof(uint16_t));
738 return efi_set_boot_order(order, n - 1);
744 static int install_variables(const char *esp_path,
745 uint32_t part, uint64_t pstart, uint64_t psize,
746 sd_id128_t uuid, const char *path,
752 if (!is_efi_boot()) {
753 log_warning("Not booted with EFI
, skipping EFI variable setup
.");
757 p = strjoina(esp_path, path);
758 if (access(p, F_OK) < 0) {
762 return log_error_errno(errno, "Cannot access
\"%s
\": %m
", p);
765 r = find_slot(uuid, path, &slot);
767 return log_error_errno(r,
769 "Failed to access EFI variables
. Is the
\"efivarfs
\" filesystem mounted
?" :
770 "Failed to determine current boot order
: %m
");
772 if (first || r == false) {
773 r = efi_add_boot_option(slot, "Linux Boot Manager
",
777 return log_error_errno(r, "Failed to create EFI Boot variable entry
: %m
");
779 log_info("Created EFI boot entry
\"Linux Boot Manager
\".");
782 return insert_into_order(slot, first);
785 static int remove_boot_efi(const char *esp_path) {
787 _cleanup_closedir_ DIR *d = NULL;
791 p = strjoina(esp_path, "/EFI
/Boot
");
797 return log_error_errno(errno, "Failed to open directory
\"%s
\": %m
", p);
800 while ((de = readdir(d))) {
801 _cleanup_close_ int fd = -1;
802 _cleanup_free_ char *v = NULL;
804 if (de->d_name[0] == '.')
807 if (!endswith_no_case(de->d_name, ".efi
"))
810 if (!startswith_no_case(de->d_name, "Boot
"))
813 fd = openat(dirfd(d), de->d_name, O_RDONLY|O_CLOEXEC);
815 return log_error_errno(errno, "Failed to open
\"%s
/%s
\" for reading
: %m
", p, de->d_name);
817 r = get_file_version(fd, &v);
820 if (r > 0 && startswith(v, "systemd
-boot
")) {
821 r = unlinkat(dirfd(d), de->d_name, 0);
823 return log_error_errno(errno, "Failed to remove
\"%s
/%s
\": %m
", p, de->d_name);
825 log_info("Removed
\"%s
/%s
\".", p, de->d_name);
834 static int rmdir_one(const char *prefix, const char *suffix) {
837 p = strjoina(prefix, "/", suffix);
839 if (!IN_SET(errno, ENOENT, ENOTEMPTY))
840 return log_error_errno(errno, "Failed to remove
\"%s
\": %m
", p);
842 log_info("Removed
\"%s
\".", p);
847 static int remove_binaries(const char *esp_path) {
852 p = strjoina(esp_path, "/EFI
/systemd
");
853 r = rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL);
855 q = remove_boot_efi(esp_path);
859 for (i = ELEMENTSOF(efi_subdirs); i > 0; i--) {
860 q = rmdir_one(esp_path, efi_subdirs[i-1]);
868 static int remove_variables(sd_id128_t uuid, const char *path, bool in_order) {
875 r = find_slot(uuid, path, &slot);
879 r = efi_remove_boot_option(slot);
884 return remove_from_order(slot);
889 static int install_loader_config(const char *esp_path) {
892 char *machine = NULL;
893 _cleanup_fclose_ FILE *f = NULL, *g = NULL;
895 f = fopen("/etc
/machine
-id
", "re
");
897 return errno == ENOENT ? 0 : -errno;
899 if (fgets(line, sizeof(line), f) != NULL) {
902 s = strchr(line, '\n');
905 if (strlen(line) == 32)
912 p = strjoina(esp_path, "/loader
/loader
.conf
");
915 fprintf(g, "#timeout 3\n");
916 fprintf(g, "default %s-*\n", machine);
918 return log_error_errno(EIO, "Failed to write \"%s\": %m", p);
924 static int help(void) {
925 printf("%s [COMMAND] [OPTIONS...]\n"
927 "Install, update or remove the systemd-boot EFI boot manager.\n\n"
928 " -h --help Show this help\n"
929 " --version Print version\n"
930 " --path=PATH Path to the EFI System Partition (ESP)\n"
931 " --no-variables Don't touch EFI variables\n"
934 " status Show status of installed systemd-boot and EFI variables\n"
935 " install Install systemd-boot to the ESP and EFI variables\n"
936 " update Update systemd-boot in the ESP and EFI variables\n"
937 " remove Remove systemd-boot from the ESP and EFI variables\n",
938 program_invocation_short_name);
943 static const char *arg_path = "/boot";
944 static bool arg_touch_variables = true;
946 static int parse_argv(int argc, char *argv[]) {
953 static const struct option options[] = {
954 { "help", no_argument, NULL, 'h' },
955 { "version", no_argument, NULL, ARG_VERSION },
956 { "path", required_argument, NULL, ARG_PATH },
957 { "no-variables", no_argument, NULL, ARG_NO_VARIABLES },
966 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
980 case ARG_NO_VARIABLES:
981 arg_touch_variables = false;
988 assert_not_reached("Unknown option");
994 static void read_loader_efi_var(const char *name, char **var) {
997 r = efi_get_variable_string(EFI_VENDOR_LOADER, name, var);
998 if (r < 0 && r != -ENOENT)
999 log_warning_errno(r, "Failed to read EFI variable %s: %m", name);
1002 static int bootctl_main(int argc, char*argv[]) {
1008 } arg_action = ACTION_STATUS;
1009 static const struct {
1013 { "status", ACTION_STATUS },
1014 { "install", ACTION_INSTALL },
1015 { "update", ACTION_UPDATE },
1016 { "remove", ACTION_REMOVE },
1019 sd_id128_t uuid = {};
1021 uint64_t pstart = 0, psize = 0;
1027 for (i = 0; i < ELEMENTSOF(verbs); i++) {
1028 if (!streq(argv[optind], verbs[i].verb))
1030 arg_action = verbs[i].action;
1033 if (i >= ELEMENTSOF(verbs)) {
1034 log_error("Unknown operation \"%s\"", argv[optind]);
1040 return log_error_errno(EPERM, "Need to be root.");
1042 r = verify_esp(arg_path, &part, &pstart, &psize, &uuid);
1043 if (r == -ENODEV && !arg_path)
1044 log_notice("You might want to use --path= to indicate the path to your ESP, in case it is not mounted on /boot.");
1048 switch (arg_action) {
1049 case ACTION_STATUS: {
1050 _cleanup_free_ char *fw_type = NULL;
1051 _cleanup_free_ char *fw_info = NULL;
1052 _cleanup_free_ char *loader = NULL;
1053 _cleanup_free_ char *loader_path = NULL;
1054 sd_id128_t loader_part_uuid = {};
1056 if (is_efi_boot()) {
1057 read_loader_efi_var("LoaderFirmwareType", &fw_type);
1058 read_loader_efi_var("LoaderFirmwareInfo", &fw_info);
1059 read_loader_efi_var("LoaderInfo", &loader);
1060 read_loader_efi_var("LoaderImageIdentifier", &loader_path);
1062 efi_tilt_backslashes(loader_path);
1063 r = efi_loader_get_device_part_uuid(&loader_part_uuid);
1064 if (r < 0 && r == -ENOENT)
1065 log_warning_errno(r, "Failed to read EFI variable LoaderDevicePartUUID: %m");
1067 printf("System:\n");
1068 printf(" Firmware: %s (%s)\n", strna(fw_type), strna(fw_info));
1070 r = is_efi_secure_boot();
1072 log_warning_errno(r, "Failed to query secure boot status: %m");
1074 printf(" Secure Boot: %s\n", r ? "enabled" : "disabled");
1076 r = is_efi_secure_boot_setup_mode();
1078 log_warning_errno(r, "Failed to query secure boot mode: %m");
1080 printf(" Setup Mode: %s\n", r ? "setup" : "user");
1083 printf("Loader:\n");
1084 printf(" Product: %s\n", strna(loader));
1085 if (!sd_id128_equal(loader_part_uuid, SD_ID128_NULL))
1086 printf(" Partition: /dev/disk/by-partuuid/%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
1087 SD_ID128_FORMAT_VAL(loader_part_uuid));
1089 printf(" Partition: n/a\n");
1090 printf(" File: %s%s\n", draw_special_char(DRAW_TREE_RIGHT), strna(loader_path));
1093 printf("System:\n Not booted with EFI\n");
1095 r = status_binaries(arg_path, uuid);
1099 if (arg_touch_variables)
1100 r = status_variables();
1104 case ACTION_INSTALL:
1108 r = install_binaries(arg_path, arg_action == ACTION_INSTALL);
1112 if (arg_action == ACTION_INSTALL) {
1113 r = install_loader_config(arg_path);
1118 if (arg_touch_variables)
1119 r = install_variables(arg_path,
1120 part, pstart, psize, uuid,
1121 "/EFI/systemd/systemd-boot" EFI_MACHINE_TYPE_NAME ".efi",
1122 arg_action == ACTION_INSTALL);
1126 r = remove_binaries(arg_path);
1128 if (arg_touch_variables) {
1129 q = remove_variables(uuid, "/EFI/systemd/systemd-boot" EFI_MACHINE_TYPE_NAME ".efi", true);
1130 if (q < 0 && r == 0)
1139 int main(int argc, char *argv[]) {
1142 log_parse_environment();
1145 r = parse_argv(argc, argv);
1149 r = bootctl_main(argc, argv);
1152 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;