about summary refs log blame commit diff stats
path: root/part_ids.c
blob: fc7ba9c8cfd2950d7ebaf7805f1410827c8fb5e1 (plain) (tree)
1
2
3
4
5
6
7
8
9

                                  






                     




                                                                                
                                                            
 












                                                                                
                                   
 



                                                                             
                 
                                    

                  
                         






                                                                             
                                                   
                                             








                                                                           




                                                







                                                                         




                                              





































                                                                               




                                                           

                                                                    









                                                        

                                                                   




                  












                                                            

                                           












                                                 

                                            



                  
/* SPDX-License-Identifier: MIT */

#include "part_ids.h"

#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>

#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;
}