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 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 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* 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 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 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* 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 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* 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* 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* 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* 292906943f9SDavid du Colombier fswalk(Rpc *r) 293906943f9SDavid du Colombier { 294906943f9SDavid du Colombier int i; 295*25fc6993SDavid 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 331906943f9SDavid du Colombier fsioproc(void* a) 332906943f9SDavid du Colombier { 333*25fc6993SDavid du Colombier long rc; 334906943f9SDavid du Colombier Channel *p = a; 335906943f9SDavid du Colombier Rpc *rpc; 336*25fc6993SDavid du Colombier Fcall *t, *r; 337906943f9SDavid du Colombier Fid *fid; 338906943f9SDavid du Colombier 339906943f9SDavid du Colombier dprint(2, "%s: fsioproc pid %d\n", argv0, getpid()); 340906943f9SDavid du Colombier while((rpc = recvp(p)) != nil){ 341906943f9SDavid du Colombier t = &rpc->t; 342906943f9SDavid du Colombier r = &rpc->r; 343906943f9SDavid du Colombier fid = rpc->fid; 344906943f9SDavid du Colombier rc = -1; 345906943f9SDavid du Colombier dprint(2, "%s: fsioproc pid %d: req %d\n", argv0, getpid(), t->type); 346906943f9SDavid du Colombier switch(t->type){ 347906943f9SDavid du Colombier case Topen: 348906943f9SDavid du Colombier rc = fsops->open(fsops, fid, t->mode); 349906943f9SDavid du Colombier if(rc >= 0){ 350906943f9SDavid du Colombier r->iounit = 0; 351906943f9SDavid du Colombier r->qid = fid->qid; 352906943f9SDavid du Colombier fid->omode = t->mode & 3; 353906943f9SDavid du Colombier } 354906943f9SDavid du Colombier break; 355906943f9SDavid du Colombier case Tread: 356906943f9SDavid du Colombier rc = fsops->read(fsops, fid, r->data, t->count, t->offset); 357906943f9SDavid du Colombier if(rc >= 0){ 358906943f9SDavid du Colombier if(rc > t->count) 359906943f9SDavid du Colombier print("%s: bug: read %ld bytes > %ud wanted\n", 360906943f9SDavid du Colombier argv0, rc, t->count); 361906943f9SDavid du Colombier r->count = rc; 362906943f9SDavid du Colombier } 363*25fc6993SDavid du Colombier /* 364*25fc6993SDavid du Colombier * TODO: if we encounter a long run of continuous read 365*25fc6993SDavid du Colombier * errors, we should do something more drastic so that 366*25fc6993SDavid du Colombier * our caller doesn't just spin its wheels forever. 367*25fc6993SDavid du Colombier */ 368906943f9SDavid du Colombier break; 369906943f9SDavid du Colombier case Twrite: 370906943f9SDavid du Colombier rc = fsops->write(fsops, fid, t->data, t->count, t->offset); 371906943f9SDavid du Colombier r->count = rc; 372906943f9SDavid du Colombier break; 373906943f9SDavid du Colombier default: 374906943f9SDavid du Colombier sysfatal("fsioproc: bad type"); 375906943f9SDavid du Colombier } 376906943f9SDavid du Colombier if(rc < 0) 377906943f9SDavid du Colombier sendp(outc, fserror(rpc, "%r")); 378906943f9SDavid du Colombier else 379906943f9SDavid du Colombier sendp(outc, rpc); 380906943f9SDavid du Colombier sendp(endc, p); 381906943f9SDavid du Colombier } 382906943f9SDavid du Colombier chanfree(p); 383906943f9SDavid du Colombier dprint(2, "%s: fsioproc %d exiting\n", argv0, getpid()); 384906943f9SDavid du Colombier threadexits(nil); 385906943f9SDavid du Colombier } 386906943f9SDavid du Colombier 387906943f9SDavid du Colombier static Rpc* 388906943f9SDavid du Colombier fsopen(Rpc *r) 389906943f9SDavid du Colombier { 390906943f9SDavid du Colombier Channel *p; 391906943f9SDavid du Colombier 392906943f9SDavid du Colombier if(r->fid->omode != ONONE) 393906943f9SDavid du Colombier return fserror(r, Eisopen); 394906943f9SDavid du Colombier if((r->t.mode & 3) != OREAD && (r->fid->qid.type & QTDIR) != 0) 395906943f9SDavid du Colombier return fserror(r, Eperm); 396906943f9SDavid du Colombier p = recvp(procc); 397906943f9SDavid du Colombier sendp(p, r); 398906943f9SDavid du Colombier return nil; 399906943f9SDavid du Colombier } 400906943f9SDavid du Colombier 401906943f9SDavid du Colombier int 402906943f9SDavid du Colombier usbdirread(Usbfs*f, Qid q, char *data, long cnt, vlong off, Dirgen gen, void *arg) 403906943f9SDavid du Colombier { 404*25fc6993SDavid du Colombier int i, n, nd; 405906943f9SDavid du Colombier char name[Namesz]; 406*25fc6993SDavid du Colombier Dir d; 407906943f9SDavid du Colombier 408906943f9SDavid du Colombier memset(&d, 0, sizeof(d)); 409906943f9SDavid du Colombier d.name = name; 410906943f9SDavid du Colombier d.uid = d.gid = d.muid = user; 411906943f9SDavid du Colombier d.atime = time(nil); 412906943f9SDavid du Colombier d.mtime = epoch; 413906943f9SDavid du Colombier d.length = 0; 414906943f9SDavid du Colombier for(i = n = 0; gen(f, q, i, &d, arg) >= 0; i++){ 415906943f9SDavid du Colombier if(usbfsdebug > 1) 416906943f9SDavid du Colombier fprint(2, "%s: dir %d q %#llux: %D\n", argv0, i, q.path, &d); 417906943f9SDavid du Colombier nd = convD2M(&d, (uchar*)data+n, cnt-n); 418906943f9SDavid du Colombier if(nd <= BIT16SZ) 419906943f9SDavid du Colombier break; 420906943f9SDavid du Colombier if(off > 0) 421906943f9SDavid du Colombier off -= nd; 422906943f9SDavid du Colombier else 423906943f9SDavid du Colombier n += nd; 424906943f9SDavid du Colombier d.name = name; 425906943f9SDavid du Colombier d.uid = d.gid = d.muid = user; 426906943f9SDavid du Colombier d.atime = time(nil); 427906943f9SDavid du Colombier d.mtime = epoch; 428906943f9SDavid du Colombier d.length = 0; 429906943f9SDavid du Colombier } 430906943f9SDavid du Colombier return n; 431906943f9SDavid du Colombier } 432906943f9SDavid du Colombier 433906943f9SDavid du Colombier long 434906943f9SDavid du Colombier usbreadbuf(void *data, long count, vlong offset, void *buf, long n) 435906943f9SDavid du Colombier { 436906943f9SDavid du Colombier if(offset >= n) 437906943f9SDavid du Colombier return 0; 438906943f9SDavid du Colombier if(offset + count > n) 439906943f9SDavid du Colombier count = n - offset; 440906943f9SDavid du Colombier memmove(data, (char*)buf + offset, count); 441906943f9SDavid du Colombier return count; 442906943f9SDavid du Colombier } 443906943f9SDavid du Colombier 444906943f9SDavid du Colombier static Rpc* 445906943f9SDavid du Colombier fsread(Rpc *r) 446906943f9SDavid du Colombier { 447906943f9SDavid du Colombier Channel *p; 448906943f9SDavid du Colombier 449906943f9SDavid du Colombier if(r->fid->omode != OREAD && r->fid->omode != ORDWR) 450906943f9SDavid du Colombier return fserror(r, Eperm); 451906943f9SDavid du Colombier p = recvp(procc); 452906943f9SDavid du Colombier sendp(p, r); 453906943f9SDavid du Colombier return nil; 454906943f9SDavid du Colombier } 455906943f9SDavid du Colombier 456906943f9SDavid du Colombier static Rpc* 457906943f9SDavid du Colombier fswrite(Rpc *r) 458906943f9SDavid du Colombier { 459906943f9SDavid du Colombier Channel *p; 460906943f9SDavid du Colombier 461906943f9SDavid du Colombier if(r->fid->omode != OWRITE && r->fid->omode != ORDWR) 462906943f9SDavid du Colombier return fserror(r, Eperm); 463906943f9SDavid du Colombier p = recvp(procc); 464906943f9SDavid du Colombier sendp(p, r); 465906943f9SDavid du Colombier return nil; 466906943f9SDavid du Colombier } 467906943f9SDavid du Colombier 468906943f9SDavid du Colombier static Rpc* 469906943f9SDavid du Colombier fsclunk(Rpc *r) 470906943f9SDavid du Colombier { 471906943f9SDavid du Colombier freefid(r->fid); 472906943f9SDavid du Colombier return r; 473906943f9SDavid du Colombier } 474906943f9SDavid du Colombier 475906943f9SDavid du Colombier static Rpc* 476906943f9SDavid du Colombier fsno(Rpc *r) 477906943f9SDavid du Colombier { 478906943f9SDavid du Colombier return fserror(r, Eperm); 479906943f9SDavid du Colombier } 480906943f9SDavid du Colombier 481906943f9SDavid du Colombier static Rpc* 482906943f9SDavid du Colombier fsstat(Rpc *r) 483906943f9SDavid du Colombier { 484906943f9SDavid du Colombier Dir d; 485906943f9SDavid du Colombier char name[Namesz]; 486906943f9SDavid du Colombier 487906943f9SDavid du Colombier memset(&d, 0, sizeof(d)); 488906943f9SDavid du Colombier d.name = name; 489906943f9SDavid du Colombier d.uid = d.gid = d.muid = user; 490906943f9SDavid du Colombier d.atime = time(nil); 491906943f9SDavid du Colombier d.mtime = epoch; 492906943f9SDavid du Colombier d.length = 0; 493906943f9SDavid du Colombier if(fsops->stat(fsops, r->fid->qid, &d) < 0) 494906943f9SDavid du Colombier return fserror(r, "%r"); 495906943f9SDavid du Colombier r->r.stat = (uchar*)r->data; 496906943f9SDavid du Colombier r->r.nstat = convD2M(&d, (uchar*)r->data, msgsize); 497906943f9SDavid du Colombier return r; 498906943f9SDavid du Colombier } 499906943f9SDavid du Colombier 500906943f9SDavid du Colombier static Rpc* 501906943f9SDavid du Colombier fsflush(Rpc *r) 502906943f9SDavid du Colombier { 503906943f9SDavid du Colombier /* 504906943f9SDavid du Colombier * Flag it as flushed and respond. 505906943f9SDavid du Colombier * Either outproc will reply to the flushed request 506906943f9SDavid du Colombier * before responding to flush, or it will never reply to it. 507906943f9SDavid du Colombier * Note that we do NOT abort the ongoing I/O. 508906943f9SDavid du Colombier * That might leave the affected endpoints in a failed 509906943f9SDavid du Colombier * state. Instead, we pretend the request is aborted. 510906943f9SDavid du Colombier * 511906943f9SDavid du Colombier * Only open, read, and write are processed 512906943f9SDavid du Colombier * by auxiliary processes and other requests wil never be 513906943f9SDavid du Colombier * flushed in practice. 514906943f9SDavid du Colombier */ 515906943f9SDavid du Colombier flushrpc(r->t.oldtag); 516906943f9SDavid du Colombier return r; 517906943f9SDavid du Colombier } 518906943f9SDavid du Colombier 519906943f9SDavid du Colombier Rpc* (*fscalls[])(Rpc*) = { 520906943f9SDavid du Colombier [Tversion] fsversion, 521906943f9SDavid du Colombier [Tauth] fsno, 522906943f9SDavid du Colombier [Tattach] fsattach, 523906943f9SDavid du Colombier [Twalk] fswalk, 524906943f9SDavid du Colombier [Topen] fsopen, 525906943f9SDavid du Colombier [Tcreate] fsno, 526906943f9SDavid du Colombier [Tread] fsread, 527906943f9SDavid du Colombier [Twrite] fswrite, 528906943f9SDavid du Colombier [Tclunk] fsclunk, 529906943f9SDavid du Colombier [Tremove] fsno, 530906943f9SDavid du Colombier [Tstat] fsstat, 531906943f9SDavid du Colombier [Twstat] fsno, 532906943f9SDavid du Colombier [Tflush] fsflush, 533906943f9SDavid du Colombier }; 534906943f9SDavid du Colombier 535906943f9SDavid du Colombier static void 536906943f9SDavid du Colombier outproc(void*) 537906943f9SDavid du Colombier { 538906943f9SDavid du Colombier static uchar buf[Bufsize]; 539906943f9SDavid du Colombier Rpc *rpc; 540906943f9SDavid du Colombier int nw; 541906943f9SDavid du Colombier static int once = 0; 542906943f9SDavid du Colombier 543906943f9SDavid du Colombier if(once++ != 0) 544906943f9SDavid du Colombier sysfatal("more than one outproc"); 545906943f9SDavid du Colombier for(;;){ 546906943f9SDavid du Colombier do 547906943f9SDavid du Colombier rpc = recvp(outc); 548906943f9SDavid du Colombier while(rpc == nil); /* a delayed reply */ 549906943f9SDavid du Colombier if(rpc->t.tag == Dietag) 550906943f9SDavid du Colombier break; 551906943f9SDavid du Colombier if(rpc->flushed){ 552906943f9SDavid du Colombier dprint(2, "outproc: tag %d flushed\n", rpc->t.tag); 553906943f9SDavid du Colombier freerpc(rpc); 554906943f9SDavid du Colombier continue; 555906943f9SDavid du Colombier } 556906943f9SDavid du Colombier dprint(2, "-> %F\n", &rpc->r); 557906943f9SDavid du Colombier nw = convS2M(&rpc->r, buf, sizeof(buf)); 558906943f9SDavid du Colombier if(nw == sizeof(buf)) 559906943f9SDavid du Colombier fprint(2, "%s: outproc: buffer is too small\n", argv0); 560906943f9SDavid du Colombier if(nw <= BIT16SZ) 561906943f9SDavid du Colombier fprint(2, "%s: conS2M failed\n", argv0); 562906943f9SDavid du Colombier else if(write(fsfd, buf, nw) != nw){ 563906943f9SDavid du Colombier fprint(2, "%s: outproc: write: %r", argv0); 564906943f9SDavid du Colombier /* continue and let the reader abort us */ 565906943f9SDavid du Colombier } 566906943f9SDavid du Colombier if(usbfsdebug > 1) 567906943f9SDavid du Colombier dump(); 568906943f9SDavid du Colombier freerpc(rpc); 569906943f9SDavid du Colombier } 570906943f9SDavid du Colombier dprint(2, "%s: outproc: exiting\n", argv0); 571906943f9SDavid du Colombier } 572906943f9SDavid du Colombier 573906943f9SDavid du Colombier static void 574906943f9SDavid du Colombier usbfs(void*) 575906943f9SDavid du Colombier { 576906943f9SDavid du Colombier Rpc *rpc; 577906943f9SDavid du Colombier int nr; 578906943f9SDavid du Colombier static int once = 0; 579906943f9SDavid du Colombier 580906943f9SDavid du Colombier if(once++ != 0) 581906943f9SDavid du Colombier sysfatal("more than one usbfs proc"); 582906943f9SDavid du Colombier 583906943f9SDavid du Colombier outc = chancreate(sizeof(Rpc*), 1); 584906943f9SDavid du Colombier procc = chancreate(sizeof(Channel*), 0); 585906943f9SDavid du Colombier endc = chancreate(sizeof(Channel*), 0); 586906943f9SDavid du Colombier if(outc == nil || procc == nil || endc == nil) 587906943f9SDavid du Colombier sysfatal("chancreate: %r"); 588906943f9SDavid du Colombier threadcreate(schedproc, nil, Stack); 589906943f9SDavid du Colombier proccreate(outproc, nil, Stack); 590906943f9SDavid du Colombier for(;;){ 591906943f9SDavid du Colombier rpc = newrpc(); 592906943f9SDavid du Colombier do{ 593906943f9SDavid du Colombier nr = read9pmsg(fsfd, rpc->data, sizeof(rpc->data)); 594906943f9SDavid du Colombier }while(nr == 0); 595906943f9SDavid du Colombier if(nr < 0){ 596906943f9SDavid du Colombier dprint(2, "%s: usbfs: read: '%r'", argv0); 597906943f9SDavid du Colombier if(fsops->end != nil) 598906943f9SDavid du Colombier fsops->end(fsops); 599906943f9SDavid du Colombier else 600906943f9SDavid du Colombier closedev(fsops->dev); 601906943f9SDavid du Colombier rpc->t.tag = Dietag; 602906943f9SDavid du Colombier sendp(outc, rpc); 603906943f9SDavid du Colombier break; 604906943f9SDavid du Colombier } 605906943f9SDavid du Colombier if(convM2S((uchar*)rpc->data, nr, &rpc->t) <=0){ 606906943f9SDavid du Colombier dprint(2, "%s: convM2S failed\n", argv0); 607906943f9SDavid du Colombier freerpc(rpc); 608906943f9SDavid du Colombier continue; 609906943f9SDavid du Colombier } 610906943f9SDavid du Colombier dprint(2, "<- %F\n", &rpc->t); 611906943f9SDavid du Colombier rpc->r.tag = rpc->t.tag; 612906943f9SDavid du Colombier rpc->r.type = rpc->t.type + 1; 613906943f9SDavid du Colombier rpc->r.fid = rpc->t.fid; 614906943f9SDavid du Colombier if(fscalls[rpc->t.type] == nil){ 615906943f9SDavid du Colombier sendp(outc, fserror(rpc, Ebadcall)); 616906943f9SDavid du Colombier continue; 617906943f9SDavid du Colombier } 618906943f9SDavid du Colombier if(rpc->t.fid != Nofid){ 619906943f9SDavid du Colombier if(rpc->t.type == Tattach) 620906943f9SDavid du Colombier rpc->fid = getfid(rpc->t.fid, 1); 621906943f9SDavid du Colombier else 622906943f9SDavid du Colombier rpc->fid = getfid(rpc->t.fid, 0); 623906943f9SDavid du Colombier if(rpc->fid == nil){ 624906943f9SDavid du Colombier sendp(outc, fserror(rpc, Ebadfid)); 625906943f9SDavid du Colombier continue; 626906943f9SDavid du Colombier } 627906943f9SDavid du Colombier } 628906943f9SDavid du Colombier sendp(outc, fscalls[rpc->t.type](rpc)); 629906943f9SDavid du Colombier } 630906943f9SDavid du Colombier dprint(2, "%s: ubfs: eof: exiting\n", argv0); 631906943f9SDavid du Colombier } 632906943f9SDavid du Colombier 633906943f9SDavid du Colombier void 634906943f9SDavid du Colombier usbfsinit(char* srv, char *mnt, Usbfs *f, int flag) 635906943f9SDavid du Colombier { 636906943f9SDavid du Colombier int fd[2]; 637906943f9SDavid du Colombier int sfd; 638906943f9SDavid du Colombier int afd; 639906943f9SDavid du Colombier char sfile[40]; 640906943f9SDavid du Colombier 641906943f9SDavid du Colombier fsops = f; 642906943f9SDavid du Colombier if(pipe(fd) < 0) 643906943f9SDavid du Colombier sysfatal("pipe: %r"); 644906943f9SDavid du Colombier user = getuser(); 645906943f9SDavid du Colombier epoch = time(nil); 646906943f9SDavid du Colombier 647906943f9SDavid du Colombier fmtinstall('D', dirfmt); 648906943f9SDavid du Colombier fmtinstall('M', dirmodefmt); 649906943f9SDavid du Colombier fmtinstall('F', fcallfmt); 650906943f9SDavid du Colombier fsfd = fd[1]; 651906943f9SDavid du Colombier procrfork(usbfs, nil, Stack, RFNAMEG); /* no RFFDG */ 652906943f9SDavid du Colombier if(srv != nil){ 653906943f9SDavid du Colombier snprint(sfile, sizeof(sfile), "#s/%s", srv); 654906943f9SDavid du Colombier remove(sfile); 655906943f9SDavid du Colombier sfd = create(sfile, OWRITE, 0660); 656906943f9SDavid du Colombier if(sfd < 0) 657906943f9SDavid du Colombier sysfatal("post: %r"); 658906943f9SDavid du Colombier snprint(sfile, sizeof(sfile), "%d", fd[0]); 659906943f9SDavid du Colombier if(write(sfd, sfile, strlen(sfile)) != strlen(sfile)) 660906943f9SDavid du Colombier sysfatal("post: %r"); 661906943f9SDavid du Colombier close(sfd); 662906943f9SDavid du Colombier } 663906943f9SDavid du Colombier if(mnt != nil){ 664906943f9SDavid du Colombier sfd = dup(fd[0], -1); /* debug */ 665906943f9SDavid du Colombier afd = fauth(sfd, ""); 666906943f9SDavid du Colombier if(afd >= 0) 667906943f9SDavid du Colombier sysfatal("authentication required??"); 668906943f9SDavid du Colombier if(mount(sfd, -1, mnt, flag, "") < 0) 669906943f9SDavid du Colombier sysfatal("mount: %r"); 670906943f9SDavid du Colombier } 671906943f9SDavid du Colombier close(fd[0]); 672906943f9SDavid du Colombier } 673906943f9SDavid du Colombier 674