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