560 lines · 9.9 KB · C
RawDownload
/*  * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ /* * disk partition editor */#include <u.h>#include <libc.h>#include <bio.h>#include <ctype.h>#include <disk.h>#include "edit.h" char*getline(Edit *edit){	static int inited;	static Biobuf bin;	char *p;	int n; 	if(!inited){		Binit(&bin, 0, OREAD);		inited = 1;	}	p = Brdline(&bin, '\n');	n = Blinelen(&bin);	if(p == nil || n < 1){		if(edit->changed)			fprint(2, "?warning: changes not written\n");		exits(0);	}	p[n - 1] = '\0';	while(isspace(*p))		p++;	return p;} Part*findpart(Edit *edit, char *name){	int i; 	for(i=0; i<edit->npart; i++)		if(strcmp(edit->part[i]->name, name) == 0)			return edit->part[i];	return nil;} static char*okname(Edit *edit, char *name){	int i;	static char msg[100]; 	if(name[0] == '\0')		return "partition has no name"; //	if(strlen(name) >= NAMELEN)//		return "name too long";//	for(i=0; i<edit->npart; i++) {		if(strcmp(name, edit->part[i]->name) == 0) {			sprint(msg, "already have partition with name \"%s\"", name);			return msg;		}	}	return nil;} char*addpart(Edit *edit, Part *p){	int i;	static char msg[100];	char *err; 	if(err = okname(edit, p->name))		return err; 	for(i=0; i<edit->npart; i++) {		if(p->start < edit->part[i]->end && edit->part[i]->start < p->end) {			sprint(msg, "\"%s\" %lld-%lld overlaps with \"%s\" %lld-%lld",				p->name, p->start, p->end,				edit->part[i]->name, edit->part[i]->start, edit->part[i]->end);		//	return msg;		}	} 	if(edit->npart >= nelem(edit->part))			return "too many partitions"; 	edit->part[i=edit->npart++] = p;	for(; i > 0 && p->start < edit->part[i-1]->start; i--) {		edit->part[i] = edit->part[i-1];		edit->part[i-1] = p;	} 	if(p->changed)		edit->changed = 1;	return nil;} char*delpart(Edit *edit, Part *p){	int i; 	for(i=0; i<edit->npart; i++)		if(edit->part[i] == p)			break;	assert(i < edit->npart);	edit->npart--;	for(; i<edit->npart; i++)		edit->part[i] = edit->part[i+1]; 	edit->changed = 1;	return nil;} static char*editdot(Edit *edit, int argc, char **argv){	char *err;	vlong ndot; 	if(argc == 1) {		print("\t. %lld\n", edit->dot);		return nil;	} 	if(argc > 2)		return "args"; 	if(err = parseexpr(argv[1], edit->dot, edit->end, edit->end, &ndot))		return err; 	edit->dot = ndot;	return nil;} static char*editadd(Edit *edit, int argc, char **argv){	char *name, *err, *q;	static char msg[100];	vlong start, end, maxend;	int i; 	if(argc < 2)		return "args"; 	name = estrdup(argv[1]);	if((err = okname(edit, name)) || (err = edit->okname(edit, name)))		return err; 	if(argc >= 3)		q = argv[2];	else {		fprint(2, "start %s: ", edit->unit);		q = getline(edit);	}	if(err = parseexpr(q, edit->dot, edit->end, edit->end, &start))		return err; 	if(start < 0 || start >= edit->end)		return "start out of range"; 	for(i=0; i < edit->npart; i++) {		if(edit->part[i]->start <= start && start < edit->part[i]->end) {			sprint(msg, "start %s in partition \"%s\"", edit->unit, edit->part[i]->name);			return msg;		}	} 	maxend = edit->end;	for(i=0; i < edit->npart; i++)		if(start < edit->part[i]->start && edit->part[i]->start < maxend)			maxend = edit->part[i]->start; 	if(argc >= 4)		q = argv[3];	else {		fprint(2, "end [%lld..%lld] ", start, maxend);		q = getline(edit);	}	if(err = parseexpr(q, edit->dot, maxend, edit->end, &end))		return err; 	if(start == end)		return "size zero partition"; 	if(end <= start || end > maxend)		return "end out of range"; 	if(argc > 4)		return "args"; 	if(err = edit->add(edit, name, start, end))		return err; 	edit->dot = end;	return nil;} static char*editdel(Edit *edit, int argc, char **argv){	Part *p; 	if(argc != 2)		return "args"; 	if((p = findpart(edit, argv[1])) == nil)		return "no such partition"; 	return edit->del(edit, p);} static char *helptext = 	". [newdot] - display or set value of dot\n"	"a name [start [end]] - add partition\n"	"d name - delete partition\n"	"h - print help message\n"	"p - print partition table\n"	"P - print commands to update sd(3) device\n"	"w - write partition table\n"	"q - quit\n"; static char*edithelp(Edit *edit, int, char**){	print("%s", helptext);	if(edit->help)		return edit->help(edit);	return nil;} static char*editprint(Edit *edit, int argc, char**){	vlong lastend;	int i;	Part **part; 	if(argc != 1)		return "args"; 	lastend = 0;	part = edit->part;	for(i=0; i<edit->npart; i++) {		if(lastend < part[i]->start)			edit->sum(edit, nil, lastend, part[i]->start);		edit->sum(edit, part[i], part[i]->start, part[i]->end);		lastend = part[i]->end;	}	if(lastend < edit->end)		edit->sum(edit, nil, lastend, edit->end);	return nil;} char*editwrite(Edit *edit, int argc, char**){	int i;	char *err; 	if(argc != 1)		return "args"; 	if(edit->disk->rdonly)		return "read only"; 	err = edit->write(edit);	if(err)		return err;	for(i=0; i<edit->npart; i++)		edit->part[i]->changed = 0;	edit->changed = 0;	return nil;} static char*editquit(Edit *edit, int argc, char**){	static int warned; 	if(argc != 1) {		warned = 0;		return "args";	} 	if(edit->changed && (!edit->warned || edit->lastcmd != 'q')) {		edit->warned = 1;		return "changes unwritten";	} 	exits(0);	return nil;	/* not reached */} char*editctlprint(Edit *edit, int argc, char **){	if(argc != 1)		return "args"; 	if(edit->printctl)		edit->printctl(edit, 1);	else		ctldiff(edit, 1);	return nil;} typedef struct Cmd Cmd;struct Cmd {	char c;	char *(*fn)(Edit*, int ,char**);}; Cmd cmds[] = {	'.',	editdot,	'a',	editadd,	'd',	editdel,	'?',	edithelp,	'h',	edithelp,	'P',	editctlprint,	'p',	editprint,	'w',	editwrite,	'q',	editquit,}; voidruncmd(Edit *edit, char *cmd){	char *f[10], *err;	int i, nf; 	while(*cmd && isspace(*cmd))		cmd++; 	nf = tokenize(cmd, f, nelem(f));	if(nf >= 10) {		fprint(2, "?\n");		return;	} 	if(nf < 1)		return;	if(strlen(f[0]) != 1) {		fprint(2, "?\n");		return;	} 	err = nil;	for(i=0; i<nelem(cmds); i++) {		if(cmds[i].c == f[0][0]) {			err = cmds[i].fn(edit, nf, f);			break;		}	}	if(i == nelem(cmds)){		if(edit->ext)			err = edit->ext(edit, nf, f);		else			err = "unknown command";	}	if(err) 		fprint(2, "?%s\n", err);	edit->lastcmd = f[0][0];} static Part*ctlmkpart(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;} static voidrdctlpart(Edit *edit){	int i, nline, nf;	char *line[128];	char buf[4096];	vlong a, b;	char *f[5];	Disk *disk; 	disk = edit->disk;	edit->nctlpart = 0;	seek(disk->ctlfd, 0, 0);	if(readn(disk->ctlfd, buf, sizeof buf) <= 0) {		return;	} 	nline = getfields(buf, line, nelem(line), 1, "\n");	for(i=0; i<nline; i++){		if(strncmp(line[i], "part ", 5) != 0)			continue; 		nf = getfields(line[i], f, nelem(f), 1, " \t\r");		if(nf != 4 || strcmp(f[0], "part") != 0)			break; 		a = strtoll(f[2], 0, 0);		b = strtoll(f[3], 0, 0); 		if(a >= b)			break; 		/* only gather partitions contained in the disk partition we are editing */		if(a < disk->offset ||  disk->offset+disk->secs < b)			continue; 		a -= disk->offset;		b -= disk->offset; 		/* the partition we are editing does not count */		if(strcmp(f[1], disk->part) == 0)			continue; 		if(edit->nctlpart >= nelem(edit->ctlpart)) {			fprint(2, "?too many partitions in ctl file\n");			exits("ctlpart");		}		edit->ctlpart[edit->nctlpart++] = ctlmkpart(f[1], a, b, 0);	}} static vlongctlstart(Part *p){	if(p->ctlstart)		return p->ctlstart;	return p->start;} static vlongctlend(Part *p){	if(p->ctlend)		return p->ctlend;	return p->end;} static intareequiv(Part *p, Part *q){	if(p->ctlname[0]=='\0' || q->ctlname[0]=='\0')		return 0; 	return strcmp(p->ctlname, q->ctlname) == 0			&& ctlstart(p) == ctlstart(q) && ctlend(p) == ctlend(q);} static voidunchange(Edit *edit, Part *p){	int i;	Part *q; 	for(i=0; i<edit->nctlpart; i++) {		q = edit->ctlpart[i];		if(p->start <= q->start && q->end <= p->end) {			q->changed = 0;		}	}assert(p->changed == 0);} intctldiff(Edit *edit, int ctlfd){	int i, j, waserr;	Part *p;	vlong offset; 	rdctlpart(edit); 	/* everything is bogus until we prove otherwise */	for(i=0; i<edit->nctlpart; i++)		edit->ctlpart[i]->changed = 1; 	/*	 * partitions with same info have not changed,	 * and neither have partitions inside them.

Lines 1–500 of 560.