about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorPeter H. Froehlich <peter.hans.froehlich@gmail.com>2021-04-10 12:57:55 +0200
committerPeter H. Froehlich <peter.hans.froehlich@gmail.com>2021-04-10 12:57:55 +0200
commitd8db100f9b1913dd0e204f7561bc89f1f46fcefc (patch)
treefea7ded38204176e886119752f219dc720871664
parentc902e91474706eea7a6f28910b777a3387168baa (diff)
downloadmkgpt-d8db100f9b1913dd0e204f7561bc89f1f46fcefc.tar.gz
Removed bad asserts, removed overly complex random, lots of other fixes.
-rw-r--r--.gitignore1
-rw-r--r--Makefile28
-rw-r--r--README.md1
-rw-r--r--crc32.c93
-rw-r--r--crc32.h12
-rw-r--r--fstypes.c4
-rw-r--r--fstypes.h2
-rw-r--r--guid.c149
-rw-r--r--guid.h13
-rw-r--r--mkgpt.c143
-rw-r--r--part.h4
-rwxr-xr-xtest-mkgpt.sh25
12 files changed, 237 insertions, 238 deletions
diff --git a/.gitignore b/.gitignore
index 5761abc..d8ac7ef 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
 *.o
+compile_commands.json
diff --git a/Makefile b/Makefile
index 8a8d04d..731570a 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,6 @@
-CFLAGS:=-Wall -Wextra -Wpedantic -std=c11
+CFLAGS+=-Wall -Wextra -Wpedantic -std=c11 -D_DEFAULT_SOURCE
 ALL:=mkgpt
+PREFIX:=/usr/local
 
 dev: CFLAGS+=-g3 -Og -fsanitize=address -fsanitize=undefined
 dev: LDFLAGS+=-fsanitize=address -fsanitize=undefined
@@ -9,22 +10,29 @@ prod: CFLAGS+=-g0 -Os
 prod: LDFLAGS+=-s
 prod: $(ALL)
 
-static: CC:=musl-gcc
-static: CFLAGS+=-g0 -Os
-static: LDFLAGS+=-static -s
-static: $(ALL)
+static: LDFLAGS+=-static
+static: prod
+
+musl-static: CC:=musl-gcc
+musl-static: static
 
 mkgpt: mkgpt.o crc32.o fstypes.o guid.o
 
-mkgpt.o: mkgpt.c guid.h fstypes.h part.h
+mkgpt.o: mkgpt.c guid.h fstypes.h part.h crc32.h
 fstypes.o: fstypes.c fstypes.h guid.h
 guid.o: guid.c guid.h
-crc32.o: crc32.c
+crc32.o: crc32.c crc32.h
 
-.PHONY: check clean format
+.PHONY: check clean format install uninstall
 check:
-	cppcheck --enable=all --inconclusive --std=c11 .
+	-cppcheck --enable=all --inconclusive --std=c11 .
+	-shellcheck *.sh
 clean:
 	$(RM) *.o $(ALL)
 format:
-	clang-format -verbose -i *.[ch]
+	-clang-format -verbose -i *.[ch]
+install: prod
+	mkdir -pv $(DESTDIR)$(PREFIX)/bin
+	cp -fv mkgpt $(DESTDIR)$(PREFIX)/bin
+uninstall:
+	rm -fv $(DESTDIR)$(PREFIX)/bin/mkgpt
diff --git a/README.md b/README.md
index 28e5ef6..09837d1 100644
--- a/README.md
+++ b/README.md
@@ -60,3 +60,4 @@ Optionally, the string `random` can be used to generate a random GUID.
 - no way to make room for larger boot loaders or to create swap partitions
 - some overly specific code (Linux, Windoze) without a strong need for it
 - some strange code (static info in oversized, dynamically populated array?)
+- some rather broken code (required calls in asserts, misaligned pointers)
diff --git a/crc32.c b/crc32.c
index 6c268ef..d232b38 100644
--- a/crc32.c
+++ b/crc32.c
@@ -18,55 +18,56 @@ Abstract:
   CalcuateCrc32 routine.
 
   Modified to avoid EFI dependencies for mkgpt
+  Modified to include a proper header file
 
 --*/
 
