void io(void) { char *err; int n, nerr; char buf[ERRMAX]; errstr(buf, sizeof buf); for(nerr=0, buf[0]='\0'; nerr<100; nerr++){ /* * reading from a pipe or a network device * will give an error after a few eof reads * however, we cannot tell the difference * between a zero-length read and an interrupt * on the processes writing to us, * so we wait for the error */ n = read9pmsg(mfd[0], mdata, sizeof mdata); if(n==0) continue; if(n < 0){ if(buf[0]=='\0') errstr(buf, sizeof buf); continue; } nerr = 0; buf[0] = '\0'; if(convM2S(mdata, n, &rhdr) != n) error("convert error in convM2S"); if(verbose) fprint(2, "tapefs: <=%F\n", &rhdr);/**/ thdr.data = (char*)mdata + IOHDRSZ; thdr.stat = mdata + IOHDRSZ; if(!fcalls[rhdr.type]) err = "bad fcall type"; else err = (*fcalls[rhdr.type])(newfid(rhdr.fid)); if(err){ thdr.type = Rerror; thdr.ename = err; }else{ thdr.type = rhdr.type + 1; thdr.fid = rhdr.fid; } thdr.tag = rhdr.tag; n = convS2M(&thdr, mdata, messagesize); if(n <= 0) error("convert error in convS2M"); if(verbose) fprint(2, "tapefs: =>%F\n", &thdr);/**/ if(write(mfd[1], mdata, n) != n) error("mount write"); } if(buf[0]=='\0' || strstr(buf, "hungup")) exits(""); fprint(2, "%s: mount read: %s\n", argv0, buf); exits(buf); }
static void sendmsg(struct job *job, char *err) { int n; uint8_t mdata[IOHDRSZ + Maxfdata]; char ename[ERRMAX]; if (err) { job->reply.type = Rerror; snprintf(ename, sizeof(ename), "cs: %s", err); job->reply.ename = ename; } else { job->reply.type = job->request.type + 1; } job->reply.tag = job->request.tag; n = convS2M(&job->reply, mdata, sizeof(mdata)); if (n == 1) { fprintf(stderr, "CS:sendmsg convS2M of %F returns 0", &job->reply); abort(); } spinlock_lock(&joblock); if (job->flushed == 0) if (write(mfd[1], mdata, n) != n) error(1, 0, "%s: %r", "mount write"); spinlock_unlock(&joblock); if (debug) fprintf(stderr, "CS:%F %d", &job->reply, n); }
void sendmsg(Job *job, char *err) { int n; uchar mdata[IOHDRSZ + Maxfdata]; char ename[ERRMAX]; if(err){ job->reply.type = Rerror; snprint(ename, sizeof ename, "dns: %s", err); job->reply.ename = ename; }else job->reply.type = job->request.type+1; job->reply.tag = job->request.tag; n = convS2M(&job->reply, mdata, sizeof mdata); if(n == 0){ warning("sendmsg convS2M of %F returns 0", &job->reply); abort(); } lock(&joblock); if(job->flushed == 0) if(write(mfd[1], mdata, n)!=n) sysfatal("mount write"); unlock(&joblock); if(debug) dnslog("%F %d", &job->reply, n); }
Xfid* respond(Xfid *x, Fcall *t, char *err) { int n; if(err) { t->type = Rerror; t->ename = err; } else t->type = x->type+1; t->fid = x->fid; t->tag = x->tag; if(x->buf == nil) x->buf = emalloc(messagesize); n = convS2M(t, x->buf, messagesize); if(n <= 0) error("convert error in convS2M"); if(write(sfd, x->buf, n) != n) error("write error in respond"); free(x->buf); x->buf = nil; if(DEBUG) fprint(2, "r: %F\n", t); return x; }
static void reply(Devlogfs *d) { d->readp = d->readbuf; d->readcount = convS2M(&d->out, d->readp, d->readbufsize); //print("reply is %d bytes\n", d->readcount); if (d->readcount == 0) panic("logfs: reply: did not fit\n"); d->reading = 1; Wakeup(&d->readrendez); }
static int putfcall(int fd, Fcall* f) { int n; n = convS2M(f, txbuf, sizeof(txbuf)); if (n == 0) return -1; if (write(fd, txbuf, n) != n) return -1; return n; }
void io(int srvfd) { int n, pid; pid = getpid(); fmtinstall('F', fcallfmt); for(;;){ /* * reading from a pipe or a network device * will give an error after a few eof reads. * however, we cannot tell the difference * between a zero-length read and an interrupt * on the processes writing to us, * so we wait for the error. */ n = read9pmsg(srvfd, mdata, sizeof mdata); if(n < 0) break; if(n == 0) continue; if(convM2S(mdata, n, req) == 0) continue; if(chatty) fprint(2, "dossrv %d:<-%F\n", pid, req); errno = 0; if(!fcalls[req->type]) errno = Ebadfcall; else (*fcalls[req->type])(); if(errno){ rep->type = Rerror; rep->ename = xerrstr(errno); }else{ rep->type = req->type + 1; rep->fid = req->fid; } rep->tag = req->tag; if(chatty) fprint(2, "dossrv %d:->%F\n", pid, rep); n = convS2M(rep, mdata, sizeof mdata); if(n == 0) panic("convS2M error on write"); if(write(srvfd, mdata, n) != n) panic("mount write"); } chat("server shut down"); }
int xmesg(Session *s, int t) { int n; if(chatty){ if(0 <= t && t < nelem(tnames) && tnames[t]) chat("T%s...", tnames[t]); else chat("T%d...", t); } s->f.type = t; s->f.tag = ++s->tag; if(p9debug) fprint(2, "xmseg\tsend %F\n", &s->f); n = convS2M(&s->f, s->data, messagesize); if(niwrite(s->fd, s->data, n) != n){ clog("xmesg write error on %d: %r\n", s->fd); return -1; } again: n = read9pmsg(s->fd, s->data, messagesize); if(n < 0){ clog("xmesg read error: %r\n"); return -1; } if(convM2S(s->data, n, &s->f) <= 0){ clog("xmesg bad convM2S %d %.2x %.2x %.2x %.2x\n", n, ((uchar*)s->data)[0], ((uchar*)s->data)[1], ((uchar*)s->data)[2], ((uchar*)s->data)[3]); return -1; } if(p9debug) fprint(2, "\trecv %F\n", &s->f); if(s->f.tag != s->tag){ clog("xmesg tag %d for %d\n", s->f.tag, s->tag); goto again; } if(s->f.type == Rerror){ if(t == Tclunk) clog("xmesg clunk: %s", s->f.ename); chat("xmesg %d error %s...", t, s->f.ename); return -1; } if(s->f.type != t+1){ clog("xmesg type mismatch: %d, expected %d\n", s->f.type, t+1); return -1; } return 0; }
void sendomsg(Msg *m) { int n, nn; n = sizeS2M(&m->tx); m->tpkt = emalloc(n); nn = convS2M(&m->tx, m->tpkt, n); if(nn <= BIT16SZ) sysfatal("convS2M conversion error"); if(nn != n) sysfatal("sizeS2M and convS2M disagree"); sendq(outq, m); }
void mainproc(void *v) { int n, nn; Fcall f; USED(v); atnotify(ignorepipe, 1); fmtinstall('D', dirfmt); fmtinstall('M', dirmodefmt); fmtinstall('F', fcallfmt); fmtinstall('H', encodefmt); outq = qalloc(); inq = qalloc(); if(!versioned){ f.type = Tversion; f.version = "9P2000"; f.msize = msize; f.tag = NOTAG; n = convS2M(&f, vbuf, sizeof vbuf); if(n <= BIT16SZ) sysfatal("convS2M conversion error"); if(verbose > 1) fprint(2, "%T * <- %F\n", &f); nn = write(1, vbuf, n); if(n != nn) sysfatal("error writing Tversion: %r\n"); n = read9pmsg(0, vbuf, sizeof vbuf); if(n < 0) sysfatal("read9pmsg failure"); if(convM2S(vbuf, n, &f) != n) sysfatal("convM2S failure"); if(f.msize < msize) msize = f.msize; if(verbose > 1) fprint(2, "%T * -> %F\n", &f); } threadcreate(inputthread, nil, STACK); threadcreate(outputthread, nil, STACK); /* if(rootfid) */ /* dorootstat(); */ threadcreate(listenthread, nil, STACK); threadexits(0); }
int fsreply(int fd, Fcall *f) { uchar buf[IOHDRSZ+Maxfdata]; int n; if(dbg) fprint(2, "notefs: <-%F\n", f); n = convS2M(f, buf, sizeof buf); if(n > 0){ if(write(fd, buf, n) != n){ close(fd); return -1; } } return 0; }
void io(void) { char *err; int n; for(;;){ n = read9pmsg(mfd[0], mdata, sizeof mdata); if(n <= 0) break; if(convM2S(mdata, n, &rhdr) != n) sysfatal("convM2S conversion error"); if(dflag) fprint(2, "vacfs:<-%F\n", &rhdr); thdr.data = (char*)mdata + IOHDRSZ; if(!fcalls[rhdr.type]) err = "bad fcall type"; else err = (*fcalls[rhdr.type])(newfid(rhdr.fid)); if(err){ thdr.type = Rerror; thdr.ename = err; #ifdef PLAN9PORT thdr.errornum = 0; #endif }else{ thdr.type = rhdr.type + 1; thdr.fid = rhdr.fid; } thdr.tag = rhdr.tag; if(dflag) fprint(2, "vacfs:->%F\n", &thdr); n = convS2M(&thdr, mdata, messagesize); if(n <= BIT16SZ) sysfatal("convS2M conversion error"); if(err) vtfree(err); if(write(mfd[1], mdata, n) != n) sysfatal("mount write: %r"); } }
/* * write a protocol reply to the client */ static void reply(Fcall *r, char *error) { int n; if(error == nil) r->type++; else { r->type = Rerror; r->ename = error; } if(debugfd >= 0) fprint(debugfd, "->%F\n", r);/**/ n = convS2M(r, rbuf, sizeof rbuf); if(n == 0) sysfatal("convS2M: %r"); if(write(srvfd, rbuf, n) < 0) sysfatal("reply: %r"); }
void fsreply(Fs *fs, Request *r, char *err) { int n; uchar buf[MAXSIZE]; if(err){ r->f.type = Rerror; r->f.ename = err; } if(debug) fprint(2, "%F path %llux\n", &r->f, r->fid->qid.path); n = convS2M(&r->f, buf, messagesize); if(n == 0) fatal("bad convS2M"); if(write(fs->fd, buf, n) != n) fatal("unmounted"); free(r); }
void repack(Fcall *f, uchar **ppkt) { uint n, nn; uchar *pkt; pkt = *ppkt; n = GBIT32(pkt); nn = sizeS2M(f); if(nn > n){ free(pkt); pkt = emalloc(nn); *ppkt = pkt; } n = convS2M(f, pkt, nn); if(n <= BIT16SZ) sysfatal("convS2M conversion error"); if(n != nn) sysfatal("convS2M and sizeS2M disagree"); }
void respond(Req *r, char *error) { int i, m, n; char errbuf[ERRMAX]; Srv *srv; srv = r->srv; assert(srv != nil); if(r->responded){ assert(r->pool); goto free; } assert(r->responded == 0); r->error = error; switch(r->ifcall.type){ default: assert(0); /* * Flush is special. If the handler says so, we return * without further processing. Respond will be called * again once it is safe. */ case Tflush: if(rflush(r, error)<0) return; break; case Tversion: rversion(r, error); break; case Tauth: rauth(r, error); break; case Tattach: rattach(r, error); break; case Twalk: rwalk(r, error); break; case Topen: ropen(r, error); break; case Tcreate: rcreate(r, error); break; case Tread: rread(r, error); break; case Twrite: rwrite(r, error); break; case Tclunk: rclunk(r, error); break; case Tremove: rremove(r, error, errbuf); break; case Tstat: rstat(r, error); break; case Twstat: rwstat(r, error); break; } r->ofcall.tag = r->ifcall.tag; r->ofcall.type = r->ifcall.type+1; if(r->error) setfcallerror(&r->ofcall, r->error); if(chatty9p) fprint(2, "-%d-> %F\n", srv->outfd, &r->ofcall); qlock(&srv->wlock); n = convS2M(&r->ofcall, srv->wbuf, srv->msize); if(n <= 0){ fprint(2, "n = %d %F\n", n, &r->ofcall); abort(); } assert(n > 2); /* * There is a race here - we must remove the entry before * the write, so that if the client is very fast and reuses the * tag, the read loop won't think it is still in use. * * By removing the entry before the write, we open up a * race with incoming Tflush messages. Specifically, an * incoming Tflush might not see r even though it has not * yet been responded to. It would then send an Rflush * immediately, potentially before we do the write. This can't * happen because we already old srv->wlock, so nothing * is going out on the wire before this write. */ if(r->pool) /* not a fake */ closereq(removereq(r->pool, r->ifcall.tag)); qlock(&r->lk); r->responded = 1; if(r->pool) if(r->ref.ref == 1+r->nflush) if(r->fid){ /* * There are no references other than in our r->flush array, * so no one else should be accessing r concurrently. * Close the fid now, before responding to the message. * * If the client is behaving (there are no outstanding T-messages * that reference r->fid) and the message is a Tclunk or Tremove, * then this closefid will call destroyfid. * * This means destroyfid can't piddle around * indefinitely (we're holding srv->wlock!), but it provides * for tighter semantics as to when destroyfid is called. * * LANL has observed cases where waiting until after the write * can delay a closefid on a Twrite for many 9P transactions, * so that a handful of transactions can happen including a Tclunk * and a Topen, and the original fid will still not be destroyed. */ closefid(r->fid); r->fid = nil; } qunlock(&r->lk); m = write(srv->outfd, srv->wbuf, n); if(m != n) sysfatal("lib9p srv: write %d returned %d on fd %d: %r", n, m, srv->outfd); qunlock(&srv->wlock); free: qlock(&r->lk); /* no one will add flushes now */ for(i=0; i<r->nflush; i++){ r->flush[i]->oldreq = nil; /* so it doesn't try to lock us! */ respond(r->flush[i], nil); } free(r->flush); r->flush = nil; r->nflush = 0; qunlock(&r->lk); if(r->pool) closereq(r); else free(r); }
void io(int srvfd) { int n, pid; Fcall xreq, xrep; req = &xreq; rep = &xrep; pid = getpid(); fmtinstall('F', fcallfmt); for(;;){ /* * reading from a pipe or a network device * will give an error after a few eof reads. * however, we cannot tell the difference * between a zero-length read and an interrupt * on the processes writing to us, * so we wait for the error. */ n = read9pmsg(srvfd, mdata, sizeof mdata); if(n < 0) break; if(n == 0) continue; if(convM2S(mdata, n, req) == 0) continue; if(chatty) fprint(2, "9660srv %d:<-%F\n", pid, req); errno = 0; if(!waserror()){ err_msg[0] = 0; if(req->type >= nelem(fcalls) || !fcalls[req->type]) error("bad fcall type"); (*fcalls[req->type])(); poperror(); } if(err_msg[0]){ rep->type = Rerror; rep->ename = err_msg; }else{ rep->type = req->type + 1; rep->fid = req->fid; } rep->tag = req->tag; if(chatty) fprint(2, "9660srv %d:->%F\n", pid, rep); n = convS2M(rep, mdata, sizeof mdata); if(n == 0) panic(1, "convS2M error on write"); if(write(srvfd, mdata, n) != n) panic(1, "mount write"); if(nerr_lab != 0) panic(0, "err stack %d"); } chat("server shut down"); }
void respond(Req *r, char *error) { int i, m, n; char errbuf[ERRMAX]; Srv *srv; srv = r->srv; assert(srv != nil); assert(r->responded == 0); r->error = error; switch(r->ifcall.type){ default: assert(0); /* * Flush is special. If the handler says so, we return * without further processing. Respond will be called * again once it is safe. */ case Tflush: if(rflush(r, error)<0) return; break; case Tversion: rversion(r, error); break; case Tauth: rauth(r, error); break; case Tattach: rattach(r, error); break; case Twalk: rwalk(r, error); break; case Topen: ropen(r, error); break; case Tcreate: rcreate(r, error); break; case Tread: rread(r, error); break; case Twrite: rwrite(r, error); break; case Tclunk: rclunk(r, error); break; case Tremove: rremove(r, error, errbuf); break; case Tstat: rstat(r, error); break; case Twstat: rwstat(r, error); break; } r->ofcall.tag = r->ifcall.tag; r->ofcall.type = r->ifcall.type+1; if(r->error) setfcallerror(&r->ofcall, r->error); if(chatty9p) fprint(2, "-%d-> %F\n", srv->outfd, &r->ofcall); qlock(&srv->wlock); n = convS2M(&r->ofcall, srv->wbuf, srv->msize); if(n <= 0){ fprint(2, "n = %d %F\n", n, &r->ofcall); abort(); } assert(n > 2); if(r->pool) /* not a fake */ closereq(removereq(r->pool, r->ifcall.tag)); m = write(srv->outfd, srv->wbuf, n); if(m != n) sysfatal("lib9p srv: write %d returned %d on fd %d: %r", n, m, srv->outfd); qunlock(&srv->wlock); qlock(&r->lk); /* no one will add flushes now */ r->responded = 1; qunlock(&r->lk); for(i=0; i<r->nflush; i++) respond(r->flush[i], nil); free(r->flush); r->flush = nil; r->nflush = 0; if(r->pool) closereq(r); else free(r); }