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