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;
56 * - Generate loader.conf from /etc/os-release?
59 static int help(void) {
60 printf("%s [COMMAND] [OPTIONS...]\n"
62 "Install, update or remove the Gummiboot EFI boot loader.\n\n"
63 " -h --help Show this help\n"
64 " --path=PATH Path to the EFI System Partition (ESP)\n"
65 " --no-variables Don't touch EFI variables\n"
68 " install Install Gummiboot to the ESP and EFI variables\n"
69 " update Update Gummiboot in the ESP and EFI variables\n"
70 " remove Remove Gummiboot from the ESP and EFI variables\n",
71 program_invocation_short_name);
76 static int uuid_parse(const char *s, uint8_t uuid[16]) {
80 if (sscanf(s, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
81 &u[0], &u[1], &u[2], &u[3], &u[4], &u[5], &u[6], &u[7],
82 &u[8], &u[9], &u[10], &u[11], &u[12], &u[13], &u[14], &u[15]) != 16)
85 for (i = 0; i < 16; i++)
91 static int verify_esp(const char *p, uint32_t *part, uint64_t *pstart, uint64_t *psize, uint8_t uuid[16]) {
99 if (statfs(p, &sfs) < 0) {
100 fprintf(stderr, "Failed to check file system type of %s: %m\n", p);
104 if (sfs.f_type != 0x4d44) {
105 fprintf(stderr, "File system %s is not a FAT EFI System Partition (ESP) file system.\n", p);
109 if (stat(p, &st) < 0) {
110 fprintf(stderr, "Failed to determine block device node of %s: %m\n", p);
114 if (major(st.st_dev) == 0) {
115 fprintf(stderr, "Block device node of %p is invalid.\n", p);
119 r = asprintf(&t, "%s/..", p);
121 fprintf(stderr, "Out of memory.\n");
128 fprintf(stderr, "Failed to determine block device node of parent of %s: %m\n", p);
132 if (st.st_dev == st2.st_dev) {
133 fprintf(stderr, "Directory %s is not the root of the EFI System Partition (ESP) file system.\n", p);
137 r = asprintf(&t, "/dev/block/%u:%u", major(st.st_dev), minor(st.st_dev));
139 fprintf(stderr, "Out of memory.\n");
144 b = blkid_new_probe_from_filename(t);
148 fprintf(stderr, "Failed to open file system %s: %m\n", p);
152 fprintf(stderr, "Out of memory.\n");
156 blkid_probe_enable_superblocks(b, 1);
157 blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE);
158 blkid_probe_enable_partitions(b, 1);
159 blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
162 r = blkid_do_safeprobe(b);
164 fprintf(stderr, "File system %s is ambigious.\n", p);
168 fprintf(stderr, "File system %s does not contain a label.\n", p);
172 r = errno ? -errno : -EIO;
173 fprintf(stderr, "Failed to probe file system %s: %s\n", p, strerror(-r));
178 r = blkid_probe_lookup_value(b, "TYPE", &v, NULL);
180 r = errno ? -errno : -EIO;
181 fprintf(stderr, "Failed to probe file system type %s: %s\n", p, strerror(-r));
185 if (strcmp(v, "vfat") != 0) {
186 fprintf(stderr, "File system %s is not a FAT EFI System Partition (ESP) file system after all.\n", p);
192 r = blkid_probe_lookup_value(b, "PART_ENTRY_SCHEME", &v, NULL);
194 r = errno ? -errno : -EIO;
195 fprintf(stderr, "Failed to probe partition scheme %s: %s\n", p, strerror(-r));
199 if (strcmp(v, "gpt") != 0) {
200 fprintf(stderr, "File system %s is not on a GPT partition table.\n", p);
206 r = blkid_probe_lookup_value(b, "PART_ENTRY_TYPE", &v, NULL);
208 r = errno ? -errno : -EIO;
209 fprintf(stderr, "Failed to probe partition type UUID %s: %s\n", p, strerror(-r));
213 if (strcmp(v, "c12a7328-f81f-11d2-ba4b-00a0c93ec93b") != 0) {
215 fprintf(stderr, "File system %s is not an EFI System Partition (ESP).\n", p);
220 r = blkid_probe_lookup_value(b, "PART_ENTRY_UUID", &v, NULL);
222 r = errno ? -errno : -EIO;
223 fprintf(stderr, "Failed to probe partition entry UUID %s: %s\n", p, strerror(-r));
229 r = blkid_probe_lookup_value(b, "PART_ENTRY_NUMBER", &v, NULL);
231 r = errno ? -errno : -EIO;
232 fprintf(stderr, "Failed to probe partition number %s: %s\n", p, strerror(-r));
235 *part = strtoul(v, NULL, 10);
238 r = blkid_probe_lookup_value(b, "PART_ENTRY_OFFSET", &v, NULL);
240 r = errno ? -errno : -EIO;
241 fprintf(stderr, "Failed to probe partition offset %s: %s\n", p, strerror(-r));
244 *pstart = strtoul(v, NULL, 10);
247 r = blkid_probe_lookup_value(b, "PART_ENTRY_SIZE", &v, NULL);
249 r = errno ? -errno : -EIO;
250 fprintf(stderr, "Failed to probe partition size %s: %s\n", p, strerror(-r));
253 *psize = strtoul(v, NULL, 10);
263 /* search for "#### LoaderInfo: gummiboot 31 ####" string inside the binary */
264 static int get_file_version(FILE *f, char **v) {
274 if (fstat(fileno(f), &st) < 0)
280 buf = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fileno(f), 0);
281 if (buf == MAP_FAILED)
284 s = memmem(buf, st.st_size - 8, "#### LoaderInfo: ", 17);
289 e = memmem(s, st.st_size - (s - buf), " ####", 5);
290 if (!e || e - s < 3) {
291 fprintf(stderr, "Malformed version string.\n");
296 x = strndup(s, e - s);
298 fprintf(stderr, "Out of memory.\n");
305 munmap(buf, st.st_size);
310 static int enumerate_binaries(const char *esp_path, const char *path, const char *prefix) {
312 char *p = NULL, *q = NULL;
316 if (asprintf(&p, "%s/%s", esp_path, path) < 0) {
317 fprintf(stderr, "Out of memory.\n");
324 if (errno == ENOENT) {
329 fprintf(stderr, "Failed to read %s: %m\n", p);
334 while ((de = readdir(d))) {
339 if (de->d_name[0] == '.')
342 n = strlen(de->d_name);
343 if (n < 4 || strcasecmp(de->d_name + n - 4, ".efi") != 0)
346 if (prefix && strncasecmp(de->d_name, prefix, strlen(prefix)) != 0)
351 if (asprintf(&q, "%s/%s/%s", esp_path, path, de->d_name) < 0) {
352 fprintf(stderr, "Out of memory.\n");
359 fprintf(stderr, "Failed to open %s for reading: %m\n", q);
364 r = get_file_version(f, &v);
371 printf("\t%s (Unknown product and version)\n", q);
373 printf("\t%s (%s)\n", q, v);
392 static int status_binaries(const char *esp_path) {
395 printf("Boot Loader Binaries found in ESP:\n");
397 r = enumerate_binaries(esp_path, "EFI/gummiboot", NULL);
399 fprintf(stderr, "\tGummiboot not installed in ESP.\n");
403 r = enumerate_binaries(esp_path, "EFI/BOOT", "BOOT");
405 fprintf(stderr, "\tNo fallback for removable devices installed in ESP.\n");
412 static int print_efi_option(uint16_t id, bool in_order) {
415 uint8_t partition[16];
418 r = efi_get_boot_option(id, &title, partition, &path);
420 fprintf(stderr, "Failed to read EFI boot entry %i.\n", id);
424 printf("\t%s%s\n", strna(title), in_order ? " [ENABLED]" : "");
426 printf("\t\t%s\n", path);
427 printf("\t\t/dev/disk/by-partuuid/%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
428 partition[0], partition[1], partition[2], partition[3], partition[4], partition[5], partition[6], partition[7],
429 partition[8], partition[9], partition[10], partition[11], partition[12], partition[13], partition[14], partition[15]);
438 static int status_variables(void) {
439 int n_options, n_order;
440 uint16_t *options = NULL, *order = NULL;
443 if (!is_efi_boot()) {
444 fprintf(stderr, "Not booted with EFI, not showing EFI variables.\n");
448 printf("\nBoot Entries found in EFI variables:\n");
450 n_options = efi_get_boot_options(&options);
452 if (n_options == -ENOENT)
453 fprintf(stderr, "\tFailed to access EFI variables. Is the \"efivarfs\" filesystem mounted?\n");
455 fprintf(stderr, "\tFailed to read EFI boot entries.\n");
460 n_order = efi_get_boot_order(&order);
461 if (n_order == -ENOENT) {
462 fprintf(stderr, "\tNo boot entries registered in EFI variables.\n");
465 } else if (n_order < 0) {
466 fprintf(stderr, "\tFailed to read EFI boot order.\n");
471 for (i = 0; i < n_order; i++) {
472 r = print_efi_option(order[i], true);
477 for (i = 0; i < n_options; i++) {
481 for (j = 0; j < n_order; j++)
482 if (options[i] == order[j]) {
490 r = print_efi_option(options[i], false);
503 static int compare_product(const char *a, const char *b) {
512 return x < y ? -1 : x > y ? 1 : 0;
514 return strncmp(a, b, x);
517 static int compare_version(const char *a, const char *b) {
521 a += strcspn(a, " ");
523 b += strcspn(b, " ");
526 return strverscmp(a, b);
529 static int version_check(FILE *f, const char *from, const char *to) {
531 char *a = NULL, *b = NULL;
538 r = get_file_version(f, &a);
543 fprintf(stderr, "Source file %s does not carry version information!\n", from);
549 if (errno == ENOENT) {
555 fprintf(stderr, "Failed to open %s for reading: %m\n", to);
559 r = get_file_version(g, &b);
562 if (r == 0 || compare_product(a, b) != 0) {
564 fprintf(stderr, "Skipping %s, since it's owned by another boot loader.\n", to);
568 if (compare_version(a, b) < 0) {
570 fprintf(stderr, "Skipping %s, since it's a newer boot loader version already.\n", to);
584 static int copy_file(const char *from, const char *to, bool force) {
585 FILE *f = NULL, *g = NULL;
588 struct timespec t[2];
594 f = fopen(from, "re");
596 fprintf(stderr, "Failed to open %s for reading: %m\n", from);
601 /* If this is an update, then let's compare versions first */
602 r = version_check(f, from, to);
607 if (asprintf(&p, "%s~", to) < 0) {
608 fprintf(stderr, "Out of memory.\n");
615 /* Directory doesn't exist yet? Then let's skip this... */
616 if (!force && errno == ENOENT) {
621 fprintf(stderr, "Failed to open %s for writing: %m\n", to);
629 uint8_t buf[32*1024];
631 k = fread(buf, 1, sizeof(buf), f);
633 fprintf(stderr, "Failed to read %s: %m\n", from);
640 fwrite(buf, 1, k, g);
642 fprintf(stderr, "Failed to write %s: %m\n", to);
650 fprintf(stderr, "Failed to write %s: %m\n", to);
655 r = fstat(fileno(f), &st);
657 fprintf(stderr, "Failed to get file timestamps of %s: %m", from);
665 r = futimens(fileno(g), t);
667 fprintf(stderr, "Failed to change file timestamps for %s: %m", p);
672 if (rename(p, to) < 0) {
673 fprintf(stderr, "Failed to rename %s to %s: %m\n", p, to);
678 fprintf(stderr, "Copied %s to %s.\n", from, to);
696 static char* strupper(char *s) {
705 static int mkdir_one(const char *prefix, const char *suffix) {
708 if (asprintf(&p, "%s/%s", prefix, suffix) < 0) {
709 fprintf(stderr, "Out of memory.\n");
713 if (mkdir(p, 0700) < 0) {
714 if (errno != EEXIST) {
715 fprintf(stderr, "Failed to create %s: %m\n", p);
720 fprintf(stderr, "Created %s.\n", p);
726 static int create_dirs(const char *esp_path) {
729 r = mkdir_one(esp_path, "EFI");
733 r = mkdir_one(esp_path, "EFI/gummiboot");
737 r = mkdir_one(esp_path, "EFI/BOOT");
741 r = mkdir_one(esp_path, "loader");
745 r = mkdir_one(esp_path, "loader/entries");
752 static int copy_one_file(const char *esp_path, const char *name, bool force) {
753 char *p = NULL, *q = NULL, *v = NULL;
756 if (asprintf(&p, "/usr/lib/gummiboot/%s", name) < 0) {
757 fprintf(stderr, "Out of memory.\n");
762 if (asprintf(&q, "%s/EFI/gummiboot/%s", esp_path, name) < 0) {
763 fprintf(stderr, "Out of memory.\n");
768 r = copy_file(p, q, force);
770 if (strncmp(name, "gummiboot", 9) == 0) {
773 /* Create the fallback names for removable devices */
774 if (asprintf(&v, "%s/EFI/BOOT/%s", esp_path, name + 5) < 0) {
775 fprintf(stderr, "Out of memory.\n");
779 strupper(strrchr(v, '/') + 1);
781 k = copy_file(p, v, force);
782 if (k < 0 && r == 0) {
795 static int install_binaries(const char *esp_path, bool force) {
801 /* Don't create any of these directories when we are
802 * just updating. When we update we'll drop-in our
803 * files (unless there are newer ones already), but we
804 * won't create the directories for them in the first
806 r = create_dirs(esp_path);
811 d = opendir("/usr/lib/gummiboot");
813 fprintf(stderr, "Failed to open /usr/lib/gummiboot: %m\n");
817 while ((de = readdir(d))) {
821 if (de->d_name[0] == '.')
824 n = strlen(de->d_name);
825 if (n < 4 || strcmp(de->d_name + n - 4, ".efi") != 0)
828 k = copy_one_file(esp_path, de->d_name, force);
837 static bool same_entry(uint16_t id, const uint8_t uuid[16], const char *path) {
843 err = efi_get_boot_option(id, NULL, ouuid, &opath);
846 if (memcmp(uuid, ouuid, 16) != 0)
849 if (!streq(path, opath))
859 static int find_slot(const uint8_t uuid[16], const char *path, uint16_t *id) {
860 uint16_t *options = NULL;
864 bool existing = false;
866 n_options = efi_get_boot_options(&options);
870 /* find already existing gummiboot entry */
871 for (i = 0; i < n_options; i++)
872 if (same_entry(options[i], uuid, path)) {
878 /* find free slot in the sorted BootXXXX variable list */
879 for (i = 0; i < n_options; i++)
880 if (i != options[i]) {
891 static int insert_into_order(uint16_t slot, bool first) {
892 uint16_t *order = NULL;
898 n_order = efi_get_boot_order(&order);
900 err = efi_set_boot_order(&slot, 1);
904 /* are we already in the boot order? */
905 for (i = 0; i < n_order; i++)
906 if (order[i] == slot)
910 new_order = realloc(order, (n_order+1) * sizeof(uint16_t));
917 /* add to the top or end of the list */
919 memmove(&order[1], order, n_order * sizeof(uint16_t));
922 order[n_order] = slot;
924 efi_set_boot_order(order, n_order+1);
931 static int remove_from_order(uint16_t slot) {
932 uint16_t *order = NULL;
937 n_order = efi_get_boot_order(&order);
943 for (i = 0; i < n_order; i++) {
944 if (order[i] != slot)
948 memmove(&order[i], &order[i+1], (n_order - i) * sizeof(uint16_t));
949 efi_set_boot_order(order, n_order-1);
957 static int install_variables(const char *esp_path,
958 uint32_t part, uint64_t pstart, uint64_t psize,
959 const uint8_t uuid[16], const char *path,
962 uint16_t *options = NULL;
966 if (!is_efi_boot()) {
967 fprintf(stderr, "Not booted with EFI, skipping EFI variable checks.\n");
971 if (asprintf(&p, "%s%s", esp_path, path) < 0) {
972 fprintf(stderr, "Out of memory.\n");
976 if (access(p, F_OK) < 0) {
984 r = find_slot(uuid, path, &slot);
987 fprintf(stderr, "Failed to access EFI variables. Is the \"efivarfs\" filesystem mounted?\n");
989 fprintf(stderr, "Failed to determine current boot order: %s\n", strerror(-r));
993 if (force || r == false) {
994 r = efi_add_boot_option(slot,
995 "Linux Boot Manager",
999 fprintf(stderr, "Failed to create EFI Boot variable entry: %s\n", strerror(-r));
1002 fprintf(stderr, "Created EFI Boot entry \"Linux Boot Manager\".\n");
1004 insert_into_order(slot, force);
1012 static int delete_nftw(const char *path, const struct stat *sb, int typeflag, struct FTW *ftw) {
1015 if (typeflag == FTW_D || typeflag == FTW_DNR || typeflag == FTW_DP)
1021 fprintf(stderr, "Failed to remove %s: %m\n", path);
1023 fprintf(stderr, "Removed %s.\n", path);
1028 static int rm_rf(const char *p) {
1029 nftw(p, delete_nftw, 20, FTW_DEPTH|FTW_MOUNT|FTW_PHYS);
1033 static int remove_boot_efi(const char *esp_path) {
1035 char *p = NULL, *q = NULL;
1039 if (asprintf(&p, "%s/EFI/BOOT", esp_path) < 0) {
1040 fprintf(stderr, "Out of memory.\n");
1046 if (errno == ENOENT) {
1051 fprintf(stderr, "Failed to read %s: %m\n", p);
1056 while ((de = readdir(d))) {
1061 if (de->d_name[0] == '.')
1064 n = strlen(de->d_name);
1065 if (n < 4 || strcasecmp(de->d_name + n - 4, ".EFI") != 0)
1068 if (strncasecmp(de->d_name, "BOOT", 4) != 0)
1073 if (asprintf(&q, "%s/%s", p, de->d_name) < 0) {
1074 fprintf(stderr, "Out of memory.\n");
1081 fprintf(stderr, "Failed to open %s for reading: %m\n", q);
1086 r = get_file_version(f, &v);
1092 if (r > 0 && strncmp(v, "gummiboot ", 10) == 0) {
1096 fprintf(stderr, "Failed to remove %s: %m\n", q);
1101 fprintf(stderr, "Removed %s.\n", q);
1119 static int rmdir_one(const char *prefix, const char *suffix) {
1122 if (asprintf(&p, "%s/%s", prefix, suffix) < 0) {
1123 fprintf(stderr, "Out of memory.\n");
1128 if (errno != ENOENT && errno != ENOTEMPTY) {
1129 fprintf(stderr, "Failed to remove %s: %m\n", p);
1134 fprintf(stderr, "Removed %s.\n", p);
1141 static int remove_binaries(const char *esp_path) {
1145 if (asprintf(&p, "%s/EFI/gummiboot", esp_path) < 0) {
1146 fprintf(stderr, "Out of memory.\n");
1153 q = remove_boot_efi(esp_path);
1154 if (q < 0 && r == 0)
1157 q = rmdir_one(esp_path, "loader/entries");
1158 if (q < 0 && r == 0)
1161 q = rmdir_one(esp_path, "loader");
1162 if (q < 0 && r == 0)
1165 q = rmdir_one(esp_path, "EFI/BOOT");
1166 if (q < 0 && r == 0)
1169 q = rmdir_one(esp_path, "EFI/gummiboot");
1170 if (q < 0 && r == 0)
1173 q = rmdir_one(esp_path, "EFI");
1174 if (q < 0 && r == 0)
1180 static int remove_variables(const uint8_t uuid[16], const char *path, bool in_order) {
1187 r = find_slot(uuid, path, &slot);
1191 r = efi_remove_boot_option(slot);
1196 remove_from_order(slot);
1201 static int install_loader_config(const char *esp_path) {
1203 char line[LINE_MAX];
1204 char *vendor = NULL;
1207 f = fopen("/etc/os-release", "re");
1211 while (fgets(line, sizeof(line), f) != NULL) {
1214 if (strncmp(line, "ID=", 3) != 0)
1217 s = strchr(vendor, '\n');
1228 if (asprintf(&p, "%s/%s", esp_path, "loader/loader.conf") < 0) {
1229 fprintf(stderr, "Out of memory.\n");
1233 f = fopen(p, "wxe");
1235 fprintf(f, "#timeout 3\n");
1236 fprintf(f, "default %s-*\n", vendor);
1244 static const char *arg_path = NULL;
1245 static bool arg_touch_variables = true;
1247 static int parse_argv(int argc, char *argv[]) {
1253 static const struct option options[] = {
1254 { "help", no_argument, NULL, 'h' },
1255 { "path", required_argument, NULL, ARG_PATH },
1256 { "no-variables", no_argument, NULL, ARG_NO_VARIABLES },
1257 { NULL, 0, NULL, 0 }
1265 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
1276 case ARG_NO_VARIABLES:
1277 arg_touch_variables = false;
1284 fprintf(stderr, "Unknown option code '%c'.\n", c);
1292 int main(int argc, char*argv[]) {
1298 } arg_action = ACTION_STATUS;
1300 static const struct {
1304 { "status", ACTION_STATUS },
1305 { "install", ACTION_INSTALL },
1306 { "update", ACTION_UPDATE },
1307 { "remove", ACTION_REMOVE },
1310 uint8_t uuid[16] = "";
1312 uint64_t pstart = 0;
1317 r = parse_argv(argc, argv);
1322 for (i = 0; i < ELEMENTSOF(verbs); i++) {
1323 if (!streq(argv[optind], verbs[i].verb))
1325 arg_action = verbs[i].action;
1328 if (i >= ELEMENTSOF(verbs)) {
1329 fprintf(stderr, "Unknown operation %s\n", argv[optind]);
1338 if (geteuid() != 0) {
1339 fprintf(stderr, "Need to be root.\n");
1344 r = verify_esp(arg_path, &part, &pstart, &psize, uuid);
1345 if (r == -ENODEV && !arg_path)
1346 fprintf(stderr, "You might want to use --path= to indicate the path to your ESP, in case it is not mounted to /boot.\n");
1350 switch (arg_action) {
1352 r = status_binaries(arg_path);
1356 if (arg_touch_variables)
1357 r = status_variables();
1360 case ACTION_INSTALL:
1364 r = install_binaries(arg_path, arg_action == ACTION_INSTALL);
1368 if (arg_action == ACTION_INSTALL)
1369 install_loader_config(arg_path);
1371 if (arg_touch_variables)
1372 r = install_variables(arg_path,
1373 part, pstart, psize, uuid,
1374 "/EFI/gummiboot/gummiboot" MACHINE_TYPE_NAME ".efi",
1375 arg_action == ACTION_INSTALL);
1379 r = remove_binaries(arg_path);
1381 if (arg_touch_variables) {
1382 q = remove_variables(uuid, "/EFI/gummiboot/gummiboot" MACHINE_TYPE_NAME ".efi", true);
1383 if (q < 0 && r == 0)
1390 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;