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