-#include <stdlib.h>
-#include <stdint.h>
-
-uint32_t mCrcTable[256] = {0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
-	0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4,
-	0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
-	0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB,
-	0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
-	0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E,
-	0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
-	0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75,
-	0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
-	0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808,
-	0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
-	0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F,
-	0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
-	0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162,
-	0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
-	0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49,
-	0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
-	0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC,
-	0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
-	0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3,
-	0xB966D409, 0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
-	0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6,
-	0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
-	0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D,
-	0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
-	0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0,
-	0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
-	0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767,
-	0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
-	0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A,
-	0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
-	0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31,
-	0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
-	0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14,
-	0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
-	0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B,
-	0x6FB077E1, 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
-	0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE,
-	0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
-	0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5,
-	0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
-	0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8,
-	0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D};
+#include "crc32.h"
+
+static uint32_t mCrcTable[256] = {0x00000000, 0x77073096, 0xEE0E612C,
+	0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832,
+	0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07,
+	0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D,
+	0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A,
+	0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8,
+	0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD,
+	0xA50AB56B, 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3,
+	0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A, 0xC8D75180,
+	0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, 0x2802B89E,
+	0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB,
+	0xB6662D3D, 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589,
+	0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E,
+	0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4,
+	0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1,
+	0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF,
+	0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074,
+	0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A,
+	0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F,
+	0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525,
+	0x206F85B3, 0xB966D409, 0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822,
+	0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320,
+	0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615,
+	0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B,
+	0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268,
+	0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76,
+	0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43,
+	0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1,
+	0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6,
+	0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C,
+	0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9,
+	0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7,
+	0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C,
+	0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 0x95BF4A82,
+	0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7,
+	0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD,
+	0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA,
+	0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278,
+	0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D,
+	0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53,
+	0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330,
+	0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E,
+	0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B,
+	0x2D02EF8D};
 
 int
 CalculateCrc32(uint8_t *Data, size_t DataSize, uint32_t *CrcOut)
diff --git a/crc32.h b/crc32.h
new file mode 100644
index 0000000..2158681
--- /dev/null
+++ b/crc32.h
@@ -0,0 +1,12 @@
+#pragma once
+
+#ifndef CRC32_H
+#define CRC32_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+int
+CalculateCrc32(uint8_t *Data, size_t DataSize, uint32_t *CrcOut);
+
+#endif
diff --git a/fstypes.c b/fstypes.c
index 094db3e..383f8c5 100644
--- a/fstypes.c
+++ b/fstypes.c
@@ -19,14 +19,12 @@
  * THE SOFTWARE.
  */
 
-#include "guid.h"
+#include "fstypes.h"
 #include <stddef.h>
 
 GUID fstypes[512];
 char *fsnames[512];
 
