xref: /plan9/sys/src/cmd/disk/mkfs.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
13e12c5d1SDavid du Colombier #include <u.h>
23e12c5d1SDavid du Colombier #include <libc.h>
3*219b2ee8SDavid 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;
243e12c5d1SDavid du Colombier 	char	uid[NAMELEN];
253e12c5d1SDavid du Colombier 	char	gid[NAMELEN];
263e12c5d1SDavid du Colombier 	ulong	mode;
273e12c5d1SDavid du Colombier };
283e12c5d1SDavid du Colombier 
293e12c5d1SDavid du Colombier void	arch(Dir*);
30*219b2ee8SDavid du Colombier void	copy(Dir*);
31*219b2ee8SDavid du Colombier int	copyfile(File*, Dir*, int);
323e12c5d1SDavid du Colombier void*	emalloc(ulong);
333e12c5d1SDavid du Colombier void	error(char *, ...);
34*219b2ee8SDavid du Colombier void	freefile(File*);
35*219b2ee8SDavid du Colombier File*	getfile(File*);
36*219b2ee8SDavid du Colombier char*	getmode(char*, ulong*);
37*219b2ee8SDavid du Colombier char*	getname(char*, char*, int);
38*219b2ee8SDavid du Colombier char*	getpath(char*);
39*219b2ee8SDavid du Colombier void	kfscmd(char *);
40*219b2ee8SDavid du Colombier void	mkdir(Dir*);
41*219b2ee8SDavid du Colombier int	mkfile(File*);
42*219b2ee8SDavid du Colombier void	mkfs(File*, int);
43*219b2ee8SDavid du Colombier char*	mkpath(char*, char*);
44*219b2ee8SDavid du Colombier void	mktree(File*, int);
45*219b2ee8SDavid du Colombier void	mountkfs(char*);
46*219b2ee8SDavid du Colombier void	printfile(File*);
47*219b2ee8SDavid du Colombier void	setnames(File*);
48*219b2ee8SDavid du Colombier void	setusers(void);
49*219b2ee8SDavid du Colombier void	skipdir(void);
50*219b2ee8SDavid du Colombier char*	strdup(char*);
51*219b2ee8SDavid du Colombier int	uptodate(Dir*, char*);
523e12c5d1SDavid du Colombier void	usage(void);
53*219b2ee8SDavid 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;
74*219b2ee8SDavid du Colombier int	debug;
753e12c5d1SDavid du Colombier int	xflag;
763e12c5d1SDavid du Colombier int	sfd;
773e12c5d1SDavid du Colombier int	fskind;			/* Kfs, Fs, Archive */
783e12c5d1SDavid du Colombier char	*user;
793e12c5d1SDavid du Colombier 
803e12c5d1SDavid du Colombier void
813e12c5d1SDavid du Colombier main(int argc, char **argv)
823e12c5d1SDavid du Colombier {
833e12c5d1SDavid du Colombier 	File file;
843e12c5d1SDavid du Colombier 	char name[NAMELEN];
853e12c5d1SDavid du Colombier 	int i, errs;
863e12c5d1SDavid du Colombier 
873e12c5d1SDavid du Colombier 	user = getuser();
883e12c5d1SDavid du Colombier 	name[0] = '\0';
893e12c5d1SDavid du Colombier 	memset(&file, 0, sizeof file);
903e12c5d1SDavid du Colombier 	file.new = "";
913e12c5d1SDavid du Colombier 	file.old = 0;
923e12c5d1SDavid du Colombier 	oldroot = "";
933e12c5d1SDavid du Colombier 	newroot = "/n/kfs";
943e12c5d1SDavid du Colombier 	users = 0;
953e12c5d1SDavid du Colombier 	fskind = Kfs;
963e12c5d1SDavid du Colombier 	ARGBEGIN{
973e12c5d1SDavid du Colombier 	case 'a':
983e12c5d1SDavid du Colombier 		fskind = Archive;
993e12c5d1SDavid du Colombier 		newroot = "";
1003e12c5d1SDavid du Colombier 		Binits(&bout, 1, OWRITE, boutbuf, sizeof boutbuf);
1013e12c5d1SDavid du Colombier 		break;
1023e12c5d1SDavid du Colombier 	case 'd':
1033e12c5d1SDavid du Colombier 		fskind = Fs;
1043e12c5d1SDavid du Colombier 		newroot = ARGF();
1053e12c5d1SDavid du Colombier 		break;
106*219b2ee8SDavid du Colombier 	case 'D':
107*219b2ee8SDavid du Colombier 		debug = 1;
108*219b2ee8SDavid du Colombier 		break;
1093e12c5d1SDavid du Colombier 	case 'n':
1103e12c5d1SDavid du Colombier 		strncpy(name, ARGF(), NAMELEN - 1);
1113e12c5d1SDavid du Colombier 		name[NAMELEN - 1] = '\0';
1123e12c5d1SDavid du Colombier 		break;
1133e12c5d1SDavid du Colombier 	case 'p':
1143e12c5d1SDavid du Colombier 		modes = 1;
1153e12c5d1SDavid du Colombier 		break;
1163e12c5d1SDavid du Colombier 	case 'r':
1173e12c5d1SDavid du Colombier 		ream = 1;
1183e12c5d1SDavid du Colombier 		break;
1193e12c5d1SDavid du Colombier 	case 's':
1203e12c5d1SDavid du Colombier 		oldroot = ARGF();
1213e12c5d1SDavid du Colombier 		break;
1223e12c5d1SDavid du Colombier 	case 'u':
1233e12c5d1SDavid du Colombier 		users = ARGF();
1243e12c5d1SDavid du Colombier 		break;
1253e12c5d1SDavid du Colombier 	case 'v':
1263e12c5d1SDavid du Colombier 		verb = 1;
1273e12c5d1SDavid du Colombier 		break;
1283e12c5d1SDavid du Colombier 	case 'x':
1293e12c5d1SDavid du Colombier 		xflag = 1;
1303e12c5d1SDavid du Colombier 		break;
1313e12c5d1SDavid du Colombier 	case 'z':
1323e12c5d1SDavid du Colombier 		buflen = atoi(ARGF())-8;
1333e12c5d1SDavid du Colombier 		break;
1343e12c5d1SDavid du Colombier 	default:
1353e12c5d1SDavid du Colombier 		usage();
1363e12c5d1SDavid du Colombier 	}ARGEND
1373e12c5d1SDavid du Colombier 
1383e12c5d1SDavid du Colombier 	if(!argc)
1393e12c5d1SDavid du Colombier 		usage();
1403e12c5d1SDavid du Colombier 
1413e12c5d1SDavid du Colombier 	buf = emalloc(buflen);
1423e12c5d1SDavid du Colombier 	zbuf = emalloc(buflen);
1433e12c5d1SDavid du Colombier 	memset(zbuf, 0, buflen);
1443e12c5d1SDavid du Colombier 
1453e12c5d1SDavid du Colombier 	mountkfs(name);
1463e12c5d1SDavid du Colombier 	kfscmd("allow");
1473e12c5d1SDavid du Colombier 	proto = "users";
1483e12c5d1SDavid du Colombier 	setusers();
1493e12c5d1SDavid du Colombier 	cputype = getenv("cputype");
1503e12c5d1SDavid du Colombier 	if(cputype == 0)
1513e12c5d1SDavid du Colombier 		cputype = "68020";
1523e12c5d1SDavid du Colombier 
1533e12c5d1SDavid du Colombier 	errs = 0;
1543e12c5d1SDavid du Colombier 	for(i = 0; i < argc; i++){
1553e12c5d1SDavid du Colombier 		proto = argv[i];
1563e12c5d1SDavid du Colombier 		fprint(2, "processing %s\n", proto);
1573e12c5d1SDavid du Colombier 
1583e12c5d1SDavid du Colombier 		b = Bopen(proto, OREAD);
1593e12c5d1SDavid du Colombier 		if(!b){
1603e12c5d1SDavid du Colombier 			fprint(2, "%s: can't open %s: skipping\n", prog, proto);
1613e12c5d1SDavid du Colombier 			errs++;
1623e12c5d1SDavid du Colombier 			continue;
1633e12c5d1SDavid du Colombier 		}
1643e12c5d1SDavid du Colombier 
1653e12c5d1SDavid du Colombier 		lineno = 0;
166*219b2ee8SDavid du Colombier 		indent = 0;
1673e12c5d1SDavid du Colombier 		mkfs(&file, -1);
168*219b2ee8SDavid du Colombier 		Bterm(b);
1693e12c5d1SDavid du Colombier 	}
1703e12c5d1SDavid du Colombier 	fprint(2, "file system made\n");
1713e12c5d1SDavid du Colombier 	kfscmd("disallow");
1723e12c5d1SDavid du Colombier 	kfscmd("sync");
1733e12c5d1SDavid du Colombier 	if(errs)
1743e12c5d1SDavid du Colombier 		exits("skipped protos");
1753e12c5d1SDavid du Colombier 	if(fskind == Archive){
1763e12c5d1SDavid du Colombier 		Bprint(&bout, "end of archive\n");
177*219b2ee8SDavid du Colombier 		Bterm(&bout);
1783e12c5d1SDavid du Colombier 	}
1793e12c5d1SDavid du Colombier 	exits(0);
1803e12c5d1SDavid du Colombier }
1813e12c5d1SDavid du Colombier 
1823e12c5d1SDavid du Colombier void
1833e12c5d1SDavid du Colombier mkfs(File *me, int level)
1843e12c5d1SDavid du Colombier {
1853e12c5d1SDavid du Colombier 	File *child;
1863e12c5d1SDavid du Colombier 	int rec;
1873e12c5d1SDavid du Colombier 
1883e12c5d1SDavid du Colombier 	child = getfile(me);
1893e12c5d1SDavid du Colombier 	if(!child)
1903e12c5d1SDavid du Colombier 		return;
1913e12c5d1SDavid du Colombier 	if((child->elem[0] == '+' || child->elem[0] == '*') && child->elem[1] == '\0'){
1923e12c5d1SDavid du Colombier 		rec = child->elem[0] == '+';
1933e12c5d1SDavid du Colombier 		free(child->new);
1943e12c5d1SDavid du Colombier 		child->new = strdup(me->new);
1953e12c5d1SDavid du Colombier 		setnames(child);
1963e12c5d1SDavid du Colombier 		mktree(child, rec);
1973e12c5d1SDavid du Colombier 		freefile(child);
1983e12c5d1SDavid du Colombier 		child = getfile(me);
1993e12c5d1SDavid du Colombier 	}
2003e12c5d1SDavid du Colombier 	while(child && indent > level){
2013e12c5d1SDavid du Colombier 		if(mkfile(child))
2023e12c5d1SDavid du Colombier 			mkfs(child, indent);
2033e12c5d1SDavid du Colombier 		freefile(child);
2043e12c5d1SDavid du Colombier 		child = getfile(me);
2053e12c5d1SDavid du Colombier 	}
2063e12c5d1SDavid du Colombier 	if(child){
2073e12c5d1SDavid du Colombier 		freefile(child);
2083e12c5d1SDavid du Colombier 		Bseek(b, -Blinelen(b), 1);
2093e12c5d1SDavid du Colombier 		lineno--;
2103e12c5d1SDavid du Colombier 	}
2113e12c5d1SDavid du Colombier }
2123e12c5d1SDavid du Colombier 
2133e12c5d1SDavid du Colombier void
2143e12c5d1SDavid du Colombier mktree(File *me, int rec)
2153e12c5d1SDavid du Colombier {
2163e12c5d1SDavid du Colombier 	File child;
2173e12c5d1SDavid du Colombier 	Dir d[HUNKS];
2183e12c5d1SDavid du Colombier 	int i, n, fd;
2193e12c5d1SDavid du Colombier 
2203e12c5d1SDavid du Colombier 	fd = open(oldfile, OREAD);
2213e12c5d1SDavid du Colombier 	if(fd < 0){
2223e12c5d1SDavid du Colombier 		warn("can't open %s: %r", oldfile);
2233e12c5d1SDavid du Colombier 		return;
2243e12c5d1SDavid du Colombier 	}
2253e12c5d1SDavid du Colombier 
2263e12c5d1SDavid du Colombier 	child = *me;
2273e12c5d1SDavid du Colombier 	while((n = dirread(fd, d, sizeof d)) > 0){
2283e12c5d1SDavid du Colombier 		n /= DIRLEN;
2293e12c5d1SDavid du Colombier 		for(i = 0; i < n; i++){
2303e12c5d1SDavid du Colombier 			child.new = mkpath(me->new, d[i].name);
2313e12c5d1SDavid du Colombier 			if(me->old)
2323e12c5d1SDavid du Colombier 				child.old = mkpath(me->old, d[i].name);
2333e12c5d1SDavid du Colombier 			child.elem = d[i].name;
2343e12c5d1SDavid du Colombier 			setnames(&child);
2353e12c5d1SDavid du Colombier 			if(copyfile(&child, &d[i], 1) && rec)
2363e12c5d1SDavid du Colombier 				mktree(&child, rec);
2373e12c5d1SDavid du Colombier 			free(child.new);
2383e12c5d1SDavid du Colombier 			if(child.old)
2393e12c5d1SDavid du Colombier 				free(child.old);
2403e12c5d1SDavid du Colombier 		}
2413e12c5d1SDavid du Colombier 	}
2423e12c5d1SDavid du Colombier 	close(fd);
2433e12c5d1SDavid du Colombier }
2443e12c5d1SDavid du Colombier 
2453e12c5d1SDavid du Colombier int
2463e12c5d1SDavid du Colombier mkfile(File *f)
2473e12c5d1SDavid du Colombier {
2483e12c5d1SDavid du Colombier 	Dir dir;
2493e12c5d1SDavid du Colombier 
2503e12c5d1SDavid du Colombier 	if(dirstat(oldfile, &dir) < 0){
2513e12c5d1SDavid du Colombier 		warn("can't stat file %s: %r", oldfile);
252*219b2ee8SDavid du Colombier 		skipdir();
2533e12c5d1SDavid du Colombier 		return 0;
2543e12c5d1SDavid du Colombier 	}
2553e12c5d1SDavid du Colombier 	return copyfile(f, &dir, 0);
2563e12c5d1SDavid du Colombier }
2573e12c5d1SDavid du Colombier 
2583e12c5d1SDavid du Colombier int
2593e12c5d1SDavid du Colombier copyfile(File *f, Dir *d, int permonly)
2603e12c5d1SDavid du Colombier {
2613e12c5d1SDavid du Colombier 	ulong mode;
2623e12c5d1SDavid du Colombier 
2633e12c5d1SDavid du Colombier 	if(xflag){
2643e12c5d1SDavid du Colombier 		Bprint(&bout, "%s\t%ld\t%d\n", f->new, d->mtime, d->length);
2653e12c5d1SDavid du Colombier 		return (d->mode & CHDIR) != 0;
2663e12c5d1SDavid du Colombier 	}
2673e12c5d1SDavid du Colombier 	if(verb)
2683e12c5d1SDavid du Colombier 		fprint(2, "%s\n", f->new);
2693e12c5d1SDavid du Colombier 	memmove(d->name, f->elem, NAMELEN);
2703e12c5d1SDavid du Colombier 	if(d->type != 'M'){
2713e12c5d1SDavid du Colombier 		strncpy(d->uid, "sys", NAMELEN);
2723e12c5d1SDavid du Colombier 		strncpy(d->gid, "sys", NAMELEN);
2733e12c5d1SDavid du Colombier 		mode = (d->mode >> 6) & 7;
2743e12c5d1SDavid du Colombier 		d->mode |= mode | (mode << 3);
2753e12c5d1SDavid du Colombier 	}
2763e12c5d1SDavid du Colombier 	if(strcmp(f->uid, "-") != 0)
2773e12c5d1SDavid du Colombier 		strncpy(d->uid, f->uid, NAMELEN);
2783e12c5d1SDavid du Colombier 	if(strcmp(f->gid, "-") != 0)
2793e12c5d1SDavid du Colombier 		strncpy(d->gid, f->gid, NAMELEN);
2803e12c5d1SDavid du Colombier 	if(fskind == Fs){
2813e12c5d1SDavid du Colombier 		strncpy(d->uid, user, NAMELEN);
2823e12c5d1SDavid du Colombier 		strncpy(d->gid, user, NAMELEN);
2833e12c5d1SDavid du Colombier 	}
2843e12c5d1SDavid du Colombier 	if(f->mode != ~0){
2853e12c5d1SDavid du Colombier 		if(permonly)
2863e12c5d1SDavid du Colombier 			d->mode = (d->mode & ~0666) | (f->mode & 0666);
2873e12c5d1SDavid du Colombier 		else if((d->mode&CHDIR) != (f->mode&CHDIR))
2883e12c5d1SDavid du Colombier 			warn("inconsistent mode for %s", f->new);
2893e12c5d1SDavid du Colombier 		else
2903e12c5d1SDavid du Colombier 			d->mode = f->mode;
2913e12c5d1SDavid du Colombier 	}
2923e12c5d1SDavid du Colombier 	if(!uptodate(d, newfile)){
2933e12c5d1SDavid du Colombier 		if(d->mode & CHDIR)
2943e12c5d1SDavid du Colombier 			mkdir(d);
2953e12c5d1SDavid du Colombier 		else
2963e12c5d1SDavid du Colombier 			copy(d);
2973e12c5d1SDavid du Colombier 	}else if(modes && dirwstat(newfile, d) < 0)
2983e12c5d1SDavid du Colombier 		warn("can't set modes for %s: %r", f->new);
2993e12c5d1SDavid du Colombier 	return (d->mode & CHDIR) != 0;
3003e12c5d1SDavid du Colombier }
3013e12c5d1SDavid du Colombier 
3023e12c5d1SDavid du Colombier /*
3033e12c5d1SDavid du Colombier  * check if file to is up to date with
3043e12c5d1SDavid du Colombier  * respect to the file represented by df
3053e12c5d1SDavid du Colombier  */
3063e12c5d1SDavid du Colombier int
3073e12c5d1SDavid du Colombier uptodate(Dir *df, char *to)
3083e12c5d1SDavid du Colombier {
3093e12c5d1SDavid du Colombier 	Dir dt;
3103e12c5d1SDavid du Colombier 
3113e12c5d1SDavid du Colombier 	if(fskind == Archive || ream || dirstat(to, &dt) < 0)
3123e12c5d1SDavid du Colombier 		return 0;
3133e12c5d1SDavid du Colombier 	return dt.mtime >= df->mtime;
3143e12c5d1SDavid du Colombier }
3153e12c5d1SDavid du Colombier 
3163e12c5d1SDavid du Colombier void
3173e12c5d1SDavid du Colombier copy(Dir *d)
3183e12c5d1SDavid du Colombier {
3193e12c5d1SDavid du Colombier 	char cptmp[LEN], *p;
3203e12c5d1SDavid du Colombier 	long tot;
3213e12c5d1SDavid du Colombier 	int f, t, n;
3223e12c5d1SDavid du Colombier 
3233e12c5d1SDavid du Colombier 	f = open(oldfile, OREAD);
3243e12c5d1SDavid du Colombier 	if(f < 0){
3253e12c5d1SDavid du Colombier 		warn("can't open %s: %r", oldfile);
3263e12c5d1SDavid du Colombier 		return;
3273e12c5d1SDavid du Colombier 	}
3283e12c5d1SDavid du Colombier 	t = -1;
3293e12c5d1SDavid du Colombier 	if(fskind == Archive)
3303e12c5d1SDavid du Colombier 		arch(d);
3313e12c5d1SDavid du Colombier 	else{
3323e12c5d1SDavid du Colombier 		strcpy(cptmp, newfile);
3333e12c5d1SDavid du Colombier 		p = utfrrune(cptmp, L'/');
3343e12c5d1SDavid du Colombier 		if(!p)
3353e12c5d1SDavid du Colombier 			error("internal temporary file error");
3363e12c5d1SDavid du Colombier 		strcpy(p+1, "__mkfstmp");
3373e12c5d1SDavid du Colombier 		t = create(cptmp, OWRITE, 0666);
3383e12c5d1SDavid du Colombier 		if(t < 0){
3393e12c5d1SDavid du Colombier 			warn("can't create %s: %r", newfile);
3403e12c5d1SDavid du Colombier 			close(f);
3413e12c5d1SDavid du Colombier 			return;
3423e12c5d1SDavid du Colombier 		}
3433e12c5d1SDavid du Colombier 	}
3443e12c5d1SDavid du Colombier 
3453e12c5d1SDavid du Colombier 	for(tot = 0;; tot += n){
3463e12c5d1SDavid du Colombier 		n = read(f, buf, buflen);
3473e12c5d1SDavid du Colombier 		if(n < 0){
3483e12c5d1SDavid du Colombier 			warn("can't read %s: %r", oldfile);
3493e12c5d1SDavid du Colombier 			break;
3503e12c5d1SDavid du Colombier 		}
3513e12c5d1SDavid du Colombier 		if(n == 0)
3523e12c5d1SDavid du Colombier 			break;
3533e12c5d1SDavid du Colombier 		if(fskind == Archive){
3543e12c5d1SDavid du Colombier 			if(Bwrite(&bout, buf, n) != n)
3553e12c5d1SDavid du Colombier 				error("write error: %r");
3563e12c5d1SDavid du Colombier 		}else if(memcmp(buf, zbuf, buflen) == 0){
3573e12c5d1SDavid du Colombier 			if(seek(t, buflen, 1) < 0)
3583e12c5d1SDavid du Colombier 				error("can't write zeros to %s: %r", newfile);
3593e12c5d1SDavid du Colombier 		}else if(write(t, buf, n) < n)
3603e12c5d1SDavid du Colombier 			error("can't write %s: %r", newfile);
3613e12c5d1SDavid du Colombier 	}
3623e12c5d1SDavid du Colombier 	close(f);
3633e12c5d1SDavid du Colombier 	if(tot != d->length){
3643e12c5d1SDavid du Colombier 		warn("wrong number bytes written to %s (was %d should be %d)\n",
3653e12c5d1SDavid du Colombier 			newfile, tot, d->length);
3663e12c5d1SDavid du Colombier 		if(fskind == Archive){
3673e12c5d1SDavid du Colombier 			warn("seeking to proper position\n");
3683e12c5d1SDavid du Colombier 			Bseek(&bout, d->length - tot, 1);
3693e12c5d1SDavid du Colombier 		}
3703e12c5d1SDavid du Colombier 	}
3713e12c5d1SDavid du Colombier 	if(fskind == Archive)
3723e12c5d1SDavid du Colombier 		return;
3733e12c5d1SDavid du Colombier 	remove(newfile);
3743e12c5d1SDavid du Colombier 	if(dirfwstat(t, d) < 0)
3753e12c5d1SDavid du Colombier 		error("can't move tmp file to %s: %r", newfile);
3763e12c5d1SDavid du Colombier 	close(t);
3773e12c5d1SDavid du Colombier }
3783e12c5d1SDavid du Colombier 
3793e12c5d1SDavid du Colombier void
3803e12c5d1SDavid du Colombier mkdir(Dir *d)
3813e12c5d1SDavid du Colombier {
3823e12c5d1SDavid du Colombier 	Dir d1;
3833e12c5d1SDavid du Colombier 	int fd;
3843e12c5d1SDavid du Colombier 
3853e12c5d1SDavid du Colombier 	if(fskind == Archive){
3863e12c5d1SDavid du Colombier 		arch(d);
3873e12c5d1SDavid du Colombier 		return;
3883e12c5d1SDavid du Colombier 	}
3893e12c5d1SDavid du Colombier 	fd = create(newfile, OREAD, d->mode);
3903e12c5d1SDavid du Colombier 	if(fd < 0){
3913e12c5d1SDavid du Colombier 		if(dirstat(newfile, &d1) < 0 || !(d1.mode & CHDIR))
3923e12c5d1SDavid du Colombier 			error("can't create %s", newfile);
3933e12c5d1SDavid du Colombier 		if(dirwstat(newfile, d) < 0)
3943e12c5d1SDavid du Colombier 			warn("can't set modes for %s: %r", newfile);
3953e12c5d1SDavid du Colombier 		return;
3963e12c5d1SDavid du Colombier 	}
3973e12c5d1SDavid du Colombier 	if(dirfwstat(fd, d) < 0)
3983e12c5d1SDavid du Colombier 		warn("can't set modes for %s: %r", newfile);
3993e12c5d1SDavid du Colombier 	close(fd);
4003e12c5d1SDavid du Colombier }
4013e12c5d1SDavid du Colombier 
4023e12c5d1SDavid du Colombier void
4033e12c5d1SDavid du Colombier arch(Dir *d)
4043e12c5d1SDavid du Colombier {
405*219b2ee8SDavid du Colombier 	Bprint(&bout, "%s %luo %s %s %lud %d\n",
406*219b2ee8SDavid du Colombier 		newfile, d->mode, d->uid, d->gid, d->mtime, d->length);
4073e12c5d1SDavid du Colombier }
4083e12c5d1SDavid du Colombier 
4093e12c5d1SDavid du Colombier char *
4103e12c5d1SDavid du Colombier mkpath(char *prefix, char *elem)
4113e12c5d1SDavid du Colombier {
4123e12c5d1SDavid du Colombier 	char *p;
4133e12c5d1SDavid du Colombier 	int n;
4143e12c5d1SDavid du Colombier 
4153e12c5d1SDavid du Colombier 	n = strlen(prefix) + strlen(elem) + 2;
4163e12c5d1SDavid du Colombier 	p = emalloc(n);
4173e12c5d1SDavid du Colombier 	sprint(p, "%s/%s", prefix, elem);
4183e12c5d1SDavid du Colombier 	return p;
4193e12c5d1SDavid du Colombier }
4203e12c5d1SDavid du Colombier 
4213e12c5d1SDavid du Colombier char *
4223e12c5d1SDavid du Colombier strdup(char *s)
4233e12c5d1SDavid du Colombier {
4243e12c5d1SDavid du Colombier 	char *t;
4253e12c5d1SDavid du Colombier 
4263e12c5d1SDavid du Colombier 	t = emalloc(strlen(s) + 1);
4273e12c5d1SDavid du Colombier 	return strcpy(t, s);
4283e12c5d1SDavid du Colombier }
4293e12c5d1SDavid du Colombier 
4303e12c5d1SDavid du Colombier void
4313e12c5d1SDavid du Colombier setnames(File *f)
4323e12c5d1SDavid du Colombier {
4333e12c5d1SDavid du Colombier 	sprint(newfile, "%s%s", newroot, f->new);
4343e12c5d1SDavid du Colombier 	if(f->old){
4353e12c5d1SDavid du Colombier 		if(f->old[0] == '/')
4363e12c5d1SDavid du Colombier 			sprint(oldfile, "%s%s", oldroot, f->old);
4373e12c5d1SDavid du Colombier 		else
4383e12c5d1SDavid du Colombier 			strcpy(oldfile, f->old);
4393e12c5d1SDavid du Colombier 	}else
4403e12c5d1SDavid du Colombier 		sprint(oldfile, "%s%s", oldroot, f->new);
4413e12c5d1SDavid du Colombier 	if(strlen(newfile) >= sizeof newfile
4423e12c5d1SDavid du Colombier 	|| strlen(oldfile) >= sizeof oldfile)
4433e12c5d1SDavid du Colombier 		error("name overfile");
4443e12c5d1SDavid du Colombier }
4453e12c5d1SDavid du Colombier 
4463e12c5d1SDavid du Colombier void
4473e12c5d1SDavid du Colombier freefile(File *f)
4483e12c5d1SDavid du Colombier {
4493e12c5d1SDavid du Colombier 	if(f->old)
4503e12c5d1SDavid du Colombier 		free(f->old);
4513e12c5d1SDavid du Colombier 	if(f->new)
4523e12c5d1SDavid du Colombier 		free(f->new);
4533e12c5d1SDavid du Colombier 	free(f);
4543e12c5d1SDavid du Colombier }
4553e12c5d1SDavid du Colombier 
456*219b2ee8SDavid du Colombier /*
457*219b2ee8SDavid du Colombier  * skip all files in the proto that
458*219b2ee8SDavid du Colombier  * could be in the current dir
459*219b2ee8SDavid du Colombier  */
460*219b2ee8SDavid du Colombier void
461*219b2ee8SDavid du Colombier skipdir(void)
462*219b2ee8SDavid du Colombier {
463*219b2ee8SDavid du Colombier 	char *p, c;
464*219b2ee8SDavid du Colombier 	int level;
465*219b2ee8SDavid du Colombier 
466*219b2ee8SDavid du Colombier 	if(indent < 0)
467*219b2ee8SDavid du Colombier 		return;
468*219b2ee8SDavid du Colombier 	level = indent;
469*219b2ee8SDavid du Colombier 	for(;;){
470*219b2ee8SDavid du Colombier 		indent = 0;
471*219b2ee8SDavid du Colombier 		p = Brdline(b, '\n');
472*219b2ee8SDavid du Colombier 		lineno++;
473*219b2ee8SDavid du Colombier 		if(!p){
474*219b2ee8SDavid du Colombier 			indent = -1;
475*219b2ee8SDavid du Colombier 			return;
476*219b2ee8SDavid du Colombier 		}
477*219b2ee8SDavid du Colombier 		while((c = *p++) != '\n')
478*219b2ee8SDavid du Colombier 			if(c == ' ')
479*219b2ee8SDavid du Colombier 				indent++;
480*219b2ee8SDavid du Colombier 			else if(c == '\t')
481*219b2ee8SDavid du Colombier 				indent += 8;
482*219b2ee8SDavid du Colombier 			else
483*219b2ee8SDavid du Colombier 				break;
484*219b2ee8SDavid du Colombier 		if(indent <= level){
485*219b2ee8SDavid du Colombier 			Bseek(b, -Blinelen(b), 1);
486*219b2ee8SDavid du Colombier 			lineno--;
487*219b2ee8SDavid du Colombier 			return;
488*219b2ee8SDavid du Colombier 		}
489*219b2ee8SDavid du Colombier 	}
490*219b2ee8SDavid du Colombier }
491*219b2ee8SDavid du Colombier 
4923e12c5d1SDavid du Colombier File*
4933e12c5d1SDavid du Colombier getfile(File *old)
4943e12c5d1SDavid du Colombier {
4953e12c5d1SDavid du Colombier 	File *f;
4963e12c5d1SDavid du Colombier 	char elem[NAMELEN];
4973e12c5d1SDavid du Colombier 	char *p;
4983e12c5d1SDavid du Colombier 	int c;
4993e12c5d1SDavid du Colombier 
500*219b2ee8SDavid du Colombier 	if(indent < 0)
501*219b2ee8SDavid du Colombier 		return 0;
5023e12c5d1SDavid du Colombier loop:
5033e12c5d1SDavid du Colombier 	indent = 0;
5043e12c5d1SDavid du Colombier 	p = Brdline(b, '\n');
5053e12c5d1SDavid du Colombier 	lineno++;
5063e12c5d1SDavid du Colombier 	if(!p){
5073e12c5d1SDavid du Colombier 		indent = -1;
5083e12c5d1SDavid du Colombier 		return 0;
5093e12c5d1SDavid du Colombier 	}
510*219b2ee8SDavid du Colombier 	while((c = *p++) != '\n')
5113e12c5d1SDavid du Colombier 		if(c == ' ')
5123e12c5d1SDavid du Colombier 			indent++;
5133e12c5d1SDavid du Colombier 		else if(c == '\t')
5143e12c5d1SDavid du Colombier 			indent += 8;
5153e12c5d1SDavid du Colombier 		else
5163e12c5d1SDavid du Colombier 			break;
517*219b2ee8SDavid du Colombier 	if(c == '\n' || c == '#')
5183e12c5d1SDavid du Colombier 		goto loop;
5193e12c5d1SDavid du Colombier 	p--;
5203e12c5d1SDavid du Colombier 	f = emalloc(sizeof *f);
5213e12c5d1SDavid du Colombier 	p = getname(p, elem, sizeof elem);
522*219b2ee8SDavid du Colombier 	if(debug)
523*219b2ee8SDavid du Colombier 		fprint(2, "getfile: %s root %s\n", elem, old->new);
5243e12c5d1SDavid du Colombier 	f->new = mkpath(old->new, elem);
5253e12c5d1SDavid du Colombier 	f->elem = utfrrune(f->new, L'/') + 1;
5263e12c5d1SDavid du Colombier 	p = getmode(p, &f->mode);
5273e12c5d1SDavid du Colombier 	p = getname(p, f->uid, sizeof f->uid);
5283e12c5d1SDavid du Colombier 	if(!*f->uid)
5293e12c5d1SDavid du Colombier 		strcpy(f->uid, "-");
5303e12c5d1SDavid du Colombier 	p = getname(p, f->gid, sizeof f->gid);
5313e12c5d1SDavid du Colombier 	if(!*f->gid)
5323e12c5d1SDavid du Colombier 		strcpy(f->gid, "-");
5333e12c5d1SDavid du Colombier 	f->old = getpath(p);
5343e12c5d1SDavid du Colombier 	if(f->old && strcmp(f->old, "-") == 0){
5353e12c5d1SDavid du Colombier 		free(f->old);
5363e12c5d1SDavid du Colombier 		f->old = 0;
5373e12c5d1SDavid du Colombier 	}
5383e12c5d1SDavid du Colombier 	setnames(f);
539*219b2ee8SDavid du Colombier 
540*219b2ee8SDavid du Colombier 	if(debug)
541*219b2ee8SDavid du Colombier 		printfile(f);
542*219b2ee8SDavid du Colombier 
5433e12c5d1SDavid du Colombier 	return f;
5443e12c5d1SDavid du Colombier }
5453e12c5d1SDavid du Colombier 
5463e12c5d1SDavid du Colombier char*
5473e12c5d1SDavid du Colombier getpath(char *p)
5483e12c5d1SDavid du Colombier {
549*219b2ee8SDavid du Colombier 	char *q, *new;
550*219b2ee8SDavid du Colombier 	int c, n;
5513e12c5d1SDavid du Colombier 
5523e12c5d1SDavid du Colombier 	while((c = *p) == ' ' || c == '\t')
5533e12c5d1SDavid du Colombier 		p++;
5543e12c5d1SDavid du Colombier 	q = p;
555*219b2ee8SDavid du Colombier 	while((c = *q) != '\n' && c != ' ' && c != '\t')
5563e12c5d1SDavid du Colombier 		q++;
557*219b2ee8SDavid du Colombier 	if(q == p)
5583e12c5d1SDavid du Colombier 		return 0;
559*219b2ee8SDavid du Colombier 	n = q - p;
560*219b2ee8SDavid du Colombier 	new = emalloc(n + 1);
561*219b2ee8SDavid du Colombier 	memcpy(new, p, n);
562*219b2ee8SDavid du Colombier 	new[n] = 0;
563*219b2ee8SDavid du Colombier 	return new;
5643e12c5d1SDavid du Colombier }
5653e12c5d1SDavid du Colombier 
5663e12c5d1SDavid du Colombier char*
5673e12c5d1SDavid du Colombier getname(char *p, char *buf, int len)
5683e12c5d1SDavid du Colombier {
5693e12c5d1SDavid du Colombier 	char *s;
5703e12c5d1SDavid du Colombier 	int i, c;
5713e12c5d1SDavid du Colombier 
5723e12c5d1SDavid du Colombier 	while((c = *p) == ' ' || c == '\t')
5733e12c5d1SDavid du Colombier 		p++;
5743e12c5d1SDavid du Colombier 	i = 0;
575*219b2ee8SDavid du Colombier 	while((c = *p) != '\n' && c != ' ' && c != '\t'){
5763e12c5d1SDavid du Colombier 		if(i < len)
5773e12c5d1SDavid du Colombier 			buf[i++] = c;
5783e12c5d1SDavid du Colombier 		p++;
5793e12c5d1SDavid du Colombier 	}
5803e12c5d1SDavid du Colombier 	if(i == len){
5813e12c5d1SDavid du Colombier 		buf[len-1] = '\0';
5823e12c5d1SDavid du Colombier 		warn("name %s too long; truncated", buf);
5833e12c5d1SDavid du Colombier 	}else
5843e12c5d1SDavid du Colombier 		buf[i] = '\0';
5853e12c5d1SDavid du Colombier 
5863e12c5d1SDavid du Colombier 	if(strcmp(buf, "$cputype") == 0)
5873e12c5d1SDavid du Colombier 		strcpy(buf, cputype);
5883e12c5d1SDavid du Colombier 	else if(buf[0] == '$'){
5893e12c5d1SDavid du Colombier 		s = getenv(buf+1);
5903e12c5d1SDavid du Colombier 		if(s == 0)
5913e12c5d1SDavid du Colombier 			error("can't read environment variable %s", buf+1);
5923e12c5d1SDavid du Colombier 		strncpy(buf, s, NAMELEN-1);
5933e12c5d1SDavid du Colombier 		buf[NAMELEN-1] = '\0';
5943e12c5d1SDavid du Colombier 		free(s);
5953e12c5d1SDavid du Colombier 	}
5963e12c5d1SDavid du Colombier 	return p;
5973e12c5d1SDavid du Colombier }
5983e12c5d1SDavid du Colombier 
5993e12c5d1SDavid du Colombier char*
6003e12c5d1SDavid du Colombier getmode(char *p, ulong *mode)
6013e12c5d1SDavid du Colombier {
6023e12c5d1SDavid du Colombier 	char buf[7], *s;
6033e12c5d1SDavid du Colombier 	ulong m;
6043e12c5d1SDavid du Colombier 
6053e12c5d1SDavid du Colombier 	*mode = ~0;
6063e12c5d1SDavid du Colombier 	p = getname(p, buf, sizeof buf);
6073e12c5d1SDavid du Colombier 	s = buf;
6083e12c5d1SDavid du Colombier 	if(!*s || strcmp(s, "-") == 0)
6093e12c5d1SDavid du Colombier 		return p;
6103e12c5d1SDavid du Colombier 	m = 0;
6113e12c5d1SDavid du Colombier 	if(*s == 'd'){
6123e12c5d1SDavid du Colombier 		m |= CHDIR;
6133e12c5d1SDavid du Colombier 		s++;
6143e12c5d1SDavid du Colombier 	}
6153e12c5d1SDavid du Colombier 	if(*s == 'a'){
6163e12c5d1SDavid du Colombier 		m |= CHAPPEND;
6173e12c5d1SDavid du Colombier 		s++;
6183e12c5d1SDavid du Colombier 	}
6193e12c5d1SDavid du Colombier 	if(*s == 'l'){
6203e12c5d1SDavid du Colombier 		m |= CHEXCL;
6213e12c5d1SDavid du Colombier 		s++;
6223e12c5d1SDavid du Colombier 	}
6233e12c5d1SDavid du Colombier 	if(s[0] < '0' || s[0] > '7'
6243e12c5d1SDavid du Colombier 	|| s[1] < '0' || s[1] > '7'
6253e12c5d1SDavid du Colombier 	|| s[2] < '0' || s[2] > '7'
6263e12c5d1SDavid du Colombier 	|| s[3]){
6273e12c5d1SDavid du Colombier 		warn("bad mode specification %s", buf);
6283e12c5d1SDavid du Colombier 		return p;
6293e12c5d1SDavid du Colombier 	}
6303e12c5d1SDavid du Colombier 	*mode = m | strtoul(s, 0, 8);
6313e12c5d1SDavid du Colombier 	return p;
6323e12c5d1SDavid du Colombier }
6333e12c5d1SDavid du Colombier 
6343e12c5d1SDavid du Colombier void
6353e12c5d1SDavid du Colombier setusers(void)
6363e12c5d1SDavid du Colombier {
6373e12c5d1SDavid du Colombier 	File file;
6383e12c5d1SDavid du Colombier 	int m;
6393e12c5d1SDavid du Colombier 
6403e12c5d1SDavid du Colombier 	if(fskind != Kfs)
6413e12c5d1SDavid du Colombier 		return;
6423e12c5d1SDavid du Colombier 	m = modes;
6433e12c5d1SDavid du Colombier 	modes = 1;
6443e12c5d1SDavid du Colombier 	strcpy(file.uid, "adm");
6453e12c5d1SDavid du Colombier 	strcpy(file.gid, "adm");
6463e12c5d1SDavid du Colombier 	file.mode = CHDIR|0775;
6473e12c5d1SDavid du Colombier 	file.new = "/adm";
6483e12c5d1SDavid du Colombier 	file.elem = "adm";
6493e12c5d1SDavid du Colombier 	file.old = 0;
6503e12c5d1SDavid du Colombier 	setnames(&file);
6513e12c5d1SDavid du Colombier 	mkfile(&file);
6523e12c5d1SDavid du Colombier 	file.new = "/adm/users";
6533e12c5d1SDavid du Colombier 	file.old = users;
6543e12c5d1SDavid du Colombier 	file.elem = "users";
6553e12c5d1SDavid du Colombier 	file.mode = 0664;
6563e12c5d1SDavid du Colombier 	setnames(&file);
6573e12c5d1SDavid du Colombier 	mkfile(&file);
6583e12c5d1SDavid du Colombier 	kfscmd("user");
6593e12c5d1SDavid du Colombier 	mkfile(&file);
6603e12c5d1SDavid du Colombier 	file.mode = CHDIR|0775;
6613e12c5d1SDavid du Colombier 	file.new = "/adm";
6623e12c5d1SDavid du Colombier 	file.old = "/adm";
6633e12c5d1SDavid du Colombier 	file.elem = "adm";
6643e12c5d1SDavid du Colombier 	setnames(&file);
6653e12c5d1SDavid du Colombier 	mkfile(&file);
6663e12c5d1SDavid du Colombier 	modes = m;
6673e12c5d1SDavid du Colombier }
6683e12c5d1SDavid du Colombier 
6693e12c5d1SDavid du Colombier void
6703e12c5d1SDavid du Colombier mountkfs(char *name)
6713e12c5d1SDavid du Colombier {
6723e12c5d1SDavid du Colombier 	char kname[2*NAMELEN];
6733e12c5d1SDavid du Colombier 
6743e12c5d1SDavid du Colombier 	if(fskind != Kfs)
6753e12c5d1SDavid du Colombier 		return;
6763e12c5d1SDavid du Colombier 	if(name[0])
6773e12c5d1SDavid du Colombier 		sprint(kname, "/srv/kfs.%s", name);
6783e12c5d1SDavid du Colombier 	else
6793e12c5d1SDavid du Colombier 		strcpy(kname, "/srv/kfs");
6803e12c5d1SDavid du Colombier 	sfd = open(kname, ORDWR);
6813e12c5d1SDavid du Colombier 	if(sfd < 0){
6823e12c5d1SDavid du Colombier 		fprint(2, "can't open %s\n", kname);
6833e12c5d1SDavid du Colombier 		exits("open /srv/kfs");
6843e12c5d1SDavid du Colombier 	}
685*219b2ee8SDavid du Colombier 	if(amount(sfd, "/n/kfs", MREPL|MCREATE, "") < 0){
6863e12c5d1SDavid du Colombier 		fprint(2, "can't mount kfs on /n/kfs\n");
6873e12c5d1SDavid du Colombier 		exits("mount kfs");
6883e12c5d1SDavid du Colombier 	}
6893e12c5d1SDavid du Colombier 	close(sfd);
6903e12c5d1SDavid du Colombier 	strcat(kname, ".cmd");
6913e12c5d1SDavid du Colombier 	sfd = open(kname, ORDWR);
6923e12c5d1SDavid du Colombier 	if(sfd < 0){
6933e12c5d1SDavid du Colombier 		fprint(2, "can't open %s\n", kname);
6943e12c5d1SDavid du Colombier 		exits("open /srv/kfs");
6953e12c5d1SDavid du Colombier 	}
6963e12c5d1SDavid du Colombier }
6973e12c5d1SDavid du Colombier 
6983e12c5d1SDavid du Colombier void
6993e12c5d1SDavid du Colombier kfscmd(char *cmd)
7003e12c5d1SDavid du Colombier {
7013e12c5d1SDavid du Colombier 	char buf[4*1024];
7023e12c5d1SDavid du Colombier 	int n;
7033e12c5d1SDavid du Colombier 
7043e12c5d1SDavid du Colombier 	if(fskind != Kfs)
7053e12c5d1SDavid du Colombier 		return;
7063e12c5d1SDavid du Colombier 	if(write(sfd, cmd, strlen(cmd)) != strlen(cmd)){
7073e12c5d1SDavid du Colombier 		fprint(2, "%s: error writing %s: %r", prog, cmd);
7083e12c5d1SDavid du Colombier 		return;
7093e12c5d1SDavid du Colombier 	}
7103e12c5d1SDavid du Colombier 	for(;;){
7113e12c5d1SDavid du Colombier 		n = read(sfd, buf, sizeof buf - 1);
7123e12c5d1SDavid du Colombier 		if(n <= 0)
7133e12c5d1SDavid du Colombier 			return;
7143e12c5d1SDavid du Colombier 		buf[n] = '\0';
7153e12c5d1SDavid du Colombier 		if(strcmp(buf, "done") == 0 || strcmp(buf, "success") == 0)
7163e12c5d1SDavid du Colombier 			return;
7173e12c5d1SDavid du Colombier 		if(strcmp(buf, "unknown command") == 0){
7183e12c5d1SDavid du Colombier 			fprint(2, "%s: command %s not recognized\n", prog, cmd);
7193e12c5d1SDavid du Colombier 			return;
7203e12c5d1SDavid du Colombier 		}
7213e12c5d1SDavid du Colombier 	}
7223e12c5d1SDavid du Colombier }
7233e12c5d1SDavid du Colombier 
7243e12c5d1SDavid du Colombier void *
7253e12c5d1SDavid du Colombier emalloc(ulong n)
7263e12c5d1SDavid du Colombier {
7273e12c5d1SDavid du Colombier 	void *p;
7283e12c5d1SDavid du Colombier 
7293e12c5d1SDavid du Colombier 	if((p = malloc(n)) == 0)
7303e12c5d1SDavid du Colombier 		error("out of memory");
7313e12c5d1SDavid du Colombier 	return p;
7323e12c5d1SDavid du Colombier }
7333e12c5d1SDavid du Colombier 
7343e12c5d1SDavid du Colombier void
7353e12c5d1SDavid du Colombier error(char *fmt, ...)
7363e12c5d1SDavid du Colombier {
7373e12c5d1SDavid du Colombier 	char buf[1024];
7383e12c5d1SDavid du Colombier 
7393e12c5d1SDavid du Colombier 	sprint(buf, "%s: %s: %d: ", prog, proto, lineno);
7403e12c5d1SDavid du Colombier 	doprint(buf+strlen(buf), buf+sizeof(buf), fmt, (&fmt+1));
7413e12c5d1SDavid du Colombier 	fprint(2, "%s\n", buf);
7423e12c5d1SDavid du Colombier 	kfscmd("disallow");
7433e12c5d1SDavid du Colombier 	kfscmd("sync");
7443e12c5d1SDavid du Colombier 	exits(0);
7453e12c5d1SDavid du Colombier }
7463e12c5d1SDavid du Colombier 
7473e12c5d1SDavid du Colombier void
7483e12c5d1SDavid du Colombier warn(char *fmt, ...)
7493e12c5d1SDavid du Colombier {
7503e12c5d1SDavid du Colombier 	char buf[1024];
7513e12c5d1SDavid du Colombier 
7523e12c5d1SDavid du Colombier 	sprint(buf, "%s: %s: %d: ", prog, proto, lineno);
7533e12c5d1SDavid du Colombier 	doprint(buf+strlen(buf), buf+sizeof(buf), fmt, (&fmt+1));
7543e12c5d1SDavid du Colombier 	fprint(2, "%s\n", buf);
7553e12c5d1SDavid du Colombier }
7563e12c5d1SDavid du Colombier 
7573e12c5d1SDavid du Colombier void
758*219b2ee8SDavid du Colombier printfile(File *f)
759*219b2ee8SDavid du Colombier {
760*219b2ee8SDavid du Colombier 	if(f->old)
761*219b2ee8SDavid du Colombier 		fprint(2, "%s from %s %s %s %o\n", f->new, f->old, f->uid, f->gid, f->mode);
762*219b2ee8SDavid du Colombier 	else
763*219b2ee8SDavid du Colombier 		fprint(2, "%s %s %s %o\n", f->new, f->uid, f->gid, f->mode);
764*219b2ee8SDavid du Colombier }
765*219b2ee8SDavid du Colombier 
766*219b2ee8SDavid du Colombier void
7673e12c5d1SDavid du Colombier usage(void)
7683e12c5d1SDavid du Colombier {
7693e12c5d1SDavid du Colombier 	fprint(2, "usage: %s [-aprv] [-z n] [-n kfsname] [-u userfile] [-s src-fs] proto ...\n", prog);
7703e12c5d1SDavid du Colombier 	exits("usage");
7713e12c5d1SDavid du Colombier }
772