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