about summary refs log tree commit diff stats
path: root/part_ids.c
diff options
context:
space:
mode:
authorPeter H. Froehlich <peter.hans.froehlich@gmail.com>2021-04-23 17:59:31 +0200
committerPeter H. Froehlich <peter.hans.froehlich@gmail.com>2021-04-23 17:59:31 +0200
commit9e51cfbfd2ab013cb5e8474e74a499827f73318f (patch)
tree67a859ab30bdf013bf289bcd108d18fbe3805390 /part_ids.c
parent5ce6e90c70378c63044b526f6a8196645971576a (diff)
downloadmkgpt-9e51cfbfd2ab013cb5e8474e74a499827f73318f.tar.gz
Replace fstypes.[ch] and make --type work for real.
Diffstat (limited to 'part_ids.c')
-rw-r--r--part_ids.c146
1 files changed, 146 insertions, 0 deletions
diff --git a/part_ids.c b/part_ids.c
new file mode 100644
index 0000000..d678598
--- /dev/null
+++ b/part_ids.c
@@ -0,0 +1,146 @@
+#include "part_ids.h"
+
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#define MBR_SWAP 0x82
+#define MBR_LINUX 0x83
+#define EFI_SYSTEM 0x100
+#define BIOS_BOOT 0x101
+
+#define GUID_TABLE \
+	X(SWAP, "0657FD6D-A4AB-43C4-84E5-0933C84B4F4F") \
+	X(LINUX, "0FC63DAF-8483-4772-8E79-3D69D8477DE4") \
+	X(SYSTEM, "C12A7328-F81F-11D2-BA4B-00A0C93EC93B") \
+	X(BDP, "EBD0A0A2-B9E5-4433-87C0-68B6B72699C7") \
+	X(BIOS, "21686148-6449-6E6F-744E-656564454649")
+
+#define ALIAS_TABLE \
+	X("fat12", 0x01, BDP) \
+	X("fat16", 0x04, BDP) \
+	X("fat16b", 0x06, BDP) \
+	X("ntfs", 0x07, BDP) \
+	X("fat32", 0x0b, BDP) \
+	X("fat32x", 0x0c, BDP) \
+	X("fat16x", 0x0e, BDP) \
+	X("fat16+", 0x28, BDP) \
+	X("fat32+", 0x29, BDP) \
+	X("swap", MBR_SWAP, SWAP) \
+	X("linux", MBR_LINUX, LINUX) \
+	X("system", EFI_SYSTEM, SYSTEM) \
+	X("bios", BIOS_BOOT, BIOS)
+
+/* First we generate compact indices for each GUID using an enum. */
+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 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 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 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;
+}
+
+/*
+ * 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 */
+	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]);
+		}
+	}
+
+	/* 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;
+	}
+	for (int i = 0; mbr_to_guid[i].key != -1; i++) {
+		if (mbr_to_guid[i].key == mbr_id) {
+			return string_to_guid(guid, guids[mbr_to_guid[i].value]);
+		}
+	}
+
+	return -1;
+}