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