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