xref: /plan9/sys/src/cmd/cfs/cfs.c (revision 7dd7cddf99dd7472612f1413b4da293630e6b1bc)
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 
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 {
15*7dd7cddfSDavid du Colombier 	Nfid=		10240,
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;
26*7dd7cddfSDavid du Colombier 	Mfile	*dp;		/* someone needing a clone from us */
27*7dd7cddfSDavid du Colombier 	Mfile	*nextdp;	/* next dependent */
28*7dd7cddfSDavid du Colombier 	Mfile	*parent;	/* fid we need a clone from */
293e12c5d1SDavid du Colombier 	char	busy;
303e12c5d1SDavid du Colombier };
313e12c5d1SDavid du Colombier 
323e12c5d1SDavid du Colombier Mfile	mfile[Nfid];
333e12c5d1SDavid du Colombier char	user[NAMELEN];
343e12c5d1SDavid du Colombier Icache	ic;
353e12c5d1SDavid du Colombier int	debug;
363e12c5d1SDavid du Colombier 
373e12c5d1SDavid du Colombier struct P9fs
383e12c5d1SDavid du Colombier {
393e12c5d1SDavid du Colombier 	int	fd[2];
403e12c5d1SDavid du Colombier 	Fcall	rhdr;
413e12c5d1SDavid du Colombier 	Fcall	thdr;
423e12c5d1SDavid du Colombier 	long	len;
433e12c5d1SDavid du Colombier 	char	*name;
443e12c5d1SDavid du Colombier };
453e12c5d1SDavid du Colombier 
463e12c5d1SDavid du Colombier P9fs	c;	/* client conversation */
473e12c5d1SDavid du Colombier P9fs	s;	/* server conversation */
483e12c5d1SDavid du Colombier 
493e12c5d1SDavid du Colombier char	datasnd[MAXFDATA + MAXMSG];
503e12c5d1SDavid du Colombier char	datarcv[MAXFDATA + MAXMSG];
513e12c5d1SDavid du Colombier 
52219b2ee8SDavid du Colombier void	rsession(void);
533e12c5d1SDavid du Colombier void	rflush(void);
543e12c5d1SDavid du Colombier void	rattach(Mfile*);
553e12c5d1SDavid du Colombier void	rclone(Mfile*);
563e12c5d1SDavid du Colombier void	rwalk(Mfile*);
573e12c5d1SDavid du Colombier void	rclwalk(Mfile*);
583e12c5d1SDavid du Colombier void	ropen(Mfile*);
593e12c5d1SDavid du Colombier void	rcreate(Mfile*);
603e12c5d1SDavid du Colombier void	rread(Mfile*);
613e12c5d1SDavid du Colombier void	rwrite(Mfile*);
623e12c5d1SDavid du Colombier void	rclunk(Mfile*);
633e12c5d1SDavid du Colombier void	rremove(Mfile*);
643e12c5d1SDavid du Colombier void	rstat(Mfile*);
653e12c5d1SDavid du Colombier void	rwstat(Mfile*);
663e12c5d1SDavid du Colombier void	error(char*);
673e12c5d1SDavid du Colombier void	warning(char*);
683e12c5d1SDavid du Colombier void	mountinit(char*, char*);
693e12c5d1SDavid du Colombier void	io(void);
703e12c5d1SDavid du Colombier void	sendreply(char*);
713e12c5d1SDavid du Colombier void	sendmsg(P9fs*, Fcall*);
723e12c5d1SDavid du Colombier void	rcvmsg(P9fs*, Fcall*);
733e12c5d1SDavid du Colombier int	delegate(void);
743e12c5d1SDavid du Colombier int	askserver(void);
753e12c5d1SDavid du Colombier void	cachesetup(int, char*);
763e12c5d1SDavid du Colombier int	doclone(Mfile*);
773e12c5d1SDavid du Colombier void	doclwalk(Mfile*, char*);
783e12c5d1SDavid du Colombier 
79*7dd7cddfSDavid du Colombier #define PREFACE(m) if(preface(m) < 0) return
803e12c5d1SDavid du Colombier 
813e12c5d1SDavid du Colombier char *mname[]={
823e12c5d1SDavid du Colombier 	[Tnop]		"Tnop",
833e12c5d1SDavid du Colombier 	[Tsession]	"Tsession",
843e12c5d1SDavid du Colombier 	[Tflush]	"Tflush",
853e12c5d1SDavid du Colombier 	[Tattach]	"Tattach",
863e12c5d1SDavid du Colombier 	[Tclone]	"Tclone",
873e12c5d1SDavid du Colombier 	[Twalk]		"Twalk",
883e12c5d1SDavid du Colombier 	[Topen]		"Topen",
893e12c5d1SDavid du Colombier 	[Tcreate]	"Tcreate",
903e12c5d1SDavid du Colombier 	[Tclunk]	"Tclunk",
913e12c5d1SDavid du Colombier 	[Tread]		"Tread",
923e12c5d1SDavid du Colombier 	[Twrite]	"Twrite",
933e12c5d1SDavid du Colombier 	[Tremove]	"Tremove",
943e12c5d1SDavid du Colombier 	[Tstat]		"Tstat",
953e12c5d1SDavid du Colombier 	[Twstat]	"Twstat",
963e12c5d1SDavid du Colombier 	[Tclwalk]	"Tclwalk",
973e12c5d1SDavid du Colombier 	[Rnop]		"Rnop",
983e12c5d1SDavid du Colombier 	[Rsession]	"Rsession",
993e12c5d1SDavid du Colombier 	[Rerror]	"Rerror",
1003e12c5d1SDavid du Colombier 	[Rflush]	"Rflush",
1013e12c5d1SDavid du Colombier 	[Rattach]	"Rattach",
1023e12c5d1SDavid du Colombier 	[Rclone]	"Rclone",
1033e12c5d1SDavid du Colombier 	[Rwalk]		"Rwalk",
1043e12c5d1SDavid du Colombier 	[Ropen]		"Ropen",
1053e12c5d1SDavid du Colombier 	[Rcreate]	"Rcreate",
1063e12c5d1SDavid du Colombier 	[Rclunk]	"Rclunk",
1073e12c5d1SDavid du Colombier 	[Rread]		"Rread",
1083e12c5d1SDavid du Colombier 	[Rwrite]	"Rwrite",
1093e12c5d1SDavid du Colombier 	[Rremove]	"Rremove",
1103e12c5d1SDavid du Colombier 	[Rstat]		"Rstat",
1113e12c5d1SDavid du Colombier 	[Rwstat]	"Rwstat",
1123e12c5d1SDavid du Colombier 	[Rclwalk]	"Rclwalk",
1133e12c5d1SDavid du Colombier 	[Rauth]		"Rauth",
1143e12c5d1SDavid du Colombier 			0,
1153e12c5d1SDavid du Colombier };
1163e12c5d1SDavid du Colombier 
1173e12c5d1SDavid du Colombier void
1183e12c5d1SDavid du Colombier usage(void)
1193e12c5d1SDavid du Colombier {
1203e12c5d1SDavid du Colombier 	fprint(2, "usage:\tcfs -s [-rd] [-f partition]");
1213e12c5d1SDavid du Colombier 	fprint(2, "\tcfs [-rd] [-f partition] [-a netaddr] [mt-pt]\n");
1223e12c5d1SDavid du Colombier }
1233e12c5d1SDavid du Colombier 
1243e12c5d1SDavid du Colombier void
1253e12c5d1SDavid du Colombier main(int argc, char *argv[])
1263e12c5d1SDavid du Colombier {
1273e12c5d1SDavid du Colombier 	int std;
1283e12c5d1SDavid du Colombier 	int format;
1293e12c5d1SDavid du Colombier 	char *part;
1303e12c5d1SDavid du Colombier 	char *server;
1313e12c5d1SDavid du Colombier 	char *mtpt;
1323e12c5d1SDavid du Colombier 
1333e12c5d1SDavid du Colombier 	std = 0;
1343e12c5d1SDavid du Colombier 	format = 0;
135*7dd7cddfSDavid du Colombier 	part = "/dev/sdC0/cache";
136*7dd7cddfSDavid du Colombier 	server = "il!emelie";
1373e12c5d1SDavid du Colombier 	mtpt = "/tmp";
1383e12c5d1SDavid du Colombier 
1393e12c5d1SDavid du Colombier 	ARGBEGIN{
1403e12c5d1SDavid du Colombier 	case 'a':
1413e12c5d1SDavid du Colombier 		server = ARGF();
1423e12c5d1SDavid du Colombier 		if(server == 0)
1433e12c5d1SDavid du Colombier 			usage();
1443e12c5d1SDavid du Colombier 		break;
1453e12c5d1SDavid du Colombier 	case 's':
1463e12c5d1SDavid du Colombier 		std = 1;
1473e12c5d1SDavid du Colombier 		break;
1483e12c5d1SDavid du Colombier 	case 'r':
1493e12c5d1SDavid du Colombier 		format = 1;
1503e12c5d1SDavid du Colombier 		break;
1513e12c5d1SDavid du Colombier 	case 'f':
1523e12c5d1SDavid du Colombier 		part = ARGF();
1533e12c5d1SDavid du Colombier 		if(part == 0)
1543e12c5d1SDavid du Colombier 			usage();
1553e12c5d1SDavid du Colombier 		break;
1563e12c5d1SDavid du Colombier 	case 'd':
1573e12c5d1SDavid du Colombier 		debug = 1;
1583e12c5d1SDavid du Colombier 		break;
1593e12c5d1SDavid du Colombier 	default:
1603e12c5d1SDavid du Colombier 		usage();
1613e12c5d1SDavid du Colombier 	}ARGEND
1623e12c5d1SDavid du Colombier 	if(argc && *argv)
1633e12c5d1SDavid du Colombier 		mtpt = *argv;
1643e12c5d1SDavid du Colombier 
165*7dd7cddfSDavid du Colombier 	if(debug)
166*7dd7cddfSDavid du Colombier 		fmtinstall('F', fcallconv);
167*7dd7cddfSDavid du Colombier 
1683e12c5d1SDavid du Colombier 	cachesetup(format, part);
1693e12c5d1SDavid du Colombier 
1703e12c5d1SDavid du Colombier 	c.name = "client";
1713e12c5d1SDavid du Colombier 	s.name = "server";
1723e12c5d1SDavid du Colombier 	if(std){
1733e12c5d1SDavid du Colombier 		c.fd[0] = c.fd[1] = 1;
1743e12c5d1SDavid du Colombier 		s.fd[0] = s.fd[1] = 0;
1753e12c5d1SDavid du Colombier 	}else
1763e12c5d1SDavid du Colombier 		mountinit(server, mtpt);
1773e12c5d1SDavid du Colombier 
1783e12c5d1SDavid du Colombier 	switch(fork()){
1793e12c5d1SDavid du Colombier 	case 0:
1803e12c5d1SDavid du Colombier 		io();
1813e12c5d1SDavid du Colombier 		exits("");
1823e12c5d1SDavid du Colombier 	case -1:
1833e12c5d1SDavid du Colombier 		error("fork");
1843e12c5d1SDavid du Colombier 	default:
1853e12c5d1SDavid du Colombier 		exits("");
1863e12c5d1SDavid du Colombier 	}
1873e12c5d1SDavid du Colombier }
1883e12c5d1SDavid du Colombier 
1893e12c5d1SDavid du Colombier void
1903e12c5d1SDavid du Colombier cachesetup(int format, char *partition)
1913e12c5d1SDavid du Colombier {
1923e12c5d1SDavid du Colombier 	int f;
1933e12c5d1SDavid du Colombier 	int secsize;
1943e12c5d1SDavid du Colombier 	int inodes;
1953e12c5d1SDavid du Colombier 	int blocksize;
1963e12c5d1SDavid du Colombier 
1973e12c5d1SDavid du Colombier 	secsize = 512;
1983e12c5d1SDavid du Colombier 	inodes = 1024;
1993e12c5d1SDavid du Colombier 	blocksize = 4*1024;
2003e12c5d1SDavid du Colombier 
2013e12c5d1SDavid du Colombier 	f = open(partition, ORDWR);
2023e12c5d1SDavid du Colombier 	if(f < 0)
2033e12c5d1SDavid du Colombier 		error("opening partition");
2043e12c5d1SDavid du Colombier 
2053e12c5d1SDavid du Colombier 	if(format || iinit(&ic, f, secsize)<0){
2063e12c5d1SDavid du Colombier 		if(iformat(&ic, f, inodes, "bootes", blocksize, secsize) < 0)
2073e12c5d1SDavid du Colombier 			error("formatting failed");
2083e12c5d1SDavid du Colombier 	}
2093e12c5d1SDavid du Colombier }
2103e12c5d1SDavid du Colombier 
2113e12c5d1SDavid du Colombier void
2123e12c5d1SDavid du Colombier mountinit(char *server, char *mountpoint)
2133e12c5d1SDavid du Colombier {
2143e12c5d1SDavid du Colombier 	int p[2];
2153e12c5d1SDavid du Colombier 
2163e12c5d1SDavid du Colombier 	/*
2173e12c5d1SDavid du Colombier 	 *  grab a channel and call up the file server
2183e12c5d1SDavid du Colombier 	 */
219*7dd7cddfSDavid du Colombier 	s.fd[0] = s.fd[1] = dial(netmkaddr(server, 0, "9fs"), 0, 0, 0);
2203e12c5d1SDavid du Colombier 	if(s.fd[0] < 0)
2213e12c5d1SDavid du Colombier 		error("opening data");
2223e12c5d1SDavid du Colombier 
2233e12c5d1SDavid du Colombier 	/*
2243e12c5d1SDavid du Colombier  	 *  mount onto name space
2253e12c5d1SDavid du Colombier 	 */
2263e12c5d1SDavid du Colombier 	if(pipe(p) < 0)
2273e12c5d1SDavid du Colombier 		error("pipe failed");
2283e12c5d1SDavid du Colombier 	switch(fork()){
2293e12c5d1SDavid du Colombier 	case 0:
230219b2ee8SDavid du Colombier 		break;
231219b2ee8SDavid du Colombier 	default:
232219b2ee8SDavid du Colombier 		if(amount(p[1], mountpoint, MREPL|MCREATE, "") < 0)
2333e12c5d1SDavid du Colombier 			error("mount failed");
2343e12c5d1SDavid du Colombier 		exits(0);
2353e12c5d1SDavid du Colombier 	case -1:
2363e12c5d1SDavid du Colombier 		error("fork failed\n");
2373e12c5d1SDavid du Colombier /*BUG: no wait!*/
2383e12c5d1SDavid du Colombier 	}
2393e12c5d1SDavid du Colombier 	c.fd[0] = c.fd[1] = p[0];
2403e12c5d1SDavid du Colombier }
2413e12c5d1SDavid du Colombier 
2423e12c5d1SDavid du Colombier void
2433e12c5d1SDavid du Colombier io(void)
2443e12c5d1SDavid du Colombier {
2453e12c5d1SDavid du Colombier 	Mfile *mf;
2463e12c5d1SDavid du Colombier     loop:
2473e12c5d1SDavid du Colombier 	rcvmsg(&c, &c.thdr);
2483e12c5d1SDavid du Colombier 	mf = &mfile[c.thdr.fid];
2493e12c5d1SDavid du Colombier 	switch(c.thdr.type){
2503e12c5d1SDavid du Colombier 	default:
2513e12c5d1SDavid du Colombier 		error("type");
2523e12c5d1SDavid du Colombier 		break;
2533e12c5d1SDavid du Colombier 	case Tsession:
254219b2ee8SDavid du Colombier 		rsession();
2553e12c5d1SDavid du Colombier 		break;
2563e12c5d1SDavid du Colombier 	case Tnop:
2573e12c5d1SDavid du Colombier 		rflush();
2583e12c5d1SDavid du Colombier 		break;
2593e12c5d1SDavid du Colombier 	case Tflush:
2603e12c5d1SDavid du Colombier 		rflush();
2613e12c5d1SDavid du Colombier 		break;
2623e12c5d1SDavid du Colombier 	case Tattach:
2633e12c5d1SDavid du Colombier 		rattach(mf);
2643e12c5d1SDavid du Colombier 		break;
2653e12c5d1SDavid du Colombier 	case Tclone:
2663e12c5d1SDavid du Colombier 		rclone(mf);
2673e12c5d1SDavid du Colombier 		break;
2683e12c5d1SDavid du Colombier 	case Twalk:
2693e12c5d1SDavid du Colombier 		rwalk(mf);
2703e12c5d1SDavid du Colombier 		break;
2713e12c5d1SDavid du Colombier 	case Topen:
2723e12c5d1SDavid du Colombier 		ropen(mf);
2733e12c5d1SDavid du Colombier 		break;
2743e12c5d1SDavid du Colombier 	case Tcreate:
2753e12c5d1SDavid du Colombier 		rcreate(mf);
2763e12c5d1SDavid du Colombier 		break;
2773e12c5d1SDavid du Colombier 	case Tread:
2783e12c5d1SDavid du Colombier 		rread(mf);
2793e12c5d1SDavid du Colombier 		break;
2803e12c5d1SDavid du Colombier 	case Twrite:
2813e12c5d1SDavid du Colombier 		rwrite(mf);
2823e12c5d1SDavid du Colombier 		break;
2833e12c5d1SDavid du Colombier 	case Tclunk:
2843e12c5d1SDavid du Colombier 		rclunk(mf);
2853e12c5d1SDavid du Colombier 		break;
2863e12c5d1SDavid du Colombier 	case Tremove:
2873e12c5d1SDavid du Colombier 		rremove(mf);
2883e12c5d1SDavid du Colombier 		break;
2893e12c5d1SDavid du Colombier 	case Tstat:
2903e12c5d1SDavid du Colombier 		rstat(mf);
2913e12c5d1SDavid du Colombier 		break;
2923e12c5d1SDavid du Colombier 	case Twstat:
2933e12c5d1SDavid du Colombier 		rwstat(mf);
2943e12c5d1SDavid du Colombier 		break;
2953e12c5d1SDavid du Colombier 	}
2963e12c5d1SDavid du Colombier 	goto loop;
2973e12c5d1SDavid du Colombier }
2983e12c5d1SDavid du Colombier 
2993e12c5d1SDavid du Colombier void
300219b2ee8SDavid du Colombier rsession(void)
301219b2ee8SDavid du Colombier {
302219b2ee8SDavid du Colombier 	delegate();
303219b2ee8SDavid du Colombier }
304219b2ee8SDavid du Colombier 
305219b2ee8SDavid du Colombier void
3063e12c5d1SDavid du Colombier rflush(void)		/* synchronous so easy */
3073e12c5d1SDavid du Colombier {
3083e12c5d1SDavid du Colombier 	sendreply(0);
3093e12c5d1SDavid du Colombier }
3103e12c5d1SDavid du Colombier 
3113e12c5d1SDavid du Colombier void
3123e12c5d1SDavid du Colombier rattach(Mfile *mf)
3133e12c5d1SDavid du Colombier {
3143e12c5d1SDavid du Colombier 	if(delegate() == 0){
3153e12c5d1SDavid du Colombier 		mf->qid = s.rhdr.qid;
3163e12c5d1SDavid du Colombier 		mf->busy = 1;
317*7dd7cddfSDavid du Colombier 		mf->parent = 0;
318*7dd7cddfSDavid du Colombier 		mf->dp = 0;
319*7dd7cddfSDavid du Colombier 		mf->nextdp = 0;
3203e12c5d1SDavid du Colombier 	}
3213e12c5d1SDavid du Colombier }
3223e12c5d1SDavid du Colombier 
323*7dd7cddfSDavid du Colombier void
324*7dd7cddfSDavid du Colombier removedep(Mfile *dep)
325*7dd7cddfSDavid du Colombier {
326*7dd7cddfSDavid du Colombier 	Mfile **l;
327*7dd7cddfSDavid du Colombier 
328*7dd7cddfSDavid du Colombier 	for(l = &dep->parent->dp; *l; l = &(*l)->nextdp){
329*7dd7cddfSDavid du Colombier 		if(*l == dep){
330*7dd7cddfSDavid du Colombier 			*l = dep->nextdp;
331*7dd7cddfSDavid du Colombier 			break;
332*7dd7cddfSDavid du Colombier 		}
333*7dd7cddfSDavid du Colombier 	}
334*7dd7cddfSDavid du Colombier 	dep->nextdp = 0;
335*7dd7cddfSDavid du Colombier 	dep->parent = 0;
336*7dd7cddfSDavid du Colombier }
337*7dd7cddfSDavid du Colombier 
3383e12c5d1SDavid du Colombier /*
3393e12c5d1SDavid du Colombier  *  check consistency and perform a delayed clone
3403e12c5d1SDavid du Colombier  */
3413e12c5d1SDavid du Colombier int
3423e12c5d1SDavid du Colombier doclone(Mfile *mf)
3433e12c5d1SDavid du Colombier {
3443e12c5d1SDavid du Colombier 	Mfile *omf;
3453e12c5d1SDavid du Colombier 
346*7dd7cddfSDavid du Colombier 	if(!mf->busy){
347*7dd7cddfSDavid du Colombier 		DPRINT(2, "doclone fid %ld\n", mf-mfile);
348*7dd7cddfSDavid du Colombier 		sendreply("delayed clone failure");
349*7dd7cddfSDavid du Colombier 		return -1;
350*7dd7cddfSDavid du Colombier 	}
351*7dd7cddfSDavid du Colombier 
352*7dd7cddfSDavid du Colombier 	/* clone this file if it needs it */
353*7dd7cddfSDavid du Colombier 	if(mf->parent){
354*7dd7cddfSDavid du Colombier 		/* recurse */
355*7dd7cddfSDavid du Colombier 		omf = mf->parent;
356*7dd7cddfSDavid du Colombier 		if(!omf->busy){
357*7dd7cddfSDavid du Colombier 			DPRINT(2, "doclone fid %ld\n", omf-mfile);
358*7dd7cddfSDavid du Colombier 			sendreply("delayed clone failure2");
359*7dd7cddfSDavid du Colombier 			return -1;
360*7dd7cddfSDavid du Colombier 		}
361*7dd7cddfSDavid du Colombier 
362*7dd7cddfSDavid du Colombier 		if(omf->parent){
363*7dd7cddfSDavid du Colombier 			DPRINT(2, "doclone recursing\n");
364*7dd7cddfSDavid du Colombier 			if(doclone(omf) < 0)
365*7dd7cddfSDavid du Colombier 				return -1;
366*7dd7cddfSDavid du Colombier 		}
367*7dd7cddfSDavid du Colombier 
368*7dd7cddfSDavid du Colombier 		removedep(mf);
3693e12c5d1SDavid du Colombier 
3703e12c5d1SDavid du Colombier 		s.thdr.type = Tclone;
371*7dd7cddfSDavid du Colombier 		s.thdr.fid = omf - mfile;
3723e12c5d1SDavid du Colombier 		s.thdr.newfid = mf - mfile;
373*7dd7cddfSDavid du Colombier 
3743e12c5d1SDavid du Colombier 		if(askserver() == 0)
3753e12c5d1SDavid du Colombier 			return 0;
3763e12c5d1SDavid du Colombier 		sendreply(s.rhdr.ename);
3773e12c5d1SDavid du Colombier 		return -1;
3783e12c5d1SDavid du Colombier 	}
3793e12c5d1SDavid du Colombier 
380*7dd7cddfSDavid du Colombier 	return 0;
381*7dd7cddfSDavid du Colombier }
382*7dd7cddfSDavid du Colombier 
383*7dd7cddfSDavid du Colombier /*
384*7dd7cddfSDavid du Colombier  *  clone any files that depend on this one
385*7dd7cddfSDavid du Colombier  */
386*7dd7cddfSDavid du Colombier void
387*7dd7cddfSDavid du Colombier fixdepend(Mfile *mf)
388*7dd7cddfSDavid du Colombier {
389*7dd7cddfSDavid du Colombier 	Mfile *dep, *next;
390*7dd7cddfSDavid du Colombier 
391*7dd7cddfSDavid du Colombier 	/* clone any files that depend on this one */
392*7dd7cddfSDavid du Colombier 	for(dep = mf->dp; dep; dep = next){
393*7dd7cddfSDavid du Colombier 		next = dep->nextdp;
394*7dd7cddfSDavid du Colombier 		if(dep->parent != mf){
395*7dd7cddfSDavid du Colombier 			DPRINT(2, "bad dep %ld -> %ld\n", mf-mfile, dep-mfile);
396*7dd7cddfSDavid du Colombier 			error("bad dependent");
397*7dd7cddfSDavid du Colombier 		}
398*7dd7cddfSDavid du Colombier 		doclone(dep);
399*7dd7cddfSDavid du Colombier 	}
400*7dd7cddfSDavid du Colombier }
401*7dd7cddfSDavid du Colombier 
402*7dd7cddfSDavid du Colombier int
403*7dd7cddfSDavid du Colombier preface(Mfile *mf)
404*7dd7cddfSDavid du Colombier {
405*7dd7cddfSDavid du Colombier 	/* clone this fid from parent if need be */
406*7dd7cddfSDavid du Colombier 	if(doclone(mf) < 0)
407*7dd7cddfSDavid du Colombier 		return -1;
408*7dd7cddfSDavid du Colombier 
409*7dd7cddfSDavid du Colombier 	/* clone any children that depend on this fid */
410*7dd7cddfSDavid du Colombier 	fixdepend(mf);
411*7dd7cddfSDavid du Colombier 	return 0;
412*7dd7cddfSDavid du Colombier }
413*7dd7cddfSDavid du Colombier 
4143e12c5d1SDavid du Colombier /*
4153e12c5d1SDavid du Colombier  *  don't send clone to server, just reply to client
4163e12c5d1SDavid du Colombier  */
4173e12c5d1SDavid du Colombier void
4183e12c5d1SDavid du Colombier rclone(Mfile *mf)
4193e12c5d1SDavid du Colombier {
4203e12c5d1SDavid du Colombier 	Mfile *nmf;
4213e12c5d1SDavid du Colombier 
4223e12c5d1SDavid du Colombier 	if(c.thdr.newfid<0 || Nfid<=c.thdr.newfid)
4233e12c5d1SDavid du Colombier 		error("clone nfid out of range");
424*7dd7cddfSDavid du Colombier 	PREFACE(mf);
4253e12c5d1SDavid du Colombier 	nmf = &mfile[c.thdr.newfid];
4263e12c5d1SDavid du Colombier 	if(nmf->busy)
4273e12c5d1SDavid du Colombier 		error("clone to used channel");
4283e12c5d1SDavid du Colombier 	nmf = &mfile[c.thdr.newfid];
4293e12c5d1SDavid du Colombier 	nmf->qid = mf->qid;
430*7dd7cddfSDavid du Colombier 	nmf->parent = mf;
431*7dd7cddfSDavid du Colombier 	nmf->nextdp = mf->dp;
432*7dd7cddfSDavid du Colombier 	mf->dp = nmf;
4333e12c5d1SDavid du Colombier 	nmf->busy = 1;
4343e12c5d1SDavid du Colombier 	sendreply(0);
4353e12c5d1SDavid du Colombier }
4363e12c5d1SDavid du Colombier 
4373e12c5d1SDavid du Colombier /*
4383e12c5d1SDavid du Colombier  *  do a combined clone and walk. An error implies a clunk.  A reply with
4393e12c5d1SDavid du Colombier  *  the wrong fid implies a "directory entry not found".
4403e12c5d1SDavid du Colombier  */
4413e12c5d1SDavid du Colombier void
4423e12c5d1SDavid du Colombier doclwalk(Mfile *mf, char *name)
4433e12c5d1SDavid du Colombier {
4443e12c5d1SDavid du Colombier 	s.thdr.type = Tclwalk;
445*7dd7cddfSDavid du Colombier 	s.thdr.fid = mf->parent - mfile;
4463e12c5d1SDavid du Colombier 	s.thdr.newfid = mf - mfile;
4473e12c5d1SDavid du Colombier 	memmove(s.thdr.name, name, sizeof s.thdr.name);
4483e12c5d1SDavid du Colombier 	if(askserver() == 0){
4493e12c5d1SDavid du Colombier 		if(s.rhdr.fid == s.thdr.fid){
4503e12c5d1SDavid du Colombier 			/*
4513e12c5d1SDavid du Colombier 			 *  this is really a short form of
4523e12c5d1SDavid du Colombier 			 *	Terror "directory entry not found"
4533e12c5d1SDavid du Colombier 			 */
4543e12c5d1SDavid du Colombier 			sendreply("directory entry not found");
455*7dd7cddfSDavid du Colombier 			removedep(mf);
456*7dd7cddfSDavid du Colombier 			mf->busy = 0;	/* this is an implicit clunk in fs/port/fs.c */
4573e12c5d1SDavid du Colombier 			return;
4583e12c5d1SDavid du Colombier 		}
4593e12c5d1SDavid du Colombier 		mf->qid = s.rhdr.qid;
4603e12c5d1SDavid du Colombier 		c.rhdr.qid = s.rhdr.qid;
461*7dd7cddfSDavid du Colombier 		removedep(mf);
4623e12c5d1SDavid du Colombier 		sendreply(0);
4633e12c5d1SDavid du Colombier 	} else {
4643e12c5d1SDavid du Colombier 		sendreply(s.rhdr.ename);
465*7dd7cddfSDavid du Colombier 		removedep(mf);
466*7dd7cddfSDavid du Colombier 		mf->busy = 0;	/* this is an implicit clunk in fs/port/fs.c */
4673e12c5d1SDavid du Colombier 	}
4683e12c5d1SDavid du Colombier }
4693e12c5d1SDavid du Colombier 
4703e12c5d1SDavid du Colombier void
4713e12c5d1SDavid du Colombier rwalk(Mfile *mf)
4723e12c5d1SDavid du Colombier {
473*7dd7cddfSDavid du Colombier 	if(mf->dp){
474*7dd7cddfSDavid du Colombier 		/* can't clwalk if we have any dependents */
475*7dd7cddfSDavid du Colombier 		doclone(mf);
476*7dd7cddfSDavid du Colombier 		fixdepend(mf);
477*7dd7cddfSDavid du Colombier 	}
478*7dd7cddfSDavid du Colombier 	if(mf->parent){
4793e12c5d1SDavid du Colombier 		doclwalk(mf, c.thdr.name);
4803e12c5d1SDavid du Colombier 		return;
4813e12c5d1SDavid du Colombier 	}
4823e12c5d1SDavid du Colombier 	if(delegate() == 0)
4833e12c5d1SDavid du Colombier 		mf->qid = s.rhdr.qid;
4843e12c5d1SDavid du Colombier }
4853e12c5d1SDavid du Colombier 
4863e12c5d1SDavid du Colombier void
4873e12c5d1SDavid du Colombier rclwalk(Mfile *mf)
4883e12c5d1SDavid du Colombier {
489*7dd7cddfSDavid du Colombier 	PREFACE(mf);
4903e12c5d1SDavid du Colombier 	if(delegate() == 0)
4913e12c5d1SDavid du Colombier 		mf->qid = s.rhdr.qid;
4923e12c5d1SDavid du Colombier }
4933e12c5d1SDavid du Colombier 
4943e12c5d1SDavid du Colombier void
4953e12c5d1SDavid du Colombier ropen(Mfile *mf)
4963e12c5d1SDavid du Colombier {
4973e12c5d1SDavid du Colombier 	PREFACE(mf);
4983e12c5d1SDavid du Colombier 	if(delegate() == 0){
4993e12c5d1SDavid du Colombier 		mf->qid = s.rhdr.qid;
500*7dd7cddfSDavid du Colombier 		if(c.thdr.mode & OTRUNC)
5013e12c5d1SDavid du Colombier 			iget(&ic, mf->qid);
5023e12c5d1SDavid du Colombier 	}
5033e12c5d1SDavid du Colombier }
5043e12c5d1SDavid du Colombier 
5053e12c5d1SDavid du Colombier void
5063e12c5d1SDavid du Colombier rcreate(Mfile *mf)
5073e12c5d1SDavid du Colombier {
5083e12c5d1SDavid du Colombier 	PREFACE(mf);
5093e12c5d1SDavid du Colombier 	if(delegate() == 0){
5103e12c5d1SDavid du Colombier 		mf->qid = s.rhdr.qid;
5113e12c5d1SDavid du Colombier 		mf->qid.vers++;
5123e12c5d1SDavid du Colombier 	}
5133e12c5d1SDavid du Colombier }
5143e12c5d1SDavid du Colombier 
5153e12c5d1SDavid du Colombier void
5163e12c5d1SDavid du Colombier rclunk(Mfile *mf)
5173e12c5d1SDavid du Colombier {
5183e12c5d1SDavid du Colombier 	if(!mf->busy){
5193e12c5d1SDavid du Colombier 		sendreply(0);
5203e12c5d1SDavid du Colombier 		return;
5213e12c5d1SDavid du Colombier 	}
522*7dd7cddfSDavid du Colombier 	PREFACE(mf);
5233e12c5d1SDavid du Colombier 	mf->busy = 0;
5243e12c5d1SDavid du Colombier 	delegate();
5253e12c5d1SDavid du Colombier }
5263e12c5d1SDavid du Colombier 
5273e12c5d1SDavid du Colombier void
5283e12c5d1SDavid du Colombier rremove(Mfile *mf)
5293e12c5d1SDavid du Colombier {
5303e12c5d1SDavid du Colombier 	PREFACE(mf);
5313e12c5d1SDavid du Colombier 	mf->busy = 0;
5323e12c5d1SDavid du Colombier 	delegate();
5333e12c5d1SDavid du Colombier }
5343e12c5d1SDavid du Colombier 
5353e12c5d1SDavid du Colombier void
5363e12c5d1SDavid du Colombier rread(Mfile *mf)
5373e12c5d1SDavid du Colombier {
5383e12c5d1SDavid du Colombier 	int cnt;
5393e12c5d1SDavid du Colombier 	long off, first;
5403e12c5d1SDavid du Colombier 	char *cp;
5413e12c5d1SDavid du Colombier 	Ibuf *b;
5423e12c5d1SDavid du Colombier 	long n;
5433e12c5d1SDavid du Colombier 	char data[MAXFDATA];
5443e12c5d1SDavid du Colombier 	int done;
5453e12c5d1SDavid du Colombier 
5463e12c5d1SDavid du Colombier 	PREFACE(mf);
5473e12c5d1SDavid du Colombier 	first = off = c.thdr.offset;
5483e12c5d1SDavid du Colombier 	cnt = c.thdr.count;
5493e12c5d1SDavid du Colombier 
5503e12c5d1SDavid du Colombier 	if(mf->qid.path & CHDIR){
5513e12c5d1SDavid du Colombier 		delegate();
5523e12c5d1SDavid du Colombier 		return;
5533e12c5d1SDavid du Colombier 	}
5543e12c5d1SDavid du Colombier 
5553e12c5d1SDavid du Colombier 	b = iget(&ic, mf->qid);
5563e12c5d1SDavid du Colombier 	if(b == 0){
5573e12c5d1SDavid du Colombier 		delegate();
5583e12c5d1SDavid du Colombier 		return;
5593e12c5d1SDavid du Colombier 	}
5603e12c5d1SDavid du Colombier 
5613e12c5d1SDavid du Colombier 	cp = data;
5623e12c5d1SDavid du Colombier 	done = 0;
5633e12c5d1SDavid du Colombier 	while(cnt>0 && !done){
5643e12c5d1SDavid du Colombier 		n = fread(&ic, b, cp, off, cnt);
5653e12c5d1SDavid du Colombier 		if(n <= 0){
5663e12c5d1SDavid du Colombier 			n = -n;
5673e12c5d1SDavid du Colombier 			if(n==0 || n>cnt)
5683e12c5d1SDavid du Colombier 				n = cnt;
5693e12c5d1SDavid du Colombier 			s.thdr.type = c.thdr.type;
5703e12c5d1SDavid du Colombier 			s.thdr.fid = c.thdr.fid;
5713e12c5d1SDavid du Colombier 			s.thdr.tag = c.thdr.tag;
5723e12c5d1SDavid du Colombier 			s.thdr.offset = off;
5733e12c5d1SDavid du Colombier 			s.thdr.count = n;
5743e12c5d1SDavid du Colombier 			if(askserver() < 0)
5753e12c5d1SDavid du Colombier 				sendreply(s.rhdr.ename);
5763e12c5d1SDavid du Colombier 			if(s.rhdr.count != n)
5773e12c5d1SDavid du Colombier 				done = 1;
5783e12c5d1SDavid du Colombier 			n = s.rhdr.count;
5793e12c5d1SDavid du Colombier 			memmove(cp, s.rhdr.data, n);
5803e12c5d1SDavid du Colombier 			fwrite(&ic, b, cp, off, n);
5813e12c5d1SDavid du Colombier 		}
5823e12c5d1SDavid du Colombier 		cnt -= n;
5833e12c5d1SDavid du Colombier 		off += n;
5843e12c5d1SDavid du Colombier 		cp += n;
5853e12c5d1SDavid du Colombier 	}
5863e12c5d1SDavid du Colombier 	c.rhdr.data = data;
5873e12c5d1SDavid du Colombier 	c.rhdr.count = off - first;
5883e12c5d1SDavid du Colombier 	sendreply(0);
5893e12c5d1SDavid du Colombier }
5903e12c5d1SDavid du Colombier 
5913e12c5d1SDavid du Colombier void
5923e12c5d1SDavid du Colombier rwrite(Mfile *mf)
5933e12c5d1SDavid du Colombier {
5943e12c5d1SDavid du Colombier 	Ibuf *b;
5953e12c5d1SDavid du Colombier 	char buf[MAXFDATA];
5963e12c5d1SDavid du Colombier 
5973e12c5d1SDavid du Colombier 	PREFACE(mf);
5983e12c5d1SDavid du Colombier 	if(mf->qid.path & CHDIR){
5993e12c5d1SDavid du Colombier 		delegate();
6003e12c5d1SDavid du Colombier 		return;
6013e12c5d1SDavid du Colombier 	}
6023e12c5d1SDavid du Colombier 
6033e12c5d1SDavid du Colombier 	memmove(buf, c.thdr.data, c.thdr.count);
6043e12c5d1SDavid du Colombier 	if(delegate() < 0)
6053e12c5d1SDavid du Colombier 		return;
6063e12c5d1SDavid du Colombier 
6073e12c5d1SDavid du Colombier 	b = iget(&ic, mf->qid);
6083e12c5d1SDavid du Colombier 	if(b == 0)
6093e12c5d1SDavid du Colombier 		return;
6103e12c5d1SDavid du Colombier 	mf->qid.vers++;
6113e12c5d1SDavid du Colombier 	if(fwrite(&ic, b, buf, c.thdr.offset, c.thdr.count) == c.thdr.count)
6123e12c5d1SDavid du Colombier 		iinc(&ic, b);
6133e12c5d1SDavid du Colombier }
6143e12c5d1SDavid du Colombier 
6153e12c5d1SDavid du Colombier void
6163e12c5d1SDavid du Colombier rstat(Mfile *mf)
6173e12c5d1SDavid du Colombier {
6183e12c5d1SDavid du Colombier 	PREFACE(mf);
6193e12c5d1SDavid du Colombier 	delegate();
6203e12c5d1SDavid du Colombier }
6213e12c5d1SDavid du Colombier 
6223e12c5d1SDavid du Colombier void
6233e12c5d1SDavid du Colombier rwstat(Mfile *mf)
6243e12c5d1SDavid du Colombier {
6253e12c5d1SDavid du Colombier 	PREFACE(mf);
6263e12c5d1SDavid du Colombier 	delegate();
6273e12c5d1SDavid du Colombier }
6283e12c5d1SDavid du Colombier 
6293e12c5d1SDavid du Colombier void
6303e12c5d1SDavid du Colombier error(char *s)
6313e12c5d1SDavid du Colombier {
632*7dd7cddfSDavid du Colombier 	fprint(2, "cfs: %s", s);
6333e12c5d1SDavid du Colombier 	perror("");
6343e12c5d1SDavid du Colombier 	exits(s);
6353e12c5d1SDavid du Colombier }
6363e12c5d1SDavid du Colombier 
6373e12c5d1SDavid du Colombier void
6383e12c5d1SDavid du Colombier warning(char *s)
6393e12c5d1SDavid du Colombier {
640*7dd7cddfSDavid du Colombier 	fprint(2, "cfs: %s: %r\n", s);
6413e12c5d1SDavid du Colombier }
6423e12c5d1SDavid du Colombier 
6433e12c5d1SDavid du Colombier /*
6443e12c5d1SDavid du Colombier  *  send a reply to the client
6453e12c5d1SDavid du Colombier  */
6463e12c5d1SDavid du Colombier void
6473e12c5d1SDavid du Colombier sendreply(char *err)
6483e12c5d1SDavid du Colombier {
6493e12c5d1SDavid du Colombier 
6503e12c5d1SDavid du Colombier 	if(err){
6513e12c5d1SDavid du Colombier 		c.rhdr.type = Rerror;
6523e12c5d1SDavid du Colombier 		strncpy(c.rhdr.ename, err, ERRLEN);
6533e12c5d1SDavid du Colombier 	}else{
6543e12c5d1SDavid du Colombier 		c.rhdr.type = c.thdr.type+1;
6553e12c5d1SDavid du Colombier 		c.rhdr.fid = c.thdr.fid;
6563e12c5d1SDavid du Colombier 	}
6573e12c5d1SDavid du Colombier 	c.rhdr.tag = c.thdr.tag;
6583e12c5d1SDavid du Colombier 	sendmsg(&c, &c.rhdr);
6593e12c5d1SDavid du Colombier }
6603e12c5d1SDavid du Colombier 
6613e12c5d1SDavid du Colombier /*
6623e12c5d1SDavid du Colombier  *  send a request to the server, get the reply, and send that to
6633e12c5d1SDavid du Colombier  *  the client
6643e12c5d1SDavid du Colombier  */
6653e12c5d1SDavid du Colombier int
6663e12c5d1SDavid du Colombier delegate(void)
6673e12c5d1SDavid du Colombier {
6683e12c5d1SDavid du Colombier 	sendmsg(&s, &c.thdr);
6693e12c5d1SDavid du Colombier 	rcvmsg(&s, &s.rhdr);
6703e12c5d1SDavid du Colombier 	sendmsg(&c, &s.rhdr);
6713e12c5d1SDavid du Colombier 	return c.thdr.type+1 == s.rhdr.type ? 0 : -1;
6723e12c5d1SDavid du Colombier }
6733e12c5d1SDavid du Colombier 
6743e12c5d1SDavid du Colombier /*
6753e12c5d1SDavid du Colombier  *  send a request to the server and get a reply
6763e12c5d1SDavid du Colombier  */
6773e12c5d1SDavid du Colombier int
6783e12c5d1SDavid du Colombier askserver(void)
6793e12c5d1SDavid du Colombier {
6803e12c5d1SDavid du Colombier 	s.thdr.tag = c.thdr.tag;
6813e12c5d1SDavid du Colombier 	sendmsg(&s, &s.thdr);
6823e12c5d1SDavid du Colombier 	rcvmsg(&s, &s.rhdr);
6833e12c5d1SDavid du Colombier 	return s.thdr.type+1 == s.rhdr.type ? 0 : -1;
6843e12c5d1SDavid du Colombier }
6853e12c5d1SDavid du Colombier 
6863e12c5d1SDavid du Colombier /*
6873e12c5d1SDavid du Colombier  *  send/receive messages with logging
6883e12c5d1SDavid du Colombier  */
6893e12c5d1SDavid du Colombier void
6903e12c5d1SDavid du Colombier sendmsg(P9fs *p, Fcall *f)
6913e12c5d1SDavid du Colombier {
692*7dd7cddfSDavid du Colombier 	DPRINT(2, "->%s: %F\n", p->name, f);
6933e12c5d1SDavid du Colombier 
6943e12c5d1SDavid du Colombier 	p->len = convS2M(f, datasnd);
695219b2ee8SDavid du Colombier 	if(write9p(p->fd[1], datasnd, p->len)!=p->len)
6963e12c5d1SDavid du Colombier 		error("smdmsg");
6973e12c5d1SDavid du Colombier }
6983e12c5d1SDavid du Colombier 
6993e12c5d1SDavid du Colombier void
7003e12c5d1SDavid du Colombier dump(uchar *p, int len)
7013e12c5d1SDavid du Colombier {
7023e12c5d1SDavid du Colombier 	fprint(2, "%d bytes", len);
7033e12c5d1SDavid du Colombier 	while(len > 0){
7043e12c5d1SDavid du Colombier 		fprint(2, " %.2ux", *p++);
7053e12c5d1SDavid du Colombier 		len--;
7063e12c5d1SDavid du Colombier 	}
7073e12c5d1SDavid du Colombier 	fprint(2, "\n");
7083e12c5d1SDavid du Colombier }
7093e12c5d1SDavid du Colombier 
7103e12c5d1SDavid du Colombier void
7113e12c5d1SDavid du Colombier rcvmsg(P9fs *p, Fcall *f)
7123e12c5d1SDavid du Colombier {
7133e12c5d1SDavid du Colombier 	int olen;
714*7dd7cddfSDavid du Colombier 	char buf[128];
7153e12c5d1SDavid du Colombier 
7163e12c5d1SDavid du Colombier 	olen = p->len;
7173e12c5d1SDavid du Colombier retry:
718219b2ee8SDavid du Colombier 	p->len = read9p(p->fd[0], datarcv, sizeof(datarcv));
719*7dd7cddfSDavid du Colombier 	if(p->len <= 0){
720*7dd7cddfSDavid du Colombier 		sprint(buf, "read9p(%d)->%ld: %r", p->fd[0], p->len);
721*7dd7cddfSDavid du Colombier 		error(buf);
722*7dd7cddfSDavid du Colombier 	}
7233e12c5d1SDavid du Colombier 	if(p->len==2 && datarcv[0]=='O' && datarcv[1]=='K')
7243e12c5d1SDavid du Colombier 		goto retry;
7253e12c5d1SDavid du Colombier 	if(convM2S(datarcv, f, p->len) == 0)
7263e12c5d1SDavid du Colombier 		error("rcvmsg format error");
7273e12c5d1SDavid du Colombier 	if(f->type != Rauth && (f->fid<0 || Nfid<=f->fid)){
7283e12c5d1SDavid du Colombier 		fprint(2, "<-%s: %d %s on %d\n", p->name, f->type,
7293e12c5d1SDavid du Colombier 			mname[f->type]? mname[f->type] : "mystery",
7303e12c5d1SDavid du Colombier 			f->fid);
7313e12c5d1SDavid du Colombier 		dump((uchar*)datasnd, olen);
7323e12c5d1SDavid du Colombier 		dump((uchar*)datarcv, p->len);
7333e12c5d1SDavid du Colombier 		error("rcvmsg fid out of range");
7343e12c5d1SDavid du Colombier 	}
735*7dd7cddfSDavid du Colombier 	DPRINT(2, "<-%s: %F\n", p->name, f);
7363e12c5d1SDavid du Colombier }
737