/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ /* * fdisk - edit dos disk partition table */ #include #include #include #include #include #include "edit.h" typedef struct Dospart Dospart; enum { NTentry = 4, Mpart = 64, }; static void rdpart(Edit*, uint64_t, uint64_t); static void findmbr(Edit*); static void autopart(Edit*); static void wrpart(Edit*); static void blankpart(Edit*); static void recover(Edit*); static int Dfmt(Fmt*); static int blank; static int dowrite; static int file; static int rdonly; static int doauto; static int64_t mbroffset; static int printflag; static int printchs; static int sec2cyl; static int written; static void cmdsum(Edit*, Part*, int64_t, int64_t); static char *cmdadd(Edit*, char*, int64_t, int64_t); 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); #pragma varargck type "D" uchar* Edit edit = { .add= cmdadd, .del= cmddel, .ext= cmdext, .help= cmdhelp, .okname= cmdokname, .sum= cmdsum, .write= cmdwrite, .printctl= cmdprintctl, .unit= "cylinder", }; /* * Catch the obvious error routines to fix up the disk. */ void sysfatal(char *fmt, ...) { char buf[1024]; va_list arg; va_start(arg, fmt); vseprint(buf, buf+sizeof(buf), fmt, arg); va_end(arg); if(argv0) fprint(2, "%s: %s\n", argv0, buf); else fprint(2, "%s\n", buf); if(written) recover(&edit); exits(buf); } void abort(void) { fprint(2, "abort\n"); recover(&edit); } void usage(void) { fprint(2, "usage: disk/fdisk [-abfprvw] [-s sectorsize] /dev/sdC0/data\n"); exits("usage"); } void main(int argc, char **argv) { int64_t secsize; 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': printchs++; break; case 'w': dowrite++; break; }ARGEND; fmtinstall('D', Dfmt); 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; } sec2cyl = edit.disk->h * edit.disk->s; edit.end = edit.disk->secs / sec2cyl; findmbr(&edit); if(blank) blankpart(&edit); else rdpart(&edit, 0, 0); if(doauto) autopart(&edit); if(dowrite) runcmd(&edit, (char[]){"w"}); if(printflag) runcmd(&edit, (char[]){"P"}); if(dowrite || printflag) exits(0); fprint(2, "cylinder = %lld bytes\n", sec2cyl*edit.disk->secsize); runcmd(&edit, (char[]){"p"}); for(;;) { fprint(2, ">>> "); runcmd(&edit, getline(&edit)); } } typedef struct Tentry Tentry; typedef struct Table Table; typedef struct Type Type; typedef struct Tab Tab; typedef struct Recover Recover; struct Tentry { uint8_t active; /* active flag */ uint8_t starth; /* starting head */ uint8_t starts; /* starting sector */ uint8_t startc; /* starting cylinder */ uint8_t type; /* partition type */ uint8_t endh; /* ending head */ uint8_t ends; /* ending sector */ uint8_t endc; /* ending cylinder */ uint8_t xlba[4]; /* starting LBA from beginning of disc or ext. partition */ uint8_t xsize[4]; /* size in sectors */ }; struct Table { Tentry entry[NTentry]; uint8_t magic[2]; uint8_t size[]; }; enum { Active = 0x80, /* partition is active */ Primary = 0x01, /* internal flag */ TypeBB = 0xFF, TypeEMPTY = 0x00, TypeFAT12 = 0x01, TypeXENIX = 0x02, /* root */ TypeXENIXUSR = 0x03, /* usr */ TypeFAT16 = 0x04, TypeEXTENDED = 0x05, TypeFATHUGE = 0x06, TypeHPFS = 0x07, TypeAIXBOOT = 0x08, TypeAIXDATA = 0x09, TypeOS2BOOT = 0x0A, /* OS/2 Boot Manager */ TypeFAT32 = 0x0B, /* FAT 32 */ TypeFAT32LBA = 0x0C, /* FAT 32 needing LBA support */ TypeFAT16X = 0x0E, /* FAT 16 needing LBA support */ TypeEXTHUGE = 0x0F, /* FAT 32 extended partition */ TypeUNFORMATTED = 0x16, /* unformatted primary partition (OS/2 FDISK)? */ TypeHPFS2 = 0x17, TypeIBMRecovery = 0x1C, /* really hidden fat */ TypeCPM0 = 0x52, TypeDMDDO = 0x54, /* Disk Manager Dynamic Disk Overlay */ TypeGB = 0x56, /* ???? */ TypeSPEEDSTOR = 0x61, TypeSYSV386 = 0x63, /* also HURD? */ TypeNETWARE = 0x64, TypePCIX = 0x75, TypeMINIX13 = 0x80, /* Minix v1.3 and below */ TypeMINIX = 0x81, /* Minix v1.5+ */ TypeLINUXSWAP = 0x82, TypeLINUX = 0x83, TypeLINUXEXT = 0x85, TypeLINUXLVM = 0x8E, /* logical volume manager */ TypeAMOEBA = 0x93, TypeAMOEBABB = 0x94, TypeBSD386 = 0xA5, TypeNETBSD = 0xA9, TypeBSDI = 0xB7, TypeBSDISWAP = 0xB8, TypeOTHER = 0xDA, TypeCPM = 0xDB, TypeDellRecovery= 0xDE, TypeSPEEDSTOR12 = 0xE1, TypeSPEEDSTOR16 = 0xE4, TypeEFIProtect = 0xEE, TypeEFI = 0xEF, TypeLANSTEP = 0xFE, Type9 = 0x39, Toffset = 446, /* offset of partition table in sector */ Magic0 = 0x55, Magic1 = 0xAA, Tablesz = offsetof(Table, size[0]), }; struct Type { char *desc; char *name; }; struct Dospart { Part; Tentry; uint32_t lba; uint32_t size; int primary; }; struct Recover { Table table; uint32_t lba; }; static Type types[256] = { [TypeEMPTY] { "EMPTY", "" }, [TypeFAT12] { "FAT12", "dos" }, [TypeFAT16] { "FAT16", "dos" }, [TypeFAT32] { "FAT32", "dos" }, [TypeFAT32LBA] { "FAT32LBA", "dos" }, [TypeFAT16X] { "FAT16X", "dos" }, [TypeEXTHUGE] { "EXTHUGE", "" }, [TypeIBMRecovery] { "IBMRECOVERY", "ibm" }, [TypeEXTENDED] { "EXTENDED", "" }, [TypeFATHUGE] { "FATHUGE", "dos" }, [TypeBB] { "BB", "bb" }, [TypeXENIX] { "XENIX", "xenix" }, [TypeXENIXUSR] { "XENIX USR", "xenixusr" }, [TypeHPFS] { "HPFS", "ntfs" }, [TypeAIXBOOT] { "AIXBOOT", "aixboot" }, [TypeAIXDATA] { "AIXDATA", "aixdata" }, [TypeOS2BOOT] { "OS/2BOOT", "os2boot" }, [TypeUNFORMATTED] { "UNFORMATTED", "" }, [TypeHPFS2] { "HPFS2", "hpfs2" }, [TypeCPM0] { "CPM0", "cpm0" }, [TypeDMDDO] { "DMDDO", "dmdd0" }, [TypeGB] { "GB", "gb" }, [TypeSPEEDSTOR] { "SPEEDSTOR", "speedstor" }, [TypeSYSV386] { "SYSV386", "sysv386" }, [TypeNETWARE] { "NETWARE", "netware" }, [TypePCIX] { "PCIX", "pcix" }, [TypeMINIX13] { "MINIXV1.3", "minix13" }, [TypeMINIX] { "MINIXV1.5", "minix15" }, [TypeLINUXSWAP] { "LINUXSWAP", "linuxswap" }, [TypeLINUX] { "LINUX", "linux" }, [TypeLINUXEXT] { "LINUXEXTENDED", "" }, [TypeLINUXLVM] { "LINUXLVM", "linuxlvm" }, [TypeAMOEBA] { "AMOEBA", "amoeba" }, [TypeAMOEBABB] { "AMOEBABB", "amoebaboot" }, [TypeBSD386] { "BSD386", "bsd386" }, [TypeNETBSD] { "NETBSD", "netbsd" }, [TypeBSDI] { "BSDI", "bsdi" }, [TypeBSDISWAP] { "BSDISWAP", "bsdiswap" }, [TypeOTHER] { "OTHER", "other" }, [TypeCPM] { "CPM", "cpm" }, [TypeDellRecovery] { "DELLRECOVERY", "dell" }, [TypeSPEEDSTOR12] { "SPEEDSTOR12", "speedstor" }, [TypeSPEEDSTOR16] { "SPEEDSTOR16", "speedstor" }, [TypeEFIProtect] { "EFIPROTECT", "efiprotect" }, [TypeEFI] { "EFI", "efi" }, [TypeLANSTEP] { "LANSTEP", "lanstep" }, [Type9] { "PLAN9", "plan9" }, }; static Dospart part[Mpart]; static int npart; static char* typestr0(int type) { static char buf[100]; sprint(buf, "type %d", type); if(type < 0 || type >= 256) return buf; if(types[type].desc == nil) return buf; return types[type].desc; } static uint32_t getle32(void* v) { uint8_t *p; p = v; return (p[3]<<24)|(p[2]<<16)|(p[1]<<8)|p[0]; } static void putle32(void* v, uint32_t i) { uint8_t *p; p = v; p[0] = i; p[1] = i>>8; p[2] = i>>16; p[3] = i>>24; } static void diskread(Disk *disk, void *data, int ndata, uint32_t sec, uint32_t off) { if(seek(disk->fd, (int64_t)sec*disk->secsize+off, 0) != (int64_t)sec*disk->secsize+off) sysfatal("diskread seek %lud.%lud: %r", (uint32_t)sec, (uint32_t)off); if(readn(disk->fd, data, ndata) != ndata) sysfatal("diskread %lud at %lud.%lud: %r", (uint32_t)ndata, (uint32_t)sec, (uint32_t)off); } static int diskwrite(Disk *disk, void *data, int ndata, uint32_t sec, uint32_t off) { written = 1; if(seek(disk->wfd, (int64_t)sec*disk->secsize+off, 0) != (int64_t)sec*disk->secsize+off) goto Error; if(write(disk->wfd, data, ndata) != ndata) goto Error; return 0; Error: fprint(2, "write %d bytes at %lud.%lud failed: %r\n", ndata, (uint32_t)sec, (uint32_t)off); return -1; } static Dospart* mkpart(char *name, int primary, int64_t lba, int64_t size, Tentry *t) { static int n; Dospart *p; p = emalloc(sizeof(*p)); if(name) p->name = estrdup(name); else{ p->name = emalloc(20); sprint(p->name, "%c%d", primary ? 'p' : 's', ++n); } if(t) p->Tentry = *t; else memset(&p->Tentry, 0, sizeof(Tentry)); p->changed = 0; p->start = lba/sec2cyl; p->end = (lba+size)/sec2cyl; p->ctlstart = lba; p->ctlend = lba+size; p->lba = lba; if (p->lba != lba) fprint(2, "%s: start of partition (%lld) won't fit in MBR table\n", argv0, lba); p->size = size; if (p->size != size) fprint(2, "%s: size of partition (%lld) won't fit in MBR table\n", argv0, size); p->primary = primary; return p; } /* * Recovery takes care of remembering what the various tables * looked like when we started, attempting to restore them when * we are finished. */ static Recover *rtab; static int nrtab; static void addrecover(Table t, uint32_t lba) { if((nrtab%8) == 0) { rtab = realloc(rtab, (nrtab+8)*sizeof(rtab[0])); if(rtab == nil) sysfatal("out of memory"); } rtab[nrtab] = (Recover){t, lba}; nrtab++; } static void recover(Edit *edit) { int err, i, ctlfd; int64_t offset; err = 0; for(i=0; idisk, &rtab[i].table, Tablesz, rtab[i].lba, Toffset) < 0) err = 1; if(err) { fprint(2, "warning: some writes failed during restoration of old partition tables\n"); exits("inconsistent"); } else { fprint(2, "restored old partition tables\n"); } ctlfd = edit->disk->ctlfd; offset = edit->disk->offset; if(ctlfd >= 0){ for(i=0; inpart; i++) if(edit->part[i]->ctlname && fprint(ctlfd, "delpart %s", edit->part[i]->ctlname)<0) fprint(2, "delpart failed: %s: %r", edit->part[i]->ctlname); for(i=0; inctlpart; i++) if(edit->part[i]->name && fprint(ctlfd, "delpart %s", edit->ctlpart[i]->name)<0) fprint(2, "delpart failed: %s: %r", edit->ctlpart[i]->name); for(i=0; inctlpart; i++){ if(fprint(ctlfd, "part %s %lld %lld", edit->ctlpart[i]->name, edit->ctlpart[i]->start+offset, edit->ctlpart[i]->end+offset) < 0){ fprint(2, "restored disk partition table but not kernel; reboot\n"); exits("inconsistent"); } } } exits("restored"); } /* * Read the partition table (including extended partition tables) * from the disk into the part array. */ static void rdpart(Edit *edit, uint64_t lba, uint64_t xbase) { char *err; Table table; Tentry *tp, *ep; Dospart *p; if(xbase == 0) xbase = lba; diskread(edit->disk, &table, Tablesz, mbroffset+lba, Toffset); addrecover(table, mbroffset+lba); if(table.magic[0] != Magic0 || table.magic[1] != Magic1) { assert(lba != 0); return; } for(tp=table.entry, ep=tp+NTentry; tptype) { case TypeEMPTY: break; case TypeEXTENDED: case TypeEXTHUGE: case TypeLINUXEXT: rdpart(edit, xbase+getle32(tp->xlba), xbase); break; default: p = mkpart(nil, lba==0, lba+getle32(tp->xlba), getle32(tp->xsize), tp); if(err = addpart(edit, p)) fprint(2, "adding partition: %s\n", err); break; } } } static void blankpart(Edit *edit) { edit->changed = 1; } static void findmbr(Edit *edit) { Table table; Tentry *tp; diskread(edit->disk, &table, Tablesz, 0, Toffset); if(table.magic[0] != Magic0 || table.magic[1] != Magic1) sysfatal("did not find master boot record"); for(tp = table.entry; tp < &table.entry[NTentry]; tp++) if(tp->type == TypeDMDDO) mbroffset = edit->disk->s; } static int haveroom(Edit *edit, int primary, int64_t start) { int i, lastsec, n; Dospart *p, *q; uint32_t pend, qstart; if(primary) { /* * must be open primary slot. * primary slots are taken by primary partitions * and runs of secondary partitions. */ n = 0; lastsec = 0; for(i=0; inpart; i++) { p = (Dospart*)edit->part[i]; if(p->primary) n++, lastsec=0; else if(!lastsec) n++, lastsec=1; } return n<4; } /* * secondary partitions can be inserted between two primary * partitions only if there is an empty primary slot. * otherwise, we can put a new secondary partition next * to a secondary partition no problem. */ n = 0; for(i=0; inpart; i++){ p = (Dospart*)edit->part[i]; if(p->primary) n++; pend = p->end; if(i+1npart){ q = (Dospart*)edit->part[i+1]; qstart = q->start; }else{ qstart = edit->end; q = nil; } if(start < pend || start >= qstart) continue; /* we go between these two */ if(p->primary==0 || (q && q->primary==0)) return 1; } /* not next to a secondary, need a new primary */ return n<4; } static void autopart(Edit *edit) { char *err; int active, i; int64_t bigstart, bigsize, start; Dospart *p; for(i=0; inpart; i++) if(((Dospart*)edit->part[i])->type == Type9) return; /* look for the biggest gap in which we can put a primary partition */ start = 0; bigsize = 0; SET(bigstart); for(i=0; inpart; i++) { p = (Dospart*)edit->part[i]; if(p->start > start && p->start - start > bigsize && haveroom(edit, 1, start)) { bigsize = p->start - start; bigstart = start; } start = p->end; } if(edit->end - start > bigsize && haveroom(edit, 1, start)) { bigsize = edit->end - start; bigstart = start; } if(bigsize < 1) { fprint(2, "couldn't find space or partition slot for plan 9 partition\n"); return; } /* set new partition active only if no others are */ active = Active; for(i=0; inpart; i++) if(((Dospart*)edit->part[i])->primary && (((Dospart*)edit->part[i])->active & Active)) active = 0; /* add new plan 9 partition */ bigsize *= sec2cyl; bigstart *= sec2cyl; if(bigstart == 0) { bigstart += edit->disk->s; bigsize -= edit->disk->s; } p = mkpart(nil, 1, bigstart, bigsize, nil); p->active = active; p->changed = 1; p->type = Type9; edit->changed = 1; if(err = addpart(edit, p)) { fprint(2, "error adding plan9 partition: %s\n", err); return; } } typedef struct Name Name; struct Name { char *name; Name *link; }; Name *namelist; static void plan9print(Dospart *part, int fd) { int i, ok; char *name, *vname; Name *n; int64_t start, end; char *sep; vname = types[part->type].name; if(vname==nil || strcmp(vname, "")==0) { part->ctlname = ""; return; } start = mbroffset+part->lba; end = start+part->size; /* 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); n = emalloc(sizeof(*n)); n->name = name; n->link = namelist; namelist = n; part->ctlname = name; if(fd >= 0) print("part %s %lld %lld\n", name, start, end); } static void freenamelist(void) { Name *n, *next; for(n=namelist; n; n=next) { next = n->link; free(n); } namelist = nil; } static void cmdprintctl(Edit *edit, int ctlfd) { int i; freenamelist(); for(i=0; inpart; i++) plan9print((Dospart*)edit->part[i], -1); ctldiff(edit, ctlfd); } static char* cmdokname(Edit *e, char *name) { char *q; if(name[0] != 'p' && name[0] != 's') return "name must be pN or sN"; strtol(name+1, &q, 10); if(*q != '\0') return "name must be pN or sN"; return nil; } #define TB (1024LL*GB) #define GB (1024*1024*1024) #define MB (1024*1024) #define KB (1024) static void cmdsum(Edit *edit, Part *vp, int64_t a, int64_t b) { char *name, *ty; char buf[3]; char *suf; Dospart *p; int64_t sz, div; p = (Dospart*)vp; buf[0] = p && p->changed ? '\'' : ' '; buf[1] = p && (p->active & Active) ? '*' : ' '; buf[2] = '\0'; name = p ? p->name : "empty"; ty = p ? typestr0(p->type) : ""; sz = (b-a)*edit->disk->secsize*sec2cyl; if(sz >= 1*TB){ suf = "TB"; div = TB; }else if(sz >= 1*GB){ suf = "GB"; div = GB; }else if(sz >= 1*MB){ suf = "MB"; div = MB; }else if(sz >= 1*KB){ suf = "KB"; div = KB; }else{ suf = "B "; div = 1; } if(div == 1) print("%s %-12s %*lld %-*lld (%lld cylinders, %lld %s) %s\n", buf, name, edit->disk->width, a, edit->disk->width, b, b-a, sz, suf, ty); else print("%s %-12s %*lld %-*lld (%lld cylinders, %lld.%.2d %s) %s\n", buf, name, edit->disk->width, a, edit->disk->width, b, b-a, sz/div, (int)(((sz%div)*100)/div), suf, ty); } static char* cmdadd(Edit *edit, char *name, int64_t start, int64_t end) { Dospart *p; if(!haveroom(edit, name[0]=='p', start)) return "no room for partition"; start *= sec2cyl; end *= sec2cyl; if(start == 0 || name[0] != 'p') start += edit->disk->s; p = mkpart(name, name[0]=='p', start, end-start, nil); p->changed = 1; p->type = Type9; return addpart(edit, p); } static char* cmddel(Edit *edit, Part *p) { return delpart(edit, p); } static char* cmdwrite(Edit *edit) { wrpart(edit); return nil; } static char *help = "A name - set partition active\n" "P - print table in ctl format\n" "R - restore disk back to initial configuration and exit\n" "e - show empty dos partitions\n" "t name [type] - set partition type\n"; static char* cmdhelp(Edit *e) { print("%s\n", help); return nil; } static char* cmdactive(Edit *edit, int nf, char **f) { int i; Dospart *p, *ip; if(nf != 2) return "args"; if(f[1][0] != 'p') return "cannot set secondary partition active"; if((p = (Dospart*)findpart(edit, f[1])) == nil) return "unknown partition"; for(i=0; inpart; i++) { ip = (Dospart*)edit->part[i]; if(ip->active & Active) { ip->active &= ~Active; ip->changed = 1; edit->changed = 1; } } if((p->active & Active) == 0) { p->active |= Active; p->changed = 1; edit->changed = 1; } return nil; } static char* strupr(char *s) { char *p; for(p=s; *p; p++) *p = toupper(*p); return s; } static void dumplist(void) { int i, n; n = 0; for(i=0; i<256; i++) { if(types[i].desc) { print("%-16s", types[i].desc); if(n++%4 == 3) print("\n"); } } if(n%4) print("\n"); } static char* cmdtype(Edit *edit, int nf, char **f) { char *q; Dospart *p; int i; if(nf < 2) return "args"; if((p = (Dospart*)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] == '?') dumplist(); else break; } } else q = f[2]; strupr(q); for(i=0; i<256; i++) if(types[i].desc && strcmp(types[i].desc, q) == 0) break; if(i < 256 && p->type != i) { p->type = i; p->changed = 1; edit->changed = 1; } return nil; } static char* cmdext(Edit *edit, int nf, char **f) { switch(f[0][0]) { case 'A': return cmdactive(edit, nf, f); case 't': return cmdtype(edit, nf, f); case 'R': recover(edit); return nil; default: return "unknown command"; } } static int Dfmt(Fmt *f) { char buf[60]; uint8_t *p; int c, h, s; p = va_arg(f->args, uint8_t*); h = p[0]; c = p[2]; c |= (p[1]&0xC0)<<2; s = (p[1] & 0x3F); sprint(buf, "%d/%d/%d", c, h, s); return fmtstrcpy(f, buf); } static void writechs(Disk *disk, uint8_t *p, int64_t lba) { int c, h, s; s = lba % disk->s; h = (lba / disk->s) % disk->h; c = lba / (disk->s * disk->h); if(c >= 1024) { c = 1023; h = disk->h - 1; s = disk->s - 1; } p[0] = h; p[1] = ((s+1) & 0x3F) | ((c>>2) & 0xC0); p[2] = c; } static void wrtentry(Disk *disk, Tentry *tp, int type, uint32_t xbase, uint32_t lba, uint32_t end) { tp->type = type; writechs(disk, &tp->starth, lba); writechs(disk, &tp->endh, end-1); putle32(tp->xlba, lba-xbase); putle32(tp->xsize, end-lba); } static int wrextend(Edit *edit, int i, int64_t xbase, int64_t startlba, int64_t *endlba) { int ni; Table table; Tentry *tp, *ep; Dospart *p; Disk *disk; if(i == edit->npart){ *endlba = edit->disk->secs; Finish: if(startlba < *endlba){ disk = edit->disk; diskread(disk, &table, Tablesz, mbroffset+startlba, Toffset); tp = table.entry; ep = tp+NTentry; for(; tpdisk, &table, Tablesz, mbroffset+startlba, Toffset) < 0) recover(edit); } return i; } p = (Dospart*)edit->part[i]; if(p->primary){ *endlba = (int64_t)p->start*sec2cyl; goto Finish; } disk = edit->disk; diskread(disk, &table, Tablesz, mbroffset+startlba, Toffset); tp = table.entry; ep = tp+NTentry; ni = wrextend(edit, i+1, xbase, p->end*sec2cyl, endlba); *tp = p->Tentry; wrtentry(disk, tp, p->type, startlba, startlba+disk->s, p->end*sec2cyl); tp++; if(p->end*sec2cyl != *endlba){ memset(tp, 0, sizeof *tp); wrtentry(disk, tp, TypeEXTENDED, xbase, p->end*sec2cyl, *endlba); tp++; } for(; tpdisk, &table, Tablesz, mbroffset+startlba, Toffset) < 0) recover(edit); return ni; } static void wrpart(Edit *edit) { int i, ni, t; Table table; Tentry *tp, *ep; Disk *disk; int64_t s, endlba; Dospart *p; disk = edit->disk; diskread(disk, &table, Tablesz, mbroffset, Toffset); tp = table.entry; ep = tp+NTentry; for(i=0; inpart && tppart[i]; if(p->start == 0) s = disk->s; else s = p->start*sec2cyl; if(p->primary) { *tp = p->Tentry; wrtentry(disk, tp, p->type, 0, s, p->end*sec2cyl); tp++; i++; } else { ni = wrextend(edit, i, p->start*sec2cyl, p->start*sec2cyl, &endlba); memset(tp, 0, sizeof *tp); if(endlba >= 1024*sec2cyl) t = TypeEXTHUGE; else t = TypeEXTENDED; wrtentry(disk, tp, t, 0, s, endlba); tp++; i = ni; } } for(; tpnpart) sysfatal("cannot happen #1"); if(diskwrite(disk, &table, Tablesz, mbroffset, Toffset) < 0) recover(edit); /* bring parts up to date */ freenamelist(); for(i=0; inpart; i++) plan9print((Dospart*)edit->part[i], -1); if(ctldiff(edit, disk->ctlfd) < 0) fprint(2, "?warning: partitions could not be updated in devsd\n"); }