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"
42 #include "dirent-util.h"
46 #include "locale-util.h"
48 #include "string-util.h"
51 static int verify_esp(const char *p
, uint32_t *part
, uint64_t *pstart
, uint64_t *psize
, sd_id128_t
*uuid
) {
54 _cleanup_free_
char *t
= NULL
;
55 _cleanup_blkid_free_probe_ blkid_probe b
= NULL
;
59 if (statfs(p
, &sfs
) < 0)
60 return log_error_errno(errno
, "Failed to check file system type of \"%s\": %m", p
);
62 if (sfs
.f_type
!= 0x4d44) {
63 log_error("File system \"%s\" is not a FAT EFI System Partition (ESP) file system.", p
);
68 return log_error_errno(errno
, "Failed to determine block device node of \"%s\": %m", p
);
70 if (major(st
.st_dev
) == 0) {
71 log_error("Block device node of %p is invalid.", p
);
75 t2
= strjoina(p
, "/..");
78 return log_error_errno(errno
, "Failed to determine block device node of parent of \"%s\": %m", p
);
80 if (st
.st_dev
== st2
.st_dev
) {
81 log_error("Directory \"%s\" is not the root of the EFI System Partition (ESP) file system.", p
);
85 r
= asprintf(&t
, "/dev/block/%u:%u", major(st
.st_dev
), minor(st
.st_dev
));
90 b
= blkid_new_probe_from_filename(t
);
95 return log_error_errno(errno
, "Failed to open file system \"%s\": %m", p
);
98 blkid_probe_enable_superblocks(b
, 1);
99 blkid_probe_set_superblocks_flags(b
, BLKID_SUBLKS_TYPE
);
100 blkid_probe_enable_partitions(b
, 1);
101 blkid_probe_set_partitions_flags(b
, BLKID_PARTS_ENTRY_DETAILS
);
104 r
= blkid_do_safeprobe(b
);
106 log_error("File system \"%s\" is ambigious.", p
);
109 log_error("File system \"%s\" does not contain a label.", p
);
112 r
= errno
? -errno
: -EIO
;
113 return log_error_errno(r
, "Failed to probe file system \"%s\": %m", p
);
117 r
= blkid_probe_lookup_value(b
, "TYPE", &v
, NULL
);
119 r
= errno
? -errno
: -EIO
;
120 return log_error_errno(r
, "Failed to probe file system type \"%s\": %m", p
);
123 if (!streq(v
, "vfat")) {
124 log_error("File system \"%s\" is not FAT.", p
);
129 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_SCHEME", &v
, NULL
);
131 r
= errno
? -errno
: -EIO
;
132 return log_error_errno(r
, "Failed to probe partition scheme \"%s\": %m", p
);
135 if (!streq(v
, "gpt")) {
136 log_error("File system \"%s\" is not on a GPT partition table.", p
);
141 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_TYPE", &v
, NULL
);
143 r
= errno
? -errno
: -EIO
;
144 return log_error_errno(r
, "Failed to probe partition type UUID \"%s\": %m", p
);
147 if (!streq(v
, "c12a7328-f81f-11d2-ba4b-00a0c93ec93b")) {
148 log_error("File system \"%s\" has wrong type for an EFI System Partition (ESP).", p
);
153 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_UUID", &v
, NULL
);
155 r
= errno
? -errno
: -EIO
;
156 return log_error_errno(r
, "Failed to probe partition entry UUID \"%s\": %m", p
);
159 r
= sd_id128_from_string(v
, uuid
);
161 log_error("Partition \"%s\" has invalid UUID \"%s\".", p
, v
);
166 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_NUMBER", &v
, NULL
);
168 r
= errno
? -errno
: -EIO
;
169 return log_error_errno(r
, "Failed to probe partition number \"%s\": m", p
);
171 *part
= strtoul(v
, NULL
, 10);
174 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_OFFSET", &v
, NULL
);
176 r
= errno
? -errno
: -EIO
;
177 return log_error_errno(r
, "Failed to probe partition offset \"%s\": %m", p
);
179 *pstart
= strtoul(v
, NULL
, 10);
182 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_SIZE", &v
, NULL
);
184 r
= errno
? -errno
: -EIO
;
185 return log_error_errno(r
, "Failed to probe partition size \"%s\": %m", p
);
187 *psize
= strtoul(v
, NULL
, 10);
192 /* search for "#### LoaderInfo: systemd-boot 218 ####" string inside the binary */
193 static int get_file_version(int fd
, char **v
) {
203 if (fstat(fd
, &st
) < 0)
209 buf
= mmap(NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0);
210 if (buf
== MAP_FAILED
)
213 s
= memmem(buf
, st
.st_size
- 8, "#### LoaderInfo: ", 17);
218 e
= memmem(s
, st
.st_size
- (s
- buf
), " ####", 5);
219 if (!e
|| e
- s
< 3) {
220 log_error("Malformed version string.");
225 x
= strndup(s
, e
- s
);
233 munmap(buf
, st
.st_size
);
238 static int enumerate_binaries(const char *esp_path
, const char *path
, const char *prefix
) {
240 _cleanup_closedir_
DIR *d
= NULL
;
244 p
= strjoina(esp_path
, "/", path
);
250 return log_error_errno(errno
, "Failed to read \"%s\": %m", p
);
253 FOREACH_DIRENT(de
, d
, break) {
254 _cleanup_close_
int fd
= -1;
255 _cleanup_free_
char *v
= NULL
;
257 if (!endswith_no_case(de
->d_name
, ".efi"))
260 if (prefix
&& !startswith_no_case(de
->d_name
, prefix
))
263 fd
= openat(dirfd(d
), de
->d_name
, O_RDONLY
|O_CLOEXEC
);
265 return log_error_errno(errno
, "Failed to open \"%s/%s\" for reading: %m", p
, de
->d_name
);
267 r
= get_file_version(fd
, &v
);
271 printf(" File: %s/%s/%s (%s)\n", draw_special_char(DRAW_TREE_RIGHT
), path
, de
->d_name
, v
);
273 printf(" File: %s/%s/%s\n", draw_special_char(DRAW_TREE_RIGHT
), path
, de
->d_name
);
280 static int status_binaries(const char *esp_path
, sd_id128_t partition
) {
283 printf("Boot Loader Binaries:\n");
285 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
));
287 r
= enumerate_binaries(esp_path
, "EFI/systemd", NULL
);
289 log_error("systemd-boot not installed in ESP.");
293 r
= enumerate_binaries(esp_path
, "EFI/Boot", "boot");
295 log_error("No default/fallback boot loader installed in ESP.");
304 static int print_efi_option(uint16_t id
, bool in_order
) {
305 _cleanup_free_
char *title
= NULL
;
306 _cleanup_free_
char *path
= NULL
;
307 sd_id128_t partition
;
311 r
= efi_get_boot_option(id
, &title
, &partition
, &path
, &active
);
315 /* print only configured entries with partition information */
316 if (!path
|| sd_id128_equal(partition
, SD_ID128_NULL
))
319 efi_tilt_backslashes(path
);
321 printf(" Title: %s\n", strna(title
));
322 printf(" ID: 0x%04X\n", id
);
323 printf(" Status: %sactive%s\n", active
? "" : "in", in_order
? ", boot-order" : "");
324 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
));
325 printf(" File: %s%s\n", draw_special_char(DRAW_TREE_RIGHT
), path
);
331 static int status_variables(void) {
332 int n_options
, n_order
;
333 _cleanup_free_
uint16_t *options
= NULL
, *order
= NULL
;
336 if (!is_efi_boot()) {
337 log_notice("Not booted with EFI, not showing EFI variables.");
341 n_options
= efi_get_boot_options(&options
);
342 if (n_options
== -ENOENT
)
343 return log_error_errno(ENOENT
, "Failed to access EFI variables, efivarfs"
344 " needs to be available at /sys/firmware/efi/efivars/.");
345 else if (n_options
< 0)
346 return log_error_errno(n_options
, "Failed to read EFI boot entries: %m");
348 n_order
= efi_get_boot_order(&order
);
349 if (n_order
== -ENOENT
)
351 else if (n_order
< 0)
352 return log_error_errno(n_order
, "Failed to read EFI boot order.");
354 /* print entries in BootOrder first */
355 printf("Boot Loader Entries in EFI Variables:\n");
356 for (i
= 0; i
< n_order
; i
++)
357 print_efi_option(order
[i
], true);
359 /* print remaining entries */
360 for (i
= 0; i
< n_options
; i
++) {
363 for (j
= 0; j
< n_order
; j
++)
364 if (options
[i
] == order
[j
])
367 print_efi_option(options
[i
], false);
375 static int compare_product(const char *a
, const char *b
) {
384 return x
< y
? -1 : x
> y
? 1 : 0;
386 return strncmp(a
, b
, x
);
389 static int compare_version(const char *a
, const char *b
) {
393 a
+= strcspn(a
, " ");
395 b
+= strcspn(b
, " ");
398 return strverscmp(a
, b
);
401 static int version_check(int fd
, const char *from
, const char *to
) {
402 _cleanup_free_
char *a
= NULL
, *b
= NULL
;
403 _cleanup_close_
int fd2
= -1;
410 r
= get_file_version(fd
, &a
);
414 log_error("Source file \"%s\" does not carry version information!", from
);
418 fd2
= open(to
, O_RDONLY
|O_CLOEXEC
);
423 return log_error_errno(errno
, "Failed to open \"%s\" for reading: %m", to
);
426 r
= get_file_version(fd2
, &b
);
429 if (r
== 0 || compare_product(a
, b
) != 0) {
430 log_notice("Skipping \"%s\", since it's owned by another boot loader.", to
);
434 if (compare_version(a
, b
) < 0) {
435 log_warning("Skipping \"%s\", since a newer boot loader version exists already.", to
);
442 static int copy_file(const char *from
, const char *to
, bool force
) {
443 _cleanup_fclose_
FILE *f
= NULL
, *g
= NULL
;
446 struct timespec t
[2];
452 f
= fopen(from
, "re");
454 return log_error_errno(errno
, "Failed to open \"%s\" for reading: %m", from
);
457 /* If this is an update, then let's compare versions first */
458 r
= version_check(fileno(f
), from
, to
);
463 p
= strjoina(to
, "~");
466 /* Directory doesn't exist yet? Then let's skip this... */
467 if (!force
&& errno
== ENOENT
)
470 return log_error_errno(errno
, "Failed to open \"%s\" for writing: %m", to
);
476 uint8_t buf
[32*1024];
478 k
= fread(buf
, 1, sizeof(buf
), f
);
480 r
= log_error_errno(EIO
, "Failed to read \"%s\": %m", from
);
487 fwrite(buf
, 1, k
, g
);
489 r
= log_error_errno(EIO
, "Failed to write \"%s\": %m", to
);
494 r
= fflush_and_check(g
);
496 log_error_errno(r
, "Failed to write \"%s\": %m", to
);
500 r
= fstat(fileno(f
), &st
);
502 r
= log_error_errno(errno
, "Failed to get file timestamps of \"%s\": %m", from
);
509 r
= futimens(fileno(g
), t
);
511 r
= log_error_errno(errno
, "Failed to set file timestamps on \"%s\": %m", p
);
515 if (rename(p
, to
) < 0) {
516 r
= log_error_errno(errno
, "Failed to rename \"%s\" to \"%s\": %m", p
, to
);
520 log_info("Copied \"%s\" to \"%s\".", from
, to
);
528 static char* strupper(char *s
) {
537 static int mkdir_one(const char *prefix
, const char *suffix
) {
540 p
= strjoina(prefix
, "/", suffix
);
541 if (mkdir(p
, 0700) < 0) {
543 return log_error_errno(errno
, "Failed to create \"%s\": %m", p
);
545 log_info("Created \"%s\".", p
);
550 static const char *efi_subdirs
[] = {
558 static int create_dirs(const char *esp_path
) {
562 for (i
= 0; i
< ELEMENTSOF(efi_subdirs
); i
++) {
563 r
= mkdir_one(esp_path
, efi_subdirs
[i
]);
571 static int copy_one_file(const char *esp_path
, const char *name
, bool force
) {
575 p
= strjoina(BOOTLIBDIR
"/", name
);
576 q
= strjoina(esp_path
, "/EFI/systemd/", name
);
577 r
= copy_file(p
, q
, force
);
579 if (startswith(name
, "systemd-boot")) {
583 /* Create the EFI default boot loader name (specified for removable devices) */
584 v
= strjoina(esp_path
, "/EFI/Boot/BOOT", name
+ strlen("systemd-boot"));
585 strupper(strrchr(v
, '/') + 1);
587 k
= copy_file(p
, v
, force
);
595 static int install_binaries(const char *esp_path
, bool force
) {
597 _cleanup_closedir_
DIR *d
= NULL
;
601 /* Don't create any of these directories when we are
602 * just updating. When we update we'll drop-in our
603 * files (unless there are newer ones already), but we
604 * won't create the directories for them in the first
606 r
= create_dirs(esp_path
);
611 d
= opendir(BOOTLIBDIR
);
613 return log_error_errno(errno
, "Failed to open \""BOOTLIBDIR
"\": %m
");
615 FOREACH_DIRENT(de, d, break) {
618 if (!endswith_no_case(de->d_name, ".efi
"))
621 k = copy_one_file(esp_path, de->d_name, force);
629 static bool same_entry(uint16_t id, const sd_id128_t uuid, const char *path) {
630 _cleanup_free_ char *opath = NULL;
634 r = efi_get_boot_option(id, NULL, &ouuid, &opath, NULL);
637 if (!sd_id128_equal(uuid, ouuid))
639 if (!streq_ptr(path, opath))
645 static int find_slot(sd_id128_t uuid, const char *path, uint16_t *id) {
646 _cleanup_free_ uint16_t *options = NULL;
649 n = efi_get_boot_options(&options);
653 /* find already existing systemd-boot entry */
654 for (i = 0; i < n; i++)
655 if (same_entry(options[i], uuid, path)) {
660 /* find free slot in the sorted BootXXXX variable list */
661 for (i = 0; i < n; i++)
662 if (i != options[i]) {
667 /* use the next one */
674 static int insert_into_order(uint16_t slot, bool first) {
675 _cleanup_free_ uint16_t *order = NULL;
679 n = efi_get_boot_order(&order);
681 /* no entry, add us */
682 return efi_set_boot_order(&slot, 1);
684 /* are we the first and only one? */
685 if (n == 1 && order[0] == slot)
688 /* are we already in the boot order? */
689 for (i = 0; i < n; i++) {
690 if (order[i] != slot)
693 /* we do not require to be the first one, all is fine */
697 /* move us to the first slot */
698 memmove(order + 1, order, i * sizeof(uint16_t));
700 return efi_set_boot_order(order, n);
704 t = realloc(order, (n + 1) * sizeof(uint16_t));
709 /* add us to the top or end of the list */
711 memmove(order + 1, order, n * sizeof(uint16_t));
716 return efi_set_boot_order(order, n + 1);
719 static int remove_from_order(uint16_t slot) {
720 _cleanup_free_ uint16_t *order = NULL;
723 n = efi_get_boot_order(&order);
727 for (i = 0; i < n; i++) {
728 if (order[i] != slot)
732 memmove(order + i, order + i+1, (n - i) * sizeof(uint16_t));
733 return efi_set_boot_order(order, n - 1);
739 static int install_variables(const char *esp_path,
740 uint32_t part, uint64_t pstart, uint64_t psize,
741 sd_id128_t uuid, const char *path,
747 if (!is_efi_boot()) {
748 log_warning("Not booted with EFI
, skipping EFI variable setup
.");
752 p = strjoina(esp_path, path);
753 if (access(p, F_OK) < 0) {
757 return log_error_errno(errno, "Cannot access
\"%s
\": %m
", p);
760 r = find_slot(uuid, path, &slot);
762 return log_error_errno(r,
764 "Failed to access EFI variables
. Is the
\"efivarfs
\" filesystem mounted
?" :
765 "Failed to determine current boot order
: %m
");
767 if (first || r == false) {
768 r = efi_add_boot_option(slot, "Linux Boot Manager
",
772 return log_error_errno(r, "Failed to create EFI Boot variable entry
: %m
");
774 log_info("Created EFI boot entry
\"Linux Boot Manager
\".");
777 return insert_into_order(slot, first);
780 static int remove_boot_efi(const char *esp_path) {
782 _cleanup_closedir_ DIR *d = NULL;
786 p = strjoina(esp_path, "/EFI
/Boot
");
792 return log_error_errno(errno, "Failed to open directory
\"%s
\": %m
", p);
795 FOREACH_DIRENT(de, d, break) {
796 _cleanup_close_ int fd = -1;
797 _cleanup_free_ char *v = NULL;
799 if (!endswith_no_case(de->d_name, ".efi
"))
802 if (!startswith_no_case(de->d_name, "Boot
"))
805 fd = openat(dirfd(d), de->d_name, O_RDONLY|O_CLOEXEC);
807 return log_error_errno(errno, "Failed to open
\"%s
/%s
\" for reading
: %m
", p, de->d_name);
809 r = get_file_version(fd, &v);
812 if (r > 0 && startswith(v, "systemd
-boot
")) {
813 r = unlinkat(dirfd(d), de->d_name, 0);
815 return log_error_errno(errno, "Failed to remove
\"%s
/%s
\": %m
", p, de->d_name);
817 log_info("Removed
\"%s
/%s
\".", p, de->d_name);
826 static int rmdir_one(const char *prefix, const char *suffix) {
829 p = strjoina(prefix, "/", suffix);
831 if (!IN_SET(errno, ENOENT, ENOTEMPTY))
832 return log_error_errno(errno, "Failed to remove
\"%s
\": %m
", p);
834 log_info("Removed
\"%s
\".", p);
839 static int remove_binaries(const char *esp_path) {
844 p = strjoina(esp_path, "/EFI
/systemd
");
845 r = rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL);
847 q = remove_boot_efi(esp_path);
851 for (i = ELEMENTSOF(efi_subdirs); i > 0; i--) {
852 q = rmdir_one(esp_path, efi_subdirs[i-1]);
860 static int remove_variables(sd_id128_t uuid, const char *path, bool in_order) {
867 r = find_slot(uuid, path, &slot);
871 r = efi_remove_boot_option(slot);
876 return remove_from_order(slot);
881 static int install_loader_config(const char *esp_path) {
884 char *machine = NULL;
885 _cleanup_fclose_ FILE *f = NULL, *g = NULL;
887 f = fopen("/etc
/machine
-id
", "re
");
889 return errno == ENOENT ? 0 : -errno;
891 if (fgets(line, sizeof(line), f) != NULL) {
894 s = strchr(line, '\n');
897 if (strlen(line) == 32)
904 p = strjoina(esp_path, "/loader
/loader
.conf
");
907 fprintf(g, "#timeout 3\n");
908 fprintf(g, "default %s-*\n", machine);
910 return log_error_errno(EIO, "Failed to write \"%s\": %m", p);
916 static int help(void) {
917 printf("%s [COMMAND] [OPTIONS...]\n"
919 "Install, update or remove the systemd-boot EFI boot manager.\n\n"
920 " -h --help Show this help\n"
921 " --version Print version\n"
922 " --path=PATH Path to the EFI System Partition (ESP)\n"
923 " --no-variables Don't touch EFI variables\n"
926 " status Show status of installed systemd-boot and EFI variables\n"
927 " install Install systemd-boot to the ESP and EFI variables\n"
928 " update Update systemd-boot in the ESP and EFI variables\n"
929 " remove Remove systemd-boot from the ESP and EFI variables\n",
930 program_invocation_short_name);
935 static const char *arg_path = "/boot";
936 static bool arg_touch_variables = true;
938 static int parse_argv(int argc, char *argv[]) {
945 static const struct option options[] = {
946 { "help", no_argument, NULL, 'h' },
947 { "version", no_argument, NULL, ARG_VERSION },
948 { "path", required_argument, NULL, ARG_PATH },
949 { "no-variables", no_argument, NULL, ARG_NO_VARIABLES },
958 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
972 case ARG_NO_VARIABLES:
973 arg_touch_variables = false;
980 assert_not_reached("Unknown option");
986 static void read_loader_efi_var(const char *name, char **var) {
989 r = efi_get_variable_string(EFI_VENDOR_LOADER, name, var);
990 if (r < 0 && r != -ENOENT)
991 log_warning_errno(r, "Failed to read EFI variable %s: %m", name);
994 static int bootctl_main(int argc, char*argv[]) {
1000 } arg_action = ACTION_STATUS;
1001 static const struct {
1005 { "status", ACTION_STATUS },
1006 { "install", ACTION_INSTALL },
1007 { "update", ACTION_UPDATE },
1008 { "remove", ACTION_REMOVE },
1011 sd_id128_t uuid = {};
1013 uint64_t pstart = 0, psize = 0;
1019 for (i = 0; i < ELEMENTSOF(verbs); i++) {
1020 if (!streq(argv[optind], verbs[i].verb))
1022 arg_action = verbs[i].action;
1025 if (i >= ELEMENTSOF(verbs)) {
1026 log_error("Unknown operation \"%s\"", argv[optind]);
1032 return log_error_errno(EPERM, "Need to be root.");
1034 r = verify_esp(arg_path, &part, &pstart, &psize, &uuid);
1035 if (r == -ENODEV && !arg_path)
1036 log_notice("You might want to use --path= to indicate the path to your ESP, in case it is not mounted on /boot.");
1040 switch (arg_action) {
1041 case ACTION_STATUS: {
1042 _cleanup_free_ char *fw_type = NULL;
1043 _cleanup_free_ char *fw_info = NULL;
1044 _cleanup_free_ char *loader = NULL;
1045 _cleanup_free_ char *loader_path = NULL;
1046 sd_id128_t loader_part_uuid = {};
1048 if (is_efi_boot()) {
1049 read_loader_efi_var("LoaderFirmwareType", &fw_type);
1050 read_loader_efi_var("LoaderFirmwareInfo", &fw_info);
1051 read_loader_efi_var("LoaderInfo", &loader);
1052 read_loader_efi_var("LoaderImageIdentifier", &loader_path);
1054 efi_tilt_backslashes(loader_path);
1055 r = efi_loader_get_device_part_uuid(&loader_part_uuid);
1056 if (r < 0 && r == -ENOENT)
1057 log_warning_errno(r, "Failed to read EFI variable LoaderDevicePartUUID: %m");
1059 printf("System:\n");
1060 printf(" Firmware: %s (%s)\n", strna(fw_type), strna(fw_info));
1062 r = is_efi_secure_boot();
1064 log_warning_errno(r, "Failed to query secure boot status: %m");
1066 printf(" Secure Boot: %s\n", r ? "enabled" : "disabled");
1068 r = is_efi_secure_boot_setup_mode();
1070 log_warning_errno(r, "Failed to query secure boot mode: %m");
1072 printf(" Setup Mode: %s\n", r ? "setup" : "user");
1075 printf("Loader:\n");
1076 printf(" Product: %s\n", strna(loader));
1077 if (!sd_id128_equal(loader_part_uuid, SD_ID128_NULL))
1078 printf(" Partition: /dev/disk/by-partuuid/%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
1079 SD_ID128_FORMAT_VAL(loader_part_uuid));
1081 printf(" Partition: n/a\n");
1082 printf(" File: %s%s\n", draw_special_char(DRAW_TREE_RIGHT), strna(loader_path));
1085 printf("System:\n Not booted with EFI\n");
1087 r = status_binaries(arg_path, uuid);
1091 if (arg_touch_variables)
1092 r = status_variables();
1096 case ACTION_INSTALL:
1100 r = install_binaries(arg_path, arg_action == ACTION_INSTALL);
1104 if (arg_action == ACTION_INSTALL) {
1105 r = install_loader_config(arg_path);
1110 if (arg_touch_variables)
1111 r = install_variables(arg_path,
1112 part, pstart, psize, uuid,
1113 "/EFI/systemd/systemd-boot" EFI_MACHINE_TYPE_NAME ".efi",
1114 arg_action == ACTION_INSTALL);
1118 r = remove_binaries(arg_path);
1120 if (arg_touch_variables) {
1121 q = remove_variables(uuid, "/EFI/systemd/systemd-boot" EFI_MACHINE_TYPE_NAME ".efi", true);
1122 if (q < 0 && r == 0)
1131 int main(int argc, char *argv[]) {
1134 log_parse_environment();
1137 r = parse_argv(argc, argv);
1141 r = bootctl_main(argc, argv);
1144 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;