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