diff options
author | cinap_lenrek <cinap_lenrek@felloff.net> | 2015-05-30 03:22:08 +0200 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@felloff.net> | 2015-05-30 03:22:08 +0200 |
commit | 4a4575bd4e0d92a0c699108c439d3cb9a546878b (patch) | |
tree | 2ee4c977dd81622f668775f2c9fc7a0c2a5b4b3d | |
parent | 09b6a92145540ca0f8b50454600e95c3dc17100f (diff) |
disk/edisk: gpt partition table editor (no manpage, work in progress)
-rw-r--r-- | sys/src/cmd/disk/prep/edisk.c | 1214 | ||||
-rw-r--r-- | sys/src/cmd/disk/prep/mkfile | 2 |
2 files changed, 1215 insertions, 1 deletions
diff --git a/sys/src/cmd/disk/prep/edisk.c b/sys/src/cmd/disk/prep/edisk.c new file mode 100644 index 000000000..bffb8b0a5 --- /dev/null +++ b/sys/src/cmd/disk/prep/edisk.c @@ -0,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"; + } +} diff --git a/sys/src/cmd/disk/prep/mkfile b/sys/src/cmd/disk/prep/mkfile index 5557c9b59..b9389aee8 100644 --- 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 |