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