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