/* SPDX-License-Identifier: MIT */ #include "part_ids.h" #include #include #include #include #define GUID_TABLE \ X(LINUX_SWAP, "0657FD6D-A4AB-43C4-84E5-0933C84B4F4F") \ X(LINUX_FS, "0FC63DAF-8483-4772-8E79-3D69D8477DE4") \ X(EFI_SYSTEM, "C12A7328-F81F-11D2-BA4B-00A0C93EC93B") \ X(MS_BASIC_DATA, "EBD0A0A2-B9E5-4433-87C0-68B6B72699C7") \ X(BIOS_BOOT, "21686148-6449-6E6F-744E-656564454649") #define ALIAS_TABLE \ X("fat12", 0x01, MS_BASIC_DATA) \ X("fat16", 0x04, MS_BASIC_DATA) \ X("fat16b", 0x06, MS_BASIC_DATA) \ X("ntfs", 0x07, MS_BASIC_DATA) \ X("fat32", 0x0b, MS_BASIC_DATA) \ X("fat32x", 0x0c, MS_BASIC_DATA) \ X("fat16x", 0x0e, MS_BASIC_DATA) \ X("fat16+", 0x28, MS_BASIC_DATA) \ X("fat32+", 0x29, MS_BASIC_DATA) \ X("swap", 0x82, LINUX_SWAP) \ X("linux", 0x83, LINUX_FS) \ X("system", 0x100, EFI_SYSTEM) \ X("bios", 0x101, BIOS_BOOT) /* * First we generate compact indices for each GUID using an enum. (It's true, * clang-format is not improving things below.) */ enum GUID_INDEX { #define X(index, guid) GUID_##index, GUID_TABLE #undef X NUM_GUIDS }; /* * Then we plop down the GUIDs in a compact table. Overly compact maybe? Note * that there are no pointers involved and no NUL terminators at the "end" of * a GUID, so don't try to `printf` them directly! */ static const char guids[NUM_GUIDS][GUID_STRLEN] = { #define X(index, guid) [GUID_##index] = guid, GUID_TABLE #undef X }; /* * Now for the aliases that "point" to the GUIDs. Note that these are *not* * sorted, but unless we have thousands of names, a linear search should be * all we need. A `key` of `NULL` marks the end. */ static const struct { char *key; int value; } name_to_guid[] = { #define X(name, id, index) {name, GUID_##index}, ALIAS_TABLE #undef X {NULL, -1}, }; /* * The same for the "short" MBR-style ids. A `key` of `-1` marks the end. */ static const struct { int key; int value; } mbr_to_guid[] = { #define X(name, id, index) {id, GUID_##index}, ALIAS_TABLE #undef X {-1, -1}, }; int valid_string_guid(const char str[GUID_STRLEN]) { /* TODO there may be a simpler way? but let's avoid regexp stuff... */ static const int spans[5] = {8, 4, 4, 4, 12}; /* spans of hex digits */ /* (sum spans) + 4 == GUID_STRLEN */ int pos = 0; /* for all spans */ for (int i = 0; i < 5; i++) { /* for all hex digits in span */ for (int j = 0; j < spans[i]; j++) { if (!isxdigit(str[pos])) { return 0; } pos++; } /* need a '-' except after the last span */ if (i == 4) { break; } if (str[pos] != '-') { return 0; } pos++; } return 1; } static int find_by_name(const char *str, GUID *guid) { for (int i = 0; name_to_guid[i].key != NULL; i++) { if (!strcmp(str, name_to_guid[i].key)) { return string_to_guid( guid, guids[name_to_guid[i].value]); } } return -1; } static int find_by_id(const int id, GUID *guid) { for (int i = 0; mbr_to_guid[i].key != -1; i++) { if (mbr_to_guid[i].key == id) { return string_to_guid( guid, guids[mbr_to_guid[i].value]); } } return -1; } /* * Parse GUID/UUID notation used on the command line. * Returns 0 on success. */ int parse_guid(const char *str, GUID *guid) { /* detect request for random uuid */ if (!strcmp(str, "random") || !strcmp(str, "rnd")) { return random_guid(guid); } /* detect by name */ if (find_by_name(str, guid) == 0) { return 0; } /* try and parse as guid */ if (valid_string_guid(str)) { return string_to_guid(guid, str); } /* detect mbr partition id by number */ errno = 0; long mbr_id = strtol(str, NULL, 0); if (errno != 0) { return -1; } if (find_by_id(mbr_id, guid) == 0) { return 0; } return -1; }