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