henesyinit from p9fd787fda5 years agoHistory
460 lines · 8.8 KB · C
RawDownload
/* * prep - prepare plan9 disk partition */#include <u.h>#include <libc.h>#include <bio.h>#include <disk.h>#include "edit.h" enum {	Maxpath = 128,}; static int		blank;static int		file;static int		doauto;static int		printflag;static Part		**opart;static int		nopart;static char	*osecbuf;static char	*secbuf;static int		rdonly;static int		dowrite;static int		docache;static int		donvram; static void		autopart(Edit*);static vlong	memsize(void);static Part		*mkpart(char*, vlong, vlong, int);static void		rdpart(Edit*);static void		wrpart(Edit*);static void		checkfat(Disk*); static void 	cmdsum(Edit*, Part*, vlong, vlong);static char 	*cmdadd(Edit*, char*, vlong, vlong);static char 	*cmddel(Edit*, Part*);static char 	*cmdokname(Edit*, char*);static char 	*cmdwrite(Edit*);static char	*cmdctlprint(Edit*, int, char**); Edit edit = {	.add=	cmdadd,	.del=		cmddel,	.okname=	cmdokname,	.sum=	cmdsum,	.write=	cmdwrite, 	.unit=	"sector",}; voidusage(void){	fprint(2, "usage: disk/prep [-abcfprw] [-s sectorsize] /dev/sdC0/plan9\n");	exits("usage");} voidmain(int argc, char **argv){	int i;	Disk *disk;	vlong secsize; 	secsize = 0;	ARGBEGIN{	case 'a':		doauto++;		break;	case 'b':		blank++;		break;	case 'c':		docache++;		break;	case 'f':		file++;		break;	case 'n':		donvram++;		break;	case 'p':		printflag++;		rdonly++;		break;	case 'r':		rdonly++;		break;	case 's':		secsize = atoi(ARGF());		break;	case 'w':		dowrite++;		break;	default:		usage();	}ARGEND; 	if(argc != 1)		usage(); 	disk = opendisk(argv[0], rdonly, file);	if(disk == nil) {		fprint(2, "cannot open disk: %r\n");		exits("opendisk");	} 	if(secsize != 0) {		disk->secsize = secsize;		disk->secs = disk->size / secsize;	}	edit.end = disk->secs; 	checkfat(disk); 	secbuf = emalloc(disk->secsize+1);	osecbuf = emalloc(disk->secsize+1);	edit.disk = disk; 	if(blank == 0)		rdpart(&edit); 	opart = emalloc(edit.npart*sizeof(opart[0])); 	/* save old partition table */	for(i=0; i<edit.npart; i++)		opart[i] = edit.part[i];	nopart = edit.npart; 	if(printflag) {		runcmd(&edit, "P");		exits(0);	} 	if(doauto)		autopart(&edit); 	if(dowrite) {		runcmd(&edit, "w");		exits(0);	} 	runcmd(&edit, "p");	for(;;) {		fprint(2, ">>> ");		runcmd(&edit, getline(&edit));	}} #define GB (1024*1024*1024)#define MB (1024*1024)#define KB (1024) static voidcmdsum(Edit *edit, Part *p, vlong a, vlong b){	vlong sz, div;	char *suf, *name;	char c; 	c = p && p->changed ? '\'' : ' ';	name = p ? p->name : "empty"; 	sz = (b-a)*edit->disk->secsize;	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("%c %-12s %*lld %-*lld (%lld sectors, %lld %s)\n", c, name,			edit->disk->width, a, edit->disk->width, b, b-a, sz, suf);	else		print("%c %-12s %*lld %-*lld (%lld sectors, %lld.%.2d %s)\n", c, name,			edit->disk->width, a, edit->disk->width, b, b-a,			sz/div, (int)(((sz%div)*100)/div), suf);} static char*cmdadd(Edit *edit, char *name, vlong start, vlong end){	if(start < 2 && strcmp(name, "9fat") != 0)		return "overlaps with the pbs and/or the partition table"; 	return addpart(edit, mkpart(name, start, end, 1));} static char*cmddel(Edit *edit, Part *p){	return delpart(edit, p);} static char*cmdwrite(Edit *edit){	wrpart(edit);	return nil;} static char isfrog[256]={	/*NUL*/	1, 1, 1, 1, 1, 1, 1, 1,	/*BKS*/	1, 1, 1, 1, 1, 1, 1, 1,	/*DLE*/	1, 1, 1, 1, 1, 1, 1, 1,	/*CAN*/	1, 1, 1, 1, 1, 1, 1, 1,	[' ']	1,	['/']	1,	[0x7f]	1,}; static char*cmdokname(Edit*, char *elem){	for(; *elem; elem++)		if(isfrog[*(uchar*)elem])			return "bad character in name";	return nil;} /* *  return memory size in bytes */static vlongmemsize(void){	int fd, n, by2pg;	char *p;	char buf[128];	vlong mem; 	p = getenv("cputype");	if(p && (strcmp(p, "68020") == 0 || strcmp(p, "alpha") == 0))		by2pg = 8*1024;	else		by2pg = 4*1024; 	mem = 64*1024*1024;	fd = open("/dev/swap", OREAD);	if(fd < 0)		return mem;	n = read(fd, buf, sizeof(buf)-1);	close(fd);	if(n <= 0)		return mem;	buf[n] = 0;	p = strchr(buf, '/');	if(p)		mem = strtoul(p+1, 0, 0) * (vlong)by2pg;	return mem;} static Part*mkpart(char *name, vlong start, vlong end, int changed){	Part *p; 	p = emalloc(sizeof(*p));	p->name = estrdup(name);	p->ctlname = estrdup(name);	p->start = start;	p->end = end;	p->changed = changed;	return p;} /* plan9 partition is first sector of the disk */static voidrdpart(Edit *edit){	int i, nline, nf, waserr;	char *line[128];	vlong a, b;	char *f[5];	char *err;	Disk *disk; 	disk = edit->disk;	seek(disk->fd, disk->secsize, 0);	if(readn(disk->fd, osecbuf, disk->secsize) != disk->secsize)		return;	osecbuf[disk->secsize] = '\0';	memmove(secbuf, osecbuf, disk->secsize+1); 	if(strncmp(secbuf, "part", 4) != 0){		fprint(2, "no plan9 partition table found\n");		return;	} 	waserr = 0;	nline = getfields(secbuf, line, nelem(line), 1, "\n");	for(i=0; i<nline; i++){		if(strncmp(line[i], "part", 4) != 0) {		Error:			if(waserr == 0)				fprint(2, "syntax error reading partition\n");			waserr = 1;			continue;		} 		nf = getfields(line[i], f, nelem(f), 1, " \t\r");		if(nf != 4 || strcmp(f[0], "part") != 0)			goto Error; 		a = strtoll(f[2], 0, 0);		b = strtoll(f[3], 0, 0);		if(a >= b)			goto Error; 		if(err = addpart(edit, mkpart(f[1], a, b, 0))) {			fprint(2, "?%s: not continuing\n", err);			exits("partition");		}	}} static vlongmin(vlong a, vlong b){	if(a < b)		return a;	return b;} static voidautopart(Edit *edit){	vlong fat, fs, swap, secs, secsize, cache, nvram;	char *err; 	if(edit->npart > 0) {		if(doauto)			fprint(2, "partitions already exist; not repartitioning\n");		return;	} 	if(doauto == 0)		fprint(2, "initializing default plan9 partition table\n"); 	secs = edit->disk->secs;	secsize = edit->disk->secsize; 	fat = min(secs/10, (10*1024*1024)/secsize)+2;	swap = min(secs/5, memsize()/secsize);	fs = secs - fat - swap;	if(docache) {		cache = fs/2;		fs -= cache;	} else		cache = 0;	if(donvram) {		nvram = 1;		fs -= nvram;	} else		nvram = 0; 	if(err = addpart(edit, mkpart("9fat", 0, fat, 1)))		fprint(2, "autopart: %s\n", err);	if(err = addpart(edit, mkpart("fs", fat, fat+fs, 1)))		fprint(2, "autopart: %s\n", err);	if(cache && (err = addpart(edit, mkpart("cache", fat+fs, fat+fs+cache, 1))))		fprint(2, "autopart: %s\n", err);	if(nvram && (err = addpart(edit, mkpart("nvram", fat+fs+cache, fat+fs+cache+nvram, 1))))		fprint(2, "autopart: %s\n", err);	if(err = addpart(edit, mkpart("swap", fat+fs+cache+nvram, fat+fs+cache+nvram+swap, 1)))		fprint(2, "autopart: %s\n", err);} static voidrestore(Edit *edit, int ctlfd){	int i;	vlong offset; 	offset = edit->disk->offset;	fprint(2, "attempting to restore partitions to previous state\n");	if(seek(edit->disk->wfd, edit->disk->secsize, 0) != 0){		fprint(2, "cannot restore: error seeking on disk\n");		exits("inconsistent");	} 	if(write(edit->disk->wfd, osecbuf, edit->disk->secsize) != edit->disk->secsize){		fprint(2, "cannot restore: couldn't write old partition table to disk\n");		exits("inconsistent");	} 	if(ctlfd >= 0){		for(i=0; i<edit->npart; i++)			fprint(ctlfd, "delpart %s", edit->part[i]->name);		for(i=0; i<nopart; i++){			if(fprint(ctlfd, "part %s %lld %lld", opart[i]->name, opart[i]->start+offset, opart[i]->end+offset) < 0){				fprint(2, "restored disk partition table but not kernel; reboot\n");				exits("inconsistent");			}		}	}	exits("restored");} static voidwrpart(Edit *edit){	int i, n;	Disk *disk; 	disk = edit->disk; 	memset(secbuf, 0, disk->secsize);	n = 0;	for(i=0; i<edit->npart; i++)		n += snprint(secbuf+n, disk->secsize-n, "part %s %lld %lld\n", 			edit->part[i]->name, edit->part[i]->start, edit->part[i]->end); 	if(seek(disk->wfd, disk->secsize, 0) != disk->secsize){		fprint(2, "error seeking %d %lld on disk: %r\n", disk->wfd, disk->secsize);		exits("seek");	} 	if(write(disk->wfd, secbuf, disk->secsize) != disk->secsize){		fprint(2, "error writing partition table to disk\n");		restore(edit, -1);	} 	if(ctldiff(edit, disk->ctlfd) < 0)		fprint(2, "?warning: partitions could not be updated in devsd\n");} /* * Look for a boot sector in sector 1, as would be * the case if editing /dev/sdC0/data when that * was really a bootable disk. */static voidcheckfat(Disk *disk){	uchar buf[32]; 	if(seek(disk->fd, disk->secsize, 0) < 0	|| read(disk->fd, buf, sizeof(buf)) < sizeof(buf))		return; 	if(buf[0] != 0xEB || buf[1] != 0x3C || buf[2] != 0x90)		return; 	fprint(2, 		"there's a fat partition where the\n"		"plan9 partition table would go.\n"		"if you really want to overwrite it, zero\n"		"the second sector of the disk and try again\n"); 	exits("fat partition");}