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