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