xref: /plan9/sys/src/libdisk/proto.c (revision b7b24591a7db843bfad3c8422d030e105c7ea168)
17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <bio.h>
47dd7cddfSDavid du Colombier #include <auth.h>
57dd7cddfSDavid du Colombier #include <fcall.h>
67dd7cddfSDavid du Colombier #include <disk.h>
77dd7cddfSDavid du Colombier 
87dd7cddfSDavid du Colombier enum {
97dd7cddfSDavid du Colombier 	LEN	= 8*1024,
107dd7cddfSDavid du Colombier 	HUNKS	= 128,
117dd7cddfSDavid du Colombier };
127dd7cddfSDavid du Colombier 
137dd7cddfSDavid du Colombier typedef struct File File;
147dd7cddfSDavid du Colombier struct File{
157dd7cddfSDavid du Colombier 	char	*new;
167dd7cddfSDavid du Colombier 	char	*elem;
177dd7cddfSDavid du Colombier 	char	*old;
189a747e4fSDavid du Colombier 	char	*uid;
199a747e4fSDavid du Colombier 	char	*gid;
207dd7cddfSDavid du Colombier 	ulong	mode;
217dd7cddfSDavid du Colombier };
227dd7cddfSDavid du Colombier 
237dd7cddfSDavid du Colombier typedef void Mkfserr(char*, void*);
247dd7cddfSDavid du Colombier typedef void Mkfsenum(char*, char*, Dir*, void*);
257dd7cddfSDavid du Colombier 
267dd7cddfSDavid du Colombier typedef struct Name Name;
277dd7cddfSDavid du Colombier struct Name {
287dd7cddfSDavid du Colombier 	int n;
297dd7cddfSDavid du Colombier 	char *s;
307dd7cddfSDavid du Colombier };
317dd7cddfSDavid du Colombier 
327dd7cddfSDavid du Colombier typedef struct Mkaux Mkaux;
337dd7cddfSDavid du Colombier struct Mkaux {
347dd7cddfSDavid du Colombier 	Mkfserr *warn;
357dd7cddfSDavid du Colombier 	Mkfsenum *mkenum;
367dd7cddfSDavid du Colombier 	char *root;
377dd7cddfSDavid du Colombier 	char *proto;
387dd7cddfSDavid du Colombier 	jmp_buf jmp;
397dd7cddfSDavid du Colombier 	Biobuf *b;
407dd7cddfSDavid du Colombier 
417dd7cddfSDavid du Colombier 	Name oldfile;
427dd7cddfSDavid du Colombier 	Name fullname;
437dd7cddfSDavid du Colombier 	int	lineno;
447dd7cddfSDavid du Colombier 	int	indent;
457dd7cddfSDavid du Colombier 
467dd7cddfSDavid du Colombier 	void *a;
477dd7cddfSDavid du Colombier };
487dd7cddfSDavid du Colombier 
497dd7cddfSDavid du Colombier static void domkfs(Mkaux *mkaux, File *me, int level);
507dd7cddfSDavid du Colombier 
517dd7cddfSDavid du Colombier static int	copyfile(Mkaux*, File*, Dir*, int);
527dd7cddfSDavid du Colombier static void	freefile(File*);
537dd7cddfSDavid du Colombier static File*	getfile(Mkaux*, File*);
547dd7cddfSDavid du Colombier static char*	getmode(Mkaux*, char*, ulong*);
559a747e4fSDavid du Colombier static char*	getname(Mkaux*, char*, char**);
5659cc4ca5SDavid du Colombier static char*	getpath(Mkaux*, char*);
577dd7cddfSDavid du Colombier static int	mkfile(Mkaux*, File*);
5859cc4ca5SDavid du Colombier static char*	mkpath(Mkaux*, char*, char*);
597dd7cddfSDavid du Colombier static void	mktree(Mkaux*, File*, int);
607dd7cddfSDavid du Colombier static void	setnames(Mkaux*, File*);
617dd7cddfSDavid du Colombier static void	skipdir(Mkaux*);
627dd7cddfSDavid du Colombier static void	warn(Mkaux*, char *, ...);
637dd7cddfSDavid du Colombier 
647dd7cddfSDavid du Colombier //static void
657dd7cddfSDavid du Colombier //mprint(char *new, char *old, Dir *d, void*)
667dd7cddfSDavid du Colombier //{
677dd7cddfSDavid du Colombier //	print("%s %s %D\n", new, old, d);
687dd7cddfSDavid du Colombier //}
697dd7cddfSDavid du Colombier 
707dd7cddfSDavid du Colombier int
rdproto(char * proto,char * root,Mkfsenum * mkenum,Mkfserr * mkerr,void * a)717dd7cddfSDavid du Colombier rdproto(char *proto, char *root, Mkfsenum *mkenum, Mkfserr *mkerr, void *a)
727dd7cddfSDavid du Colombier {
737dd7cddfSDavid du Colombier 	Mkaux mx, *m;
747dd7cddfSDavid du Colombier 	File file;
7559cc4ca5SDavid du Colombier 	int rv;
767dd7cddfSDavid du Colombier 
777dd7cddfSDavid du Colombier 	m = &mx;
787dd7cddfSDavid du Colombier 	memset(&mx, 0, sizeof mx);
797dd7cddfSDavid du Colombier 	if(root == nil)
807dd7cddfSDavid du Colombier 		root = "/";
817dd7cddfSDavid du Colombier 
827dd7cddfSDavid du Colombier 	m->root = root;
837dd7cddfSDavid du Colombier 	m->warn = mkerr;
847dd7cddfSDavid du Colombier 	m->mkenum = mkenum;
857dd7cddfSDavid du Colombier 	m->a = a;
867dd7cddfSDavid du Colombier 	m->proto = proto;
877dd7cddfSDavid du Colombier 	m->lineno = 0;
887dd7cddfSDavid du Colombier 	m->indent = 0;
897dd7cddfSDavid du Colombier 	if((m->b = Bopen(proto, OREAD)) == nil) {
907dd7cddfSDavid du Colombier 		werrstr("open '%s': %r", proto);
917dd7cddfSDavid du Colombier 		return -1;
927dd7cddfSDavid du Colombier 	}
937dd7cddfSDavid du Colombier 
947dd7cddfSDavid du Colombier 	memset(&file, 0, sizeof file);
957dd7cddfSDavid du Colombier 	file.new = "";
967dd7cddfSDavid du Colombier 	file.old = nil;
9759cc4ca5SDavid du Colombier 
9859cc4ca5SDavid du Colombier 	rv = 0;
9959cc4ca5SDavid du Colombier 	if(setjmp(m->jmp) == 0)
1007dd7cddfSDavid du Colombier 		domkfs(m, &file, -1);
10159cc4ca5SDavid du Colombier 	else
10259cc4ca5SDavid du Colombier 		rv = -1;
1037dd7cddfSDavid du Colombier 	free(m->oldfile.s);
1047dd7cddfSDavid du Colombier 	free(m->fullname.s);
10559cc4ca5SDavid du Colombier 	return rv;
10659cc4ca5SDavid du Colombier }
10759cc4ca5SDavid du Colombier 
10859cc4ca5SDavid du Colombier static void*
emalloc(Mkaux * mkaux,ulong n)10959cc4ca5SDavid du Colombier emalloc(Mkaux *mkaux, ulong n)
11059cc4ca5SDavid du Colombier {
11159cc4ca5SDavid du Colombier 	void *v;
11259cc4ca5SDavid du Colombier 
11359cc4ca5SDavid du Colombier 	v = malloc(n);
11459cc4ca5SDavid du Colombier 	if(v == nil)
11559cc4ca5SDavid du Colombier 		longjmp(mkaux->jmp, 1);	/* memory leak */
11659cc4ca5SDavid du Colombier 	memset(v, 0, n);
11759cc4ca5SDavid du Colombier 	return v;
11859cc4ca5SDavid du Colombier }
11959cc4ca5SDavid du Colombier 
12059cc4ca5SDavid du Colombier static char*
estrdup(Mkaux * mkaux,char * s)12159cc4ca5SDavid du Colombier estrdup(Mkaux *mkaux, char *s)
12259cc4ca5SDavid du Colombier {
12359cc4ca5SDavid du Colombier 	s = strdup(s);
12459cc4ca5SDavid du Colombier 	if(s == nil)
12559cc4ca5SDavid du Colombier 		longjmp(mkaux->jmp, 1);	/* memory leak */
12659cc4ca5SDavid du Colombier 	return s;
1277dd7cddfSDavid du Colombier }
1287dd7cddfSDavid du Colombier 
1297dd7cddfSDavid du Colombier static void
domkfs(Mkaux * mkaux,File * me,int level)1307dd7cddfSDavid du Colombier domkfs(Mkaux *mkaux, File *me, int level)
1317dd7cddfSDavid du Colombier {
1327dd7cddfSDavid du Colombier 	File *child;
1337dd7cddfSDavid du Colombier 	int rec;
1347dd7cddfSDavid du Colombier 
1357dd7cddfSDavid du Colombier 	child = getfile(mkaux, me);
1367dd7cddfSDavid du Colombier 	if(!child)
1377dd7cddfSDavid du Colombier 		return;
1387dd7cddfSDavid du Colombier 	if((child->elem[0] == '+' || child->elem[0] == '*') && child->elem[1] == '\0'){
1397dd7cddfSDavid du Colombier 		rec = child->elem[0] == '+';
1407dd7cddfSDavid du Colombier 		free(child->new);
14159cc4ca5SDavid du Colombier 		child->new = estrdup(mkaux, me->new);
1427dd7cddfSDavid du Colombier 		setnames(mkaux, child);
1437dd7cddfSDavid du Colombier 		mktree(mkaux, child, rec);
1447dd7cddfSDavid du Colombier 		freefile(child);
1457dd7cddfSDavid du Colombier 		child = getfile(mkaux, me);
1467dd7cddfSDavid du Colombier 	}
1477dd7cddfSDavid du Colombier 	while(child && mkaux->indent > level){
1487dd7cddfSDavid du Colombier 		if(mkfile(mkaux, child))
1497dd7cddfSDavid du Colombier 			domkfs(mkaux, child, mkaux->indent);
1507dd7cddfSDavid du Colombier 		freefile(child);
1517dd7cddfSDavid du Colombier 		child = getfile(mkaux, me);
1527dd7cddfSDavid du Colombier 	}
1537dd7cddfSDavid du Colombier 	if(child){
1547dd7cddfSDavid du Colombier 		freefile(child);
1557dd7cddfSDavid du Colombier 		Bseek(mkaux->b, -Blinelen(mkaux->b), 1);
1567dd7cddfSDavid du Colombier 		mkaux->lineno--;
1577dd7cddfSDavid du Colombier 	}
1587dd7cddfSDavid du Colombier }
1597dd7cddfSDavid du Colombier 
1607dd7cddfSDavid du Colombier static void
mktree(Mkaux * mkaux,File * me,int rec)1617dd7cddfSDavid du Colombier mktree(Mkaux *mkaux, File *me, int rec)
1627dd7cddfSDavid du Colombier {
1637dd7cddfSDavid du Colombier 	File child;
1649a747e4fSDavid du Colombier 	Dir *d;
1657dd7cddfSDavid du Colombier 	int i, n, fd;
1667dd7cddfSDavid du Colombier 
1677dd7cddfSDavid du Colombier 	fd = open(mkaux->oldfile.s, OREAD);
1687dd7cddfSDavid du Colombier 	if(fd < 0){
1697dd7cddfSDavid du Colombier 		warn(mkaux, "can't open %s: %r", mkaux->oldfile.s);
1707dd7cddfSDavid du Colombier 		return;
1717dd7cddfSDavid du Colombier 	}
1727dd7cddfSDavid du Colombier 
1737dd7cddfSDavid du Colombier 	child = *me;
1749a747e4fSDavid du Colombier 	while((n = dirread(fd, &d)) > 0){
1757dd7cddfSDavid du Colombier 		for(i = 0; i < n; i++){
17659cc4ca5SDavid du Colombier 			child.new = mkpath(mkaux, me->new, d[i].name);
1777dd7cddfSDavid du Colombier 			if(me->old)
17859cc4ca5SDavid du Colombier 				child.old = mkpath(mkaux, me->old, d[i].name);
1797dd7cddfSDavid du Colombier 			child.elem = d[i].name;
1807dd7cddfSDavid du Colombier 			setnames(mkaux, &child);
1819a747e4fSDavid du Colombier 			if((!(d[i].mode&DMDIR) || rec) && copyfile(mkaux, &child, &d[i], 1) && rec)
1827dd7cddfSDavid du Colombier 				mktree(mkaux, &child, rec);
1837dd7cddfSDavid du Colombier 			free(child.new);
1847dd7cddfSDavid du Colombier 			if(child.old)
1857dd7cddfSDavid du Colombier 				free(child.old);
1867dd7cddfSDavid du Colombier 		}
1877dd7cddfSDavid du Colombier 	}
1887dd7cddfSDavid du Colombier 	close(fd);
1897dd7cddfSDavid du Colombier }
1907dd7cddfSDavid du Colombier 
1917dd7cddfSDavid du Colombier static int
mkfile(Mkaux * mkaux,File * f)1927dd7cddfSDavid du Colombier mkfile(Mkaux *mkaux, File *f)
1937dd7cddfSDavid du Colombier {
1949a747e4fSDavid du Colombier 	Dir *d;
1957dd7cddfSDavid du Colombier 
1969a747e4fSDavid du Colombier 	if((d = dirstat(mkaux->oldfile.s)) == nil){
1977dd7cddfSDavid du Colombier 		warn(mkaux, "can't stat file %s: %r", mkaux->oldfile.s);
1987dd7cddfSDavid du Colombier 		skipdir(mkaux);
1997dd7cddfSDavid du Colombier 		return 0;
2007dd7cddfSDavid du Colombier 	}
2019a747e4fSDavid du Colombier 	return copyfile(mkaux, f, d, 0);
2027dd7cddfSDavid du Colombier }
2037dd7cddfSDavid du Colombier 
2047dd7cddfSDavid du Colombier enum {
2057dd7cddfSDavid du Colombier 	SLOP = 30
2067dd7cddfSDavid du Colombier };
2077dd7cddfSDavid du Colombier 
2087dd7cddfSDavid du Colombier static void
setname(Mkaux * mkaux,Name * name,char * s1,char * s2)20959cc4ca5SDavid du Colombier setname(Mkaux *mkaux, Name *name, char *s1, char *s2)
2107dd7cddfSDavid du Colombier {
2117dd7cddfSDavid du Colombier 	int l;
2127dd7cddfSDavid du Colombier 
2137dd7cddfSDavid du Colombier 	l = strlen(s1)+strlen(s2)+1;
214*b7b24591SDavid du Colombier 	if(name->n < l+SLOP/2) {
2157dd7cddfSDavid du Colombier 		free(name->s);
21659cc4ca5SDavid du Colombier 		name->s = emalloc(mkaux, l+SLOP);
2177dd7cddfSDavid du Colombier 		name->n = l+SLOP;
2187dd7cddfSDavid du Colombier 	}
2199a747e4fSDavid du Colombier 	snprint(name->s, name->n, "%s%s%s", s1, s1[0]==0 || s1[strlen(s1)-1]!='/' ? "/" : "", s2);
2207dd7cddfSDavid du Colombier }
2217dd7cddfSDavid du Colombier 
2227dd7cddfSDavid du Colombier static int
copyfile(Mkaux * mkaux,File * f,Dir * d,int permonly)2237dd7cddfSDavid du Colombier copyfile(Mkaux *mkaux, File *f, Dir *d, int permonly)
2247dd7cddfSDavid du Colombier {
2259a747e4fSDavid du Colombier 	Dir *nd;
2267dd7cddfSDavid du Colombier 	ulong xmode;
2277dd7cddfSDavid du Colombier 	char *p;
2287dd7cddfSDavid du Colombier 
22980ee5cbfSDavid du Colombier 	setname(mkaux, &mkaux->fullname, mkaux->root, f->old ? f->old : f->new);
23080ee5cbfSDavid du Colombier 	/*
23180ee5cbfSDavid du Colombier 	 * Extra stat here is inefficient but accounts for binds.
23280ee5cbfSDavid du Colombier 	 */
2339a747e4fSDavid du Colombier 	if((nd = dirstat(mkaux->fullname.s)) != nil)
2349a747e4fSDavid du Colombier 		d = nd;
2359a747e4fSDavid du Colombier 
2369a747e4fSDavid du Colombier 	d->name = f->elem;
2377dd7cddfSDavid du Colombier 	if(d->type != 'M'){
2389a747e4fSDavid du Colombier 		d->uid = "sys";
2399a747e4fSDavid du Colombier 		d->gid = "sys";
2407dd7cddfSDavid du Colombier 		xmode = (d->mode >> 6) & 7;
2417dd7cddfSDavid du Colombier 		d->mode |= xmode | (xmode << 3);
2427dd7cddfSDavid du Colombier 	}
2437dd7cddfSDavid du Colombier 	if(strcmp(f->uid, "-") != 0)
2449a747e4fSDavid du Colombier 		d->uid = f->uid;
2457dd7cddfSDavid du Colombier 	if(strcmp(f->gid, "-") != 0)
2469a747e4fSDavid du Colombier 		d->gid = f->gid;
2477dd7cddfSDavid du Colombier 	if(f->mode != ~0){
2487dd7cddfSDavid du Colombier 		if(permonly)
2497dd7cddfSDavid du Colombier 			d->mode = (d->mode & ~0666) | (f->mode & 0666);
2509a747e4fSDavid du Colombier 		else if((d->mode&DMDIR) != (f->mode&DMDIR))
2517dd7cddfSDavid du Colombier 			warn(mkaux, "inconsistent mode for %s", f->new);
2527dd7cddfSDavid du Colombier 		else
2537dd7cddfSDavid du Colombier 			d->mode = f->mode;
2547dd7cddfSDavid du Colombier 	}
2557dd7cddfSDavid du Colombier 
2567dd7cddfSDavid du Colombier 	if(p = strrchr(f->new, '/'))
2579a747e4fSDavid du Colombier 		d->name = p+1;
2587dd7cddfSDavid du Colombier 	else
2599a747e4fSDavid du Colombier 		d->name = f->new;
2607dd7cddfSDavid du Colombier 
2617dd7cddfSDavid du Colombier 	mkaux->mkenum(f->new, mkaux->fullname.s, d, mkaux->a);
2629a747e4fSDavid du Colombier 	xmode = d->mode;
2639a747e4fSDavid du Colombier 	free(nd);
2649a747e4fSDavid du Colombier 	return (xmode&DMDIR) != 0;
2657dd7cddfSDavid du Colombier }
2667dd7cddfSDavid du Colombier 
2677dd7cddfSDavid du Colombier static char *
mkpath(Mkaux * mkaux,char * prefix,char * elem)26859cc4ca5SDavid du Colombier mkpath(Mkaux *mkaux, char *prefix, char *elem)
2697dd7cddfSDavid du Colombier {
2707dd7cddfSDavid du Colombier 	char *p;
2717dd7cddfSDavid du Colombier 	int n;
2727dd7cddfSDavid du Colombier 
2737dd7cddfSDavid du Colombier 	n = strlen(prefix) + strlen(elem) + 2;
27459cc4ca5SDavid du Colombier 	p = emalloc(mkaux, n);
27580ee5cbfSDavid du Colombier 	strcpy(p, prefix);
27680ee5cbfSDavid du Colombier 	strcat(p, "/");
27780ee5cbfSDavid du Colombier 	strcat(p, elem);
2787dd7cddfSDavid du Colombier 	return p;
2797dd7cddfSDavid du Colombier }
2807dd7cddfSDavid du Colombier 
2817dd7cddfSDavid du Colombier static void
setnames(Mkaux * mkaux,File * f)2827dd7cddfSDavid du Colombier setnames(Mkaux *mkaux, File *f)
2837dd7cddfSDavid du Colombier {
2847dd7cddfSDavid du Colombier 
2857dd7cddfSDavid du Colombier 	if(f->old){
2867dd7cddfSDavid du Colombier 		if(f->old[0] == '/')
28759cc4ca5SDavid du Colombier 			setname(mkaux, &mkaux->oldfile, f->old, "");
2889a747e4fSDavid du Colombier 		else
2899a747e4fSDavid du Colombier 			setname(mkaux, &mkaux->oldfile, mkaux->root, f->old);
2907dd7cddfSDavid du Colombier 	} else
29159cc4ca5SDavid du Colombier 		setname(mkaux, &mkaux->oldfile, mkaux->root, f->new);
2927dd7cddfSDavid du Colombier }
2937dd7cddfSDavid du Colombier 
2947dd7cddfSDavid du Colombier static void
freefile(File * f)2957dd7cddfSDavid du Colombier freefile(File *f)
2967dd7cddfSDavid du Colombier {
2977dd7cddfSDavid du Colombier 	if(f->old)
2987dd7cddfSDavid du Colombier 		free(f->old);
2997dd7cddfSDavid du Colombier 	if(f->new)
3007dd7cddfSDavid du Colombier 		free(f->new);
3017dd7cddfSDavid du Colombier 	free(f);
3027dd7cddfSDavid du Colombier }
3037dd7cddfSDavid du Colombier 
3047dd7cddfSDavid du Colombier /*
3057dd7cddfSDavid du Colombier  * skip all files in the proto that
3067dd7cddfSDavid du Colombier  * could be in the current dir
3077dd7cddfSDavid du Colombier  */
3087dd7cddfSDavid du Colombier static void
skipdir(Mkaux * mkaux)3097dd7cddfSDavid du Colombier skipdir(Mkaux *mkaux)
3107dd7cddfSDavid du Colombier {
3117dd7cddfSDavid du Colombier 	char *p, c;
3127dd7cddfSDavid du Colombier 	int level;
3137dd7cddfSDavid du Colombier 
3147dd7cddfSDavid du Colombier 	if(mkaux->indent < 0)
3157dd7cddfSDavid du Colombier 		return;
3167dd7cddfSDavid du Colombier 	level = mkaux->indent;
3177dd7cddfSDavid du Colombier 	for(;;){
3187dd7cddfSDavid du Colombier 		mkaux->indent = 0;
3197dd7cddfSDavid du Colombier 		p = Brdline(mkaux->b, '\n');
3207dd7cddfSDavid du Colombier 		mkaux->lineno++;
3217dd7cddfSDavid du Colombier 		if(!p){
3227dd7cddfSDavid du Colombier 			mkaux->indent = -1;
3237dd7cddfSDavid du Colombier 			return;
3247dd7cddfSDavid du Colombier 		}
3257dd7cddfSDavid du Colombier 		while((c = *p++) != '\n')
3267dd7cddfSDavid du Colombier 			if(c == ' ')
3277dd7cddfSDavid du Colombier 				mkaux->indent++;
3287dd7cddfSDavid du Colombier 			else if(c == '\t')
3297dd7cddfSDavid du Colombier 				mkaux->indent += 8;
3307dd7cddfSDavid du Colombier 			else
3317dd7cddfSDavid du Colombier 				break;
3327dd7cddfSDavid du Colombier 		if(mkaux->indent <= level){
3337dd7cddfSDavid du Colombier 			Bseek(mkaux->b, -Blinelen(mkaux->b), 1);
3347dd7cddfSDavid du Colombier 			mkaux->lineno--;
3357dd7cddfSDavid du Colombier 			return;
3367dd7cddfSDavid du Colombier 		}
3377dd7cddfSDavid du Colombier 	}
3387dd7cddfSDavid du Colombier }
3397dd7cddfSDavid du Colombier 
3407dd7cddfSDavid du Colombier static File*
getfile(Mkaux * mkaux,File * old)3417dd7cddfSDavid du Colombier getfile(Mkaux *mkaux, File *old)
3427dd7cddfSDavid du Colombier {
3437dd7cddfSDavid du Colombier 	File *f;
3449a747e4fSDavid du Colombier 	char *elem;
3457dd7cddfSDavid du Colombier 	char *p;
3467dd7cddfSDavid du Colombier 	int c;
3477dd7cddfSDavid du Colombier 
3487dd7cddfSDavid du Colombier 	if(mkaux->indent < 0)
3497dd7cddfSDavid du Colombier 		return 0;
3507dd7cddfSDavid du Colombier loop:
3517dd7cddfSDavid du Colombier 	mkaux->indent = 0;
3527dd7cddfSDavid du Colombier 	p = Brdline(mkaux->b, '\n');
3537dd7cddfSDavid du Colombier 	mkaux->lineno++;
3547dd7cddfSDavid du Colombier 	if(!p){
3557dd7cddfSDavid du Colombier 		mkaux->indent = -1;
3567dd7cddfSDavid du Colombier 		return 0;
3577dd7cddfSDavid du Colombier 	}
3587dd7cddfSDavid du Colombier 	while((c = *p++) != '\n')
3597dd7cddfSDavid du Colombier 		if(c == ' ')
3607dd7cddfSDavid du Colombier 			mkaux->indent++;
3617dd7cddfSDavid du Colombier 		else if(c == '\t')
3627dd7cddfSDavid du Colombier 			mkaux->indent += 8;
3637dd7cddfSDavid du Colombier 		else
3647dd7cddfSDavid du Colombier 			break;
3657dd7cddfSDavid du Colombier 	if(c == '\n' || c == '#')
3667dd7cddfSDavid du Colombier 		goto loop;
3677dd7cddfSDavid du Colombier 	p--;
36859cc4ca5SDavid du Colombier 	f = emalloc(mkaux, sizeof *f);
3699a747e4fSDavid du Colombier 	p = getname(mkaux, p, &elem);
3707dd7cddfSDavid du Colombier 	if(p == nil)
3717dd7cddfSDavid du Colombier 		return nil;
3727dd7cddfSDavid du Colombier 
37359cc4ca5SDavid du Colombier 	f->new = mkpath(mkaux, old->new, elem);
3749a747e4fSDavid du Colombier 	free(elem);
3757dd7cddfSDavid du Colombier 	f->elem = utfrrune(f->new, L'/') + 1;
3767dd7cddfSDavid du Colombier 	p = getmode(mkaux, p, &f->mode);
3779a747e4fSDavid du Colombier 	p = getname(mkaux, p, &f->uid);	/* LEAK */
3787dd7cddfSDavid du Colombier 	if(p == nil)
3797dd7cddfSDavid du Colombier 		return nil;
3807dd7cddfSDavid du Colombier 
3817dd7cddfSDavid du Colombier 	if(!*f->uid)
3827dd7cddfSDavid du Colombier 		strcpy(f->uid, "-");
3839a747e4fSDavid du Colombier 	p = getname(mkaux, p, &f->gid);	/* LEAK */
3847dd7cddfSDavid du Colombier 	if(p == nil)
3857dd7cddfSDavid du Colombier 		return nil;
3867dd7cddfSDavid du Colombier 
3877dd7cddfSDavid du Colombier 	if(!*f->gid)
3887dd7cddfSDavid du Colombier 		strcpy(f->gid, "-");
38959cc4ca5SDavid du Colombier 	f->old = getpath(mkaux, p);
3907dd7cddfSDavid du Colombier 	if(f->old && strcmp(f->old, "-") == 0){
3917dd7cddfSDavid du Colombier 		free(f->old);
3927dd7cddfSDavid du Colombier 		f->old = 0;
3937dd7cddfSDavid du Colombier 	}
3947dd7cddfSDavid du Colombier 	setnames(mkaux, f);
3957dd7cddfSDavid du Colombier 
3967dd7cddfSDavid du Colombier 	return f;
3977dd7cddfSDavid du Colombier }
3987dd7cddfSDavid du Colombier 
3997dd7cddfSDavid du Colombier static char*
getpath(Mkaux * mkaux,char * p)40059cc4ca5SDavid du Colombier getpath(Mkaux *mkaux, char *p)
4017dd7cddfSDavid du Colombier {
4027dd7cddfSDavid du Colombier 	char *q, *new;
4037dd7cddfSDavid du Colombier 	int c, n;
4047dd7cddfSDavid du Colombier 
4057dd7cddfSDavid du Colombier 	while((c = *p) == ' ' || c == '\t')
4067dd7cddfSDavid du Colombier 		p++;
4077dd7cddfSDavid du Colombier 	q = p;
4087dd7cddfSDavid du Colombier 	while((c = *q) != '\n' && c != ' ' && c != '\t')
4097dd7cddfSDavid du Colombier 		q++;
4107dd7cddfSDavid du Colombier 	if(q == p)
4117dd7cddfSDavid du Colombier 		return 0;
4127dd7cddfSDavid du Colombier 	n = q - p;
41359cc4ca5SDavid du Colombier 	new = emalloc(mkaux, n + 1);
4147dd7cddfSDavid du Colombier 	memcpy(new, p, n);
4157dd7cddfSDavid du Colombier 	new[n] = 0;
4167dd7cddfSDavid du Colombier 	return new;
4177dd7cddfSDavid du Colombier }
4187dd7cddfSDavid du Colombier 
4197dd7cddfSDavid du Colombier static char*
getname(Mkaux * mkaux,char * p,char ** buf)4209a747e4fSDavid du Colombier getname(Mkaux *mkaux, char *p, char **buf)
4217dd7cddfSDavid du Colombier {
4229a747e4fSDavid du Colombier 	char *s, *start;
4239a747e4fSDavid du Colombier 	int c;
4247dd7cddfSDavid du Colombier 
4257dd7cddfSDavid du Colombier 	while((c = *p) == ' ' || c == '\t')
4267dd7cddfSDavid du Colombier 		p++;
4277dd7cddfSDavid du Colombier 
4289a747e4fSDavid du Colombier 	start = p;
4299a747e4fSDavid du Colombier 	while((c = *p) != '\n' && c != ' ' && c != '\t')
4309a747e4fSDavid du Colombier 		p++;
4319a747e4fSDavid du Colombier 
4329a747e4fSDavid du Colombier 	*buf = malloc(p+2-start);	/* +2: need at least 2 bytes; might strcpy "-" into buf */
4339a747e4fSDavid du Colombier 	if(*buf == nil)
4349a747e4fSDavid du Colombier 		return nil;
4359a747e4fSDavid du Colombier 	memmove(*buf, start, p-start);
4369a747e4fSDavid du Colombier 
4379a747e4fSDavid du Colombier 	(*buf)[p-start] = '\0';
4389a747e4fSDavid du Colombier 
4399a747e4fSDavid du Colombier 	if(**buf == '$'){
4409a747e4fSDavid du Colombier 		s = getenv(*buf+1);
4417dd7cddfSDavid du Colombier 		if(s == 0){
4429a747e4fSDavid du Colombier 			warn(mkaux, "can't read environment variable %s", *buf+1);
4437dd7cddfSDavid du Colombier 			skipdir(mkaux);
4449a747e4fSDavid du Colombier 			free(*buf);
4457dd7cddfSDavid du Colombier 			return nil;
4467dd7cddfSDavid du Colombier 		}
4479a747e4fSDavid du Colombier 		free(*buf);
4489a747e4fSDavid du Colombier 		*buf = s;
4497dd7cddfSDavid du Colombier 	}
4507dd7cddfSDavid du Colombier 	return p;
4517dd7cddfSDavid du Colombier }
4527dd7cddfSDavid du Colombier 
4537dd7cddfSDavid du Colombier static char*
getmode(Mkaux * mkaux,char * p,ulong * xmode)4547dd7cddfSDavid du Colombier getmode(Mkaux *mkaux, char *p, ulong *xmode)
4557dd7cddfSDavid du Colombier {
4569a747e4fSDavid du Colombier 	char *buf, *s;
4577dd7cddfSDavid du Colombier 	ulong m;
4587dd7cddfSDavid du Colombier 
4597dd7cddfSDavid du Colombier 	*xmode = ~0;
4609a747e4fSDavid du Colombier 	p = getname(mkaux, p, &buf);
4619a747e4fSDavid du Colombier 	if(p == nil)
4629a747e4fSDavid du Colombier 		return nil;
4639a747e4fSDavid du Colombier 
4647dd7cddfSDavid du Colombier 	s = buf;
4657dd7cddfSDavid du Colombier 	if(!*s || strcmp(s, "-") == 0)
4667dd7cddfSDavid du Colombier 		return p;
4677dd7cddfSDavid du Colombier 	m = 0;
4687dd7cddfSDavid du Colombier 	if(*s == 'd'){
4699a747e4fSDavid du Colombier 		m |= DMDIR;
4707dd7cddfSDavid du Colombier 		s++;
4717dd7cddfSDavid du Colombier 	}
4727dd7cddfSDavid du Colombier 	if(*s == 'a'){
4739a747e4fSDavid du Colombier 		m |= DMAPPEND;
4747dd7cddfSDavid du Colombier 		s++;
4757dd7cddfSDavid du Colombier 	}
4767dd7cddfSDavid du Colombier 	if(*s == 'l'){
4779a747e4fSDavid du Colombier 		m |= DMEXCL;
4787dd7cddfSDavid du Colombier 		s++;
4797dd7cddfSDavid du Colombier 	}
4807dd7cddfSDavid du Colombier 	if(s[0] < '0' || s[0] > '7'
4817dd7cddfSDavid du Colombier 	|| s[1] < '0' || s[1] > '7'
4827dd7cddfSDavid du Colombier 	|| s[2] < '0' || s[2] > '7'
4837dd7cddfSDavid du Colombier 	|| s[3]){
4847dd7cddfSDavid du Colombier 		warn(mkaux, "bad mode specification %s", buf);
4859a747e4fSDavid du Colombier 		free(buf);
4867dd7cddfSDavid du Colombier 		return p;
4877dd7cddfSDavid du Colombier 	}
4887dd7cddfSDavid du Colombier 	*xmode = m | strtoul(s, 0, 8);
4899a747e4fSDavid du Colombier 	free(buf);
4907dd7cddfSDavid du Colombier 	return p;
4917dd7cddfSDavid du Colombier }
4927dd7cddfSDavid du Colombier 
4937dd7cddfSDavid du Colombier static void
warn(Mkaux * mkaux,char * fmt,...)4947dd7cddfSDavid du Colombier warn(Mkaux *mkaux, char *fmt, ...)
4957dd7cddfSDavid du Colombier {
4967dd7cddfSDavid du Colombier 	char buf[256];
4977dd7cddfSDavid du Colombier 	va_list va;
4987dd7cddfSDavid du Colombier 
4997dd7cddfSDavid du Colombier 	va_start(va, fmt);
5009a747e4fSDavid du Colombier 	vseprint(buf, buf+sizeof(buf), fmt, va);
5017dd7cddfSDavid du Colombier 	va_end(va);
5027dd7cddfSDavid du Colombier 
5037dd7cddfSDavid du Colombier 	if(mkaux->warn)
5047dd7cddfSDavid du Colombier 		mkaux->warn(buf, mkaux->a);
5057dd7cddfSDavid du Colombier 	else
5067dd7cddfSDavid du Colombier 		fprint(2, "warning: %s\n", buf);
5077dd7cddfSDavid du Colombier }
508