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 activePrimary: con 16r01; # internal flag TypeBB: con 16rFF; TypeEMPTY: con 16r00;TypeFAT12: con 16r01;TypeXENIX: con 16r02; # rootTypeXENIXUSR: con 16r03; # usrTypeFAT16: con 16r04;TypeEXTENDED: con 16r05;TypeFATHUGE: con 16r06;TypeHPFS: con 16r07;TypeAIXBOOT: con 16r08;TypeAIXDATA: con 16r09;TypeOS2BOOT: con 16r0A; # OS/2 Boot ManagerTypeFAT32: con 16r0B; # FAT 32TypeFAT32LBA: con 16r0C; # FAT 32 needing LBA supportTypeEXTHUGE: con 16r0F; # FAT 32 extended partitionTypeUNFORMATTED: con 16r16; # unformatted primary partition (OS/2 FDISK)?TypeHPFS2: con 16r17;TypeIBMRecovery: con 16r1C; # really hidden fatTypeCPM0: con 16r52;TypeDMDDO: con 16r54; # Disk Manager Dynamic Disk OverlayTypeGB: con 16r56; # ????TypeSPEEDSTOR: con 16r61;TypeSYSV386: con 16r63; # also HURD?TypeNETWARE: con 16r64;TypePCIX: con 16r75;TypeMINIX13: con 16r80; # Minix v1.3 and belowTypeMINIX: 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;} Lines 1–500 of 924. Load more
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; }