-#include "fstypes.h"
-
 void
 init_fstypes()
 {
diff --git a/fstypes.h b/fstypes.h
index f1b81c7..4c63e64 100644
--- a/fstypes.h
+++ b/fstypes.h
@@ -1,3 +1,5 @@
+#pragma once
+
 /* Copyright (C) 2014 by John Cronin
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
diff --git a/guid.c b/guid.c
index b4ee887..12247fc 100644
--- a/guid.c
+++ b/guid.c
@@ -19,32 +19,22 @@
  * THE SOFTWARE.
  */
 
-#include <stddef.h>
+#include "guid.h"
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <time.h>
 
-#ifdef WINDOWS
-#include <windows.h>
-#include <wincrypt.h>
-#endif
-
-#include "guid.h"
-
 #define GUID_FMT                                                               \
 	"%08X-%04hX-%04hX-%02hhX%02hhX-%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX"
 
-static int rnd_init = 0;
-
 int
-guid_to_string(char *str, GUID *guid)
+guid_to_string(char *str, const GUID *guid)
 {
 	if (guid == NULL) {
-		fprintf(stderr, "guid_to_string: guid is null\n");
 		return -1;
 	}
 	if (str == NULL) {
-		fprintf(stderr, "guid_to_string: str is null\n");
 		return -1;
 	}
 
@@ -56,14 +46,12 @@ guid_to_string(char *str, GUID *guid)
 }
 
 int
-string_to_guid(GUID *guid, char *str)
+string_to_guid(GUID *guid, const char *str)
 {
 	if (guid == NULL) {
-		fprintf(stderr, "string_to_guid: guid is null\n");
 		return -1;
 	}
 	if (str == NULL) {
-		fprintf(stderr, "string_to_guid: str is null\n");
 		return -1;
 	}
 
@@ -76,134 +64,71 @@ string_to_guid(GUID *guid, char *str)
 }
 
 int
-guid_to_bytestring(uint8_t *bytes, GUID *guid)
+guid_to_bytestring(uint8_t *bytes, const GUID *guid)
 {
-	int i;
-
 	if (guid == NULL) {
-		fprintf(stderr, "guid_to_bytestring: guid is null\n");
 		return -1;
 	}
 	if (bytes == NULL) {
-		fprintf(stderr, "guid_to_bytestring: bytes is null\n");
 		return -1;
 	}
 
+	/* TODO potential alignment problem? */
 	*(uint32_t *)&bytes[0] = guid->data1;
 	*(uint16_t *)&bytes[4] = guid->data2;
 	*(uint16_t *)&bytes[6] = guid->data3;
-	for (i = 0; i < 8; i++)
+	for (int i = 0; i < 8; i++) {
 		bytes[8 + i] = guid->data4[i];
+	}
 
 	return 0;
 }
 
 int
-guid_is_zero(GUID *guid)
+guid_is_zero(const GUID *guid)
 {
-	int i;
-
-	if (guid->data1 != 0)
+	if (guid->data1 != 0) {
 		return 0;
-	if (guid->data2 != 0)
-		return 0;
-	if (guid->data3 != 0)
+	}
+	if (guid->data2 != 0) {
 		return 0;
-	for (i = 0; i < 8; i++) {
-		if (guid->data4[i] != 0)
-			return 0;
 	}
-	return 1;
-}
-
-void
-init_rnd()
-{
-	/* Attempt to initialise the random number generator */
-	FILE *rnd = fopen("/dev/random", "r");
-	if (rnd != NULL) {
-		unsigned int seed;
-		if (fread(&seed, 1, sizeof(unsigned int), rnd) ==
-			sizeof(unsigned int)) {
-			srand(seed);
-			fclose(rnd);
-			rnd_init = 1;
-			return;
-		}
-
-		fclose(rnd);
+	if (guid->data3 != 0) {
+		return 0;
 	}
-
-#ifdef WINDOWS
-	{
-		HCRYPTPROV prov = 0;
-		if (!CryptAcquireContext(&prov, NULL, NULL, PROV_INTEL_SEC,
-			    CRYPT_VERIFYCONTEXT)) {
-			if (!CryptAcquireContext(&prov, NULL, NULL,
-				    PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
-				prov = 0;
-		}
-
-		if (prov != 0) {
-			unsigned int seed;
-			CryptGenRandom(
-				prov, sizeof(unsigned int), (BYTE *)&seed);
-			srand(seed);
-			rnd_init = 1;
-			return;
+	for (int i = 0; i < 8; i++) {
+		if (guid->data4[i] != 0) {
+			return 0;
 		}
 	}
-#endif
-
-	{
-		time_t t = time(NULL);
-		struct tm *tmptr = gmtime(&t);
-		int seed = tmptr->tm_hour;
-		seed <<= 3;
-		seed ^= tmptr->tm_isdst;
-		seed <<= 3;
-		seed ^= tmptr->tm_mday;
-		seed <<= 3;
-		seed ^= tmptr->tm_min;
-		seed <<= 3;
-		seed ^= tmptr->tm_mon;
-		seed <<= 3;
-		seed ^= tmptr->tm_sec;
-		seed <<= 3;
-		seed ^= tmptr->tm_wday;
-		seed <<= 3;
-		seed ^= tmptr->tm_yday;
-		seed <<= 3;
-		seed ^= tmptr->tm_year;
-
-		srand((unsigned int)seed);
-		rnd_init = 1;
-		return;
-	}
+	return 1;
 }
 
-uint8_t
-rnd_byte()
+static uint32_t
+rnd()
 {
-	if (rnd_init == 0)
-		init_rnd();
-
-	return (uint8_t)(rand() & 0xff);
+	return random() & 0xff; /* just a byte please */
 }
 
 int
 random_guid(GUID *guid)
 {
-	int i;
-
-	guid->data1 = (uint32_t)rnd_byte() | (((uint32_t)rnd_byte()) << 8) |
-		      (((uint32_t)rnd_byte()) << 16) |
-		      (((uint32_t)rnd_byte()) << 24);
-	guid->data2 = (uint16_t)rnd_byte() | (((uint16_t)rnd_byte()) << 8);
-	guid->data3 = (uint16_t)rnd_byte() |
-		      (((uint16_t)((rnd_byte() & 0x0f) | 0x40)) << 8);
-	for (i = 0; i < 8; i++)
-		guid->data4[i] = rnd_byte();
+	if (guid == NULL) {
+		return -1;
+	}
+
+	static int initialized = 0;
+	if (!initialized) {
+		srandom(time(NULL));
+		initialized = 1;
+	}
+
+	guid->data1 = rnd() | rnd() << 8 | rnd() << 16 | rnd() << 24;
+	guid->data2 = rnd() | rnd() << 8;
+	guid->data3 = rnd() | ((rnd() & 0x0f) | 0x40) << 8;
+	for (int i = 0; i < 8; i++) {
+		guid->data4[i] = rnd();
+	}
 
 	return 0;
 }
diff --git a/guid.h b/guid.h
index 1a73cf9..c9e0509 100644
--- a/guid.h
+++ b/guid.h
@@ -1,3 +1,5 @@
+#pragma once
+
 /* Copyright (C) 2014 by John Cronin
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -24,6 +26,7 @@
 
 #include <stdint.h>
 
+/* TODO is this abstraction really needed? (see fstype.c mess) */
 typedef struct _guid {
 	uint32_t data1;
 	uint16_t data2;
@@ -34,15 +37,17 @@ typedef struct _guid {
 #define GUID_STRING_LENGTH 36
 #define GUID_BYTESTRING_LENGTH 16
 
+/* TODO never actually used? */
 int
-guid_to_string(char *str, GUID *guid);
+guid_to_string(char *str, const GUID *guid);
+
 int
-string_to_guid(GUID *guid, char *str);
+string_to_guid(GUID *guid, const char *str);
 int
-guid_to_bytestring(uint8_t *bytes, GUID *guid);
+guid_to_bytestring(uint8_t *bytes, const GUID *guid);
 int
 random_guid(GUID *guid);
 int
-guid_is_zero(GUID *guid);
+guid_is_zero(const GUID *guid);
 
 #endif
diff --git a/mkgpt.c b/mkgpt.c
index 382f774..29ac72b 100644
--- a/mkgpt.c
+++ b/mkgpt.c
@@ -19,43 +19,41 @@
  * THE SOFTWARE.
  */
 
+#include "crc32.h"
+#include "fstypes.h"
 #include "guid.h"
 #include "part.h"
-#include "fstypes.h"
+
+#include <errno.h>
+#include <limits.h>
 #include <stddef.h>
 #include <stdio.h>
-#include <string.h>
 #include <stdlib.h>
-#include <assert.h>
-#include <errno.h>
-#include <limits.h>
+#include <string.h>
 
-void
+static void
 dump_help(char *fname);
-int
+static int
 check_parts();
-int
+static int
 parse_opts(int argc, char **argv);
-int
+static int
 parse_guid(char *str, GUID *guid);
-void
+static void
 write_output();
 
-int
-CalculateCrc32(uint8_t *Data, size_t DataSize, uint32_t *CrcOut);
-
-size_t sect_size = 512;
-long image_sects = 0;
-long min_image_sects = 2048;
-PART *first_part = NULL;
-PART *last_part = NULL;
-FILE *output = NULL;
-GUID disk_guid;
-int part_count;
-int header_sectors;
-int first_usable_sector;
-int secondary_headers_sect;
-int secondary_gpt_sect;
+static size_t sect_size = 512;
+static long image_sects = 0;
+static long min_image_sects = 2048;
+static PART *first_part = NULL;
+static PART *last_part = NULL;
+static FILE *output = NULL;
+static GUID disk_guid;
+static int part_count;
+static int header_sectors;
+static int first_usable_sector;
+static int secondary_headers_sect;
+static int secondary_gpt_sect;
 
 int
 main(int argc, char **argv)
@@ -86,7 +84,7 @@ main(int argc, char **argv)
 	return 0;
 }
 
-int
+static int
 parse_opts(int argc, char **argv)
 {
 	int i = 1;
@@ -201,13 +199,12 @@ parse_opts(int argc, char **argv)
 			}
 
 			/* Allocate a new partition structure */
-			cur_part = (PART *)malloc(sizeof(PART));
+			cur_part = calloc(1, sizeof(*cur_part));
 			if (cur_part == NULL) {
 				fprintf(stderr, "out of memory allocating "
 						"partition structure\n");
 				return -1;
 			}
-			memset(cur_part, 0, sizeof(PART));
 			cur_part_id++;
 			cur_part->id = cur_part_id;
 
@@ -320,23 +317,22 @@ parse_opts(int argc, char **argv)
 	return 0;
 }
 
-void
+static void
 dump_help(char *fname)
 {
-	printf("Usage: %s -o <output_file> [-h] [--sector-size sect_size] [-s "
-	       "min_image_size] [partition def 0] [part def 1] ... [part def "
-	       "n]\n"
+	printf("Usage: %s -o <output_file> [-h] [--disk-guid GUID] "
+	       "[--sector-size sect_size] [-s min_image_size] "
+	       "[partition def 0] [part def 1] ... [part def n]\n"
 	       "  Partition definition: --part <image_file> --type <type> "
 	       "[--uuid uuid] [--name name]\n"
 	       "  Please see the README file for further information\n",
 		fname);
 }
 
-int
+static int
 parse_guid(char *str, GUID *guid)
 {
 	long mbr_id = -1;
-	int i;
 
 	/* detect request for random uuid */
 	if (!strcmp(str, "random") || !strcmp(str, "rnd"))
@@ -348,7 +344,7 @@ parse_guid(char *str, GUID *guid)
 		mbr_id = -1;
 
 	/* detect by name */
-	for (i = 0; i < 512; i++) {
+	for (int i = 0; i < 512; i++) {
 		if (fsnames[i] == NULL)
 			continue;
 		if (!strcmp(fsnames[i], str)) {
@@ -360,7 +356,7 @@ parse_guid(char *str, GUID *guid)
 	if (mbr_id >= 0 && mbr_id <= 511) {
 		if (guid_is_zero(&fstypes[mbr_id]))
 			return -1;
-		memcpy(guid, &fstypes[mbr_id], sizeof(GUID));
+		*guid = fstypes[mbr_id];
 		return 0;
 	}
 
@@ -368,7 +364,7 @@ parse_guid(char *str, GUID *guid)
 	return string_to_guid(guid, str);
 }
 
-int
+static int
 check_parts()
 {
 	/* Iterate through the partitions, checking validity */
@@ -431,7 +427,7 @@ check_parts()
 		}
 
 		if (cur_part->name == NULL) {
-			cur_part->name = (char *)malloc(128);
+			cur_part->name = malloc(128);
 			sprintf(cur_part->name, "part%i", cur_part_id);
 		}
 
@@ -459,7 +455,7 @@ check_parts()
 			image_sects = min_image_sects;
 	} else if (image_sects < needed_file_length) {
 		fprintf(stderr,
-			"requested image size (%lu) is too small to hold the "
+			"requested image size (%zu) is too small to hold the "
 			"partitions\n",
 			image_sects * sect_size);
 		return -1;
@@ -471,7 +467,14 @@ check_parts()
 	return 0;
 }
 
-void
+static void
+panic(const char *msg)
+{
+	fprintf(stderr, "panic: %s", msg);
+	exit(EXIT_FAILURE);
+}
+
+static void
 write_output()
 {
 	int i;
@@ -479,8 +482,10 @@ write_output()
 	PART *cur_part;
 
 	/* Write MBR */
-	mbr = (uint8_t *)malloc(sect_size);
-	memset(mbr, 0, sect_size);
+	mbr = calloc(1, sect_size);
+	if (mbr == NULL) {
+		panic("calloc failed");
+	}
 
 	*(uint32_t *)&mbr[446] =
 		0x00020000; /* boot indicator = 0, start CHS = 0x000200 */
@@ -498,16 +503,19 @@ write_output()
 	mbr[510] = 0x55;
 	mbr[511] = 0xaa; /* Signature */
 
-	assert(fwrite(mbr, 1, sect_size, output) == sect_size);
+	if (fwrite(mbr, 1, sect_size, output) != sect_size) {
+		panic("fwrite failed");
+	}
 
 	/* Define GPT headers */
-	gpt = (uint8_t *)malloc(sect_size);
-	assert(gpt);
-	gpt2 = (uint8_t *)malloc(sect_size);
-	assert(gpt2);
-
-	memset(gpt, 0, sect_size);
-	memset(gpt2, 0, sect_size);
+	gpt = calloc(1, sect_size);
+	if (gpt == NULL) {
+		panic("calloc failed");
+	}
+	gpt2 = calloc(1, sect_size);
+	if (gpt2 == NULL) {
+		panic("calloc failed");
+	}
 
 	*(uint64_t *)&gpt[0] = 0x5452415020494645ULL; /* Signature */
 	*(uint32_t *)&gpt[8] = 0x00010000UL; /* Revision */
@@ -525,9 +533,10 @@ write_output()
 	*(uint32_t *)&gpt[88] = 0; /* PartitionEntryArrayCRC32 */
 
 	/* Define GPT partition entries */
-	parts = (uint8_t *)malloc(header_sectors * sect_size);
-	assert(parts);
-	memset(parts, 0, header_sectors * sect_size);
+	parts = calloc(header_sectors, sect_size);
+	if (parts == NULL) {
+		panic("calloc failed");
+	}
 
 	cur_part = first_part;
 	i = 0;
@@ -568,13 +577,17 @@ write_output()
 	CalculateCrc32(gpt2, 96, (uint32_t *)&gpt2[16]);
 
 	/* Write primary GPT and headers */
-	assert(fwrite(gpt, 1, sect_size, output) == sect_size);
-	assert(fwrite(parts, 1, header_sectors * sect_size, output) ==
-		header_sectors * sect_size);
+	if (fwrite(gpt, 1, sect_size, output) != sect_size) {
+		panic("fwrite failed");
+	}
+	if (fwrite(parts, 1, header_sectors * sect_size, output) !=
+		header_sectors * sect_size) {
+		panic("fwrite failed");
+	}
 
 	/* Write partitions */
 	cur_part = first_part;
-	image_buf = (uint8_t *)malloc(sect_size);
+	image_buf = malloc(sect_size);
 	while (cur_part) {
 		size_t bytes_read;
 		size_t bytes_written = 0;
@@ -591,8 +604,10 @@ write_output()
 					cur_part->sect_length * sect_size -
 					bytes_written;
 
-			assert(fwrite(image_buf, 1, bytes_to_write, output) ==
-				bytes_to_write);
+			if (fwrite(image_buf, 1, bytes_to_write, output) !=
+				bytes_to_write) {
+				panic("fwrite failed");
+			}
 
 			bytes_written += bytes_to_write;
 		}
@@ -602,8 +617,12 @@ write_output()
 
 	/* Write secondary GPT partition headers and header */
 	fseek(output, secondary_headers_sect * sect_size, SEEK_SET);
-	assert(fwrite(parts, 1, header_sectors * sect_size, output) ==
-		header_sectors * sect_size);
+	if (fwrite(parts, 1, header_sectors * sect_size, output) !=
+		header_sectors * sect_size) {
+		panic("fwrite failed");
+	}
 	fseek(output, secondary_gpt_sect * sect_size, SEEK_SET);
-	assert(fwrite(gpt2, 1, sect_size, output) == sect_size);
+	if (fwrite(gpt2, 1, sect_size, output) != sect_size) {
+		panic("fwrite failed");
+	}
 }
diff --git a/part.h b/part.h
index 0d4b7c3..80504c8 100644
--- a/part.h
+++ b/part.h
@@ -1,3 +1,5 @@
+#pragma once
+
 /* Copyright (C) 2014 by John Cronin
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -37,7 +39,7 @@ typedef struct _part {
 	char *name;
 	FILE *src;
 
-	struct _part *next;
+	struct _part *next; /* TODO why build a list? */
 } PART;
 
 #endif
diff --git a/test-mkgpt.sh b/test-mkgpt.sh
new file mode 100755
index 0000000..43bee6e
--- /dev/null
+++ b/test-mkgpt.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+#
+# Simplistic test case, but better than none.
+
+tmpdir="/tmp/test-mkgpt"
+
+if [ ! -x ./mkgpt ]; then
+	echo "No ./mkgpt to run, no fun!"
+	exit 1
+fi
+
+mkdir -pv ${tmpdir}
+for name in a.img b.img c.img; do
+	truncate --size=16M ${tmpdir}/${name}
+done
+
+# TODO something goes wrong with --sector-size 1024 or 4096
+./mkgpt -o ${tmpdir}/bla.img \
+	--part ${tmpdir}/a.img --type system \
+	--part ${tmpdir}/b.img --type fat32 \
+	--part ${tmpdir}/c.img --type linux
+
+fdisk -l ${tmpdir}/bla.img
+
+rm -rfv ${tmpdir}