about summary refs log tree commit diff stats
path: root/mkgpt.c
diff options
context:
space:
mode:
Diffstat (limited to 'mkgpt.c')
-rw-r--r--mkgpt.c156
1 files changed, 100 insertions, 56 deletions
diff --git a/mkgpt.c b/mkgpt.c
index 3f8ad36..ae71032 100644
--- a/mkgpt.c
+++ b/mkgpt.c
@@ -23,7 +23,6 @@
 
 #include "crc32.h"
 #include "guid.h"
-#include "part.h"
 #include "part_ids.h"
 #include "unaligned.h"
 
@@ -35,10 +34,36 @@
 #include <stdlib.h>
 #include <string.h>
 
+struct partition {
+	GUID type;
+	GUID uuid;
+	uint64_t attrs;
+	long src_length;
+	FILE *src;
+	struct partition *next; /* TODO why build a list? */
+	int id;
+	int sect_start;
+	int sect_length;
+	char name[52];
+};
+
 #define MAX_PART_NAME (36U)
 #define MIN_SECTOR_SIZE (512U)
 #define MAX_SECTOR_SIZE (4096U)
 
+/*
+ * UEFI says 128 is the "minimum size" but since we're generating the image we
+ * get to pick; and we're fine with 128 for now; anything else would probably
+ * also mess with other GPT tools?
+ */
+#define PART_ENTRY_SIZE (128U)
+
+/*
+ * TODO Everything else says 92 instead, and that's also what gdisk does when
+ * it creates a GPT. It's a mystery why the code here uses 96 instead.
+ */
+#define GPT_HEADER_SIZE (96U)
+
 static void
 dump_help(char *fname);
 static int
@@ -68,35 +93,37 @@ static int secondary_headers_sect;
 static int secondary_gpt_sect;
 
 int
-main(int argc, char **argv)
+main(int argc, char *argv[])
 {
 	random_guid(&disk_guid);
 
-	if (parse_opts(argc, argv) != 0)
-		return -1;
+	if (parse_opts(argc, argv) != 0) {
+		exit(EXIT_FAILURE);
+	}
 
 	if (output == NULL) {
-		fprintf(stderr, "no output file specifed\n");
+		fprintf(stderr, "no output file specified\n");
 		dump_help(argv[0]);
-		return -1;
+		exit(EXIT_FAILURE);
 	}
 	if (first_part == NULL) {
 		fprintf(stderr, "no partitions specified\n");
 		dump_help(argv[0]);
-		return -1;
+		exit(EXIT_FAILURE);
 	}
 
-	if (check_parts() != 0)
-		return -1;
+	if (check_parts() != 0) {
+		exit(EXIT_FAILURE);
+	}
 
 	write_output();
 	fclose(output);
 
-	return 0;
+	exit(EXIT_SUCCESS);
 }
 
 static int
-parse_opts(int argc, char **argv)
+parse_opts(int argc, char *argv[])
 {
 	int i = 1;
 	int cur_part_id = 0;
@@ -264,7 +291,7 @@ parse_opts(int argc, char **argv)
 			 */
 			if (strlen(argv[i]) > MAX_PART_NAME) {
 				fprintf(stderr,
-					"partition name too long (max %i)\n",
+					"partition name too long (max %u)\n",
 					MAX_PART_NAME);
 				return -1;
 			}
@@ -377,16 +404,18 @@ check_parts()
 	/* Determine the sectors needed for MBR, GPT header and partition
 	 * entries */
 	cur_sect = 2; /* MBR + GPT header */
-	header_length = part_count * 128;
+	header_length = part_count * PART_ENTRY_SIZE;
 	header_sectors = header_length / sect_size;
-	if (header_length % sect_size)
+	if (header_length % sect_size) {
 		header_sectors++;
+	}
 
 	/* The GPT entry array must be a minimum of 16,384 bytes (reports
 	 * wikipedia and testdisk, but not the UEFI spec)
 	 */
-	if (header_sectors < (int)(16384 / sect_size))
+	if (header_sectors < (int)(16384 / sect_size)) {
 		header_sectors = (int)(16384 / sect_size);
+	}
 
 	cur_sect += header_sectors;
 	first_usable_sector = cur_sect;
@@ -405,12 +434,14 @@ check_parts()
 			return -1;
 		}
 
