diff --git a/src/Makefile b/src/Makefile index 6fc2a622..16d03b42 100644 --- a/src/Makefile +++ b/src/Makefile @@ -98,7 +98,7 @@ libefivar.so : private LIBS=dl libefivar.so : private MAP=libefivar.map efivar : $(EFIVAR_OBJECTS) | libefivar.so -efivar : private LIBS=efivar dl +efivar : private LIBS=efivar dl blkid efivar-static : $(EFIVAR_OBJECTS) $(patsubst %.o,%.static.o,$(LIBEFIVAR_OBJECTS)) efivar-static : | $(GENERATED_SOURCES) diff --git a/src/efivar.c b/src/efivar.c index 519f7c52..4a8bca8b 100644 --- a/src/efivar.c +++ b/src/efivar.c @@ -19,6 +19,8 @@ #include #include #include +#include +#include extern char *optarg; extern int optind, opterr, optopt; @@ -42,6 +44,11 @@ extern int optind, opterr, optopt; #define SHOW_VERBOSE 0 #define SHOW_DECIMAL 1 +#define EFI_VARTOFILE "b2ac5fc9-92b7-4acd-aeac-11e818c3130c-VarToFile" +#define EFI_RTSTORAGEVOLATILE "b2ac5fc9-92b7-4acd-aeac-11e818c3130c-RTStorageVolatile" + +static void save_esp_filename(); + static const char *attribute_names[] = { "Non-Volatile", "Boot Service Access", @@ -382,6 +389,8 @@ edit_variable(const char *guid_name, void *data, size_t data_size, show_errors(); exit(1); } + + save_esp_filename(); } static void @@ -424,6 +433,172 @@ prepare_data(const char *filename, uint8_t **data, size_t *data_size) exit(1); } +void +find_esp(char **esp_paths, size_t *esp_count) +{ + blkid_cache cache; + blkid_dev_iterate iter; + blkid_dev dev; + const char *devname; + const char *parttype; + const char *esp_parttype = "c12a7328-f81f-11d2-ba4b-00a0c93ec93b"; // ESP UUID + FILE *mounts; + struct mntent *ent; + blkid_probe pr = NULL; + int r, size = 0; + *esp_count = 0; + + // Initialize the blkid cache + if (blkid_get_cache(&cache, NULL) < 0) { + fprintf(stderr, "Failed to get blkid cache\n"); + return; + } + + // Probe all block devices + blkid_probe_all(cache); + + // Create an iterator to go through all block devices + iter = blkid_dev_iterate_begin(cache); + if (!iter) { + fprintf(stderr, "Failed to create blkid iterator\n"); + blkid_put_cache(cache); + return; + } + + // Open /proc/mounts to find mount points + mounts = setmntent("/proc/mounts", "r"); + if (!mounts) { + fprintf(stderr, "Failed to open /proc/mounts\n"); + endmntent(mounts); + return; + } + + while (blkid_dev_next(iter, &dev) == 0) { + dev = blkid_verify(cache, dev); + if (!dev) { + continue; + } + devname = blkid_dev_devname(dev); + + pr = blkid_new_probe_from_filename(devname); + if (!pr) { + fprintf(stderr, "Failed to create blkid probe\n"); + blkid_free_probe(pr); + return; + } + + // Generate partition details + blkid_probe_enable_partitions(pr, 1); + blkid_probe_set_partitions_flags(pr, BLKID_PARTS_ENTRY_DETAILS); + + r = blkid_do_safeprobe(pr); + if (r == -2) { + debug("File system %s is ambiguous\n", devname); + continue; + } else if (r != 0) { + debug("Failed to probe file system %s\n", devname); + continue; + } + + // Get the PARTTYPE of the current device + r = blkid_probe_lookup_value(pr, "PART_ENTRY_TYPE", &parttype, NULL); + if (r != 0) { + debug("Failed to probe partition type UUID %s\n", devname); + continue; + } + + if (parttype && strcmp(parttype, esp_parttype) == 0) { + // Iterate over mount points to find ESP matches + while ((ent = getmntent(mounts)) != NULL) { + if (strcmp(ent->mnt_fsname, devname) == 0) { + printf("ESP %s path is mounted at dev %s\n", ent->mnt_dir, devname); + size += strlen(ent->mnt_dir) + 1; // +1 for the null terminator + char *temp = realloc(*esp_paths, size); + if (temp == NULL) { + fprintf(stderr, "Failed to allocate memory for ESP paths\n"); + free(*esp_paths); + *esp_count = 0; + return; + } + *esp_paths = temp; + strcpy(*esp_paths + size - strlen(ent->mnt_dir) - 1, ent->mnt_dir); + (*esp_count)++; + } + } + } + + // Cleanup + blkid_free_probe(pr); + } + + // Cleanup + endmntent(mounts); + blkid_dev_iterate_end(iter); + blkid_put_cache(cache); +} + +static void +get_esp_filename(char **esp_filename) +{ + char *dst_name = NULL; + efi_guid_t dst_guid = efi_guid_empty; + size_t filename_size; + uint32_t filename_attr; + uint8_t *filename = NULL; + int rc; + + parse_name(EFI_RTSTORAGEVOLATILE, &dst_name, &dst_guid); + if (!dst_name || efi_guid_is_empty(&dst_guid)) { + fprintf(stderr, "efivar: could not parse %s\n", EFI_RTSTORAGEVOLATILE); + show_errors(); + exit(1); + } + + rc = efi_get_variable(dst_guid, dst_name, &filename, &filename_size, &filename_attr); + if (rc < 0) { + fprintf(stderr, "efivar: get ESP filename\n"); + show_errors(); + exit(1); + } + + *esp_filename = (char *)filename; +} + +static void +save_esp_filename() +{ + char *esp_paths = NULL; + size_t esp_count = 0; + char *ptr; + char *esp_filename_path = NULL; + char *esp_filename = NULL; + + get_esp_filename(&esp_filename); + if (esp_filename) { + fprintf(stderr, "efivar: No ESP filename found\n"); + show_errors(); + exit(1); + } + + find_esp(&esp_paths, &esp_count); + if (esp_paths) { + ptr = esp_paths; + for (size_t i = 0; i < esp_count; i++) { + esp_filename_path = strcat(ptr, "/"); + esp_filename_path = strcat(esp_filename_path, esp_filename); + save_variable(EFI_VARTOFILE, esp_filename_path, false); + printf("efivar: VarToFile content saved at %s\n", esp_filename_path); + ptr += strlen(ptr) + 1; + } + free(esp_paths); + } + else { + fprintf(stderr, "efivar: no EFI System Partitions (ESP) found\n"); + show_errors(); + exit(1); + } +} + static void __attribute__((__noreturn__)) usage(int ret) {