xref: /plan9/sys/src/cmd/disk/prep/edit.c (revision 14cc0f535177405a84c5b73603a98e5db6674719)
17dd7cddfSDavid du Colombier /*
27dd7cddfSDavid du Colombier  * disk partition editor
37dd7cddfSDavid du Colombier  */
47dd7cddfSDavid du Colombier #include <u.h>
57dd7cddfSDavid du Colombier #include <libc.h>
67dd7cddfSDavid du Colombier #include <bio.h>
77dd7cddfSDavid du Colombier #include <ctype.h>
87dd7cddfSDavid du Colombier #include <disk.h>
97dd7cddfSDavid du Colombier #include "edit.h"
107dd7cddfSDavid du Colombier 
117dd7cddfSDavid du Colombier char*
getline(Edit * edit)127dd7cddfSDavid du Colombier getline(Edit *edit)
137dd7cddfSDavid du Colombier {
1480ee5cbfSDavid du Colombier 	static int inited;
1580ee5cbfSDavid du Colombier 	static Biobuf bin;
167dd7cddfSDavid du Colombier 	char *p;
177dd7cddfSDavid du Colombier 	int n;
187dd7cddfSDavid du Colombier 
1980ee5cbfSDavid du Colombier 	if(!inited){
2080ee5cbfSDavid du Colombier 		Binit(&bin, 0, OREAD);
2180ee5cbfSDavid du Colombier 		inited = 1;
2280ee5cbfSDavid du Colombier 	}
2380ee5cbfSDavid du Colombier 	p = Brdline(&bin, '\n');
2480ee5cbfSDavid du Colombier 	n = Blinelen(&bin);
259a747e4fSDavid du Colombier 	if(p == nil || n < 1){
267dd7cddfSDavid du Colombier 		if(edit->changed)
277dd7cddfSDavid du Colombier 			fprint(2, "?warning: changes not written\n");
287dd7cddfSDavid du Colombier 		exits(0);
297dd7cddfSDavid du Colombier 	}
3080ee5cbfSDavid du Colombier 	p[n - 1] = '\0';
317dd7cddfSDavid du Colombier 	while(isspace(*p))
327dd7cddfSDavid du Colombier 		p++;
337dd7cddfSDavid du Colombier 	return p;
347dd7cddfSDavid du Colombier }
357dd7cddfSDavid du Colombier 
367dd7cddfSDavid du Colombier Part*
findpart(Edit * edit,char * name)377dd7cddfSDavid du Colombier findpart(Edit *edit, char *name)
387dd7cddfSDavid du Colombier {
397dd7cddfSDavid du Colombier 	int i;
407dd7cddfSDavid du Colombier 
417dd7cddfSDavid du Colombier 	for(i=0; i<edit->npart; i++)
427dd7cddfSDavid du Colombier 		if(strcmp(edit->part[i]->name, name) == 0)
437dd7cddfSDavid du Colombier 			return edit->part[i];
447dd7cddfSDavid du Colombier 	return nil;
457dd7cddfSDavid du Colombier }
467dd7cddfSDavid du Colombier 
477dd7cddfSDavid du Colombier static char*
okname(Edit * edit,char * name)487dd7cddfSDavid du Colombier okname(Edit *edit, char *name)
497dd7cddfSDavid du Colombier {
507dd7cddfSDavid du Colombier 	int i;
517dd7cddfSDavid du Colombier 	static char msg[100];
527dd7cddfSDavid du Colombier 
537dd7cddfSDavid du Colombier 	if(name[0] == '\0')
547dd7cddfSDavid du Colombier 		return "partition has no name";
557dd7cddfSDavid du Colombier 
569a747e4fSDavid du Colombier //	if(strlen(name) >= NAMELEN)
579a747e4fSDavid du Colombier //		return "name too long";
589a747e4fSDavid du Colombier //
597dd7cddfSDavid du Colombier 	for(i=0; i<edit->npart; i++) {
607dd7cddfSDavid du Colombier 		if(strcmp(name, edit->part[i]->name) == 0) {
617dd7cddfSDavid du Colombier 			sprint(msg, "already have partition with name \"%s\"", name);
627dd7cddfSDavid du Colombier 			return msg;
637dd7cddfSDavid du Colombier 		}
647dd7cddfSDavid du Colombier 	}
657dd7cddfSDavid du Colombier 	return nil;
667dd7cddfSDavid du Colombier }
677dd7cddfSDavid du Colombier 
687dd7cddfSDavid du Colombier char*
addpart(Edit * edit,Part * p)697dd7cddfSDavid du Colombier addpart(Edit *edit, Part *p)
707dd7cddfSDavid du Colombier {
717dd7cddfSDavid du Colombier 	int i;
727dd7cddfSDavid du Colombier 	static char msg[100];
737dd7cddfSDavid du Colombier 	char *err;
747dd7cddfSDavid du Colombier 
757dd7cddfSDavid du Colombier 	if(err = okname(edit, p->name))
767dd7cddfSDavid du Colombier 		return err;
777dd7cddfSDavid du Colombier 
787dd7cddfSDavid du Colombier 	for(i=0; i<edit->npart; i++) {
797dd7cddfSDavid du Colombier 		if(p->start < edit->part[i]->end && edit->part[i]->start < p->end) {
809a747e4fSDavid du Colombier 			sprint(msg, "\"%s\" %lld-%lld overlaps with \"%s\" %lld-%lld",
819a747e4fSDavid du Colombier 				p->name, p->start, p->end,
829a747e4fSDavid du Colombier 				edit->part[i]->name, edit->part[i]->start, edit->part[i]->end);
839a747e4fSDavid du Colombier 		//	return msg;
847dd7cddfSDavid du Colombier 		}
857dd7cddfSDavid du Colombier 	}
867dd7cddfSDavid du Colombier 
877dd7cddfSDavid du Colombier 	if(edit->npart >= nelem(edit->part))
887dd7cddfSDavid du Colombier 		return "too many partitions";
897dd7cddfSDavid du Colombier 
907dd7cddfSDavid du Colombier 	edit->part[i=edit->npart++] = p;
917dd7cddfSDavid du Colombier 	for(; i > 0 && p->start < edit->part[i-1]->start; i--) {
927dd7cddfSDavid du Colombier 		edit->part[i] = edit->part[i-1];
937dd7cddfSDavid du Colombier 		edit->part[i-1] = p;
947dd7cddfSDavid du Colombier 	}
957dd7cddfSDavid du Colombier 
967dd7cddfSDavid du Colombier 	if(p->changed)
977dd7cddfSDavid du Colombier 		edit->changed = 1;
987dd7cddfSDavid du Colombier 	return nil;
997dd7cddfSDavid du Colombier }
1007dd7cddfSDavid du Colombier 
1017dd7cddfSDavid du Colombier char*
delpart(Edit * edit,Part * p)1027dd7cddfSDavid du Colombier delpart(Edit *edit, Part *p)
1037dd7cddfSDavid du Colombier {
1047dd7cddfSDavid du Colombier 	int i;
1057dd7cddfSDavid du Colombier 
1067dd7cddfSDavid du Colombier 	for(i=0; i<edit->npart; i++)
1077dd7cddfSDavid du Colombier 		if(edit->part[i] == p)
1087dd7cddfSDavid du Colombier 			break;
1097dd7cddfSDavid du Colombier 	assert(i < edit->npart);
1107dd7cddfSDavid du Colombier 	edit->npart--;
1117dd7cddfSDavid du Colombier 	for(; i<edit->npart; i++)
1127dd7cddfSDavid du Colombier 		edit->part[i] = edit->part[i+1];
1137dd7cddfSDavid du Colombier 
1147dd7cddfSDavid du Colombier 	edit->changed = 1;
1157dd7cddfSDavid du Colombier 	return nil;
1167dd7cddfSDavid du Colombier }
1177dd7cddfSDavid du Colombier 
1187dd7cddfSDavid du Colombier static char*
editdot(Edit * edit,int argc,char ** argv)1197dd7cddfSDavid du Colombier editdot(Edit *edit, int argc, char **argv)
1207dd7cddfSDavid du Colombier {
1217dd7cddfSDavid du Colombier 	char *err;
1227dd7cddfSDavid du Colombier 	vlong ndot;
1237dd7cddfSDavid du Colombier 
1247dd7cddfSDavid du Colombier 	if(argc == 1) {
1257dd7cddfSDavid du Colombier 		print("\t. %lld\n", edit->dot);
1267dd7cddfSDavid du Colombier 		return nil;
1277dd7cddfSDavid du Colombier 	}
1287dd7cddfSDavid du Colombier 
1297dd7cddfSDavid du Colombier 	if(argc > 2)
1307dd7cddfSDavid du Colombier 		return "args";
1317dd7cddfSDavid du Colombier 
13280ee5cbfSDavid du Colombier 	if(err = parseexpr(argv[1], edit->dot, edit->end, edit->end, &ndot))
1337dd7cddfSDavid du Colombier 		return err;
1347dd7cddfSDavid du Colombier 
1357dd7cddfSDavid du Colombier 	edit->dot = ndot;
1367dd7cddfSDavid du Colombier 	return nil;
1377dd7cddfSDavid du Colombier }
1387dd7cddfSDavid du Colombier 
1397dd7cddfSDavid du Colombier static char*
editadd(Edit * edit,int argc,char ** argv)1407dd7cddfSDavid du Colombier editadd(Edit *edit, int argc, char **argv)
1417dd7cddfSDavid du Colombier {
1427dd7cddfSDavid du Colombier 	char *name, *err, *q;
1437dd7cddfSDavid du Colombier 	static char msg[100];
1447dd7cddfSDavid du Colombier 	vlong start, end, maxend;
1457dd7cddfSDavid du Colombier 	int i;
1467dd7cddfSDavid du Colombier 
1477dd7cddfSDavid du Colombier 	if(argc < 2)
1487dd7cddfSDavid du Colombier 		return "args";
1497dd7cddfSDavid du Colombier 
1507dd7cddfSDavid du Colombier 	name = estrdup(argv[1]);
1517dd7cddfSDavid du Colombier 	if((err = okname(edit, name)) || (err = edit->okname(edit, name)))
1527dd7cddfSDavid du Colombier 		return err;
1537dd7cddfSDavid du Colombier 
1547dd7cddfSDavid du Colombier 	if(argc >= 3)
1557dd7cddfSDavid du Colombier 		q = argv[2];
1567dd7cddfSDavid du Colombier 	else {
15780ee5cbfSDavid du Colombier 		fprint(2, "start %s: ", edit->unit);
1587dd7cddfSDavid du Colombier 		q = getline(edit);
1597dd7cddfSDavid du Colombier 	}
16080ee5cbfSDavid du Colombier 	if(err = parseexpr(q, edit->dot, edit->end, edit->end, &start))
1617dd7cddfSDavid du Colombier 		return err;
1627dd7cddfSDavid du Colombier 
16380ee5cbfSDavid du Colombier 	if(start < 0 || start >= edit->end)
16480ee5cbfSDavid du Colombier 		return "start out of range";
1657dd7cddfSDavid du Colombier 
1667dd7cddfSDavid du Colombier 	for(i=0; i < edit->npart; i++) {
1677dd7cddfSDavid du Colombier 		if(edit->part[i]->start <= start && start < edit->part[i]->end) {
16880ee5cbfSDavid du Colombier 			sprint(msg, "start %s in partition \"%s\"", edit->unit, edit->part[i]->name);
1697dd7cddfSDavid du Colombier 			return msg;
1707dd7cddfSDavid du Colombier 		}
1717dd7cddfSDavid du Colombier 	}
1727dd7cddfSDavid du Colombier 
17380ee5cbfSDavid du Colombier 	maxend = edit->end;
1747dd7cddfSDavid du Colombier 	for(i=0; i < edit->npart; i++)
1757dd7cddfSDavid du Colombier 		if(start < edit->part[i]->start && edit->part[i]->start < maxend)
1767dd7cddfSDavid du Colombier 			maxend = edit->part[i]->start;
1777dd7cddfSDavid du Colombier 
1787dd7cddfSDavid du Colombier 	if(argc >= 4)
1797dd7cddfSDavid du Colombier 		q = argv[3];
1807dd7cddfSDavid du Colombier 	else {
1817dd7cddfSDavid du Colombier 		fprint(2, "end [%lld..%lld] ", start, maxend);
1827dd7cddfSDavid du Colombier 		q = getline(edit);
1837dd7cddfSDavid du Colombier 	}
18480ee5cbfSDavid du Colombier 	if(err = parseexpr(q, edit->dot, maxend, edit->end, &end))
1857dd7cddfSDavid du Colombier 		return err;
1867dd7cddfSDavid du Colombier 
1877dd7cddfSDavid du Colombier 	if(start == end)
1887dd7cddfSDavid du Colombier 		return "size zero partition";
1897dd7cddfSDavid du Colombier 
1907dd7cddfSDavid du Colombier 	if(end <= start || end > maxend)
19180ee5cbfSDavid du Colombier 		return "end out of range";
19280ee5cbfSDavid du Colombier 
19380ee5cbfSDavid du Colombier 	if(argc > 4)
19480ee5cbfSDavid du Colombier 		return "args";
1957dd7cddfSDavid du Colombier 
1967dd7cddfSDavid du Colombier 	if(err = edit->add(edit, name, start, end))
1977dd7cddfSDavid du Colombier 		return err;
1987dd7cddfSDavid du Colombier 
1997dd7cddfSDavid du Colombier 	edit->dot = end;
2007dd7cddfSDavid du Colombier 	return nil;
2017dd7cddfSDavid du Colombier }
2027dd7cddfSDavid du Colombier 
2037dd7cddfSDavid du Colombier static char*
editdel(Edit * edit,int argc,char ** argv)2047dd7cddfSDavid du Colombier editdel(Edit *edit, int argc, char **argv)
2057dd7cddfSDavid du Colombier {
2067dd7cddfSDavid du Colombier 	Part *p;
2077dd7cddfSDavid du Colombier 
2087dd7cddfSDavid du Colombier 	if(argc != 2)
2097dd7cddfSDavid du Colombier 		return "args";
2107dd7cddfSDavid du Colombier 
2117dd7cddfSDavid du Colombier 	if((p = findpart(edit, argv[1])) == nil)
2127dd7cddfSDavid du Colombier 		return "no such partition";
2137dd7cddfSDavid du Colombier 
2147dd7cddfSDavid du Colombier 	return edit->del(edit, p);
2157dd7cddfSDavid du Colombier }
2167dd7cddfSDavid du Colombier 
2177dd7cddfSDavid du Colombier static char *helptext =
2187dd7cddfSDavid du Colombier 	". [newdot] - display or set value of dot\n"
219223a736eSDavid du Colombier 	"a name [start [end]] - add partition\n"
2207dd7cddfSDavid du Colombier 	"d name - delete partition\n"
2217dd7cddfSDavid du Colombier 	"h - print help message\n"
2227dd7cddfSDavid du Colombier 	"p - print partition table\n"
2237dd7cddfSDavid du Colombier 	"P - print commands to update sd(3) device\n"
2247dd7cddfSDavid du Colombier 	"w - write partition table\n"
2257dd7cddfSDavid du Colombier 	"q - quit\n";
2267dd7cddfSDavid du Colombier 
2277dd7cddfSDavid du Colombier static char*
edithelp(Edit * edit,int,char **)2287dd7cddfSDavid du Colombier edithelp(Edit *edit, int, char**)
2297dd7cddfSDavid du Colombier {
2307dd7cddfSDavid du Colombier 	print("%s", helptext);
2317dd7cddfSDavid du Colombier 	if(edit->help)
2327dd7cddfSDavid du Colombier 		return edit->help(edit);
2337dd7cddfSDavid du Colombier 	return nil;
2347dd7cddfSDavid du Colombier }
2357dd7cddfSDavid du Colombier 
2367dd7cddfSDavid du Colombier static char*
editprint(Edit * edit,int argc,char **)2377dd7cddfSDavid du Colombier editprint(Edit *edit, int argc, char**)
2387dd7cddfSDavid du Colombier {
2397dd7cddfSDavid du Colombier 	vlong lastend;
2407dd7cddfSDavid du Colombier 	int i;
2417dd7cddfSDavid du Colombier 	Part **part;
2427dd7cddfSDavid du Colombier 
2437dd7cddfSDavid du Colombier 	if(argc != 1)
2447dd7cddfSDavid du Colombier 		return "args";
2457dd7cddfSDavid du Colombier 
2467dd7cddfSDavid du Colombier 	lastend = 0;
2477dd7cddfSDavid du Colombier 	part = edit->part;
2487dd7cddfSDavid du Colombier 	for(i=0; i<edit->npart; i++) {
2497dd7cddfSDavid du Colombier 		if(lastend < part[i]->start)
2507dd7cddfSDavid du Colombier 			edit->sum(edit, nil, lastend, part[i]->start);
2517dd7cddfSDavid du Colombier 		edit->sum(edit, part[i], part[i]->start, part[i]->end);
2527dd7cddfSDavid du Colombier 		lastend = part[i]->end;
2537dd7cddfSDavid du Colombier 	}
25480ee5cbfSDavid du Colombier 	if(lastend < edit->end)
25580ee5cbfSDavid du Colombier 		edit->sum(edit, nil, lastend, edit->end);
2567dd7cddfSDavid du Colombier 	return nil;
2577dd7cddfSDavid du Colombier }
2587dd7cddfSDavid du Colombier 
2597dd7cddfSDavid du Colombier char*
editwrite(Edit * edit,int argc,char **)2607dd7cddfSDavid du Colombier editwrite(Edit *edit, int argc, char**)
2617dd7cddfSDavid du Colombier {
2627dd7cddfSDavid du Colombier 	int i;
2637dd7cddfSDavid du Colombier 	char *err;
2647dd7cddfSDavid du Colombier 
2657dd7cddfSDavid du Colombier 	if(argc != 1)
2667dd7cddfSDavid du Colombier 		return "args";
2677dd7cddfSDavid du Colombier 
2687dd7cddfSDavid du Colombier 	if(edit->disk->rdonly)
2697dd7cddfSDavid du Colombier 		return "read only";
2707dd7cddfSDavid du Colombier 
2717dd7cddfSDavid du Colombier 	err = edit->write(edit);
2727dd7cddfSDavid du Colombier 	if(err)
2737dd7cddfSDavid du Colombier 		return err;
2747dd7cddfSDavid du Colombier 	for(i=0; i<edit->npart; i++)
2757dd7cddfSDavid du Colombier 		edit->part[i]->changed = 0;
2767dd7cddfSDavid du Colombier 	edit->changed = 0;
2777dd7cddfSDavid du Colombier 	return nil;
2787dd7cddfSDavid du Colombier }
2797dd7cddfSDavid du Colombier 
2807dd7cddfSDavid du Colombier static char*
editquit(Edit * edit,int argc,char **)2817dd7cddfSDavid du Colombier editquit(Edit *edit, int argc, char**)
2827dd7cddfSDavid du Colombier {
2837dd7cddfSDavid du Colombier 	static int warned;
2847dd7cddfSDavid du Colombier 
2857dd7cddfSDavid du Colombier 	if(argc != 1) {
2867dd7cddfSDavid du Colombier 		warned = 0;
2877dd7cddfSDavid du Colombier 		return "args";
2887dd7cddfSDavid du Colombier 	}
2897dd7cddfSDavid du Colombier 
2907dd7cddfSDavid du Colombier 	if(edit->changed && (!edit->warned || edit->lastcmd != 'q')) {
2917dd7cddfSDavid du Colombier 		edit->warned = 1;
2927dd7cddfSDavid du Colombier 		return "changes unwritten";
2937dd7cddfSDavid du Colombier 	}
2947dd7cddfSDavid du Colombier 
2957dd7cddfSDavid du Colombier 	exits(0);
2967dd7cddfSDavid du Colombier 	return nil;	/* not reached */
2977dd7cddfSDavid du Colombier }
2987dd7cddfSDavid du Colombier 
2997dd7cddfSDavid du Colombier char*
editctlprint(Edit * edit,int argc,char **)3007dd7cddfSDavid du Colombier editctlprint(Edit *edit, int argc, char **)
3017dd7cddfSDavid du Colombier {
3027dd7cddfSDavid du Colombier 	if(argc != 1)
3037dd7cddfSDavid du Colombier 		return "args";
3047dd7cddfSDavid du Colombier 
3057dd7cddfSDavid du Colombier 	if(edit->printctl)
3067dd7cddfSDavid du Colombier 		edit->printctl(edit, 1);
3077dd7cddfSDavid du Colombier 	else
3087dd7cddfSDavid du Colombier 		ctldiff(edit, 1);
3097dd7cddfSDavid du Colombier 	return nil;
3107dd7cddfSDavid du Colombier }
3117dd7cddfSDavid du Colombier 
3127dd7cddfSDavid du Colombier typedef struct Cmd Cmd;
3137dd7cddfSDavid du Colombier struct Cmd {
3147dd7cddfSDavid du Colombier 	char c;
3157dd7cddfSDavid du Colombier 	char *(*fn)(Edit*, int ,char**);
3167dd7cddfSDavid du Colombier };
3177dd7cddfSDavid du Colombier 
3187dd7cddfSDavid du Colombier Cmd cmds[] = {
3197dd7cddfSDavid du Colombier 	'.',	editdot,
3207dd7cddfSDavid du Colombier 	'a',	editadd,
3217dd7cddfSDavid du Colombier 	'd',	editdel,
3227dd7cddfSDavid du Colombier 	'?',	edithelp,
3237dd7cddfSDavid du Colombier 	'h',	edithelp,
3247dd7cddfSDavid du Colombier 	'P',	editctlprint,
3257dd7cddfSDavid du Colombier 	'p',	editprint,
3267dd7cddfSDavid du Colombier 	'w',	editwrite,
3277dd7cddfSDavid du Colombier 	'q',	editquit,
3287dd7cddfSDavid du Colombier };
3297dd7cddfSDavid du Colombier 
3307dd7cddfSDavid du Colombier void
runcmd(Edit * edit,char * cmd)3317dd7cddfSDavid du Colombier runcmd(Edit *edit, char *cmd)
3327dd7cddfSDavid du Colombier {
3337dd7cddfSDavid du Colombier 	char *f[10], *err;
3347dd7cddfSDavid du Colombier 	int i, nf;
3357dd7cddfSDavid du Colombier 
3367dd7cddfSDavid du Colombier 	while(*cmd && isspace(*cmd))
3377dd7cddfSDavid du Colombier 		cmd++;
3387dd7cddfSDavid du Colombier 
3397dd7cddfSDavid du Colombier 	nf = tokenize(cmd, f, nelem(f));
3407dd7cddfSDavid du Colombier 	if(nf >= 10) {
3417dd7cddfSDavid du Colombier 		fprint(2, "?\n");
3427dd7cddfSDavid du Colombier 		return;
3437dd7cddfSDavid du Colombier 	}
3447dd7cddfSDavid du Colombier 
3459a747e4fSDavid du Colombier 	if(nf < 1)
3469a747e4fSDavid du Colombier 		return;
3477dd7cddfSDavid du Colombier 	if(strlen(f[0]) != 1) {
3487dd7cddfSDavid du Colombier 		fprint(2, "?\n");
3497dd7cddfSDavid du Colombier 		return;
3507dd7cddfSDavid du Colombier 	}
3517dd7cddfSDavid du Colombier 
3527dd7cddfSDavid du Colombier 	err = nil;
3537dd7cddfSDavid du Colombier 	for(i=0; i<nelem(cmds); i++) {
3547dd7cddfSDavid du Colombier 		if(cmds[i].c == f[0][0]) {
3557dd7cddfSDavid du Colombier 			err = cmds[i].fn(edit, nf, f);
3567dd7cddfSDavid du Colombier 			break;
3577dd7cddfSDavid du Colombier 		}
3587dd7cddfSDavid du Colombier 	}
35980ee5cbfSDavid du Colombier 	if(i == nelem(cmds)){
36080ee5cbfSDavid du Colombier 		if(edit->ext)
3617dd7cddfSDavid du Colombier 			err = edit->ext(edit, nf, f);
36280ee5cbfSDavid du Colombier 		else
36380ee5cbfSDavid du Colombier 			err = "unknown command";
36480ee5cbfSDavid du Colombier 	}
3657dd7cddfSDavid du Colombier 	if(err)
3667dd7cddfSDavid du Colombier 		fprint(2, "?%s\n", err);
3677dd7cddfSDavid du Colombier 	edit->lastcmd = f[0][0];
3687dd7cddfSDavid du Colombier }
3697dd7cddfSDavid du Colombier 
3707dd7cddfSDavid du Colombier static Part*
ctlmkpart(char * name,vlong start,vlong end,int changed)3717dd7cddfSDavid du Colombier ctlmkpart(char *name, vlong start, vlong end, int changed)
3727dd7cddfSDavid du Colombier {
3737dd7cddfSDavid du Colombier 	Part *p;
3747dd7cddfSDavid du Colombier 
3757dd7cddfSDavid du Colombier 	p = emalloc(sizeof(*p));
3769a747e4fSDavid du Colombier 	p->name = estrdup(name);
3779a747e4fSDavid du Colombier 	p->ctlname = estrdup(name);
3787dd7cddfSDavid du Colombier 	p->start = start;
3797dd7cddfSDavid du Colombier 	p->end = end;
3807dd7cddfSDavid du Colombier 	p->changed = changed;
3817dd7cddfSDavid du Colombier 	return p;
3827dd7cddfSDavid du Colombier }
3837dd7cddfSDavid du Colombier 
3847dd7cddfSDavid du Colombier static void
rdctlpart(Edit * edit)3857dd7cddfSDavid du Colombier rdctlpart(Edit *edit)
3867dd7cddfSDavid du Colombier {
3877dd7cddfSDavid du Colombier 	int i, nline, nf;
3887dd7cddfSDavid du Colombier 	char *line[128];
3897dd7cddfSDavid du Colombier 	char buf[4096];
3907dd7cddfSDavid du Colombier 	vlong a, b;
3917dd7cddfSDavid du Colombier 	char *f[5];
3927dd7cddfSDavid du Colombier 	Disk *disk;
3937dd7cddfSDavid du Colombier 
3947dd7cddfSDavid du Colombier 	disk = edit->disk;
3957dd7cddfSDavid du Colombier 	edit->nctlpart = 0;
3967dd7cddfSDavid du Colombier 	seek(disk->ctlfd, 0, 0);
3977dd7cddfSDavid du Colombier 	if(readn(disk->ctlfd, buf, sizeof buf) <= 0) {
3987dd7cddfSDavid du Colombier 		return;
3997dd7cddfSDavid du Colombier 	}
4007dd7cddfSDavid du Colombier 
4017dd7cddfSDavid du Colombier 	nline = getfields(buf, line, nelem(line), 1, "\n");
4027dd7cddfSDavid du Colombier 	for(i=0; i<nline; i++){
4037dd7cddfSDavid du Colombier 		if(strncmp(line[i], "part ", 5) != 0)
4047dd7cddfSDavid du Colombier 			continue;
4057dd7cddfSDavid du Colombier 
4067dd7cddfSDavid du Colombier 		nf = getfields(line[i], f, nelem(f), 1, " \t\r");
4077dd7cddfSDavid du Colombier 		if(nf != 4 || strcmp(f[0], "part") != 0)
4087dd7cddfSDavid du Colombier 			break;
4097dd7cddfSDavid du Colombier 
4107dd7cddfSDavid du Colombier 		a = strtoll(f[2], 0, 0);
4117dd7cddfSDavid du Colombier 		b = strtoll(f[3], 0, 0);
4127dd7cddfSDavid du Colombier 
4137dd7cddfSDavid du Colombier 		if(a >= b)
4147dd7cddfSDavid du Colombier 			break;
4157dd7cddfSDavid du Colombier 
4167dd7cddfSDavid du Colombier 		/* only gather partitions contained in the disk partition we are editing */
4177dd7cddfSDavid du Colombier 		if(a < disk->offset ||  disk->offset+disk->secs < b)
4187dd7cddfSDavid du Colombier 			continue;
4197dd7cddfSDavid du Colombier 
4207dd7cddfSDavid du Colombier 		a -= disk->offset;
4217dd7cddfSDavid du Colombier 		b -= disk->offset;
4227dd7cddfSDavid du Colombier 
4237dd7cddfSDavid du Colombier 		/* the partition we are editing does not count */
4247dd7cddfSDavid du Colombier 		if(strcmp(f[1], disk->part) == 0)
4257dd7cddfSDavid du Colombier 			continue;
4267dd7cddfSDavid du Colombier 
4277dd7cddfSDavid du Colombier 		if(edit->nctlpart >= nelem(edit->ctlpart)) {
4287dd7cddfSDavid du Colombier 			fprint(2, "?too many partitions in ctl file\n");
4297dd7cddfSDavid du Colombier 			exits("ctlpart");
4307dd7cddfSDavid du Colombier 		}
4317dd7cddfSDavid du Colombier 		edit->ctlpart[edit->nctlpart++] = ctlmkpart(f[1], a, b, 0);
4327dd7cddfSDavid du Colombier 	}
4337dd7cddfSDavid du Colombier }
4347dd7cddfSDavid du Colombier 
43580ee5cbfSDavid du Colombier static vlong
ctlstart(Part * p)43680ee5cbfSDavid du Colombier ctlstart(Part *p)
43780ee5cbfSDavid du Colombier {
43880ee5cbfSDavid du Colombier 	if(p->ctlstart)
43980ee5cbfSDavid du Colombier 		return p->ctlstart;
44080ee5cbfSDavid du Colombier 	return p->start;
44180ee5cbfSDavid du Colombier }
44280ee5cbfSDavid du Colombier 
44380ee5cbfSDavid du Colombier static vlong
ctlend(Part * p)44480ee5cbfSDavid du Colombier ctlend(Part *p)
44580ee5cbfSDavid du Colombier {
44680ee5cbfSDavid du Colombier 	if(p->ctlend)
44780ee5cbfSDavid du Colombier 		return p->ctlend;
44880ee5cbfSDavid du Colombier 	return p->end;
44980ee5cbfSDavid du Colombier }
45080ee5cbfSDavid du Colombier 
4517dd7cddfSDavid du Colombier static int
areequiv(Part * p,Part * q)4527dd7cddfSDavid du Colombier areequiv(Part *p, Part *q)
4537dd7cddfSDavid du Colombier {
4549a747e4fSDavid du Colombier 	if(p->ctlname[0]=='\0' || q->ctlname[0]=='\0')
4559a747e4fSDavid du Colombier 		return 0;
4569a747e4fSDavid du Colombier 
4577dd7cddfSDavid du Colombier 	return strcmp(p->ctlname, q->ctlname) == 0
45880ee5cbfSDavid du Colombier 			&& ctlstart(p) == ctlstart(q) && ctlend(p) == ctlend(q);
4597dd7cddfSDavid du Colombier }
4607dd7cddfSDavid du Colombier 
4617dd7cddfSDavid du Colombier static void
unchange(Edit * edit,Part * p)4627dd7cddfSDavid du Colombier unchange(Edit *edit, Part *p)
4637dd7cddfSDavid du Colombier {
4647dd7cddfSDavid du Colombier 	int i;
4657dd7cddfSDavid du Colombier 	Part *q;
4667dd7cddfSDavid du Colombier 
4677dd7cddfSDavid du Colombier 	for(i=0; i<edit->nctlpart; i++) {
4687dd7cddfSDavid du Colombier 		q = edit->ctlpart[i];
4697dd7cddfSDavid du Colombier 		if(p->start <= q->start && q->end <= p->end) {
4707dd7cddfSDavid du Colombier 			q->changed = 0;
4717dd7cddfSDavid du Colombier 		}
4727dd7cddfSDavid du Colombier 	}
4737dd7cddfSDavid du Colombier assert(p->changed == 0);
4747dd7cddfSDavid du Colombier }
4757dd7cddfSDavid du Colombier 
4767dd7cddfSDavid du Colombier int
ctldiff(Edit * edit,int ctlfd)4777dd7cddfSDavid du Colombier ctldiff(Edit *edit, int ctlfd)
4787dd7cddfSDavid du Colombier {
4797dd7cddfSDavid du Colombier 	int i, j, waserr;
4807dd7cddfSDavid du Colombier 	Part *p;
4817dd7cddfSDavid du Colombier 	vlong offset;
4827dd7cddfSDavid du Colombier 
4837dd7cddfSDavid du Colombier 	rdctlpart(edit);
4847dd7cddfSDavid du Colombier 
4857dd7cddfSDavid du Colombier 	/* everything is bogus until we prove otherwise */
4867dd7cddfSDavid du Colombier 	for(i=0; i<edit->nctlpart; i++)
4877dd7cddfSDavid du Colombier 		edit->ctlpart[i]->changed = 1;
4887dd7cddfSDavid du Colombier 
4897dd7cddfSDavid du Colombier 	/*
4907dd7cddfSDavid du Colombier 	 * partitions with same info have not changed,
4917dd7cddfSDavid du Colombier 	 * and neither have partitions inside them.
4927dd7cddfSDavid du Colombier 	 */
4937dd7cddfSDavid du Colombier 	for(i=0; i<edit->nctlpart; i++)
4947dd7cddfSDavid du Colombier 		for(j=0; j<edit->npart; j++)
4957dd7cddfSDavid du Colombier 			if(areequiv(edit->ctlpart[i], edit->part[j])) {
4967dd7cddfSDavid du Colombier 				unchange(edit, edit->ctlpart[i]);
4977dd7cddfSDavid du Colombier 				break;
4987dd7cddfSDavid du Colombier 			}
4997dd7cddfSDavid du Colombier 
50080ee5cbfSDavid du Colombier 	waserr = 0;
5017dd7cddfSDavid du Colombier 	/*
5027dd7cddfSDavid du Colombier 	 * delete all the changed partitions except data (we'll add them back if necessary)
5037dd7cddfSDavid du Colombier 	 */
5047dd7cddfSDavid du Colombier 	for(i=0; i<edit->nctlpart; i++) {
5057dd7cddfSDavid du Colombier 		p = edit->ctlpart[i];
5067dd7cddfSDavid du Colombier 		if(p->changed)
50780ee5cbfSDavid du Colombier 		if(fprint(ctlfd, "delpart %s\n", p->ctlname)<0) {
50880ee5cbfSDavid du Colombier 			fprint(2, "delpart failed: %s: %r\n", p->ctlname);
50980ee5cbfSDavid du Colombier 			waserr = -1;
51080ee5cbfSDavid du Colombier 		}
5117dd7cddfSDavid du Colombier 	}
5127dd7cddfSDavid du Colombier 
5137dd7cddfSDavid du Colombier 	/*
5147dd7cddfSDavid du Colombier 	 * add all the partitions from the real list;
5157dd7cddfSDavid du Colombier 	 * this is okay since adding a parition with
5167dd7cddfSDavid du Colombier 	 * information identical to what is there is a no-op.
5177dd7cddfSDavid du Colombier 	 */
5187dd7cddfSDavid du Colombier 	offset = edit->disk->offset;
5197dd7cddfSDavid du Colombier 	for(i=0; i<edit->npart; i++) {
5207dd7cddfSDavid du Colombier 		p = edit->part[i];
52180ee5cbfSDavid du Colombier 		if(p->ctlname[0]) {
52280ee5cbfSDavid du Colombier 			if(fprint(ctlfd, "part %s %lld %lld\n", p->ctlname, offset+ctlstart(p), offset+ctlend(p)) < 0) {
52380ee5cbfSDavid du Colombier 				fprint(2, "adding part failed: %s: %r\n", p->ctlname);
5247dd7cddfSDavid du Colombier 				waserr = -1;
5257dd7cddfSDavid du Colombier 			}
52680ee5cbfSDavid du Colombier 		}
52780ee5cbfSDavid du Colombier 	}
5287dd7cddfSDavid du Colombier 	return waserr;
5297dd7cddfSDavid du Colombier }
53059cc4ca5SDavid du Colombier 
53159cc4ca5SDavid du Colombier void*
emalloc(ulong sz)53259cc4ca5SDavid du Colombier emalloc(ulong sz)
53359cc4ca5SDavid du Colombier {
53459cc4ca5SDavid du Colombier 	void *v;
53559cc4ca5SDavid du Colombier 
53659cc4ca5SDavid du Colombier 	v = malloc(sz);
53759cc4ca5SDavid du Colombier 	if(v == nil)
538*14cc0f53SDavid du Colombier 		sysfatal("malloc %lud fails", sz);
53959cc4ca5SDavid du Colombier 	memset(v, 0, sz);
54059cc4ca5SDavid du Colombier 	return v;
54159cc4ca5SDavid du Colombier }
54259cc4ca5SDavid du Colombier 
54359cc4ca5SDavid du Colombier char*
estrdup(char * s)54459cc4ca5SDavid du Colombier estrdup(char *s)
54559cc4ca5SDavid du Colombier {
54659cc4ca5SDavid du Colombier 	s = strdup(s);
54759cc4ca5SDavid du Colombier 	if(s == nil)
548*14cc0f53SDavid du Colombier 		sysfatal("strdup (%.10s) fails", s);
54959cc4ca5SDavid du Colombier 	return s;
55059cc4ca5SDavid du Colombier }
55159cc4ca5SDavid du Colombier 
552