-		if (guid_is_zero(&cur_part->uuid))
+		/* TODO is this appropriate? check the spec! */
+		if (guid_is_zero(&cur_part->uuid)) {
 			random_guid(&cur_part->uuid);
+		}
 
-		if (cur_part->sect_start == 0)
+		if (cur_part->sect_start == 0) {
 			cur_part->sect_start = cur_sect;
-		else if (cur_part->sect_start < cur_sect) {
+		} else if (cur_part->sect_start < cur_sect) {
 			fprintf(stderr,
 				"unable to start partition %i at sector %i "
 				"(would conflict with other data)\n",
@@ -424,8 +455,9 @@ check_parts()
 
 		if (cur_part->sect_length == 0) {
 			cur_part->sect_length = cur_part_file_len / sect_size;
-			if (cur_part_file_len % sect_size)
+			if (cur_part_file_len % sect_size) {
 				cur_part->sect_length++;
+			}
 		}
 		cur_sect = cur_part->sect_start + cur_part->sect_length;
 
@@ -436,10 +468,11 @@ check_parts()
 	needed_file_length = cur_sect + 1 + header_sectors;
 
 	if (image_sects == 0) {
-		if (needed_file_length > min_image_sects)
+		if (needed_file_length > min_image_sects) {
 			image_sects = needed_file_length;
-		else
+		} else {
 			image_sects = min_image_sects;
+		}
 	} else if (image_sects < needed_file_length) {
 		fprintf(stderr,
 			"requested image size (%zu) is too small to hold the "
@@ -508,20 +541,20 @@ write_output(void)
 	uint8_t gpt2[MAX_SECTOR_SIZE] = {0};
 	assert(sect_size <= sizeof(gpt2));
 
-	*(uint64_t *)&gpt[0] = 0x5452415020494645ULL; /* Signature */
-	*(uint32_t *)&gpt[8] = 0x00010000UL; /* Revision */
-	*(uint32_t *)&gpt[12] = 96; /* HeaderSize */
-	*(uint32_t *)&gpt[16] = 0; /* HeaderCRC32 */
-	*(uint32_t *)&gpt[20] = 0; /* Reserved */
-	*(uint64_t *)&gpt[24] = 0x1; /* MyLBA */
-	*(uint64_t *)&gpt[32] = secondary_gpt_sect; /* AlternateLBA */
-	*(uint64_t *)&gpt[40] = first_usable_sector; /* FirstUsableLBA */
-	*(uint64_t *)&gpt[48] = secondary_headers_sect - 1; /* LastUsableLBA */
-	guid_to_bytestring(&gpt[56], &disk_guid); /* DiskGUID */
-	*(uint64_t *)&gpt[72] = 0x2; /* PartitionEntryLBA */
-	*(uint32_t *)&gpt[80] = part_count; /* NumberOfPartitionEntries */
-	*(uint32_t *)&gpt[84] = 128; /* SizeOfPartitionEntry */
-	*(uint32_t *)&gpt[88] = 0; /* PartitionEntryArrayCRC32 */
+	set_u64(gpt + 0, 0x5452415020494645ULL); /* Signature */
+	set_u32(gpt + 8, 0x00010000UL); /* Revision */
+	set_u32(gpt + 12, GPT_HEADER_SIZE); /* HeaderSize */
+	set_u32(gpt + 16, 0); /* HeaderCRC32 */
+	set_u32(gpt + 20, 0); /* Reserved */
+	set_u64(gpt + 24, 0x1); /* MyLBA */
+	set_u64(gpt + 32, secondary_gpt_sect); /* AlternateLBA */
+	set_u64(gpt + 40, first_usable_sector); /* FirstUsableLBA */
+	set_u64(gpt + 48, secondary_headers_sect - 1); /* LastUsableLBA */
+	guid_to_bytestring(gpt + 56, &disk_guid); /* DiskGUID */
+	set_u64(gpt + 72, 0x2); /* PartitionEntryLBA */
+	set_u32(gpt + 80, part_count); /* NumberOfPartitionEntries */
+	set_u32(gpt + 84, PART_ENTRY_SIZE); /* SizeOfPartitionEntry */
+	set_u32(gpt + 88, 0); /* PartitionEntryArrayCRC32 */
 
 	/* Define GPT partition entries */
 	parts = calloc(header_sectors, sect_size);
@@ -534,29 +567,32 @@ write_output(void)
 	while (cur_part) {
 		int char_id;
 
-		guid_to_bytestring(&parts[i * 128],
+		guid_to_bytestring(parts + i * PART_ENTRY_SIZE + 0,
 			&cur_part->type); /* PartitionTypeGUID */
-		guid_to_bytestring(&parts[i * 128 + 16],
+		guid_to_bytestring(parts + i * PART_ENTRY_SIZE + 16,
 			&cur_part->uuid); /* UniquePartitionGUID */
-		*(uint64_t *)&parts[i * 128 + 32] =
-			cur_part->sect_start; /* StartingLBA */
-		*(uint64_t *)&parts[i * 128 + 40] = cur_part->sect_start +
-						    cur_part->sect_length -
-						    1; /* EndingLBA */
-		*(uint64_t *)&parts[i * 128 + 48] =
-			cur_part->attrs; /* Attributes */
+		set_u64(parts + i * PART_ENTRY_SIZE + 32,
+			cur_part->sect_start); /* StartingLBA */
+		set_u64(parts + i * PART_ENTRY_SIZE + 40,
+			cur_part->sect_start + cur_part->sect_length -
+				1); /* EndingLBA */
+		set_u64(parts + i * PART_ENTRY_SIZE + 48,
+			cur_part->attrs); /* Attributes */
 
 		/*
 		 * TODO settle missing UTF-16LE conversion issue somehow,
 		 * possibly by simply limiting the tool to ASCII here?
 		 * TODO used to be "&& char_id < 35" but MAX_PART_NAME is 36
 		 * now so which is correct? do we need a "double zero" at the
-		 * end or not? what does the spec say?
+		 * end or not? what does the spec say? sfdisk works with 36
+		 * chars and if we try 37 it just ignores the extra one, so
+		 * there's some indication that no "double zero" is needed and
+		 * that 36 is indeed the correct limit
 		 */
 		int len = min(strlen(cur_part->name), MAX_PART_NAME);
 		for (char_id = 0; char_id < len; char_id++) {
-			*(uint16_t *)&parts[i * 128 + 56 + char_id * 2] =
-				(uint16_t)cur_part->name[char_id];
+			set_u16(parts + i * PART_ENTRY_SIZE + 56 + char_id * 2,
+				cur_part->name[char_id]);
 		}
 
 		i++;
@@ -564,15 +600,23 @@ write_output(void)
 	}
 
 	/* Do CRC calculations on the partition table entries and GPT headers */
-	CalculateCrc32(parts, part_count * 128, (uint32_t *)&gpt[88]);
-	CalculateCrc32(gpt, 96, (uint32_t *)&gpt[16]);
-
-	memcpy(gpt2, gpt, 96);
-	*(uint32_t *)&gpt2[16] = 0; /* HeaderCRC32 */
-	*(uint64_t *)&gpt2[24] = secondary_gpt_sect; /* MyLBA */
-	*(uint64_t *)&gpt2[32] = 0x1; /* AlternateLBA */
-	*(uint64_t *)&gpt2[72] = secondary_headers_sect; /* PartitionEntryLBA */
-	CalculateCrc32(gpt2, 96, (uint32_t *)&gpt2[16]);
+	uint32_t parts_crc;
+	CalculateCrc32(parts, part_count * PART_ENTRY_SIZE, &parts_crc);
+	set_u32(gpt + 88, parts_crc);
+
+	uint32_t gpt_crc;
+	CalculateCrc32(gpt, GPT_HEADER_SIZE, &gpt_crc);
+	set_u32(gpt + 16, gpt_crc);
+
+	memcpy(gpt2, gpt, GPT_HEADER_SIZE);
+	set_u32(gpt2 + 16, 0); /* HeaderCRC32 */
+	set_u64(gpt2 + 24, secondary_gpt_sect); /* MyLBA */
+	set_u64(gpt2 + 32, 0x1); /* AlternateLBA */
+	set_u64(gpt2 + 72, secondary_headers_sect); /* PartitionEntryLBA */
+
+	uint32_t gpt2_crc;
+	CalculateCrc32(gpt2, GPT_HEADER_SIZE, &gpt2_crc);
+	set_u32(gpt2 + 16, gpt2_crc);
 
 	/* Write primary GPT and headers */
 	if (fwrite(gpt, 1, sect_size, output) != sect_size) {