📄 srvold9p.c
字号:
#include <u.h>#include <libc.h>#include <auth.h>#include <fcall.h>#include <libsec.h>#include "9p1.h"char *user;int newfd;int roldfd;int woldfd;int debug;int dofcall;QLock servelock;QLock fidlock;QLock taglock;int mainpid;int ntag;int nfork;char FLUSHED[] = "FLUSHED";enum{ Maxfdata = 8192};enum{ Command, Network, File, Stdio,};typedef struct Tag Tag;struct Tag{ int tag; int flushed; int received; int ref; Tag *next;};typedef struct Message Message;struct Message{ char *data; int n;};typedef struct Fid Fid;struct Fid{ short busy; short allocated; int fid; Qid qid; ulong newoffset; ulong oldoffset; Fid *next;};Fid *fids;Tag *tags;char *rflush(Fcall*, Fcall*, char*), *rversion(Fcall*, Fcall*, char*), *rauth(Fcall*, Fcall*, char*), *rattach(Fcall*, Fcall*, char*), *rwalk(Fcall*, Fcall*, char*), *ropen(Fcall*, Fcall*, char*), *rcreate(Fcall*, Fcall*, char*), *rread(Fcall*, Fcall*, char*), *rwrite(Fcall*, Fcall*, char*), *rclunk(Fcall*, Fcall*, char*), *rremove(Fcall*, Fcall*, char*), *rstat(Fcall*, Fcall*, char*), *rwstat(Fcall*, Fcall*, char*);char *(*fcalls[])(Fcall*, Fcall*, char*) = { [Tversion] rversion, [Tflush] rflush, [Tauth] rauth, [Tattach] rattach, [Twalk] rwalk, [Topen] ropen, [Tcreate] rcreate, [Tread] rread, [Twrite] rwrite, [Tclunk] rclunk, [Tremove] rremove, [Tstat] rstat, [Twstat] rwstat,};char Etoolong[] = "name too long";void connect(int, char*);void post(int, char*);void serve(void);void demux(void);void* emalloc(ulong);char* transact9p1(Fcall9p1*, Fcall9p1*, char*);Fid* newfid(int);struct{ char chal[CHALLEN]; /* my challenge */ char rchal[CHALLEN]; /* his challenge */ char authid[NAMEREC]; char authdom[DOMLEN]; int id;} ai;voidusage(void){ fprint(2, "usage: srvold9p [-abcCd] [-u user] [-s | [-m mountpoint]] [-x 'command' | -n network-addr | -f file] [-F] [-p servicename]\n"); exits("usage");}voidmain(int argc, char *argv[]){ int method; char *oldstring; char *mountpoint, *postname; int mountflag, mountfd; int p[2];int i; fmtinstall('F', fcallfmt); fmtinstall('G', fcallfmt9p1); fmtinstall('D', dirfmt); user = getuser(); mountpoint = nil; mountflag = 0; postname = nil; oldstring = nil; method = -1; mountfd = -1; ARGBEGIN{ case 'a': mountflag |= MAFTER; break; case 'b': mountflag |= MBEFORE; break; case 'c': mountflag |= MCREATE; break; case 'C': mountflag |= MCACHE; break; case 'd': debug++; break; case 'f': method = File; oldstring = ARGF(); break; case 'F': dofcall++; break; case 'm': mountpoint = EARGF(usage()); break; case 'n': method = Network; oldstring = ARGF(); break; case 'p': postname = ARGF(); if(postname == nil) usage(); break; case 's': method = Stdio; break; case 'u': user = EARGF(usage()); break; case 'x': method = Command; oldstring = ARGF(); break; default: usage(); }ARGEND; if(method == Stdio){ if(mountpoint!=nil || argc!=0) usage(); }else{ if(oldstring == nil || argc != 0 || (mountflag!=0 && mountpoint==nil)) usage(); } rfork(RFNOTEG|RFREND); connect(method, oldstring); if(method == Stdio) newfd = 0; else{ if(pipe(p) < 0) fatal("pipe: %r"); if(postname != nil) post(p[0], postname); mountfd = p[0]; newfd = p[1]; } if(debug) fprint(2, "connected and posted\n"); switch(rfork(RFPROC|RFMEM|RFNAMEG|RFFDG)){ case 0: mainpid = getpid(); /* child does all the work */ if(mountfd >= 0) close(mountfd); switch(rfork(RFPROC|RFMEM|RFFDG)){ case 0: for(i = 0; i < 20; i++) if (i != roldfd) close(i); demux(); return; case -1: fatal("fork error: %r"); break; } for(i = 0; i < 20; i++) if (i != newfd && i != woldfd && (debug == 0 || i != 2)) close(i); serve(); break; case -1: fatal("fork error: %r"); break; default: /* parent mounts if required, then exits */ if(mountpoint){ if(mount(mountfd, -1, mountpoint, mountflag, "") < 0) fatal("can't mount: %r"); } break; } exits(nil);}voidconnect(int method, char *oldstring){ char *s; char dir[256]; switch(method){ default: roldfd = -1; woldfd = -1; fatal("can't handle method type %d", method); break; case Network: s = netmkaddr(oldstring, 0, "9fs"); roldfd = dial(s, 0, dir, 0); if(roldfd < 0) fatal("dial %s: %r", s); woldfd = roldfd; if(dofcall) roldfd = fcall(woldfd); break; case File: roldfd = open(oldstring, ORDWR); if(roldfd < 0) fatal("can't open %s: %r", oldstring); woldfd = roldfd; if(dofcall) roldfd = fcall(woldfd); break; case Stdio: roldfd = fcall(1); woldfd = 1; break; }}voidpost(int fd, char *srv){ int f; char buf[128]; snprint(buf, sizeof buf, "/srv/%s", srv); f = create(buf, OWRITE, 0666); if(f < 0) fatal("can't create %s: %r", buf); sprint(buf, "%d", fd); if(write(f, buf, strlen(buf)) != strlen(buf)) fatal("post write: %r"); close(f);}Fid *newfid(int fid){ Fid *f, *ff; ff = 0; qlock(&fidlock); for(f = fids; f; f = f->next) if(f->fid == fid){ f->allocated = 1; qunlock(&fidlock); return f; } else if(!ff && !f->allocated) ff = f; if(ff){ ff->fid = fid; ff->allocated = 1; qunlock(&fidlock); return ff; } f = emalloc(sizeof *f); f->fid = fid; f->next = fids; f->allocated = 1; fids = f; qunlock(&fidlock); return f;}/* * Reads returning 9P1 messages and demultiplexes them. * BUG: assumes one read per message. */voiddemux(void){ int m, n; char *data; Fcall9p1 r; Message *msg; Tag *t; for(;;){ data = malloc(IOHDRSZ+Maxfdata); /* no need to clear memory */ if(data == nil) fatal("demux malloc: %r"); m = read(roldfd, data, IOHDRSZ+Maxfdata); if(m <= 0) fatal("read error talking to old system: %r"); n = convM2S9p1(data, &r, m); if(n == 0) fatal("bad conversion receiving from old system"); if(debug) fprint(2, "srvold9p:<=%G\n", &r); qlock(&taglock); for(t=tags; t!=nil; t=t->next) if(t->tag == r.tag){ t->received = 1; break; } qunlock(&taglock); /* * Fcall9p1 tag is used to rendezvous. * Recipient converts message a second time, but that's OK. */ msg = emalloc(sizeof(Message)); msg->data = data; msg->n = n; rendezvous((void*)r.tag, msg); }}Tag*newtag(int tag){ Tag *t; t = emalloc(sizeof(Tag)); t->tag = tag; t->flushed = 0; t->received = 0; t->ref = 1; qlock(&taglock); t->next = tags; tags = t; qunlock(&taglock); return t;}voidfreetag(Tag *tag) /* called with taglock set */{ Tag *t, *prev; if(tag->ref-- == 1){ prev = nil; for(t=tags; t!=nil; t=t->next){ if(t == tag){ if(prev == nil) tags = t->next; else prev->next = t->next; break; } prev = t; } if(t == nil) sysfatal("freetag"); free(tag); }}voidserve(void){ char *err; int n; Fcall thdr; Fcall rhdr; uchar mdata[IOHDRSZ+Maxfdata]; char mdata9p1[IOHDRSZ+Maxfdata]; Tag *tag; for(;;){ qlock(&servelock); for(;;){ n = read9pmsg(newfd, mdata, sizeof mdata); if(n == 0) continue; if(n < 0) break; if(n > 0 && convM2S(mdata, n, &thdr) > 0) break; } if(n>0 && servelock.head==nil) /* no other processes waiting to read */ switch(rfork(RFPROC|RFMEM)){ case 0: /* child starts serving */ continue; break; case -1: fatal("fork error: %r"); break; default: break; } qunlock(&servelock); if(n < 0) fatal(nil); /* exit quietly; remote end has just hung up */ if(debug) fprint(2, "srvold9p:<-%F\n", &thdr); tag = newtag(thdr.tag); if(!fcalls[thdr.type]) err = "bad fcall type"; else err = (*fcalls[thdr.type])(&thdr, &rhdr, mdata9p1); qlock(&taglock); if(tag->flushed){ freetag(tag); qunlock(&taglock); continue; } qunlock(&taglock); if(err){ rhdr.type = Rerror; rhdr.ename = err; }else{ rhdr.type = thdr.type + 1; rhdr.fid = thdr.fid; } rhdr.tag = thdr.tag; if(debug) fprint(2, "srvold9p:->%F\n", &rhdr);/**/ n = convS2M(&rhdr, mdata, sizeof mdata); if(n == 0) fatal("convS2M error on write"); if(write(newfd, mdata, n) != n) fatal("mount write"); qlock(&taglock); freetag(tag); qunlock(&taglock); }}voidsend9p1(Fcall9p1 *t, char *data){ int m, n; if(debug) fprint(2, "srvold9p:=>%G\n", t); n = convS2M9p1(t, data); if(n == 0) fatal("bad conversion sending to old system"); m = write(woldfd, data, n); if(m != n) fatal("wrote %d to old system; should be %d", m, n);}intrecv9p1(Fcall9p1 *r, int tag, char *data){ int n; Message *msg; msg = rendezvous((void*)tag, 0); if(msg == (void*)~0) fatal("rendezvous: %r"); if(msg == nil){ if(debug) fprint(2, "recv flushed\n"); return -1; } /* copy data to local buffer */ memmove(data, msg->data, msg->n); n = convM2S9p1(data, r, msg->n); if(n == 0) fatal("bad conversion receiving from old system"); free(msg->data); free(msg); return 1;}char*transact9p1(Fcall9p1 *t, Fcall9p1 *r, char *mdata9p1){ send9p1(t, mdata9p1); if(recv9p1(r, t->tag, mdata9p1) < 0) return FLUSHED; if(r->type == Rerror9p1) return r->ename; if(r->type != t->type+1) fatal("bad message type; expected %d got %d", t->type+1, r->type); return nil;}char*rflush(Fcall *t, Fcall *, char *mdata9p1){ Fcall9p1 t9, r9; Tag *oldt; t9.type = Tflush9p1; t9.tag = t->tag; t9.oldtag = t->oldtag; qlock(&taglock); for(oldt=tags; oldt!=nil; oldt=oldt->next) if(oldt->tag == t->oldtag){ oldt->flushed = 1; oldt->ref++;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -