xref: /plan9/sys/src/cmd/9660srv/main.c (revision 28eece76e251dd6da5b00eb078b51cec7fd6eff9)
13e12c5d1SDavid du Colombier #include <u.h>
23e12c5d1SDavid du Colombier #include <libc.h>
3219b2ee8SDavid du Colombier #include <auth.h>
43e12c5d1SDavid du Colombier #include <fcall.h>
53e12c5d1SDavid du Colombier #include "dat.h"
63e12c5d1SDavid du Colombier #include "fns.h"
73e12c5d1SDavid du Colombier 
89a747e4fSDavid du Colombier enum
99a747e4fSDavid du Colombier {
109a747e4fSDavid du Colombier 	Maxfdata	= 8192,
119a747e4fSDavid du Colombier 	Maxiosize	= IOHDRSZ+Maxfdata,
129a747e4fSDavid du Colombier };
139a747e4fSDavid du Colombier 
149a747e4fSDavid du Colombier void io(int);
159a747e4fSDavid du Colombier void rversion(void);
169a747e4fSDavid du Colombier void	rattach(void);
179a747e4fSDavid du Colombier void	rauth(void);
189a747e4fSDavid du Colombier void	rclunk(void);
199a747e4fSDavid du Colombier void	rcreate(void);
209a747e4fSDavid du Colombier void	rflush(void);
219a747e4fSDavid du Colombier void	ropen(void);
229a747e4fSDavid du Colombier void	rread(void);
239a747e4fSDavid du Colombier void	rremove(void);
249a747e4fSDavid du Colombier void	rsession(void);
259a747e4fSDavid du Colombier void	rstat(void);
269a747e4fSDavid du Colombier void	rwalk(void);
279a747e4fSDavid du Colombier void	rwrite(void);
289a747e4fSDavid du Colombier void	rwstat(void);
299a747e4fSDavid du Colombier 
303e12c5d1SDavid du Colombier static int	openflags(int);
313e12c5d1SDavid du Colombier static void	rmservice(void);
323e12c5d1SDavid du Colombier static void	usage(void);
333e12c5d1SDavid du Colombier 
349a747e4fSDavid du Colombier #define Reqsize (sizeof(Fcall)+Maxfdata)
359a747e4fSDavid du Colombier 
369a747e4fSDavid du Colombier Fcall *req;
379a747e4fSDavid du Colombier Fcall *rep;
389a747e4fSDavid du Colombier 
399a747e4fSDavid du Colombier uchar mdata[Maxiosize];
409a747e4fSDavid du Colombier char fdata[Maxfdata];
419a747e4fSDavid du Colombier uchar statbuf[STATMAX];
429a747e4fSDavid du Colombier int errno;
439a747e4fSDavid du Colombier 
449a747e4fSDavid du Colombier static char	srvfile[64];
453e12c5d1SDavid du Colombier 
463e12c5d1SDavid du Colombier extern Xfsub	*xsublist[];
47208510e1SDavid du Colombier extern int	nclust;
483e12c5d1SDavid du Colombier 
493e12c5d1SDavid du Colombier jmp_buf	err_lab[16];
503e12c5d1SDavid du Colombier int	nerr_lab;
519a747e4fSDavid du Colombier char	err_msg[ERRMAX];
523e12c5d1SDavid du Colombier 
533e12c5d1SDavid du Colombier int	chatty;
547dd7cddfSDavid du Colombier int	nojoliet;
557dd7cddfSDavid du Colombier int	noplan9;
5659cc4ca5SDavid du Colombier int norock;
573e12c5d1SDavid du Colombier 
589a747e4fSDavid du Colombier void	(*fcalls[])(void) = {
599a747e4fSDavid du Colombier 	[Tversion]	rversion,
609a747e4fSDavid du Colombier 	[Tflush]	rflush,
619a747e4fSDavid du Colombier 	[Tauth]	rauth,
629a747e4fSDavid du Colombier 	[Tattach]	rattach,
639a747e4fSDavid du Colombier 	[Twalk]		rwalk,
649a747e4fSDavid du Colombier 	[Topen]		ropen,
659a747e4fSDavid du Colombier 	[Tcreate]	rcreate,
669a747e4fSDavid du Colombier 	[Tread]		rread,
679a747e4fSDavid du Colombier 	[Twrite]	rwrite,
689a747e4fSDavid du Colombier 	[Tclunk]	rclunk,
699a747e4fSDavid du Colombier 	[Tremove]	rremove,
709a747e4fSDavid du Colombier 	[Tstat]		rstat,
719a747e4fSDavid du Colombier 	[Twstat]	rwstat,
729a747e4fSDavid du Colombier };
739a747e4fSDavid du Colombier 
743e12c5d1SDavid du Colombier void
main(int argc,char ** argv)753e12c5d1SDavid du Colombier main(int argc, char **argv)
763e12c5d1SDavid du Colombier {
779a747e4fSDavid du Colombier 	int srvfd, pipefd[2], stdio;
783e12c5d1SDavid du Colombier 	Xfsub **xs;
793e12c5d1SDavid du Colombier 
803e12c5d1SDavid du Colombier 	stdio = 0;
813e12c5d1SDavid du Colombier 	ARGBEGIN {
82208510e1SDavid du Colombier 	case '9':
83208510e1SDavid du Colombier 		noplan9 = 1;
84208510e1SDavid du Colombier 		break;
85208510e1SDavid du Colombier 	case 'c':
86208510e1SDavid du Colombier 		nclust = atoi(EARGF(usage()));
87208510e1SDavid du Colombier 		if (nclust <= 0)
88208510e1SDavid du Colombier 			sysfatal("nclust %d non-positive", nclust);
893e12c5d1SDavid du Colombier 		break;
903e12c5d1SDavid du Colombier 	case 'f':
91208510e1SDavid du Colombier 		deffile = EARGF(usage());
92208510e1SDavid du Colombier 		break;
93208510e1SDavid du Colombier 	case 'r':
94208510e1SDavid du Colombier 		norock = 1;
953e12c5d1SDavid du Colombier 		break;
963e12c5d1SDavid du Colombier 	case 's':
973e12c5d1SDavid du Colombier 		stdio = 1;
983e12c5d1SDavid du Colombier 		break;
99208510e1SDavid du Colombier 	case 'v':
100208510e1SDavid du Colombier 		chatty = 1;
1017dd7cddfSDavid du Colombier 		break;
1027dd7cddfSDavid du Colombier 	case 'J':
1037dd7cddfSDavid du Colombier 		nojoliet = 1;
1047dd7cddfSDavid du Colombier 		break;
1053e12c5d1SDavid du Colombier 	default:
1063e12c5d1SDavid du Colombier 		usage();
1073e12c5d1SDavid du Colombier 	} ARGEND
1083e12c5d1SDavid du Colombier 
1093e12c5d1SDavid du Colombier 	switch(argc) {
1103e12c5d1SDavid du Colombier 	case 0:
1113e12c5d1SDavid du Colombier 		break;
1123e12c5d1SDavid du Colombier 	case 1:
1133e12c5d1SDavid du Colombier 		srvname = argv[0];
1143e12c5d1SDavid du Colombier 		break;
1153e12c5d1SDavid du Colombier 	default:
1163e12c5d1SDavid du Colombier 		usage();
1173e12c5d1SDavid du Colombier 	}
1183e12c5d1SDavid du Colombier 
1193e12c5d1SDavid du Colombier 	iobuf_init();
1203e12c5d1SDavid du Colombier 	for(xs=xsublist; *xs; xs++)
1213e12c5d1SDavid du Colombier 		(*(*xs)->reset)();
1223e12c5d1SDavid du Colombier 
1233e12c5d1SDavid du Colombier 	if(stdio) {
1243e12c5d1SDavid du Colombier 		pipefd[0] = 0;
1253e12c5d1SDavid du Colombier 		pipefd[1] = 1;
1263e12c5d1SDavid du Colombier 	} else {
1273e12c5d1SDavid du Colombier 		close(0);
1283e12c5d1SDavid du Colombier 		close(1);
1293e12c5d1SDavid du Colombier 		open("/dev/null", OREAD);
1303e12c5d1SDavid du Colombier 		open("/dev/null", OWRITE);
1313e12c5d1SDavid du Colombier 		if(pipe(pipefd) < 0)
1323e12c5d1SDavid du Colombier 			panic(1, "pipe");
1333e12c5d1SDavid du Colombier 		sprint(srvfile, "/srv/%s", srvname);
134b7b24591SDavid du Colombier 		srvfd = create(srvfile, OWRITE|ORCLOSE, 0600);
1353e12c5d1SDavid du Colombier 		if(srvfd < 0)
1363e12c5d1SDavid du Colombier 			panic(1, srvfile);
1373e12c5d1SDavid du Colombier 		fprint(srvfd, "%d", pipefd[0]);
1383e12c5d1SDavid du Colombier 		close(pipefd[0]);
1393e12c5d1SDavid du Colombier 		fprint(2, "%s %d: serving %s\n", argv0, getpid(), srvfile);
1403e12c5d1SDavid du Colombier 	}
1413e12c5d1SDavid du Colombier 	srvfd = pipefd[1];
1423e12c5d1SDavid du Colombier 
1433e12c5d1SDavid du Colombier 	switch(rfork(RFNOWAIT|RFNOTEG|RFFDG|RFPROC)){
1443e12c5d1SDavid du Colombier 	case -1:
1453e12c5d1SDavid du Colombier 		panic(1, "fork");
1463e12c5d1SDavid du Colombier 	default:
1473e12c5d1SDavid du Colombier 		_exits(0);
1483e12c5d1SDavid du Colombier 	case 0:
1493e12c5d1SDavid du Colombier 		break;
1503e12c5d1SDavid du Colombier 	}
1513e12c5d1SDavid du Colombier 
1529a747e4fSDavid du Colombier 	io(srvfd);
1539a747e4fSDavid du Colombier 	exits(0);
1549a747e4fSDavid du Colombier }
1559a747e4fSDavid du Colombier 
1569a747e4fSDavid du Colombier void
io(int srvfd)1579a747e4fSDavid du Colombier io(int srvfd)
1589a747e4fSDavid du Colombier {
1599a747e4fSDavid du Colombier 	int n, pid;
1609a747e4fSDavid du Colombier 	Fcall xreq, xrep;
1619a747e4fSDavid du Colombier 
1629a747e4fSDavid du Colombier 	req = &xreq;
1639a747e4fSDavid du Colombier 	rep = &xrep;
1649a747e4fSDavid du Colombier 	pid = getpid();
1659a747e4fSDavid du Colombier 	fmtinstall('F', fcallfmt);
1669a747e4fSDavid du Colombier 
1679a747e4fSDavid du Colombier 	for(;;){
1689a747e4fSDavid du Colombier 		/*
1699a747e4fSDavid du Colombier 		 * reading from a pipe or a network device
1709a747e4fSDavid du Colombier 		 * will give an error after a few eof reads.
1719a747e4fSDavid du Colombier 		 * however, we cannot tell the difference
1729a747e4fSDavid du Colombier 		 * between a zero-length read and an interrupt
1739a747e4fSDavid du Colombier 		 * on the processes writing to us,
1749a747e4fSDavid du Colombier 		 * so we wait for the error.
1759a747e4fSDavid du Colombier 		 */
1769a747e4fSDavid du Colombier 		n = read9pmsg(srvfd, mdata, sizeof mdata);
1779a747e4fSDavid du Colombier 		if(n < 0)
1783e12c5d1SDavid du Colombier 			break;
1799a747e4fSDavid du Colombier 		if(n == 0)
1809a747e4fSDavid du Colombier 			continue;
1819a747e4fSDavid du Colombier 		if(convM2S(mdata, n, req) == 0)
1829a747e4fSDavid du Colombier 			continue;
1839a747e4fSDavid du Colombier 
1849a747e4fSDavid du Colombier 		if(chatty)
1859a747e4fSDavid du Colombier 			fprint(2, "9660srv %d:<-%F\n", pid, req);
1869a747e4fSDavid du Colombier 
1879a747e4fSDavid du Colombier 		errno = 0;
1889a747e4fSDavid du Colombier 		if(!waserror()){
1899a747e4fSDavid du Colombier 			err_msg[0] = 0;
19022a127bbSDavid du Colombier 			if(req->type >= nelem(fcalls) || !fcalls[req->type])
1919a747e4fSDavid du Colombier 				error("bad fcall type");
1929a747e4fSDavid du Colombier 			(*fcalls[req->type])();
1933e12c5d1SDavid du Colombier 			poperror();
1943e12c5d1SDavid du Colombier 		}
1959a747e4fSDavid du Colombier 
1969a747e4fSDavid du Colombier 		if(err_msg[0]){
1979a747e4fSDavid du Colombier 			rep->type = Rerror;
1989a747e4fSDavid du Colombier 			rep->ename = err_msg;
1999a747e4fSDavid du Colombier 		}else{
2009a747e4fSDavid du Colombier 			rep->type = req->type + 1;
2019a747e4fSDavid du Colombier 			rep->fid = req->fid;
2029a747e4fSDavid du Colombier 		}
2039a747e4fSDavid du Colombier 		rep->tag = req->tag;
2049a747e4fSDavid du Colombier 
2059a747e4fSDavid du Colombier 		if(chatty)
2069a747e4fSDavid du Colombier 			fprint(2, "9660srv %d:->%F\n", pid, rep);
2079a747e4fSDavid du Colombier 		n = convS2M(rep, mdata, sizeof mdata);
2089a747e4fSDavid du Colombier 		if(n == 0)
2099a747e4fSDavid du Colombier 			panic(1, "convS2M error on write");
2109a747e4fSDavid du Colombier 		if(write(srvfd, mdata, n) != n)
2119a747e4fSDavid du Colombier 			panic(1, "mount write");
2123e12c5d1SDavid du Colombier 		if(nerr_lab != 0)
2133e12c5d1SDavid du Colombier 			panic(0, "err stack %d: %lux %lux %lux %lux %lux %lux", nerr_lab,
2143e12c5d1SDavid du Colombier 			err_lab[0][JMPBUFPC], err_lab[1][JMPBUFPC],
2153e12c5d1SDavid du Colombier 			err_lab[2][JMPBUFPC], err_lab[3][JMPBUFPC],
2163e12c5d1SDavid du Colombier 			err_lab[4][JMPBUFPC], err_lab[5][JMPBUFPC]);
2173e12c5d1SDavid du Colombier 	}
2189a747e4fSDavid du Colombier 	chat("server shut down");
2193e12c5d1SDavid du Colombier }
2203e12c5d1SDavid du Colombier 
2213e12c5d1SDavid du Colombier static void
usage(void)2223e12c5d1SDavid du Colombier usage(void)
2233e12c5d1SDavid du Colombier {
22459cc4ca5SDavid du Colombier 	fprint(2, "usage: %s [-v] [-9Jr] [-s] [-f devicefile] [srvname]\n", argv0);
2253e12c5d1SDavid du Colombier 	exits("usage");
2263e12c5d1SDavid du Colombier }
2273e12c5d1SDavid du Colombier 
2283e12c5d1SDavid du Colombier void
error(char * p)2293e12c5d1SDavid du Colombier error(char *p)
2303e12c5d1SDavid du Colombier {
2319a747e4fSDavid du Colombier 	strecpy(err_msg, err_msg+sizeof err_msg, p);
2323e12c5d1SDavid du Colombier 	nexterror();
2333e12c5d1SDavid du Colombier }
2343e12c5d1SDavid du Colombier 
2353e12c5d1SDavid du Colombier void
nexterror(void)2363e12c5d1SDavid du Colombier nexterror(void)
2373e12c5d1SDavid du Colombier {
2383e12c5d1SDavid du Colombier 	longjmp(err_lab[--nerr_lab], 1);
2393e12c5d1SDavid du Colombier }
2403e12c5d1SDavid du Colombier 
2413e12c5d1SDavid du Colombier void*
ealloc(long n)2423e12c5d1SDavid du Colombier ealloc(long n)
2433e12c5d1SDavid du Colombier {
2443e12c5d1SDavid du Colombier 	void *p;
2453e12c5d1SDavid du Colombier 
2463e12c5d1SDavid du Colombier 	p = malloc(n);
2473e12c5d1SDavid du Colombier 	if(p == 0)
2483e12c5d1SDavid du Colombier 		error("no memory");
2493e12c5d1SDavid du Colombier 	return p;
2503e12c5d1SDavid du Colombier }
2513e12c5d1SDavid du Colombier 
2529a747e4fSDavid du Colombier void
setnames(Dir * d,char * n)2539a747e4fSDavid du Colombier setnames(Dir *d, char *n)
2543e12c5d1SDavid du Colombier {
2559a747e4fSDavid du Colombier 	d->name = n;
2569a747e4fSDavid du Colombier 	d->uid = n+Maxname;
2579a747e4fSDavid du Colombier 	d->gid = n+Maxname*2;
2589a747e4fSDavid du Colombier 	d->muid = n+Maxname*3;
2599a747e4fSDavid du Colombier 
2609a747e4fSDavid du Colombier 	d->name[0] = '\0';
2619a747e4fSDavid du Colombier 	d->uid[0] = '\0';
2629a747e4fSDavid du Colombier 	d->gid[0] = '\0';
2639a747e4fSDavid du Colombier 	d->muid[0] = '\0';
2643e12c5d1SDavid du Colombier }
2653e12c5d1SDavid du Colombier 
2669a747e4fSDavid du Colombier void
rversion(void)2679a747e4fSDavid du Colombier rversion(void)
2683e12c5d1SDavid du Colombier {
2699a747e4fSDavid du Colombier 	if(req->msize > Maxiosize)
2709a747e4fSDavid du Colombier 		rep->msize = Maxiosize;
2719a747e4fSDavid du Colombier 	else
2729a747e4fSDavid du Colombier 		rep->msize = req->msize;
2739a747e4fSDavid du Colombier 	rep->version = "9P2000";
2743e12c5d1SDavid du Colombier }
2753e12c5d1SDavid du Colombier 
2769a747e4fSDavid du Colombier void
rauth(void)2773e12c5d1SDavid du Colombier rauth(void)
2783e12c5d1SDavid du Colombier {
2799a747e4fSDavid du Colombier 	error("9660srv: authentication not required");
2803e12c5d1SDavid du Colombier }
2813e12c5d1SDavid du Colombier 
2829a747e4fSDavid du Colombier void
rflush(void)2833e12c5d1SDavid du Colombier rflush(void)
2843e12c5d1SDavid du Colombier {
2853e12c5d1SDavid du Colombier }
2863e12c5d1SDavid du Colombier 
2879a747e4fSDavid du Colombier void
rattach(void)2883e12c5d1SDavid du Colombier rattach(void)
2893e12c5d1SDavid du Colombier {
2903e12c5d1SDavid du Colombier 	Xfs *xf;
2919a747e4fSDavid du Colombier 	Xfile *root;
2923e12c5d1SDavid du Colombier 	Xfsub **xs;
2933e12c5d1SDavid du Colombier 
2949a747e4fSDavid du Colombier 	chat("attach(fid=%d,uname=\"%s\",aname=\"%s\")...",
2959a747e4fSDavid du Colombier 		req->fid, req->uname, req->aname);
2963e12c5d1SDavid du Colombier 
2973e12c5d1SDavid du Colombier 	if(waserror()){
2989a747e4fSDavid du Colombier 		xfile(req->fid, Clunk);
2993e12c5d1SDavid du Colombier 		nexterror();
3003e12c5d1SDavid du Colombier 	}
3019a747e4fSDavid du Colombier 	root = xfile(req->fid, Clean);
3029a747e4fSDavid du Colombier 	root->qid = (Qid){0, 0, QTDIR};
3033e12c5d1SDavid du Colombier 	root->xf = xf = ealloc(sizeof(Xfs));
3043e12c5d1SDavid du Colombier 	memset(xf, 0, sizeof(Xfs));
3053e12c5d1SDavid du Colombier 	xf->ref = 1;
3069a747e4fSDavid du Colombier 	xf->d = getxdata(req->aname);
3073e12c5d1SDavid du Colombier 
3083e12c5d1SDavid du Colombier 	for(xs=xsublist; *xs; xs++)
3093e12c5d1SDavid du Colombier 		if((*(*xs)->attach)(root) >= 0){
3103e12c5d1SDavid du Colombier 			poperror();
3113e12c5d1SDavid du Colombier 			xf->s = *xs;
3123e12c5d1SDavid du Colombier 			xf->rootqid = root->qid;
3139a747e4fSDavid du Colombier 			rep->qid = root->qid;
3143e12c5d1SDavid du Colombier 			return;
3153e12c5d1SDavid du Colombier 		}
3163e12c5d1SDavid du Colombier 	error("unknown format");
3173e12c5d1SDavid du Colombier }
3183e12c5d1SDavid du Colombier 
3199a747e4fSDavid du Colombier Xfile*
doclone(Xfile * of,int newfid)3209a747e4fSDavid du Colombier doclone(Xfile *of, int newfid)
3213e12c5d1SDavid du Colombier {
3229a747e4fSDavid du Colombier 	Xfile *nf, *next;
3233e12c5d1SDavid du Colombier 
3249a747e4fSDavid du Colombier 	nf = xfile(newfid, Clean);
3253e12c5d1SDavid du Colombier 	if(waserror()){
3269a747e4fSDavid du Colombier 		xfile(newfid, Clunk);
3273e12c5d1SDavid du Colombier 		nexterror();
3283e12c5d1SDavid du Colombier 	}
3293e12c5d1SDavid du Colombier 	next = nf->next;
3303e12c5d1SDavid du Colombier 	*nf = *of;
3313e12c5d1SDavid du Colombier 	nf->next = next;
3329a747e4fSDavid du Colombier 	nf->fid = newfid;
3333e12c5d1SDavid du Colombier 	refxfs(nf->xf, 1);
3343e12c5d1SDavid du Colombier 	if(nf->len){
3353e12c5d1SDavid du Colombier 		nf->ptr = ealloc(nf->len);
3363e12c5d1SDavid du Colombier 		memmove(nf->ptr, of->ptr, nf->len);
3373e12c5d1SDavid du Colombier 	}else
3383e12c5d1SDavid du Colombier 		nf->ptr = of->ptr;
3393e12c5d1SDavid du Colombier 	(*of->xf->s->clone)(of, nf);
3403e12c5d1SDavid du Colombier 	poperror();
3419a747e4fSDavid du Colombier 	return nf;
3423e12c5d1SDavid du Colombier }
3433e12c5d1SDavid du Colombier 
3449a747e4fSDavid du Colombier void
rwalk(void)3453e12c5d1SDavid du Colombier rwalk(void)
3463e12c5d1SDavid du Colombier {
3479a747e4fSDavid du Colombier 	Xfile *f, *nf;
3489a747e4fSDavid du Colombier 	Isofile *oldptr;
3499a747e4fSDavid du Colombier 	int oldlen;
3509a747e4fSDavid du Colombier 	Qid oldqid;
3513e12c5d1SDavid du Colombier 
3529a747e4fSDavid du Colombier 	rep->nwqid = 0;
3539a747e4fSDavid du Colombier 	nf = nil;
3549a747e4fSDavid du Colombier 	f = xfile(req->fid, Asis);
3559a747e4fSDavid du Colombier 	if(req->fid != req->newfid)
3569a747e4fSDavid du Colombier 		f = nf = doclone(f, req->newfid);
3579a747e4fSDavid du Colombier 
3589a747e4fSDavid du Colombier 	/* save old state in case of error */
3599a747e4fSDavid du Colombier 	oldqid = f->qid;
3609a747e4fSDavid du Colombier 	oldlen = f->len;
3619a747e4fSDavid du Colombier 	oldptr = f->ptr;
3629a747e4fSDavid du Colombier 	if(oldlen){
3639a747e4fSDavid du Colombier 		oldptr = ealloc(oldlen);
3649a747e4fSDavid du Colombier 		memmove(oldptr, f->ptr, oldlen);
3659a747e4fSDavid du Colombier 	}
3669a747e4fSDavid du Colombier 
3679a747e4fSDavid du Colombier 	if(waserror()){
368*28eece76SDavid du Colombier 		/*
369*28eece76SDavid du Colombier 		 * if nf != nil, nf == f, which is derived from req->newfid,
370*28eece76SDavid du Colombier 		 * so we can't clunk req->newfid with xfile, which would put
371*28eece76SDavid du Colombier 		 * f back on the free list, until we're done with f below.
372*28eece76SDavid du Colombier 		 */
3739a747e4fSDavid du Colombier 		if(rep->nwqid == req->nwname){
3749a747e4fSDavid du Colombier 			if(oldlen)
3759a747e4fSDavid du Colombier 				free(oldptr);
3769a747e4fSDavid du Colombier 		}else{
3779a747e4fSDavid du Colombier 			/* restore previous state */
3789a747e4fSDavid du Colombier 			f->qid = oldqid;
3799a747e4fSDavid du Colombier 			if(f->len)
3809a747e4fSDavid du Colombier 				free(f->ptr);
3819a747e4fSDavid du Colombier 			f->ptr = oldptr;
3829a747e4fSDavid du Colombier 			f->len = oldlen;
3839a747e4fSDavid du Colombier 		}
384*28eece76SDavid du Colombier 		if(nf != nil)
385*28eece76SDavid du Colombier 			xfile(req->newfid, Clunk);
3869a747e4fSDavid du Colombier 		if(rep->nwqid==req->nwname || rep->nwqid > 0){
3879a747e4fSDavid du Colombier 			err_msg[0] = '\0';
3889a747e4fSDavid du Colombier 			return;
3899a747e4fSDavid du Colombier 		}
3909a747e4fSDavid du Colombier 		nexterror();
3919a747e4fSDavid du Colombier 	}
3929a747e4fSDavid du Colombier 
3939a747e4fSDavid du Colombier 	for(rep->nwqid=0; rep->nwqid < req->nwname && rep->nwqid < MAXWELEM; rep->nwqid++){
3949a747e4fSDavid du Colombier 		chat("\twalking %s\n", req->wname[rep->nwqid]);
3959a747e4fSDavid du Colombier 		if(!(f->qid.type & QTDIR)){
3969a747e4fSDavid du Colombier 			chat("\tnot dir: type=%#x\n", f->qid.type);
3973e12c5d1SDavid du Colombier 			error("walk in non-directory");
3983e12c5d1SDavid du Colombier 		}
3999a747e4fSDavid du Colombier 
4009a747e4fSDavid du Colombier 		if(strcmp(req->wname[rep->nwqid], "..")==0){
4019a747e4fSDavid du Colombier 			if(f->qid.path != f->xf->rootqid.path)
4023e12c5d1SDavid du Colombier 				(*f->xf->s->walkup)(f);
4033e12c5d1SDavid du Colombier 		}else
4049a747e4fSDavid du Colombier 			(*f->xf->s->walk)(f, req->wname[rep->nwqid]);
4059a747e4fSDavid du Colombier 		rep->wqid[rep->nwqid] = f->qid;
4069a747e4fSDavid du Colombier 	}
4079a747e4fSDavid du Colombier 	poperror();
4089a747e4fSDavid du Colombier 	if(oldlen)
4099a747e4fSDavid du Colombier 		free(oldptr);
4103e12c5d1SDavid du Colombier }
4113e12c5d1SDavid du Colombier 
4129a747e4fSDavid du Colombier void
ropen(void)4133e12c5d1SDavid du Colombier ropen(void)
4143e12c5d1SDavid du Colombier {
4153e12c5d1SDavid du Colombier 	Xfile *f;
4163e12c5d1SDavid du Colombier 
4179a747e4fSDavid du Colombier 	f = xfile(req->fid, Asis);
4183e12c5d1SDavid du Colombier 	if(f->flags&Omodes)
4193e12c5d1SDavid du Colombier 		error("open on open file");
4209a747e4fSDavid du Colombier 	if(req->mode&ORCLOSE)
4219a747e4fSDavid du Colombier 		error("no removes");
4229a747e4fSDavid du Colombier 	(*f->xf->s->open)(f, req->mode);
4239a747e4fSDavid du Colombier 	f->flags = openflags(req->mode);
4249a747e4fSDavid du Colombier 	rep->qid = f->qid;
4259a747e4fSDavid du Colombier 	rep->iounit = 0;
4263e12c5d1SDavid du Colombier }
4273e12c5d1SDavid du Colombier 
4289a747e4fSDavid du Colombier void
rcreate(void)4293e12c5d1SDavid du Colombier rcreate(void)
4303e12c5d1SDavid du Colombier {
4319a747e4fSDavid du Colombier 	error("no creates");
4329a747e4fSDavid du Colombier /*
4333e12c5d1SDavid du Colombier 	Xfile *f;
4343e12c5d1SDavid du Colombier 
4359a747e4fSDavid du Colombier 	if(strcmp(req->name, ".") == 0 || strcmp(req->name, "..") == 0)
4363e12c5d1SDavid du Colombier 		error("create . or ..");
4379a747e4fSDavid du Colombier 	f = xfile(req->fid, Asis);
4383e12c5d1SDavid du Colombier 	if(f->flags&Omodes)
4393e12c5d1SDavid du Colombier 		error("create on open file");
4403e12c5d1SDavid du Colombier 	if(!(f->qid.path&CHDIR))
4413e12c5d1SDavid du Colombier 		error("create in non-directory");
4429a747e4fSDavid du Colombier 	(*f->xf->s->create)(f, req->name, req->perm, req->mode);
4433e12c5d1SDavid du Colombier 	chat("f->qid=0x%8.8lux...", f->qid.path);
4449a747e4fSDavid du Colombier 	f->flags = openflags(req->mode);
4459a747e4fSDavid du Colombier 	rep->qid = f->qid;
4469a747e4fSDavid du Colombier */
4473e12c5d1SDavid du Colombier }
4483e12c5d1SDavid du Colombier 
4499a747e4fSDavid du Colombier void
rread(void)4503e12c5d1SDavid du Colombier rread(void)
4513e12c5d1SDavid du Colombier {
4523e12c5d1SDavid du Colombier 	Xfile *f;
4533e12c5d1SDavid du Colombier 
4549a747e4fSDavid du Colombier 	f=xfile(req->fid, Asis);
4553e12c5d1SDavid du Colombier 	if (!(f->flags&Oread))
4563e12c5d1SDavid du Colombier 		error("file not opened for reading");
4579a747e4fSDavid du Colombier 	if(f->qid.type & QTDIR)
4589a747e4fSDavid du Colombier 		rep->count = (*f->xf->s->readdir)(f, (uchar*)fdata, req->offset, req->count);
4599a747e4fSDavid du Colombier 	else
4609a747e4fSDavid du Colombier 		rep->count = (*f->xf->s->read)(f, fdata, req->offset, req->count);
4619a747e4fSDavid du Colombier 	rep->data = fdata;
4623e12c5d1SDavid du Colombier }
4633e12c5d1SDavid du Colombier 
4649a747e4fSDavid du Colombier void
rwrite(void)4653e12c5d1SDavid du Colombier rwrite(void)
4663e12c5d1SDavid du Colombier {
4673e12c5d1SDavid du Colombier 	Xfile *f;
4683e12c5d1SDavid du Colombier 
4699a747e4fSDavid du Colombier 	f=xfile(req->fid, Asis);
4703e12c5d1SDavid du Colombier 	if(!(f->flags&Owrite))
4713e12c5d1SDavid du Colombier 		error("file not opened for writing");
4729a747e4fSDavid du Colombier 	rep->count = (*f->xf->s->write)(f, req->data, req->offset, req->count);
4733e12c5d1SDavid du Colombier }
4743e12c5d1SDavid du Colombier 
4759a747e4fSDavid du Colombier void
rclunk(void)4763e12c5d1SDavid du Colombier rclunk(void)
4773e12c5d1SDavid du Colombier {
4783e12c5d1SDavid du Colombier 	Xfile *f;
4793e12c5d1SDavid du Colombier 
4803e12c5d1SDavid du Colombier 	if(!waserror()){
4819a747e4fSDavid du Colombier 		f = xfile(req->fid, Asis);
4823e12c5d1SDavid du Colombier 		(*f->xf->s->clunk)(f);
4833e12c5d1SDavid du Colombier 		poperror();
4843e12c5d1SDavid du Colombier 	}
4859a747e4fSDavid du Colombier 	xfile(req->fid, Clunk);
4863e12c5d1SDavid du Colombier }
4873e12c5d1SDavid du Colombier 
4889a747e4fSDavid du Colombier void
rremove(void)4893e12c5d1SDavid du Colombier rremove(void)
4903e12c5d1SDavid du Colombier {
4919a747e4fSDavid du Colombier 	error("no removes");
4923e12c5d1SDavid du Colombier }
4933e12c5d1SDavid du Colombier 
4949a747e4fSDavid du Colombier void
rstat(void)4953e12c5d1SDavid du Colombier rstat(void)
4963e12c5d1SDavid du Colombier {
4973e12c5d1SDavid du Colombier 	Xfile *f;
4983e12c5d1SDavid du Colombier 	Dir dir;
4993e12c5d1SDavid du Colombier 
5009a747e4fSDavid du Colombier 	chat("stat(fid=%d)...", req->fid);
5019a747e4fSDavid du Colombier 	f=xfile(req->fid, Asis);
5029a747e4fSDavid du Colombier 	setnames(&dir, fdata);
5033e12c5d1SDavid du Colombier 	(*f->xf->s->stat)(f, &dir);
5043e12c5d1SDavid du Colombier 	if(chatty)
5053e12c5d1SDavid du Colombier 		showdir(2, &dir);
5069a747e4fSDavid du Colombier 	rep->nstat = convD2M(&dir, statbuf, sizeof statbuf);
5079a747e4fSDavid du Colombier 	rep->stat = statbuf;
5083e12c5d1SDavid du Colombier }
5093e12c5d1SDavid du Colombier 
5109a747e4fSDavid du Colombier void
rwstat(void)5113e12c5d1SDavid du Colombier rwstat(void)
5123e12c5d1SDavid du Colombier {
5139a747e4fSDavid du Colombier 	error("no wstat");
5143e12c5d1SDavid du Colombier }
5153e12c5d1SDavid du Colombier 
5163e12c5d1SDavid du Colombier static int
openflags(int mode)5173e12c5d1SDavid du Colombier openflags(int mode)
5183e12c5d1SDavid du Colombier {
5193e12c5d1SDavid du Colombier 	int flags = 0;
5203e12c5d1SDavid du Colombier 
5213e12c5d1SDavid du Colombier 	switch(mode & ~(OTRUNC|OCEXEC|ORCLOSE)){
5223e12c5d1SDavid du Colombier 	case OREAD:
5233e12c5d1SDavid du Colombier 	case OEXEC:
5243e12c5d1SDavid du Colombier 		flags = Oread; break;
5253e12c5d1SDavid du Colombier 	case OWRITE:
5263e12c5d1SDavid du Colombier 		flags = Owrite; break;
5273e12c5d1SDavid du Colombier 	case ORDWR:
5283e12c5d1SDavid du Colombier 		flags = Oread|Owrite; break;
5293e12c5d1SDavid du Colombier 	}
5303e12c5d1SDavid du Colombier 	if(mode & ORCLOSE)
5313e12c5d1SDavid du Colombier 		flags |= Orclose;
5323e12c5d1SDavid du Colombier 	return flags;
5333e12c5d1SDavid du Colombier }
5343e12c5d1SDavid du Colombier 
5353e12c5d1SDavid du Colombier void
showdir(int fd,Dir * s)5363e12c5d1SDavid du Colombier showdir(int fd, Dir *s)
5373e12c5d1SDavid du Colombier {
5383e12c5d1SDavid du Colombier 	char a_time[32], m_time[32];
5393e12c5d1SDavid du Colombier 	char *p;
5403e12c5d1SDavid du Colombier 
5413e12c5d1SDavid du Colombier 	strcpy(a_time, ctime(s->atime));
5423e12c5d1SDavid du Colombier 	if(p=strchr(a_time, '\n'))	/* assign = */
5433e12c5d1SDavid du Colombier 		*p = 0;
5443e12c5d1SDavid du Colombier 	strcpy(m_time, ctime(s->mtime));
5453e12c5d1SDavid du Colombier 	if(p=strchr(m_time, '\n'))	/* assign = */
5463e12c5d1SDavid du Colombier 		*p = 0;
5479a747e4fSDavid du Colombier 	fprint(fd, "name=\"%s\" qid=(0x%llux,%lud) type=%d dev=%d \
5487dd7cddfSDavid du Colombier mode=0x%8.8lux=0%luo atime=%s mtime=%s length=%lld uid=\"%s\" gid=\"%s\"...",
5493e12c5d1SDavid du Colombier 		s->name, s->qid.path, s->qid.vers, s->type, s->dev,
5503e12c5d1SDavid du Colombier 		s->mode, s->mode,
5513e12c5d1SDavid du Colombier 		a_time, m_time, s->length, s->uid, s->gid);
5523e12c5d1SDavid du Colombier }
5533e12c5d1SDavid du Colombier 
5543e12c5d1SDavid du Colombier #define	SIZE	1024
5553e12c5d1SDavid du Colombier 
5563e12c5d1SDavid du Colombier void
chat(char * fmt,...)5573e12c5d1SDavid du Colombier chat(char *fmt, ...)
5583e12c5d1SDavid du Colombier {
5597dd7cddfSDavid du Colombier 	va_list arg;
5603e12c5d1SDavid du Colombier 
5613e12c5d1SDavid du Colombier 	if(chatty){
5627dd7cddfSDavid du Colombier 		va_start(arg, fmt);
5639a747e4fSDavid du Colombier 		vfprint(2, fmt, arg);
5647dd7cddfSDavid du Colombier 		va_end(arg);
5653e12c5d1SDavid du Colombier 	}
5663e12c5d1SDavid du Colombier }
5673e12c5d1SDavid du Colombier 
5683e12c5d1SDavid du Colombier void
panic(int rflag,char * fmt,...)5693e12c5d1SDavid du Colombier panic(int rflag, char *fmt, ...)
5703e12c5d1SDavid du Colombier {
5717dd7cddfSDavid du Colombier 	va_list arg;
5723e12c5d1SDavid du Colombier 	char buf[SIZE]; int n;
5733e12c5d1SDavid du Colombier 
5743e12c5d1SDavid du Colombier 	n = sprint(buf, "%s %d: ", argv0, getpid());
5757dd7cddfSDavid du Colombier 	va_start(arg, fmt);
5769a747e4fSDavid du Colombier 	vseprint(buf+n, buf+SIZE, fmt, arg);
5777dd7cddfSDavid du Colombier 	va_end(arg);
5783e12c5d1SDavid du Colombier 	fprint(2, (rflag ? "%s: %r\n" : "%s\n"), buf);
5793e12c5d1SDavid du Colombier 	if(chatty){
5803e12c5d1SDavid du Colombier 		fprint(2, "abort\n");
5813e12c5d1SDavid du Colombier 		abort();
5823e12c5d1SDavid du Colombier 	}
5833e12c5d1SDavid du Colombier 	exits("panic");
5843e12c5d1SDavid du Colombier }
585