shithub: riscv

Download patch

ref: 4a4575bd4e0d92a0c699108c439d3cb9a546878b
parent: 09b6a92145540ca0f8b50454600e95c3dc17100f
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Fri May 29 23:22:08 EDT 2015

disk/edisk: gpt partition table editor (no manpage, work in progress)

--- /dev/null
+++ b/sys/src/cmd/disk/prep/edisk.c
@@ -1,0 +1,1214 @@
+/*
+ * edisk - edit gpt disk partition table
+ */
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <ctype.h>
+#include <disk.h>
+#include "edit.h"
+#include <mp.h>
+#include <libsec.h>
+
+#define TB (1024LL*GB)
+#define GB (1024*1024*1024)
+#define MB (1024*1024)
+#define KB (1024)
+
+typedef struct Header Header;
+typedef struct Entry Entry;
+
+typedef struct Type Type;
+typedef struct Flag Flag;
+typedef struct Gptpart Gptpart;
+
+struct Header
+{
+	uchar	sig[8];
+	uchar	rev[4];
+	uchar	hdrsiz[4];
+	uchar	hdrcrc[4];
+	uchar	zero[4];
+	uchar	selflba[8];
+	uchar	backlba[8];
+	uchar	firstlba[8];
+	uchar	lastlba[8];
+	uchar	devid[16];
+	uchar	tablba[8];
+	uchar	entrycount[4];
+	uchar	entrysize[4];
+	uchar	tabcrc[4];
+};
+
+struct Entry
+{
+	uchar	typeid[16];
+	uchar	partid[16];
+	uchar	firstlba[8];
+	uchar	lastlba[8];
+	uchar	attr[8];
+	uchar	name[72];
+};
+
+enum {
+	Headersiz = 92,
+	Entrysiz = 16+16+8+8+8+72,
+};
+
+
+struct Type {
+	uchar	uuid[16];
+	char	*name;
+	char	*desc;
+};
+
+struct Flag {
+	int	s;
+	char	c;
+	char	*desc;
+};
+
+struct Gptpart {
+	Part;
+	Type	*type;	/* nil when not in use */
+	uvlong	attr;
+	uchar	uuid[16];
+	Rune	label[72+1];
+	char	namebuf[8];
+};
+
+static uchar	*pmbr;
+static Header	*phdr;
+static Header	*bhdr;
+
+static vlong	partoff;
+static vlong	partend;
+
+static Gptpart	*parts;
+static int	nparts;
+
+static uchar	devid[16];
+static uchar	zeros[16];
+
+static Type	*type9;
+
+/* RFC4122, but in little endian format */
+#define UU(a,b,c,d,e,f,g,h,i,j) { \
+	(a)&255,((a)>>8)&255,((a)>>16)&255,((a)>>24)&255, \
+	(b)&255,((b)>>8)&255, \
+	(c)&255,((c)>>8)&255, \
+	((d)>>8)&255,(d)&255, \
+	(e)&255,(f)&255,(g)&255,(h)&255,(i)&255,(j)&255}
+
+static Type	types[100] = {
+{UU(0x00000000,0x0000,0x0000,0x0000,0x00,0x00,0x00,0x00,0x00,0x00), "", "Unused entry"},
+{UU(0x024DEE41,0x33E7,0x11D3,0x9D69,0x00,0x08,0xC7,0x81,0xF3,0x9F), "mbr", "MBR partition"},
+{UU(0xC12A7328,0xF81F,0x11D2,0xBA4B,0x00,0xA0,0xC9,0x3E,0xC9,0x3B), "esp", "EFI System Partition"},
+{UU(0x21686148,0x6449,0x6E6F,0x744E,0x65,0x65,0x64,0x45,0x46,0x49), "bios", "BIOS boot partition"},
+{UU(0xD3BFE2DE,0x3DAF,0x11DF,0xBA40,0xE3,0xA5,0x56,0xD8,0x95,0x93), "iffs", "Intel Fast Flash"},
+{UU(0xF4019732,0x066E,0x4E12,0x8273,0x34,0x6C,0x56,0x41,0x49,0x4F), "sony", "Sony boot"},
+{UU(0xBFBFAFE7,0xA34F,0x448A,0x9A5B,0x62,0x13,0xEB,0x73,0x6C,0x22), "lenovo", "Lenovo boot"},
+{UU(0xE3C9E316,0x0B5C,0x4DB8,0x817D,0xF9,0x2D,0xF0,0x02,0x15,0xAE), "msr", "Microsoft Reserved Partition"},
+{UU(0xEBD0A0A2,0xB9E5,0x4433,0x87C0,0x68,0xB6,0xB7,0x26,0x99,0xC7), "dos", "Microsoft Basic data"},
+{UU(0x5808C8AA,0x7E8F,0x42E0,0x85D2,0xE1,0xE9,0x04,0x34,0xCF,0xB3), "ldmm", "Logical Disk Manager metadata"},
+{UU(0xAF9B60A0,0x1431,0x4F62,0xBC68,0x33,0x11,0x71,0x4A,0x69,0xAD), "ldmd", "Logical Disk Manager data"},
+{UU(0xDE94BBA4,0x06D1,0x4D40,0xA16A,0xBF,0xD5,0x01,0x79,0xD6,0xAC), "recovery", "Windows Recovery Environment"},
+{UU(0x37AFFC90,0xEF7D,0x4E96,0x91C3,0x2D,0x7A,0xE0,0x55,0xB1,0x74), "gpfs", "IBM General Parallel File System"},
+{UU(0xE75CAF8F,0xF680,0x4CEE,0xAFA3,0xB0,0x01,0xE5,0x6E,0xFC,0x2D), "storagespaces", "Storage Spaces"},
+{UU(0x75894C1E,0x3AEB,0x11D3,0xB7C1,0x7B,0x03,0xA0,0x00,0x00,0x00), "hpuxdata", "HP-UX Data"},
+{UU(0xE2A1E728,0x32E3,0x11D6,0xA682,0x7B,0x03,0xA0,0x00,0x00,0x00), "hpuxserv", "HP-UX Service"},
+{UU(0x0FC63DAF,0x8483,0x4772,0x8E79,0x3D,0x69,0xD8,0x47,0x7D,0xE4), "linuxdata", "Linux Data"},
+{UU(0xA19D880F,0x05FC,0x4D3B,0xA006,0x74,0x3F,0x0F,0x84,0x91,0x1E), "linuxraid", "Linux RAID"},
+{UU(0x0657FD6D,0xA4AB,0x43C4,0x84E5,0x09,0x33,0xC8,0x4B,0x4F,0x4F), "linuxswap", "Linux Swap"},
+{UU(0xE6D6D379,0xF507,0x44C2,0xA23C,0x23,0x8F,0x2A,0x3D,0xF9,0x28), "linuxlvm", "Linux Logical Volume Manager"},
+{UU(0x933AC7E1,0x2EB4,0x4F13,0xB844,0x0E,0x14,0xE2,0xAE,0xF9,0x15), "linuxhome", "Linux /home"},
+{UU(0x3B8F8425,0x20E0,0x4F3B,0x907F,0x1A,0x25,0xA7,0x6F,0x98,0xE8), "linuxsrv", "Linux /srv"},
+{UU(0x7FFEC5C9,0x2D00,0x49B7,0x8941,0x3E,0xA1,0x0A,0x55,0x86,0xB7), "linuxcrypt", "Linux Plain dm-crypt"},
+{UU(0xCA7D7CCB,0x63ED,0x4C53,0x861C,0x17,0x42,0x53,0x60,0x59,0xCC), "luks", "LUKS"},
+{UU(0x8DA63339,0x0007,0x60C0,0xC436,0x08,0x3A,0xC8,0x23,0x09,0x08), "linuxreserved", "Linux Reserved"},
+{UU(0x83BD6B9D,0x7F41,0x11DC,0xBE0B,0x00,0x15,0x60,0xB8,0x4F,0x0F), "fbsdboot", "FreeBSD Boot"},
+{UU(0x516E7CB4,0x6ECF,0x11D6,0x8FF8,0x00,0x02,0x2D,0x09,0x71,0x2B), "fbsddata", "FreeBSD Data"},
+{UU(0x516E7CB5,0x6ECF,0x11D6,0x8FF8,0x00,0x02,0x2D,0x09,0x71,0x2B), "fbsdswap", "FreeBSD Swap"},
+{UU(0x516E7CB6,0x6ECF,0x11D6,0x8FF8,0x00,0x02,0x2D,0x09,0x71,0x2B), "fbsdufs", "FreeBSD Unix File System"},
+{UU(0x516E7CB8,0x6ECF,0x11D6,0x8FF8,0x00,0x02,0x2D,0x09,0x71,0x2B), "fbsdvvm", "FreeBSD Vinum volume manager"},
+{UU(0x516E7CBA,0x6ECF,0x11D6,0x8FF8,0x00,0x02,0x2D,0x09,0x71,0x2B), "fbsdzfs", "FreeBSD ZFS"},
+{UU(0x48465300,0x0000,0x11AA,0xAA11,0x00,0x30,0x65,0x43,0xEC,0xAC), "applehfs", "Apple HFS+"},
+{UU(0x55465300,0x0000,0x11AA,0xAA11,0x00,0x30,0x65,0x43,0xEC,0xAC), "appleufs", "Apple UFS"},
+{UU(0x6A898CC3,0x1DD2,0x11B2,0x99A6,0x08,0x00,0x20,0x73,0x66,0x31), "applezfs", "Apple ZFS"},
+{UU(0x52414944,0x0000,0x11AA,0xAA11,0x00,0x30,0x65,0x43,0xEC,0xAC), "appleraid", "Apple RAID"},
+{UU(0x52414944,0x5F4F,0x11AA,0xAA11,0x00,0x30,0x65,0x43,0xEC,0xAC), "appleraidoff", "Apple RAID, offline"},
+{UU(0x426F6F74,0x0000,0x11AA,0xAA11,0x00,0x30,0x65,0x43,0xEC,0xAC), "appleboot", "Apple Boot"},
+{UU(0x4C616265,0x6C00,0x11AA,0xAA11,0x00,0x30,0x65,0x43,0xEC,0xAC), "applelabel", "Apple Label"},
+{UU(0x5265636F,0x7665,0x11AA,0xAA11,0x00,0x30,0x65,0x43,0xEC,0xAC), "appletv", "Apple TV Recovery"},
+{UU(0x53746F72,0x6167,0x11AA,0xAA11,0x00,0x30,0x65,0x43,0xEC,0xAC), "applecs", "Apple Core Storage"},
+{UU(0x6A82CB45,0x1DD2,0x11B2,0x99A6,0x08,0x00,0x20,0x73,0x66,0x31), "solarisboot", "Solaris Boot"},
+{UU(0x6A85CF4D,0x1DD2,0x11B2,0x99A6,0x08,0x00,0x20,0x73,0x66,0x31), "solarisroot", "Solaris Root"},
+{UU(0x6A87C46F,0x1DD2,0x11B2,0x99A6,0x08,0x00,0x20,0x73,0x66,0x31), "solarisswap", "Solaris Swap"},
+{UU(0x6A8B642B,0x1DD2,0x11B2,0x99A6,0x08,0x00,0x20,0x73,0x66,0x31), "solarisbakup", "Solaris Backup"},
+{UU(0x6A898CC3,0x1DD2,0x11B2,0x99A6,0x08,0x00,0x20,0x73,0x66,0x31), "solarisusr", "Solaris /usr"},
+{UU(0x6A8EF2E9,0x1DD2,0x11B2,0x99A6,0x08,0x00,0x20,0x73,0x66,0x31), "solarisvar", "Solaris /var"},
+{UU(0x6A90BA39,0x1DD2,0x11B2,0x99A6,0x08,0x00,0x20,0x73,0x66,0x31), "solarishome", "Solaris /home"},
+{UU(0x6A9283A5,0x1DD2,0x11B2,0x99A6,0x08,0x00,0x20,0x73,0x66,0x31), "solarisalt", "Solaris Alternate sector"},
+{UU(0x6A945A3B,0x1DD2,0x11B2,0x99A6,0x08,0x00,0x20,0x73,0x66,0x31), "solaris", "Solaris Reserved"},
+{UU(0x6A9630D1,0x1DD2,0x11B2,0x99A6,0x08,0x00,0x20,0x73,0x66,0x31), "solaris", "Solaris Reserved"},
+{UU(0x6A980767,0x1DD2,0x11B2,0x99A6,0x08,0x00,0x20,0x73,0x66,0x31), "solaris", "Solaris Reserved"},
+{UU(0x6A96237F,0x1DD2,0x11B2,0x99A6,0x08,0x00,0x20,0x73,0x66,0x31), "solaris", "Solaris Reserved"},
+{UU(0x6A8D2AC7,0x1DD2,0x11B2,0x99A6,0x08,0x00,0x20,0x73,0x66,0x31), "solaris", "Solaris Reserved"},
+{UU(0x49F48D32,0xB10E,0x11DC,0xB99B,0x00,0x19,0xD1,0x87,0x96,0x48), "nbsdswap", "NetBSD Swap"},
+{UU(0x49F48D5A,0xB10E,0x11DC,0xB99B,0x00,0x19,0xD1,0x87,0x96,0x48), "nbsdffs", "NetBSD FFS"},
+{UU(0x49F48D82,0xB10E,0x11DC,0xB99B,0x00,0x19,0xD1,0x87,0x96,0x48), "nbsdlfs", "NetBSD LFS"},
+{UU(0x49F48DAA,0xB10E,0x11DC,0xB99B,0x00,0x19,0xD1,0x87,0x96,0x48), "nbsdraid", "NetBSD RAID"},
+{UU(0x2DB519C4,0xB10F,0x11DC,0xB99B,0x00,0x19,0xD1,0x87,0x96,0x48), "nbsdcat", "NetBSD Concatenated"},
+{UU(0x2DB519EC,0xB10F,0x11DC,0xB99B,0x00,0x19,0xD1,0x87,0x96,0x48), "nbsdcrypt", "NetBSD Encrypted"},
+{UU(0xFE3A2A5D,0x4F32,0x41A7,0xB725,0xAC,0xCC,0x32,0x85,0xA3,0x09), "chromeoskern", "ChromeOS kernel"},
+{UU(0x3CB8E202,0x3B7E,0x47DD,0x8A3C,0x7F,0xF2,0xA1,0x3C,0xFC,0xEC), "chromeosroot", "ChromeOS rootfs"},
+{UU(0x2E0A753D,0x9E48,0x43B0,0x8337,0xB1,0x51,0x92,0xCB,0x1B,0x5E), "chromeos", "ChromeOS future use"},
+{UU(0x42465331,0x3BA3,0x10F1,0x802A,0x48,0x61,0x69,0x6B,0x75,0x21), "haikubfs", "Haiku BFS"},
+{UU(0x85D5E45E,0x237C,0x11E1,0xB4B3,0xE8,0x9A,0x8F,0x7F,0xC3,0xA7), "midbsdboot", "MidnightBSD Boot"},
+{UU(0x85D5E45A,0x237C,0x11E1,0xB4B3,0xE8,0x9A,0x8F,0x7F,0xC3,0xA7), "midbsddata", "MidnightBSD Data"},
+{UU(0x85D5E45B,0x237C,0x11E1,0xB4B3,0xE8,0x9A,0x8F,0x7F,0xC3,0xA7), "midbsdswap", "MidnightBSD Swap"},
+{UU(0x0394EF8B,0x237E,0x11E1,0xB4B3,0xE8,0x9A,0x8F,0x7F,0xC3,0xA7), "midbsdufs", "MidnightBSD Unix File System"},
+{UU(0x85D5E45C,0x237C,0x11E1,0xB4B3,0xE8,0x9A,0x8F,0x7F,0xC3,0xA7), "midbsdvvm", "MidnightBSD Vinum volume manager"},
+{UU(0x85D5E45D,0x237C,0x11E1,0xB4B3,0xE8,0x9A,0x8F,0x7F,0xC3,0xA7), "midbsdzfs", "MidnightBSD ZFS"},
+{UU(0x45B0969E,0x9B03,0x4F30,0xB4C6,0xB4,0xB8,0x0C,0xEF,0xF1,0x06), "cephjournal", "Ceph Journal"},
+{UU(0x45B0969E,0x9B03,0x4F30,0xB4C6,0x5E,0xC0,0x0C,0xEF,0xF1,0x06), "cephcrypt", "Ceph dm-crypt Encrypted Journal"},
+{UU(0x4FBD7E29,0x9D25,0x41B8,0xAFD0,0x06,0x2C,0x0C,0xEF,0xF0,0x5D), "cephosd", "Ceph OSD"},
+{UU(0x4FBD7E29,0x9D25,0x41B8,0xAFD0,0x5E,0xC0,0x0C,0xEF,0xF0,0x5D), "cephcryptosd", "Ceph dm-crypt OSD"},
+{UU(0x824CC7A0,0x36A8,0x11E3,0x890A,0x95,0x25,0x19,0xAD,0x3F,0x61), "openbsd", "OpenBSD Data"},
+{UU(0xCEF5A9AD,0x73BC,0x4601,0x89F3,0xCD,0xEE,0xEE,0xE3,0x21,0xA1), "qnx6", "QNX6 Power-safe file system"},
+{UU(0xC91818F9,0x8025,0x47AF,0x89D2,0xF0,0x30,0xD7,0x00,0x0C,0x2C), "plan9", "Plan 9"},
+};
+
+static Flag	flags[] = {
+	{ 0,	'S',	"system" },
+	{ 1,	'E',	"efi-hidden" },
+	{ 2,	'A',	"active" },
+	{ 60,	'R',	"read-only" },
+	{ 62,	'H',	"hidden" },
+	{ 63,	'M',	"nomount" },
+	{ -1,	0,	nil }
+};
+
+static void initcrc32(void);
+static u32int sumcrc32(u32int, uchar *, ulong);
+
+static u32int getle32(void*);
+static void putle32(void*, u32int);
+static u64int getle64(void *);
+static void putle64(void *, u64int);
+
+static void uugen(uchar uuid[16]);
+static Type* gettype(uchar uuid[16], char *name);
+static int uufmt(Fmt*);
+#pragma	varargck	type	"U"	uchar*
+
+static int attrfmt(Fmt*);
+#pragma varargck	type	"A"	uvlong
+
+static void rdpart(Edit*);
+static void autopart(Edit*);
+static void blankpart(Edit*);
+static void cmdnamectl(Edit*);
+
+static int blank;
+static int dowrite;
+static int file;
+static int rdonly;
+static int doauto;
+static int printflag;
+static int written;
+
+static void 	cmdsum(Edit*, Part*, vlong, vlong);
+static char 	*cmdadd(Edit*, char*, vlong, vlong);
+static char 	*cmddel(Edit*, Part*);
+static char 	*cmdext(Edit*, int, char**);
+static char 	*cmdhelp(Edit*);
+static char 	*cmdokname(Edit*, char*);
+static char 	*cmdwrite(Edit*);
+static void	cmdprintctl(Edit*, int);
+
+Edit edit = {
+	.add =		cmdadd,
+	.del =		cmddel,
+	.ext =		cmdext,
+	.help =		cmdhelp,
+	.okname =	cmdokname,
+	.sum =		cmdsum,
+	.write =	cmdwrite,
+	.printctl =	cmdprintctl,
+	.unit =		"sector",
+};
+
+void
+usage(void)
+{
+	fprint(2, "usage: disk/gdisk [-abfprw] [-s sectorsize] /dev/sdC0/data\n");
+	exits("usage");
+}
+
+void
+main(int argc, char **argv)
+{
+	vlong secsize;
+
+	fmtinstall('U', uufmt);
+	fmtinstall('A', attrfmt);
+
+	initcrc32();
+
+	type9 = gettype(nil, "plan9");
+
+	secsize = 0;
+	ARGBEGIN{
+	case 'a':
+		doauto++;
+		break;
+	case 'b':
+		blank++;
+		break;
+	case 'f':
+		file++;
+		break;
+	case 'p':
+		printflag++;
+		break;
+	case 'r':
+		rdonly++;
+		break;
+	case 's':
+		secsize = atoi(ARGF());
+		break;
+	case 'v':
+		break;
+	case 'w':
+		dowrite++;
+		break;
+	}ARGEND;
+
+	if(argc != 1)
+		usage();
+
+	edit.disk = opendisk(argv[0], rdonly, file);
+	if(edit.disk == nil) {
+		fprint(2, "cannot open disk: %r\n");
+		exits("opendisk");
+	}
+
+	if(secsize != 0) {
+		edit.disk->secsize = secsize;
+		edit.disk->secs = edit.disk->size / secsize;
+	}
+	edit.end = edit.disk->secs;
+
+	if(blank)
+		blankpart(&edit);
+	else
+		rdpart(&edit);
+
+	if(doauto)
+		autopart(&edit);
+
+	if(dowrite)
+		runcmd(&edit, "w");
+
+	if(printflag)
+		runcmd(&edit, "P");
+
+	if(dowrite || printflag)
+		exits(0);
+
+	runcmd(&edit, "p");
+	for(;;) {
+		fprint(2, ">>> ");
+		runcmd(&edit, getline(&edit));
+	}
+}
+
+
+typedef struct Block Block;
+struct Block
+{
+	Block	*link;
+	Disk	*disk;
+	uchar	*save;	/* saved backup data */
+	vlong	addr;
+	uchar	data[];
+};
+
+static Block *blocks;
+
+static void*
+getblock(Disk *disk, vlong addr)
+{
+	Block *b;
+
+	if(addr < 0 || addr >= disk->secs)
+		abort();
+
+	for(b = blocks; b != nil; b = b->link){
+		if(b->addr == addr && b->disk == disk)
+			return b->data;
+	}
+	b = malloc(sizeof(Block) + 2*disk->secsize);
+	if(pread(disk->fd, b->data, disk->secsize, disk->secsize*addr) != disk->secsize){
+		sysfatal("getblock %llud: %r", addr);
+		return nil;
+	}
+	b->save = &b->data[disk->secsize];
+	memmove(b->save, b->data, disk->secsize);
+
+	b->addr = addr;
+	b->link = blocks;
+	b->disk = disk;
+	blocks = b;
+	return b->data;
+}
+
+static void
+flushdisk(Disk *disk)
+{
+	Block *b, *r;
+
+	if(disk->wfd < 0)
+		return;
+
+	for(b = blocks; b != nil; b = b->link){
+		if(b->disk != disk || memcmp(b->data, b->save, disk->secsize) == 0)
+			continue;
+		if(pwrite(disk->wfd, b->data, disk->secsize, b->addr*disk->secsize) != disk->secsize){
+			fprint(2, "error writing lba %llud: %r\n", b->addr);
+			goto Recover;
+		}
+	}
+	return;
+
+Recover:
+	for(r = blocks; r != b; r = r->link){
+		if(r->disk != disk || memcmp(r->data, r->save, disk->secsize) == 0)
+			continue;
+		pwrite(disk->wfd, r->save, disk->secsize, r->addr*disk->secsize);
+	}
+	exits("recovered");
+}
+
+
+static u32int crc32tab[256];
+
+static void
+initcrc32(void)
+{
+	u32int c;
+	int n, k;
+
+	for(n = 0; n < 256; n++){
+		c = n;
+		for(k = 0; k < 8; k++)
+			if((c & 1) != 0)
+				c = 0xedb88320 ^ c >> 1;
+			else
+				c >>= 1;
+		crc32tab[n] = c;
+	}
+}
+static u32int
+sumcrc32(u32int c, uchar *buf, ulong len)
+{
+	c = ~c;
+	while(len-- != 0)
+		c = crc32tab[(*buf++ ^ c) & 0xff] ^ c >> 8;
+	return ~c;
+}
+
+
+static u32int
+getle32(void* v)
+{
+	uchar *p;
+
+	p = v;
+	return (p[3]<<24)|(p[2]<<16)|(p[1]<<8)|p[0];
+}
+
+static void
+putle32(void* v, u32int i)
+{
+	uchar *p;
+
+	p = v;
+	p[0] = i;
+	p[1] = i>>8;
+	p[2] = i>>16;
+	p[3] = i>>24;
+}
+
+static u64int
+getle64(void *v)
+{
+	return ((u64int)getle32((uchar*)v + 4) << 32) | getle32(v);
+}
+
+static void
+putle64(void *v, u64int i)
+{
+	putle32(v, i);
+	putle32((uchar*)v + 4, i >> 32);
+}
+
+
+static void
+uugen(uchar uu[16])
+{
+	genrandom(uu, 16);
+	uu[7] = (uu[7] & ~0xF0) | 0x40;
+	uu[8] = (uu[8] & ~0xC0) | 0x80;
+}
+
+static int
+uufmt(Fmt *fmt)
+{
+	uchar *uu = va_arg(fmt->args, uchar*);
+	return fmtprint(fmt,
+		"%.2uX%.2uX%.2uX%.2uX-"
+		"%.2uX%.2uX-"
+		"%.2uX%.2uX-"
+		"%.2uX%.2uX-%.2uX%.2uX%.2uX%.2uX%.2uX%.2uX",
+/* Data1 */	uu[3], uu[2], uu[1], uu[0], 
+/* Data2 */	uu[5], uu[4],
+/* Data3 */	uu[7], uu[6],
+/* Data4 */	uu[8], uu[9], uu[10], uu[11], uu[12], uu[13], uu[14], uu[15]);
+}
+
+
+static int
+attrfmt(Fmt *fmt)
+{
+	uvlong a = va_arg(fmt->args, uvlong);
+	char s[64+1], *p;
+	Flag *f;
+
+	p = s;
+	for(f=flags; f->c != '\0'; f++){
+		if(a & (1ULL<<f->s))
+			*p = f->c;
+		else
+			*p = '-';
+		p++;
+	}
+	*p = '\0';
+	return fmtprint(fmt, "%s", s);
+}
+
+
+static Header*
+readhdr(Disk *disk, vlong lba)
+{
+	Header *hdr;
+	u32int crc;
+	int siz;
+
+	if(lba < 0)
+		lba += disk->secs;
+
+	hdr = getblock(disk, lba);
+	if(memcmp(hdr->sig, "EFI PART", 8) != 0)
+		return nil;
+	if(getle64(hdr->selflba) != lba)
+		return nil;
+	siz = getle32(hdr->hdrsiz);
+	if(siz < Headersiz || siz > disk->secsize)
+		return nil;
+	crc = getle32(hdr->hdrcrc);
+	putle32(hdr->hdrcrc, 0);
+	putle32(hdr->hdrcrc, sumcrc32(0, (uchar*)hdr, siz));
+	if(getle32(hdr->hdrcrc) != crc){
+		putle32(hdr->hdrcrc, crc);
+		return nil;
+	}
+
+	return hdr;
+}
+
+static void
+partname(Edit *, Gptpart *p)
+{
+	snprint(p->namebuf, sizeof(p->namebuf), "p%d", (int)(p - parts)+1);
+	p->name = p->namebuf;
+}
+
+static char*
+readent(Edit *edit, Entry *ent, Gptpart *p)
+{
+	int i;
+
+	memset(p, 0, sizeof(*p));
+	if(memcmp(ent->typeid, zeros, 16) == 0)
+		return nil;
+
+	p->type = gettype(ent->typeid, nil);
+	memmove(p->uuid, ent->partid, 16);
+	p->start = getle64(ent->firstlba);
+	p->end = getle64(ent->lastlba)+1;
+	p->attr = getle64(ent->attr);
+	for(i=0; i<nelem(p->label)-1; i++)
+		p->label[i] = ent->name[i*2] | (Rune)ent->name[i*2+1]<<8;
+	p->label[i] = 0;
+	partname(edit, p);
+
+	return addpart(edit, p);
+}
+
+static Entry*
+getent(Disk *disk, vlong tablba, int entsize, int i)
+{
+	int ent2blk;
+	uchar *blkp;
+
+	ent2blk = disk->secsize / entsize;
+	blkp = getblock(disk, tablba + (i/ent2blk));
+	blkp += entsize * (i%ent2blk);
+	return (Entry*)blkp;
+}
+
+static int
+readtab(Edit *edit, Header *hdr)
+{
+	int entries, entsize, i;
+	vlong tablba;
+	u32int crc;
+	Entry *ent;
+	char *err;
+
+	entries = getle32(hdr->entrycount);
+	entsize = getle32(hdr->entrysize);
+	if(entsize < Entrysiz || entsize > edit->disk->secsize)
+		return -1;
+
+	crc = 0;
+	tablba = getle64(hdr->tablba);
+	for(i=0; i<entries; i++){
+		ent = getent(edit->disk, tablba, entsize, i);
+		crc = sumcrc32(crc, (uchar*)ent, entsize);
+	}
+	if(getle32(hdr->tabcrc) != crc)
+		return -1;
+
+	nparts = entries;
+	parts = emalloc(nparts*sizeof(parts[0]));
+
+	partoff = getle64(hdr->firstlba);
+	partend = getle64(hdr->lastlba)+1;
+
+	edit->dot = partoff;
+	edit->end = partend;
+
+	for(i=0; i<nparts; i++){
+		ent = getent(edit->disk, tablba, entsize, i);
+		if((err = readent(edit, ent, &parts[i])) != nil)
+			fprint(2, "readtab: %s\n", err);
+	}
+
+	return 0;
+}
+
+static Header*
+getbakhdr(Edit *edit, Header *bhdr)
+{
+	vlong lba, blba, tlba;
+	Header *hdr;
+	int siz;
+
+	siz = getle32(bhdr->hdrsiz);
+	lba = getle64(bhdr->backlba);
+	hdr = readhdr(edit->disk, lba);
+	if(hdr != nil)
+		return hdr;
+
+	hdr = getblock(edit->disk, lba);
+	memmove(hdr, bhdr, siz);
+	putle64(hdr->selflba, lba);
+	blba = getle64(bhdr->selflba);
+	putle64(hdr->backlba, blba);
+	if(lba <= blba)
+		tlba = lba+1;
+	else
+		tlba = partend;
+	putle64(hdr->tablba, tlba);
+	edit->changed = 1;
+
+	return hdr;
+}
+
+typedef struct Tentry Tentry;
+struct Tentry {
+	uchar	active;			/* active flag */
+	uchar	starth;			/* starting head */
+	uchar	starts;			/* starting sector */
+	uchar	startc;			/* starting cylinder */
+	uchar	type;			/* partition type */
+	uchar	endh;			/* ending head */
+	uchar	ends;			/* ending sector */
+	uchar	endc;			/* ending cylinder */
+	uchar	lba[4];			/* starting LBA */
+	uchar	size[4];		/* size in sectors */
+};
+
+enum {
+	NTentry = 4,
+	Tentrysiz = 16,
+};
+
+static uchar*
+readmbr(Disk *disk)
+{
+	uchar *mbr, *magic;
+	Tentry *t;
+	int i;
+
+	mbr = getblock(disk, 0);
+	magic = &mbr[disk->secsize - 2];
+	if(magic[0] != 0x55 || magic[1] != 0xAA)
+		sysfatal("did not find master boot record");
+
+	for(i=0; i<NTentry; i++){
+		t = (Tentry*)&mbr[disk->secsize - 2 - (i+1)*Tentrysiz];
+		switch(t->type){
+		case 0xEE:
+		case 0xEF:
+		case 0x00:
+			continue;
+		}
+		sysfatal("dos partition table in use");
+	}
+
+	return mbr;
+}
+
+static void
+rdpart(Edit *edit)
+{
+	pmbr = readmbr(edit->disk);
+	if((phdr = readhdr(edit->disk, 1)) != nil && readtab(edit, phdr) == 0){
+		memmove(devid, phdr->devid, 16);
+		bhdr = getbakhdr(edit, phdr);
+		return;
+	}
+	if((bhdr = readhdr(edit->disk, -1)) != nil && readtab(edit, bhdr) == 0){
+		memmove(devid, bhdr->devid, 16);
+		phdr = getbakhdr(edit, bhdr);
+		return;
+	}
+	sysfatal("did not find partition table");
+}
+
+static Header*
+inithdr(Disk *disk)
+{
+	vlong tabsize, baklba;
+	Header *hdr;
+
+	tabsize = (Entrysiz*nparts + disk->secsize-1) / disk->secsize;
+	if(tabsize < 1)
+		tabsize = 1;
+
+	baklba = disk->secs-1;
+	partend = baklba - tabsize;
+	partoff = 2 + tabsize;
+
+	if(partoff >= partend)
+		sysfatal("disk too small for partition table");
+
+	hdr = getblock(disk, 1);
+	memset(hdr, 0, Headersiz);
+
+	memmove(hdr->sig, "EFI PART", 8);
+	putle32(hdr->rev, 0x10000);
+	putle32(hdr->hdrsiz, Headersiz);
+	putle32(hdr->hdrcrc, 0);
+	putle64(hdr->selflba, 1);
+	putle64(hdr->backlba, baklba);
+	putle64(hdr->firstlba, partoff);
+	putle64(hdr->lastlba, partend-1);
+	memmove(hdr->devid, devid, 16);
+	putle64(hdr->tablba, 2);
+	putle32(hdr->entrycount, nparts);
+	putle32(hdr->entrysize, Entrysiz);
+	putle32(hdr->tabcrc, 0);
+
+	return hdr;
+}
+
+static uchar*
+initmbr(Disk *disk)
+{
+	uchar *mbr, *magic;
+	u32int size;
+	Tentry *t;
+
+	mbr = getblock(disk, 0);
+
+	magic = &mbr[disk->secsize - 2];
+	magic[0] = 0x55;
+	magic[1] = 0xAA;
+
+	t = (Tentry*)&mbr[disk->secsize - 2 - NTentry*Tentrysiz];
+	memset(t, 0, NTentry * Tentrysiz);
+
+	t->type = 0xEE;
+	t->active = 0;
+
+	size = disk->secs > 0xFFFFFFFF ? 0xFFFFFFFF : disk->secs;
+	putle32(t->lba, 0);
+	putle32(t->size, size);
+
+	t->starth = 0;
+	t->startc = 0;
+	t->starts = 0;
+	t->endh = disk->h-1;
+	t->ends = (disk->s & 0x3F) | (((disk->c-1)>>2) & 0xC0);
+	t->endc = disk->c-1;
+
+	return mbr;
+}
+
+static void
+blankpart(Edit *edit)
+{
+	nparts = 128;
+	parts = emalloc(nparts*sizeof(parts[0]));
+
+	uugen(devid);
+	pmbr = initmbr(edit->disk);
+	phdr = inithdr(edit->disk);
+	bhdr = getbakhdr(edit, phdr);
+
+	edit->dot = partoff;
+	edit->end = partend;
+
+	edit->changed = 1;
+}
+
+static void
+writeent(Entry *ent, Gptpart *p)
+{
+	int i;
+
+	if(p->type == nil)
+		return;
+	memmove(ent->typeid, p->type->uuid, 16);
+	memmove(ent->partid, p->uuid, 16);
+	putle64(ent->firstlba, p->start);
+	putle64(ent->lastlba, p->end-1);
+	putle64(ent->attr, p->attr);
+	for(i=0; i<nelem(ent->name)/2; i++){
+		ent->name[i*2] = p->label[i] & 0xFF;
+		ent->name[i*2+1] = p->label[i] >> 8;
+	}
+}
+
+static void
+writetab(Edit *edit, Header *hdr)
+{
+	int hdrsize, entsize, i;
+	vlong tablba;
+	u32int crc;
+	Entry *ent;
+
+	crc = 0;
+	entsize = getle32(hdr->entrysize);
+	tablba = getle64(hdr->tablba);
+	for(i=0; i<nparts; i++){
+		ent = getent(edit->disk, tablba, entsize, i);
+		memset(ent, 0, entsize);
+		writeent(ent, &parts[i]);
+		crc = sumcrc32(crc, (uchar*)ent, entsize);
+	}
+
+	hdrsize = getle32(hdr->hdrsiz);
+	putle32(hdr->tabcrc, crc);
+	putle32(hdr->hdrcrc, 0);
+	putle32(hdr->hdrcrc, sumcrc32(0, (uchar*)hdr, hdrsize));
+}
+
+static char*
+cmdwrite(Edit *edit)
+{
+	writetab(edit, phdr);
+	writetab(edit, bhdr);
+	flushdisk(edit->disk);
+	cmdprintctl(edit, edit->disk->ctlfd);
+	return nil;
+}
+
+static char*
+newpart(Edit *edit, Gptpart *p, vlong start, vlong end, Type *type, uvlong attr)
+{
+	if(end <= partoff || start >= partend)
+		return "partition overlaps partition table";
+
+	if(start < partoff)
+		start = partoff;
+
+	memset(p, 0, sizeof(*p));
+	p->type = type;
+	p->attr = attr;
+	p->start = start;
+	p->end = end;
+	uugen(p->uuid);
+	runesnprint(p->label, nelem(p->label), "%s", p->type->desc);
+	partname(edit, p);
+	return addpart(edit, p);
+}
+
+static void
+autopart(Edit *edit)
+{
+	vlong start, bigstart, bigsize;
+	Gptpart *p;
+	int i;
+
+	bigsize = 0;
+	bigstart = 0;
+	start = partoff;
+	for(i=0; i<edit->npart; i++){
+		p = (Gptpart*)edit->part[i];
+		if(p->type == type9)
+			return;
+		if(p->start > start && (p->start - start) > bigsize){
+			bigsize = p->start - start;
+			bigstart = start;
+		}
+		start = p->end;
+	}
+	if(partend > start && (partend - start) > bigsize){
+		bigsize = partend - start;
+		bigstart = start;
+	}
+	if(bigsize < 1) {
+		fprint(2, "couldn't find space for plan 9 partition\n");
+		return;
+	}
+	for(i=0; i<nparts; i++){
+		p = &parts[i];
+		if(p->type == nil){
+			newpart(edit, p, bigstart, bigstart+bigsize, type9, 0);
+			return;
+		}
+	}
+	fprint(2, "couldn't find free slot for plan 9 partition\n");
+}
+
+typedef struct Name Name;
+struct Name {
+	char *name;
+	Name *link;
+};
+
+static Name *namelist;
+
+static void
+plan9print(Gptpart *p)
+{
+	int i, ok;
+	char *name, *vname;
+	Name *n;
+	char *sep;
+
+	vname = p->type->name;
+	if(vname==nil || strcmp(vname, "")==0) {
+		p->ctlname = "";
+		return;
+	}
+
+	/* avoid names like plan90 */
+	i = strlen(vname) - 1;
+	if(vname[i] >= '0' && vname[i] <= '9')
+		sep = ".";
+	else
+		sep = "";
+
+	i = 0;
+
+	name = emalloc(strlen(vname)+10);
+	sprint(name, "%s", vname);
+	do {
+		ok = 1;
+		for(n=namelist; n; n=n->link) {
+			if(strcmp(name, n->name) == 0) {
+				i++;
+				sprint(name, "%s%s%d", vname, sep, i);
+				ok = 0;
+			}
+		}
+	} while(ok == 0);
+
+	p->ctlname = name;
+
+	n = emalloc(sizeof(*n));
+	n->name = name;
+	n->link = namelist;
+	namelist = n;
+}
+
+static void
+freenamelist(void)
+{
+	Name *n, *next;
+
+	for(n=namelist; n; n=next) {
+		next = n->link;
+		free(n->name);
+		free(n);
+	}
+	namelist = nil;
+}
+
+static void
+cmdprintctl(Edit *edit, int ctlfd)
+{
+	int i;
+
+	freenamelist();
+	for(i=0; i<edit->npart; i++)
+		plan9print((Gptpart*)edit->part[i]);
+	ctldiff(edit, ctlfd);
+}
+
+static char*
+cmdokname(Edit*, char *name)
+{
+	if(name[0] != 'p' || atoi(name+1) <= 0)
+		return "name must be pN";
+	return nil;
+}
+
+static void
+cmdsum(Edit *edit, Part *vp, vlong a, vlong b)
+{
+	char *name, *type, *unit;
+	Rune *label;
+	Gptpart *p;
+	uvlong attr;
+	vlong s, d;
+
+	if((p = (Gptpart*)vp) == nil){
+		if(a < partoff)
+			a = partoff;
+		if(a >= b)
+			return;
+		name = "empty";
+		type = "";
+		attr = 0;
+		label = L"";
+	} else {
+		name = p->name;
+		type = p->type->name;
+		attr = p->attr;
+		label = p->label;
+	}
+
+	s = (b - a)*edit->disk->secsize;
+	if(s >= 1*TB){
+		unit = "TB";
+		d = TB;
+	}else if(s >= 1*GB){
+		unit = "GB";
+		d = GB;
+	}else if(s >= 1*MB){
+		unit = "MB";
+		d = MB;
+	}else if(s >= 1*KB){
+		unit = "KB";
+		d = KB;
+	}else{
+		unit = "B ";
+		d = 1;
+	}
+
+	print("%-6s %*llud %*llud (%lld.%.2d %s) %A %8s \"%S\"\n",
+		name, edit->disk->width, a, edit->disk->width, b,
+		s/d, (int)(((s%d)*100)/d), unit, attr, type, label);
+}
+
+static char*
+cmdadd(Edit *edit, char *name, vlong start, vlong end)
+{
+	int slot;
+
+	slot = atoi(name+1)-1;
+	if(slot < 0 || slot >= nparts)
+		return "partition number out of range";
+	return newpart(edit, &parts[slot], start, end, type9, 0);
+}
+
+static char*
+cmddel(Edit *edit, Part *p)
+{
+	memset((Gptpart*)p, 0, sizeof(Gptpart));
+	return delpart(edit, p);
+}
+
+static char *help = 
+	"t name [type] - set partition type\n"
+	"f name [+-flags] - set partition attributes\n"
+	"l name [label] - set partition label\n";
+
+static char*
+cmdhelp(Edit*)
+{
+	print("%s\n", help);
+	return nil;
+}
+
+static char*
+cmdflag(Edit *edit, int na, char **a)
+{
+	Gptpart *p;
+	char *s, op;
+	Flag *f;
+
+	if(na < 2)
+		return "args";
+
+	if((p = (Gptpart*)findpart(edit, a[1])) == nil)
+		return "unknown partition";
+
+	if(na == 2){
+		for(;;){
+			fprint(2, "set attibutes [? for list]: ");
+			s = getline(edit);
+			if(s[0] != '?')
+				break;
+			for(f = flags; f->c != '\0'; f++)
+				fprint(2, "%.16llux %c - %s\n", 1ULL<<f->s, f->c, f->desc);
+		}
+	} else {
+		s = a[2];
+	}
+
+	op = '+';
+	for(; *s != '\0'; s++){
+		switch(*s){
+		case '+':
+		case '-':
+			op = *s;
+		case ' ':
+			continue;
+		}
+		for(f = flags; f->c != '\0'; f++)
+			if(f->c == *s)
+				break;
+		if(f->c == '\0')
+			return "unknown flag";
+		switch(op){
+		case '+':
+			p->attr |= 1ULL<<f->s;
+			break;
+		case '-':
+			p->attr &= ~(1ULL<<f->s);
+			break;
+		}
+		p->changed = 1;
+		edit->changed = 1;
+	}
+	return nil;
+}
+
+static Type*
+gettype(uchar uuid[16], char *name)
+{
+	Type *t;
+
+	if(name != nil){
+		for(t = types; t->name != nil; t++)
+			if(strcmp(name, t->name) == 0)
+				return t;
+		uugen(uuid);
+	} else {
+		for(t = types; t->name != nil; t++)
+			if(memcmp(t->uuid, uuid, 16) == 0)
+				return t;
+	}
+	if(t >= &types[nelem(types)-1])
+		sysfatal("too many partition types");
+	memmove(t->uuid, uuid, 16);
+	t->name = smprint("type%.2uX%.2uX%.2uX%.2uX", uuid[3], uuid[2], uuid[1], uuid[0]);
+	t->desc = name != nil ? estrdup(name) : "";
+	return t;
+}
+
+static char*
+cmdtype(Edit *edit, int nf, char **f)
+{
+	uchar uuid[16];
+	Gptpart *p;
+	char *q;
+	Type *t;
+
+	if(nf < 2)
+		return "args";
+
+	if((p = (Gptpart*)findpart(edit, f[1])) == nil)
+		return "unknown partition";
+
+	if(nf == 2) {
+		for(;;) {
+			fprint(2, "new partition type [? for list]: ");
+			q = getline(edit);
+			if(q[0] != '?')
+				break;
+			for(t = types+1; t->name != nil; t++)
+				fprint(2, "%U %-15s %s\n", t->uuid, t->name, t->desc);
+		}
+	} else
+		q = f[2];
+
+	if(q[0] == '\0' || (t = gettype(uuid, q)) == p->type)
+		return nil;
+
+	p->type = t;
+	memset(p->label, 0, sizeof(p->label));
+	runesnprint(p->label, nelem(p->label), "%s", t->desc);
+	p->changed = 1;
+	edit->changed = 1;
+	return nil;
+}
+
+static char*
+cmdlabel(Edit *edit, int nf, char **f)
+{
+	Gptpart *p;
+	char *q;
+
+	if(nf < 2)
+		return "args";
+
+	if((p = (Gptpart*)findpart(edit, f[1])) == nil)
+		return "unknown partition";
+
+	if(nf == 2) {
+		fprint(2, "new label: ");
+		q = getline(edit);
+	} else
+		q = f[2];
+
+	memset(p->label, 0, sizeof(p->label));
+	runesnprint(p->label, nelem(p->label), "%s", q);
+	p->changed = 1;
+	edit->changed = 1;
+	return nil;
+}
+
+static char*
+cmdext(Edit *edit, int nf, char **f)
+{
+	switch(f[0][0]) {
+	case 't':
+		return cmdtype(edit, nf, f);
+	case 'f':
+		return cmdflag(edit, nf, f);
+	case 'l':
+		return cmdlabel(edit, nf, f);
+	default:
+		return "unknown command";
+	}
+}
--- a/sys/src/cmd/disk/prep/mkfile
+++ b/sys/src/cmd/disk/prep/mkfile
@@ -1,6 +1,6 @@
 </$objtype/mkfile
 
-TARG=fdisk prep
+TARG=fdisk edisk prep
 
 YFILES=calc.y
 HFILES=edit.h