]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/boot/bootctl.c
bootctl: don't trip up in "bootctl status" when we can't find the ESP because of...
[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", 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", name + strlen("systemd-boot"));
501 ascii_strupper(strrchr(v, '/') + 1);
502
503 k = copy_file_with_version_check(p, v, force);
504 if (k < 0 && r == 0)
505 r = k;
506 }
507
508 return r;
509 }
510
511 static int install_binaries(const char *esp_path, bool force) {
512 struct dirent *de;
513 _cleanup_closedir_ DIR *d = NULL;
514 int r = 0;
515
516 if (force) {
517 /* Don't create any of these directories when we are
518 * just updating. When we update we'll drop-in our
519 * files (unless there are newer ones already), but we
520 * won't create the directories for them in the first
521 * place. */
522 r = create_dirs(esp_path);
523 if (r < 0)
524 return r;
525 }
526
527 d = opendir(BOOTLIBDIR);
528 if (!d)
529 return log_error_errno(errno, "Failed to open \""BOOTLIBDIR"\": %m");
530
531 FOREACH_DIRENT(de, d, break) {
532 int k;
533
534 if (!endswith_no_case(de->d_name, ".efi"))
535 continue;
536
537 k = copy_one_file(esp_path, de->d_name, force);
538 if (k < 0 && r == 0)
539 r = k;
540 }
541
542 return r;
543 }
544
545 static bool same_entry(uint16_t id, const sd_id128_t uuid, const char *path) {
546 _cleanup_free_ char *opath = NULL;
547 sd_id128_t ouuid;
548 int r;
549
550 r = efi_get_boot_option(id, NULL, &ouuid, &opath, NULL);
551 if (r < 0)
552 return false;
553 if (!sd_id128_equal(uuid, ouuid))
554 return false;
555 if (!streq_ptr(path, opath))
556 return false;
557
558 return true;
559 }
560
561 static int find_slot(sd_id128_t uuid, const char *path, uint16_t *id) {
562 _cleanup_free_ uint16_t *options = NULL;
563 int n, i;
564
565 n = efi_get_boot_options(&options);
566 if (n < 0)
567 return n;
568
569 /* find already existing systemd-boot entry */
570 for (i = 0; i < n; i++)
571 if (same_entry(options[i], uuid, path)) {
572 *id = options[i];
573 return 1;
574 }
575
576 /* find free slot in the sorted BootXXXX variable list */
577 for (i = 0; i < n; i++)
578 if (i != options[i]) {
579 *id = i;
580 return 1;
581 }
582
583 /* use the next one */
584 if (i == 0xffff)
585 return -ENOSPC;
586 *id = i;
587 return 0;
588 }
589
590 static int insert_into_order(uint16_t slot, bool first) {
591 _cleanup_free_ uint16_t *order = NULL;
592 uint16_t *t;
593 int n, i;
594
595 n = efi_get_boot_order(&order);
596 if (n <= 0)
597 /* no entry, add us */
598 return efi_set_boot_order(&slot, 1);
599
600 /* are we the first and only one? */
601 if (n == 1 && order[0] == slot)
602 return 0;
603
604 /* are we already in the boot order? */
605 for (i = 0; i < n; i++) {
606 if (order[i] != slot)
607 continue;
608
609 /* we do not require to be the first one, all is fine */
610 if (!first)
611 return 0;
612
613 /* move us to the first slot */
614 memmove(order + 1, order, i * sizeof(uint16_t));
615 order[0] = slot;
616 return efi_set_boot_order(order, n);
617 }
618
619 /* extend array */
620 t = realloc(order, (n + 1) * sizeof(uint16_t));
621 if (!t)
622 return -ENOMEM;
623 order = t;
624
625 /* add us to the top or end of the list */
626 if (first) {
627 memmove(order + 1, order, n * sizeof(uint16_t));
628 order[0] = slot;
629 } else
630 order[n] = slot;
631
632 return efi_set_boot_order(order, n + 1);
633 }
634
635 static int remove_from_order(uint16_t slot) {
636 _cleanup_free_ uint16_t *order = NULL;
637 int n, i;
638
639 n = efi_get_boot_order(&order);
640 if (n <= 0)
641 return n;
642
643 for (i = 0; i < n; i++) {
644 if (order[i] != slot)
645 continue;
646
647 if (i + 1 < n)
648 memmove(order + i, order + i+1, (n - i) * sizeof(uint16_t));
649 return efi_set_boot_order(order, n - 1);
650 }
651
652 return 0;
653 }
654
655 static int install_variables(const char *esp_path,
656 uint32_t part, uint64_t pstart, uint64_t psize,
657 sd_id128_t uuid, const char *path,
658 bool first) {
659 char *p;
660 uint16_t slot;
661 int r;
662
663 if (!is_efi_boot()) {
664 log_warning("Not booted with EFI, skipping EFI variable setup.");
665 return 0;
666 }
667
668 p = strjoina(esp_path, path);
669 if (access(p, F_OK) < 0) {
670 if (errno == ENOENT)
671 return 0;
672
673 return log_error_errno(errno, "Cannot access \"%s\": %m", p);
674 }
675
676 r = find_slot(uuid, path, &slot);
677 if (r < 0)
678 return log_error_errno(r,
679 r == -ENOENT ?
680 "Failed to access EFI variables. Is the \"efivarfs\" filesystem mounted?" :
681 "Failed to determine current boot order: %m");
682
683 if (first || r == 0) {
684 r = efi_add_boot_option(slot, "Linux Boot Manager",
685 part, pstart, psize,
686 uuid, path);
687 if (r < 0)
688 return log_error_errno(r, "Failed to create EFI Boot variable entry: %m");
689
690 log_info("Created EFI boot entry \"Linux Boot Manager\".");
691 }
692
693 return insert_into_order(slot, first);
694 }
695
696 static int remove_boot_efi(const char *esp_path) {
697 char *p;
698 _cleanup_closedir_ DIR *d = NULL;
699 struct dirent *de;
700 int r, c = 0;
701
702 p = strjoina(esp_path, "/EFI/BOOT");
703 d = opendir(p);
704 if (!d) {
705 if (errno == ENOENT)
706 return 0;
707
708 return log_error_errno(errno, "Failed to open directory \"%s\": %m", p);
709 }
710
711 FOREACH_DIRENT(de, d, break) {
712 _cleanup_close_ int fd = -1;
713 _cleanup_free_ char *v = NULL;
714
715 if (!endswith_no_case(de->d_name, ".efi"))
716 continue;
717
718 if (!startswith_no_case(de->d_name, "boot"))
719 continue;
720
721 fd = openat(dirfd(d), de->d_name, O_RDONLY|O_CLOEXEC);
722 if (fd < 0)
723 return log_error_errno(errno, "Failed to open \"%s/%s\" for reading: %m", p, de->d_name);
724
725 r = get_file_version(fd, &v);
726 if (r < 0)
727 return r;
728 if (r > 0 && startswith(v, "systemd-boot ")) {
729 r = unlinkat(dirfd(d), de->d_name, 0);
730 if (r < 0)
731 return log_error_errno(errno, "Failed to remove \"%s/%s\": %m", p, de->d_name);
732
733 log_info("Removed \"%s/%s\".", p, de->d_name);
734 }
735
736 c++;
737 }
738
739 return c;
740 }
741
742 static int rmdir_one(const char *prefix, const char *suffix) {
743 char *p;
744
745 p = strjoina(prefix, "/", suffix);
746 if (rmdir(p) < 0) {
747 if (!IN_SET(errno, ENOENT, ENOTEMPTY))
748 return log_error_errno(errno, "Failed to remove \"%s\": %m", p);
749 } else
750 log_info("Removed \"%s\".", p);
751
752 return 0;
753 }
754
755 static int remove_binaries(const char *esp_path) {
756 char *p;
757 int r, q;
758 unsigned i;
759
760 p = strjoina(esp_path, "/EFI/systemd");
761 r = rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL);
762
763 q = remove_boot_efi(esp_path);
764 if (q < 0 && r == 0)
765 r = q;
766
767 for (i = ELEMENTSOF(efi_subdirs)-1; i > 0; i--) {
768 q = rmdir_one(esp_path, efi_subdirs[i-1]);
769 if (q < 0 && r == 0)
770 r = q;
771 }
772
773 return r;
774 }
775
776 static int remove_variables(sd_id128_t uuid, const char *path, bool in_order) {
777 uint16_t slot;
778 int r;
779
780 if (!is_efi_boot())
781 return 0;
782
783 r = find_slot(uuid, path, &slot);
784 if (r != 1)
785 return 0;
786
787 r = efi_remove_boot_option(slot);
788 if (r < 0)
789 return r;
790
791 if (in_order)
792 return remove_from_order(slot);
793
794 return 0;
795 }
796
797 static int install_loader_config(const char *esp_path) {
798
799 char machine_string[SD_ID128_STRING_MAX];
800 _cleanup_(unlink_and_freep) char *t = NULL;
801 _cleanup_fclose_ FILE *f = NULL;
802 sd_id128_t machine_id;
803 const char *p;
804 int r, fd;
805
806 r = sd_id128_get_machine(&machine_id);
807 if (r < 0)
808 return log_error_errno(r, "Failed to get machine id: %m");
809
810 p = strjoina(esp_path, "/loader/loader.conf");
811
812 if (access(p, F_OK) >= 0) /* Silently skip creation if the file already exists (early check) */
813 return 0;
814
815 fd = open_tmpfile_linkable(p, O_WRONLY|O_CLOEXEC, &t);
816 if (fd < 0)
817 return log_error_errno(fd, "Failed to open \"%s\" for writing: %m", p);
818
819 f = fdopen(fd, "we");
820 if (!f) {
821 safe_close(fd);
822 return log_oom();
823 }
824
825 fprintf(f, "#timeout 3\n");
826 fprintf(f, "default %s-*\n", sd_id128_to_string(machine_id, machine_string));
827
828 r = fflush_sync_and_check(f);
829 if (r < 0)
830 return log_error_errno(r, "Failed to write \"%s\": %m", p);
831
832 r = link_tmpfile(fd, t, p);
833 if (r == -EEXIST)
834 return 0; /* Silently skip creation if the file exists now (recheck) */
835 if (r < 0)
836 return log_error_errno(r, "Failed to move \"%s\" into place: %m", p);
837
838 t = mfree(t);
839
840 return 1;
841 }
842
843 static int help(int argc, char *argv[], void *userdata) {
844
845 printf("%s [COMMAND] [OPTIONS...]\n"
846 "\n"
847 "Install, update or remove the systemd-boot EFI boot manager.\n\n"
848 " -h --help Show this help\n"
849 " --version Print version\n"
850 " --path=PATH Path to the EFI System Partition (ESP)\n"
851 " -p --print-path Print path to the EFI partition\n"
852 " --no-variables Don't touch EFI variables\n"
853 "\n"
854 "Commands:\n"
855 " status Show status of installed systemd-boot and EFI variables\n"
856 " list List boot entries\n"
857 " install Install systemd-boot to the ESP and EFI variables\n"
858 " update Update systemd-boot in the ESP and EFI variables\n"
859 " remove Remove systemd-boot from the ESP and EFI variables\n",
860 program_invocation_short_name);
861
862 return 0;
863 }
864
865 static int parse_argv(int argc, char *argv[]) {
866 enum {
867 ARG_PATH = 0x100,
868 ARG_VERSION,
869 ARG_NO_VARIABLES,
870 };
871
872 static const struct option options[] = {
873 { "help", no_argument, NULL, 'h' },
874 { "version", no_argument, NULL, ARG_VERSION },
875 { "path", required_argument, NULL, ARG_PATH },
876 { "print-path", no_argument, NULL, 'p' },
877 { "no-variables", no_argument, NULL, ARG_NO_VARIABLES },
878 { NULL, 0, NULL, 0 }
879 };
880
881 int c, r;
882
883 assert(argc >= 0);
884 assert(argv);
885
886 while ((c = getopt_long(argc, argv, "hp", options, NULL)) >= 0)
887 switch (c) {
888
889 case 'h':
890 help(0, NULL, NULL);
891 return 0;
892
893 case ARG_VERSION:
894 return version();
895
896 case ARG_PATH:
897 r = free_and_strdup(&arg_path, optarg);
898 if (r < 0)
899 return log_oom();
900 break;
901
902 case 'p':
903 arg_print_path = true;
904 break;
905
906 case ARG_NO_VARIABLES:
907 arg_touch_variables = false;
908 break;
909
910 case '?':
911 return -EINVAL;
912
913 default:
914 assert_not_reached("Unknown option");
915 }
916
917 return 1;
918 }
919
920 static void read_loader_efi_var(const char *name, char **var) {
921 int r;
922
923 r = efi_get_variable_string(EFI_VENDOR_LOADER, name, var);
924 if (r < 0 && r != -ENOENT)
925 log_warning_errno(r, "Failed to read EFI variable %s: %m", name);
926 }
927
928 static int must_be_root(void) {
929
930 if (geteuid() == 0)
931 return 0;
932
933 log_error("Need to be root.");
934 return -EPERM;
935 }
936
937 static int verb_status(int argc, char *argv[], void *userdata) {
938
939 sd_id128_t uuid = SD_ID128_NULL;
940 int r, k;
941
942 r = acquire_esp(geteuid() != 0, NULL, NULL, NULL, &uuid);
943
944 if (arg_print_path) {
945 if (r == -EACCES) /* If we couldn't acquire the ESP path, log about access errors (which is the only
946 * error the find_esp_and_warn() won't log on its own) */
947 return log_error_errno(r, "Failed to determine ESP: %m");
948 if (r < 0)
949 return r;
950
951 puts(arg_path);
952 return 0;
953 }
954
955 r = 0; /* If we couldn't determine the path, then don't consider that a problem from here on, just show what we
956 * can show */
957
958 if (is_efi_boot()) {
959 _cleanup_free_ char *fw_type = NULL, *fw_info = NULL, *loader = NULL, *loader_path = NULL;
960 sd_id128_t loader_part_uuid = SD_ID128_NULL;
961
962 read_loader_efi_var("LoaderFirmwareType", &fw_type);
963 read_loader_efi_var("LoaderFirmwareInfo", &fw_info);
964 read_loader_efi_var("LoaderInfo", &loader);
965 read_loader_efi_var("LoaderImageIdentifier", &loader_path);
966
967 if (loader_path)
968 efi_tilt_backslashes(loader_path);
969
970 k = efi_loader_get_device_part_uuid(&loader_part_uuid);
971 if (k < 0 && k != -ENOENT)
972 r = log_warning_errno(k, "Failed to read EFI variable LoaderDevicePartUUID: %m");
973
974 printf("System:\n");
975 printf(" Firmware: %s (%s)\n", strna(fw_type), strna(fw_info));
976
977 k = is_efi_secure_boot();
978 if (k < 0)
979 r = log_warning_errno(k, "Failed to query secure boot status: %m");
980 else
981 printf(" Secure Boot: %sd\n", enable_disable(k));
982
983 k = is_efi_secure_boot_setup_mode();
984 if (k < 0)
985 r = log_warning_errno(k, "Failed to query secure boot mode: %m");
986 else
987 printf(" Setup Mode: %s\n", k ? "setup" : "user");
988 printf("\n");
989
990 printf("Current Loader:\n");
991 printf(" Product: %s\n", strna(loader));
992 if (!sd_id128_is_null(loader_part_uuid))
993 printf(" ESP: /dev/disk/by-partuuid/%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
994 SD_ID128_FORMAT_VAL(loader_part_uuid));
995 else
996 printf(" ESP: n/a\n");
997 printf(" File: %s%s\n", special_glyph(TREE_RIGHT), strna(loader_path));
998 printf("\n");
999 } else
1000 printf("System:\n Not booted with EFI\n\n");
1001
1002 if (arg_path) {
1003 k = status_binaries(arg_path, uuid);
1004 if (k < 0)
1005 r = k;
1006 }
1007
1008 if (is_efi_boot()) {
1009 k = status_variables();
1010 if (k < 0)
1011 r = k;
1012 }
1013
1014 if (arg_path) {
1015 k = status_entries(arg_path, uuid);
1016 if (k < 0)
1017 r = k;
1018 }
1019
1020 return r;
1021 }
1022
1023 static int verb_list(int argc, char *argv[], void *userdata) {
1024 _cleanup_(boot_config_free) BootConfig config = {};
1025 sd_id128_t uuid = SD_ID128_NULL;
1026 unsigned n;
1027 int r;
1028
1029 /* If we lack privileges we invoke find_esp_and_warn() in "unprivileged mode" here, which does two things: turn
1030 * off logging about access errors and turn off potentially privileged device probing. Here we're interested in
1031 * the latter but not the former, hence request the mode, and log about EACCES. */
1032
1033 r = acquire_esp(geteuid() != 0, NULL, NULL, NULL, &uuid);
1034 if (r == -EACCES) /* We really need the ESP path for this call, hence also log about access errors */
1035 return log_error_errno(r, "Failed to determine ESP: %m");
1036 if (r < 0)
1037 return r;
1038
1039 r = boot_entries_load_config(arg_path, &config);
1040 if (r < 0)
1041 return log_error_errno(r, "Failed to load bootspec config from \"%s/loader\": %m",
1042 arg_path);
1043
1044 printf("Available boot entries:\n");
1045
1046 for (n = 0; n < config.n_entries; n++) {
1047 const BootEntry *e = &config.entries[n];
1048
1049 printf(" title: %s%s%s%s%s%s\n",
1050 ansi_highlight(),
1051 boot_entry_title(e),
1052 ansi_normal(),
1053 ansi_highlight_green(),
1054 n == config.default_entry ? " (default)" : "",
1055 ansi_normal());
1056 if (e->version)
1057 printf(" version: %s\n", e->version);
1058 if (e->machine_id)
1059 printf(" machine-id: %s\n", e->machine_id);
1060 if (e->architecture)
1061 printf(" architecture: %s\n", e->architecture);
1062 if (e->kernel)
1063 printf(" linux: %s\n", e->kernel);
1064 if (!strv_isempty(e->initrd)) {
1065 _cleanup_free_ char *t;
1066
1067 t = strv_join(e->initrd, " ");
1068 if (!t)
1069 return log_oom();
1070
1071 printf(" initrd: %s\n", t);
1072 }
1073 if (!strv_isempty(e->options)) {
1074 _cleanup_free_ char *t;
1075
1076 t = strv_join(e->options, " ");
1077 if (!t)
1078 return log_oom();
1079
1080 printf(" options: %s\n", t);
1081 }
1082 if (e->device_tree)
1083 printf(" devicetree: %s\n", e->device_tree);
1084
1085 puts("");
1086 }
1087
1088 return 0;
1089 }
1090
1091 static int verb_install(int argc, char *argv[], void *userdata) {
1092
1093 sd_id128_t uuid = SD_ID128_NULL;
1094 uint64_t pstart = 0, psize = 0;
1095 uint32_t part = 0;
1096 bool install;
1097 int r;
1098
1099 r = must_be_root();
1100 if (r < 0)
1101 return r;
1102
1103 r = acquire_esp(false, &part, &pstart, &psize, &uuid);
1104 if (r < 0)
1105 return r;
1106
1107 install = streq(argv[0], "install");
1108
1109 RUN_WITH_UMASK(0002) {
1110 r = install_binaries(arg_path, install);
1111 if (r < 0)
1112 return r;
1113
1114 if (install) {
1115 r = install_loader_config(arg_path);
1116 if (r < 0)
1117 return r;
1118 }
1119 }
1120
1121 if (arg_touch_variables)
1122 r = install_variables(arg_path,
1123 part, pstart, psize, uuid,
1124 "/EFI/systemd/systemd-boot" EFI_MACHINE_TYPE_NAME ".efi",
1125 install);
1126
1127 return r;
1128 }
1129
1130 static int verb_remove(int argc, char *argv[], void *userdata) {
1131 sd_id128_t uuid = SD_ID128_NULL;
1132 int r;
1133
1134 r = must_be_root();
1135 if (r < 0)
1136 return r;
1137
1138 r = acquire_esp(false, NULL, NULL, NULL, &uuid);
1139 if (r < 0)
1140 return r;
1141
1142 r = remove_binaries(arg_path);
1143
1144 if (arg_touch_variables) {
1145 int q;
1146
1147 q = remove_variables(uuid, "/EFI/systemd/systemd-boot" EFI_MACHINE_TYPE_NAME ".efi", true);
1148 if (q < 0 && r == 0)
1149 r = q;
1150 }
1151
1152 return r;
1153 }
1154
1155 static int bootctl_main(int argc, char *argv[]) {
1156
1157 static const Verb verbs[] = {
1158 { "help", VERB_ANY, VERB_ANY, 0, help },
1159 { "status", VERB_ANY, 1, VERB_DEFAULT, verb_status },
1160 { "list", VERB_ANY, 1, 0, verb_list },
1161 { "install", VERB_ANY, 1, 0, verb_install },
1162 { "update", VERB_ANY, 1, 0, verb_install },
1163 { "remove", VERB_ANY, 1, 0, verb_remove },
1164 {}
1165 };
1166
1167 return dispatch_verb(argc, argv, verbs, NULL);
1168 }
1169
1170 int main(int argc, char *argv[]) {
1171 int r;
1172
1173 log_parse_environment();
1174 log_open();
1175
1176 /* If we run in a container, automatically turn of EFI file system access */
1177 if (detect_container() > 0)
1178 arg_touch_variables = false;
1179
1180 r = parse_argv(argc, argv);
1181 if (r <= 0)
1182 goto finish;
1183
1184 r = bootctl_main(argc, argv);
1185
1186 finish:
1187 free(arg_path);
1188 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1189 }