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