1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Lennart Poettering
7 Copyright 2013 Kay Sievers
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.
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.
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/>.
28 #include <sys/statfs.h>
43 #define ELEMENTSOF(x) (sizeof(x)/sizeof((x)[0]))
44 #define streq(a,b) (strcmp((a),(b)) == 0)
46 static inline bool isempty(const char *p) {
50 static inline const char *strna(const char *s) {
51 return isempty(s) ? "n/a" : s;
54 static int help(void) {
55 printf("%s [COMMAND] [OPTIONS...]\n"
57 "Install, update or remove the Gummiboot EFI boot loader.\n\n"
58 " -h --help Show this help\n"
59 " --path=PATH Path to the EFI System Partition (ESP)\n"
60 " --no-variables Don't touch EFI variables\n"
63 " install Install Gummiboot to the ESP and EFI variables\n"
64 " update Update Gummiboot in the ESP and EFI variables\n"
65 " remove Remove Gummiboot from the ESP and EFI variables\n",
66 program_invocation_short_name);
71 static int uuid_parse(const char *s, uint8_t uuid[16]) {
75 if (sscanf(s, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
76 &u[0], &u[1], &u[2], &u[3], &u[4], &u[5], &u[6], &u[7],
77 &u[8], &u[9], &u[10], &u[11], &u[12], &u[13], &u[14], &u[15]) != 16)
80 for (i = 0; i < 16; i++)
86 static int verify_esp(const char *p, uint32_t *part, uint64_t *pstart, uint64_t *psize, uint8_t uuid[16]) {
94 if (statfs(p, &sfs) < 0) {
95 fprintf(stderr, "Failed to check file system type of %s: %m\n", p);
99 if (sfs.f_type != 0x4d44) {
100 fprintf(stderr, "File system %s is not a FAT EFI System Partition (ESP) file system.\n", p);
104 if (stat(p, &st) < 0) {
105 fprintf(stderr, "Failed to determine block device node of %s: %m\n", p);
109 if (major(st.st_dev) == 0) {
110 fprintf(stderr, "Block device node of %p is invalid.\n", p);
114 r = asprintf(&t, "%s/..", p);
116 fprintf(stderr, "Out of memory.\n");
123 fprintf(stderr, "Failed to determine block device node of parent of %s: %m\n", p);
127 if (st.st_dev == st2.st_dev) {
128 fprintf(stderr, "Directory %s is not the root of the EFI System Partition (ESP) file system.\n", p);
132 r = asprintf(&t, "/dev/block/%u:%u", major(st.st_dev), minor(st.st_dev));
134 fprintf(stderr, "Out of memory.\n");
139 b = blkid_new_probe_from_filename(t);
143 fprintf(stderr, "Failed to open file system %s: %m\n", p);
147 fprintf(stderr, "Out of memory.\n");
151 blkid_probe_enable_superblocks(b, 1);
152 blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE);
153 blkid_probe_enable_partitions(b, 1);
154 blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
157 r = blkid_do_safeprobe(b);
159 fprintf(stderr, "File system %s is ambigious.\n", p);
163 fprintf(stderr, "File system %s does not contain a label.\n", p);
167 r = errno ? -errno : -EIO;
168 fprintf(stderr, "Failed to probe file system %s: %s\n", p, strerror(-r));
173 r = blkid_probe_lookup_value(b, "TYPE", &v, NULL);
175 r = errno ? -errno : -EIO;
176 fprintf(stderr, "Failed to probe file system type %s: %s\n", p, strerror(-r));
180 if (strcmp(v, "vfat") != 0) {
181 fprintf(stderr, "File system %s is not a FAT EFI System Partition (ESP) file system after all.\n", p);
187 r = blkid_probe_lookup_value(b, "PART_ENTRY_SCHEME", &v, NULL);
189 r = errno ? -errno : -EIO;
190 fprintf(stderr, "Failed to probe partition scheme %s: %s\n", p, strerror(-r));
194 if (strcmp(v, "gpt") != 0) {
195 fprintf(stderr, "File system %s is not on a GPT partition table.\n", p);
201 r = blkid_probe_lookup_value(b, "PART_ENTRY_TYPE", &v, NULL);
203 r = errno ? -errno : -EIO;
204 fprintf(stderr, "Failed to probe partition type UUID %s: %s\n", p, strerror(-r));
208 if (strcmp(v, "c12a7328-f81f-11d2-ba4b-00a0c93ec93b") != 0) {
210 fprintf(stderr, "File system %s is not an EFI System Partition (ESP).\n", p);
215 r = blkid_probe_lookup_value(b, "PART_ENTRY_UUID", &v, NULL);
217 r = errno ? -errno : -EIO;
218 fprintf(stderr, "Failed to probe partition entry UUID %s: %s\n", p, strerror(-r));
224 r = blkid_probe_lookup_value(b, "PART_ENTRY_NUMBER", &v, NULL);
226 r = errno ? -errno : -EIO;
227 fprintf(stderr, "Failed to probe partition number %s: %s\n", p, strerror(-r));
230 *part = strtoul(v, NULL, 10);
233 r = blkid_probe_lookup_value(b, "PART_ENTRY_OFFSET", &v, NULL);
235 r = errno ? -errno : -EIO;
236 fprintf(stderr, "Failed to probe partition offset %s: %s\n", p, strerror(-r));
239 *pstart = strtoul(v, NULL, 10);
242 r = blkid_probe_lookup_value(b, "PART_ENTRY_SIZE", &v, NULL);
244 r = errno ? -errno : -EIO;
245 fprintf(stderr, "Failed to probe partition size %s: %s\n", p, strerror(-r));
248 *psize = strtoul(v, NULL, 10);
258 /* search for "#### LoaderInfo: gummiboot 31 ####" string inside the binary */
259 static int get_file_version(FILE *f, char **v) {
269 if (fstat(fileno(f), &st) < 0)
275 buf = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fileno(f), 0);
276 if (buf == MAP_FAILED)
279 s = memmem(buf, st.st_size - 8, "#### LoaderInfo: ", 17);
284 e = memmem(s, st.st_size - (s - buf), " ####", 5);
285 if (!e || e - s < 3) {
286 fprintf(stderr, "Malformed version string.\n");
291 x = strndup(s, e - s);
293 fprintf(stderr, "Out of memory.\n");
300 munmap(buf, st.st_size);
305 static int enumerate_binaries(const char *esp_path, const char *path, const char *prefix) {
307 char *p = NULL, *q = NULL;
311 if (asprintf(&p, "%s/%s", esp_path, path) < 0) {
312 fprintf(stderr, "Out of memory.\n");
319 if (errno == ENOENT) {
324 fprintf(stderr, "Failed to read %s: %m\n", p);
329 while ((de = readdir(d))) {
334 if (de->d_name[0] == '.')
337 n = strlen(de->d_name);
338 if (n < 4 || strcasecmp(de->d_name + n - 4, ".efi") != 0)
341 if (prefix && strncasecmp(de->d_name, prefix, strlen(prefix)) != 0)
346 if (asprintf(&q, "%s/%s/%s", esp_path, path, de->d_name) < 0) {
347 fprintf(stderr, "Out of memory.\n");
354 fprintf(stderr, "Failed to open %s for reading: %m\n", q);
359 r = get_file_version(f, &v);
366 printf("\t%s (Unknown product and version)\n", q);
368 printf("\t%s (%s)\n", q, v);
387 static int status_binaries(const char *esp_path) {
390 printf("Boot Loader Binaries found in ESP:\n");
392 r = enumerate_binaries(esp_path, "EFI/gummiboot", NULL);
394 fprintf(stderr, "\tGummiboot not installed in ESP.\n");
398 r = enumerate_binaries(esp_path, "EFI/BOOT", "BOOT");
400 fprintf(stderr, "\tNo fallback for removable devices installed in ESP.\n");
407 static int print_efi_option(uint16_t id, bool in_order) {
410 uint8_t partition[16];
413 r = efi_get_boot_option(id, &title, partition, &path);
415 fprintf(stderr, "Failed to read EFI boot entry %i.\n", id);
419 printf("\t%s%s\n", strna(title), in_order ? " [ENABLED]" : "");
421 printf("\t\t%s\n", path);
422 printf("\t\t/dev/disk/by-partuuid/%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
423 partition[0], partition[1], partition[2], partition[3], partition[4], partition[5], partition[6], partition[7],
424 partition[8], partition[9], partition[10], partition[11], partition[12], partition[13], partition[14], partition[15]);
433 static int status_variables(void) {
434 int n_options, n_order;
435 uint16_t *options = NULL, *order = NULL;
438 if (!is_efi_boot()) {
439 fprintf(stderr, "Not booted with EFI, not showing EFI variables.\n");
443 printf("\nBoot Entries found in EFI variables:\n");
445 n_options = efi_get_boot_options(&options);
447 if (n_options == -ENOENT)
448 fprintf(stderr, "\tFailed to access EFI variables. Is the \"efivarfs\" filesystem mounted?\n");
450 fprintf(stderr, "\tFailed to read EFI boot entries.\n");
455 n_order = efi_get_boot_order(&order);
456 if (n_order == -ENOENT) {
457 fprintf(stderr, "\tNo boot entries registered in EFI variables.\n");
460 } else if (n_order < 0) {
461 fprintf(stderr, "\tFailed to read EFI boot order.\n");
466 for (i = 0; i < n_order; i++) {
467 r = print_efi_option(order[i], true);
472 for (i = 0; i < n_options; i++) {
476 for (j = 0; j < n_order; j++)
477 if (options[i] == order[j]) {
485 r = print_efi_option(options[i], false);
498 static int compare_product(const char *a, const char *b) {
507 return x < y ? -1 : x > y ? 1 : 0;
509 return strncmp(a, b, x);
512 static int compare_version(const char *a, const char *b) {
516 a += strcspn(a, " ");
518 b += strcspn(b, " ");
521 return strverscmp(a, b);
524 static int version_check(FILE *f, const char *from, const char *to) {
526 char *a = NULL, *b = NULL;
533 r = get_file_version(f, &a);
538 fprintf(stderr, "Source file %s does not carry version information!\n", from);
544 if (errno == ENOENT) {
550 fprintf(stderr, "Failed to open %s for reading: %m\n", to);
554 r = get_file_version(g, &b);
557 if (r == 0 || compare_product(a, b) != 0) {
559 fprintf(stderr, "Skipping %s, since it's owned by another boot loader.\n", to);
563 if (compare_version(a, b) < 0) {
565 fprintf(stderr, "Skipping %s, since it's a newer boot loader version already.\n", to);
579 static int copy_file(const char *from, const char *to, bool force) {
580 FILE *f = NULL, *g = NULL;
583 struct timespec t[2];
589 f = fopen(from, "re");
591 fprintf(stderr, "Failed to open %s for reading: %m\n", from);
596 /* If this is an update, then let's compare versions first */
597 r = version_check(f, from, to);
602 if (asprintf(&p, "%s~", to) < 0) {
603 fprintf(stderr, "Out of memory.\n");
610 /* Directory doesn't exist yet? Then let's skip this... */
611 if (!force && errno == ENOENT) {
616 fprintf(stderr, "Failed to open %s for writing: %m\n", to);
624 uint8_t buf[32*1024];
626 k = fread(buf, 1, sizeof(buf), f);
628 fprintf(stderr, "Failed to read %s: %m\n", from);
635 fwrite(buf, 1, k, g);
637 fprintf(stderr, "Failed to write %s: %m\n", to);
645 fprintf(stderr, "Failed to write %s: %m\n", to);
650 r = fstat(fileno(f), &st);
652 fprintf(stderr, "Failed to get file timestamps of %s: %m", from);
660 r = futimens(fileno(g), t);
662 fprintf(stderr, "Failed to change file timestamps for %s: %m", p);
667 if (rename(p, to) < 0) {
668 fprintf(stderr, "Failed to rename %s to %s: %m\n", p, to);
673 fprintf(stderr, "Copied %s to %s.\n", from, to);
691 static char* strupper(char *s) {
700 static int mkdir_one(const char *prefix, const char *suffix) {
703 if (asprintf(&p, "%s/%s", prefix, suffix) < 0) {
704 fprintf(stderr, "Out of memory.\n");
708 if (mkdir(p, 0700) < 0) {
709 if (errno != EEXIST) {
710 fprintf(stderr, "Failed to create %s: %m\n", p);
715 fprintf(stderr, "Created %s.\n", p);
721 static int create_dirs(const char *esp_path) {
724 r = mkdir_one(esp_path, "EFI");
728 r = mkdir_one(esp_path, "EFI/gummiboot");
732 r = mkdir_one(esp_path, "EFI/BOOT");
736 r = mkdir_one(esp_path, "loader");
740 r = mkdir_one(esp_path, "loader/entries");
747 static int copy_one_file(const char *esp_path, const char *name, bool force) {
748 char *p = NULL, *q = NULL, *v = NULL;
751 if (asprintf(&p, "/usr/lib/gummiboot/%s", name) < 0) {
752 fprintf(stderr, "Out of memory.\n");
757 if (asprintf(&q, "%s/EFI/gummiboot/%s", esp_path, name) < 0) {
758 fprintf(stderr, "Out of memory.\n");
763 r = copy_file(p, q, force);
765 if (strncmp(name, "gummiboot", 9) == 0) {
768 /* Create the fallback names for removable devices */
769 if (asprintf(&v, "%s/EFI/BOOT/%s", esp_path, name + 5) < 0) {
770 fprintf(stderr, "Out of memory.\n");
774 strupper(strrchr(v, '/') + 1);
776 k = copy_file(p, v, force);
777 if (k < 0 && r == 0) {
790 static int install_binaries(const char *esp_path, bool force) {
796 /* Don't create any of these directories when we are
797 * just updating. When we update we'll drop-in our
798 * files (unless there are newer ones already), but we
799 * won't create the directories for them in the first
801 r = create_dirs(esp_path);
806 d = opendir("/usr/lib/gummiboot");
808 fprintf(stderr, "Failed to open /usr/lib/gummiboot: %m\n");
812 while ((de = readdir(d))) {
816 if (de->d_name[0] == '.')
819 n = strlen(de->d_name);
820 if (n < 4 || strcmp(de->d_name + n - 4, ".efi") != 0)
823 k = copy_one_file(esp_path, de->d_name, force);
832 static bool same_entry(uint16_t id, const uint8_t uuid[16], const char *path) {
838 err = efi_get_boot_option(id, NULL, ouuid, &opath);
841 if (memcmp(uuid, ouuid, 16) != 0)
844 if (!streq(path, opath))
854 static int find_slot(const uint8_t uuid[16], const char *path, uint16_t *id) {
855 uint16_t *options = NULL;
859 bool existing = false;
861 n_options = efi_get_boot_options(&options);
865 /* find already existing gummiboot entry */
866 for (i = 0; i < n_options; i++)
867 if (same_entry(options[i], uuid, path)) {
873 /* find free slot in the sorted BootXXXX variable list */
874 for (i = 0; i < n_options; i++)
875 if (i != options[i]) {
886 static int insert_into_order(uint16_t slot, bool first) {
887 uint16_t *order = NULL;
893 n_order = efi_get_boot_order(&order);
895 err = efi_set_boot_order(&slot, 1);
899 /* are we already in the boot order? */
900 for (i = 0; i < n_order; i++)
901 if (order[i] == slot)
905 new_order = realloc(order, (n_order+1) * sizeof(uint16_t));
912 /* add to the top or end of the list */
914 memmove(&order[1], order, n_order * sizeof(uint16_t));
917 order[n_order] = slot;
919 efi_set_boot_order(order, n_order+1);
926 static int remove_from_order(uint16_t slot) {
927 uint16_t *order = NULL;
932 n_order = efi_get_boot_order(&order);
938 for (i = 0; i < n_order; i++) {
939 if (order[i] != slot)
943 memmove(&order[i], &order[i+1], (n_order - i) * sizeof(uint16_t));
944 efi_set_boot_order(order, n_order-1);
952 static int install_variables(const char *esp_path,
953 uint32_t part, uint64_t pstart, uint64_t psize,
954 const uint8_t uuid[16], const char *path,
957 uint16_t *options = NULL;
961 if (!is_efi_boot()) {
962 fprintf(stderr, "Not booted with EFI, skipping EFI variable checks.\n");
966 if (asprintf(&p, "%s%s", esp_path, path) < 0) {
967 fprintf(stderr, "Out of memory.\n");
971 if (access(p, F_OK) < 0) {
979 r = find_slot(uuid, path, &slot);
982 fprintf(stderr, "Failed to access EFI variables. Is the \"efivarfs\" filesystem mounted?\n");
984 fprintf(stderr, "Failed to determine current boot order: %s\n", strerror(-r));
988 if (force || r == false) {
989 r = efi_add_boot_option(slot,
990 "Linux Boot Manager",
994 fprintf(stderr, "Failed to create EFI Boot variable entry: %s\n", strerror(-r));
997 fprintf(stderr, "Created EFI Boot entry \"Linux Boot Manager\".\n");
999 insert_into_order(slot, force);
1007 static int delete_nftw(const char *path, const struct stat *sb, int typeflag, struct FTW *ftw) {
1010 if (typeflag == FTW_D || typeflag == FTW_DNR || typeflag == FTW_DP)
1016 fprintf(stderr, "Failed to remove %s: %m\n", path);
1018 fprintf(stderr, "Removed %s.\n", path);
1023 static int rm_rf(const char *p) {
1024 nftw(p, delete_nftw, 20, FTW_DEPTH|FTW_MOUNT|FTW_PHYS);
1028 static int remove_boot_efi(const char *esp_path) {
1030 char *p = NULL, *q = NULL;
1034 if (asprintf(&p, "%s/EFI/BOOT", esp_path) < 0) {
1035 fprintf(stderr, "Out of memory.\n");
1041 if (errno == ENOENT) {
1046 fprintf(stderr, "Failed to read %s: %m\n", p);
1051 while ((de = readdir(d))) {
1056 if (de->d_name[0] == '.')
1059 n = strlen(de->d_name);
1060 if (n < 4 || strcasecmp(de->d_name + n - 4, ".EFI") != 0)
1063 if (strncasecmp(de->d_name, "BOOT", 4) != 0)
1068 if (asprintf(&q, "%s/%s", p, de->d_name) < 0) {
1069 fprintf(stderr, "Out of memory.\n");
1076 fprintf(stderr, "Failed to open %s for reading: %m\n", q);
1081 r = get_file_version(f, &v);
1087 if (r > 0 && strncmp(v, "gummiboot ", 10) == 0) {
1091 fprintf(stderr, "Failed to remove %s: %m\n", q);
1096 fprintf(stderr, "Removed %s.\n", q);
1114 static int rmdir_one(const char *prefix, const char *suffix) {
1117 if (asprintf(&p, "%s/%s", prefix, suffix) < 0) {
1118 fprintf(stderr, "Out of memory.\n");
1123 if (errno != ENOENT && errno != ENOTEMPTY) {
1124 fprintf(stderr, "Failed to remove %s: %m\n", p);
1129 fprintf(stderr, "Removed %s.\n", p);
1136 static int remove_binaries(const char *esp_path) {
1140 if (asprintf(&p, "%s/EFI/gummiboot", esp_path) < 0) {
1141 fprintf(stderr, "Out of memory.\n");
1148 q = remove_boot_efi(esp_path);
1149 if (q < 0 && r == 0)
1152 q = rmdir_one(esp_path, "loader/entries");
1153 if (q < 0 && r == 0)
1156 q = rmdir_one(esp_path, "loader");
1157 if (q < 0 && r == 0)
1160 q = rmdir_one(esp_path, "EFI/BOOT");
1161 if (q < 0 && r == 0)
1164 q = rmdir_one(esp_path, "EFI/gummiboot");
1165 if (q < 0 && r == 0)
1168 q = rmdir_one(esp_path, "EFI");
1169 if (q < 0 && r == 0)
1175 static int remove_variables(const uint8_t uuid[16], const char *path, bool in_order) {
1182 r = find_slot(uuid, path, &slot);
1186 r = efi_remove_boot_option(slot);
1191 remove_from_order(slot);
1196 static int install_loader_config(const char *esp_path) {
1198 char line[LINE_MAX];
1199 char *vendor = NULL;
1202 f = fopen("/etc/os-release", "re");
1206 while (fgets(line, sizeof(line), f) != NULL) {
1209 if (strncmp(line, "ID=", 3) != 0)
1212 s = strchr(vendor, '\n');
1223 if (asprintf(&p, "%s/%s", esp_path, "loader/loader.conf") < 0) {
1224 fprintf(stderr, "Out of memory.\n");
1228 f = fopen(p, "wxe");
1230 fprintf(f, "#timeout 3\n");
1231 fprintf(f, "default %s-*\n", vendor);
1239 static const char *arg_path = NULL;
1240 static bool arg_touch_variables = true;
1242 static int parse_argv(int argc, char *argv[]) {
1248 static const struct option options[] = {
1249 { "help", no_argument, NULL, 'h' },
1250 { "path", required_argument, NULL, ARG_PATH },
1251 { "no-variables", no_argument, NULL, ARG_NO_VARIABLES },
1252 { NULL, 0, NULL, 0 }
1260 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
1271 case ARG_NO_VARIABLES:
1272 arg_touch_variables = false;
1279 fprintf(stderr, "Unknown option code '%c'.\n", c);
1287 int main(int argc, char*argv[]) {
1293 } arg_action = ACTION_STATUS;
1295 static const struct {
1299 { "status", ACTION_STATUS },
1300 { "install", ACTION_INSTALL },
1301 { "update", ACTION_UPDATE },
1302 { "remove", ACTION_REMOVE },
1305 uint8_t uuid[16] = "";
1307 uint64_t pstart = 0;
1312 r = parse_argv(argc, argv);
1317 for (i = 0; i < ELEMENTSOF(verbs); i++) {
1318 if (!streq(argv[optind], verbs[i].verb))
1320 arg_action = verbs[i].action;
1323 if (i >= ELEMENTSOF(verbs)) {
1324 fprintf(stderr, "Unknown operation %s\n", argv[optind]);
1333 if (geteuid() != 0) {
1334 fprintf(stderr, "Need to be root.\n");
1339 r = verify_esp(arg_path, &part, &pstart, &psize, uuid);
1340 if (r == -ENODEV && !arg_path)
1341 fprintf(stderr, "You might want to use --path= to indicate the path to your ESP, in case it is not mounted to /boot.\n");
1345 switch (arg_action) {
1347 r = status_binaries(arg_path);
1351 if (arg_touch_variables)
1352 r = status_variables();
1355 case ACTION_INSTALL:
1359 r = install_binaries(arg_path, arg_action == ACTION_INSTALL);
1363 if (arg_action == ACTION_INSTALL)
1364 install_loader_config(arg_path);
1366 if (arg_touch_variables)
1367 r = install_variables(arg_path,
1368 part, pstart, psize, uuid,
1369 "/EFI/gummiboot/gummiboot" MACHINE_TYPE_NAME ".efi",
1370 arg_action == ACTION_INSTALL);
1374 r = remove_binaries(arg_path);
1376 if (arg_touch_variables) {
1377 q = remove_variables(uuid, "/EFI/gummiboot/gummiboot" MACHINE_TYPE_NAME ".efi", true);
1378 if (q < 0 && r == 0)
1385 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;