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