]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/boot/bootctl.c
tree-wide: make use of fsync_directory_of_file() all over the place
[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, "default %s-*\n", sd_id128_to_string(machine_id, machine_string));
831
832 r = fflush_sync_and_check(f);
833 if (r < 0)
834 return log_error_errno(r, "Failed to write \"%s\": %m", p);
835
836 r = link_tmpfile(fd, t, p);
837 if (r == -EEXIST)
838 return 0; /* Silently skip creation if the file exists now (recheck) */
839 if (r < 0)
840 return log_error_errno(r, "Failed to move \"%s\" into place: %m", p);
841
842 t = mfree(t);
843
844 return 1;
845 }
846
847 static int help(int argc, char *argv[], void *userdata) {
848
849 printf("%s [COMMAND] [OPTIONS...]\n"
850 "\n"
851 "Install, update or remove the systemd-boot EFI boot manager.\n\n"
852 " -h --help Show this help\n"
853 " --version Print version\n"
854 " --path=PATH Path to the EFI System Partition (ESP)\n"
855 " -p --print-path Print path to the EFI partition\n"
856 " --no-variables Don't touch EFI variables\n"
857 "\n"
858 "Commands:\n"
859 " status Show status of installed systemd-boot and EFI variables\n"
860 " list List boot entries\n"
861 " install Install systemd-boot to the ESP and EFI variables\n"
862 " update Update systemd-boot in the ESP and EFI variables\n"
863 " remove Remove systemd-boot from the ESP and EFI variables\n",
864 program_invocation_short_name);
865
866 return 0;
867 }
868
869 static int parse_argv(int argc, char *argv[]) {
870 enum {
871 ARG_PATH = 0x100,
872 ARG_VERSION,
873 ARG_NO_VARIABLES,
874 };
875
876 static const struct option options[] = {
877 { "help", no_argument, NULL, 'h' },
878 { "version", no_argument, NULL, ARG_VERSION },
879 { "path", required_argument, NULL, ARG_PATH },
880 { "print-path", no_argument, NULL, 'p' },
881 { "no-variables", no_argument, NULL, ARG_NO_VARIABLES },
882 { NULL, 0, NULL, 0 }
883 };
884
885 int c, r;
886
887 assert(argc >= 0);
888 assert(argv);
889
890 while ((c = getopt_long(argc, argv, "hp", options, NULL)) >= 0)
891 switch (c) {
892
893 case 'h':
894 help(0, NULL, NULL);
895 return 0;
896
897 case ARG_VERSION:
898 return version();
899
900 case ARG_PATH:
901 r = free_and_strdup(&arg_path, optarg);
902 if (r < 0)
903 return log_oom();
904 break;
905
906 case 'p':
907 arg_print_path = true;
908 break;
909
910 case ARG_NO_VARIABLES:
911 arg_touch_variables = false;
912 break;
913
914 case '?':
915 return -EINVAL;
916
917 default:
918 assert_not_reached("Unknown option");
919 }
920
921 return 1;
922 }
923
924 static void read_loader_efi_var(const char *name, char **var) {
925 int r;
926
927 r = efi_get_variable_string(EFI_VENDOR_LOADER, name, var);
928 if (r < 0 && r != -ENOENT)
929 log_warning_errno(r, "Failed to read EFI variable %s: %m", name);
930 }
931
932 static int verb_status(int argc, char *argv[], void *userdata) {
933
934 sd_id128_t uuid = SD_ID128_NULL;
935 int r, k;
936
937 r = acquire_esp(geteuid() != 0, NULL, NULL, NULL, &uuid);
938
939 if (arg_print_path) {
940 if (r == -EACCES) /* If we couldn't acquire the ESP path, log about access errors (which is the only
941 * error the find_esp_and_warn() won't log on its own) */
942 return log_error_errno(r, "Failed to determine ESP: %m");
943 if (r < 0)
944 return r;
945
946 puts(arg_path);
947 return 0;
948 }
949
950 r = 0; /* If we couldn't determine the path, then don't consider that a problem from here on, just show what we
951 * can show */
952
953 if (is_efi_boot()) {
954 _cleanup_free_ char *fw_type = NULL, *fw_info = NULL, *loader = NULL, *loader_path = NULL, *stub = NULL;
955 sd_id128_t loader_part_uuid = SD_ID128_NULL;
956
957 read_loader_efi_var("LoaderFirmwareType", &fw_type);
958 read_loader_efi_var("LoaderFirmwareInfo", &fw_info);
959 read_loader_efi_var("LoaderInfo", &loader);
960 read_loader_efi_var("StubInfo", &stub);
961 read_loader_efi_var("LoaderImageIdentifier", &loader_path);
962
963 if (loader_path)
964 efi_tilt_backslashes(loader_path);
965
966 k = efi_loader_get_device_part_uuid(&loader_part_uuid);
967 if (k < 0 && k != -ENOENT)
968 r = log_warning_errno(k, "Failed to read EFI variable LoaderDevicePartUUID: %m");
969
970 printf("System:\n");
971 printf(" Firmware: %s (%s)\n", strna(fw_type), strna(fw_info));
972
973 k = is_efi_secure_boot();
974 if (k < 0)
975 r = log_warning_errno(k, "Failed to query secure boot status: %m");
976 else
977 printf(" Secure Boot: %sd\n", enable_disable(k));
978
979 k = is_efi_secure_boot_setup_mode();
980 if (k < 0)
981 r = log_warning_errno(k, "Failed to query secure boot mode: %m");
982 else
983 printf(" Setup Mode: %s\n", k ? "setup" : "user");
984 printf("\n");
985
986 printf("Current Loader:\n");
987 printf(" Product: %s\n", strna(loader));
988 if (stub)
989 printf(" Stub: %s\n", stub);
990 if (!sd_id128_is_null(loader_part_uuid))
991 printf(" ESP: /dev/disk/by-partuuid/%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
992 SD_ID128_FORMAT_VAL(loader_part_uuid));
993 else
994 printf(" ESP: n/a\n");
995 printf(" File: %s%s\n", special_glyph(TREE_RIGHT), strna(loader_path));
996 printf("\n");
997 } else
998 printf("System:\n Not booted with EFI\n\n");
999
1000 if (arg_path) {
1001 k = status_binaries(arg_path, uuid);
1002 if (k < 0)
1003 r = k;
1004 }
1005
1006 if (is_efi_boot()) {
1007 k = status_variables();
1008 if (k < 0)
1009 r = k;
1010 }
1011
1012 if (arg_path) {
1013 k = status_entries(arg_path, uuid);
1014 if (k < 0)
1015 r = k;
1016 }
1017
1018 return r;
1019 }
1020
1021 static int verb_list(int argc, char *argv[], void *userdata) {
1022 _cleanup_(boot_config_free) BootConfig config = {};
1023 sd_id128_t uuid = SD_ID128_NULL;
1024 unsigned n;
1025 int r;
1026
1027 /* If we lack privileges we invoke find_esp_and_warn() in "unprivileged mode" here, which does two things: turn
1028 * off logging about access errors and turn off potentially privileged device probing. Here we're interested in
1029 * the latter but not the former, hence request the mode, and log about EACCES. */
1030
1031 r = acquire_esp(geteuid() != 0, NULL, NULL, NULL, &uuid);
1032 if (r == -EACCES) /* We really need the ESP path for this call, hence also log about access errors */
1033 return log_error_errno(r, "Failed to determine ESP: %m");
1034 if (r < 0)
1035 return r;
1036
1037 r = boot_entries_load_config(arg_path, &config);
1038 if (r < 0)
1039 return log_error_errno(r, "Failed to load bootspec config from \"%s/loader\": %m",
1040 arg_path);
1041
1042 printf("Available boot entries:\n");
1043
1044 for (n = 0; n < config.n_entries; n++) {
1045 const BootEntry *e = &config.entries[n];
1046
1047 printf(" title: %s%s%s%s%s%s\n",
1048 ansi_highlight(),
1049 boot_entry_title(e),
1050 ansi_normal(),
1051 ansi_highlight_green(),
1052 n == (unsigned) config.default_entry ? " (default)" : "",
1053 ansi_normal());
1054 if (e->version)
1055 printf(" version: %s\n", e->version);
1056 if (e->machine_id)
1057 printf(" machine-id: %s\n", e->machine_id);
1058 if (e->architecture)
1059 printf(" architecture: %s\n", e->architecture);
1060 if (e->kernel)
1061 printf(" linux: %s\n", e->kernel);
1062 if (!strv_isempty(e->initrd)) {
1063 _cleanup_free_ char *t;
1064
1065 t = strv_join(e->initrd, " ");
1066 if (!t)
1067 return log_oom();
1068
1069 printf(" initrd: %s\n", t);
1070 }
1071 if (!strv_isempty(e->options)) {
1072 _cleanup_free_ char *t;
1073
1074 t = strv_join(e->options, " ");
1075 if (!t)
1076 return log_oom();
1077
1078 printf(" options: %s\n", t);
1079 }
1080 if (e->device_tree)
1081 printf(" devicetree: %s\n", e->device_tree);
1082
1083 puts("");
1084 }
1085
1086 return 0;
1087 }
1088
1089 static int verb_install(int argc, char *argv[], void *userdata) {
1090
1091 sd_id128_t uuid = SD_ID128_NULL;
1092 uint64_t pstart = 0, psize = 0;
1093 uint32_t part = 0;
1094 bool install;
1095 int r;
1096
1097 r = acquire_esp(false, &part, &pstart, &psize, &uuid);
1098 if (r < 0)
1099 return r;
1100
1101 install = streq(argv[0], "install");
1102
1103 RUN_WITH_UMASK(0002) {
1104 r = install_binaries(arg_path, install);
1105 if (r < 0)
1106 return r;
1107
1108 if (install) {
1109 r = install_loader_config(arg_path);
1110 if (r < 0)
1111 return r;
1112 }
1113 }
1114
1115 if (arg_touch_variables)
1116 r = install_variables(arg_path,
1117 part, pstart, psize, uuid,
1118 "/EFI/systemd/systemd-boot" EFI_MACHINE_TYPE_NAME ".efi",
1119 install);
1120
1121 return r;
1122 }
1123
1124 static int verb_remove(int argc, char *argv[], void *userdata) {
1125 sd_id128_t uuid = SD_ID128_NULL;
1126 int r;
1127
1128 r = acquire_esp(false, NULL, NULL, NULL, &uuid);
1129 if (r < 0)
1130 return r;
1131
1132 r = remove_binaries(arg_path);
1133
1134 if (arg_touch_variables) {
1135 int q;
1136
1137 q = remove_variables(uuid, "/EFI/systemd/systemd-boot" EFI_MACHINE_TYPE_NAME ".efi", true);
1138 if (q < 0 && r == 0)
1139 r = q;
1140 }
1141
1142 return r;
1143 }
1144
1145 static int bootctl_main(int argc, char *argv[]) {
1146
1147 static const Verb verbs[] = {
1148 { "help", VERB_ANY, VERB_ANY, 0, help },
1149 { "status", VERB_ANY, 1, VERB_DEFAULT, verb_status },
1150 { "list", VERB_ANY, 1, 0, verb_list },
1151 { "install", VERB_ANY, 1, VERB_MUST_BE_ROOT, verb_install },
1152 { "update", VERB_ANY, 1, VERB_MUST_BE_ROOT, verb_install },
1153 { "remove", VERB_ANY, 1, VERB_MUST_BE_ROOT, verb_remove },
1154 {}
1155 };
1156
1157 return dispatch_verb(argc, argv, verbs, NULL);
1158 }
1159
1160 int main(int argc, char *argv[]) {
1161 int r;
1162
1163 log_parse_environment();
1164 log_open();
1165
1166 /* If we run in a container, automatically turn of EFI file system access */
1167 if (detect_container() > 0)
1168 arg_touch_variables = false;
1169
1170 r = parse_argv(argc, argv);
1171 if (r <= 0)
1172 goto finish;
1173
1174 r = bootctl_main(argc, argv);
1175
1176 finish:
1177 free(arg_path);
1178 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1179 }