ref: babf901b4a508c3ec5d1f89655f10377bbdf9637
dir: /appl/cmd/disk/prep/fdisk.b/
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;
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(sys->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;
}