diff options
Diffstat (limited to 'appl/cmd/disk/prep/fdisk.b')
| -rw-r--r-- | appl/cmd/disk/prep/fdisk.b | 925 |
1 files changed, 925 insertions, 0 deletions
diff --git a/appl/cmd/disk/prep/fdisk.b b/appl/cmd/disk/prep/fdisk.b new file mode 100644 index 00000000..00ecbb36 --- /dev/null +++ b/appl/cmd/disk/prep/fdisk.b @@ -0,0 +1,925 @@ +implement Fdisk; + +# +# fdisk - edit dos disk partition table +# + +include "sys.m"; + sys: Sys; + +include "draw.m"; + +include "disks.m"; + disks: Disks; + Disk, PCpart: import disks; + NTentry, Toffset, TentrySize: import Disks; + Magic0, Magic1: import Disks; + readn: import disks; + +include "pedit.m"; + pedit: Pedit; + Edit, Part: import pedit; + +include "arg.m"; + +Fdisk: module +{ + init: fn(nil: ref Draw->Context, nil: list of string); +}; + +Mpart: con 64; + +blank := 0; +dowrite := 0; +file := 0; +rdonly := 0; +doauto := 0; +mbroffset := big 0; +printflag := 0; +printchs := 0; +sec2cyl := big 0; +written := 0; + +edit: ref Edit; +stderr: ref Sys->FD; + +init(nil: ref Draw->Context, args: list of string) +{ + sys = load Sys Sys->PATH; + disks = load Disks Disks->PATH; + pedit = load Pedit Pedit->PATH; + + sys->pctl(Sys->FORKFD, nil); + disks->init(); + pedit->init(); + + edit = Edit.mk("cylinder"); + + edit.add = cmdadd; + edit.del = cmddel; + edit.okname = cmdokname; + edit.ext = cmdext; + edit.help = cmdhelp; + edit.sum = cmdsum; + edit.write = cmdwrite; + edit.printctl = cmdprintctl; + + stderr = sys->fildes(2); + + secsize := 0; + arg := load Arg Arg->PATH; + arg->init(args); + arg->setusage("disk/fdisk [-abfprvw] [-s sectorsize] /dev/sdC0/data"); + while((o := arg->opt()) != 0) + case o { + 'a' => + doauto++; + 'b' => + blank++; + 'f' => + file++; + 'p' => + printflag++; + 'r' => + rdonly++; + 's' => + secsize = int arg->earg(); + 'v' => + printchs++; + 'w' => + dowrite++; + * => + arg->usage(); + } + args = arg->argv(); + if(len args != 1) + arg->usage(); + arg = nil; + + mode := Sys->ORDWR; + if(rdonly) + mode = Sys->OREAD; + edit.disk = Disk.open(hd args, mode, file); + if(edit.disk == nil) { + sys->fprint(stderr, "cannot open disk: %r\n"); + exits("opendisk"); + } + + if(secsize != 0) { + edit.disk.secsize = secsize; + edit.disk.secs = edit.disk.size / big secsize; + } + + sec2cyl = big (edit.disk.h * edit.disk.s); + edit.end = edit.disk.secs / sec2cyl; + + findmbr(edit); + + if(blank) + blankpart(edit); + else + rdpart(edit, big 0, big 0); + + if(doauto) + autopart(edit); + + { + if(dowrite) + edit.runcmd("w"); + + if(printflag) + edit.runcmd("P"); + + if(dowrite || printflag) + exits(nil); + + sys->fprint(stderr, "cylinder = %bd bytes\n", sec2cyl*big edit.disk.secsize); + edit.runcmd("p"); + for(;;) { + sys->fprint(stderr, ">>> "); + edit.runcmd(edit.getline()); + } + }exception e{ + "*" => + sys->fprint(stderr, "fdisk: exception %q\n", e); + if(written) + recover(edit); + } +} + +Active: con 16r80; # partition is active +Primary: con 16r01; # internal flag + +TypeBB: con 16rFF; + +TypeEMPTY: con 16r00; +TypeFAT12: con 16r01; +TypeXENIX: con 16r02; # root +TypeXENIXUSR: con 16r03; # usr +TypeFAT16: con 16r04; +TypeEXTENDED: con 16r05; +TypeFATHUGE: con 16r06; +TypeHPFS: con 16r07; +TypeAIXBOOT: con 16r08; +TypeAIXDATA: con 16r09; +TypeOS2BOOT: con 16r0A; # OS/2 Boot Manager +TypeFAT32: con 16r0B; # FAT 32 +TypeFAT32LBA: con 16r0C; # FAT 32 needing LBA support +TypeEXTHUGE: con 16r0F; # FAT 32 extended partition +TypeUNFORMATTED: con 16r16; # unformatted primary partition (OS/2 FDISK)? +TypeHPFS2: con 16r17; +TypeIBMRecovery: con 16r1C; # really hidden fat +TypeCPM0: con 16r52; +TypeDMDDO: con 16r54; # Disk Manager Dynamic Disk Overlay +TypeGB: con 16r56; # ???? +TypeSPEEDSTOR: con 16r61; +TypeSYSV386: con 16r63; # also HURD? +TypeNETWARE: con 16r64; +TypePCIX: con 16r75; +TypeMINIX13: con 16r80; # Minix v1.3 and below +TypeMINIX: con 16r81; # Minix v1.5+ +TypeLINUXSWAP: con 16r82; +TypeLINUX: con 16r83; +TypeLINUXEXT: con 16r85; +TypeAMOEBA: con 16r93; +TypeAMOEBABB: con 16r94; +TypeBSD386: con 16rA5; +TypeBSDI: con 16rB7; +TypeBSDISWAP: con 16rB8; +TypeOTHER: con 16rDA; +TypeCPM: con 16rDB; +TypeDellRecovery: con 16rDE; +TypeSPEEDSTOR12: con 16rE1; +TypeSPEEDSTOR16: con 16rE4; +TypeLANSTEP: con 16rFE; + +Type9: con Disks->Type9; + +TableSize: con TentrySize*NTentry; +Omagic: con TableSize; + +Type: adt { + desc: string; + name: string; +}; + +Dospart: adt { + p: ref Part; + pc: ref PCpart; + primary: int; + lba: big; # absolute address + size: big; +}; + +Recover: adt { + table: array of byte; # [TableSize+2] copy of table and magic + lba: big; # where it came from +}; + +types: array of Type = array[256] of { + TypeEMPTY => ( "EMPTY", "" ), + TypeFAT12 => ( "FAT12", "dos" ), + TypeFAT16 => ( "FAT16", "dos" ), + TypeFAT32 => ( "FAT32", "dos" ), + TypeFAT32LBA => ( "FAT32LBA", "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", "" ), + TypeAMOEBA => ( "AMOEBA", "amoeba" ), + TypeAMOEBABB => ( "AMOEBABB", "amoebaboot" ), + TypeBSD386 => ( "BSD386", "bsd386" ), + TypeBSDI => ( "BSDI", "bsdi" ), + TypeBSDISWAP => ( "BSDISWAP", "bsdiswap" ), + TypeOTHER => ( "OTHER", "other" ), + TypeCPM => ( "CPM", "cpm" ), + TypeDellRecovery => ( "DELLRECOVERY", "dell" ), + TypeSPEEDSTOR12 => ( "SPEEDSTOR12", "speedstor" ), + TypeSPEEDSTOR16 => ( "SPEEDSTOR16", "speedstor" ), + TypeLANSTEP => ( "LANSTEP", "lanstep" ), + + Type9 => ( "PLAN9", "plan9" ), + + * => (nil, nil), +}; + +dosparts: list of ref Dospart; + +tag2part(p: ref Part): ref Dospart +{ + for(l := dosparts; l != nil; l = tl l) + if((hd l).p.tag == p.tag) + return hd l; + raise "tag2part: cannot happen"; +} + +typestr0(ptype: int): string +{ + if(ptype < 0 || ptype >= len types || types[ptype].desc == nil) + return sys->sprint("type %d", ptype); + return types[ptype].desc; +} + +gettable(disk: ref Disk, addr: big, mbr: int): array of byte +{ + table := array[TableSize+2] of {* => byte 0}; + diskread(disk, table, len table, addr, Toffset); + if(mbr){ + # the informal specs say all must have this but apparently not, only mbr + if(int table[Omagic] != Magic0 || int table[Omagic+1] != Magic1) + sysfatal("did not find master boot record"); + } + return table; +} + +diskread(disk: ref Disk, data: array of byte, ndata: int, sec: big, off: int) +{ + a := sec*big disk.secsize + big off; + if(sys->seek(disk.fd, a, 0) != a) + sysfatal(sys->sprint("diskread seek %bud.%ud: %r", sec, off)); + if(readn(disk.fd, data, ndata) != ndata) + sysfatal(sys->sprint("diskread %ud at %bud.%ud: %r", ndata, sec, off)); +} + +puttable(disk: ref Disk, table: array of byte, sec: big): int +{ + return diskwrite(disk, table, len table, sec, Toffset); +} + +diskwrite(disk: ref Disk, data: array of byte, ndata: int, sec: big, off: int): int +{ + written = 1; + a := sec*big disk.secsize + big off; + if(sys->seek(disk.wfd, a, 0) != a || + sys->write(disk.wfd, data, ndata) != ndata){ + sys->fprint(stderr, "write %d bytes at %bud.%ud failed: %r\n", ndata, sec, off); + return -1; + } + return 0; +} + +partgen := 0; +parttag := 0; + +mkpart(name: string, primary: int, lba: big, size: big, pcpart: ref PCpart): ref Dospart +{ + p := ref Dospart; + if(name == nil){ + if(primary) + c := 'p'; + else + c = 's'; + name = sys->sprint("%c%d", c, ++partgen); + } + + if(pcpart != nil) + p.pc = pcpart; + else + p.pc = ref PCpart(0, 0, big 0, big 0, big 0); + + p.primary = primary; + p.p = ref Part; # TO DO + p.p.name = name; + p.p.start = lba/sec2cyl; + p.p.end = (lba+size)/sec2cyl; + p.p.ctlstart = lba; + p.p.ctlend = lba+size; + p.p.tag = ++parttag; + p.lba = lba; # absolute lba + p.size = size; + dosparts = p :: dosparts; + return p; +} + +# +# Recovery takes care of remembering what the various tables +# looked like when we started, attempting to restore them when +# we are finished. +# +rtabs: list of ref Recover; + +addrecover(t: array of byte, lba: big) +{ + tc := array[TableSize+2] of byte; + tc[0:] = t[0:len tc]; + rtabs = ref Recover(tc, lba) :: rtabs; +} + +recover(edit: ref Edit) +{ + err := 0; + for(rl := rtabs; rl != nil; rl = tl rl){ + r := hd rl; + if(puttable(edit.disk, r.table, r.lba) < 0) + err = 1; + } + if(err) { + sys->fprint(stderr, "warning: some writes failed during restoration of old partition tables\n"); + exits("inconsistent"); + } else + sys->fprint(stderr, "restored old partition tables\n"); + + ctlfd := edit.disk.ctlfd; + if(ctlfd != nil){ + offset := edit.disk.offset; + for(i:=0; i<len edit.part; i++) + if(edit.part[i].ctlname != nil && sys->fprint(ctlfd, "delpart %s", edit.part[i].ctlname)<0) + sys->fprint(stderr, "delpart failed: %s: %r", edit.part[i].ctlname); + for(i=0; i<len edit.ctlpart; i++) + if(edit.part[i].name != nil && sys->fprint(ctlfd, "delpart %s", edit.ctlpart[i].name)<0) + sys->fprint(stderr, "delpart failed: %s: %r", edit.ctlpart[i].name); + for(i=0; i<len edit.ctlpart; i++){ + if(sys->fprint(ctlfd, "part %s %bd %bd", edit.ctlpart[i].name, + edit.ctlpart[i].start+offset, edit.ctlpart[i].end+offset) < 0){ + sys->fprint(stderr, "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. +# +rdpart(edit: ref Edit, lba: big, xbase: big) +{ + if(xbase == big 0) + xbase = lba; # extended partition in mbr sets the base + + table := gettable(edit.disk, mbroffset+lba, lba == big 0); + addrecover(table, mbroffset+lba); + + for(tp := 0; tp<TableSize; tp += TentrySize){ + dp := PCpart.extract(table[tp:], edit.disk); + case dp.ptype { + TypeEMPTY => + ; + TypeEXTENDED or + TypeEXTHUGE or + TypeLINUXEXT => + rdpart(edit, xbase+dp.offset, xbase); + * => + p := mkpart(nil, lba==big 0, lba+dp.offset, dp.size, ref dp); + if((err := edit.addpart(p.p)) != nil) + sys->fprint(stderr, "error adding partition: %s\n", err); + } + } +} + +blankpart(edit: ref Edit) +{ + edit.changed = 1; +} + +findmbr(edit: ref Edit) +{ + table := gettable(edit.disk, big 0, 1); + for(tp := 0; tp < TableSize; tp += TentrySize){ + p := PCpart.extract(table[tp:], edit.disk); + if(p.ptype == TypeDMDDO) + mbroffset = big edit.disk.s; + } +} + +haveroom(edit: ref Edit, primary: int, start: big): int +{ + 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; i<len edit.part; i++) { + p := tag2part(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; i<len edit.part; i++){ + p := tag2part(edit.part[i]); + if(p.primary) + n++; + pend := p.p.end; + q: ref Dospart; + qstart: big; + if(i+1<len edit.part){ + q = tag2part(edit.part[i+1]); + qstart = q.p.start; + }else{ + qstart = edit.end; + q = nil; + } + if(start < pend || start >= qstart) + continue; + # we go between these two + if(p.primary==0 || (q != nil && q.primary==0)) + return 1; + } + # not next to a secondary, need a new primary + return n<4; +} + +autopart(edit: ref Edit) +{ + for(i:=0; i<len edit.part; i++) + if(tag2part(edit.part[i]).pc.ptype == Type9) + return; + + # look for the biggest gap in which we can put a primary partition + start := big 0; + bigsize := big 0; + bigstart := big 0; + for(i=0; i<len edit.part; i++) { + p := tag2part(edit.part[i]); + if(p.p.start > start && p.p.start - start > bigsize && haveroom(edit, 1, start)) { + bigsize = p.p.start - start; + bigstart = start; + } + start = p.p.end; + } + + if(edit.end - start > bigsize && haveroom(edit, 1, start)) { + bigsize = edit.end - start; + bigstart = start; + } + if(bigsize < big 1) { + sys->fprint(stderr, "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; i<len edit.part; i++){ + p := tag2part(edit.part[i]); + if(p.primary && p.pc.active & Active) + active = 0; + } + + # add new plan 9 partition + bigsize *= sec2cyl; + bigstart *= sec2cyl; + if(bigstart == big 0) { + bigstart += big edit.disk.s; + bigsize -= big edit.disk.s; + } + p := mkpart(nil, 1, bigstart, bigsize, nil); + p.p.changed = 1; + p.pc.active = active; + p.pc.ptype = Type9; + edit.changed = 1; + if((err := edit.addpart(p.p)) != nil){ + sys->fprint(stderr, "error adding plan9 partition: %s\n", err); + return; + } +} + +namelist: list of string; + +plan9print(part: ref Dospart, fd: ref Sys->FD) +{ + vname := types[part.pc.ptype].name; + if(vname==nil) { + part.p.ctlname = ""; + return; + } + + start := mbroffset+part.lba; + end := start+part.size; + + # avoid names like plan90 + i := len vname - 1; + if(isdigit(vname[i])) + sep := "."; + else + sep = ""; + + i = 0; + name := sys->sprint("%s", vname); + ok: int; + do { + ok = 1; + for(nl := namelist; nl != nil; nl = tl nl) + if(name == hd nl) { + i++; + name = sys->sprint("%s%s%d", vname, sep, i); + ok = 0; + } + } while(ok == 0); + + namelist = name :: namelist; + part.p.ctlname = name; + + if(fd != nil) + sys->print("part %s %bd %bd\n", name, start, end); +} + +cmdprintctl(edit: ref Edit, ctlfd: ref Sys->FD) +{ + namelist = nil; + for(i:=0; i<len edit.part; i++) + plan9print(tag2part(edit.part[i]), nil); + edit.ctldiff(ctlfd); +} + +cmdokname(nil: ref Edit, name: string): string +{ + if(name[0] != 'p' && name[0] != 's' || len name < 2) + return "name must be pN or sN"; + for(i := 1; i < len name; i++) + if(!isdigit(name[i])) + return "name must be pN or sN"; + + return nil; +} + +KB: con big 1024; +MB: con KB*KB; +GB: con KB*MB; + +cmdsum(edit: ref Edit, vp: ref Part, a, b: big) +{ + if(vp != nil) + p := tag2part(vp); + + qual: string; + if(p != nil && p.p.changed) + qual += "'"; + else + qual += " "; + if(p != nil && p.pc.active&Active) + qual += "*"; + else + qual += " "; + + if(p != nil) + name := p.p.name; + else + name = "empty"; + if(p != nil) + ty := " "+typestr0(p.pc.ptype); + else + ty = ""; + + sz := (b-a)*big edit.disk.secsize*sec2cyl; + suf := "B"; + div := big 1; + if(sz >= big 1*GB){ + suf = "GB"; + div = GB; + }else if(sz >= big 1*MB){ + suf = "MB"; + div = MB; + }else if(sz >= big 1*KB){ + suf = "KB"; + div = KB; + } + + if(div == big 1) + sys->print("%s %-12s %*bd %-*bd (%bd cylinders, %bd %s)%s\n", qual, name, + edit.disk.width, a, edit.disk.width, b, b-a, sz, suf, ty); + else + sys->print("%s %-12s %*bd %-*bd (%bd cylinders, %bd.%.2d %s)%s\n", qual, name, + edit.disk.width, a, edit.disk.width, b, b-a, + sz/div, int(((sz%div)*big 100)/div), suf, ty); +} + +cmdadd(edit: ref Edit, name: string, start: big, end: big): string +{ + if(!haveroom(edit, name[0]=='p', start)) + return "no room for partition"; + start *= sec2cyl; + end *= sec2cyl; + if(start == big 0 || name[0] != 'p') + start += big edit.disk.s; + p := mkpart(name, name[0]=='p', start, end-start, nil); + p.p.changed = 1; + p.pc.ptype = Type9; + return edit.addpart(p.p); +} + +cmddel(edit: ref Edit, p: ref Part): string +{ + return edit.delpart(p); +} + +cmdwrite(edit: ref Edit): string +{ + wrpart(edit); + return nil; +} + +help: con + "A name - set partition active\n"+ + "P - sys->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"; + +cmdhelp(nil: ref Edit): string +{ + sys->print("%s\n", help); + return nil; +} + +cmdactive(edit: ref Edit, f: array of string): string +{ + if(len f != 2) + return "args"; + + if(f[1][0] != 'p') + return "cannot set secondary partition active"; + + if((p := tag2part(edit.findpart(f[1]))) == nil) + return "unknown partition"; + + for(i:=0; i<len edit.part; i++) { + ip := tag2part(edit.part[i]); + if(ip.pc.active & Active) { + ip.pc.active &= ~Active; + ip.p.changed = 1; + edit.changed = 1; + } + } + + if((p.pc.active & Active) == 0) { + p.pc.active |= Active; + p.p.changed = 1; + edit.changed = 1; + } + + return nil; +} + +strupr(s: string): string +{ + for(i := 0; i < len s; i++) + if(s[i] >= 'a' && s[i] <= 'z') + s[i] += 'A' - 'a'; + return s; +} + +dumplist() +{ + n := 0; + for(i:=0; i<len types; i++) { + if(types[i].desc != nil) { + sys->print("%-16s", types[i].desc); + if(n++%4 == 3) + sys->print("\n"); + } + } + if(n%4) + sys->print("\n"); +} + +cmdtype(edit: ref Edit, f: array of string): string +{ + if(len f < 2) + return "args"; + + if((p := tag2part(edit.findpart(f[1]))) == nil) + return "unknown partition"; + + q: string; + if(len f == 2) { + for(;;) { + sys->fprint(stderr, "new partition type [? for list]: "); + q = edit.getline(); + if(q[0] == '?') + dumplist(); + else + break; + } + } else + q = f[2]; + + q = strupr(q); + for(i:=0; i<len types; i++) + if(types[i].desc != nil && types[i].desc == q) + break; + if(i < len types && p.pc.ptype != i) { + p.pc.ptype = i; + p.p.changed = 1; + edit.changed = 1; + } + return nil; +} + +cmdext(edit: ref Edit, f: array of string): string +{ + case f[0][0] { + 'A' => + return cmdactive(edit, f); + 't' => + return cmdtype(edit, f); + 'R' => + recover(edit); + return nil; + * => + return "unknown command"; + } +} + +wrextend(edit: ref Edit, i: int, xbase: big, startlba: big): (int, big) +{ + if(i == len edit.part){ + endlba := edit.disk.secs; + if(startlba < endlba) + wrzerotab(edit.disk, mbroffset+startlba); + return (i, endlba); + } + + p := tag2part(edit.part[i]); + if(p.primary){ + endlba := p.p.start*sec2cyl; + if(startlba < endlba) + wrzerotab(edit.disk, mbroffset+startlba); + return (i, endlba); + } + + disk := edit.disk; + table := gettable(disk, mbroffset+startlba, 0); + + (ni, endlba) := wrextend(edit, i+1, xbase, p.p.end*sec2cyl); + + tp := wrtentry(disk, table[0:], p.pc.active, p.pc.ptype, startlba, startlba+big disk.s, p.p.end*sec2cyl); + if(p.p.end*sec2cyl != endlba) + tp += wrtentry(disk, table[tp:], 0, TypeEXTENDED, xbase, p.p.end*sec2cyl, endlba); + + for(; tp<TableSize; tp++) + table[tp] = byte 0; + + table[Omagic] = byte Magic0; + table[Omagic+1] = byte Magic1; + + if(puttable(edit.disk, table, mbroffset+startlba) < 0) + recover(edit); + return (ni, endlba); +} + +wrzerotab(disk: ref Disk, addr: big) +{ + table := array[TableSize+2] of {Omagic => byte Magic0, Omagic+1 => byte Magic1, * => byte 0}; + if(puttable(disk, table, addr) < 0) + recover(edit); +} + +wrpart(edit: ref Edit) +{ + disk := edit.disk; + + table := gettable(disk, mbroffset, 0); + + tp := 0; + for(i:=0; i<len edit.part && tp<TableSize; ) { + p := tag2part(edit.part[i]); + if(p.p.start == big 0) + s := big disk.s; + else + s = p.p.start*sec2cyl; + if(p.primary) { + tp += wrtentry(disk, table[tp:], p.pc.active, p.pc.ptype, big 0, s, p.p.end*sec2cyl); + i++; + }else{ + (ni, endlba) := wrextend(edit, i, p.p.start*sec2cyl, p.p.start*sec2cyl); + if(endlba >= big 1024*sec2cyl) + t := TypeEXTHUGE; + else + t = TypeEXTENDED; + tp += wrtentry(disk, table[tp:], 0, t, big 0, s, endlba); + i = ni; + } + } + for(; tp<TableSize; tp++) + table[tp] = byte 0; + + if(i != len edit.part) + raise "wrpart: cannot happen #1"; + + if(puttable(disk, table, mbroffset) < 0) + recover(edit); + + # bring parts up to date + namelist = nil; + for(i=0; i<len edit.part; i++) + plan9print(tag2part(edit.part[i]), nil); + + if(edit.ctldiff(disk.ctlfd) < 0) + sys->fprint(stderr, "?warning: partitions could not be updated in devsd\n"); +} + +isdigit(c: int): int +{ + return c >= '0' && c <= '9'; +} + +sysfatal(s: string) +{ + sys->fprint(stderr, "fdisk: %s\n", s); + raise "fail:error"; +} + +exits(s: string) +{ + if(s != nil) + raise "fail:"+s; + exit; +} + +assert(i: int) +{ + if(!i) + raise "assertion failed"; +} + +wrtentry(disk: ref Disk, entry: array of byte, active: int, ptype: int, xbase: big, lba: big, end: big): int +{ + pc: PCpart; + pc.active = active; + pc.ptype = ptype; + pc.base = xbase; + pc.offset = lba-xbase; + pc.size = end-lba; + entry[0:] = pc.bytes(disk); + return TentrySize; +} |
