xref: /plan9-contrib/sys/src/cmd/cfs/cfs.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 <fcall.h>
53e12c5d1SDavid du Colombier 
63e12c5d1SDavid du Colombier #include "cformat.h"
73e12c5d1SDavid du Colombier #include "lru.h"
83e12c5d1SDavid du Colombier #include "bcache.h"
93e12c5d1SDavid du Colombier #include "disk.h"
103e12c5d1SDavid du Colombier #include "inode.h"
113e12c5d1SDavid du Colombier #include "file.h"
123e12c5d1SDavid du Colombier 
133e12c5d1SDavid du Colombier enum
143e12c5d1SDavid du Colombier {
153e12c5d1SDavid du Colombier 	Nfid=		1024,
163e12c5d1SDavid du Colombier };
173e12c5d1SDavid du Colombier 
183e12c5d1SDavid du Colombier 
193e12c5d1SDavid du Colombier typedef struct Mfile Mfile;
203e12c5d1SDavid du Colombier typedef struct Ram Ram;
213e12c5d1SDavid du Colombier typedef struct P9fs P9fs;
223e12c5d1SDavid du Colombier 
233e12c5d1SDavid du Colombier struct Mfile
243e12c5d1SDavid du Colombier {
253e12c5d1SDavid du Colombier 	Qid	qid;
263e12c5d1SDavid du Colombier 	short	oldfid;
273e12c5d1SDavid du Colombier 	char	needclone;
283e12c5d1SDavid du Colombier 	char	busy;
293e12c5d1SDavid du Colombier };
303e12c5d1SDavid du Colombier 
313e12c5d1SDavid du Colombier Mfile	mfile[Nfid];
323e12c5d1SDavid du Colombier char	user[NAMELEN];
333e12c5d1SDavid du Colombier Icache	ic;
343e12c5d1SDavid du Colombier int	debug;
353e12c5d1SDavid du Colombier 
363e12c5d1SDavid du Colombier struct P9fs
373e12c5d1SDavid du Colombier {
383e12c5d1SDavid du Colombier 	int	fd[2];
393e12c5d1SDavid du Colombier 	Fcall	rhdr;
403e12c5d1SDavid du Colombier 	Fcall	thdr;
413e12c5d1SDavid du Colombier 	long	len;
423e12c5d1SDavid du Colombier 	char	*name;
433e12c5d1SDavid du Colombier };
443e12c5d1SDavid du Colombier 
453e12c5d1SDavid du Colombier P9fs	c;	/* client conversation */
463e12c5d1SDavid du Colombier P9fs	s;	/* server conversation */
473e12c5d1SDavid du Colombier 
483e12c5d1SDavid du Colombier char	datasnd[MAXFDATA + MAXMSG];
493e12c5d1SDavid du Colombier char	datarcv[MAXFDATA + MAXMSG];
503e12c5d1SDavid du Colombier 
51*219b2ee8SDavid du Colombier void	rsession(void);
523e12c5d1SDavid du Colombier void	rflush(void);
533e12c5d1SDavid du Colombier void	rattach(Mfile*);
543e12c5d1SDavid du Colombier void	rclone(Mfile*);
553e12c5d1SDavid du Colombier void	rwalk(Mfile*);
563e12c5d1SDavid du Colombier void	rclwalk(Mfile*);
573e12c5d1SDavid du Colombier void	ropen(Mfile*);
583e12c5d1SDavid du Colombier void	rcreate(Mfile*);
593e12c5d1SDavid du Colombier void	rread(Mfile*);
603e12c5d1SDavid du Colombier void	rwrite(Mfile*);
613e12c5d1SDavid du Colombier void	rclunk(Mfile*);
623e12c5d1SDavid du Colombier void	rremove(Mfile*);
633e12c5d1SDavid du Colombier void	rstat(Mfile*);
643e12c5d1SDavid du Colombier void	rwstat(Mfile*);
653e12c5d1SDavid du Colombier void	error(char*);
663e12c5d1SDavid du Colombier void	warning(char*);
673e12c5d1SDavid du Colombier void	mountinit(char*, char*);
683e12c5d1SDavid du Colombier void	io(void);
693e12c5d1SDavid du Colombier void	sendreply(char*);
703e12c5d1SDavid du Colombier void	sendmsg(P9fs*, Fcall*);
713e12c5d1SDavid du Colombier void	rcvmsg(P9fs*, Fcall*);
723e12c5d1SDavid du Colombier int	delegate(void);
733e12c5d1SDavid du Colombier int	askserver(void);
743e12c5d1SDavid du Colombier void	cachesetup(int, char*);
753e12c5d1SDavid du Colombier int	doclone(Mfile*);
763e12c5d1SDavid du Colombier void	doclwalk(Mfile*, char*);
773e12c5d1SDavid du Colombier 
783e12c5d1SDavid du Colombier #define PREFACE(m) if(doclone(m) < 0) return
793e12c5d1SDavid du Colombier 
803e12c5d1SDavid du Colombier char *mname[]={
813e12c5d1SDavid du Colombier 	[Tnop]		"Tnop",
823e12c5d1SDavid du Colombier 	[Tsession]	"Tsession",
833e12c5d1SDavid du Colombier 	[Tflush]	"Tflush",
843e12c5d1SDavid du Colombier 	[Tattach]	"Tattach",
853e12c5d1SDavid du Colombier 	[Tclone]	"Tclone",
863e12c5d1SDavid du Colombier 	[Twalk]		"Twalk",
873e12c5d1SDavid du Colombier 	[Topen]		"Topen",
883e12c5d1SDavid du Colombier 	[Tcreate]	"Tcreate",
893e12c5d1SDavid du Colombier 	[Tclunk]	"Tclunk",
903e12c5d1SDavid du Colombier 	[Tread]		"Tread",
913e12c5d1SDavid du Colombier 	[Twrite]	"Twrite",
923e12c5d1SDavid du Colombier 	[Tremove]	"Tremove",
933e12c5d1SDavid du Colombier 	[Tstat]		"Tstat",
943e12c5d1SDavid du Colombier 	[Twstat]	"Twstat",
953e12c5d1SDavid du Colombier 	[Tclwalk]	"Tclwalk",
963e12c5d1SDavid du Colombier 	[Rnop]		"Rnop",
973e12c5d1SDavid du Colombier 	[Rsession]	"Rsession",
983e12c5d1SDavid du Colombier 	[Rerror]	"Rerror",
993e12c5d1SDavid du Colombier 	[Rflush]	"Rflush",
1003e12c5d1SDavid du Colombier 	[Rattach]	"Rattach",
1013e12c5d1SDavid du Colombier 	[Rclone]	"Rclone",
1023e12c5d1SDavid du Colombier 	[Rwalk]		"Rwalk",
1033e12c5d1SDavid du Colombier 	[Ropen]		"Ropen",
1043e12c5d1SDavid du Colombier 	[Rcreate]	"Rcreate",
1053e12c5d1SDavid du Colombier 	[Rclunk]	"Rclunk",
1063e12c5d1SDavid du Colombier 	[Rread]		"Rread",
1073e12c5d1SDavid du Colombier 	[Rwrite]	"Rwrite",
1083e12c5d1SDavid du Colombier 	[Rremove]	"Rremove",
1093e12c5d1SDavid du Colombier 	[Rstat]		"Rstat",
1103e12c5d1SDavid du Colombier 	[Rwstat]	"Rwstat",
1113e12c5d1SDavid du Colombier 	[Rclwalk]	"Rclwalk",
1123e12c5d1SDavid du Colombier 	[Rauth]		"Rauth",
1133e12c5d1SDavid du Colombier 			0,
1143e12c5d1SDavid du Colombier };
1153e12c5d1SDavid du Colombier 
1163e12c5d1SDavid du Colombier void
1173e12c5d1SDavid du Colombier usage(void)
1183e12c5d1SDavid du Colombier {
1193e12c5d1SDavid du Colombier 	fprint(2, "usage:\tcfs -s [-rd] [-f partition]");
1203e12c5d1SDavid du Colombier 	fprint(2, "\tcfs [-rd] [-f partition] [-a netaddr] [mt-pt]\n");
1213e12c5d1SDavid du Colombier }
1223e12c5d1SDavid du Colombier 
1233e12c5d1SDavid du Colombier void
1243e12c5d1SDavid du Colombier main(int argc, char *argv[])
1253e12c5d1SDavid du Colombier {
1263e12c5d1SDavid du Colombier 	int std;
1273e12c5d1SDavid du Colombier 	int format;
1283e12c5d1SDavid du Colombier 	char *part;
1293e12c5d1SDavid du Colombier 	char *server;
1303e12c5d1SDavid du Colombier 	char *mtpt;
1313e12c5d1SDavid du Colombier 
1323e12c5d1SDavid du Colombier 	std = 0;
1333e12c5d1SDavid du Colombier 	format = 0;
1343e12c5d1SDavid du Colombier 	part = "/dev/hd0cache";
1353e12c5d1SDavid du Colombier 	server = "dk!bootes";
1363e12c5d1SDavid du Colombier 	mtpt = "/tmp";
1373e12c5d1SDavid du Colombier 
1383e12c5d1SDavid du Colombier 	ARGBEGIN{
1393e12c5d1SDavid du Colombier 	case 'a':
1403e12c5d1SDavid du Colombier 		server = ARGF();
1413e12c5d1SDavid du Colombier 		if(server == 0)
1423e12c5d1SDavid du Colombier 			usage();
1433e12c5d1SDavid du Colombier 		break;
1443e12c5d1SDavid du Colombier 	case 's':
1453e12c5d1SDavid du Colombier 		std = 1;
1463e12c5d1SDavid du Colombier 		break;
1473e12c5d1SDavid du Colombier 	case 'r':
1483e12c5d1SDavid du Colombier 		format = 1;
1493e12c5d1SDavid du Colombier 		break;
1503e12c5d1SDavid du Colombier 	case 'f':
1513e12c5d1SDavid du Colombier 		part = ARGF();
1523e12c5d1SDavid du Colombier 		if(part == 0)
1533e12c5d1SDavid du Colombier 			usage();
1543e12c5d1SDavid du Colombier 		break;
1553e12c5d1SDavid du Colombier 	case 'd':
1563e12c5d1SDavid du Colombier 		debug = 1;
1573e12c5d1SDavid du Colombier 		break;
1583e12c5d1SDavid du Colombier 	default:
1593e12c5d1SDavid du Colombier 		usage();
1603e12c5d1SDavid du Colombier 	}ARGEND
1613e12c5d1SDavid du Colombier 	if(argc && *argv)
1623e12c5d1SDavid du Colombier 		mtpt = *argv;
1633e12c5d1SDavid du Colombier 
1643e12c5d1SDavid du Colombier 	cachesetup(format, part);
1653e12c5d1SDavid du Colombier 
1663e12c5d1SDavid du Colombier 	c.name = "client";
1673e12c5d1SDavid du Colombier 	s.name = "server";
1683e12c5d1SDavid du Colombier 	if(std){
1693e12c5d1SDavid du Colombier 		c.fd[0] = c.fd[1] = 1;
1703e12c5d1SDavid du Colombier 		s.fd[0] = s.fd[1] = 0;
1713e12c5d1SDavid du Colombier 	}else
1723e12c5d1SDavid du Colombier 		mountinit(server, mtpt);
1733e12c5d1SDavid du Colombier 
1743e12c5d1SDavid du Colombier 	switch(fork()){
1753e12c5d1SDavid du Colombier 	case 0:
1763e12c5d1SDavid du Colombier 		io();
1773e12c5d1SDavid du Colombier 		exits("");
1783e12c5d1SDavid du Colombier 	case -1:
1793e12c5d1SDavid du Colombier 		error("fork");
1803e12c5d1SDavid du Colombier 	default:
1813e12c5d1SDavid du Colombier 		exits("");
1823e12c5d1SDavid du Colombier 	}
1833e12c5d1SDavid du Colombier }
1843e12c5d1SDavid du Colombier 
1853e12c5d1SDavid du Colombier void
1863e12c5d1SDavid du Colombier cachesetup(int format, char *partition)
1873e12c5d1SDavid du Colombier {
1883e12c5d1SDavid du Colombier 	int f;
1893e12c5d1SDavid du Colombier 	int secsize;
1903e12c5d1SDavid du Colombier 	int inodes;
1913e12c5d1SDavid du Colombier 	int blocksize;
1923e12c5d1SDavid du Colombier 
1933e12c5d1SDavid du Colombier 	secsize = 512;
1943e12c5d1SDavid du Colombier 	inodes = 1024;
1953e12c5d1SDavid du Colombier 	blocksize = 4*1024;
1963e12c5d1SDavid du Colombier 
1973e12c5d1SDavid du Colombier 	f = open(partition, ORDWR);
1983e12c5d1SDavid du Colombier 	if(f < 0)
1993e12c5d1SDavid du Colombier 		error("opening partition");
2003e12c5d1SDavid du Colombier 
2013e12c5d1SDavid du Colombier 	if(format || iinit(&ic, f, secsize)<0){
2023e12c5d1SDavid du Colombier 		if(iformat(&ic, f, inodes, "bootes", blocksize, secsize) < 0)
2033e12c5d1SDavid du Colombier 			error("formatting failed");
2043e12c5d1SDavid du Colombier 	}
2053e12c5d1SDavid du Colombier }
2063e12c5d1SDavid du Colombier 
2073e12c5d1SDavid du Colombier void
2083e12c5d1SDavid du Colombier mountinit(char *server, char *mountpoint)
2093e12c5d1SDavid du Colombier {
2103e12c5d1SDavid du Colombier 	int p[2];
2113e12c5d1SDavid du Colombier 
2123e12c5d1SDavid du Colombier 	/*
2133e12c5d1SDavid du Colombier 	 *  grab a channel and call up the file server
2143e12c5d1SDavid du Colombier 	 */
2153e12c5d1SDavid du Colombier 	s.fd[0] = s.fd[1] = dial(netmkaddr(server, 0, 0), 0, 0, 0);
2163e12c5d1SDavid du Colombier 	if(s.fd[0] < 0)
2173e12c5d1SDavid du Colombier 		error("opening data");
2183e12c5d1SDavid du Colombier 
2193e12c5d1SDavid du Colombier 	/*
2203e12c5d1SDavid du Colombier  	 *  mount onto name space
2213e12c5d1SDavid du Colombier 	 */
2223e12c5d1SDavid du Colombier 	if(pipe(p) < 0)
2233e12c5d1SDavid du Colombier 		error("pipe failed");
2243e12c5d1SDavid du Colombier 	switch(fork()){
2253e12c5d1SDavid du Colombier 	case 0:
226*219b2ee8SDavid du Colombier 		break;
227*219b2ee8SDavid du Colombier 	default:
228*219b2ee8SDavid du Colombier 		if(amount(p[1], mountpoint, MREPL|MCREATE, "") < 0)
2293e12c5d1SDavid du Colombier 			error("mount failed");
2303e12c5d1SDavid du Colombier 		exits(0);
2313e12c5d1SDavid du Colombier 	case -1:
2323e12c5d1SDavid du Colombier 		error("fork failed\n");
2333e12c5d1SDavid du Colombier /*BUG: no wait!*/
2343e12c5d1SDavid du Colombier 	}
2353e12c5d1SDavid du Colombier 	c.fd[0] = c.fd[1] = p[0];
2363e12c5d1SDavid du Colombier }
2373e12c5d1SDavid du Colombier 
2383e12c5d1SDavid du Colombier void
2393e12c5d1SDavid du Colombier io(void)
2403e12c5d1SDavid du Colombier {
2413e12c5d1SDavid du Colombier 	Mfile *mf;
2423e12c5d1SDavid du Colombier     loop:
2433e12c5d1SDavid du Colombier 	rcvmsg(&c, &c.thdr);
2443e12c5d1SDavid du Colombier 	mf = &mfile[c.thdr.fid];
2453e12c5d1SDavid du Colombier 	switch(c.thdr.type){
2463e12c5d1SDavid du Colombier 	default:
2473e12c5d1SDavid du Colombier 		error("type");
2483e12c5d1SDavid du Colombier 		break;
2493e12c5d1SDavid du Colombier 	case Tsession:
250*219b2ee8SDavid du Colombier 		rsession();
2513e12c5d1SDavid du Colombier 		break;
2523e12c5d1SDavid du Colombier 	case Tnop:
2533e12c5d1SDavid du Colombier 		rflush();
2543e12c5d1SDavid du Colombier 		break;
2553e12c5d1SDavid du Colombier 	case Tflush:
2563e12c5d1SDavid du Colombier 		rflush();
2573e12c5d1SDavid du Colombier 		break;
2583e12c5d1SDavid du Colombier 	case Tattach:
2593e12c5d1SDavid du Colombier 		rattach(mf);
2603e12c5d1SDavid du Colombier 		break;
2613e12c5d1SDavid du Colombier 	case Tclone:
2623e12c5d1SDavid du Colombier 		rclone(mf);
2633e12c5d1SDavid du Colombier 		break;
2643e12c5d1SDavid du Colombier 	case Twalk:
2653e12c5d1SDavid du Colombier 		rwalk(mf);
2663e12c5d1SDavid du Colombier 		break;
2673e12c5d1SDavid du Colombier 	case Topen:
2683e12c5d1SDavid du Colombier 		ropen(mf);
2693e12c5d1SDavid du Colombier 		break;
2703e12c5d1SDavid du Colombier 	case Tcreate:
2713e12c5d1SDavid du Colombier 		rcreate(mf);
2723e12c5d1SDavid du Colombier 		break;
2733e12c5d1SDavid du Colombier 	case Tread:
2743e12c5d1SDavid du Colombier 		rread(mf);
2753e12c5d1SDavid du Colombier 		break;
2763e12c5d1SDavid du Colombier 	case Twrite:
2773e12c5d1SDavid du Colombier 		rwrite(mf);
2783e12c5d1SDavid du Colombier 		break;
2793e12c5d1SDavid du Colombier 	case Tclunk:
2803e12c5d1SDavid du Colombier 		rclunk(mf);
2813e12c5d1SDavid du Colombier 		break;
2823e12c5d1SDavid du Colombier 	case Tremove:
2833e12c5d1SDavid du Colombier 		rremove(mf);
2843e12c5d1SDavid du Colombier 		break;
2853e12c5d1SDavid du Colombier 	case Tstat:
2863e12c5d1SDavid du Colombier 		rstat(mf);
2873e12c5d1SDavid du Colombier 		break;
2883e12c5d1SDavid du Colombier 	case Twstat:
2893e12c5d1SDavid du Colombier 		rwstat(mf);
2903e12c5d1SDavid du Colombier 		break;
2913e12c5d1SDavid du Colombier 	}
2923e12c5d1SDavid du Colombier 	goto loop;
2933e12c5d1SDavid du Colombier }
2943e12c5d1SDavid du Colombier 
2953e12c5d1SDavid du Colombier void
296*219b2ee8SDavid du Colombier rsession(void)
297*219b2ee8SDavid du Colombier {
298*219b2ee8SDavid du Colombier 	delegate();
299*219b2ee8SDavid du Colombier }
300*219b2ee8SDavid du Colombier 
301*219b2ee8SDavid du Colombier void
3023e12c5d1SDavid du Colombier rflush(void)		/* synchronous so easy */
3033e12c5d1SDavid du Colombier {
3043e12c5d1SDavid du Colombier 	sendreply(0);
3053e12c5d1SDavid du Colombier }
3063e12c5d1SDavid du Colombier 
3073e12c5d1SDavid du Colombier void
3083e12c5d1SDavid du Colombier rattach(Mfile *mf)
3093e12c5d1SDavid du Colombier {
3103e12c5d1SDavid du Colombier 	if(delegate() == 0){
3113e12c5d1SDavid du Colombier 		mf->qid = s.rhdr.qid;
3123e12c5d1SDavid du Colombier 		mf->busy = 1;
3133e12c5d1SDavid du Colombier 		mf->needclone = 0;
3143e12c5d1SDavid du Colombier 	}
3153e12c5d1SDavid du Colombier }
3163e12c5d1SDavid du Colombier 
3173e12c5d1SDavid du Colombier /*
3183e12c5d1SDavid du Colombier  *  check consistency and perform a delayed clone
3193e12c5d1SDavid du Colombier  */
3203e12c5d1SDavid du Colombier int
3213e12c5d1SDavid du Colombier doclone(Mfile *mf)
3223e12c5d1SDavid du Colombier {
3233e12c5d1SDavid du Colombier 	Mfile *omf;
3243e12c5d1SDavid du Colombier 
3253e12c5d1SDavid du Colombier 	if(!mf->busy)
3263e12c5d1SDavid du Colombier 		error("bad fid");
3273e12c5d1SDavid du Colombier 	if(!mf->needclone)
3283e12c5d1SDavid du Colombier 		return 0;
3293e12c5d1SDavid du Colombier 	omf = &mfile[mf->oldfid];
3303e12c5d1SDavid du Colombier 	if(!omf->busy)
3313e12c5d1SDavid du Colombier 		error("bad old fid");
3323e12c5d1SDavid du Colombier 
3333e12c5d1SDavid du Colombier 	s.thdr.type = Tclone;
3343e12c5d1SDavid du Colombier 	s.thdr.fid = mf->oldfid;
3353e12c5d1SDavid du Colombier 	s.thdr.newfid = mf - mfile;
3363e12c5d1SDavid du Colombier 	mf->needclone = 0;
3373e12c5d1SDavid du Colombier 	if(askserver() == 0)
3383e12c5d1SDavid du Colombier 		return 0;
3393e12c5d1SDavid du Colombier 	sendreply(s.rhdr.ename);
3403e12c5d1SDavid du Colombier 	return -1;
3413e12c5d1SDavid du Colombier }
3423e12c5d1SDavid du Colombier 
3433e12c5d1SDavid du Colombier /*
3443e12c5d1SDavid du Colombier  *  don't send clone to server, just reply to client
3453e12c5d1SDavid du Colombier  */
3463e12c5d1SDavid du Colombier void
3473e12c5d1SDavid du Colombier rclone(Mfile *mf)
3483e12c5d1SDavid du Colombier {
3493e12c5d1SDavid du Colombier 	Mfile *nmf;
3503e12c5d1SDavid du Colombier 
3513e12c5d1SDavid du Colombier 	PREFACE(mf);
3523e12c5d1SDavid du Colombier 	if(c.thdr.newfid<0 || Nfid<=c.thdr.newfid)
3533e12c5d1SDavid du Colombier 		error("clone nfid out of range");
3543e12c5d1SDavid du Colombier 	nmf = &mfile[c.thdr.newfid];
3553e12c5d1SDavid du Colombier 	if(nmf->busy)
3563e12c5d1SDavid du Colombier 		error("clone to used channel");
3573e12c5d1SDavid du Colombier 	nmf = &mfile[c.thdr.newfid];
3583e12c5d1SDavid du Colombier 	nmf->qid = mf->qid;
3593e12c5d1SDavid du Colombier 	nmf->needclone = 1;
3603e12c5d1SDavid du Colombier 	nmf->oldfid = mf - mfile;
3613e12c5d1SDavid du Colombier 	nmf->busy = 1;
3623e12c5d1SDavid du Colombier 	sendreply(0);
3633e12c5d1SDavid du Colombier }
3643e12c5d1SDavid du Colombier 
3653e12c5d1SDavid du Colombier /*
3663e12c5d1SDavid du Colombier  *  do a combined clone and walk. An error implies a clunk.  A reply with
3673e12c5d1SDavid du Colombier  *  the wrong fid implies a "directory entry not found".
3683e12c5d1SDavid du Colombier  */
3693e12c5d1SDavid du Colombier void
3703e12c5d1SDavid du Colombier doclwalk(Mfile *mf, char *name)
3713e12c5d1SDavid du Colombier {
3723e12c5d1SDavid du Colombier 	s.thdr.type = Tclwalk;
3733e12c5d1SDavid du Colombier 	s.thdr.fid = mf->oldfid;
3743e12c5d1SDavid du Colombier 	s.thdr.newfid = mf - mfile;
3753e12c5d1SDavid du Colombier 	memmove(s.thdr.name, name, sizeof s.thdr.name);
3763e12c5d1SDavid du Colombier 	if(askserver() == 0){
3773e12c5d1SDavid du Colombier 		if(s.rhdr.fid == s.thdr.fid){
3783e12c5d1SDavid du Colombier 			/*
3793e12c5d1SDavid du Colombier 			 *  this is really a short form of
3803e12c5d1SDavid du Colombier 			 *	Terror "directory entry not found"
3813e12c5d1SDavid du Colombier 			 */
3823e12c5d1SDavid du Colombier 			mf->busy = 0;
3833e12c5d1SDavid du Colombier 			sendreply("directory entry not found");
3843e12c5d1SDavid du Colombier 			return;
3853e12c5d1SDavid du Colombier 		}
3863e12c5d1SDavid du Colombier 		mf->qid = s.rhdr.qid;
3873e12c5d1SDavid du Colombier 		c.rhdr.qid = s.rhdr.qid;
3883e12c5d1SDavid du Colombier 		mf->needclone = 0;
3893e12c5d1SDavid du Colombier 		sendreply(0);
3903e12c5d1SDavid du Colombier 	} else {
3913e12c5d1SDavid du Colombier 		mf->busy = 0;
3923e12c5d1SDavid du Colombier 		sendreply(s.rhdr.ename);
3933e12c5d1SDavid du Colombier 	}
3943e12c5d1SDavid du Colombier }
3953e12c5d1SDavid du Colombier 
3963e12c5d1SDavid du Colombier void
3973e12c5d1SDavid du Colombier rwalk(Mfile *mf)
3983e12c5d1SDavid du Colombier {
3993e12c5d1SDavid du Colombier 	if(mf->needclone){
4003e12c5d1SDavid du Colombier 		doclwalk(mf, c.thdr.name);
4013e12c5d1SDavid du Colombier 		return;
4023e12c5d1SDavid du Colombier 	}
4033e12c5d1SDavid du Colombier 	if(delegate() == 0)
4043e12c5d1SDavid du Colombier 		mf->qid = s.rhdr.qid;
4053e12c5d1SDavid du Colombier }
4063e12c5d1SDavid du Colombier 
4073e12c5d1SDavid du Colombier void
4083e12c5d1SDavid du Colombier rclwalk(Mfile *mf)
4093e12c5d1SDavid du Colombier {
4103e12c5d1SDavid du Colombier 	if(delegate() == 0)
4113e12c5d1SDavid du Colombier 		mf->qid = s.rhdr.qid;
4123e12c5d1SDavid du Colombier }
4133e12c5d1SDavid du Colombier 
4143e12c5d1SDavid du Colombier void
4153e12c5d1SDavid du Colombier ropen(Mfile *mf)
4163e12c5d1SDavid du Colombier {
4173e12c5d1SDavid du Colombier 	PREFACE(mf);
4183e12c5d1SDavid du Colombier 	if(delegate() == 0){
4193e12c5d1SDavid du Colombier 		mf->qid = s.rhdr.qid;
4203e12c5d1SDavid du Colombier 		if(c.thdr.mode & OTRUNC){
4213e12c5d1SDavid du Colombier 			mf->qid.vers++;
4223e12c5d1SDavid du Colombier 			iget(&ic, mf->qid);
4233e12c5d1SDavid du Colombier 		}
4243e12c5d1SDavid du Colombier 	}
4253e12c5d1SDavid du Colombier }
4263e12c5d1SDavid du Colombier 
4273e12c5d1SDavid du Colombier void
4283e12c5d1SDavid du Colombier rcreate(Mfile *mf)
4293e12c5d1SDavid du Colombier {
4303e12c5d1SDavid du Colombier 	PREFACE(mf);
4313e12c5d1SDavid du Colombier 	if(delegate() == 0){
4323e12c5d1SDavid du Colombier 		mf->qid = s.rhdr.qid;
4333e12c5d1SDavid du Colombier 		mf->qid.vers++;
4343e12c5d1SDavid du Colombier 	}
4353e12c5d1SDavid du Colombier }
4363e12c5d1SDavid du Colombier 
4373e12c5d1SDavid du Colombier void
4383e12c5d1SDavid du Colombier rclunk(Mfile *mf)
4393e12c5d1SDavid du Colombier {
4403e12c5d1SDavid du Colombier 	if(!mf->busy){
4413e12c5d1SDavid du Colombier 		sendreply(0);
4423e12c5d1SDavid du Colombier 		return;
4433e12c5d1SDavid du Colombier 	}
4443e12c5d1SDavid du Colombier 	mf->busy = 0;
4453e12c5d1SDavid du Colombier 	mf->needclone = 0;
4463e12c5d1SDavid du Colombier 	delegate();
4473e12c5d1SDavid du Colombier }
4483e12c5d1SDavid du Colombier 
4493e12c5d1SDavid du Colombier void
4503e12c5d1SDavid du Colombier rremove(Mfile *mf)
4513e12c5d1SDavid du Colombier {
4523e12c5d1SDavid du Colombier 	PREFACE(mf);
4533e12c5d1SDavid du Colombier 	mf->busy = 0;
4543e12c5d1SDavid du Colombier 	delegate();
4553e12c5d1SDavid du Colombier }
4563e12c5d1SDavid du Colombier 
4573e12c5d1SDavid du Colombier void
4583e12c5d1SDavid du Colombier rread(Mfile *mf)
4593e12c5d1SDavid du Colombier {
4603e12c5d1SDavid du Colombier 	int cnt;
4613e12c5d1SDavid du Colombier 	long off, first;
4623e12c5d1SDavid du Colombier 	char *cp;
4633e12c5d1SDavid du Colombier 	Ibuf *b;
4643e12c5d1SDavid du Colombier 	long n;
4653e12c5d1SDavid du Colombier 	char data[MAXFDATA];
4663e12c5d1SDavid du Colombier 	int done;
4673e12c5d1SDavid du Colombier 
4683e12c5d1SDavid du Colombier 	PREFACE(mf);
4693e12c5d1SDavid du Colombier 	first = off = c.thdr.offset;
4703e12c5d1SDavid du Colombier 	cnt = c.thdr.count;
4713e12c5d1SDavid du Colombier 
4723e12c5d1SDavid du Colombier 	if(mf->qid.path & CHDIR){
4733e12c5d1SDavid du Colombier 		delegate();
4743e12c5d1SDavid du Colombier 		return;
4753e12c5d1SDavid du Colombier 	}
4763e12c5d1SDavid du Colombier 
4773e12c5d1SDavid du Colombier 	b = iget(&ic, mf->qid);
4783e12c5d1SDavid du Colombier 	if(b == 0){
4793e12c5d1SDavid du Colombier 		delegate();
4803e12c5d1SDavid du Colombier 		return;
4813e12c5d1SDavid du Colombier 	}
4823e12c5d1SDavid du Colombier 
4833e12c5d1SDavid du Colombier 	cp = data;
4843e12c5d1SDavid du Colombier 	done = 0;
4853e12c5d1SDavid du Colombier 	while(cnt>0 && !done){
4863e12c5d1SDavid du Colombier 		n = fread(&ic, b, cp, off, cnt);
4873e12c5d1SDavid du Colombier 		if(n <= 0){
4883e12c5d1SDavid du Colombier 			n = -n;
4893e12c5d1SDavid du Colombier 			if(n==0 || n>cnt)
4903e12c5d1SDavid du Colombier 				n = cnt;
4913e12c5d1SDavid du Colombier 			s.thdr.type = c.thdr.type;
4923e12c5d1SDavid du Colombier 			s.thdr.fid = c.thdr.fid;
4933e12c5d1SDavid du Colombier 			s.thdr.tag = c.thdr.tag;
4943e12c5d1SDavid du Colombier 			s.thdr.offset = off;
4953e12c5d1SDavid du Colombier 			s.thdr.count = n;
4963e12c5d1SDavid du Colombier 			if(askserver() < 0)
4973e12c5d1SDavid du Colombier 				sendreply(s.rhdr.ename);
4983e12c5d1SDavid du Colombier 			if(s.rhdr.count != n)
4993e12c5d1SDavid du Colombier 				done = 1;
5003e12c5d1SDavid du Colombier 			n = s.rhdr.count;
5013e12c5d1SDavid du Colombier 			memmove(cp, s.rhdr.data, n);
5023e12c5d1SDavid du Colombier 			fwrite(&ic, b, cp, off, n);
5033e12c5d1SDavid du Colombier 		}
5043e12c5d1SDavid du Colombier 		cnt -= n;
5053e12c5d1SDavid du Colombier 		off += n;
5063e12c5d1SDavid du Colombier 		cp += n;
5073e12c5d1SDavid du Colombier 	}
5083e12c5d1SDavid du Colombier 	c.rhdr.data = data;
5093e12c5d1SDavid du Colombier 	c.rhdr.count = off - first;
5103e12c5d1SDavid du Colombier 	sendreply(0);
5113e12c5d1SDavid du Colombier }
5123e12c5d1SDavid du Colombier 
5133e12c5d1SDavid du Colombier void
5143e12c5d1SDavid du Colombier rwrite(Mfile *mf)
5153e12c5d1SDavid du Colombier {
5163e12c5d1SDavid du Colombier 	Ibuf *b;
5173e12c5d1SDavid du Colombier 	char buf[MAXFDATA];
5183e12c5d1SDavid du Colombier 
5193e12c5d1SDavid du Colombier 	PREFACE(mf);
5203e12c5d1SDavid du Colombier 	if(mf->qid.path & CHDIR){
5213e12c5d1SDavid du Colombier 		delegate();
5223e12c5d1SDavid du Colombier 		return;
5233e12c5d1SDavid du Colombier 	}
5243e12c5d1SDavid du Colombier 
5253e12c5d1SDavid du Colombier 	memmove(buf, c.thdr.data, c.thdr.count);
5263e12c5d1SDavid du Colombier 	if(delegate() < 0)
5273e12c5d1SDavid du Colombier 		return;
5283e12c5d1SDavid du Colombier 
5293e12c5d1SDavid du Colombier 	b = iget(&ic, mf->qid);
5303e12c5d1SDavid du Colombier 	if(b == 0)
5313e12c5d1SDavid du Colombier 		return;
5323e12c5d1SDavid du Colombier 	mf->qid.vers++;
5333e12c5d1SDavid du Colombier 	if(fwrite(&ic, b, buf, c.thdr.offset, c.thdr.count) == c.thdr.count)
5343e12c5d1SDavid du Colombier 		iinc(&ic, b);
5353e12c5d1SDavid du Colombier }
5363e12c5d1SDavid du Colombier 
5373e12c5d1SDavid du Colombier void
5383e12c5d1SDavid du Colombier rstat(Mfile *mf)
5393e12c5d1SDavid du Colombier {
5403e12c5d1SDavid du Colombier 	PREFACE(mf);
5413e12c5d1SDavid du Colombier 	delegate();
5423e12c5d1SDavid du Colombier }
5433e12c5d1SDavid du Colombier 
5443e12c5d1SDavid du Colombier void
5453e12c5d1SDavid du Colombier rwstat(Mfile *mf)
5463e12c5d1SDavid du Colombier {
5473e12c5d1SDavid du Colombier 	PREFACE(mf);
5483e12c5d1SDavid du Colombier 	delegate();
5493e12c5d1SDavid du Colombier }
5503e12c5d1SDavid du Colombier 
5513e12c5d1SDavid du Colombier void
5523e12c5d1SDavid du Colombier error(char *s)
5533e12c5d1SDavid du Colombier {
5543e12c5d1SDavid du Colombier 	fprint(2, "cfs: %s: ", s);
5553e12c5d1SDavid du Colombier 	perror("");
5563e12c5d1SDavid du Colombier 	exits(s);
5573e12c5d1SDavid du Colombier }
5583e12c5d1SDavid du Colombier 
5593e12c5d1SDavid du Colombier void
5603e12c5d1SDavid du Colombier warning(char *s)
5613e12c5d1SDavid du Colombier {
5623e12c5d1SDavid du Colombier 	char buf[ERRLEN];
5633e12c5d1SDavid du Colombier 
5643e12c5d1SDavid du Colombier 	errstr(buf);
5653e12c5d1SDavid du Colombier 	fprint(2, "cfs: %s: %s\n", s, buf);
5663e12c5d1SDavid du Colombier 	if(strstr(buf, "illegal network address"))
5673e12c5d1SDavid du Colombier 		exits("death");
5683e12c5d1SDavid du Colombier }
5693e12c5d1SDavid du Colombier 
5703e12c5d1SDavid du Colombier /*
5713e12c5d1SDavid du Colombier  *  send a reply to the client
5723e12c5d1SDavid du Colombier  */
5733e12c5d1SDavid du Colombier void
5743e12c5d1SDavid du Colombier sendreply(char *err)
5753e12c5d1SDavid du Colombier {
5763e12c5d1SDavid du Colombier 
5773e12c5d1SDavid du Colombier 	if(err){
5783e12c5d1SDavid du Colombier 		c.rhdr.type = Rerror;
5793e12c5d1SDavid du Colombier 		strncpy(c.rhdr.ename, err, ERRLEN);
5803e12c5d1SDavid du Colombier 	}else{
5813e12c5d1SDavid du Colombier 		c.rhdr.type = c.thdr.type+1;
5823e12c5d1SDavid du Colombier 		c.rhdr.fid = c.thdr.fid;
5833e12c5d1SDavid du Colombier 	}
5843e12c5d1SDavid du Colombier 	c.rhdr.tag = c.thdr.tag;
5853e12c5d1SDavid du Colombier 	sendmsg(&c, &c.rhdr);
5863e12c5d1SDavid du Colombier }
5873e12c5d1SDavid du Colombier 
5883e12c5d1SDavid du Colombier /*
5893e12c5d1SDavid du Colombier  *  send a request to the server, get the reply, and send that to
5903e12c5d1SDavid du Colombier  *  the client
5913e12c5d1SDavid du Colombier  */
5923e12c5d1SDavid du Colombier int
5933e12c5d1SDavid du Colombier delegate(void)
5943e12c5d1SDavid du Colombier {
5953e12c5d1SDavid du Colombier 	sendmsg(&s, &c.thdr);
5963e12c5d1SDavid du Colombier 	rcvmsg(&s, &s.rhdr);
5973e12c5d1SDavid du Colombier 	sendmsg(&c, &s.rhdr);
5983e12c5d1SDavid du Colombier 	return c.thdr.type+1 == s.rhdr.type ? 0 : -1;
5993e12c5d1SDavid du Colombier }
6003e12c5d1SDavid du Colombier 
6013e12c5d1SDavid du Colombier /*
6023e12c5d1SDavid du Colombier  *  send a request to the server and get a reply
6033e12c5d1SDavid du Colombier  */
6043e12c5d1SDavid du Colombier int
6053e12c5d1SDavid du Colombier askserver(void)
6063e12c5d1SDavid du Colombier {
6073e12c5d1SDavid du Colombier 	s.thdr.tag = c.thdr.tag;
6083e12c5d1SDavid du Colombier 	sendmsg(&s, &s.thdr);
6093e12c5d1SDavid du Colombier 	rcvmsg(&s, &s.rhdr);
6103e12c5d1SDavid du Colombier 	return s.thdr.type+1 == s.rhdr.type ? 0 : -1;
6113e12c5d1SDavid du Colombier }
6123e12c5d1SDavid du Colombier 
6133e12c5d1SDavid du Colombier /*
6143e12c5d1SDavid du Colombier  *  send/receive messages with logging
6153e12c5d1SDavid du Colombier  */
6163e12c5d1SDavid du Colombier void
6173e12c5d1SDavid du Colombier sendmsg(P9fs *p, Fcall *f)
6183e12c5d1SDavid du Colombier {
6193e12c5d1SDavid du Colombier 	DPRINT(2, "->%s: %d %s on %d\n", p->name, f->type,
6203e12c5d1SDavid du Colombier 		mname[f->type]? mname[f->type] : "mystery",
6213e12c5d1SDavid du Colombier 		f->fid);
6223e12c5d1SDavid du Colombier 
6233e12c5d1SDavid du Colombier 	p->len = convS2M(f, datasnd);
624*219b2ee8SDavid du Colombier 	if(write9p(p->fd[1], datasnd, p->len)!=p->len)
6253e12c5d1SDavid du Colombier 		error("smdmsg");
6263e12c5d1SDavid du Colombier }
6273e12c5d1SDavid du Colombier 
6283e12c5d1SDavid du Colombier void
6293e12c5d1SDavid du Colombier dump(uchar *p, int len)
6303e12c5d1SDavid du Colombier {
6313e12c5d1SDavid du Colombier 	fprint(2, "%d bytes", len);
6323e12c5d1SDavid du Colombier 	while(len > 0){
6333e12c5d1SDavid du Colombier 		fprint(2, " %.2ux", *p++);
6343e12c5d1SDavid du Colombier 		len--;
6353e12c5d1SDavid du Colombier 	}
6363e12c5d1SDavid du Colombier 	fprint(2, "\n");
6373e12c5d1SDavid du Colombier }
6383e12c5d1SDavid du Colombier 
6393e12c5d1SDavid du Colombier void
6403e12c5d1SDavid du Colombier rcvmsg(P9fs *p, Fcall *f)
6413e12c5d1SDavid du Colombier {
6423e12c5d1SDavid du Colombier 	int olen;
6433e12c5d1SDavid du Colombier 
6443e12c5d1SDavid du Colombier 	olen = p->len;
6453e12c5d1SDavid du Colombier retry:
646*219b2ee8SDavid du Colombier 	p->len = read9p(p->fd[0], datarcv, sizeof(datarcv));
6473e12c5d1SDavid du Colombier 	if(p->len <= 0)
6483e12c5d1SDavid du Colombier 		error("rcvmsg");
6493e12c5d1SDavid du Colombier 	if(p->len==2 && datarcv[0]=='O' && datarcv[1]=='K')
6503e12c5d1SDavid du Colombier 		goto retry;
6513e12c5d1SDavid du Colombier 	if(convM2S(datarcv, f, p->len) == 0)
6523e12c5d1SDavid du Colombier 		error("rcvmsg format error");
6533e12c5d1SDavid du Colombier 	if(f->type != Rauth && (f->fid<0 || Nfid<=f->fid)){
6543e12c5d1SDavid du Colombier 		fprint(2, "<-%s: %d %s on %d\n", p->name, f->type,
6553e12c5d1SDavid du Colombier 			mname[f->type]? mname[f->type] : "mystery",
6563e12c5d1SDavid du Colombier 			f->fid);
6573e12c5d1SDavid du Colombier 		dump((uchar*)datasnd, olen);
6583e12c5d1SDavid du Colombier 		dump((uchar*)datarcv, p->len);
6593e12c5d1SDavid du Colombier 		error("rcvmsg fid out of range");
6603e12c5d1SDavid du Colombier 	}
6613e12c5d1SDavid du Colombier 	DPRINT(2, "<-%s: %d %s on %d\n", p->name, f->type,
6623e12c5d1SDavid du Colombier 		mname[f->type]? mname[f->type] : "mystery",
6633e12c5d1SDavid du Colombier 		f->fid);
6643e12c5d1SDavid du Colombier }
665