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