xref: /plan9/sys/src/cmd/disk/mkfs.c (revision 603dff34803c6d085f66bc0f73d9b5b3dfaec8a3)
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;
249a747e4fSDavid du Colombier 	char	*uid;
259a747e4fSDavid 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*);
379a747e4fSDavid 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 */
789a747e4fSDavid du Colombier int	setuid;			/* on Fs: set uid and gid? */
793e12c5d1SDavid du Colombier char	*user;
803e12c5d1SDavid du Colombier 
813e12c5d1SDavid du Colombier void
main(int argc,char ** argv)823e12c5d1SDavid du Colombier main(int argc, char **argv)
833e12c5d1SDavid du Colombier {
843e12c5d1SDavid du Colombier 	File file;
859a747e4fSDavid du Colombier 	char *name;
863e12c5d1SDavid du Colombier 	int i, errs;
873e12c5d1SDavid du Colombier 
889a747e4fSDavid du Colombier 	quotefmtinstall();
893e12c5d1SDavid du Colombier 	user = getuser();
909a747e4fSDavid 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':
1209a747e4fSDavid 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;
1349a747e4fSDavid du Colombier 	case 'U':
1359a747e4fSDavid du Colombier 		setuid = 1;
1369a747e4fSDavid 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];
1689a747e4fSDavid du Colombier 		fprint(2, "processing %q\n", proto);
1693e12c5d1SDavid du Colombier 
1703e12c5d1SDavid du Colombier 		b = Bopen(proto, OREAD);
1713e12c5d1SDavid du Colombier 		if(!b){
1729a747e4fSDavid 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
mkfs(File * me,int level)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
mktree(File * me,int rec)2263e12c5d1SDavid du Colombier mktree(File *me, int rec)
2273e12c5d1SDavid du Colombier {
2283e12c5d1SDavid du Colombier 	File child;
2299a747e4fSDavid 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){
2349a747e4fSDavid du Colombier 		warn("can't open %q: %r", oldfile);
2353e12c5d1SDavid du Colombier 		return;
2363e12c5d1SDavid du Colombier 	}
2373e12c5d1SDavid du Colombier 
2383e12c5d1SDavid du Colombier 	child = *me;
2399a747e4fSDavid 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
mkfile(File * f)2573e12c5d1SDavid du Colombier mkfile(File *f)
2583e12c5d1SDavid du Colombier {
2599a747e4fSDavid du Colombier 	Dir *dir;
2603e12c5d1SDavid du Colombier 
2619a747e4fSDavid du Colombier 	if((dir = dirstat(oldfile)) == nil){
2629a747e4fSDavid du Colombier 		warn("can't stat file %q: %r", oldfile);
263219b2ee8SDavid du Colombier 		skipdir();
2643e12c5d1SDavid du Colombier 		return 0;
2653e12c5d1SDavid du Colombier 	}
2669a747e4fSDavid du Colombier 	return copyfile(f, dir, 0);
2673e12c5d1SDavid du Colombier }
2683e12c5d1SDavid du Colombier 
2693e12c5d1SDavid du Colombier int
copyfile(File * f,Dir * d,int permonly)2703e12c5d1SDavid du Colombier copyfile(File *f, Dir *d, int permonly)
2713e12c5d1SDavid du Colombier {
2723e12c5d1SDavid du Colombier 	ulong mode;
2739a747e4fSDavid du Colombier 	Dir nd;
2743e12c5d1SDavid du Colombier 
2753e12c5d1SDavid du Colombier 	if(xflag){
2769a747e4fSDavid du Colombier 		Bprint(&bout, "%q\t%ld\t%lld\n", f->new, d->mtime, d->length);
2779a747e4fSDavid du Colombier 		return (d->mode & DMDIR) != 0;
2783e12c5d1SDavid du Colombier 	}
2797dd7cddfSDavid du Colombier 	if(verb && (fskind == Archive || ream))
2809a747e4fSDavid du Colombier 		fprint(2, "%q\n", f->new);
2819a747e4fSDavid du Colombier 	d->name = f->elem;
2823e12c5d1SDavid du Colombier 	if(d->type != 'M'){
2839a747e4fSDavid du Colombier 		d->uid = "sys";
2849a747e4fSDavid 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)
2899a747e4fSDavid du Colombier 		d->uid = f->uid;
2903e12c5d1SDavid du Colombier 	if(strcmp(f->gid, "-") != 0)
2919a747e4fSDavid du Colombier 		d->gid = f->gid;
2929a747e4fSDavid du Colombier 	if(fskind == Fs && !setuid){
2939a747e4fSDavid du Colombier 		d->uid = "";
2949a747e4fSDavid 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);
2999a747e4fSDavid du Colombier 		else if((d->mode&DMDIR) != (f->mode&DMDIR))
3009a747e4fSDavid 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))
3069a747e4fSDavid du Colombier 			fprint(2, "%q\n", f->new);
3079a747e4fSDavid 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){
3129a747e4fSDavid du Colombier 		nulldir(&nd);
3139a747e4fSDavid du Colombier 		nd.mode = d->mode;
3149a747e4fSDavid du Colombier 		nd.gid = d->gid;
3159a747e4fSDavid du Colombier 		nd.mtime = d->mtime;
3167dd7cddfSDavid du Colombier 		if(verb && (fskind != Archive && ream == 0))
3179a747e4fSDavid du Colombier 			fprint(2, "%q\n", f->new);
3189a747e4fSDavid du Colombier 		if(dirwstat(newfile, &nd) < 0)
3199a747e4fSDavid du Colombier 			warn("can't set modes for %q: %r", f->new);
3209a747e4fSDavid du Colombier 		nulldir(&nd);
3219a747e4fSDavid du Colombier 		nd.uid = d->uid;
3229a747e4fSDavid du Colombier 		dirwstat(newfile, &nd);
3237dd7cddfSDavid du Colombier 	}
3249a747e4fSDavid 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
uptodate(Dir * df,char * to)3323e12c5d1SDavid du Colombier uptodate(Dir *df, char *to)
3333e12c5d1SDavid du Colombier {
3349a747e4fSDavid du Colombier 	int ret;
3359a747e4fSDavid du Colombier 	Dir *dt;
3363e12c5d1SDavid du Colombier 
3379a747e4fSDavid du Colombier 	if(fskind == Archive || ream || (dt = dirstat(to)) == nil)
3383e12c5d1SDavid du Colombier 		return 0;
3399a747e4fSDavid du Colombier 	ret = dt->mtime >= df->mtime;
3409a747e4fSDavid du Colombier 	free(dt);
3419a747e4fSDavid du Colombier 	return ret;
3423e12c5d1SDavid du Colombier }
3433e12c5d1SDavid du Colombier 
3443e12c5d1SDavid du Colombier void
copy(Dir * d)3453e12c5d1SDavid du Colombier copy(Dir *d)
3463e12c5d1SDavid du Colombier {
3473e12c5d1SDavid du Colombier 	char cptmp[LEN], *p;
348*603dff34SDavid du Colombier 	int f, t, n, needwrite, nowarnyet = 1;
349*603dff34SDavid du Colombier 	vlong tot, len;
3509a747e4fSDavid du Colombier 	Dir nd;
3513e12c5d1SDavid du Colombier 
3523e12c5d1SDavid du Colombier 	f = open(oldfile, OREAD);
3533e12c5d1SDavid du Colombier 	if(f < 0){
3549a747e4fSDavid 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){
3689a747e4fSDavid 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 
3749a747e4fSDavid du Colombier 	needwrite = 0;
375*603dff34SDavid du Colombier 	for(tot = 0; tot < d->length; tot += n){
376*603dff34SDavid du Colombier 		len = d->length - tot;
377*603dff34SDavid du Colombier 		/* don't read beyond d->length */
378*603dff34SDavid du Colombier 		if (len > buflen)
379*603dff34SDavid du Colombier 			len = buflen;
380*603dff34SDavid du Colombier 		n = read(f, buf, len);
381*603dff34SDavid du Colombier 		if(n <= 0) {
382*603dff34SDavid du Colombier 			if(n < 0 && nowarnyet) {
3839a747e4fSDavid du Colombier 				warn("can't read %q: %r", oldfile);
384*603dff34SDavid du Colombier 				nowarnyet = 0;
3853e12c5d1SDavid du Colombier 			}
386*603dff34SDavid du Colombier 			/*
387*603dff34SDavid du Colombier 			 * don't quit: pad to d->length (in pieces) to agree
388*603dff34SDavid du Colombier 			 * with the length in the header, already emitted.
389*603dff34SDavid du Colombier 			 */
390*603dff34SDavid du Colombier 			memset(buf, 0, len);
391*603dff34SDavid du Colombier 			n = len;
392*603dff34SDavid du Colombier 		}
3933e12c5d1SDavid du Colombier 		if(fskind == Archive){
3943e12c5d1SDavid du Colombier 			if(Bwrite(&bout, buf, n) != n)
3953e12c5d1SDavid du Colombier 				error("write error: %r");
3969a747e4fSDavid du Colombier 		}else if(memcmp(buf, zbuf, n) == 0){
3979a747e4fSDavid du Colombier 			if(seek(t, n, 1) < 0)
3989a747e4fSDavid du Colombier 				error("can't write zeros to %q: %r", newfile);
3999a747e4fSDavid du Colombier 			needwrite = 1;
4009a747e4fSDavid du Colombier 		}else{
4019a747e4fSDavid du Colombier 			if(write(t, buf, n) < n)
4029a747e4fSDavid du Colombier 				error("can't write %q: %r", newfile);
4039a747e4fSDavid du Colombier 			needwrite = 0;
4049a747e4fSDavid du Colombier 		}
4053e12c5d1SDavid du Colombier 	}
4063e12c5d1SDavid du Colombier 	close(f);
4079a747e4fSDavid du Colombier 	if(needwrite){
4089a747e4fSDavid du Colombier 		if(seek(t, -1, 1) < 0 || write(t, zbuf, 1) != 1)
4099a747e4fSDavid du Colombier 			error("can't write zero at end of %q: %r", newfile);
4109a747e4fSDavid du Colombier 	}
4113e12c5d1SDavid du Colombier 	if(tot != d->length){
412*603dff34SDavid du Colombier 		/* this should no longer happen */
413*603dff34SDavid du Colombier 		warn("wrong number of bytes written to %q (was %lld should be %lld)\n",
4143e12c5d1SDavid du Colombier 			newfile, tot, d->length);
4153e12c5d1SDavid du Colombier 		if(fskind == Archive){
4163e12c5d1SDavid du Colombier 			warn("seeking to proper position\n");
417*603dff34SDavid du Colombier 			/* does no good if stdout is a pipe */
4183e12c5d1SDavid du Colombier 			Bseek(&bout, d->length - tot, 1);
4193e12c5d1SDavid du Colombier 		}
4203e12c5d1SDavid du Colombier 	}
4213e12c5d1SDavid du Colombier 	if(fskind == Archive)
4223e12c5d1SDavid du Colombier 		return;
4233e12c5d1SDavid du Colombier 	remove(newfile);
4249a747e4fSDavid du Colombier 	nulldir(&nd);
4259a747e4fSDavid du Colombier 	nd.mode = d->mode;
4269a747e4fSDavid du Colombier 	nd.gid = d->gid;
4279a747e4fSDavid du Colombier 	nd.mtime = d->mtime;
4289a747e4fSDavid du Colombier 	nd.name = d->name;
4299a747e4fSDavid du Colombier 	if(dirfwstat(t, &nd) < 0)
4309a747e4fSDavid du Colombier 		error("can't move tmp file to %q: %r", newfile);
4319a747e4fSDavid du Colombier 	nulldir(&nd);
4329a747e4fSDavid du Colombier 	nd.uid = d->uid;
4339a747e4fSDavid du Colombier 	dirfwstat(t, &nd);
4343e12c5d1SDavid du Colombier 	close(t);
4353e12c5d1SDavid du Colombier }
4363e12c5d1SDavid du Colombier 
4373e12c5d1SDavid du Colombier void
mkdir(Dir * d)4383e12c5d1SDavid du Colombier mkdir(Dir *d)
4393e12c5d1SDavid du Colombier {
4409a747e4fSDavid du Colombier 	Dir *d1;
4419a747e4fSDavid du Colombier 	Dir nd;
4423e12c5d1SDavid du Colombier 	int fd;
4433e12c5d1SDavid du Colombier 
4443e12c5d1SDavid du Colombier 	if(fskind == Archive){
4453e12c5d1SDavid du Colombier 		arch(d);
4463e12c5d1SDavid du Colombier 		return;
4473e12c5d1SDavid du Colombier 	}
4483e12c5d1SDavid du Colombier 	fd = create(newfile, OREAD, d->mode);
4499a747e4fSDavid du Colombier 	nulldir(&nd);
4509a747e4fSDavid du Colombier 	nd.mode = d->mode;
4519a747e4fSDavid du Colombier 	nd.gid = d->gid;
4529a747e4fSDavid du Colombier 	nd.mtime = d->mtime;
4533e12c5d1SDavid du Colombier 	if(fd < 0){
4549a747e4fSDavid du Colombier 		if((d1 = dirstat(newfile)) == nil || !(d1->mode & DMDIR)){
4559a747e4fSDavid du Colombier 			free(d1);
4569a747e4fSDavid du Colombier 			error("can't create %q", newfile);
4579a747e4fSDavid du Colombier 		}
4589a747e4fSDavid du Colombier 		free(d1);
4599a747e4fSDavid du Colombier 		if(dirwstat(newfile, &nd) < 0)
4609a747e4fSDavid du Colombier 			warn("can't set modes for %q: %r", newfile);
4619a747e4fSDavid du Colombier 		nulldir(&nd);
4629a747e4fSDavid du Colombier 		nd.uid = d->uid;
4639a747e4fSDavid du Colombier 		dirwstat(newfile, &nd);
4643e12c5d1SDavid du Colombier 		return;
4653e12c5d1SDavid du Colombier 	}
4669a747e4fSDavid du Colombier 	if(dirfwstat(fd, &nd) < 0)
4679a747e4fSDavid du Colombier 		warn("can't set modes for %q: %r", newfile);
4689a747e4fSDavid du Colombier 	nulldir(&nd);
4699a747e4fSDavid du Colombier 	nd.uid = d->uid;
4709a747e4fSDavid du Colombier 	dirfwstat(fd, &nd);
4713e12c5d1SDavid du Colombier 	close(fd);
4723e12c5d1SDavid du Colombier }
4733e12c5d1SDavid du Colombier 
4743e12c5d1SDavid du Colombier void
arch(Dir * d)4753e12c5d1SDavid du Colombier arch(Dir *d)
4763e12c5d1SDavid du Colombier {
4779a747e4fSDavid du Colombier 	Bprint(&bout, "%q %luo %q %q %lud %lld\n",
478219b2ee8SDavid du Colombier 		newfile, d->mode, d->uid, d->gid, d->mtime, d->length);
4793e12c5d1SDavid du Colombier }
4803e12c5d1SDavid du Colombier 
4813e12c5d1SDavid du Colombier char *
mkpath(char * prefix,char * elem)4823e12c5d1SDavid du Colombier mkpath(char *prefix, char *elem)
4833e12c5d1SDavid du Colombier {
4843e12c5d1SDavid du Colombier 	char *p;
4853e12c5d1SDavid du Colombier 	int n;
4863e12c5d1SDavid du Colombier 
4873e12c5d1SDavid du Colombier 	n = strlen(prefix) + strlen(elem) + 2;
4883e12c5d1SDavid du Colombier 	p = emalloc(n);
4893e12c5d1SDavid du Colombier 	sprint(p, "%s/%s", prefix, elem);
4903e12c5d1SDavid du Colombier 	return p;
4913e12c5d1SDavid du Colombier }
4923e12c5d1SDavid du Colombier 
4933e12c5d1SDavid du Colombier char *
strdup(char * s)4943e12c5d1SDavid du Colombier strdup(char *s)
4953e12c5d1SDavid du Colombier {
4963e12c5d1SDavid du Colombier 	char *t;
4973e12c5d1SDavid du Colombier 
4983e12c5d1SDavid du Colombier 	t = emalloc(strlen(s) + 1);
4993e12c5d1SDavid du Colombier 	return strcpy(t, s);
5003e12c5d1SDavid du Colombier }
5013e12c5d1SDavid du Colombier 
5023e12c5d1SDavid du Colombier void
setnames(File * f)5033e12c5d1SDavid du Colombier setnames(File *f)
5043e12c5d1SDavid du Colombier {
5053e12c5d1SDavid du Colombier 	sprint(newfile, "%s%s", newroot, f->new);
5063e12c5d1SDavid du Colombier 	if(f->old){
5073e12c5d1SDavid du Colombier 		if(f->old[0] == '/')
5083e12c5d1SDavid du Colombier 			sprint(oldfile, "%s%s", oldroot, f->old);
5093e12c5d1SDavid du Colombier 		else
5103e12c5d1SDavid du Colombier 			strcpy(oldfile, f->old);
5113e12c5d1SDavid du Colombier 	}else
5123e12c5d1SDavid du Colombier 		sprint(oldfile, "%s%s", oldroot, f->new);
5133e12c5d1SDavid du Colombier 	if(strlen(newfile) >= sizeof newfile
5143e12c5d1SDavid du Colombier 	|| strlen(oldfile) >= sizeof oldfile)
5153e12c5d1SDavid du Colombier 		error("name overfile");
5163e12c5d1SDavid du Colombier }
5173e12c5d1SDavid du Colombier 
5183e12c5d1SDavid du Colombier void
freefile(File * f)5193e12c5d1SDavid du Colombier freefile(File *f)
5203e12c5d1SDavid du Colombier {
5213e12c5d1SDavid du Colombier 	if(f->old)
5223e12c5d1SDavid du Colombier 		free(f->old);
5233e12c5d1SDavid du Colombier 	if(f->new)
5243e12c5d1SDavid du Colombier 		free(f->new);
5253e12c5d1SDavid du Colombier 	free(f);
5263e12c5d1SDavid du Colombier }
5273e12c5d1SDavid du Colombier 
528219b2ee8SDavid du Colombier /*
529219b2ee8SDavid du Colombier  * skip all files in the proto that
530219b2ee8SDavid du Colombier  * could be in the current dir
531219b2ee8SDavid du Colombier  */
532219b2ee8SDavid du Colombier void
skipdir(void)533219b2ee8SDavid du Colombier skipdir(void)
534219b2ee8SDavid du Colombier {
535219b2ee8SDavid du Colombier 	char *p, c;
536219b2ee8SDavid du Colombier 	int level;
537219b2ee8SDavid du Colombier 
5383ff48bf5SDavid du Colombier 	if(indent < 0 || b == nil)	/* b is nil when copying adm/users */
539219b2ee8SDavid du Colombier 		return;
540219b2ee8SDavid du Colombier 	level = indent;
541219b2ee8SDavid du Colombier 	for(;;){
542219b2ee8SDavid du Colombier 		indent = 0;
543219b2ee8SDavid du Colombier 		p = Brdline(b, '\n');
544219b2ee8SDavid du Colombier 		lineno++;
545219b2ee8SDavid du Colombier 		if(!p){
546219b2ee8SDavid du Colombier 			indent = -1;
547219b2ee8SDavid du Colombier 			return;
548219b2ee8SDavid du Colombier 		}
549219b2ee8SDavid du Colombier 		while((c = *p++) != '\n')
550219b2ee8SDavid du Colombier 			if(c == ' ')
551219b2ee8SDavid du Colombier 				indent++;
552219b2ee8SDavid du Colombier 			else if(c == '\t')
553219b2ee8SDavid du Colombier 				indent += 8;
554219b2ee8SDavid du Colombier 			else
555219b2ee8SDavid du Colombier 				break;
556219b2ee8SDavid du Colombier 		if(indent <= level){
557219b2ee8SDavid du Colombier 			Bseek(b, -Blinelen(b), 1);
558219b2ee8SDavid du Colombier 			lineno--;
559219b2ee8SDavid du Colombier 			return;
560219b2ee8SDavid du Colombier 		}
561219b2ee8SDavid du Colombier 	}
562219b2ee8SDavid du Colombier }
563219b2ee8SDavid du Colombier 
5643e12c5d1SDavid du Colombier File*
getfile(File * old)5653e12c5d1SDavid du Colombier getfile(File *old)
5663e12c5d1SDavid du Colombier {
5673e12c5d1SDavid du Colombier 	File *f;
5689a747e4fSDavid du Colombier 	char *elem;
5693e12c5d1SDavid du Colombier 	char *p;
5703e12c5d1SDavid du Colombier 	int c;
5713e12c5d1SDavid du Colombier 
572219b2ee8SDavid du Colombier 	if(indent < 0)
573219b2ee8SDavid du Colombier 		return 0;
5743e12c5d1SDavid du Colombier loop:
5753e12c5d1SDavid du Colombier 	indent = 0;
5763e12c5d1SDavid du Colombier 	p = Brdline(b, '\n');
5773e12c5d1SDavid du Colombier 	lineno++;
5783e12c5d1SDavid du Colombier 	if(!p){
5793e12c5d1SDavid du Colombier 		indent = -1;
5803e12c5d1SDavid du Colombier 		return 0;
5813e12c5d1SDavid du Colombier 	}
582219b2ee8SDavid du Colombier 	while((c = *p++) != '\n')
5833e12c5d1SDavid du Colombier 		if(c == ' ')
5843e12c5d1SDavid du Colombier 			indent++;
5853e12c5d1SDavid du Colombier 		else if(c == '\t')
5863e12c5d1SDavid du Colombier 			indent += 8;
5873e12c5d1SDavid du Colombier 		else
5883e12c5d1SDavid du Colombier 			break;
589219b2ee8SDavid du Colombier 	if(c == '\n' || c == '#')
5903e12c5d1SDavid du Colombier 		goto loop;
5913e12c5d1SDavid du Colombier 	p--;
5923e12c5d1SDavid du Colombier 	f = emalloc(sizeof *f);
5939a747e4fSDavid du Colombier 	p = getname(p, &elem);
594219b2ee8SDavid du Colombier 	if(debug)
5959a747e4fSDavid du Colombier 		fprint(2, "getfile: %q root %q\n", elem, old->new);
5963e12c5d1SDavid du Colombier 	f->new = mkpath(old->new, elem);
5973e12c5d1SDavid du Colombier 	f->elem = utfrrune(f->new, L'/') + 1;
5983e12c5d1SDavid du Colombier 	p = getmode(p, &f->mode);
5999a747e4fSDavid du Colombier 	p = getname(p, &f->uid);
6003e12c5d1SDavid du Colombier 	if(!*f->uid)
6019a747e4fSDavid du Colombier 		f->uid = "-";
6029a747e4fSDavid du Colombier 	p = getname(p, &f->gid);
6033e12c5d1SDavid du Colombier 	if(!*f->gid)
6049a747e4fSDavid du Colombier 		f->gid = "-";
6053e12c5d1SDavid du Colombier 	f->old = getpath(p);
6063e12c5d1SDavid du Colombier 	if(f->old && strcmp(f->old, "-") == 0){
6073e12c5d1SDavid du Colombier 		free(f->old);
6083e12c5d1SDavid du Colombier 		f->old = 0;
6093e12c5d1SDavid du Colombier 	}
6103e12c5d1SDavid du Colombier 	setnames(f);
611219b2ee8SDavid du Colombier 
612219b2ee8SDavid du Colombier 	if(debug)
613219b2ee8SDavid du Colombier 		printfile(f);
614219b2ee8SDavid du Colombier 
6153e12c5d1SDavid du Colombier 	return f;
6163e12c5d1SDavid du Colombier }
6173e12c5d1SDavid du Colombier 
6183e12c5d1SDavid du Colombier char*
getpath(char * p)6193e12c5d1SDavid du Colombier getpath(char *p)
6203e12c5d1SDavid du Colombier {
621219b2ee8SDavid du Colombier 	char *q, *new;
622219b2ee8SDavid du Colombier 	int c, n;
6233e12c5d1SDavid du Colombier 
6243e12c5d1SDavid du Colombier 	while((c = *p) == ' ' || c == '\t')
6253e12c5d1SDavid du Colombier 		p++;
6263e12c5d1SDavid du Colombier 	q = p;
627219b2ee8SDavid du Colombier 	while((c = *q) != '\n' && c != ' ' && c != '\t')
6283e12c5d1SDavid du Colombier 		q++;
629219b2ee8SDavid du Colombier 	if(q == p)
6303e12c5d1SDavid du Colombier 		return 0;
631219b2ee8SDavid du Colombier 	n = q - p;
632219b2ee8SDavid du Colombier 	new = emalloc(n + 1);
633219b2ee8SDavid du Colombier 	memcpy(new, p, n);
634219b2ee8SDavid du Colombier 	new[n] = 0;
635219b2ee8SDavid du Colombier 	return new;
6363e12c5d1SDavid du Colombier }
6373e12c5d1SDavid du Colombier 
6383e12c5d1SDavid du Colombier char*
getname(char * p,char ** buf)6399a747e4fSDavid du Colombier getname(char *p, char **buf)
6403e12c5d1SDavid du Colombier {
6419a747e4fSDavid du Colombier 	char *s, *start;
6429a747e4fSDavid du Colombier 	int c;
6433e12c5d1SDavid du Colombier 
6443e12c5d1SDavid du Colombier 	while((c = *p) == ' ' || c == '\t')
6453e12c5d1SDavid du Colombier 		p++;
6463e12c5d1SDavid du Colombier 
6479a747e4fSDavid du Colombier 	start = p;
6489a747e4fSDavid du Colombier 	while((c = *p) != '\n' && c != ' ' && c != '\t' && c != '\0')
6499a747e4fSDavid du Colombier 		p++;
6509a747e4fSDavid du Colombier 
6519a747e4fSDavid du Colombier 	*buf = malloc(p+1-start);
6529a747e4fSDavid du Colombier 	if(*buf == nil)
6539a747e4fSDavid du Colombier 		return nil;
6549a747e4fSDavid du Colombier 	memmove(*buf, start, p-start);
6559a747e4fSDavid du Colombier 	(*buf)[p-start] = '\0';
6569a747e4fSDavid du Colombier 
6579a747e4fSDavid du Colombier 	if(**buf == '$'){
6589a747e4fSDavid du Colombier 		s = getenv(*buf+1);
6599a747e4fSDavid du Colombier 		if(s == 0){
6609a747e4fSDavid du Colombier 			warn("can't read environment variable %q", *buf+1);
6619a747e4fSDavid du Colombier 			skipdir();
6629a747e4fSDavid du Colombier 			free(*buf);
6639a747e4fSDavid du Colombier 			return nil;
6649a747e4fSDavid du Colombier 		}
6659a747e4fSDavid du Colombier 		free(*buf);
6669a747e4fSDavid du Colombier 		*buf = s;
6673e12c5d1SDavid du Colombier 	}
6683e12c5d1SDavid du Colombier 	return p;
6693e12c5d1SDavid du Colombier }
6703e12c5d1SDavid du Colombier 
6713e12c5d1SDavid du Colombier char*
getmode(char * p,ulong * xmode)6729a747e4fSDavid du Colombier getmode(char *p, ulong *xmode)
6733e12c5d1SDavid du Colombier {
6749a747e4fSDavid du Colombier 	char *buf, *s;
6753e12c5d1SDavid du Colombier 	ulong m;
6763e12c5d1SDavid du Colombier 
6779a747e4fSDavid du Colombier 	*xmode = ~0;
6789a747e4fSDavid du Colombier 	p = getname(p, &buf);
6799a747e4fSDavid du Colombier 	if(p == nil)
6809a747e4fSDavid du Colombier 		return nil;
6819a747e4fSDavid du Colombier 
6823e12c5d1SDavid du Colombier 	s = buf;
6833e12c5d1SDavid du Colombier 	if(!*s || strcmp(s, "-") == 0)
6843e12c5d1SDavid du Colombier 		return p;
6853e12c5d1SDavid du Colombier 	m = 0;
6863e12c5d1SDavid du Colombier 	if(*s == 'd'){
6879a747e4fSDavid du Colombier 		m |= DMDIR;
6883e12c5d1SDavid du Colombier 		s++;
6893e12c5d1SDavid du Colombier 	}
6903e12c5d1SDavid du Colombier 	if(*s == 'a'){
6919a747e4fSDavid du Colombier 		m |= DMAPPEND;
6923e12c5d1SDavid du Colombier 		s++;
6933e12c5d1SDavid du Colombier 	}
6943e12c5d1SDavid du Colombier 	if(*s == 'l'){
6959a747e4fSDavid du Colombier 		m |= DMEXCL;
6963e12c5d1SDavid du Colombier 		s++;
6973e12c5d1SDavid du Colombier 	}
6983e12c5d1SDavid du Colombier 	if(s[0] < '0' || s[0] > '7'
6993e12c5d1SDavid du Colombier 	|| s[1] < '0' || s[1] > '7'
7003e12c5d1SDavid du Colombier 	|| s[2] < '0' || s[2] > '7'
7013e12c5d1SDavid du Colombier 	|| s[3]){
7029a747e4fSDavid du Colombier 		warn("bad mode specification %q", buf);
7039a747e4fSDavid du Colombier 		free(buf);
7043e12c5d1SDavid du Colombier 		return p;
7053e12c5d1SDavid du Colombier 	}
7069a747e4fSDavid du Colombier 	*xmode = m | strtoul(s, 0, 8);
7079a747e4fSDavid du Colombier 	free(buf);
7083e12c5d1SDavid du Colombier 	return p;
7093e12c5d1SDavid du Colombier }
7103e12c5d1SDavid du Colombier 
7113e12c5d1SDavid du Colombier void
setusers(void)7123e12c5d1SDavid du Colombier setusers(void)
7133e12c5d1SDavid du Colombier {
7143e12c5d1SDavid du Colombier 	File file;
7153e12c5d1SDavid du Colombier 	int m;
7163e12c5d1SDavid du Colombier 
7173e12c5d1SDavid du Colombier 	if(fskind != Kfs)
7183e12c5d1SDavid du Colombier 		return;
7193e12c5d1SDavid du Colombier 	m = modes;
7203e12c5d1SDavid du Colombier 	modes = 1;
7219a747e4fSDavid du Colombier 	file.uid = "adm";
7229a747e4fSDavid du Colombier 	file.gid = "adm";
7239a747e4fSDavid du Colombier 	file.mode = DMDIR|0775;
7243e12c5d1SDavid du Colombier 	file.new = "/adm";
7253e12c5d1SDavid du Colombier 	file.elem = "adm";
7263e12c5d1SDavid du Colombier 	file.old = 0;
7273e12c5d1SDavid du Colombier 	setnames(&file);
7283ff48bf5SDavid du Colombier 	strcpy(oldfile, file.new);	/* Don't use root for /adm */
7293e12c5d1SDavid du Colombier 	mkfile(&file);
7303e12c5d1SDavid du Colombier 	file.new = "/adm/users";
7313e12c5d1SDavid du Colombier 	file.old = users;
7323e12c5d1SDavid du Colombier 	file.elem = "users";
7333e12c5d1SDavid du Colombier 	file.mode = 0664;
7343e12c5d1SDavid du Colombier 	setnames(&file);
7353ff48bf5SDavid du Colombier 	if (file.old)
7363ff48bf5SDavid du Colombier 		strcpy(oldfile, file.old);	/* Don't use root for /adm/users */
7373e12c5d1SDavid du Colombier 	mkfile(&file);
7383e12c5d1SDavid du Colombier 	kfscmd("user");
7393e12c5d1SDavid du Colombier 	mkfile(&file);
7409a747e4fSDavid du Colombier 	file.mode = DMDIR|0775;
7413e12c5d1SDavid du Colombier 	file.new = "/adm";
7423e12c5d1SDavid du Colombier 	file.old = "/adm";
7433e12c5d1SDavid du Colombier 	file.elem = "adm";
7443e12c5d1SDavid du Colombier 	setnames(&file);
7453ff48bf5SDavid du Colombier 	strcpy(oldfile, file.old);	/* Don't use root for /adm */
7463e12c5d1SDavid du Colombier 	mkfile(&file);
7473e12c5d1SDavid du Colombier 	modes = m;
7483e12c5d1SDavid du Colombier }
7493e12c5d1SDavid du Colombier 
7503e12c5d1SDavid du Colombier void
mountkfs(char * name)7513e12c5d1SDavid du Colombier mountkfs(char *name)
7523e12c5d1SDavid du Colombier {
7539a747e4fSDavid du Colombier 	char kname[64];
7543e12c5d1SDavid du Colombier 
7553e12c5d1SDavid du Colombier 	if(fskind != Kfs)
7563e12c5d1SDavid du Colombier 		return;
7573e12c5d1SDavid du Colombier 	if(name[0])
7589a747e4fSDavid du Colombier 		snprint(kname, sizeof kname, "/srv/kfs.%s", name);
7593e12c5d1SDavid du Colombier 	else
7603e12c5d1SDavid du Colombier 		strcpy(kname, "/srv/kfs");
7613e12c5d1SDavid du Colombier 	sfd = open(kname, ORDWR);
7623e12c5d1SDavid du Colombier 	if(sfd < 0){
7639a747e4fSDavid du Colombier 		fprint(2, "can't open %q\n", kname);
7643e12c5d1SDavid du Colombier 		exits("open /srv/kfs");
7653e12c5d1SDavid du Colombier 	}
7669a747e4fSDavid du Colombier 	if(mount(sfd, -1, "/n/kfs", MREPL|MCREATE, "") < 0){
7673e12c5d1SDavid du Colombier 		fprint(2, "can't mount kfs on /n/kfs\n");
7683e12c5d1SDavid du Colombier 		exits("mount kfs");
7693e12c5d1SDavid du Colombier 	}
7703e12c5d1SDavid du Colombier 	close(sfd);
7713e12c5d1SDavid du Colombier 	strcat(kname, ".cmd");
7723e12c5d1SDavid du Colombier 	sfd = open(kname, ORDWR);
7733e12c5d1SDavid du Colombier 	if(sfd < 0){
7749a747e4fSDavid du Colombier 		fprint(2, "can't open %q\n", kname);
7753e12c5d1SDavid du Colombier 		exits("open /srv/kfs");
7763e12c5d1SDavid du Colombier 	}
7773e12c5d1SDavid du Colombier }
7783e12c5d1SDavid du Colombier 
7793e12c5d1SDavid du Colombier void
kfscmd(char * cmd)7803e12c5d1SDavid du Colombier kfscmd(char *cmd)
7813e12c5d1SDavid du Colombier {
7823e12c5d1SDavid du Colombier 	char buf[4*1024];
7833e12c5d1SDavid du Colombier 	int n;
7843e12c5d1SDavid du Colombier 
7853e12c5d1SDavid du Colombier 	if(fskind != Kfs)
7863e12c5d1SDavid du Colombier 		return;
7873e12c5d1SDavid du Colombier 	if(write(sfd, cmd, strlen(cmd)) != strlen(cmd)){
7889a747e4fSDavid du Colombier 		fprint(2, "%q: error writing %q: %r", prog, cmd);
7893e12c5d1SDavid du Colombier 		return;
7903e12c5d1SDavid du Colombier 	}
7913e12c5d1SDavid du Colombier 	for(;;){
7923e12c5d1SDavid du Colombier 		n = read(sfd, buf, sizeof buf - 1);
7933e12c5d1SDavid du Colombier 		if(n <= 0)
7943e12c5d1SDavid du Colombier 			return;
7953e12c5d1SDavid du Colombier 		buf[n] = '\0';
7963e12c5d1SDavid du Colombier 		if(strcmp(buf, "done") == 0 || strcmp(buf, "success") == 0)
7973e12c5d1SDavid du Colombier 			return;
7983e12c5d1SDavid du Colombier 		if(strcmp(buf, "unknown command") == 0){
7999a747e4fSDavid du Colombier 			fprint(2, "%q: command %q not recognized\n", prog, cmd);
8003e12c5d1SDavid du Colombier 			return;
8013e12c5d1SDavid du Colombier 		}
8023e12c5d1SDavid du Colombier 	}
8033e12c5d1SDavid du Colombier }
8043e12c5d1SDavid du Colombier 
8053e12c5d1SDavid du Colombier void *
emalloc(ulong n)8063e12c5d1SDavid du Colombier emalloc(ulong n)
8073e12c5d1SDavid du Colombier {
8083e12c5d1SDavid du Colombier 	void *p;
8093e12c5d1SDavid du Colombier 
8103e12c5d1SDavid du Colombier 	if((p = malloc(n)) == 0)
8113e12c5d1SDavid du Colombier 		error("out of memory");
8123e12c5d1SDavid du Colombier 	return p;
8133e12c5d1SDavid du Colombier }
8143e12c5d1SDavid du Colombier 
8153e12c5d1SDavid du Colombier void
error(char * fmt,...)8163e12c5d1SDavid du Colombier error(char *fmt, ...)
8173e12c5d1SDavid du Colombier {
8183e12c5d1SDavid du Colombier 	char buf[1024];
8197dd7cddfSDavid du Colombier 	va_list arg;
8203e12c5d1SDavid du Colombier 
8219a747e4fSDavid du Colombier 	sprint(buf, "%q: %q:%d: ", prog, proto, lineno);
8227dd7cddfSDavid du Colombier 	va_start(arg, fmt);
8239a747e4fSDavid 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 	kfscmd("disallow");
8273e12c5d1SDavid du Colombier 	kfscmd("sync");
8283e12c5d1SDavid du Colombier 	exits(0);
8293e12c5d1SDavid du Colombier }
8303e12c5d1SDavid du Colombier 
8313e12c5d1SDavid du Colombier void
warn(char * fmt,...)8323e12c5d1SDavid du Colombier warn(char *fmt, ...)
8333e12c5d1SDavid du Colombier {
8343e12c5d1SDavid du Colombier 	char buf[1024];
8357dd7cddfSDavid du Colombier 	va_list arg;
8363e12c5d1SDavid du Colombier 
8379a747e4fSDavid du Colombier 	sprint(buf, "%q: %q:%d: ", prog, proto, lineno);
8387dd7cddfSDavid du Colombier 	va_start(arg, fmt);
8399a747e4fSDavid du Colombier 	vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg);
8407dd7cddfSDavid du Colombier 	va_end(arg);
8413e12c5d1SDavid du Colombier 	fprint(2, "%s\n", buf);
8423e12c5d1SDavid du Colombier }
8433e12c5d1SDavid du Colombier 
8443e12c5d1SDavid du Colombier void
printfile(File * f)845219b2ee8SDavid du Colombier printfile(File *f)
846219b2ee8SDavid du Colombier {
847219b2ee8SDavid du Colombier 	if(f->old)
8489a747e4fSDavid du Colombier 		fprint(2, "%q from %q %q %q %lo\n", f->new, f->old, f->uid, f->gid, f->mode);
849219b2ee8SDavid du Colombier 	else
8509a747e4fSDavid du Colombier 		fprint(2, "%q %q %q %lo\n", f->new, f->uid, f->gid, f->mode);
851219b2ee8SDavid du Colombier }
852219b2ee8SDavid du Colombier 
853219b2ee8SDavid du Colombier void
usage(void)8543e12c5d1SDavid du Colombier usage(void)
8553e12c5d1SDavid du Colombier {
8569a747e4fSDavid du Colombier 	fprint(2, "usage: %q [-aprvx] [-d root] [-n name] [-s source] [-u users] [-z n] proto ...\n", prog);
8573e12c5d1SDavid du Colombier 	exits("usage");
8583e12c5d1SDavid du Colombier }
859