]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/boot/bootctl.c
verbs: add a new VERB_MUSTBEROOT flag
[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 verb_status(int argc, char *argv[], void *userdata) {
929
930 sd_id128_t uuid = SD_ID128_NULL;
931 int r, k;
932
933 r = acquire_esp(geteuid() != 0, NULL, NULL, NULL, &uuid);
934
935 if (arg_print_path) {
936 if (r == -EACCES) /* If we couldn't acquire the ESP path, log about access errors (which is the only
937 * error the find_esp_and_warn() won't log on its own) */
938 return log_error_errno(r, "Failed to determine ESP: %m");
939 if (r < 0)
940 return r;
941
942 puts(arg_path);
943 return 0;
944 }
945
946 r = 0; /* If we couldn't determine the path, then don't consider that a problem from here on, just show what we
947 * can show */
948
949 if (is_efi_boot()) {
950 _cleanup_free_ char *fw_type = NULL, *fw_info = NULL, *loader = NULL, *loader_path = NULL;
951 sd_id128_t loader_part_uuid = SD_ID128_NULL;
952
953 read_loader_efi_var("LoaderFirmwareType", &fw_type);
954 read_loader_efi_var("LoaderFirmwareInfo", &fw_info);
955 read_loader_efi_var("LoaderInfo", &loader);
956 read_loader_efi_var("LoaderImageIdentifier", &loader_path);
957
958 if (loader_path)
959 efi_tilt_backslashes(loader_path);
960
961 k = efi_loader_get_device_part_uuid(&loader_part_uuid);
962 if (k < 0 && k != -ENOENT)
963 r = log_warning_errno(k, "Failed to read EFI variable LoaderDevicePartUUID: %m");
964
965 printf("System:\n");
966 printf(" Firmware: %s (%s)\n", strna(fw_type), strna(fw_info));
967
968 k = is_efi_secure_boot();
969 if (k < 0)
970 r = log_warning_errno(k, "Failed to query secure boot status: %m");
971 else
972 printf(" Secure Boot: %sd\n", enable_disable(k));
973
974 k = is_efi_secure_boot_setup_mode();
975 if (k < 0)
976 r = log_warning_errno(k, "Failed to query secure boot mode: %m");
977 else
978 printf(" Setup Mode: %s\n", k ? "setup" : "user");
979 printf("\n");
980
981 printf("Current Loader:\n");
982 printf(" Product: %s\n", strna(loader));
983 if (!sd_id128_is_null(loader_part_uuid))
984 printf(" ESP: /dev/disk/by-partuuid/%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
985 SD_ID128_FORMAT_VAL(loader_part_uuid));
986 else
987 printf(" ESP: n/a\n");
988 printf(" File: %s%s\n", special_glyph(TREE_RIGHT), strna(loader_path));
989 printf("\n");
990 } else
991 printf("System:\n Not booted with EFI\n\n");
992
993 if (arg_path) {
994 k = status_binaries(arg_path, uuid);
995 if (k < 0)
996 r = k;
997 }
998
999 if (is_efi_boot()) {
1000 k = status_variables();
1001 if (k < 0)
1002 r = k;
1003 }
1004
1005 if (arg_path) {
1006 k = status_entries(arg_path, uuid);
1007 if (k < 0)
1008 r = k;
1009 }
1010
1011 return r;
1012 }
1013
1014 static int verb_list(int argc, char *argv[], void *userdata) {
1015 _cleanup_(boot_config_free) BootConfig config = {};
1016 sd_id128_t uuid = SD_ID128_NULL;
1017 unsigned n;
1018 int r;
1019
1020 /* If we lack privileges we invoke find_esp_and_warn() in "unprivileged mode" here, which does two things: turn
1021 * off logging about access errors and turn off potentially privileged device probing. Here we're interested in
1022 * the latter but not the former, hence request the mode, and log about EACCES. */
1023
1024 r = acquire_esp(geteuid() != 0, NULL, NULL, NULL, &uuid);
1025 if (r == -EACCES) /* We really need the ESP path for this call, hence also log about access errors */
1026 return log_error_errno(r, "Failed to determine ESP: %m");
1027 if (r < 0)
1028 return r;
1029
1030 r = boot_entries_load_config(arg_path, &config);
1031 if (r < 0)
1032 return log_error_errno(r, "Failed to load bootspec config from \"%s/loader\": %m",
1033 arg_path);
1034
1035 printf("Available boot entries:\n");
1036
1037 for (n = 0; n < config.n_entries; n++) {
1038 const BootEntry *e = &config.entries[n];
1039
1040 printf(" title: %s%s%s%s%s%s\n",
1041 ansi_highlight(),
1042 boot_entry_title(e),
1043 ansi_normal(),
1044 ansi_highlight_green(),
1045 n == config.default_entry ? " (default)" : "",
1046 ansi_normal());
1047 if (e->version)
1048 printf(" version: %s\n", e->version);
1049 if (e->machine_id)
1050 printf(" machine-id: %s\n", e->machine_id);
1051 if (e->architecture)
1052 printf(" architecture: %s\n", e->architecture);
1053 if (e->kernel)
1054 printf(" linux: %s\n", e->kernel);
1055 if (!strv_isempty(e->initrd)) {
1056 _cleanup_free_ char *t;
1057
1058 t = strv_join(e->initrd, " ");
1059 if (!t)
1060 return log_oom();
1061
1062 printf(" initrd: %s\n", t);
1063 }
1064 if (!strv_isempty(e->options)) {
1065 _cleanup_free_ char *t;
1066
1067 t = strv_join(e->options, " ");
1068 if (!t)
1069 return log_oom();
1070
1071 printf(" options: %s\n", t);
1072 }
1073 if (e->device_tree)
1074 printf(" devicetree: %s\n", e->device_tree);
1075
1076 puts("");
1077 }
1078
1079 return 0;
1080 }
1081
1082 static int verb_install(int argc, char *argv[], void *userdata) {
1083
1084 sd_id128_t uuid = SD_ID128_NULL;
1085 uint64_t pstart = 0, psize = 0;
1086 uint32_t part = 0;
1087 bool install;
1088 int r;
1089
1090 r = acquire_esp(false, &part, &pstart, &psize, &uuid);
1091 if (r < 0)
1092 return r;
1093
1094 install = streq(argv[0], "install");
1095
1096 RUN_WITH_UMASK(0002) {
1097 r = install_binaries(arg_path, install);
1098 if (r < 0)
1099 return r;
1100
1101 if (install) {
1102 r = install_loader_config(arg_path);
1103 if (r < 0)
1104 return r;
1105 }
1106 }
1107
1108 if (arg_touch_variables)
1109 r = install_variables(arg_path,
1110 part, pstart, psize, uuid,
1111 "/EFI/systemd/systemd-boot" EFI_MACHINE_TYPE_NAME ".efi",
1112 install);
1113
1114 return r;
1115 }
1116
1117 static int verb_remove(int argc, char *argv[], void *userdata) {
1118 sd_id128_t uuid = SD_ID128_NULL;
1119 int r;
1120
1121 r = acquire_esp(false, NULL, NULL, NULL, &uuid);
1122 if (r < 0)
1123 return r;
1124
1125 r = remove_binaries(arg_path);
1126
1127 if (arg_touch_variables) {
1128 int q;
1129
1130 q = remove_variables(uuid, "/EFI/systemd/systemd-boot" EFI_MACHINE_TYPE_NAME ".efi", true);
1131 if (q < 0 && r == 0)
1132 r = q;
1133 }
1134
1135 return r;
1136 }
1137
1138 static int bootctl_main(int argc, char *argv[]) {
1139
1140 static const Verb verbs[] = {
1141 { "help", VERB_ANY, VERB_ANY, 0, help },
1142 { "status", VERB_ANY, 1, VERB_DEFAULT, verb_status },
1143 { "list", VERB_ANY, 1, 0, verb_list },
1144 { "install", VERB_ANY, 1, VERB_MUSTBEROOT, verb_install },
1145 { "update", VERB_ANY, 1, VERB_MUSTBEROOT, verb_install },
1146 { "remove", VERB_ANY, 1, VERB_MUSTBEROOT, verb_remove },
1147 {}
1148 };
1149
1150 return dispatch_verb(argc, argv, verbs, NULL);
1151 }
1152
1153 int main(int argc, char *argv[]) {
1154 int r;
1155
1156 log_parse_environment();
1157 log_open();
1158
1159 /* If we run in a container, automatically turn of EFI file system access */
1160 if (detect_container() > 0)
1161 arg_touch_variables = false;
1162
1163 r = parse_argv(argc, argv);
1164 if (r <= 0)
1165 goto finish;
1166
1167 r = bootctl_main(argc, argv);
1168
1169 finish:
1170 free(arg_path);
1171 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1172 }