1906943f9SDavid du Colombier /*
2906943f9SDavid du Colombier * Framework for USB devices that provide a file tree.
3906943f9SDavid du Colombier * The main process (usbd or the driver's main proc)
4906943f9SDavid du Colombier * calls fsinit() to start FS operation.
5906943f9SDavid du Colombier *
6906943f9SDavid du Colombier * One or more drivers call fsstart/fsend to register
7906943f9SDavid du Colombier * or unregister their operations for their subtrees.
8906943f9SDavid du Colombier *
9906943f9SDavid du Colombier * root dir has qids with 0 in high 32 bits.
10906943f9SDavid du Colombier * for other files we keep the device id in there.
11906943f9SDavid du Colombier * The low 32 bits for directories at / must be 0.
12906943f9SDavid du Colombier */
13906943f9SDavid du Colombier #include <u.h>
14906943f9SDavid du Colombier #include <libc.h>
15906943f9SDavid du Colombier #include <thread.h>
16906943f9SDavid du Colombier #include <fcall.h>
17906943f9SDavid du Colombier #include "usb.h"
18906943f9SDavid du Colombier #include "usbfs.h"
19906943f9SDavid du Colombier
20906943f9SDavid du Colombier #undef dprint
21906943f9SDavid du Colombier #define dprint if(usbfsdebug)fprint
22906943f9SDavid du Colombier
23906943f9SDavid du Colombier typedef struct Rpc Rpc;
24906943f9SDavid du Colombier
25906943f9SDavid du Colombier enum
26906943f9SDavid du Colombier {
27906943f9SDavid du Colombier Nproc = 3, /* max nb. of cached FS procs */
28906943f9SDavid du Colombier
29906943f9SDavid du Colombier Nofid = ~0, /* null value for fid number */
30906943f9SDavid du Colombier Notag = ~0, /* null value for tags */
31906943f9SDavid du Colombier Dietag = 0xdead, /* fake tag to ask outproc to die */
32906943f9SDavid du Colombier
33906943f9SDavid du Colombier Stack = 16 * 1024,
34906943f9SDavid du Colombier
35906943f9SDavid du Colombier /* Fsproc requests */
36906943f9SDavid du Colombier Run = 0, /* call f(r) */
37906943f9SDavid du Colombier Exit, /* terminate */
38906943f9SDavid du Colombier
39906943f9SDavid du Colombier };
40906943f9SDavid du Colombier
41906943f9SDavid du Colombier struct Rpc
42906943f9SDavid du Colombier {
43906943f9SDavid du Colombier Fcall t;
44906943f9SDavid du Colombier Fcall r;
45906943f9SDavid du Colombier Fid* fid;
46906943f9SDavid du Colombier int flushed;
47906943f9SDavid du Colombier Rpc* next;
48906943f9SDavid du Colombier char data[Bufsize];
49906943f9SDavid du Colombier };
50906943f9SDavid du Colombier
51906943f9SDavid du Colombier int usbfsdebug;
52906943f9SDavid du Colombier
53906943f9SDavid du Colombier char Enotfound[] = "file not found";
54906943f9SDavid du Colombier char Etoosmall[] = "parameter too small";
55906943f9SDavid du Colombier char Eio[] = "i/o error";
56906943f9SDavid du Colombier char Eperm[] = "permission denied";
57906943f9SDavid du Colombier char Ebadcall[] = "unknown fs call";
58906943f9SDavid du Colombier char Ebadfid[] = "fid not found";
59906943f9SDavid du Colombier char Einuse[] = "fid already in use";
60906943f9SDavid du Colombier char Eisopen[] = "it is already open";
61906943f9SDavid du Colombier char Ebadctl[] = "unknown control request";
62906943f9SDavid du Colombier
63906943f9SDavid du Colombier static char *user;
64906943f9SDavid du Colombier static ulong epoch;
65906943f9SDavid du Colombier static ulong msgsize = Msgsize;
66906943f9SDavid du Colombier static int fsfd = -1;
67906943f9SDavid du Colombier static Channel *outc; /* of Rpc* */
68906943f9SDavid du Colombier
69906943f9SDavid du Colombier static QLock rpclck; /* protect vars in this block */
70906943f9SDavid du Colombier static Fid *freefids;
71906943f9SDavid du Colombier static Fid *fids;
72906943f9SDavid du Colombier static Rpc *freerpcs;
73906943f9SDavid du Colombier static Rpc *rpcs;
74906943f9SDavid du Colombier
75906943f9SDavid du Colombier static Channel*procc;
76906943f9SDavid du Colombier static Channel*endc;
77906943f9SDavid du Colombier
78906943f9SDavid du Colombier static Usbfs* fsops;
79906943f9SDavid du Colombier
80906943f9SDavid du Colombier static void fsioproc(void*);
81906943f9SDavid du Colombier
82906943f9SDavid du Colombier static void
schedproc(void *)83906943f9SDavid du Colombier schedproc(void*)
84906943f9SDavid du Colombier {
85906943f9SDavid du Colombier Channel *proc[Nproc];
86906943f9SDavid du Colombier int nproc;
87906943f9SDavid du Colombier Channel *p;
88906943f9SDavid du Colombier
89906943f9SDavid du Colombier Alt a[] =
90906943f9SDavid du Colombier {
91906943f9SDavid du Colombier {procc, &proc[0], CHANSND},
92906943f9SDavid du Colombier {endc, &p, CHANRCV},
93906943f9SDavid du Colombier {nil, nil, CHANEND}
94906943f9SDavid du Colombier };
95906943f9SDavid du Colombier memset(proc, 0, sizeof(proc));
96906943f9SDavid du Colombier nproc = 0;
97906943f9SDavid du Colombier for(;;){
98906943f9SDavid du Colombier if(nproc == 0){
99906943f9SDavid du Colombier proc[0] = chancreate(sizeof(Rpc*), 0);
100906943f9SDavid du Colombier proccreate(fsioproc, proc[0], Stack);
101906943f9SDavid du Colombier nproc++;
102906943f9SDavid du Colombier }
103906943f9SDavid du Colombier switch(alt(a)){
104906943f9SDavid du Colombier case 0:
105906943f9SDavid du Colombier proc[0] = nil;
106906943f9SDavid du Colombier if(nproc > 1){
107906943f9SDavid du Colombier proc[0] = proc[nproc-1];
108906943f9SDavid du Colombier proc[nproc-1] = nil;
109906943f9SDavid du Colombier }
110906943f9SDavid du Colombier nproc--;
111906943f9SDavid du Colombier break;
112906943f9SDavid du Colombier case 1:
113906943f9SDavid du Colombier if(nproc < nelem(proc))
114906943f9SDavid du Colombier proc[nproc++] = p;
115906943f9SDavid du Colombier else
116906943f9SDavid du Colombier sendp(p, nil);
117906943f9SDavid du Colombier break;
118906943f9SDavid du Colombier default:
119906943f9SDavid du Colombier sysfatal("alt");
120906943f9SDavid du Colombier }
121906943f9SDavid du Colombier }
122906943f9SDavid du Colombier }
123906943f9SDavid du Colombier
124906943f9SDavid du Colombier static void
dump(void)125906943f9SDavid du Colombier dump(void)
126906943f9SDavid du Colombier {
127906943f9SDavid du Colombier Rpc *rpc;
128906943f9SDavid du Colombier Fid *fid;
129906943f9SDavid du Colombier
130906943f9SDavid du Colombier qlock(&rpclck);
131906943f9SDavid du Colombier fprint(2, "dump:\n");
132906943f9SDavid du Colombier for(rpc = rpcs; rpc != nil; rpc = rpc->next)
133906943f9SDavid du Colombier fprint(2, "rpc %#p %F next %#p\n", rpc, &rpc->t, rpc->next);
134906943f9SDavid du Colombier for(fid = fids; fid != nil; fid = fid->next)
135906943f9SDavid du Colombier fprint(2, "fid %d qid %#llux omode %d aux %#p\n",
136906943f9SDavid du Colombier fid->fid, fid->qid.path, fid->omode, fid->aux);
137906943f9SDavid du Colombier fprint(2, "\n");
138906943f9SDavid du Colombier qunlock(&rpclck);
139906943f9SDavid du Colombier }
140906943f9SDavid du Colombier
141906943f9SDavid du Colombier static Rpc*
newrpc(void)142906943f9SDavid du Colombier newrpc(void)
143906943f9SDavid du Colombier {
144906943f9SDavid du Colombier Rpc *r;
145906943f9SDavid du Colombier
146906943f9SDavid du Colombier qlock(&rpclck);
147906943f9SDavid du Colombier r = freerpcs;
148906943f9SDavid du Colombier if(r != nil)
149906943f9SDavid du Colombier freerpcs = r->next;
150906943f9SDavid du Colombier else
151906943f9SDavid du Colombier r = emallocz(sizeof(Rpc), 0);
152906943f9SDavid du Colombier r->next = rpcs;
153906943f9SDavid du Colombier rpcs = r;
154906943f9SDavid du Colombier r->t.tag = r->r.tag = Notag;
155906943f9SDavid du Colombier r->t.fid = r->r.fid = Nofid;
156906943f9SDavid du Colombier r->t.type = r->r.type = 0;
157906943f9SDavid du Colombier r->flushed = 0;
158906943f9SDavid du Colombier r->fid = nil;
159906943f9SDavid du Colombier r->r.data = (char*)r->data;
160906943f9SDavid du Colombier qunlock(&rpclck);
161906943f9SDavid du Colombier return r;
162906943f9SDavid du Colombier }
163906943f9SDavid du Colombier
164906943f9SDavid du Colombier static void
freerpc(Rpc * r)165906943f9SDavid du Colombier freerpc(Rpc *r)
166906943f9SDavid du Colombier {
167906943f9SDavid du Colombier Rpc **l;
168906943f9SDavid du Colombier if(r == nil)
169906943f9SDavid du Colombier return;
170906943f9SDavid du Colombier qlock(&rpclck);
171906943f9SDavid du Colombier for(l = &rpcs; *l != nil && *l != r; l = &(*l)->next)
172906943f9SDavid du Colombier ;
173906943f9SDavid du Colombier assert(*l == r);
174906943f9SDavid du Colombier *l = r->next;
175906943f9SDavid du Colombier r->next = freerpcs;
176906943f9SDavid du Colombier freerpcs = r;
177906943f9SDavid du Colombier r->t.type = 0;
178906943f9SDavid du Colombier r->t.tag = 0x77777777;
179906943f9SDavid du Colombier qunlock(&rpclck);
180906943f9SDavid du Colombier }
181906943f9SDavid du Colombier
182906943f9SDavid du Colombier static void
flushrpc(int tag)183906943f9SDavid du Colombier flushrpc(int tag)
184906943f9SDavid du Colombier {
185906943f9SDavid du Colombier Rpc *r;
186906943f9SDavid du Colombier
187906943f9SDavid du Colombier qlock(&rpclck);
188906943f9SDavid du Colombier for(r = rpcs; r != nil; r = r->next)
189906943f9SDavid du Colombier if(r->t.tag == tag){
190906943f9SDavid du Colombier r->flushed = 1;
191906943f9SDavid du Colombier break;
192906943f9SDavid du Colombier }
193906943f9SDavid du Colombier qunlock(&rpclck);
194906943f9SDavid du Colombier }
195906943f9SDavid du Colombier
196906943f9SDavid du Colombier static Fid*
getfid(int fid,int alloc)197906943f9SDavid du Colombier getfid(int fid, int alloc)
198906943f9SDavid du Colombier {
199906943f9SDavid du Colombier Fid *f;
200906943f9SDavid du Colombier
201906943f9SDavid du Colombier qlock(&rpclck);
202906943f9SDavid du Colombier for(f = fids; f != nil && f->fid != fid; f = f->next)
203906943f9SDavid du Colombier ;
204906943f9SDavid du Colombier if(f != nil && alloc != 0){ /* fid in use */
205906943f9SDavid du Colombier qunlock(&rpclck);
206906943f9SDavid du Colombier return nil;
207906943f9SDavid du Colombier }
208906943f9SDavid du Colombier if(f == nil && alloc != 0){
209906943f9SDavid du Colombier if(freefids != nil){
210906943f9SDavid du Colombier f = freefids;
211906943f9SDavid du Colombier freefids = freefids->next;
212906943f9SDavid du Colombier }else
213906943f9SDavid du Colombier f = emallocz(sizeof(Fid), 1);
214906943f9SDavid du Colombier f->fid = fid;
215906943f9SDavid du Colombier f->aux = nil;
216906943f9SDavid du Colombier f->omode = ONONE;
217906943f9SDavid du Colombier f->next = fids;
218906943f9SDavid du Colombier fids = f;
219906943f9SDavid du Colombier }
220906943f9SDavid du Colombier qunlock(&rpclck);
221906943f9SDavid du Colombier return f;
222906943f9SDavid du Colombier }
223906943f9SDavid du Colombier
224906943f9SDavid du Colombier static void
freefid(Fid * f)225906943f9SDavid du Colombier freefid(Fid *f)
226906943f9SDavid du Colombier {
227906943f9SDavid du Colombier Fid **l;
228906943f9SDavid du Colombier
229906943f9SDavid du Colombier if(f == nil)
230906943f9SDavid du Colombier return;
231906943f9SDavid du Colombier if(fsops->clunk != nil)
232906943f9SDavid du Colombier fsops->clunk(fsops, f);
233906943f9SDavid du Colombier qlock(&rpclck);
234906943f9SDavid du Colombier for(l = &fids; *l != nil && *l != f; l = &(*l)->next)
235906943f9SDavid du Colombier ;
236906943f9SDavid du Colombier assert(*l == f);
237906943f9SDavid du Colombier *l = f->next;
238906943f9SDavid du Colombier f->next = freefids;
239906943f9SDavid du Colombier freefids = f;
240906943f9SDavid du Colombier qunlock(&rpclck);
241906943f9SDavid du Colombier }
242906943f9SDavid du Colombier
243906943f9SDavid du Colombier static Rpc*
fserror(Rpc * rpc,char * fmt,...)244906943f9SDavid du Colombier fserror(Rpc *rpc, char* fmt, ...)
245906943f9SDavid du Colombier {
246906943f9SDavid du Colombier va_list arg;
247906943f9SDavid du Colombier char *c;
248906943f9SDavid du Colombier
249906943f9SDavid du Colombier va_start(arg, fmt);
250906943f9SDavid du Colombier c = (char*)rpc->data;
251906943f9SDavid du Colombier vseprint(c, c+sizeof(rpc->data), fmt, arg);
252906943f9SDavid du Colombier va_end(arg);
253906943f9SDavid du Colombier rpc->r.type = Rerror;
254906943f9SDavid du Colombier rpc->r.ename = (char*)rpc->data;
255906943f9SDavid du Colombier return rpc;
256906943f9SDavid du Colombier }
257906943f9SDavid du Colombier
258906943f9SDavid du Colombier static Rpc*
fsversion(Rpc * r)259906943f9SDavid du Colombier fsversion(Rpc *r)
260906943f9SDavid du Colombier {
261906943f9SDavid du Colombier if(r->t.msize < 256)
262906943f9SDavid du Colombier return fserror(r, Etoosmall);
263906943f9SDavid du Colombier if(strncmp(r->t.version, "9P2000", 6) != 0)
264906943f9SDavid du Colombier return fserror(r, "wrong version");
265906943f9SDavid du Colombier if(r->t.msize < msgsize)
266906943f9SDavid du Colombier msgsize = r->t.msize;
267906943f9SDavid du Colombier r->r.msize = msgsize;
268906943f9SDavid du Colombier r->r.version = "9P2000";
269906943f9SDavid du Colombier return r;
270906943f9SDavid du Colombier }
271906943f9SDavid du Colombier
272906943f9SDavid du Colombier static Rpc*
fsattach(Rpc * r)273906943f9SDavid du Colombier fsattach(Rpc *r)
274906943f9SDavid du Colombier {
275906943f9SDavid du Colombier static int already;
276906943f9SDavid du Colombier
277906943f9SDavid du Colombier /* Reload user because at boot it could be still none */
278906943f9SDavid du Colombier user=getuser();
279906943f9SDavid du Colombier if(already++ > 0 && strcmp(r->t.uname, user) != 0)
280906943f9SDavid du Colombier return fserror(r, Eperm);
281906943f9SDavid du Colombier if(r->fid == nil)
282906943f9SDavid du Colombier return fserror(r, Einuse);
283906943f9SDavid du Colombier
284906943f9SDavid du Colombier r->r.qid.type = QTDIR;
285906943f9SDavid du Colombier r->r.qid.path = fsops->qid;
286906943f9SDavid du Colombier r->r.qid.vers = 0;
287906943f9SDavid du Colombier r->fid->qid = r->r.qid;
288906943f9SDavid du Colombier return r;
289906943f9SDavid du Colombier }
290906943f9SDavid du Colombier
291906943f9SDavid du Colombier static Rpc*
fswalk(Rpc * r)292906943f9SDavid du Colombier fswalk(Rpc *r)
293906943f9SDavid du Colombier {
294906943f9SDavid du Colombier int i;
29525fc6993SDavid du Colombier Fid *nfid, *ofid;
296906943f9SDavid du Colombier
297906943f9SDavid du Colombier if(r->fid->omode != ONONE)
298906943f9SDavid du Colombier return fserror(r, Eisopen);
299906943f9SDavid du Colombier
300906943f9SDavid du Colombier nfid = nil;
301906943f9SDavid du Colombier ofid = r->fid;
302906943f9SDavid du Colombier if(r->t.newfid != r->t.fid){
303906943f9SDavid du Colombier nfid = getfid(r->t.newfid, 1);
304906943f9SDavid du Colombier if(nfid == nil)
305906943f9SDavid du Colombier return fserror(r, Einuse);
306906943f9SDavid du Colombier nfid->qid = r->fid->qid;
307906943f9SDavid du Colombier if(fsops->clone != nil)
308906943f9SDavid du Colombier fsops->clone(fsops, ofid, nfid);
309906943f9SDavid du Colombier else
310906943f9SDavid du Colombier nfid->aux = r->fid->aux;
311906943f9SDavid du Colombier r->fid = nfid;
312906943f9SDavid du Colombier }
313906943f9SDavid du Colombier r->r.nwqid = 0;
314906943f9SDavid du Colombier for(i = 0; i < r->t.nwname; i++)
315906943f9SDavid du Colombier if(fsops->walk(fsops, r->fid, r->t.wname[i]) < 0)
316906943f9SDavid du Colombier break;
317906943f9SDavid du Colombier else
318906943f9SDavid du Colombier r->r.wqid[i] = r->fid->qid;
319906943f9SDavid du Colombier r->r.nwqid = i;
320906943f9SDavid du Colombier if(i != r->t.nwname && r->t.nwname > 0){
321906943f9SDavid du Colombier if(nfid != nil)
322906943f9SDavid du Colombier freefid(nfid);
323906943f9SDavid du Colombier r->fid = ofid;
324906943f9SDavid du Colombier }
325906943f9SDavid du Colombier if(i == 0 && r->t.nwname > 0)
326906943f9SDavid du Colombier return fserror(r, "%r");
327906943f9SDavid du Colombier return r;
328906943f9SDavid du Colombier }
329906943f9SDavid du Colombier
330906943f9SDavid du Colombier static void
fsioproc(void * a)331906943f9SDavid du Colombier fsioproc(void* a)
332906943f9SDavid du Colombier {
33325fc6993SDavid du Colombier long rc;
334906943f9SDavid du Colombier Channel *p = a;
335906943f9SDavid du Colombier Rpc *rpc;
33625fc6993SDavid du Colombier Fcall *t, *r;
337906943f9SDavid du Colombier Fid *fid;
338906943f9SDavid du Colombier
339*f1a26d48SDavid du Colombier threadsetname("fsioproc");
340906943f9SDavid du Colombier dprint(2, "%s: fsioproc pid %d\n", argv0, getpid());
341906943f9SDavid du Colombier while((rpc = recvp(p)) != nil){
342906943f9SDavid du Colombier t = &rpc->t;
343906943f9SDavid du Colombier r = &rpc->r;
344906943f9SDavid du Colombier fid = rpc->fid;
345906943f9SDavid du Colombier rc = -1;
346906943f9SDavid du Colombier dprint(2, "%s: fsioproc pid %d: req %d\n", argv0, getpid(), t->type);
347906943f9SDavid du Colombier switch(t->type){
348906943f9SDavid du Colombier case Topen:
349906943f9SDavid du Colombier rc = fsops->open(fsops, fid, t->mode);
350906943f9SDavid du Colombier if(rc >= 0){
351906943f9SDavid du Colombier r->iounit = 0;
352906943f9SDavid du Colombier r->qid = fid->qid;
353906943f9SDavid du Colombier fid->omode = t->mode & 3;
354906943f9SDavid du Colombier }
355906943f9SDavid du Colombier break;
356906943f9SDavid du Colombier case Tread:
357906943f9SDavid du Colombier rc = fsops->read(fsops, fid, r->data, t->count, t->offset);
358906943f9SDavid du Colombier if(rc >= 0){
359906943f9SDavid du Colombier if(rc > t->count)
360906943f9SDavid du Colombier print("%s: bug: read %ld bytes > %ud wanted\n",
361906943f9SDavid du Colombier argv0, rc, t->count);
362906943f9SDavid du Colombier r->count = rc;
363906943f9SDavid du Colombier }
36425fc6993SDavid du Colombier /*
36525fc6993SDavid du Colombier * TODO: if we encounter a long run of continuous read
36625fc6993SDavid du Colombier * errors, we should do something more drastic so that
36725fc6993SDavid du Colombier * our caller doesn't just spin its wheels forever.
36825fc6993SDavid du Colombier */
369906943f9SDavid du Colombier break;
370906943f9SDavid du Colombier case Twrite:
371906943f9SDavid du Colombier rc = fsops->write(fsops, fid, t->data, t->count, t->offset);
372906943f9SDavid du Colombier r->count = rc;
373906943f9SDavid du Colombier break;
374906943f9SDavid du Colombier default:
375906943f9SDavid du Colombier sysfatal("fsioproc: bad type");
376906943f9SDavid du Colombier }
377906943f9SDavid du Colombier if(rc < 0)
378906943f9SDavid du Colombier sendp(outc, fserror(rpc, "%r"));
379906943f9SDavid du Colombier else
380906943f9SDavid du Colombier sendp(outc, rpc);
381906943f9SDavid du Colombier sendp(endc, p);
382906943f9SDavid du Colombier }
383906943f9SDavid du Colombier chanfree(p);
384906943f9SDavid du Colombier dprint(2, "%s: fsioproc %d exiting\n", argv0, getpid());
385906943f9SDavid du Colombier threadexits(nil);
386906943f9SDavid du Colombier }
387906943f9SDavid du Colombier
388906943f9SDavid du Colombier static Rpc*
fsopen(Rpc * r)389906943f9SDavid du Colombier fsopen(Rpc *r)
390906943f9SDavid du Colombier {
391906943f9SDavid du Colombier Channel *p;
392906943f9SDavid du Colombier
393906943f9SDavid du Colombier if(r->fid->omode != ONONE)
394906943f9SDavid du Colombier return fserror(r, Eisopen);
395906943f9SDavid du Colombier if((r->t.mode & 3) != OREAD && (r->fid->qid.type & QTDIR) != 0)
396906943f9SDavid du Colombier return fserror(r, Eperm);
397906943f9SDavid du Colombier p = recvp(procc);
398906943f9SDavid du Colombier sendp(p, r);
399906943f9SDavid du Colombier return nil;
400906943f9SDavid du Colombier }
401906943f9SDavid du Colombier
402906943f9SDavid du Colombier int
usbdirread(Usbfs * f,Qid q,char * data,long cnt,vlong off,Dirgen gen,void * arg)403906943f9SDavid du Colombier usbdirread(Usbfs*f, Qid q, char *data, long cnt, vlong off, Dirgen gen, void *arg)
404906943f9SDavid du Colombier {
40525fc6993SDavid du Colombier int i, n, nd;
406906943f9SDavid du Colombier char name[Namesz];
40725fc6993SDavid du Colombier Dir d;
408906943f9SDavid du Colombier
409906943f9SDavid du Colombier memset(&d, 0, sizeof(d));
410906943f9SDavid du Colombier d.name = name;
411906943f9SDavid du Colombier d.uid = d.gid = d.muid = user;
412906943f9SDavid du Colombier d.atime = time(nil);
413906943f9SDavid du Colombier d.mtime = epoch;
414906943f9SDavid du Colombier d.length = 0;
415906943f9SDavid du Colombier for(i = n = 0; gen(f, q, i, &d, arg) >= 0; i++){
416906943f9SDavid du Colombier if(usbfsdebug > 1)
417906943f9SDavid du Colombier fprint(2, "%s: dir %d q %#llux: %D\n", argv0, i, q.path, &d);
418906943f9SDavid du Colombier nd = convD2M(&d, (uchar*)data+n, cnt-n);
419906943f9SDavid du Colombier if(nd <= BIT16SZ)
420906943f9SDavid du Colombier break;
421906943f9SDavid du Colombier if(off > 0)
422906943f9SDavid du Colombier off -= nd;
423906943f9SDavid du Colombier else
424906943f9SDavid du Colombier n += nd;
425906943f9SDavid du Colombier d.name = name;
426906943f9SDavid du Colombier d.uid = d.gid = d.muid = user;
427906943f9SDavid du Colombier d.atime = time(nil);
428906943f9SDavid du Colombier d.mtime = epoch;
429906943f9SDavid du Colombier d.length = 0;
430906943f9SDavid du Colombier }
431906943f9SDavid du Colombier return n;
432906943f9SDavid du Colombier }
433906943f9SDavid du Colombier
434906943f9SDavid du Colombier long
usbreadbuf(void * data,long count,vlong offset,void * buf,long n)435906943f9SDavid du Colombier usbreadbuf(void *data, long count, vlong offset, void *buf, long n)
436906943f9SDavid du Colombier {
437906943f9SDavid du Colombier if(offset >= n)
438906943f9SDavid du Colombier return 0;
439906943f9SDavid du Colombier if(offset + count > n)
440906943f9SDavid du Colombier count = n - offset;
441906943f9SDavid du Colombier memmove(data, (char*)buf + offset, count);
442906943f9SDavid du Colombier return count;
443906943f9SDavid du Colombier }
444906943f9SDavid du Colombier
445906943f9SDavid du Colombier static Rpc*
fsread(Rpc * r)446906943f9SDavid du Colombier fsread(Rpc *r)
447906943f9SDavid du Colombier {
448906943f9SDavid du Colombier Channel *p;
449906943f9SDavid du Colombier
450906943f9SDavid du Colombier if(r->fid->omode != OREAD && r->fid->omode != ORDWR)
451906943f9SDavid du Colombier return fserror(r, Eperm);
452906943f9SDavid du Colombier p = recvp(procc);
453906943f9SDavid du Colombier sendp(p, r);
454906943f9SDavid du Colombier return nil;
455906943f9SDavid du Colombier }
456906943f9SDavid du Colombier
457906943f9SDavid du Colombier static Rpc*
fswrite(Rpc * r)458906943f9SDavid du Colombier fswrite(Rpc *r)
459906943f9SDavid du Colombier {
460906943f9SDavid du Colombier Channel *p;
461906943f9SDavid du Colombier
462906943f9SDavid du Colombier if(r->fid->omode != OWRITE && r->fid->omode != ORDWR)
463906943f9SDavid du Colombier return fserror(r, Eperm);
464906943f9SDavid du Colombier p = recvp(procc);
465906943f9SDavid du Colombier sendp(p, r);
466906943f9SDavid du Colombier return nil;
467906943f9SDavid du Colombier }
468906943f9SDavid du Colombier
469906943f9SDavid du Colombier static Rpc*
fsclunk(Rpc * r)470906943f9SDavid du Colombier fsclunk(Rpc *r)
471906943f9SDavid du Colombier {
472906943f9SDavid du Colombier freefid(r->fid);
473906943f9SDavid du Colombier return r;
474906943f9SDavid du Colombier }
475906943f9SDavid du Colombier
476906943f9SDavid du Colombier static Rpc*
fsno(Rpc * r)477906943f9SDavid du Colombier fsno(Rpc *r)
478906943f9SDavid du Colombier {
479906943f9SDavid du Colombier return fserror(r, Eperm);
480906943f9SDavid du Colombier }
481906943f9SDavid du Colombier
482906943f9SDavid du Colombier static Rpc*
fsstat(Rpc * r)483906943f9SDavid du Colombier fsstat(Rpc *r)
484906943f9SDavid du Colombier {
485906943f9SDavid du Colombier Dir d;
486906943f9SDavid du Colombier char name[Namesz];
487906943f9SDavid du Colombier
488906943f9SDavid du Colombier memset(&d, 0, sizeof(d));
489906943f9SDavid du Colombier d.name = name;
490906943f9SDavid du Colombier d.uid = d.gid = d.muid = user;
491906943f9SDavid du Colombier d.atime = time(nil);
492906943f9SDavid du Colombier d.mtime = epoch;
493906943f9SDavid du Colombier d.length = 0;
494906943f9SDavid du Colombier if(fsops->stat(fsops, r->fid->qid, &d) < 0)
495906943f9SDavid du Colombier return fserror(r, "%r");
496906943f9SDavid du Colombier r->r.stat = (uchar*)r->data;
497906943f9SDavid du Colombier r->r.nstat = convD2M(&d, (uchar*)r->data, msgsize);
498906943f9SDavid du Colombier return r;
499906943f9SDavid du Colombier }
500906943f9SDavid du Colombier
501906943f9SDavid du Colombier static Rpc*
fsflush(Rpc * r)502906943f9SDavid du Colombier fsflush(Rpc *r)
503906943f9SDavid du Colombier {
504906943f9SDavid du Colombier /*
505906943f9SDavid du Colombier * Flag it as flushed and respond.
506906943f9SDavid du Colombier * Either outproc will reply to the flushed request
507906943f9SDavid du Colombier * before responding to flush, or it will never reply to it.
508906943f9SDavid du Colombier * Note that we do NOT abort the ongoing I/O.
509906943f9SDavid du Colombier * That might leave the affected endpoints in a failed
510906943f9SDavid du Colombier * state. Instead, we pretend the request is aborted.
511906943f9SDavid du Colombier *
512906943f9SDavid du Colombier * Only open, read, and write are processed
513906943f9SDavid du Colombier * by auxiliary processes and other requests wil never be
514906943f9SDavid du Colombier * flushed in practice.
515906943f9SDavid du Colombier */
516906943f9SDavid du Colombier flushrpc(r->t.oldtag);
517906943f9SDavid du Colombier return r;
518906943f9SDavid du Colombier }
519906943f9SDavid du Colombier
520906943f9SDavid du Colombier Rpc* (*fscalls[])(Rpc*) = {
521906943f9SDavid du Colombier [Tversion] fsversion,
522906943f9SDavid du Colombier [Tauth] fsno,
523906943f9SDavid du Colombier [Tattach] fsattach,
524906943f9SDavid du Colombier [Twalk] fswalk,
525906943f9SDavid du Colombier [Topen] fsopen,
526906943f9SDavid du Colombier [Tcreate] fsno,
527906943f9SDavid du Colombier [Tread] fsread,
528906943f9SDavid du Colombier [Twrite] fswrite,
529906943f9SDavid du Colombier [Tclunk] fsclunk,
530906943f9SDavid du Colombier [Tremove] fsno,
531906943f9SDavid du Colombier [Tstat] fsstat,
532906943f9SDavid du Colombier [Twstat] fsno,
533906943f9SDavid du Colombier [Tflush] fsflush,
534906943f9SDavid du Colombier };
535906943f9SDavid du Colombier
536906943f9SDavid du Colombier static void
outproc(void *)537906943f9SDavid du Colombier outproc(void*)
538906943f9SDavid du Colombier {
539906943f9SDavid du Colombier static uchar buf[Bufsize];
540906943f9SDavid du Colombier Rpc *rpc;
541906943f9SDavid du Colombier int nw;
542906943f9SDavid du Colombier static int once = 0;
543906943f9SDavid du Colombier
544906943f9SDavid du Colombier if(once++ != 0)
545906943f9SDavid du Colombier sysfatal("more than one outproc");
546*f1a26d48SDavid du Colombier threadsetname("outproc");
547906943f9SDavid du Colombier for(;;){
548906943f9SDavid du Colombier do
549906943f9SDavid du Colombier rpc = recvp(outc);
550906943f9SDavid du Colombier while(rpc == nil); /* a delayed reply */
551906943f9SDavid du Colombier if(rpc->t.tag == Dietag)
552906943f9SDavid du Colombier break;
553906943f9SDavid du Colombier if(rpc->flushed){
554906943f9SDavid du Colombier dprint(2, "outproc: tag %d flushed\n", rpc->t.tag);
555906943f9SDavid du Colombier freerpc(rpc);
556906943f9SDavid du Colombier continue;
557906943f9SDavid du Colombier }
558906943f9SDavid du Colombier dprint(2, "-> %F\n", &rpc->r);
559906943f9SDavid du Colombier nw = convS2M(&rpc->r, buf, sizeof(buf));
560906943f9SDavid du Colombier if(nw == sizeof(buf))
561906943f9SDavid du Colombier fprint(2, "%s: outproc: buffer is too small\n", argv0);
562906943f9SDavid du Colombier if(nw <= BIT16SZ)
563906943f9SDavid du Colombier fprint(2, "%s: conS2M failed\n", argv0);
564906943f9SDavid du Colombier else if(write(fsfd, buf, nw) != nw){
565906943f9SDavid du Colombier fprint(2, "%s: outproc: write: %r", argv0);
566906943f9SDavid du Colombier /* continue and let the reader abort us */
567906943f9SDavid du Colombier }
568906943f9SDavid du Colombier if(usbfsdebug > 1)
569906943f9SDavid du Colombier dump();
570906943f9SDavid du Colombier freerpc(rpc);
571906943f9SDavid du Colombier }
572906943f9SDavid du Colombier dprint(2, "%s: outproc: exiting\n", argv0);
573906943f9SDavid du Colombier }
574906943f9SDavid du Colombier
575906943f9SDavid du Colombier static void
usbfs(void *)576906943f9SDavid du Colombier usbfs(void*)
577906943f9SDavid du Colombier {
578906943f9SDavid du Colombier Rpc *rpc;
579906943f9SDavid du Colombier int nr;
580906943f9SDavid du Colombier static int once = 0;
581906943f9SDavid du Colombier
582906943f9SDavid du Colombier if(once++ != 0)
583906943f9SDavid du Colombier sysfatal("more than one usbfs proc");
584906943f9SDavid du Colombier
585*f1a26d48SDavid du Colombier threadsetname("usbfs");
586906943f9SDavid du Colombier outc = chancreate(sizeof(Rpc*), 1);
587906943f9SDavid du Colombier procc = chancreate(sizeof(Channel*), 0);
588906943f9SDavid du Colombier endc = chancreate(sizeof(Channel*), 0);
589906943f9SDavid du Colombier if(outc == nil || procc == nil || endc == nil)
590906943f9SDavid du Colombier sysfatal("chancreate: %r");
591906943f9SDavid du Colombier threadcreate(schedproc, nil, Stack);
592906943f9SDavid du Colombier proccreate(outproc, nil, Stack);
593906943f9SDavid du Colombier for(;;){
594906943f9SDavid du Colombier rpc = newrpc();
595906943f9SDavid du Colombier do{
596906943f9SDavid du Colombier nr = read9pmsg(fsfd, rpc->data, sizeof(rpc->data));
597906943f9SDavid du Colombier }while(nr == 0);
598906943f9SDavid du Colombier if(nr < 0){
599906943f9SDavid du Colombier dprint(2, "%s: usbfs: read: '%r'", argv0);
600906943f9SDavid du Colombier if(fsops->end != nil)
601906943f9SDavid du Colombier fsops->end(fsops);
602906943f9SDavid du Colombier else
603906943f9SDavid du Colombier closedev(fsops->dev);
604906943f9SDavid du Colombier rpc->t.tag = Dietag;
605906943f9SDavid du Colombier sendp(outc, rpc);
606906943f9SDavid du Colombier break;
607906943f9SDavid du Colombier }
608906943f9SDavid du Colombier if(convM2S((uchar*)rpc->data, nr, &rpc->t) <=0){
609906943f9SDavid du Colombier dprint(2, "%s: convM2S failed\n", argv0);
610906943f9SDavid du Colombier freerpc(rpc);
611906943f9SDavid du Colombier continue;
612906943f9SDavid du Colombier }
613906943f9SDavid du Colombier dprint(2, "<- %F\n", &rpc->t);
614906943f9SDavid du Colombier rpc->r.tag = rpc->t.tag;
615906943f9SDavid du Colombier rpc->r.type = rpc->t.type + 1;
616906943f9SDavid du Colombier rpc->r.fid = rpc->t.fid;
617906943f9SDavid du Colombier if(fscalls[rpc->t.type] == nil){
618906943f9SDavid du Colombier sendp(outc, fserror(rpc, Ebadcall));
619906943f9SDavid du Colombier continue;
620906943f9SDavid du Colombier }
621906943f9SDavid du Colombier if(rpc->t.fid != Nofid){
622906943f9SDavid du Colombier if(rpc->t.type == Tattach)
623906943f9SDavid du Colombier rpc->fid = getfid(rpc->t.fid, 1);
624906943f9SDavid du Colombier else
625906943f9SDavid du Colombier rpc->fid = getfid(rpc->t.fid, 0);
626906943f9SDavid du Colombier if(rpc->fid == nil){
627906943f9SDavid du Colombier sendp(outc, fserror(rpc, Ebadfid));
628906943f9SDavid du Colombier continue;
629906943f9SDavid du Colombier }
630906943f9SDavid du Colombier }
631906943f9SDavid du Colombier sendp(outc, fscalls[rpc->t.type](rpc));
632906943f9SDavid du Colombier }
633906943f9SDavid du Colombier dprint(2, "%s: ubfs: eof: exiting\n", argv0);
634906943f9SDavid du Colombier }
635906943f9SDavid du Colombier
636906943f9SDavid du Colombier void
usbfsinit(char * srv,char * mnt,Usbfs * f,int flag)637906943f9SDavid du Colombier usbfsinit(char* srv, char *mnt, Usbfs *f, int flag)
638906943f9SDavid du Colombier {
639906943f9SDavid du Colombier int fd[2];
640906943f9SDavid du Colombier int sfd;
641906943f9SDavid du Colombier int afd;
642906943f9SDavid du Colombier char sfile[40];
643906943f9SDavid du Colombier
644906943f9SDavid du Colombier fsops = f;
645906943f9SDavid du Colombier if(pipe(fd) < 0)
646906943f9SDavid du Colombier sysfatal("pipe: %r");
647906943f9SDavid du Colombier user = getuser();
648906943f9SDavid du Colombier epoch = time(nil);
649906943f9SDavid du Colombier
650906943f9SDavid du Colombier fmtinstall('D', dirfmt);
651906943f9SDavid du Colombier fmtinstall('M', dirmodefmt);
652906943f9SDavid du Colombier fmtinstall('F', fcallfmt);
653906943f9SDavid du Colombier fsfd = fd[1];
654906943f9SDavid du Colombier procrfork(usbfs, nil, Stack, RFNAMEG); /* no RFFDG */
655906943f9SDavid du Colombier if(srv != nil){
656906943f9SDavid du Colombier snprint(sfile, sizeof(sfile), "#s/%s", srv);
657906943f9SDavid du Colombier remove(sfile);
658906943f9SDavid du Colombier sfd = create(sfile, OWRITE, 0660);
659906943f9SDavid du Colombier if(sfd < 0)
660906943f9SDavid du Colombier sysfatal("post: %r");
661906943f9SDavid du Colombier snprint(sfile, sizeof(sfile), "%d", fd[0]);
662906943f9SDavid du Colombier if(write(sfd, sfile, strlen(sfile)) != strlen(sfile))
663906943f9SDavid du Colombier sysfatal("post: %r");
664906943f9SDavid du Colombier close(sfd);
665906943f9SDavid du Colombier }
666906943f9SDavid du Colombier if(mnt != nil){
667906943f9SDavid du Colombier sfd = dup(fd[0], -1); /* debug */
668906943f9SDavid du Colombier afd = fauth(sfd, "");
669906943f9SDavid du Colombier if(afd >= 0)
670906943f9SDavid du Colombier sysfatal("authentication required??");
671906943f9SDavid du Colombier if(mount(sfd, -1, mnt, flag, "") < 0)
672906943f9SDavid du Colombier sysfatal("mount: %r");
673906943f9SDavid du Colombier }
674906943f9SDavid du Colombier close(fd[0]);
675906943f9SDavid du Colombier }
676906943f9SDavid du Colombier
677