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