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