xref: /plan9/sys/src/cmd/disk/mkfs.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
13e12c5d1SDavid du Colombier #include <u.h>
23e12c5d1SDavid du Colombier #include <libc.h>
3219b2ee8SDavid du Colombier #include <auth.h>
43e12c5d1SDavid du Colombier #include <bio.h>
53e12c5d1SDavid du Colombier 
63e12c5d1SDavid du Colombier enum{
73e12c5d1SDavid du Colombier 	LEN	= 8*1024,
83e12c5d1SDavid du Colombier 	HUNKS	= 128,
93e12c5d1SDavid du Colombier 
103e12c5d1SDavid du Colombier 	/*
113e12c5d1SDavid du Colombier 	 * types of destination file sytems
123e12c5d1SDavid du Colombier 	 */
133e12c5d1SDavid du Colombier 	Kfs = 0,
143e12c5d1SDavid du Colombier 	Fs,
153e12c5d1SDavid du Colombier 	Archive,
163e12c5d1SDavid du Colombier };
173e12c5d1SDavid du Colombier 
183e12c5d1SDavid du Colombier typedef struct File	File;
193e12c5d1SDavid du Colombier 
203e12c5d1SDavid du Colombier struct File{
213e12c5d1SDavid du Colombier 	char	*new;
223e12c5d1SDavid du Colombier 	char	*elem;
233e12c5d1SDavid du Colombier 	char	*old;
24*9a747e4fSDavid du Colombier 	char	*uid;
25*9a747e4fSDavid du Colombier 	char	*gid;
263e12c5d1SDavid du Colombier 	ulong	mode;
273e12c5d1SDavid du Colombier };
283e12c5d1SDavid du Colombier 
293e12c5d1SDavid du Colombier void	arch(Dir*);
30219b2ee8SDavid du Colombier void	copy(Dir*);
31219b2ee8SDavid du Colombier int	copyfile(File*, Dir*, int);
323e12c5d1SDavid du Colombier void*	emalloc(ulong);
333e12c5d1SDavid du Colombier void	error(char *, ...);
34219b2ee8SDavid du Colombier void	freefile(File*);
35219b2ee8SDavid du Colombier File*	getfile(File*);
36219b2ee8SDavid du Colombier char*	getmode(char*, ulong*);
37*9a747e4fSDavid du Colombier char*	getname(char*, char**);
38219b2ee8SDavid du Colombier char*	getpath(char*);
39219b2ee8SDavid du Colombier void	kfscmd(char *);
40219b2ee8SDavid du Colombier void	mkdir(Dir*);
41219b2ee8SDavid du Colombier int	mkfile(File*);
42219b2ee8SDavid du Colombier void	mkfs(File*, int);
43219b2ee8SDavid du Colombier char*	mkpath(char*, char*);
44219b2ee8SDavid du Colombier void	mktree(File*, int);
45219b2ee8SDavid du Colombier void	mountkfs(char*);
46219b2ee8SDavid du Colombier void	printfile(File*);
47219b2ee8SDavid du Colombier void	setnames(File*);
48219b2ee8SDavid du Colombier void	setusers(void);
49219b2ee8SDavid du Colombier void	skipdir(void);
50219b2ee8SDavid du Colombier char*	strdup(char*);
51219b2ee8SDavid du Colombier int	uptodate(Dir*, char*);
523e12c5d1SDavid du Colombier void	usage(void);
53219b2ee8SDavid du Colombier void	warn(char *, ...);
543e12c5d1SDavid du Colombier 
553e12c5d1SDavid du Colombier Biobuf	*b;
563e12c5d1SDavid du Colombier Biobufhdr bout;			/* stdout when writing archive */
573e12c5d1SDavid du Colombier uchar	boutbuf[2*LEN];
583e12c5d1SDavid du Colombier char	newfile[LEN];
593e12c5d1SDavid du Colombier char	oldfile[LEN];
603e12c5d1SDavid du Colombier char	*proto;
613e12c5d1SDavid du Colombier char	*cputype;
623e12c5d1SDavid du Colombier char	*users;
633e12c5d1SDavid du Colombier char	*oldroot;
643e12c5d1SDavid du Colombier char	*newroot;
653e12c5d1SDavid du Colombier char	*prog = "mkfs";
663e12c5d1SDavid du Colombier int	lineno;
673e12c5d1SDavid du Colombier char	*buf;
683e12c5d1SDavid du Colombier char	*zbuf;
693e12c5d1SDavid du Colombier int	buflen = 1024-8;
703e12c5d1SDavid du Colombier int	indent;
713e12c5d1SDavid du Colombier int	verb;
723e12c5d1SDavid du Colombier int	modes;
733e12c5d1SDavid du Colombier int	ream;
74219b2ee8SDavid du Colombier int	debug;
753e12c5d1SDavid du Colombier int	xflag;
763e12c5d1SDavid du Colombier int	sfd;
773e12c5d1SDavid du Colombier int	fskind;			/* Kfs, Fs, Archive */
78*9a747e4fSDavid du Colombier int	setuid;			/* on Fs: set uid and gid? */
793e12c5d1SDavid du Colombier char	*user;
803e12c5d1SDavid du Colombier 
813e12c5d1SDavid du Colombier void
823e12c5d1SDavid du Colombier main(int argc, char **argv)
833e12c5d1SDavid du Colombier {
843e12c5d1SDavid du Colombier 	File file;
85*9a747e4fSDavid du Colombier 	char *name;
863e12c5d1SDavid du Colombier 	int i, errs;
873e12c5d1SDavid du Colombier 
88*9a747e4fSDavid du Colombier 	quotefmtinstall();
893e12c5d1SDavid du Colombier 	user = getuser();
90*9a747e4fSDavid du Colombier 	name = "";
913e12c5d1SDavid du Colombier 	memset(&file, 0, sizeof file);
923e12c5d1SDavid du Colombier 	file.new = "";
933e12c5d1SDavid du Colombier 	file.old = 0;
943e12c5d1SDavid du Colombier 	oldroot = "";
953e12c5d1SDavid du Colombier 	newroot = "/n/kfs";
963e12c5d1SDavid du Colombier 	users = 0;
973e12c5d1SDavid du Colombier 	fskind = Kfs;
983e12c5d1SDavid du Colombier 	ARGBEGIN{
993e12c5d1SDavid du Colombier 	case 'a':
1007dd7cddfSDavid du Colombier 		if(fskind != Kfs) {
1017dd7cddfSDavid du Colombier 			fprint(2, "cannot use -a with -d\n");
1027dd7cddfSDavid du Colombier 			usage();
1037dd7cddfSDavid du Colombier 		}
1043e12c5d1SDavid du Colombier 		fskind = Archive;
1053e12c5d1SDavid du Colombier 		newroot = "";
1063e12c5d1SDavid du Colombier 		Binits(&bout, 1, OWRITE, boutbuf, sizeof boutbuf);
1073e12c5d1SDavid du Colombier 		break;
1083e12c5d1SDavid du Colombier 	case 'd':
1097dd7cddfSDavid du Colombier 		if(fskind != Kfs) {
1107dd7cddfSDavid du Colombier 			fprint(2, "cannot use -d with -a\n");
1117dd7cddfSDavid du Colombier 			usage();
1127dd7cddfSDavid du Colombier 		}
1133e12c5d1SDavid du Colombier 		fskind = Fs;
1143e12c5d1SDavid du Colombier 		newroot = ARGF();
1153e12c5d1SDavid du Colombier 		break;
116219b2ee8SDavid du Colombier 	case 'D':
117219b2ee8SDavid du Colombier 		debug = 1;
118219b2ee8SDavid du Colombier 		break;
1193e12c5d1SDavid du Colombier 	case 'n':
120*9a747e4fSDavid du Colombier 		name = EARGF(usage());
1213e12c5d1SDavid du Colombier 		break;
1223e12c5d1SDavid du Colombier 	case 'p':
1233e12c5d1SDavid du Colombier 		modes = 1;
1243e12c5d1SDavid du Colombier 		break;
1253e12c5d1SDavid du Colombier 	case 'r':
1263e12c5d1SDavid du Colombier 		ream = 1;
1273e12c5d1SDavid du Colombier 		break;
1283e12c5d1SDavid du Colombier 	case 's':
1293e12c5d1SDavid du Colombier 		oldroot = ARGF();
1303e12c5d1SDavid du Colombier 		break;
1313e12c5d1SDavid du Colombier 	case 'u':
1323e12c5d1SDavid du Colombier 		users = ARGF();
1333e12c5d1SDavid du Colombier 		break;
134*9a747e4fSDavid du Colombier 	case 'U':
135*9a747e4fSDavid du Colombier 		setuid = 1;
136*9a747e4fSDavid du Colombier 		break;
1373e12c5d1SDavid du Colombier 	case 'v':
1383e12c5d1SDavid du Colombier 		verb = 1;
1393e12c5d1SDavid du Colombier 		break;
1403e12c5d1SDavid du Colombier 	case 'x':
1413e12c5d1SDavid du Colombier 		xflag = 1;
1423e12c5d1SDavid du Colombier 		break;
1433e12c5d1SDavid du Colombier 	case 'z':
1443e12c5d1SDavid du Colombier 		buflen = atoi(ARGF())-8;
1453e12c5d1SDavid du Colombier 		break;
1463e12c5d1SDavid du Colombier 	default:
1473e12c5d1SDavid du Colombier 		usage();
1483e12c5d1SDavid du Colombier 	}ARGEND
1493e12c5d1SDavid du Colombier 
1503e12c5d1SDavid du Colombier 	if(!argc)
1513e12c5d1SDavid du Colombier 		usage();
1523e12c5d1SDavid du Colombier 
1533e12c5d1SDavid du Colombier 	buf = emalloc(buflen);
1543e12c5d1SDavid du Colombier 	zbuf = emalloc(buflen);
1553e12c5d1SDavid du Colombier 	memset(zbuf, 0, buflen);
1563e12c5d1SDavid du Colombier 
1573e12c5d1SDavid du Colombier 	mountkfs(name);
1583e12c5d1SDavid du Colombier 	kfscmd("allow");
1593e12c5d1SDavid du Colombier 	proto = "users";
1603e12c5d1SDavid du Colombier 	setusers();
1613e12c5d1SDavid du Colombier 	cputype = getenv("cputype");
1623e12c5d1SDavid du Colombier 	if(cputype == 0)
1633e12c5d1SDavid du Colombier 		cputype = "68020";
1643e12c5d1SDavid du Colombier 
1653e12c5d1SDavid du Colombier 	errs = 0;
1663e12c5d1SDavid du Colombier 	for(i = 0; i < argc; i++){
1673e12c5d1SDavid du Colombier 		proto = argv[i];
168*9a747e4fSDavid du Colombier 		fprint(2, "processing %q\n", proto);
1693e12c5d1SDavid du Colombier 
1703e12c5d1SDavid du Colombier 		b = Bopen(proto, OREAD);
1713e12c5d1SDavid du Colombier 		if(!b){
172*9a747e4fSDavid du Colombier 			fprint(2, "%q: can't open %q: skipping\n", prog, proto);
1733e12c5d1SDavid du Colombier 			errs++;
1743e12c5d1SDavid du Colombier 			continue;
1753e12c5d1SDavid du Colombier 		}
1763e12c5d1SDavid du Colombier 
1773e12c5d1SDavid du Colombier 		lineno = 0;
178219b2ee8SDavid du Colombier 		indent = 0;
1793e12c5d1SDavid du Colombier 		mkfs(&file, -1);
180219b2ee8SDavid du Colombier 		Bterm(b);
1813e12c5d1SDavid du Colombier 	}
1823e12c5d1SDavid du Colombier 	fprint(2, "file system made\n");
1833e12c5d1SDavid du Colombier 	kfscmd("disallow");
1843e12c5d1SDavid du Colombier 	kfscmd("sync");
1853e12c5d1SDavid du Colombier 	if(errs)
1863e12c5d1SDavid du Colombier 		exits("skipped protos");
1873e12c5d1SDavid du Colombier 	if(fskind == Archive){
1883e12c5d1SDavid du Colombier 		Bprint(&bout, "end of archive\n");
189219b2ee8SDavid du Colombier 		Bterm(&bout);
1903e12c5d1SDavid du Colombier 	}
1913e12c5d1SDavid du Colombier 	exits(0);
1923e12c5d1SDavid du Colombier }
1933e12c5d1SDavid du Colombier 
1943e12c5d1SDavid du Colombier void
1953e12c5d1SDavid du Colombier mkfs(File *me, int level)
1963e12c5d1SDavid du Colombier {
1973e12c5d1SDavid du Colombier 	File *child;
1983e12c5d1SDavid du Colombier 	int rec;
1993e12c5d1SDavid du Colombier 
2003e12c5d1SDavid du Colombier 	child = getfile(me);
2013e12c5d1SDavid du Colombier 	if(!child)
2023e12c5d1SDavid du Colombier 		return;
2033e12c5d1SDavid du Colombier 	if((child->elem[0] == '+' || child->elem[0] == '*') && child->elem[1] == '\0'){
2043e12c5d1SDavid du Colombier 		rec = child->elem[0] == '+';
2053e12c5d1SDavid du Colombier 		free(child->new);
2063e12c5d1SDavid du Colombier 		child->new = strdup(me->new);
2073e12c5d1SDavid du Colombier 		setnames(child);
2083e12c5d1SDavid du Colombier 		mktree(child, rec);
2093e12c5d1SDavid du Colombier 		freefile(child);
2103e12c5d1SDavid du Colombier 		child = getfile(me);
2113e12c5d1SDavid du Colombier 	}
2123e12c5d1SDavid du Colombier 	while(child && indent > level){
2133e12c5d1SDavid du Colombier 		if(mkfile(child))
2143e12c5d1SDavid du Colombier 			mkfs(child, indent);
2153e12c5d1SDavid du Colombier 		freefile(child);
2163e12c5d1SDavid du Colombier 		child = getfile(me);
2173e12c5d1SDavid du Colombier 	}
2183e12c5d1SDavid du Colombier 	if(child){
2193e12c5d1SDavid du Colombier 		freefile(child);
2203e12c5d1SDavid du Colombier 		Bseek(b, -Blinelen(b), 1);
2213e12c5d1SDavid du Colombier 		lineno--;
2223e12c5d1SDavid du Colombier 	}
2233e12c5d1SDavid du Colombier }
2243e12c5d1SDavid du Colombier 
2253e12c5d1SDavid du Colombier void
2263e12c5d1SDavid du Colombier mktree(File *me, int rec)
2273e12c5d1SDavid du Colombier {
2283e12c5d1SDavid du Colombier 	File child;
229*9a747e4fSDavid du Colombier 	Dir *d;
2303e12c5d1SDavid du Colombier 	int i, n, fd;
2313e12c5d1SDavid du Colombier 
2323e12c5d1SDavid du Colombier 	fd = open(oldfile, OREAD);
2333e12c5d1SDavid du Colombier 	if(fd < 0){
234*9a747e4fSDavid du Colombier 		warn("can't open %q: %r", oldfile);
2353e12c5d1SDavid du Colombier 		return;
2363e12c5d1SDavid du Colombier 	}
2373e12c5d1SDavid du Colombier 
2383e12c5d1SDavid du Colombier 	child = *me;
239*9a747e4fSDavid du Colombier 	while((n = dirread(fd, &d)) > 0){
2403e12c5d1SDavid du Colombier 		for(i = 0; i < n; i++){
2413e12c5d1SDavid du Colombier 			child.new = mkpath(me->new, d[i].name);
2423e12c5d1SDavid du Colombier 			if(me->old)
2433e12c5d1SDavid du Colombier 				child.old = mkpath(me->old, d[i].name);
2443e12c5d1SDavid du Colombier 			child.elem = d[i].name;
2453e12c5d1SDavid du Colombier 			setnames(&child);
2463e12c5d1SDavid du Colombier 			if(copyfile(&child, &d[i], 1) && rec)
2473e12c5d1SDavid du Colombier 				mktree(&child, rec);
2483e12c5d1SDavid du Colombier 			free(child.new);
2493e12c5d1SDavid du Colombier 			if(child.old)
2503e12c5d1SDavid du Colombier 				free(child.old);
2513e12c5d1SDavid du Colombier 		}
2523e12c5d1SDavid du Colombier 	}
2533e12c5d1SDavid du Colombier 	close(fd);
2543e12c5d1SDavid du Colombier }
2553e12c5d1SDavid du Colombier 
2563e12c5d1SDavid du Colombier int
2573e12c5d1SDavid du Colombier mkfile(File *f)
2583e12c5d1SDavid du Colombier {
259*9a747e4fSDavid du Colombier 	Dir *dir;
2603e12c5d1SDavid du Colombier 
261*9a747e4fSDavid du Colombier 	if((dir = dirstat(oldfile)) == nil){
262*9a747e4fSDavid du Colombier 		warn("can't stat file %q: %r", oldfile);
263219b2ee8SDavid du Colombier 		skipdir();
2643e12c5d1SDavid du Colombier 		return 0;
2653e12c5d1SDavid du Colombier 	}
266*9a747e4fSDavid du Colombier 	return copyfile(f, dir, 0);
2673e12c5d1SDavid du Colombier }
2683e12c5d1SDavid du Colombier 
2693e12c5d1SDavid du Colombier int
2703e12c5d1SDavid du Colombier copyfile(File *f, Dir *d, int permonly)
2713e12c5d1SDavid du Colombier {
2723e12c5d1SDavid du Colombier 	ulong mode;
273*9a747e4fSDavid du Colombier 	Dir nd;
2743e12c5d1SDavid du Colombier 
2753e12c5d1SDavid du Colombier 	if(xflag){
276*9a747e4fSDavid du Colombier 		Bprint(&bout, "%q\t%ld\t%lld\n", f->new, d->mtime, d->length);
277*9a747e4fSDavid du Colombier 		return (d->mode & DMDIR) != 0;
2783e12c5d1SDavid du Colombier 	}
2797dd7cddfSDavid du Colombier 	if(verb && (fskind == Archive || ream))
280*9a747e4fSDavid du Colombier 		fprint(2, "%q\n", f->new);
281*9a747e4fSDavid du Colombier 	d->name = f->elem;
2823e12c5d1SDavid du Colombier 	if(d->type != 'M'){
283*9a747e4fSDavid du Colombier 		d->uid = "sys";
284*9a747e4fSDavid du Colombier 		d->gid = "sys";
2853e12c5d1SDavid du Colombier 		mode = (d->mode >> 6) & 7;
2863e12c5d1SDavid du Colombier 		d->mode |= mode | (mode << 3);
2873e12c5d1SDavid du Colombier 	}
2883e12c5d1SDavid du Colombier 	if(strcmp(f->uid, "-") != 0)
289*9a747e4fSDavid du Colombier 		d->uid = f->uid;
2903e12c5d1SDavid du Colombier 	if(strcmp(f->gid, "-") != 0)
291*9a747e4fSDavid du Colombier 		d->gid = f->gid;
292*9a747e4fSDavid du Colombier 	if(fskind == Fs && !setuid){
293*9a747e4fSDavid du Colombier 		d->uid = "";
294*9a747e4fSDavid du Colombier 		d->gid = "";
2953e12c5d1SDavid du Colombier 	}
2963e12c5d1SDavid du Colombier 	if(f->mode != ~0){
2973e12c5d1SDavid du Colombier 		if(permonly)
2983e12c5d1SDavid du Colombier 			d->mode = (d->mode & ~0666) | (f->mode & 0666);
299*9a747e4fSDavid du Colombier 		else if((d->mode&DMDIR) != (f->mode&DMDIR))
300*9a747e4fSDavid du Colombier 			warn("inconsistent mode for %q", f->new);
3013e12c5d1SDavid du Colombier 		else
3023e12c5d1SDavid du Colombier 			d->mode = f->mode;
3033e12c5d1SDavid du Colombier 	}
3043e12c5d1SDavid du Colombier 	if(!uptodate(d, newfile)){
3057dd7cddfSDavid du Colombier 		if(verb && (fskind != Archive && ream == 0))
306*9a747e4fSDavid du Colombier 			fprint(2, "%q\n", f->new);
307*9a747e4fSDavid du Colombier 		if(d->mode & DMDIR)
3083e12c5d1SDavid du Colombier 			mkdir(d);
3093e12c5d1SDavid du Colombier 		else
3103e12c5d1SDavid du Colombier 			copy(d);
3117dd7cddfSDavid du Colombier 	}else if(modes){
312*9a747e4fSDavid du Colombier 		nulldir(&nd);
313*9a747e4fSDavid du Colombier 		nd.mode = d->mode;
314*9a747e4fSDavid du Colombier 		nd.gid = d->gid;
315*9a747e4fSDavid du Colombier 		nd.mtime = d->mtime;
3167dd7cddfSDavid du Colombier 		if(verb && (fskind != Archive && ream == 0))
317*9a747e4fSDavid du Colombier 			fprint(2, "%q\n", f->new);
318*9a747e4fSDavid du Colombier 		if(dirwstat(newfile, &nd) < 0)
319*9a747e4fSDavid du Colombier 			warn("can't set modes for %q: %r", f->new);
320*9a747e4fSDavid du Colombier 		nulldir(&nd);
321*9a747e4fSDavid du Colombier 		nd.uid = d->uid;
322*9a747e4fSDavid du Colombier 		dirwstat(newfile, &nd);
3237dd7cddfSDavid du Colombier 	}
324*9a747e4fSDavid du Colombier 	return (d->mode & DMDIR) != 0;
3253e12c5d1SDavid du Colombier }
3263e12c5d1SDavid du Colombier 
3273e12c5d1SDavid du Colombier /*
3283e12c5d1SDavid du Colombier  * check if file to is up to date with
3293e12c5d1SDavid du Colombier  * respect to the file represented by df
3303e12c5d1SDavid du Colombier  */
3313e12c5d1SDavid du Colombier int
3323e12c5d1SDavid du Colombier uptodate(Dir *df, char *to)
3333e12c5d1SDavid du Colombier {
334*9a747e4fSDavid du Colombier 	int ret;
335*9a747e4fSDavid du Colombier 	Dir *dt;
3363e12c5d1SDavid du Colombier 
337*9a747e4fSDavid du Colombier 	if(fskind == Archive || ream || (dt = dirstat(to)) == nil)
3383e12c5d1SDavid du Colombier 		return 0;
339*9a747e4fSDavid du Colombier 	ret = dt->mtime >= df->mtime;
340*9a747e4fSDavid du Colombier 	free(dt);
341*9a747e4fSDavid du Colombier 	return ret;
3423e12c5d1SDavid du Colombier }
3433e12c5d1SDavid du Colombier 
3443e12c5d1SDavid du Colombier void
3453e12c5d1SDavid du Colombier copy(Dir *d)
3463e12c5d1SDavid du Colombier {
3473e12c5d1SDavid du Colombier 	char cptmp[LEN], *p;
3483e12c5d1SDavid du Colombier 	long tot;
349*9a747e4fSDavid du Colombier 	int f, t, n, needwrite;
350*9a747e4fSDavid du Colombier 	Dir nd;
3513e12c5d1SDavid du Colombier 
3523e12c5d1SDavid du Colombier 	f = open(oldfile, OREAD);
3533e12c5d1SDavid du Colombier 	if(f < 0){
354*9a747e4fSDavid du Colombier 		warn("can't open %q: %r", oldfile);
3553e12c5d1SDavid du Colombier 		return;
3563e12c5d1SDavid du Colombier 	}
3573e12c5d1SDavid du Colombier 	t = -1;
3583e12c5d1SDavid du Colombier 	if(fskind == Archive)
3593e12c5d1SDavid du Colombier 		arch(d);
3603e12c5d1SDavid du Colombier 	else{
3613e12c5d1SDavid du Colombier 		strcpy(cptmp, newfile);
3623e12c5d1SDavid du Colombier 		p = utfrrune(cptmp, L'/');
3633e12c5d1SDavid du Colombier 		if(!p)
3643e12c5d1SDavid du Colombier 			error("internal temporary file error");
3653e12c5d1SDavid du Colombier 		strcpy(p+1, "__mkfstmp");
3663e12c5d1SDavid du Colombier 		t = create(cptmp, OWRITE, 0666);
3673e12c5d1SDavid du Colombier 		if(t < 0){
368*9a747e4fSDavid du Colombier 			warn("can't create %q: %r", newfile);
3693e12c5d1SDavid du Colombier 			close(f);
3703e12c5d1SDavid du Colombier 			return;
3713e12c5d1SDavid du Colombier 		}
3723e12c5d1SDavid du Colombier 	}
3733e12c5d1SDavid du Colombier 
374*9a747e4fSDavid du Colombier 	needwrite = 0;
3753e12c5d1SDavid du Colombier 	for(tot = 0;; tot += n){
3763e12c5d1SDavid du Colombier 		n = read(f, buf, buflen);
3773e12c5d1SDavid du Colombier 		if(n < 0){
378*9a747e4fSDavid du Colombier 			warn("can't read %q: %r", oldfile);
3793e12c5d1SDavid du Colombier 			break;
3803e12c5d1SDavid du Colombier 		}
3813e12c5d1SDavid du Colombier 		if(n == 0)
3823e12c5d1SDavid du Colombier 			break;
3833e12c5d1SDavid du Colombier 		if(fskind == Archive){
3843e12c5d1SDavid du Colombier 			if(Bwrite(&bout, buf, n) != n)
3853e12c5d1SDavid du Colombier 				error("write error: %r");
386*9a747e4fSDavid du Colombier 		}else if(memcmp(buf, zbuf, n) == 0){
387*9a747e4fSDavid du Colombier 			if(seek(t, n, 1) < 0)
388*9a747e4fSDavid du Colombier 				error("can't write zeros to %q: %r", newfile);
389*9a747e4fSDavid du Colombier 			needwrite = 1;
390*9a747e4fSDavid du Colombier 		}else{
391*9a747e4fSDavid du Colombier 			if(write(t, buf, n) < n)
392*9a747e4fSDavid du Colombier 				error("can't write %q: %r", newfile);
393*9a747e4fSDavid du Colombier 			needwrite = 0;
394*9a747e4fSDavid du Colombier 		}
3953e12c5d1SDavid du Colombier 	}
3963e12c5d1SDavid du Colombier 	close(f);
397*9a747e4fSDavid du Colombier 	if(needwrite){
398*9a747e4fSDavid du Colombier 		if(seek(t, -1, 1) < 0 || write(t, zbuf, 1) != 1)
399*9a747e4fSDavid du Colombier 			error("can't write zero at end of %q: %r", newfile);
400*9a747e4fSDavid du Colombier 	}
4013e12c5d1SDavid du Colombier 	if(tot != d->length){
402*9a747e4fSDavid du Colombier 		warn("wrong number bytes written to %q (was %d should be %d)\n",
4033e12c5d1SDavid du Colombier 			newfile, tot, d->length);
4043e12c5d1SDavid du Colombier 		if(fskind == Archive){
4053e12c5d1SDavid du Colombier 			warn("seeking to proper position\n");
4063e12c5d1SDavid du Colombier 			Bseek(&bout, d->length - tot, 1);
4073e12c5d1SDavid du Colombier 		}
4083e12c5d1SDavid du Colombier 	}
4093e12c5d1SDavid du Colombier 	if(fskind == Archive)
4103e12c5d1SDavid du Colombier 		return;
4113e12c5d1SDavid du Colombier 	remove(newfile);
412*9a747e4fSDavid du Colombier 	nulldir(&nd);
413*9a747e4fSDavid du Colombier 	nd.mode = d->mode;
414*9a747e4fSDavid du Colombier 	nd.gid = d->gid;
415*9a747e4fSDavid du Colombier 	nd.mtime = d->mtime;
416*9a747e4fSDavid du Colombier 	nd.name = d->name;
417*9a747e4fSDavid du Colombier 	if(dirfwstat(t, &nd) < 0)
418*9a747e4fSDavid du Colombier 		error("can't move tmp file to %q: %r", newfile);
419*9a747e4fSDavid du Colombier 	nulldir(&nd);
420*9a747e4fSDavid du Colombier 	nd.uid = d->uid;
421*9a747e4fSDavid du Colombier 	dirfwstat(t, &nd);
4223e12c5d1SDavid du Colombier 	close(t);
4233e12c5d1SDavid du Colombier }
4243e12c5d1SDavid du Colombier 
4253e12c5d1SDavid du Colombier void
4263e12c5d1SDavid du Colombier mkdir(Dir *d)
4273e12c5d1SDavid du Colombier {
428*9a747e4fSDavid du Colombier 	Dir *d1;
429*9a747e4fSDavid du Colombier 	Dir nd;
4303e12c5d1SDavid du Colombier 	int fd;
4313e12c5d1SDavid du Colombier 
4323e12c5d1SDavid du Colombier 	if(fskind == Archive){
4333e12c5d1SDavid du Colombier 		arch(d);
4343e12c5d1SDavid du Colombier 		return;
4353e12c5d1SDavid du Colombier 	}
4363e12c5d1SDavid du Colombier 	fd = create(newfile, OREAD, d->mode);
437*9a747e4fSDavid du Colombier 	nulldir(&nd);
438*9a747e4fSDavid du Colombier 	nd.mode = d->mode;
439*9a747e4fSDavid du Colombier 	nd.gid = d->gid;
440*9a747e4fSDavid du Colombier 	nd.mtime = d->mtime;
4413e12c5d1SDavid du Colombier 	if(fd < 0){
442*9a747e4fSDavid du Colombier 		if((d1 = dirstat(newfile)) == nil || !(d1->mode & DMDIR)){
443*9a747e4fSDavid du Colombier 			free(d1);
444*9a747e4fSDavid du Colombier 			error("can't create %q", newfile);
445*9a747e4fSDavid du Colombier 		}
446*9a747e4fSDavid du Colombier 		free(d1);
447*9a747e4fSDavid du Colombier 		if(dirwstat(newfile, &nd) < 0)
448*9a747e4fSDavid du Colombier 			warn("can't set modes for %q: %r", newfile);
449*9a747e4fSDavid du Colombier 		nulldir(&nd);
450*9a747e4fSDavid du Colombier 		nd.uid = d->uid;
451*9a747e4fSDavid du Colombier 		dirwstat(newfile, &nd);
4523e12c5d1SDavid du Colombier 		return;
4533e12c5d1SDavid du Colombier 	}
454*9a747e4fSDavid du Colombier 	if(dirfwstat(fd, &nd) < 0)
455*9a747e4fSDavid du Colombier 		warn("can't set modes for %q: %r", newfile);
456*9a747e4fSDavid du Colombier 	nulldir(&nd);
457*9a747e4fSDavid du Colombier 	nd.uid = d->uid;
458*9a747e4fSDavid du Colombier 	dirfwstat(fd, &nd);
4593e12c5d1SDavid du Colombier 	close(fd);
4603e12c5d1SDavid du Colombier }
4613e12c5d1SDavid du Colombier 
4623e12c5d1SDavid du Colombier void
4633e12c5d1SDavid du Colombier arch(Dir *d)
4643e12c5d1SDavid du Colombier {
465*9a747e4fSDavid du Colombier 	Bprint(&bout, "%q %luo %q %q %lud %lld\n",
466219b2ee8SDavid du Colombier 		newfile, d->mode, d->uid, d->gid, d->mtime, d->length);
4673e12c5d1SDavid du Colombier }
4683e12c5d1SDavid du Colombier 
4693e12c5d1SDavid du Colombier char *
4703e12c5d1SDavid du Colombier mkpath(char *prefix, char *elem)
4713e12c5d1SDavid du Colombier {
4723e12c5d1SDavid du Colombier 	char *p;
4733e12c5d1SDavid du Colombier 	int n;
4743e12c5d1SDavid du Colombier 
4753e12c5d1SDavid du Colombier 	n = strlen(prefix) + strlen(elem) + 2;
4763e12c5d1SDavid du Colombier 	p = emalloc(n);
4773e12c5d1SDavid du Colombier 	sprint(p, "%s/%s", prefix, elem);
4783e12c5d1SDavid du Colombier 	return p;
4793e12c5d1SDavid du Colombier }
4803e12c5d1SDavid du Colombier 
4813e12c5d1SDavid du Colombier char *
4823e12c5d1SDavid du Colombier strdup(char *s)
4833e12c5d1SDavid du Colombier {
4843e12c5d1SDavid du Colombier 	char *t;
4853e12c5d1SDavid du Colombier 
4863e12c5d1SDavid du Colombier 	t = emalloc(strlen(s) + 1);
4873e12c5d1SDavid du Colombier 	return strcpy(t, s);
4883e12c5d1SDavid du Colombier }
4893e12c5d1SDavid du Colombier 
4903e12c5d1SDavid du Colombier void
4913e12c5d1SDavid du Colombier setnames(File *f)
4923e12c5d1SDavid du Colombier {
4933e12c5d1SDavid du Colombier 	sprint(newfile, "%s%s", newroot, f->new);
4943e12c5d1SDavid du Colombier 	if(f->old){
4953e12c5d1SDavid du Colombier 		if(f->old[0] == '/')
4963e12c5d1SDavid du Colombier 			sprint(oldfile, "%s%s", oldroot, f->old);
4973e12c5d1SDavid du Colombier 		else
4983e12c5d1SDavid du Colombier 			strcpy(oldfile, f->old);
4993e12c5d1SDavid du Colombier 	}else
5003e12c5d1SDavid du Colombier 		sprint(oldfile, "%s%s", oldroot, f->new);
5013e12c5d1SDavid du Colombier 	if(strlen(newfile) >= sizeof newfile
5023e12c5d1SDavid du Colombier 	|| strlen(oldfile) >= sizeof oldfile)
5033e12c5d1SDavid du Colombier 		error("name overfile");
5043e12c5d1SDavid du Colombier }
5053e12c5d1SDavid du Colombier 
5063e12c5d1SDavid du Colombier void
5073e12c5d1SDavid du Colombier freefile(File *f)
5083e12c5d1SDavid du Colombier {
5093e12c5d1SDavid du Colombier 	if(f->old)
5103e12c5d1SDavid du Colombier 		free(f->old);
5113e12c5d1SDavid du Colombier 	if(f->new)
5123e12c5d1SDavid du Colombier 		free(f->new);
5133e12c5d1SDavid du Colombier 	free(f);
5143e12c5d1SDavid du Colombier }
5153e12c5d1SDavid du Colombier 
516219b2ee8SDavid du Colombier /*
517219b2ee8SDavid du Colombier  * skip all files in the proto that
518219b2ee8SDavid du Colombier  * could be in the current dir
519219b2ee8SDavid du Colombier  */
520219b2ee8SDavid du Colombier void
521219b2ee8SDavid du Colombier skipdir(void)
522219b2ee8SDavid du Colombier {
523219b2ee8SDavid du Colombier 	char *p, c;
524219b2ee8SDavid du Colombier 	int level;
525219b2ee8SDavid du Colombier 
526219b2ee8SDavid du Colombier 	if(indent < 0)
527219b2ee8SDavid du Colombier 		return;
528219b2ee8SDavid du Colombier 	level = indent;
529219b2ee8SDavid du Colombier 	for(;;){
530219b2ee8SDavid du Colombier 		indent = 0;
531219b2ee8SDavid du Colombier 		p = Brdline(b, '\n');
532219b2ee8SDavid du Colombier 		lineno++;
533219b2ee8SDavid du Colombier 		if(!p){
534219b2ee8SDavid du Colombier 			indent = -1;
535219b2ee8SDavid du Colombier 			return;
536219b2ee8SDavid du Colombier 		}
537219b2ee8SDavid du Colombier 		while((c = *p++) != '\n')
538219b2ee8SDavid du Colombier 			if(c == ' ')
539219b2ee8SDavid du Colombier 				indent++;
540219b2ee8SDavid du Colombier 			else if(c == '\t')
541219b2ee8SDavid du Colombier 				indent += 8;
542219b2ee8SDavid du Colombier 			else
543219b2ee8SDavid du Colombier 				break;
544219b2ee8SDavid du Colombier 		if(indent <= level){
545219b2ee8SDavid du Colombier 			Bseek(b, -Blinelen(b), 1);
546219b2ee8SDavid du Colombier 			lineno--;
547219b2ee8SDavid du Colombier 			return;
548219b2ee8SDavid du Colombier 		}
549219b2ee8SDavid du Colombier 	}
550219b2ee8SDavid du Colombier }
551219b2ee8SDavid du Colombier 
5523e12c5d1SDavid du Colombier File*
5533e12c5d1SDavid du Colombier getfile(File *old)
5543e12c5d1SDavid du Colombier {
5553e12c5d1SDavid du Colombier 	File *f;
556*9a747e4fSDavid du Colombier 	char *elem;
5573e12c5d1SDavid du Colombier 	char *p;
5583e12c5d1SDavid du Colombier 	int c;
5593e12c5d1SDavid du Colombier 
560219b2ee8SDavid du Colombier 	if(indent < 0)
561219b2ee8SDavid du Colombier 		return 0;
5623e12c5d1SDavid du Colombier loop:
5633e12c5d1SDavid du Colombier 	indent = 0;
5643e12c5d1SDavid du Colombier 	p = Brdline(b, '\n');
5653e12c5d1SDavid du Colombier 	lineno++;
5663e12c5d1SDavid du Colombier 	if(!p){
5673e12c5d1SDavid du Colombier 		indent = -1;
5683e12c5d1SDavid du Colombier 		return 0;
5693e12c5d1SDavid du Colombier 	}
570219b2ee8SDavid du Colombier 	while((c = *p++) != '\n')
5713e12c5d1SDavid du Colombier 		if(c == ' ')
5723e12c5d1SDavid du Colombier 			indent++;
5733e12c5d1SDavid du Colombier 		else if(c == '\t')
5743e12c5d1SDavid du Colombier 			indent += 8;
5753e12c5d1SDavid du Colombier 		else
5763e12c5d1SDavid du Colombier 			break;
577219b2ee8SDavid du Colombier 	if(c == '\n' || c == '#')
5783e12c5d1SDavid du Colombier 		goto loop;
5793e12c5d1SDavid du Colombier 	p--;
5803e12c5d1SDavid du Colombier 	f = emalloc(sizeof *f);
581*9a747e4fSDavid du Colombier 	p = getname(p, &elem);
582219b2ee8SDavid du Colombier 	if(debug)
583*9a747e4fSDavid du Colombier 		fprint(2, "getfile: %q root %q\n", elem, old->new);
5843e12c5d1SDavid du Colombier 	f->new = mkpath(old->new, elem);
5853e12c5d1SDavid du Colombier 	f->elem = utfrrune(f->new, L'/') + 1;
5863e12c5d1SDavid du Colombier 	p = getmode(p, &f->mode);
587*9a747e4fSDavid du Colombier 	p = getname(p, &f->uid);
5883e12c5d1SDavid du Colombier 	if(!*f->uid)
589*9a747e4fSDavid du Colombier 		f->uid = "-";
590*9a747e4fSDavid du Colombier 	p = getname(p, &f->gid);
5913e12c5d1SDavid du Colombier 	if(!*f->gid)
592*9a747e4fSDavid du Colombier 		f->gid = "-";
5933e12c5d1SDavid du Colombier 	f->old = getpath(p);
5943e12c5d1SDavid du Colombier 	if(f->old && strcmp(f->old, "-") == 0){
5953e12c5d1SDavid du Colombier 		free(f->old);
5963e12c5d1SDavid du Colombier 		f->old = 0;
5973e12c5d1SDavid du Colombier 	}
5983e12c5d1SDavid du Colombier 	setnames(f);
599219b2ee8SDavid du Colombier 
600219b2ee8SDavid du Colombier 	if(debug)
601219b2ee8SDavid du Colombier 		printfile(f);
602219b2ee8SDavid du Colombier 
6033e12c5d1SDavid du Colombier 	return f;
6043e12c5d1SDavid du Colombier }
6053e12c5d1SDavid du Colombier 
6063e12c5d1SDavid du Colombier char*
6073e12c5d1SDavid du Colombier getpath(char *p)
6083e12c5d1SDavid du Colombier {
609219b2ee8SDavid du Colombier 	char *q, *new;
610219b2ee8SDavid du Colombier 	int c, n;
6113e12c5d1SDavid du Colombier 
6123e12c5d1SDavid du Colombier 	while((c = *p) == ' ' || c == '\t')
6133e12c5d1SDavid du Colombier 		p++;
6143e12c5d1SDavid du Colombier 	q = p;
615219b2ee8SDavid du Colombier 	while((c = *q) != '\n' && c != ' ' && c != '\t')
6163e12c5d1SDavid du Colombier 		q++;
617219b2ee8SDavid du Colombier 	if(q == p)
6183e12c5d1SDavid du Colombier 		return 0;
619219b2ee8SDavid du Colombier 	n = q - p;
620219b2ee8SDavid du Colombier 	new = emalloc(n + 1);
621219b2ee8SDavid du Colombier 	memcpy(new, p, n);
622219b2ee8SDavid du Colombier 	new[n] = 0;
623219b2ee8SDavid du Colombier 	return new;
6243e12c5d1SDavid du Colombier }
6253e12c5d1SDavid du Colombier 
6263e12c5d1SDavid du Colombier char*
627*9a747e4fSDavid du Colombier getname(char *p, char **buf)
6283e12c5d1SDavid du Colombier {
629*9a747e4fSDavid du Colombier 	char *s, *start;
630*9a747e4fSDavid du Colombier 	int c;
6313e12c5d1SDavid du Colombier 
6323e12c5d1SDavid du Colombier 	while((c = *p) == ' ' || c == '\t')
6333e12c5d1SDavid du Colombier 		p++;
6343e12c5d1SDavid du Colombier 
635*9a747e4fSDavid du Colombier 	start = p;
636*9a747e4fSDavid du Colombier 	while((c = *p) != '\n' && c != ' ' && c != '\t' && c != '\0')
637*9a747e4fSDavid du Colombier 		p++;
638*9a747e4fSDavid du Colombier 
639*9a747e4fSDavid du Colombier 	*buf = malloc(p+1-start);
640*9a747e4fSDavid du Colombier 	if(*buf == nil)
641*9a747e4fSDavid du Colombier 		return nil;
642*9a747e4fSDavid du Colombier 	memmove(*buf, start, p-start);
643*9a747e4fSDavid du Colombier 	(*buf)[p-start] = '\0';
644*9a747e4fSDavid du Colombier 
645*9a747e4fSDavid du Colombier 	if(**buf == '$'){
646*9a747e4fSDavid du Colombier 		s = getenv(*buf+1);
647*9a747e4fSDavid du Colombier 		if(s == 0){
648*9a747e4fSDavid du Colombier 			warn("can't read environment variable %q", *buf+1);
649*9a747e4fSDavid du Colombier 			skipdir();
650*9a747e4fSDavid du Colombier 			free(*buf);
651*9a747e4fSDavid du Colombier 			return nil;
652*9a747e4fSDavid du Colombier 		}
653*9a747e4fSDavid du Colombier 		free(*buf);
654*9a747e4fSDavid du Colombier 		*buf = s;
6553e12c5d1SDavid du Colombier 	}
6563e12c5d1SDavid du Colombier 	return p;
6573e12c5d1SDavid du Colombier }
6583e12c5d1SDavid du Colombier 
6593e12c5d1SDavid du Colombier char*
660*9a747e4fSDavid du Colombier getmode(char *p, ulong *xmode)
6613e12c5d1SDavid du Colombier {
662*9a747e4fSDavid du Colombier 	char *buf, *s;
6633e12c5d1SDavid du Colombier 	ulong m;
6643e12c5d1SDavid du Colombier 
665*9a747e4fSDavid du Colombier 	*xmode = ~0;
666*9a747e4fSDavid du Colombier 	p = getname(p, &buf);
667*9a747e4fSDavid du Colombier 	if(p == nil)
668*9a747e4fSDavid du Colombier 		return nil;
669*9a747e4fSDavid du Colombier 
6703e12c5d1SDavid du Colombier 	s = buf;
6713e12c5d1SDavid du Colombier 	if(!*s || strcmp(s, "-") == 0)
6723e12c5d1SDavid du Colombier 		return p;
6733e12c5d1SDavid du Colombier 	m = 0;
6743e12c5d1SDavid du Colombier 	if(*s == 'd'){
675*9a747e4fSDavid du Colombier 		m |= DMDIR;
6763e12c5d1SDavid du Colombier 		s++;
6773e12c5d1SDavid du Colombier 	}
6783e12c5d1SDavid du Colombier 	if(*s == 'a'){
679*9a747e4fSDavid du Colombier 		m |= DMAPPEND;
6803e12c5d1SDavid du Colombier 		s++;
6813e12c5d1SDavid du Colombier 	}
6823e12c5d1SDavid du Colombier 	if(*s == 'l'){
683*9a747e4fSDavid du Colombier 		m |= DMEXCL;
6843e12c5d1SDavid du Colombier 		s++;
6853e12c5d1SDavid du Colombier 	}
6863e12c5d1SDavid du Colombier 	if(s[0] < '0' || s[0] > '7'
6873e12c5d1SDavid du Colombier 	|| s[1] < '0' || s[1] > '7'
6883e12c5d1SDavid du Colombier 	|| s[2] < '0' || s[2] > '7'
6893e12c5d1SDavid du Colombier 	|| s[3]){
690*9a747e4fSDavid du Colombier 		warn("bad mode specification %q", buf);
691*9a747e4fSDavid du Colombier 		free(buf);
6923e12c5d1SDavid du Colombier 		return p;
6933e12c5d1SDavid du Colombier 	}
694*9a747e4fSDavid du Colombier 	*xmode = m | strtoul(s, 0, 8);
695*9a747e4fSDavid du Colombier 	free(buf);
6963e12c5d1SDavid du Colombier 	return p;
6973e12c5d1SDavid du Colombier }
6983e12c5d1SDavid du Colombier 
6993e12c5d1SDavid du Colombier void
7003e12c5d1SDavid du Colombier setusers(void)
7013e12c5d1SDavid du Colombier {
7023e12c5d1SDavid du Colombier 	File file;
7033e12c5d1SDavid du Colombier 	int m;
7043e12c5d1SDavid du Colombier 
7053e12c5d1SDavid du Colombier 	if(fskind != Kfs)
7063e12c5d1SDavid du Colombier 		return;
7073e12c5d1SDavid du Colombier 	m = modes;
7083e12c5d1SDavid du Colombier 	modes = 1;
709*9a747e4fSDavid du Colombier 	file.uid = "adm";
710*9a747e4fSDavid du Colombier 	file.gid = "adm";
711*9a747e4fSDavid du Colombier 	file.mode = DMDIR|0775;
7123e12c5d1SDavid du Colombier 	file.new = "/adm";
7133e12c5d1SDavid du Colombier 	file.elem = "adm";
7143e12c5d1SDavid du Colombier 	file.old = 0;
7153e12c5d1SDavid du Colombier 	setnames(&file);
7163e12c5d1SDavid du Colombier 	mkfile(&file);
7173e12c5d1SDavid du Colombier 	file.new = "/adm/users";
7183e12c5d1SDavid du Colombier 	file.old = users;
7193e12c5d1SDavid du Colombier 	file.elem = "users";
7203e12c5d1SDavid du Colombier 	file.mode = 0664;
7213e12c5d1SDavid du Colombier 	setnames(&file);
7223e12c5d1SDavid du Colombier 	mkfile(&file);
7233e12c5d1SDavid du Colombier 	kfscmd("user");
7243e12c5d1SDavid du Colombier 	mkfile(&file);
725*9a747e4fSDavid du Colombier 	file.mode = DMDIR|0775;
7263e12c5d1SDavid du Colombier 	file.new = "/adm";
7273e12c5d1SDavid du Colombier 	file.old = "/adm";
7283e12c5d1SDavid du Colombier 	file.elem = "adm";
7293e12c5d1SDavid du Colombier 	setnames(&file);
7303e12c5d1SDavid du Colombier 	mkfile(&file);
7313e12c5d1SDavid du Colombier 	modes = m;
7323e12c5d1SDavid du Colombier }
7333e12c5d1SDavid du Colombier 
7343e12c5d1SDavid du Colombier void
7353e12c5d1SDavid du Colombier mountkfs(char *name)
7363e12c5d1SDavid du Colombier {
737*9a747e4fSDavid du Colombier 	char kname[64];
7383e12c5d1SDavid du Colombier 
7393e12c5d1SDavid du Colombier 	if(fskind != Kfs)
7403e12c5d1SDavid du Colombier 		return;
7413e12c5d1SDavid du Colombier 	if(name[0])
742*9a747e4fSDavid du Colombier 		snprint(kname, sizeof kname, "/srv/kfs.%s", name);
7433e12c5d1SDavid du Colombier 	else
7443e12c5d1SDavid du Colombier 		strcpy(kname, "/srv/kfs");
7453e12c5d1SDavid du Colombier 	sfd = open(kname, ORDWR);
7463e12c5d1SDavid du Colombier 	if(sfd < 0){
747*9a747e4fSDavid du Colombier 		fprint(2, "can't open %q\n", kname);
7483e12c5d1SDavid du Colombier 		exits("open /srv/kfs");
7493e12c5d1SDavid du Colombier 	}
750*9a747e4fSDavid du Colombier 	if(mount(sfd, -1, "/n/kfs", MREPL|MCREATE, "") < 0){
7513e12c5d1SDavid du Colombier 		fprint(2, "can't mount kfs on /n/kfs\n");
7523e12c5d1SDavid du Colombier 		exits("mount kfs");
7533e12c5d1SDavid du Colombier 	}
7543e12c5d1SDavid du Colombier 	close(sfd);
7553e12c5d1SDavid du Colombier 	strcat(kname, ".cmd");
7563e12c5d1SDavid du Colombier 	sfd = open(kname, ORDWR);
7573e12c5d1SDavid du Colombier 	if(sfd < 0){
758*9a747e4fSDavid du Colombier 		fprint(2, "can't open %q\n", kname);
7593e12c5d1SDavid du Colombier 		exits("open /srv/kfs");
7603e12c5d1SDavid du Colombier 	}
7613e12c5d1SDavid du Colombier }
7623e12c5d1SDavid du Colombier 
7633e12c5d1SDavid du Colombier void
7643e12c5d1SDavid du Colombier kfscmd(char *cmd)
7653e12c5d1SDavid du Colombier {
7663e12c5d1SDavid du Colombier 	char buf[4*1024];
7673e12c5d1SDavid du Colombier 	int n;
7683e12c5d1SDavid du Colombier 
7693e12c5d1SDavid du Colombier 	if(fskind != Kfs)
7703e12c5d1SDavid du Colombier 		return;
7713e12c5d1SDavid du Colombier 	if(write(sfd, cmd, strlen(cmd)) != strlen(cmd)){
772*9a747e4fSDavid du Colombier 		fprint(2, "%q: error writing %q: %r", prog, cmd);
7733e12c5d1SDavid du Colombier 		return;
7743e12c5d1SDavid du Colombier 	}
7753e12c5d1SDavid du Colombier 	for(;;){
7763e12c5d1SDavid du Colombier 		n = read(sfd, buf, sizeof buf - 1);
7773e12c5d1SDavid du Colombier 		if(n <= 0)
7783e12c5d1SDavid du Colombier 			return;
7793e12c5d1SDavid du Colombier 		buf[n] = '\0';
7803e12c5d1SDavid du Colombier 		if(strcmp(buf, "done") == 0 || strcmp(buf, "success") == 0)
7813e12c5d1SDavid du Colombier 			return;
7823e12c5d1SDavid du Colombier 		if(strcmp(buf, "unknown command") == 0){
783*9a747e4fSDavid du Colombier 			fprint(2, "%q: command %q not recognized\n", prog, cmd);
7843e12c5d1SDavid du Colombier 			return;
7853e12c5d1SDavid du Colombier 		}
7863e12c5d1SDavid du Colombier 	}
7873e12c5d1SDavid du Colombier }
7883e12c5d1SDavid du Colombier 
7893e12c5d1SDavid du Colombier void *
7903e12c5d1SDavid du Colombier emalloc(ulong n)
7913e12c5d1SDavid du Colombier {
7923e12c5d1SDavid du Colombier 	void *p;
7933e12c5d1SDavid du Colombier 
7943e12c5d1SDavid du Colombier 	if((p = malloc(n)) == 0)
7953e12c5d1SDavid du Colombier 		error("out of memory");
7963e12c5d1SDavid du Colombier 	return p;
7973e12c5d1SDavid du Colombier }
7983e12c5d1SDavid du Colombier 
7993e12c5d1SDavid du Colombier void
8003e12c5d1SDavid du Colombier error(char *fmt, ...)
8013e12c5d1SDavid du Colombier {
8023e12c5d1SDavid du Colombier 	char buf[1024];
8037dd7cddfSDavid du Colombier 	va_list arg;
8043e12c5d1SDavid du Colombier 
805*9a747e4fSDavid du Colombier 	sprint(buf, "%q: %q:%d: ", prog, proto, lineno);
8067dd7cddfSDavid du Colombier 	va_start(arg, fmt);
807*9a747e4fSDavid du Colombier 	vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg);
8087dd7cddfSDavid du Colombier 	va_end(arg);
8093e12c5d1SDavid du Colombier 	fprint(2, "%s\n", buf);
8103e12c5d1SDavid du Colombier 	kfscmd("disallow");
8113e12c5d1SDavid du Colombier 	kfscmd("sync");
8123e12c5d1SDavid du Colombier 	exits(0);
8133e12c5d1SDavid du Colombier }
8143e12c5d1SDavid du Colombier 
8153e12c5d1SDavid du Colombier void
8163e12c5d1SDavid du Colombier warn(char *fmt, ...)
8173e12c5d1SDavid du Colombier {
8183e12c5d1SDavid du Colombier 	char buf[1024];
8197dd7cddfSDavid du Colombier 	va_list arg;
8203e12c5d1SDavid du Colombier 
821*9a747e4fSDavid du Colombier 	sprint(buf, "%q: %q:%d: ", prog, proto, lineno);
8227dd7cddfSDavid du Colombier 	va_start(arg, fmt);
823*9a747e4fSDavid du Colombier 	vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg);
8247dd7cddfSDavid du Colombier 	va_end(arg);
8253e12c5d1SDavid du Colombier 	fprint(2, "%s\n", buf);
8263e12c5d1SDavid du Colombier }
8273e12c5d1SDavid du Colombier 
8283e12c5d1SDavid du Colombier void
829219b2ee8SDavid du Colombier printfile(File *f)
830219b2ee8SDavid du Colombier {
831219b2ee8SDavid du Colombier 	if(f->old)
832*9a747e4fSDavid du Colombier 		fprint(2, "%q from %q %q %q %lo\n", f->new, f->old, f->uid, f->gid, f->mode);
833219b2ee8SDavid du Colombier 	else
834*9a747e4fSDavid du Colombier 		fprint(2, "%q %q %q %lo\n", f->new, f->uid, f->gid, f->mode);
835219b2ee8SDavid du Colombier }
836219b2ee8SDavid du Colombier 
837219b2ee8SDavid du Colombier void
8383e12c5d1SDavid du Colombier usage(void)
8393e12c5d1SDavid du Colombier {
840*9a747e4fSDavid du Colombier 	fprint(2, "usage: %q [-aprvx] [-d root] [-n name] [-s source] [-u users] [-z n] proto ...\n", prog);
8413e12c5d1SDavid du Colombier 	exits("usage");
8423e12c5d1SDavid du Colombier }
843