xref: /plan9-contrib/sys/src/cmd/usb/lib/fs.c (revision 906943f9f6b8411972abb5e3a03ed19f74be7ccc)
1*906943f9SDavid du Colombier /*
2*906943f9SDavid du Colombier  * Framework for USB devices that provide a file tree.
3*906943f9SDavid du Colombier  * The main process (usbd or the driver's main proc)
4*906943f9SDavid du Colombier  * calls fsinit() to start FS operation.
5*906943f9SDavid du Colombier  *
6*906943f9SDavid du Colombier  * One or more drivers call fsstart/fsend to register
7*906943f9SDavid du Colombier  * or unregister their operations for their subtrees.
8*906943f9SDavid du Colombier  *
9*906943f9SDavid du Colombier  * root dir has qids with 0 in high 32 bits.
10*906943f9SDavid du Colombier  * for other files we keep the device id in there.
11*906943f9SDavid du Colombier  * The low 32 bits for directories at / must be 0.
12*906943f9SDavid du Colombier  */
13*906943f9SDavid du Colombier #include <u.h>
14*906943f9SDavid du Colombier #include <libc.h>
15*906943f9SDavid du Colombier #include <thread.h>
16*906943f9SDavid du Colombier #include <fcall.h>
17*906943f9SDavid du Colombier #include "usb.h"
18*906943f9SDavid du Colombier #include "usbfs.h"
19*906943f9SDavid du Colombier 
20*906943f9SDavid du Colombier #undef dprint
21*906943f9SDavid du Colombier #define dprint if(usbfsdebug)fprint
22*906943f9SDavid du Colombier 
23*906943f9SDavid du Colombier typedef struct Rpc Rpc;
24*906943f9SDavid du Colombier 
25*906943f9SDavid du Colombier enum
26*906943f9SDavid du Colombier {
27*906943f9SDavid du Colombier 	Nproc = 3,		/* max nb. of cached FS procs */
28*906943f9SDavid du Colombier 
29*906943f9SDavid du Colombier 	Nofid = ~0,		/* null value for fid number */
30*906943f9SDavid du Colombier 	Notag = ~0,		/* null value for tags */
31*906943f9SDavid du Colombier 	Dietag = 0xdead,		/* fake tag to ask outproc to die */
32*906943f9SDavid du Colombier 
33*906943f9SDavid du Colombier 	Stack = 16 * 1024,
34*906943f9SDavid du Colombier 
35*906943f9SDavid du Colombier 	/* Fsproc requests */
36*906943f9SDavid du Colombier 	Run = 0,		/* call f(r) */
37*906943f9SDavid du Colombier 	Exit,			/* terminate */
38*906943f9SDavid du Colombier 
39*906943f9SDavid du Colombier };
40*906943f9SDavid du Colombier 
41*906943f9SDavid du Colombier struct Rpc
42*906943f9SDavid du Colombier {
43*906943f9SDavid du Colombier 	Fcall	t;
44*906943f9SDavid du Colombier 	Fcall	r;
45*906943f9SDavid du Colombier 	Fid*	fid;
46*906943f9SDavid du Colombier 	int	flushed;
47*906943f9SDavid du Colombier 	Rpc*	next;
48*906943f9SDavid du Colombier 	char	data[Bufsize];
49*906943f9SDavid du Colombier };
50*906943f9SDavid du Colombier 
51*906943f9SDavid du Colombier int usbfsdebug;
52*906943f9SDavid du Colombier 
53*906943f9SDavid du Colombier char Enotfound[] = "file not found";
54*906943f9SDavid du Colombier char Etoosmall[] = "parameter too small";
55*906943f9SDavid du Colombier char Eio[] = "i/o error";
56*906943f9SDavid du Colombier char Eperm[] = "permission denied";
57*906943f9SDavid du Colombier char Ebadcall[] = "unknown fs call";
58*906943f9SDavid du Colombier char Ebadfid[] = "fid not found";
59*906943f9SDavid du Colombier char Einuse[] = "fid already in use";
60*906943f9SDavid du Colombier char Eisopen[] = "it is already open";
61*906943f9SDavid du Colombier char Ebadctl[] = "unknown control request";
62*906943f9SDavid du Colombier 
63*906943f9SDavid du Colombier static char *user;
64*906943f9SDavid du Colombier static ulong epoch;
65*906943f9SDavid du Colombier static ulong msgsize = Msgsize;
66*906943f9SDavid du Colombier static int fsfd = -1;
67*906943f9SDavid du Colombier static Channel *outc;	/* of Rpc* */
68*906943f9SDavid du Colombier 
69*906943f9SDavid du Colombier static QLock rpclck;	/* protect vars in this block */
70*906943f9SDavid du Colombier static Fid *freefids;
71*906943f9SDavid du Colombier static Fid *fids;
72*906943f9SDavid du Colombier static Rpc *freerpcs;
73*906943f9SDavid du Colombier static Rpc *rpcs;
74*906943f9SDavid du Colombier 
75*906943f9SDavid du Colombier static Channel*procc;
76*906943f9SDavid du Colombier static Channel*endc;
77*906943f9SDavid du Colombier 
78*906943f9SDavid du Colombier static Usbfs* fsops;
79*906943f9SDavid du Colombier 
80*906943f9SDavid du Colombier static void fsioproc(void*);
81*906943f9SDavid du Colombier 
82*906943f9SDavid du Colombier static void
83*906943f9SDavid du Colombier schedproc(void*)
84*906943f9SDavid du Colombier {
85*906943f9SDavid du Colombier 	Channel *proc[Nproc];
86*906943f9SDavid du Colombier 	int nproc;
87*906943f9SDavid du Colombier 	Channel *p;
88*906943f9SDavid du Colombier 
89*906943f9SDavid du Colombier 	Alt a[] =
90*906943f9SDavid du Colombier 	{
91*906943f9SDavid du Colombier 		{procc, &proc[0], CHANSND},
92*906943f9SDavid du Colombier 		{endc, &p, CHANRCV},
93*906943f9SDavid du Colombier 		{nil, nil, CHANEND}
94*906943f9SDavid du Colombier 	};
95*906943f9SDavid du Colombier 	memset(proc, 0, sizeof(proc));
96*906943f9SDavid du Colombier 	nproc = 0;
97*906943f9SDavid du Colombier 	for(;;){
98*906943f9SDavid du Colombier 		if(nproc == 0){
99*906943f9SDavid du Colombier 			proc[0] = chancreate(sizeof(Rpc*), 0);
100*906943f9SDavid du Colombier 			proccreate(fsioproc, proc[0], Stack);
101*906943f9SDavid du Colombier 			nproc++;
102*906943f9SDavid du Colombier 		}
103*906943f9SDavid du Colombier 		switch(alt(a)){
104*906943f9SDavid du Colombier 		case 0:
105*906943f9SDavid du Colombier 			proc[0] = nil;
106*906943f9SDavid du Colombier 			if(nproc > 1){
107*906943f9SDavid du Colombier 				proc[0] = proc[nproc-1];
108*906943f9SDavid du Colombier 				proc[nproc-1] = nil;
109*906943f9SDavid du Colombier 			}
110*906943f9SDavid du Colombier 			nproc--;
111*906943f9SDavid du Colombier 			break;
112*906943f9SDavid du Colombier 		case 1:
113*906943f9SDavid du Colombier 			if(nproc < nelem(proc))
114*906943f9SDavid du Colombier 				proc[nproc++] = p;
115*906943f9SDavid du Colombier 			else
116*906943f9SDavid du Colombier 				sendp(p, nil);
117*906943f9SDavid du Colombier 			break;
118*906943f9SDavid du Colombier 		default:
119*906943f9SDavid du Colombier 			sysfatal("alt");
120*906943f9SDavid du Colombier 		}
121*906943f9SDavid du Colombier 	}
122*906943f9SDavid du Colombier }
123*906943f9SDavid du Colombier 
124*906943f9SDavid du Colombier static void
125*906943f9SDavid du Colombier dump(void)
126*906943f9SDavid du Colombier {
127*906943f9SDavid du Colombier 	Rpc *rpc;
128*906943f9SDavid du Colombier 	Fid *fid;
129*906943f9SDavid du Colombier 
130*906943f9SDavid du Colombier 	qlock(&rpclck);
131*906943f9SDavid du Colombier 	fprint(2, "dump:\n");
132*906943f9SDavid du Colombier 	for(rpc = rpcs; rpc != nil; rpc = rpc->next)
133*906943f9SDavid du Colombier 		fprint(2, "rpc %#p %F next %#p\n", rpc, &rpc->t, rpc->next);
134*906943f9SDavid du Colombier 	for(fid = fids; fid != nil; fid = fid->next)
135*906943f9SDavid du Colombier 		fprint(2, "fid %d qid %#llux omode %d aux %#p\n",
136*906943f9SDavid du Colombier 			fid->fid, fid->qid.path, fid->omode, fid->aux);
137*906943f9SDavid du Colombier 	fprint(2, "\n");
138*906943f9SDavid du Colombier 	qunlock(&rpclck);
139*906943f9SDavid du Colombier }
140*906943f9SDavid du Colombier 
141*906943f9SDavid du Colombier static Rpc*
142*906943f9SDavid du Colombier newrpc(void)
143*906943f9SDavid du Colombier {
144*906943f9SDavid du Colombier 	Rpc *r;
145*906943f9SDavid du Colombier 
146*906943f9SDavid du Colombier 	qlock(&rpclck);
147*906943f9SDavid du Colombier 	r = freerpcs;
148*906943f9SDavid du Colombier 	if(r != nil)
149*906943f9SDavid du Colombier 		freerpcs = r->next;
150*906943f9SDavid du Colombier 	else
151*906943f9SDavid du Colombier 		r = emallocz(sizeof(Rpc), 0);
152*906943f9SDavid du Colombier 	r->next = rpcs;
153*906943f9SDavid du Colombier 	rpcs = r;
154*906943f9SDavid du Colombier 	r->t.tag = r->r.tag = Notag;
155*906943f9SDavid du Colombier 	r->t.fid = r->r.fid = Nofid;
156*906943f9SDavid du Colombier 	r->t.type = r->r.type = 0;
157*906943f9SDavid du Colombier 	r->flushed = 0;
158*906943f9SDavid du Colombier 	r->fid = nil;
159*906943f9SDavid du Colombier 	r->r.data = (char*)r->data;
160*906943f9SDavid du Colombier 	qunlock(&rpclck);
161*906943f9SDavid du Colombier 	return r;
162*906943f9SDavid du Colombier }
163*906943f9SDavid du Colombier 
164*906943f9SDavid du Colombier static void
165*906943f9SDavid du Colombier freerpc(Rpc *r)
166*906943f9SDavid du Colombier {
167*906943f9SDavid du Colombier 	Rpc **l;
168*906943f9SDavid du Colombier 	if(r == nil)
169*906943f9SDavid du Colombier 		return;
170*906943f9SDavid du Colombier 	qlock(&rpclck);
171*906943f9SDavid du Colombier 	for(l = &rpcs; *l != nil && *l != r; l = &(*l)->next)
172*906943f9SDavid du Colombier 		;
173*906943f9SDavid du Colombier 	assert(*l == r);
174*906943f9SDavid du Colombier 	*l = r->next;
175*906943f9SDavid du Colombier 	r->next = freerpcs;
176*906943f9SDavid du Colombier 	freerpcs = r;
177*906943f9SDavid du Colombier 	r->t.type = 0;
178*906943f9SDavid du Colombier 	r->t.tag = 0x77777777;
179*906943f9SDavid du Colombier 	qunlock(&rpclck);
180*906943f9SDavid du Colombier }
181*906943f9SDavid du Colombier 
182*906943f9SDavid du Colombier static void
183*906943f9SDavid du Colombier flushrpc(int tag)
184*906943f9SDavid du Colombier {
185*906943f9SDavid du Colombier 	Rpc *r;
186*906943f9SDavid du Colombier 
187*906943f9SDavid du Colombier 	qlock(&rpclck);
188*906943f9SDavid du Colombier 	for(r = rpcs; r != nil; r = r->next)
189*906943f9SDavid du Colombier 		if(r->t.tag == tag){
190*906943f9SDavid du Colombier 			r->flushed = 1;
191*906943f9SDavid du Colombier 			break;
192*906943f9SDavid du Colombier 		}
193*906943f9SDavid du Colombier 	qunlock(&rpclck);
194*906943f9SDavid du Colombier }
195*906943f9SDavid du Colombier 
196*906943f9SDavid du Colombier static Fid*
197*906943f9SDavid du Colombier getfid(int fid, int alloc)
198*906943f9SDavid du Colombier {
199*906943f9SDavid du Colombier 	Fid *f;
200*906943f9SDavid du Colombier 
201*906943f9SDavid du Colombier 	qlock(&rpclck);
202*906943f9SDavid du Colombier 	for(f = fids; f != nil && f->fid != fid; f = f->next)
203*906943f9SDavid du Colombier 		;
204*906943f9SDavid du Colombier 	if(f != nil && alloc != 0){	/* fid in use */
205*906943f9SDavid du Colombier 		qunlock(&rpclck);
206*906943f9SDavid du Colombier 		return nil;
207*906943f9SDavid du Colombier 	}
208*906943f9SDavid du Colombier 	if(f == nil && alloc != 0){
209*906943f9SDavid du Colombier 		if(freefids != nil){
210*906943f9SDavid du Colombier 			f = freefids;
211*906943f9SDavid du Colombier 			freefids = freefids->next;
212*906943f9SDavid du Colombier 		}else
213*906943f9SDavid du Colombier 			f = emallocz(sizeof(Fid), 1);
214*906943f9SDavid du Colombier 		f->fid = fid;
215*906943f9SDavid du Colombier 		f->aux = nil;
216*906943f9SDavid du Colombier 		f->omode = ONONE;
217*906943f9SDavid du Colombier 		f->next = fids;
218*906943f9SDavid du Colombier 		fids = f;
219*906943f9SDavid du Colombier 	}
220*906943f9SDavid du Colombier 	qunlock(&rpclck);
221*906943f9SDavid du Colombier 	return f;
222*906943f9SDavid du Colombier }
223*906943f9SDavid du Colombier 
224*906943f9SDavid du Colombier static void
225*906943f9SDavid du Colombier freefid(Fid *f)
226*906943f9SDavid du Colombier {
227*906943f9SDavid du Colombier 	Fid **l;
228*906943f9SDavid du Colombier 
229*906943f9SDavid du Colombier 	if(f == nil)
230*906943f9SDavid du Colombier 		return;
231*906943f9SDavid du Colombier 	if(fsops->clunk != nil)
232*906943f9SDavid du Colombier 		fsops->clunk(fsops, f);
233*906943f9SDavid du Colombier 	qlock(&rpclck);
234*906943f9SDavid du Colombier 	for(l = &fids; *l != nil && *l != f; l = &(*l)->next)
235*906943f9SDavid du Colombier 		;
236*906943f9SDavid du Colombier 	assert(*l == f);
237*906943f9SDavid du Colombier 	*l = f->next;
238*906943f9SDavid du Colombier 	f->next = freefids;
239*906943f9SDavid du Colombier 	freefids = f;
240*906943f9SDavid du Colombier 	qunlock(&rpclck);
241*906943f9SDavid du Colombier }
242*906943f9SDavid du Colombier 
243*906943f9SDavid du Colombier static Rpc*
244*906943f9SDavid du Colombier fserror(Rpc *rpc, char* fmt, ...)
245*906943f9SDavid du Colombier {
246*906943f9SDavid du Colombier 	va_list arg;
247*906943f9SDavid du Colombier 	char *c;
248*906943f9SDavid du Colombier 
249*906943f9SDavid du Colombier 	va_start(arg, fmt);
250*906943f9SDavid du Colombier 	c = (char*)rpc->data;
251*906943f9SDavid du Colombier 	vseprint(c, c+sizeof(rpc->data), fmt, arg);
252*906943f9SDavid du Colombier 	va_end(arg);
253*906943f9SDavid du Colombier 	rpc->r.type = Rerror;
254*906943f9SDavid du Colombier 	rpc->r.ename = (char*)rpc->data;
255*906943f9SDavid du Colombier 	return rpc;
256*906943f9SDavid du Colombier }
257*906943f9SDavid du Colombier 
258*906943f9SDavid du Colombier static Rpc*
259*906943f9SDavid du Colombier fsversion(Rpc *r)
260*906943f9SDavid du Colombier {
261*906943f9SDavid du Colombier 	if(r->t.msize < 256)
262*906943f9SDavid du Colombier 		return fserror(r, Etoosmall);
263*906943f9SDavid du Colombier 	if(strncmp(r->t.version, "9P2000", 6) != 0)
264*906943f9SDavid du Colombier 		return fserror(r, "wrong version");
265*906943f9SDavid du Colombier 	if(r->t.msize < msgsize)
266*906943f9SDavid du Colombier 		msgsize = r->t.msize;
267*906943f9SDavid du Colombier 	r->r.msize = msgsize;
268*906943f9SDavid du Colombier 	r->r.version = "9P2000";
269*906943f9SDavid du Colombier 	return r;
270*906943f9SDavid du Colombier }
271*906943f9SDavid du Colombier 
272*906943f9SDavid du Colombier static Rpc*
273*906943f9SDavid du Colombier fsattach(Rpc *r)
274*906943f9SDavid du Colombier {
275*906943f9SDavid du Colombier 	static int already;
276*906943f9SDavid du Colombier 
277*906943f9SDavid du Colombier 	/* Reload user because at boot it could be still none */
278*906943f9SDavid du Colombier 	user=getuser();
279*906943f9SDavid du Colombier 	if(already++ > 0 && strcmp(r->t.uname, user) != 0)
280*906943f9SDavid du Colombier 		return fserror(r, Eperm);
281*906943f9SDavid du Colombier 	if(r->fid == nil)
282*906943f9SDavid du Colombier 		return fserror(r, Einuse);
283*906943f9SDavid du Colombier 
284*906943f9SDavid du Colombier 	r->r.qid.type = QTDIR;
285*906943f9SDavid du Colombier 	r->r.qid.path = fsops->qid;
286*906943f9SDavid du Colombier 	r->r.qid.vers = 0;
287*906943f9SDavid du Colombier 	r->fid->qid = r->r.qid;
288*906943f9SDavid du Colombier 	return r;
289*906943f9SDavid du Colombier }
290*906943f9SDavid du Colombier 
291*906943f9SDavid du Colombier static Rpc*
292*906943f9SDavid du Colombier fswalk(Rpc *r)
293*906943f9SDavid du Colombier {
294*906943f9SDavid du Colombier 	int i;
295*906943f9SDavid du Colombier 	Fid *nfid;
296*906943f9SDavid du Colombier 	Fid *ofid;
297*906943f9SDavid du Colombier 
298*906943f9SDavid du Colombier 	if(r->fid->omode != ONONE)
299*906943f9SDavid du Colombier 		return fserror(r, Eisopen);
300*906943f9SDavid du Colombier 
301*906943f9SDavid du Colombier 	nfid = nil;
302*906943f9SDavid du Colombier 	ofid = r->fid;
303*906943f9SDavid du Colombier 	if(r->t.newfid != r->t.fid){
304*906943f9SDavid du Colombier 		nfid = getfid(r->t.newfid, 1);
305*906943f9SDavid du Colombier 		if(nfid == nil)
306*906943f9SDavid du Colombier 			return fserror(r, Einuse);
307*906943f9SDavid du Colombier 		nfid->qid = r->fid->qid;
308*906943f9SDavid du Colombier 		if(fsops->clone != nil)
309*906943f9SDavid du Colombier 			fsops->clone(fsops, ofid, nfid);
310*906943f9SDavid du Colombier 		else
311*906943f9SDavid du Colombier 			nfid->aux = r->fid->aux;
312*906943f9SDavid du Colombier 		r->fid = nfid;
313*906943f9SDavid du Colombier 	}
314*906943f9SDavid du Colombier 	r->r.nwqid = 0;
315*906943f9SDavid du Colombier 	for(i = 0; i < r->t.nwname; i++)
316*906943f9SDavid du Colombier 		if(fsops->walk(fsops, r->fid, r->t.wname[i]) < 0)
317*906943f9SDavid du Colombier 			break;
318*906943f9SDavid du Colombier 		else
319*906943f9SDavid du Colombier 			r->r.wqid[i] = r->fid->qid;
320*906943f9SDavid du Colombier 	r->r.nwqid = i;
321*906943f9SDavid du Colombier 	if(i != r->t.nwname && r->t.nwname > 0){
322*906943f9SDavid du Colombier 		if(nfid != nil)
323*906943f9SDavid du Colombier 			freefid(nfid);
324*906943f9SDavid du Colombier 		r->fid = ofid;
325*906943f9SDavid du Colombier 	}
326*906943f9SDavid du Colombier 	if(i == 0 && r->t.nwname > 0)
327*906943f9SDavid du Colombier 		return fserror(r, "%r");
328*906943f9SDavid du Colombier 	return r;
329*906943f9SDavid du Colombier }
330*906943f9SDavid du Colombier 
331*906943f9SDavid du Colombier static void
332*906943f9SDavid du Colombier fsioproc(void* a)
333*906943f9SDavid du Colombier {
334*906943f9SDavid du Colombier 	Channel *p = a;
335*906943f9SDavid du Colombier 	Rpc *rpc;
336*906943f9SDavid du Colombier 	long rc;
337*906943f9SDavid du Colombier 	Fcall *t;
338*906943f9SDavid du Colombier 	Fcall *r;
339*906943f9SDavid du Colombier 	Fid *fid;
340*906943f9SDavid du Colombier 
341*906943f9SDavid du Colombier 	dprint(2, "%s: fsioproc pid %d\n", argv0, getpid());
342*906943f9SDavid du Colombier 	while((rpc = recvp(p)) != nil){
343*906943f9SDavid du Colombier 		t = &rpc->t;
344*906943f9SDavid du Colombier 		r = &rpc->r;
345*906943f9SDavid du Colombier 		fid = rpc->fid;
346*906943f9SDavid du Colombier 		rc = -1;
347*906943f9SDavid du Colombier 		dprint(2, "%s: fsioproc pid %d: req %d\n", argv0, getpid(), t->type);
348*906943f9SDavid du Colombier 		switch(t->type){
349*906943f9SDavid du Colombier 		case Topen:
350*906943f9SDavid du Colombier 			rc = fsops->open(fsops, fid, t->mode);
351*906943f9SDavid du Colombier 			if(rc >= 0){
352*906943f9SDavid du Colombier 				r->iounit = 0;
353*906943f9SDavid du Colombier 				r->qid = fid->qid;
354*906943f9SDavid du Colombier 				fid->omode = t->mode & 3;
355*906943f9SDavid du Colombier 			}
356*906943f9SDavid du Colombier 			break;
357*906943f9SDavid du Colombier 		case Tread:
358*906943f9SDavid du Colombier 			rc = fsops->read(fsops,fid,r->data,t->count,t->offset);
359*906943f9SDavid du Colombier 			if(rc >= 0){
360*906943f9SDavid du Colombier 				if(rc > t->count)
361*906943f9SDavid du Colombier 					print("%s: bug: read %ld bytes > %ud wanted\n",
362*906943f9SDavid du Colombier 						argv0, rc, t->count);
363*906943f9SDavid du Colombier 				r->count = rc;
364*906943f9SDavid du Colombier 			}
365*906943f9SDavid du Colombier 			break;
366*906943f9SDavid du Colombier 		case Twrite:
367*906943f9SDavid du Colombier 			rc = fsops->write(fsops,fid,t->data,t->count,t->offset);
368*906943f9SDavid du Colombier 			r->count = rc;
369*906943f9SDavid du Colombier 			break;
370*906943f9SDavid du Colombier 		default:
371*906943f9SDavid du Colombier 			sysfatal("fsioproc: bad type");
372*906943f9SDavid du Colombier 		}
373*906943f9SDavid du Colombier 		if(rc < 0)
374*906943f9SDavid du Colombier 			sendp(outc, fserror(rpc, "%r"));
375*906943f9SDavid du Colombier 		else
376*906943f9SDavid du Colombier 			sendp(outc, rpc);
377*906943f9SDavid du Colombier 		sendp(endc, p);
378*906943f9SDavid du Colombier 	}
379*906943f9SDavid du Colombier 	chanfree(p);
380*906943f9SDavid du Colombier 	dprint(2, "%s: fsioproc %d exiting\n", argv0, getpid());
381*906943f9SDavid du Colombier 	threadexits(nil);
382*906943f9SDavid du Colombier }
383*906943f9SDavid du Colombier 
384*906943f9SDavid du Colombier static Rpc*
385*906943f9SDavid du Colombier fsopen(Rpc *r)
386*906943f9SDavid du Colombier {
387*906943f9SDavid du Colombier 	Channel *p;
388*906943f9SDavid du Colombier 
389*906943f9SDavid du Colombier 	if(r->fid->omode != ONONE)
390*906943f9SDavid du Colombier 		return fserror(r, Eisopen);
391*906943f9SDavid du Colombier 	if((r->t.mode & 3) != OREAD && (r->fid->qid.type & QTDIR) != 0)
392*906943f9SDavid du Colombier 		return fserror(r, Eperm);
393*906943f9SDavid du Colombier 	p = recvp(procc);
394*906943f9SDavid du Colombier 	sendp(p, r);
395*906943f9SDavid du Colombier 	return nil;
396*906943f9SDavid du Colombier }
397*906943f9SDavid du Colombier 
398*906943f9SDavid du Colombier int
399*906943f9SDavid du Colombier usbdirread(Usbfs*f, Qid q, char *data, long cnt, vlong off, Dirgen gen, void *arg)
400*906943f9SDavid du Colombier {
401*906943f9SDavid du Colombier 	Dir d;
402*906943f9SDavid du Colombier 	char name[Namesz];
403*906943f9SDavid du Colombier 	int i;
404*906943f9SDavid du Colombier 	int n;
405*906943f9SDavid du Colombier 	int nd;
406*906943f9SDavid du Colombier 
407*906943f9SDavid du Colombier 	memset(&d, 0, sizeof(d));
408*906943f9SDavid du Colombier 	d.name = name;
409*906943f9SDavid du Colombier 	d.uid = d.gid = d.muid = user;
410*906943f9SDavid du Colombier 	d.atime = time(nil);
411*906943f9SDavid du Colombier 	d.mtime = epoch;
412*906943f9SDavid du Colombier 	d.length = 0;
413*906943f9SDavid du Colombier 	for(i = n = 0; gen(f, q, i, &d, arg) >= 0; i++){
414*906943f9SDavid du Colombier 		if(usbfsdebug > 1)
415*906943f9SDavid du Colombier 			fprint(2, "%s: dir %d q %#llux: %D\n", argv0, i, q.path, &d);
416*906943f9SDavid du Colombier 		nd = convD2M(&d, (uchar*)data+n, cnt-n);
417*906943f9SDavid du Colombier 		if(nd <= BIT16SZ)
418*906943f9SDavid du Colombier 			break;
419*906943f9SDavid du Colombier 		if(off > 0)
420*906943f9SDavid du Colombier 			off -= nd;
421*906943f9SDavid du Colombier 		else
422*906943f9SDavid du Colombier 			n += nd;
423*906943f9SDavid du Colombier 		d.name = name;
424*906943f9SDavid du Colombier 		d.uid = d.gid = d.muid = user;
425*906943f9SDavid du Colombier 		d.atime = time(nil);
426*906943f9SDavid du Colombier 		d.mtime = epoch;
427*906943f9SDavid du Colombier 		d.length = 0;
428*906943f9SDavid du Colombier 	}
429*906943f9SDavid du Colombier 	return n;
430*906943f9SDavid du Colombier }
431*906943f9SDavid du Colombier 
432*906943f9SDavid du Colombier long
433*906943f9SDavid du Colombier usbreadbuf(void *data, long count, vlong offset, void *buf, long n)
434*906943f9SDavid du Colombier {
435*906943f9SDavid du Colombier 	if(offset >= n)
436*906943f9SDavid du Colombier 		return 0;
437*906943f9SDavid du Colombier 	if(offset + count > n)
438*906943f9SDavid du Colombier 		count = n - offset;
439*906943f9SDavid du Colombier 	memmove(data, (char*)buf + offset, count);
440*906943f9SDavid du Colombier 	return count;
441*906943f9SDavid du Colombier }
442*906943f9SDavid du Colombier 
443*906943f9SDavid du Colombier static Rpc*
444*906943f9SDavid du Colombier fsread(Rpc *r)
445*906943f9SDavid du Colombier {
446*906943f9SDavid du Colombier 	Channel *p;
447*906943f9SDavid du Colombier 
448*906943f9SDavid du Colombier 	if(r->fid->omode != OREAD && r->fid->omode != ORDWR)
449*906943f9SDavid du Colombier 		return fserror(r, Eperm);
450*906943f9SDavid du Colombier 	p = recvp(procc);
451*906943f9SDavid du Colombier 	sendp(p, r);
452*906943f9SDavid du Colombier 	return nil;
453*906943f9SDavid du Colombier }
454*906943f9SDavid du Colombier 
455*906943f9SDavid du Colombier static Rpc*
456*906943f9SDavid du Colombier fswrite(Rpc *r)
457*906943f9SDavid du Colombier {
458*906943f9SDavid du Colombier 	Channel *p;
459*906943f9SDavid du Colombier 
460*906943f9SDavid du Colombier 	if(r->fid->omode != OWRITE && r->fid->omode != ORDWR)
461*906943f9SDavid du Colombier 		return fserror(r, Eperm);
462*906943f9SDavid du Colombier 	p = recvp(procc);
463*906943f9SDavid du Colombier 	sendp(p, r);
464*906943f9SDavid du Colombier 	return nil;
465*906943f9SDavid du Colombier }
466*906943f9SDavid du Colombier 
467*906943f9SDavid du Colombier static Rpc*
468*906943f9SDavid du Colombier fsclunk(Rpc *r)
469*906943f9SDavid du Colombier {
470*906943f9SDavid du Colombier 	freefid(r->fid);
471*906943f9SDavid du Colombier 	return r;
472*906943f9SDavid du Colombier }
473*906943f9SDavid du Colombier 
474*906943f9SDavid du Colombier static Rpc*
475*906943f9SDavid du Colombier fsno(Rpc *r)
476*906943f9SDavid du Colombier {
477*906943f9SDavid du Colombier 	return fserror(r, Eperm);
478*906943f9SDavid du Colombier }
479*906943f9SDavid du Colombier 
480*906943f9SDavid du Colombier static Rpc*
481*906943f9SDavid du Colombier fsstat(Rpc *r)
482*906943f9SDavid du Colombier {
483*906943f9SDavid du Colombier 	Dir d;
484*906943f9SDavid du Colombier 	char name[Namesz];
485*906943f9SDavid du Colombier 
486*906943f9SDavid du Colombier 	memset(&d, 0, sizeof(d));
487*906943f9SDavid du Colombier 	d.name = name;
488*906943f9SDavid du Colombier 	d.uid = d.gid = d.muid = user;
489*906943f9SDavid du Colombier 	d.atime = time(nil);
490*906943f9SDavid du Colombier 	d.mtime = epoch;
491*906943f9SDavid du Colombier 	d.length = 0;
492*906943f9SDavid du Colombier 	if(fsops->stat(fsops, r->fid->qid, &d) < 0)
493*906943f9SDavid du Colombier 		return fserror(r, "%r");
494*906943f9SDavid du Colombier 	r->r.stat = (uchar*)r->data;
495*906943f9SDavid du Colombier 	r->r.nstat = convD2M(&d, (uchar*)r->data, msgsize);
496*906943f9SDavid du Colombier 	return r;
497*906943f9SDavid du Colombier }
498*906943f9SDavid du Colombier 
499*906943f9SDavid du Colombier static Rpc*
500*906943f9SDavid du Colombier fsflush(Rpc *r)
501*906943f9SDavid du Colombier {
502*906943f9SDavid du Colombier 	/*
503*906943f9SDavid du Colombier 	 * Flag it as flushed and respond.
504*906943f9SDavid du Colombier 	 * Either outproc will reply to the flushed request
505*906943f9SDavid du Colombier 	 * before responding to flush, or it will never reply to it.
506*906943f9SDavid du Colombier 	 * Note that we do NOT abort the ongoing I/O.
507*906943f9SDavid du Colombier 	 * That might leave the affected endpoints in a failed
508*906943f9SDavid du Colombier 	 * state. Instead, we pretend the request is aborted.
509*906943f9SDavid du Colombier 	 *
510*906943f9SDavid du Colombier 	 * Only open, read, and write are processed
511*906943f9SDavid du Colombier 	 * by auxiliary processes and other requests wil never be
512*906943f9SDavid du Colombier 	 * flushed in practice.
513*906943f9SDavid du Colombier 	 */
514*906943f9SDavid du Colombier 	flushrpc(r->t.oldtag);
515*906943f9SDavid du Colombier 	return r;
516*906943f9SDavid du Colombier }
517*906943f9SDavid du Colombier 
518*906943f9SDavid du Colombier Rpc* (*fscalls[])(Rpc*) = {
519*906943f9SDavid du Colombier 	[Tversion]	fsversion,
520*906943f9SDavid du Colombier 	[Tauth]		fsno,
521*906943f9SDavid du Colombier 	[Tattach]	fsattach,
522*906943f9SDavid du Colombier 	[Twalk]		fswalk,
523*906943f9SDavid du Colombier 	[Topen]		fsopen,
524*906943f9SDavid du Colombier 	[Tcreate]	fsno,
525*906943f9SDavid du Colombier 	[Tread]		fsread,
526*906943f9SDavid du Colombier 	[Twrite]	fswrite,
527*906943f9SDavid du Colombier 	[Tclunk]	fsclunk,
528*906943f9SDavid du Colombier 	[Tremove]	fsno,
529*906943f9SDavid du Colombier 	[Tstat]		fsstat,
530*906943f9SDavid du Colombier 	[Twstat]	fsno,
531*906943f9SDavid du Colombier 	[Tflush]	fsflush,
532*906943f9SDavid du Colombier };
533*906943f9SDavid du Colombier 
534*906943f9SDavid du Colombier static void
535*906943f9SDavid du Colombier outproc(void*)
536*906943f9SDavid du Colombier {
537*906943f9SDavid du Colombier 	static uchar buf[Bufsize];
538*906943f9SDavid du Colombier 	Rpc *rpc;
539*906943f9SDavid du Colombier 	int nw;
540*906943f9SDavid du Colombier 	static int once = 0;
541*906943f9SDavid du Colombier 
542*906943f9SDavid du Colombier 	if(once++ != 0)
543*906943f9SDavid du Colombier 		sysfatal("more than one outproc");
544*906943f9SDavid du Colombier 	for(;;){
545*906943f9SDavid du Colombier 		do
546*906943f9SDavid du Colombier 			rpc = recvp(outc);
547*906943f9SDavid du Colombier 		while(rpc == nil);		/* a delayed reply */
548*906943f9SDavid du Colombier 		if(rpc->t.tag == Dietag)
549*906943f9SDavid du Colombier 			break;
550*906943f9SDavid du Colombier 		if(rpc->flushed){
551*906943f9SDavid du Colombier 			dprint(2, "outproc: tag %d flushed\n", rpc->t.tag);
552*906943f9SDavid du Colombier 			freerpc(rpc);
553*906943f9SDavid du Colombier 			continue;
554*906943f9SDavid du Colombier 		}
555*906943f9SDavid du Colombier 		dprint(2, "-> %F\n", &rpc->r);
556*906943f9SDavid du Colombier 		nw = convS2M(&rpc->r, buf, sizeof(buf));
557*906943f9SDavid du Colombier 		if(nw == sizeof(buf))
558*906943f9SDavid du Colombier 			fprint(2, "%s: outproc: buffer is too small\n", argv0);
559*906943f9SDavid du Colombier 		if(nw <= BIT16SZ)
560*906943f9SDavid du Colombier 			fprint(2, "%s: conS2M failed\n", argv0);
561*906943f9SDavid du Colombier 		else if(write(fsfd, buf, nw) != nw){
562*906943f9SDavid du Colombier 			fprint(2, "%s: outproc: write: %r", argv0);
563*906943f9SDavid du Colombier 			/* continue and let the reader abort us */
564*906943f9SDavid du Colombier 		}
565*906943f9SDavid du Colombier 		if(usbfsdebug > 1)
566*906943f9SDavid du Colombier 			dump();
567*906943f9SDavid du Colombier 		freerpc(rpc);
568*906943f9SDavid du Colombier 	}
569*906943f9SDavid du Colombier 	dprint(2, "%s: outproc: exiting\n", argv0);
570*906943f9SDavid du Colombier }
571*906943f9SDavid du Colombier 
572*906943f9SDavid du Colombier static void
573*906943f9SDavid du Colombier usbfs(void*)
574*906943f9SDavid du Colombier {
575*906943f9SDavid du Colombier 	Rpc *rpc;
576*906943f9SDavid du Colombier 	int nr;
577*906943f9SDavid du Colombier 	static int once = 0;
578*906943f9SDavid du Colombier 
579*906943f9SDavid du Colombier 	if(once++ != 0)
580*906943f9SDavid du Colombier 		sysfatal("more than one usbfs proc");
581*906943f9SDavid du Colombier 
582*906943f9SDavid du Colombier 	outc = chancreate(sizeof(Rpc*), 1);
583*906943f9SDavid du Colombier 	procc = chancreate(sizeof(Channel*), 0);
584*906943f9SDavid du Colombier 	endc = chancreate(sizeof(Channel*), 0);
585*906943f9SDavid du Colombier 	if(outc == nil || procc == nil || endc == nil)
586*906943f9SDavid du Colombier 		sysfatal("chancreate: %r");
587*906943f9SDavid du Colombier 	threadcreate(schedproc, nil, Stack);
588*906943f9SDavid du Colombier 	proccreate(outproc, nil, Stack);
589*906943f9SDavid du Colombier 	for(;;){
590*906943f9SDavid du Colombier 		rpc = newrpc();
591*906943f9SDavid du Colombier 		do{
592*906943f9SDavid du Colombier 			nr = read9pmsg(fsfd, rpc->data, sizeof(rpc->data));
593*906943f9SDavid du Colombier 		}while(nr == 0);
594*906943f9SDavid du Colombier 		if(nr < 0){
595*906943f9SDavid du Colombier 			dprint(2, "%s: usbfs: read: '%r'", argv0);
596*906943f9SDavid du Colombier 			if(fsops->end != nil)
597*906943f9SDavid du Colombier 				fsops->end(fsops);
598*906943f9SDavid du Colombier 			else
599*906943f9SDavid du Colombier 				closedev(fsops->dev);
600*906943f9SDavid du Colombier 			rpc->t.tag = Dietag;
601*906943f9SDavid du Colombier 			sendp(outc, rpc);
602*906943f9SDavid du Colombier 			break;
603*906943f9SDavid du Colombier 		}
604*906943f9SDavid du Colombier 		if(convM2S((uchar*)rpc->data, nr, &rpc->t) <=0){
605*906943f9SDavid du Colombier 			dprint(2, "%s: convM2S failed\n", argv0);
606*906943f9SDavid du Colombier 			freerpc(rpc);
607*906943f9SDavid du Colombier 			continue;
608*906943f9SDavid du Colombier 		}
609*906943f9SDavid du Colombier 		dprint(2, "<- %F\n", &rpc->t);
610*906943f9SDavid du Colombier 		rpc->r.tag = rpc->t.tag;
611*906943f9SDavid du Colombier 		rpc->r.type = rpc->t.type + 1;
612*906943f9SDavid du Colombier 		rpc->r.fid = rpc->t.fid;
613*906943f9SDavid du Colombier 		if(fscalls[rpc->t.type] == nil){
614*906943f9SDavid du Colombier 			sendp(outc, fserror(rpc, Ebadcall));
615*906943f9SDavid du Colombier 			continue;
616*906943f9SDavid du Colombier 		}
617*906943f9SDavid du Colombier 		if(rpc->t.fid != Nofid){
618*906943f9SDavid du Colombier 			if(rpc->t.type == Tattach)
619*906943f9SDavid du Colombier 				rpc->fid = getfid(rpc->t.fid, 1);
620*906943f9SDavid du Colombier 			else
621*906943f9SDavid du Colombier 				rpc->fid = getfid(rpc->t.fid, 0);
622*906943f9SDavid du Colombier 			if(rpc->fid == nil){
623*906943f9SDavid du Colombier 				sendp(outc, fserror(rpc, Ebadfid));
624*906943f9SDavid du Colombier 				continue;
625*906943f9SDavid du Colombier 			}
626*906943f9SDavid du Colombier 		}
627*906943f9SDavid du Colombier 		sendp(outc, fscalls[rpc->t.type](rpc));
628*906943f9SDavid du Colombier 	}
629*906943f9SDavid du Colombier 	dprint(2, "%s: ubfs: eof: exiting\n", argv0);
630*906943f9SDavid du Colombier }
631*906943f9SDavid du Colombier 
632*906943f9SDavid du Colombier void
633*906943f9SDavid du Colombier usbfsinit(char* srv, char *mnt, Usbfs *f, int flag)
634*906943f9SDavid du Colombier {
635*906943f9SDavid du Colombier 	int fd[2];
636*906943f9SDavid du Colombier 	int sfd;
637*906943f9SDavid du Colombier 	int afd;
638*906943f9SDavid du Colombier 	char sfile[40];
639*906943f9SDavid du Colombier 
640*906943f9SDavid du Colombier 	fsops = f;
641*906943f9SDavid du Colombier 	if(pipe(fd) < 0)
642*906943f9SDavid du Colombier 		sysfatal("pipe: %r");
643*906943f9SDavid du Colombier 	user = getuser();
644*906943f9SDavid du Colombier 	epoch = time(nil);
645*906943f9SDavid du Colombier 
646*906943f9SDavid du Colombier 	fmtinstall('D', dirfmt);
647*906943f9SDavid du Colombier 	fmtinstall('M', dirmodefmt);
648*906943f9SDavid du Colombier 	fmtinstall('F', fcallfmt);
649*906943f9SDavid du Colombier 	fsfd = fd[1];
650*906943f9SDavid du Colombier 	procrfork(usbfs, nil, Stack, RFNAMEG);	/* no RFFDG */
651*906943f9SDavid du Colombier 	if(srv != nil){
652*906943f9SDavid du Colombier 		snprint(sfile, sizeof(sfile), "#s/%s", srv);
653*906943f9SDavid du Colombier 		remove(sfile);
654*906943f9SDavid du Colombier 		sfd = create(sfile, OWRITE, 0660);
655*906943f9SDavid du Colombier 		if(sfd < 0)
656*906943f9SDavid du Colombier 			sysfatal("post: %r");
657*906943f9SDavid du Colombier 		snprint(sfile, sizeof(sfile), "%d", fd[0]);
658*906943f9SDavid du Colombier 		if(write(sfd, sfile, strlen(sfile)) != strlen(sfile))
659*906943f9SDavid du Colombier 			sysfatal("post: %r");
660*906943f9SDavid du Colombier 		close(sfd);
661*906943f9SDavid du Colombier 	}
662*906943f9SDavid du Colombier 	if(mnt != nil){
663*906943f9SDavid du Colombier 		sfd = dup(fd[0], -1);	/* debug */
664*906943f9SDavid du Colombier 		afd = fauth(sfd, "");
665*906943f9SDavid du Colombier 		if(afd >= 0)
666*906943f9SDavid du Colombier 			sysfatal("authentication required??");
667*906943f9SDavid du Colombier 		if(mount(sfd, -1, mnt, flag, "") < 0)
668*906943f9SDavid du Colombier 			sysfatal("mount: %r");
669*906943f9SDavid du Colombier 	}
670*906943f9SDavid du Colombier 	close(fd[0]);
671*906943f9SDavid du Colombier }
672*906943f9SDavid du Colombier 
673