forsyth20121205-174063a80cc13 years agoHistory
924 lines · 19.7 KB · Brainfuck
RawDownload
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.