chiark / gitweb /
boot: efi - add config option to disable the command line editor
[elogind.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         r = parse_argv(argc, argv);
1289         if (r <= 0)
1290                 goto finish;
1291
1292         if (argv[optind]) {
1293                 for (i = 0; i < ELEMENTSOF(verbs); i++) {
1294                         if (!streq(argv[optind], verbs[i].verb))
1295                                 continue;
1296                         arg_action = verbs[i].action;
1297                         break;
1298                 }
1299                 if (i >= ELEMENTSOF(verbs)) {
1300                         fprintf(stderr, "Unknown operation %s\n", argv[optind]);
1301                         r = -EINVAL;
1302                         goto finish;
1303                 }
1304         }
1305
1306         if (!arg_path)
1307                 arg_path = "/boot";
1308
1309         if (geteuid() != 0) {
1310                 fprintf(stderr, "Need to be root.\n");
1311                 r = -EPERM;
1312                 goto finish;
1313         }
1314
1315         r = verify_esp(arg_path, &part, &pstart, &psize, &uuid);
1316         if (r == -ENODEV && !arg_path)
1317                 fprintf(stderr, "You might want to use --path= to indicate the path to your ESP, in case it is not mounted to /boot.\n");
1318         if (r < 0)
1319                 goto finish;
1320
1321         switch (arg_action) {
1322         case ACTION_STATUS: {
1323                 _cleanup_free_ char *fw_type = NULL;
1324                 _cleanup_free_ char *fw_info = NULL;
1325                 _cleanup_free_ char *loader = NULL;
1326                 _cleanup_free_ char *loader_path = NULL;
1327                 sd_id128_t loader_part_uuid = {};
1328
1329                 efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderFirmwareType", &fw_type);
1330                 efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderFirmwareInfo", &fw_info);
1331                 efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderInfo", &loader);
1332                 if (efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderImageIdentifier", &loader_path) > 0)
1333                         efi_tilt_backslashes(loader_path);
1334                 efi_loader_get_device_part_uuid(&loader_part_uuid);
1335
1336                 printf("System:\n");
1337                 printf("     Firmware: %s (%s)\n", fw_type, strna(fw_info));
1338                 printf("  Secure Boot: %s\n", is_efi_secure_boot() ? "enabled" : "disabled");
1339                 printf("   Setup Mode: %s\n", is_efi_secure_boot_setup_mode() ? "setup" : "user");
1340                 printf("\n");
1341
1342                 printf("Loader:\n");
1343                 printf("      Product: %s\n", strna(loader));
1344                 if (!sd_id128_equal(loader_part_uuid, SD_ID128_NULL))
1345                         printf("    Partition: /dev/disk/by-partuuid/%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
1346                                SD_ID128_FORMAT_VAL(loader_part_uuid));
1347                 else
1348                         printf("    Partition: n/a\n");
1349                 printf("         File: %s%s\n", draw_special_char(DRAW_TREE_RIGHT), strna(loader_path));
1350                 printf("\n");
1351
1352                 r = status_binaries(arg_path, uuid);
1353                 if (r < 0)
1354                         goto finish;
1355
1356                 if (arg_touch_variables)
1357                         r = status_variables();
1358                 break;
1359         }
1360
1361         case ACTION_INSTALL:
1362         case ACTION_UPDATE:
1363                 umask(0002);
1364
1365                 r = install_binaries(arg_path, arg_action == ACTION_INSTALL);
1366                 if (r < 0)
1367                         goto finish;
1368
1369                 if (arg_action == ACTION_INSTALL)
1370                         install_loader_config(arg_path);
1371
1372                 if (arg_touch_variables)
1373                         r = install_variables(arg_path,
1374                                               part, pstart, psize, uuid,
1375                                               "/EFI/systemd/systemd-boot" EFI_MACHINE_TYPE_NAME ".efi",
1376                                               arg_action == ACTION_INSTALL);
1377                 break;
1378
1379         case ACTION_REMOVE:
1380                 r = remove_binaries(arg_path);
1381
1382                 if (arg_touch_variables) {
1383                         q = remove_variables(uuid, "/EFI/systemd/systemd-boot" EFI_MACHINE_TYPE_NAME ".efi", true);
1384                         if (q < 0 && r == 0)
1385                                 r = q;
1386                 }
1387                 break;
1388         }
1389
1390 finish:
1391         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1392 }
1393
1394 int main(int argc, char *argv[]) {
1395         int r;
1396
1397         log_parse_environment();
1398         log_open();
1399
1400         r = parse_argv(argc, argv);
1401         if (r <= 0)
1402                 goto finish;
1403
1404         r = bootctl_main(argc, argv);
1405
1406  finish:
1407         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1408 }