]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/boot/bootctl.c
pkgconfig: define variables relative to ${prefix}/${rootprefix}/${sysconfdir}
[thirdparty/systemd.git] / src / boot / bootctl.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #include <blkid.h>
4 #include <ctype.h>
5 #include <dirent.h>
6 #include <errno.h>
7 #include <ftw.h>
8 #include <getopt.h>
9 #include <limits.h>
10 #include <linux/magic.h>
11 #include <stdbool.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <sys/mman.h>
16 #include <sys/stat.h>
17 #include <sys/statfs.h>
18 #include <unistd.h>
19
20 #include "sd-id128.h"
21
22 #include "alloc-util.h"
23 #include "blkid-util.h"
24 #include "bootspec.h"
25 #include "copy.h"
26 #include "dirent-util.h"
27 #include "efivars.h"
28 #include "fd-util.h"
29 #include "fileio.h"
30 #include "fs-util.h"
31 #include "locale-util.h"
32 #include "pager.h"
33 #include "parse-util.h"
34 #include "rm-rf.h"
35 #include "stat-util.h"
36 #include "string-util.h"
37 #include "strv.h"
38 #include "terminal-util.h"
39 #include "umask-util.h"
40 #include "utf8.h"
41 #include "util.h"
42 #include "verbs.h"
43 #include "virt.h"
44
45 static char *arg_path = NULL;
46 static bool arg_print_path = false;
47 static bool arg_touch_variables = true;
48 static PagerFlags arg_pager_flags = 0;
49
50 static int acquire_esp(
51 bool unprivileged_mode,
52 uint32_t *ret_part,
53 uint64_t *ret_pstart,
54 uint64_t *ret_psize,
55 sd_id128_t *ret_uuid) {
56
57 char *np;
58 int r;
59
60 /* Find the ESP, and log about errors. Note that find_esp_and_warn() will log in all error cases on its own,
61 * except for ENOKEY (which is good, we want to show our own message in that case, suggesting use of --path=)
62 * and EACCESS (only when we request unprivileged mode; in this case we simply eat up the error here, so that
63 * --list and --status work too, without noise about this). */
64
65 r = find_esp_and_warn(arg_path, unprivileged_mode, &np, ret_part, ret_pstart, ret_psize, ret_uuid);
66 if (r == -ENOKEY)
67 return log_error_errno(r,
68 "Couldn't find EFI system partition. It is recommended to mount it to /boot or /efi.\n"
69 "Alternatively, use --path= to specify path to mount point.");
70 if (r < 0)
71 return r;
72
73 free_and_replace(arg_path, np);
74
75 log_debug("Using EFI System Partition at %s.", arg_path);
76
77 return 0;
78 }
79
80 /* search for "#### LoaderInfo: systemd-boot 218 ####" string inside the binary */
81 static int get_file_version(int fd, char **v) {
82 struct stat st;
83 char *buf;
84 const char *s, *e;
85 char *x = NULL;
86 int r = 0;
87
88 assert(fd >= 0);
89 assert(v);
90
91 if (fstat(fd, &st) < 0)
92 return log_error_errno(errno, "Failed to stat EFI binary: %m");
93
94 if (st.st_size < 27) {
95 *v = NULL;
96 return 0;
97 }
98
99 buf = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
100 if (buf == MAP_FAILED)
101 return log_error_errno(errno, "Failed to memory map EFI binary: %m");
102
103 s = memmem(buf, st.st_size - 8, "#### LoaderInfo: ", 17);
104 if (!s)
105 goto finish;
106 s += 17;
107
108 e = memmem(s, st.st_size - (s - buf), " ####", 5);
109 if (!e || e - s < 3) {
110 log_error("Malformed version string.");
111 r = -EINVAL;
112 goto finish;
113 }
114
115 x = strndup(s, e - s);
116 if (!x) {
117 r = log_oom();
118 goto finish;
119 }
120 r = 1;
121
122 finish:
123 (void) munmap(buf, st.st_size);
124 *v = x;
125 return r;
126 }
127
128 static int enumerate_binaries(const char *esp_path, const char *path, const char *prefix) {
129 char *p;
130 _cleanup_closedir_ DIR *d = NULL;
131 struct dirent *de;
132 int r = 0, c = 0;
133
134 p = strjoina(esp_path, "/", path);
135 d = opendir(p);
136 if (!d) {
137 if (errno == ENOENT)
138 return 0;
139
140 return log_error_errno(errno, "Failed to read \"%s\": %m", p);
141 }
142
143 FOREACH_DIRENT(de, d, break) {
144 _cleanup_close_ int fd = -1;
145 _cleanup_free_ char *v = NULL;
146
147 if (!endswith_no_case(de->d_name, ".efi"))
148 continue;
149
150 if (prefix && !startswith_no_case(de->d_name, prefix))
151 continue;
152
153 fd = openat(dirfd(d), de->d_name, O_RDONLY|O_CLOEXEC);
154 if (fd < 0)
155 return log_error_errno(errno, "Failed to open \"%s/%s\" for reading: %m", p, de->d_name);
156
157 r = get_file_version(fd, &v);
158 if (r < 0)
159 return r;
160 if (r > 0)
161 printf(" File: %s/%s/%s (%s%s%s)\n", special_glyph(TREE_RIGHT), path, de->d_name, ansi_highlight(), v, ansi_normal());
162 else
163 printf(" File: %s/%s/%s\n", special_glyph(TREE_RIGHT), path, de->d_name);
164 c++;
165 }
166
167 return c;
168 }
169
170 static int status_binaries(const char *esp_path, sd_id128_t partition) {
171 int r;
172
173 printf("Available Boot Loaders on ESP:\n");
174
175 if (!esp_path) {
176 printf(" ESP: Cannot find or access mount point of ESP.\n\n");
177 return -ENOENT;
178 }
179
180 printf(" ESP: %s", esp_path);
181 if (!sd_id128_is_null(partition))
182 printf(" (/dev/disk/by-partuuid/%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x)", SD_ID128_FORMAT_VAL(partition));
183 printf("\n");
184
185 r = enumerate_binaries(esp_path, "EFI/systemd", NULL);
186 if (r == 0)
187 log_info("systemd-boot not installed in ESP.");
188 else if (r < 0)
189 return r;
190
191 r = enumerate_binaries(esp_path, "EFI/BOOT", "boot");
192 if (r == 0)
193 log_info("No default/fallback boot loader installed in ESP.");
194 else if (r < 0)
195 return r;
196
197 printf("\n");
198
199 return 0;
200 }
201
202 static int print_efi_option(uint16_t id, bool in_order) {
203 _cleanup_free_ char *title = NULL;
204 _cleanup_free_ char *path = NULL;
205 sd_id128_t partition;
206 bool active;
207 int r = 0;
208
209 r = efi_get_boot_option(id, &title, &partition, &path, &active);
210 if (r < 0)
211 return r;
212
213 /* print only configured entries with partition information */
214 if (!path || sd_id128_is_null(partition))
215 return 0;
216
217 efi_tilt_backslashes(path);
218
219 printf(" Title: %s%s%s\n", ansi_highlight(), strna(title), ansi_normal());
220 printf(" ID: 0x%04X\n", id);
221 printf(" Status: %sactive%s\n", active ? "" : "in", in_order ? ", boot-order" : "");
222 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));
223 printf(" File: %s%s\n", special_glyph(TREE_RIGHT), path);
224 printf("\n");
225
226 return 0;
227 }
228
229 static int status_variables(void) {
230 _cleanup_free_ uint16_t *options = NULL, *order = NULL;
231 int n_options, n_order, i;
232
233 n_options = efi_get_boot_options(&options);
234 if (n_options == -ENOENT)
235 return log_error_errno(n_options,
236 "Failed to access EFI variables, efivarfs"
237 " needs to be available at /sys/firmware/efi/efivars/.");
238 if (n_options < 0)
239 return log_error_errno(n_options, "Failed to read EFI boot entries: %m");
240
241 n_order = efi_get_boot_order(&order);
242 if (n_order == -ENOENT)
243 n_order = 0;
244 else if (n_order < 0)
245 return log_error_errno(n_order, "Failed to read EFI boot order: %m");
246
247 /* print entries in BootOrder first */
248 printf("Boot Loaders Listed in EFI Variables:\n");
249 for (i = 0; i < n_order; i++)
250 print_efi_option(order[i], true);
251
252 /* print remaining entries */
253 for (i = 0; i < n_options; i++) {
254 int j;
255
256 for (j = 0; j < n_order; j++)
257 if (options[i] == order[j])
258 goto next_option;
259
260 print_efi_option(options[i], false);
261
262 next_option:
263 continue;
264 }
265
266 return 0;
267 }
268
269 static int boot_entry_show(const BootEntry *e, bool show_as_default) {
270 assert(e);
271
272 printf(" title: %s%s%s%s%s%s\n",
273 ansi_highlight(),
274 boot_entry_title(e),
275 ansi_normal(),
276 ansi_highlight_green(),
277 show_as_default ? " (default)" : "",
278 ansi_normal());
279
280 if (e->id)
281 printf(" id: %s\n", e->id);
282 if (e->version)
283 printf(" version: %s\n", e->version);
284 if (e->machine_id)
285 printf(" machine-id: %s\n", e->machine_id);
286 if (e->architecture)
287 printf(" architecture: %s\n", e->architecture);
288 if (e->kernel)
289 printf(" linux: %s\n", e->kernel);
290 if (!strv_isempty(e->initrd)) {
291 _cleanup_free_ char *t;
292
293 t = strv_join(e->initrd, " ");
294 if (!t)
295 return log_oom();
296
297 printf(" initrd: %s\n", t);
298 }
299 if (!strv_isempty(e->options)) {
300 _cleanup_free_ char *t;
301
302 t = strv_join(e->options, " ");
303 if (!t)
304 return log_oom();
305
306 printf(" options: %s\n", t);
307 }
308 if (e->device_tree)
309 printf(" devicetree: %s\n", e->device_tree);
310
311 return 0;
312 }
313
314 static int status_entries(const char *esp_path, sd_id128_t partition) {
315 _cleanup_(boot_config_free) BootConfig config = {};
316 int r;
317
318 r = boot_entries_load_config(esp_path, &config);
319 if (r < 0)
320 return r;
321
322 if (config.default_entry < 0)
323 printf("%zu entries, no entry could be determined as default.\n", config.n_entries);
324 else {
325 printf("Default Boot Loader Entry:\n");
326
327 boot_entry_show(config.entries + config.default_entry, false);
328 }
329
330 return 0;
331 }
332
333 static int compare_product(const char *a, const char *b) {
334 size_t x, y;
335
336 assert(a);
337 assert(b);
338
339 x = strcspn(a, " ");
340 y = strcspn(b, " ");
341 if (x != y)
342 return x < y ? -1 : x > y ? 1 : 0;
343
344 return strncmp(a, b, x);
345 }
346
347 static int compare_version(const char *a, const char *b) {
348 assert(a);
349 assert(b);
350
351 a += strcspn(a, " ");
352 a += strspn(a, " ");
353 b += strcspn(b, " ");
354 b += strspn(b, " ");
355
356 return strverscmp(a, b);
357 }
358
359 static int version_check(int fd_from, const char *from, int fd_to, const char *to) {
360 _cleanup_free_ char *a = NULL, *b = NULL;
361 int r;
362
363 assert(fd_from >= 0);
364 assert(from);
365 assert(fd_to >= 0);
366 assert(to);
367
368 r = get_file_version(fd_from, &a);
369 if (r < 0)
370 return r;
371 if (r == 0) {
372 log_error("Source file \"%s\" does not carry version information!", from);
373 return -EINVAL;
374 }
375
376 r = get_file_version(fd_to, &b);
377 if (r < 0)
378 return r;
379 if (r == 0 || compare_product(a, b) != 0) {
380 log_notice("Skipping \"%s\", since it's owned by another boot loader.", to);
381 return -EEXIST;
382 }
383
384 if (compare_version(a, b) < 0) {
385 log_warning("Skipping \"%s\", since a newer boot loader version exists already.", to);
386 return -ESTALE;
387 }
388
389 return 0;
390 }
391
392 static int copy_file_with_version_check(const char *from, const char *to, bool force) {
393 _cleanup_close_ int fd_from = -1, fd_to = -1;
394 _cleanup_free_ char *t = NULL;
395 int r;
396
397 fd_from = open(from, O_RDONLY|O_CLOEXEC|O_NOCTTY);
398 if (fd_from < 0)
399 return log_error_errno(errno, "Failed to open \"%s\" for reading: %m", from);
400
401 if (!force) {
402 fd_to = open(to, O_RDONLY|O_CLOEXEC|O_NOCTTY);
403 if (fd_to < 0) {
404 if (errno != -ENOENT)
405 return log_error_errno(errno, "Failed to open \"%s\" for reading: %m", to);
406 } else {
407 r = version_check(fd_from, from, fd_to, to);
408 if (r < 0)
409 return r;
410
411 if (lseek(fd_from, 0, SEEK_SET) == (off_t) -1)
412 return log_error_errno(errno, "Failed to seek in \"%s\": %m", from);
413
414 fd_to = safe_close(fd_to);
415 }
416 }
417
418 r = tempfn_random(to, NULL, &t);
419 if (r < 0)
420 return log_oom();
421
422 RUN_WITH_UMASK(0000) {
423 fd_to = open(t, O_WRONLY|O_CREAT|O_CLOEXEC|O_EXCL|O_NOFOLLOW, 0644);
424 if (fd_to < 0)
425 return log_error_errno(errno, "Failed to open \"%s\" for writing: %m", t);
426 }
427
428 r = copy_bytes(fd_from, fd_to, (uint64_t) -1, COPY_REFLINK);
429 if (r < 0) {
430 (void) unlink(t);
431 return log_error_errno(r, "Failed to copy data from \"%s\" to \"%s\": %m", from, t);
432 }
433
434 (void) copy_times(fd_from, fd_to);
435
436 if (fsync(fd_to) < 0) {
437 (void) unlink_noerrno(t);
438 return log_error_errno(errno, "Failed to copy data from \"%s\" to \"%s\": %m", from, t);
439 }
440
441 (void) fsync_directory_of_file(fd_to);
442
443 if (renameat(AT_FDCWD, t, AT_FDCWD, to) < 0) {
444 (void) unlink_noerrno(t);
445 return log_error_errno(errno, "Failed to rename \"%s\" to \"%s\": %m", t, to);
446 }
447
448 log_info("Copied \"%s\" to \"%s\".", from, to);
449
450 return 0;
451 }
452
453 static int mkdir_one(const char *prefix, const char *suffix) {
454 char *p;
455
456 p = strjoina(prefix, "/", suffix);
457 if (mkdir(p, 0700) < 0) {
458 if (errno != EEXIST)
459 return log_error_errno(errno, "Failed to create \"%s\": %m", p);
460 } else
461 log_info("Created \"%s\".", p);
462
463 return 0;
464 }
465
466 static const char *efi_subdirs[] = {
467 "EFI",
468 "EFI/systemd",
469 "EFI/BOOT",
470 "loader",
471 "loader/entries",
472 NULL
473 };
474
475 static int create_dirs(const char *esp_path) {
476 const char **i;
477 int r;
478
479 STRV_FOREACH(i, efi_subdirs) {
480 r = mkdir_one(esp_path, *i);
481 if (r < 0)
482 return r;
483 }
484
485 return 0;
486 }
487
488 static int copy_one_file(const char *esp_path, const char *name, bool force) {
489 char *p, *q;
490 int r;
491
492 p = strjoina(BOOTLIBDIR "/", name);
493 q = strjoina(esp_path, "/EFI/systemd/", name);
494 r = copy_file_with_version_check(p, q, force);
495
496 if (startswith(name, "systemd-boot")) {
497 int k;
498 char *v;
499
500 /* Create the EFI default boot loader name (specified for removable devices) */
501 v = strjoina(esp_path, "/EFI/BOOT/BOOT",
502 name + STRLEN("systemd-boot"));
503 ascii_strupper(strrchr(v, '/') + 1);
504
505 k = copy_file_with_version_check(p, v, force);
506 if (k < 0 && r == 0)
507 r = k;
508 }
509
510 return r;
511 }
512
513 static int install_binaries(const char *esp_path, bool force) {
514 struct dirent *de;
515 _cleanup_closedir_ DIR *d = NULL;
516 int r = 0;
517
518 if (force) {
519 /* Don't create any of these directories when we are
520 * just updating. When we update we'll drop-in our
521 * files (unless there are newer ones already), but we
522 * won't create the directories for them in the first
523 * place. */
524 r = create_dirs(esp_path);
525 if (r < 0)
526 return r;
527 }
528
529 d = opendir(BOOTLIBDIR);
530 if (!d)
531 return log_error_errno(errno, "Failed to open \""BOOTLIBDIR"\": %m");
532
533 FOREACH_DIRENT(de, d, break) {
534 int k;
535
536 if (!endswith_no_case(de->d_name, ".efi"))
537 continue;
538
539 k = copy_one_file(esp_path, de->d_name, force);
540 if (k < 0 && r == 0)
541 r = k;
542 }
543
544 return r;
545 }
546
547 static bool same_entry(uint16_t id, const sd_id128_t uuid, const char *path) {
548 _cleanup_free_ char *opath = NULL;
549 sd_id128_t ouuid;
550 int r;
551
552 r = efi_get_boot_option(id, NULL, &ouuid, &opath, NULL);
553 if (r < 0)
554 return false;
555 if (!sd_id128_equal(uuid, ouuid))
556 return false;
557 if (!streq_ptr(path, opath))
558 return false;
559
560 return true;
561 }
562
563 static int find_slot(sd_id128_t uuid, const char *path, uint16_t *id) {
564 _cleanup_free_ uint16_t *options = NULL;
565 int n, i;
566
567 n = efi_get_boot_options(&options);
568 if (n < 0)
569 return n;
570
571 /* find already existing systemd-boot entry */
572 for (i = 0; i < n; i++)
573 if (same_entry(options[i], uuid, path)) {
574 *id = options[i];
575 return 1;
576 }
577
578 /* find free slot in the sorted BootXXXX variable list */
579 for (i = 0; i < n; i++)
580 if (i != options[i]) {
581 *id = i;
582 return 1;
583 }
584
585 /* use the next one */
586 if (i == 0xffff)
587 return -ENOSPC;
588 *id = i;
589 return 0;
590 }
591
592 static int insert_into_order(uint16_t slot, bool first) {
593 _cleanup_free_ uint16_t *order = NULL;
594 uint16_t *t;
595 int n, i;
596
597 n = efi_get_boot_order(&order);
598 if (n <= 0)
599 /* no entry, add us */
600 return efi_set_boot_order(&slot, 1);
601
602 /* are we the first and only one? */
603 if (n == 1 && order[0] == slot)
604 return 0;
605
606 /* are we already in the boot order? */
607 for (i = 0; i < n; i++) {
608 if (order[i] != slot)
609 continue;
610
611 /* we do not require to be the first one, all is fine */
612 if (!first)
613 return 0;
614
615 /* move us to the first slot */
616 memmove(order + 1, order, i * sizeof(uint16_t));
617 order[0] = slot;
618 return efi_set_boot_order(order, n);
619 }
620
621 /* extend array */
622 t = realloc(order, (n + 1) * sizeof(uint16_t));
623 if (!t)
624 return -ENOMEM;
625 order = t;
626
627 /* add us to the top or end of the list */
628 if (first) {
629 memmove(order + 1, order, n * sizeof(uint16_t));
630 order[0] = slot;
631 } else
632 order[n] = slot;
633
634 return efi_set_boot_order(order, n + 1);
635 }
636
637 static int remove_from_order(uint16_t slot) {
638 _cleanup_free_ uint16_t *order = NULL;
639 int n, i;
640
641 n = efi_get_boot_order(&order);
642 if (n <= 0)
643 return n;
644
645 for (i = 0; i < n; i++) {
646 if (order[i] != slot)
647 continue;
648
649 if (i + 1 < n)
650 memmove(order + i, order + i+1, (n - i) * sizeof(uint16_t));
651 return efi_set_boot_order(order, n - 1);
652 }
653
654 return 0;
655 }
656
657 static int install_variables(const char *esp_path,
658 uint32_t part, uint64_t pstart, uint64_t psize,
659 sd_id128_t uuid, const char *path,
660 bool first) {
661 char *p;
662 uint16_t slot;
663 int r;
664
665 if (!is_efi_boot()) {
666 log_warning("Not booted with EFI, skipping EFI variable setup.");
667 return 0;
668 }
669
670 p = strjoina(esp_path, path);
671 if (access(p, F_OK) < 0) {
672 if (errno == ENOENT)
673 return 0;
674
675 return log_error_errno(errno, "Cannot access \"%s\": %m", p);
676 }
677
678 r = find_slot(uuid, path, &slot);
679 if (r < 0)
680 return log_error_errno(r,
681 r == -ENOENT ?
682 "Failed to access EFI variables. Is the \"efivarfs\" filesystem mounted?" :
683 "Failed to determine current boot order: %m");
684
685 if (first || r == 0) {
686 r = efi_add_boot_option(slot, "Linux Boot Manager",
687 part, pstart, psize,
688 uuid, path);
689 if (r < 0)
690 return log_error_errno(r, "Failed to create EFI Boot variable entry: %m");
691
692 log_info("Created EFI boot entry \"Linux Boot Manager\".");
693 }
694
695 return insert_into_order(slot, first);
696 }
697
698 static int remove_boot_efi(const char *esp_path) {
699 char *p;
700 _cleanup_closedir_ DIR *d = NULL;
701 struct dirent *de;
702 int r, c = 0;
703
704 p = strjoina(esp_path, "/EFI/BOOT");
705 d = opendir(p);
706 if (!d) {
707 if (errno == ENOENT)
708 return 0;
709
710 return log_error_errno(errno, "Failed to open directory \"%s\": %m", p);
711 }
712
713 FOREACH_DIRENT(de, d, break) {
714 _cleanup_close_ int fd = -1;
715 _cleanup_free_ char *v = NULL;
716
717 if (!endswith_no_case(de->d_name, ".efi"))
718 continue;
719
720 if (!startswith_no_case(de->d_name, "boot"))
721 continue;
722
723 fd = openat(dirfd(d), de->d_name, O_RDONLY|O_CLOEXEC);
724 if (fd < 0)
725 return log_error_errno(errno, "Failed to open \"%s/%s\" for reading: %m", p, de->d_name);
726
727 r = get_file_version(fd, &v);
728 if (r < 0)
729 return r;
730 if (r > 0 && startswith(v, "systemd-boot ")) {
731 r = unlinkat(dirfd(d), de->d_name, 0);
732 if (r < 0)
733 return log_error_errno(errno, "Failed to remove \"%s/%s\": %m", p, de->d_name);
734
735 log_info("Removed \"%s/%s\".", p, de->d_name);
736 }
737
738 c++;
739 }
740
741 return c;
742 }
743
744 static int rmdir_one(const char *prefix, const char *suffix) {
745 char *p;
746
747 p = strjoina(prefix, "/", suffix);
748 if (rmdir(p) < 0) {
749 if (!IN_SET(errno, ENOENT, ENOTEMPTY))
750 return log_error_errno(errno, "Failed to remove \"%s\": %m", p);
751 } else
752 log_info("Removed \"%s\".", p);
753
754 return 0;
755 }
756
757 static int remove_binaries(const char *esp_path) {
758 char *p;
759 int r, q;
760 unsigned i;
761
762 p = strjoina(esp_path, "/EFI/systemd");
763 r = rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL);
764
765 q = remove_boot_efi(esp_path);
766 if (q < 0 && r == 0)
767 r = q;
768
769 for (i = ELEMENTSOF(efi_subdirs)-1; i > 0; i--) {
770 q = rmdir_one(esp_path, efi_subdirs[i-1]);
771 if (q < 0 && r == 0)
772 r = q;
773 }
774
775 return r;
776 }
777
778 static int remove_variables(sd_id128_t uuid, const char *path, bool in_order) {
779 uint16_t slot;
780 int r;
781
782 if (!is_efi_boot())
783 return 0;
784
785 r = find_slot(uuid, path, &slot);
786 if (r != 1)
787 return 0;
788
789 r = efi_remove_boot_option(slot);
790 if (r < 0)
791 return r;
792
793 if (in_order)
794 return remove_from_order(slot);
795
796 return 0;
797 }
798
799 static int install_loader_config(const char *esp_path) {
800
801 char machine_string[SD_ID128_STRING_MAX];
802 _cleanup_(unlink_and_freep) char *t = NULL;
803 _cleanup_fclose_ FILE *f = NULL;
804 sd_id128_t machine_id;
805 const char *p;
806 int r, fd;
807
808 r = sd_id128_get_machine(&machine_id);
809 if (r < 0)
810 return log_error_errno(r, "Failed to get machine id: %m");
811
812 p = strjoina(esp_path, "/loader/loader.conf");
813
814 if (access(p, F_OK) >= 0) /* Silently skip creation if the file already exists (early check) */
815 return 0;
816
817 fd = open_tmpfile_linkable(p, O_WRONLY|O_CLOEXEC, &t);
818 if (fd < 0)
819 return log_error_errno(fd, "Failed to open \"%s\" for writing: %m", p);
820
821 f = fdopen(fd, "we");
822 if (!f) {
823 safe_close(fd);
824 return log_oom();
825 }
826
827 fprintf(f, "#timeout 3\n"
828 "#console-mode keep\n"
829 "default %s-*\n", sd_id128_to_string(machine_id, machine_string));
830
831 r = fflush_sync_and_check(f);
832 if (r < 0)
833 return log_error_errno(r, "Failed to write \"%s\": %m", p);
834
835 r = link_tmpfile(fd, t, p);
836 if (r == -EEXIST)
837 return 0; /* Silently skip creation if the file exists now (recheck) */
838 if (r < 0)
839 return log_error_errno(r, "Failed to move \"%s\" into place: %m", p);
840
841 t = mfree(t);
842
843 return 1;
844 }
845
846 static int help(int argc, char *argv[], void *userdata) {
847 _cleanup_free_ char *link = NULL;
848 int r;
849
850 r = terminal_urlify_man("bootctl", "1", &link);
851 if (r < 0)
852 return log_oom();
853
854 printf("%s [COMMAND] [OPTIONS...]\n\n"
855 "Install, update or remove the systemd-boot EFI boot manager.\n\n"
856 " -h --help Show this help\n"
857 " --version Print version\n"
858 " --path=PATH Path to the EFI System Partition (ESP)\n"
859 " -p --print-path Print path to the EFI partition\n"
860 " --no-variables Don't touch EFI variables\n"
861 " --no-pager Do not pipe output into a pager\n"
862 "\nBoot Loader Commands:\n"
863 " status Show status of installed systemd-boot and EFI variables\n"
864 " install Install systemd-boot to the ESP and EFI variables\n"
865 " update Update systemd-boot in the ESP and EFI variables\n"
866 " remove Remove systemd-boot from the ESP and EFI variables\n"
867 "\nBoot Loader Entries Commands:\n"
868 " list List boot loader entries\n"
869 " set-default ID Set default boot loader entry\n"
870 " set-oneshot ID Set default boot loader entry, for next boot only\n"
871 "\nSee the %s for details.\n"
872 , program_invocation_short_name
873 , link);
874
875 return 0;
876 }
877
878 static int parse_argv(int argc, char *argv[]) {
879 enum {
880 ARG_PATH = 0x100,
881 ARG_VERSION,
882 ARG_NO_VARIABLES,
883 ARG_NO_PAGER,
884 };
885
886 static const struct option options[] = {
887 { "help", no_argument, NULL, 'h' },
888 { "version", no_argument, NULL, ARG_VERSION },
889 { "path", required_argument, NULL, ARG_PATH },
890 { "print-path", no_argument, NULL, 'p' },
891 { "no-variables", no_argument, NULL, ARG_NO_VARIABLES },
892 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
893 {}
894 };
895
896 int c, r;
897
898 assert(argc >= 0);
899 assert(argv);
900
901 while ((c = getopt_long(argc, argv, "hp", options, NULL)) >= 0)
902 switch (c) {
903
904 case 'h':
905 help(0, NULL, NULL);
906 return 0;
907
908 case ARG_VERSION:
909 return version();
910
911 case ARG_PATH:
912 r = free_and_strdup(&arg_path, optarg);
913 if (r < 0)
914 return log_oom();
915 break;
916
917 case 'p':
918 arg_print_path = true;
919 break;
920
921 case ARG_NO_VARIABLES:
922 arg_touch_variables = false;
923 break;
924
925 case ARG_NO_PAGER:
926 arg_pager_flags |= PAGER_DISABLE;
927 break;
928
929 case '?':
930 return -EINVAL;
931
932 default:
933 assert_not_reached("Unknown option");
934 }
935
936 return 1;
937 }
938
939 static void read_loader_efi_var(const char *name, char **var) {
940 int r;
941
942 r = efi_get_variable_string(EFI_VENDOR_LOADER, name, var);
943 if (r < 0 && r != -ENOENT)
944 log_warning_errno(r, "Failed to read EFI variable %s: %m", name);
945 }
946
947 static int verb_status(int argc, char *argv[], void *userdata) {
948
949 sd_id128_t uuid = SD_ID128_NULL;
950 int r, k;
951
952 r = acquire_esp(geteuid() != 0, NULL, NULL, NULL, &uuid);
953
954 if (arg_print_path) {
955 if (r == -EACCES) /* If we couldn't acquire the ESP path, log about access errors (which is the only
956 * error the find_esp_and_warn() won't log on its own) */
957 return log_error_errno(r, "Failed to determine ESP: %m");
958 if (r < 0)
959 return r;
960
961 puts(arg_path);
962 return 0;
963 }
964
965 r = 0; /* If we couldn't determine the path, then don't consider that a problem from here on, just show what we
966 * can show */
967
968 (void) pager_open(arg_pager_flags);
969
970 if (is_efi_boot()) {
971 static const struct {
972 uint64_t flag;
973 const char *name;
974 } flags[] = {
975 { EFI_LOADER_FEATURE_BOOT_COUNTING, "Boot counting" },
976 { EFI_LOADER_FEATURE_CONFIG_TIMEOUT, "Menu timeout control" },
977 { EFI_LOADER_FEATURE_CONFIG_TIMEOUT_ONE_SHOT, "One-shot menu timeout control" },
978 { EFI_LOADER_FEATURE_ENTRY_DEFAULT, "Default entry control" },
979 { EFI_LOADER_FEATURE_ENTRY_ONESHOT, "One-shot entry control" },
980 };
981
982 _cleanup_free_ char *fw_type = NULL, *fw_info = NULL, *loader = NULL, *loader_path = NULL, *stub = NULL;
983 sd_id128_t loader_part_uuid = SD_ID128_NULL;
984 uint64_t loader_features = 0;
985 size_t i;
986
987 read_loader_efi_var("LoaderFirmwareType", &fw_type);
988 read_loader_efi_var("LoaderFirmwareInfo", &fw_info);
989 read_loader_efi_var("LoaderInfo", &loader);
990 read_loader_efi_var("StubInfo", &stub);
991 read_loader_efi_var("LoaderImageIdentifier", &loader_path);
992 (void) efi_loader_get_features(&loader_features);
993
994 if (loader_path)
995 efi_tilt_backslashes(loader_path);
996
997 k = efi_loader_get_device_part_uuid(&loader_part_uuid);
998 if (k < 0 && k != -ENOENT)
999 r = log_warning_errno(k, "Failed to read EFI variable LoaderDevicePartUUID: %m");
1000
1001 printf("System:\n");
1002 printf(" Firmware: %s%s (%s)%s\n", ansi_highlight(), strna(fw_type), strna(fw_info), ansi_normal());
1003 printf(" Secure Boot: %sd\n", enable_disable(is_efi_secure_boot()));
1004 printf(" Setup Mode: %s\n", is_efi_secure_boot_setup_mode() ? "setup" : "user");
1005 printf("\n");
1006
1007 printf("Current Boot Loader:\n");
1008 printf(" Product: %s%s%s\n", ansi_highlight(), strna(loader), ansi_normal());
1009
1010 for (i = 0; i < ELEMENTSOF(flags); i++) {
1011
1012 if (i == 0)
1013 printf(" Features: ");
1014 else
1015 printf(" ");
1016
1017 if (FLAGS_SET(loader_features, flags[i].flag))
1018 printf("%s%s%s %s\n", ansi_highlight_green(), special_glyph(CHECK_MARK), ansi_normal(), flags[i].name);
1019 else
1020 printf("%s%s%s %s\n", ansi_highlight_red(), special_glyph(CROSS_MARK), ansi_normal(), flags[i].name);
1021 }
1022
1023 if (stub)
1024 printf(" Stub: %s\n", stub);
1025 if (!sd_id128_is_null(loader_part_uuid))
1026 printf(" ESP: /dev/disk/by-partuuid/%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
1027 SD_ID128_FORMAT_VAL(loader_part_uuid));
1028 else
1029 printf(" ESP: n/a\n");
1030 printf(" File: %s%s\n", special_glyph(TREE_RIGHT), strna(loader_path));
1031 printf("\n");
1032 } else
1033 printf("System:\n Not booted with EFI\n\n");
1034
1035 if (arg_path) {
1036 k = status_binaries(arg_path, uuid);
1037 if (k < 0)
1038 r = k;
1039 }
1040
1041 if (is_efi_boot()) {
1042 k = status_variables();
1043 if (k < 0)
1044 r = k;
1045 }
1046
1047 if (arg_path) {
1048 k = status_entries(arg_path, uuid);
1049 if (k < 0)
1050 r = k;
1051 }
1052
1053 return r;
1054 }
1055
1056 static int verb_list(int argc, char *argv[], void *userdata) {
1057 _cleanup_(boot_config_free) BootConfig config = {};
1058 _cleanup_free_ char **found_by_loader = NULL;
1059 sd_id128_t uuid = SD_ID128_NULL;
1060 int r;
1061
1062 /* If we lack privileges we invoke find_esp_and_warn() in "unprivileged mode" here, which does two things: turn
1063 * off logging about access errors and turn off potentially privileged device probing. Here we're interested in
1064 * the latter but not the former, hence request the mode, and log about EACCES. */
1065
1066 r = acquire_esp(geteuid() != 0, NULL, NULL, NULL, &uuid);
1067 if (r == -EACCES) /* We really need the ESP path for this call, hence also log about access errors */
1068 return log_error_errno(r, "Failed to determine ESP: %m");
1069 if (r < 0)
1070 return r;
1071
1072 r = boot_entries_load_config(arg_path, &config);
1073 if (r < 0)
1074 return r;
1075
1076 r = efi_loader_get_entries(&found_by_loader);
1077 if (r < 0 && !IN_SET(r, -ENOENT, -EOPNOTSUPP))
1078 log_debug_errno(r, "Failed to acquire boot loader discovered entries: %m");
1079
1080 if (config.n_entries == 0)
1081 log_info("No boot loader entries found.");
1082 else {
1083 size_t n;
1084
1085 (void) pager_open(arg_pager_flags);
1086
1087 printf("Boot Loader Entries:\n");
1088
1089 for (n = 0; n < config.n_entries; n++) {
1090 r = boot_entry_show(config.entries + n, n == (size_t) config.default_entry);
1091 if (r < 0)
1092 return r;
1093
1094 puts("");
1095
1096 strv_remove(found_by_loader, config.entries[n].id);
1097 }
1098 }
1099
1100 if (!strv_isempty(found_by_loader)) {
1101 char **i;
1102
1103 printf("Automatic/Other Entries Found by Boot Loader:\n\n");
1104
1105 STRV_FOREACH(i, found_by_loader)
1106 puts(*i);
1107 }
1108
1109 return 0;
1110 }
1111
1112 static int sync_esp(void) {
1113 _cleanup_close_ int fd = -1;
1114
1115 if (!arg_path)
1116 return 0;
1117
1118 fd = open(arg_path, O_CLOEXEC|O_DIRECTORY|O_RDONLY);
1119 if (fd < 0)
1120 return log_error_errno(errno, "Couldn't open ESP '%s' for synchronization: %m", arg_path);
1121
1122 if (syncfs(fd) < 0)
1123 return log_error_errno(errno, "Failed to synchronize the ESP '%s': %m", arg_path);
1124
1125 return 1;
1126 }
1127
1128 static int verb_install(int argc, char *argv[], void *userdata) {
1129
1130 sd_id128_t uuid = SD_ID128_NULL;
1131 uint64_t pstart = 0, psize = 0;
1132 uint32_t part = 0;
1133 bool install;
1134 int r;
1135
1136 r = acquire_esp(false, &part, &pstart, &psize, &uuid);
1137 if (r < 0)
1138 return r;
1139
1140 install = streq(argv[0], "install");
1141
1142 RUN_WITH_UMASK(0002) {
1143 r = install_binaries(arg_path, install);
1144 if (r < 0)
1145 return r;
1146
1147 if (install) {
1148 r = install_loader_config(arg_path);
1149 if (r < 0)
1150 return r;
1151 }
1152 }
1153
1154 (void) sync_esp();
1155
1156 if (arg_touch_variables)
1157 r = install_variables(arg_path,
1158 part, pstart, psize, uuid,
1159 "/EFI/systemd/systemd-boot" EFI_MACHINE_TYPE_NAME ".efi",
1160 install);
1161
1162 return r;
1163 }
1164
1165 static int verb_remove(int argc, char *argv[], void *userdata) {
1166 sd_id128_t uuid = SD_ID128_NULL;
1167 int r;
1168
1169 r = acquire_esp(false, NULL, NULL, NULL, &uuid);
1170 if (r < 0)
1171 return r;
1172
1173 r = remove_binaries(arg_path);
1174
1175 (void) sync_esp();
1176
1177 if (arg_touch_variables) {
1178 int q;
1179
1180 q = remove_variables(uuid, "/EFI/systemd/systemd-boot" EFI_MACHINE_TYPE_NAME ".efi", true);
1181 if (q < 0 && r == 0)
1182 r = q;
1183 }
1184
1185 return r;
1186 }
1187
1188 static int verb_set_default(int argc, char *argv[], void *userdata) {
1189 const char *name;
1190 int r;
1191
1192 if (!is_efi_boot()) {
1193 log_error("Not booted with UEFI.");
1194 return -EOPNOTSUPP;
1195 }
1196
1197 if (access("/sys/firmware/efi/efivars/LoaderInfo-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f", F_OK) < 0) {
1198 if (errno == ENOENT) {
1199 log_error_errno(errno, "Not booted with a supported boot loader.");
1200 return -EOPNOTSUPP;
1201 }
1202
1203 return log_error_errno(errno, "Failed to detect whether boot loader supports '%s' operation: %m", argv[0]);
1204 }
1205
1206 if (detect_container() > 0) {
1207 log_error("'%s' operation not supported in a container.", argv[0]);
1208 return -EOPNOTSUPP;
1209 }
1210
1211 if (!arg_touch_variables) {
1212 log_error("'%s' operation cannot be combined with --touch-variables=no.", argv[0]);
1213 return -EINVAL;
1214 }
1215
1216 name = streq(argv[0], "set-default") ? "LoaderEntryDefault" : "LoaderEntryOneShot";
1217
1218 if (isempty(argv[1])) {
1219 r = efi_set_variable(EFI_VENDOR_LOADER, name, NULL, 0);
1220 if (r < 0 && r != -ENOENT)
1221 return log_error_errno(r, "Failed to remove EFI variale: %m");
1222 } else {
1223 _cleanup_free_ char16_t *encoded = NULL;
1224
1225 encoded = utf8_to_utf16(argv[1], strlen(argv[1]));
1226 if (!encoded)
1227 return log_oom();
1228
1229 r = efi_set_variable(EFI_VENDOR_LOADER, name, encoded, char16_strlen(encoded) * 2 + 2);
1230 if (r < 0)
1231 return log_error_errno(r, "Failed to update EFI variable: %m");
1232 }
1233
1234 return 0;
1235 }
1236
1237 static int bootctl_main(int argc, char *argv[]) {
1238
1239 static const Verb verbs[] = {
1240 { "help", VERB_ANY, VERB_ANY, 0, help },
1241 { "status", VERB_ANY, 1, VERB_DEFAULT, verb_status },
1242 { "install", VERB_ANY, 1, VERB_MUST_BE_ROOT, verb_install },
1243 { "update", VERB_ANY, 1, VERB_MUST_BE_ROOT, verb_install },
1244 { "remove", VERB_ANY, 1, VERB_MUST_BE_ROOT, verb_remove },
1245 { "list", VERB_ANY, 1, 0, verb_list },
1246 { "set-default", 2, 2, VERB_MUST_BE_ROOT, verb_set_default },
1247 { "set-oneshot", 2, 2, VERB_MUST_BE_ROOT, verb_set_default },
1248 {}
1249 };
1250
1251 return dispatch_verb(argc, argv, verbs, NULL);
1252 }
1253
1254 int main(int argc, char *argv[]) {
1255 int r;
1256
1257 log_parse_environment();
1258 log_open();
1259
1260 /* If we run in a container, automatically turn of EFI file system access */
1261 if (detect_container() > 0)
1262 arg_touch_variables = false;
1263
1264 r = parse_argv(argc, argv);
1265 if (r <= 0)
1266 goto finish;
1267
1268 r = bootctl_main(argc, argv);
1269
1270 finish:
1271 pager_close();
1272 free(arg_path);
1273
1274 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1275 }