📄 cs.c
字号:
#include <u.h>#include <libc.h>#include <auth.h>#include <fcall.h>#include <bio.h>#include <ctype.h>#include <ndb.h>#include <ip.h>#include <String.h>enum{ Nreply= 20, Maxreply= 256, Maxrequest= 128, Maxpath= 128, Maxfdata= 8192, Maxhost= 64, /* maximum host name size */ Maxservice= 64, /* maximum service name size */ Qdir= 0, Qcs= 1,};typedef struct Mfile Mfile;typedef struct Mlist Mlist;typedef struct Network Network;typedef struct Flushreq Flushreq;typedef struct Job Job;int vers; /* incremented each clone/attach */struct Mfile{ int busy; char *user; Qid qid; int fid; /* * current request */ char *net; char *host; char *serv; char *rem; /* * result of the last lookup */ Network *nextnet; int nreply; char *reply[Nreply]; int replylen[Nreply];};struct Mlist{ Mlist *next; Mfile mf;};//// active requests//struct Job{ Job *next; int flushed; Fcall request; Fcall reply;};Lock joblock;Job *joblist;Mlist *mlist;int mfd[2];int debug;int paranoia;jmp_buf masterjmp; /* return through here after a slave process has been created */int *isslave; /* *isslave non-zero means this is a slave process */char *dbfile;Ndb *db, *netdb;void rversion(Job*);void rflush(Job*);void rattach(Job*, Mfile*);char* rwalk(Job*, Mfile*);void ropen(Job*, Mfile*);void rcreate(Job*, Mfile*);void rread(Job*, Mfile*);void rwrite(Job*, Mfile*);void rclunk(Job*, Mfile*);void rremove(Job*, Mfile*);void rstat(Job*, Mfile*);void rwstat(Job*, Mfile*);void rauth(Job*);void sendmsg(Job*, char*);void error(char*);void mountinit(char*, char*);void io(void);void ndbinit(void);void netinit(int);void netadd(char*);char *genquery(Mfile*, char*);char* ipinfoquery(Mfile*, char**, int);int needproto(Network*, Ndbtuple*);int lookup(Mfile*);Ndbtuple* reorder(Ndbtuple*, Ndbtuple*);void ipid(void);void readipinterfaces(void);void* emalloc(int);char* estrdup(char*);Job* newjob(void);void freejob(Job*);void setext(char*, int, char*);void cleanmf(Mfile*);extern void paralloc(void);Lock dblock; /* mutex on database operations */Lock netlock; /* mutex for netinit() */char *logfile = "cs";char *paranoiafile = "cs.paranoia";char mntpt[Maxpath];char netndb[Maxpath];/* * Network specific translators */Ndbtuple* iplookup(Network*, char*, char*, int);char* iptrans(Ndbtuple*, Network*, char*, char*, int);Ndbtuple* telcolookup(Network*, char*, char*, int);char* telcotrans(Ndbtuple*, Network*, char*, char*, int);Ndbtuple* dnsiplookup(char*, Ndbs*);struct Network{ char *net; Ndbtuple *(*lookup)(Network*, char*, char*, int); char *(*trans)(Ndbtuple*, Network*, char*, char*, int); int considered; int fasttimeouthack; Network *next;};enum{ Nilfast, Ntcp, Nil, Nudp, Nicmp, Nicmpv6, Nrudp, Ntelco,};/* * net doesn't apply to (r)udp, icmp(v6), or telco (for speed) */Network network[] = {[Ntcp] { "tcp", iplookup, iptrans, 0, 0 },[Nilfast] { "il", iplookup, iptrans, 0, 1 },[Nil] { "il", iplookup, iptrans, 0, 0 },[Nudp] { "udp", iplookup, iptrans, 1, 0 },[Nicmp] { "icmp", iplookup, iptrans, 1, 0 },[Nicmpv6] { "icmpv6", iplookup, iptrans, 1, 0 },[Nrudp] { "rudp", iplookup, iptrans, 1, 0 },[Ntelco] { "telco", telcolookup, telcotrans, 1, 0 }, { 0 },};Lock ipifclock;Ipifc *ipifcs;char eaddr[16]; /* ascii ethernet address */char ipaddr[64]; /* ascii internet address */uchar ipa[IPaddrlen]; /* binary internet address */char *mysysname;Network *netlist; /* networks ordered by preference */Network *last;static voidnstrcpy(char *to, char *from, int len){ strncpy(to, from, len); to[len-1] = 0;}voidusage(void){ fprint(2, "usage: %s [-d] [-f ndb-file] [-x netmtpt] [-n]\n", argv0); exits("usage");}voidmain(int argc, char *argv[]){ char servefile[Maxpath]; int justsetname; char *p; char ext[Maxpath]; justsetname = 0; setnetmtpt(mntpt, sizeof(mntpt), nil); ext[0] = 0; ARGBEGIN{ case 'd': debug = 1; break; case 'f': p = ARGF(); if(p == nil) usage(); dbfile = p; break; case 'x': p = ARGF(); if(p == nil) usage(); setnetmtpt(mntpt, sizeof(mntpt), p); setext(ext, sizeof(ext), mntpt); break; case 'n': justsetname = 1; break; }ARGEND USED(argc); USED(argv); rfork(RFREND|RFNOTEG); snprint(servefile, sizeof(servefile), "#s/cs%s", ext); snprint(netndb, sizeof(netndb), "%s/ndb", mntpt); unmount(servefile, mntpt); remove(servefile); fmtinstall('E', eipfmt); fmtinstall('I', eipfmt); fmtinstall('M', eipfmt); fmtinstall('F', fcallfmt); ndbinit(); netinit(0); if(!justsetname){ mountinit(servefile, mntpt); io(); } exits(0);}/* * if a mount point is specified, set the cs extention to be the mount point * with '_'s replacing '/'s */voidsetext(char *ext, int n, char *p){ int i, c; n--; for(i = 0; i < n; i++){ c = p[i]; if(c == 0) break; if(c == '/') c = '_'; ext[i] = c; } ext[i] = 0;}voidmountinit(char *service, char *mntpt){ int f; int p[2]; char buf[32]; if(pipe(p) < 0) error("pipe failed"); /* * make a /srv/cs */ f = create(service, OWRITE|ORCLOSE, 0666); if(f < 0) error(service); snprint(buf, sizeof(buf), "%d", p[1]); if(write(f, buf, strlen(buf)) != strlen(buf)) error("write /srv/cs"); switch(rfork(RFFDG|RFPROC|RFNAMEG)){ case 0: close(p[1]); break; case -1: error("fork failed\n"); default: /* * put ourselves into the file system */ close(p[0]); if(mount(p[1], -1, mntpt, MAFTER, "") < 0) error("mount failed\n"); _exits(0); } mfd[0] = mfd[1] = p[0];}voidndbinit(void){ db = ndbopen(dbfile); if(db == nil) error("can't open network database"); netdb = ndbopen(netndb); if(netdb != nil){ netdb->nohash = 1; db = ndbcat(netdb, db); }}Mfile*newfid(int fid){ Mlist *f, *ff; Mfile *mf; ff = 0; for(f = mlist; f; f = f->next) if(f->mf.busy && f->mf.fid == fid) return &f->mf; else if(!ff && !f->mf.busy) ff = f; if(ff == 0){ ff = emalloc(sizeof *f); ff->next = mlist; mlist = ff; } mf = &ff->mf; memset(mf, 0, sizeof *mf); mf->fid = fid; return mf;}Job*newjob(void){ Job *job; job = mallocz(sizeof(Job), 1); lock(&joblock); job->next = joblist; joblist = job; job->request.tag = -1; unlock(&joblock); return job;}voidfreejob(Job *job){ Job **l; lock(&joblock); for(l = &joblist; *l; l = &(*l)->next){ if((*l) == job){ *l = job->next; free(job); break; } } unlock(&joblock);}voidflushjob(int tag){ Job *job; lock(&joblock); for(job = joblist; job; job = job->next){ if(job->request.tag == tag && job->request.type != Tflush){ job->flushed = 1; break; } } unlock(&joblock);}voidio(void){ long n; Mfile *mf; int slaveflag; uchar mdata[IOHDRSZ + Maxfdata]; Job *job; /* * if we ask dns to fulfill requests, * a slave process is created to wait for replies. The * master process returns immediately via a longjmp * through 'masterjmp'. * * *isslave is a pointer into the call stack to a variable * that tells whether or not the current process is a slave. */ slaveflag = 0; /* init slave variable */ isslave = &slaveflag; setjmp(masterjmp); for(;;){ n = read9pmsg(mfd[0], mdata, sizeof mdata); if(n<=0) error("mount read"); job = newjob(); if(convM2S(mdata, n, &job->request) != n){ syslog(1, logfile, "format error %ux %ux %ux %ux %ux", mdata[0], mdata[1], mdata[2], mdata[3], mdata[4]); freejob(job); continue; } lock(&dblock); mf = newfid(job->request.fid); if(debug) syslog(0, logfile, "%F", &job->request); switch(job->request.type){ default: syslog(1, logfile, "unknown request type %d", job->request.type); break; case Tversion: rversion(job); break; case Tauth: rauth(job); break; case Tflush: rflush(job); break; case Tattach: rattach(job, mf); break; case Twalk: rwalk(job, mf); break; case Topen: ropen(job, mf); break; case Tcreate: rcreate(job, mf); break; case Tread: rread(job, mf); break; case Twrite: rwrite(job, mf); break; case Tclunk: rclunk(job, mf); break; case Tremove: rremove(job, mf); break; case Tstat: rstat(job, mf); break; case Twstat: rwstat(job, mf); break; } unlock(&dblock); freejob(job); /* * slave processes die after replying */ if(*isslave){ if(debug) syslog(0, logfile, "slave death %d", getpid()); _exits(0); } }}voidrversion(Job *job){ if(job->request.msize > IOHDRSZ + Maxfdata) job->reply.msize = IOHDRSZ + Maxfdata; else job->reply.msize = job->request.msize; if(strncmp(job->request.version, "9P2000", 6) != 0) sendmsg(job, "unknown 9P version"); else{ job->reply.version = "9P2000"; sendmsg(job, 0); }}voidrauth(Job *job){ sendmsg(job, "cs: authentication not required");}/* * don't flush till all the slaves are done */voidrflush(Job *job){ flushjob(job->request.oldtag); sendmsg(job, 0);}voidrattach(Job *job, Mfile *mf){ if(mf->busy == 0){ mf->busy = 1; mf->user = estrdup(job->request.uname); } mf->qid.vers = vers++; mf->qid.type = QTDIR; mf->qid.path = 0LL; job->reply.qid = mf->qid; sendmsg(job, 0);}char*rwalk(Job *job, Mfile *mf){ char *err; char **elems; int nelems; int i; Mfile *nmf; Qid qid; err = 0; nmf = nil; elems = job->request.wname; nelems = job->request.nwname; job->reply.nwqid = 0; if(job->request.newfid != job->request.fid){ /* clone fid */ nmf = newfid(job->request.newfid); if(nmf->busy){ nmf = nil; err = "clone to used channel"; goto send; } *nmf = *mf; nmf->user = estrdup(mf->user); nmf->fid = job->request.newfid; nmf->qid.vers = vers++; mf = nmf; } /* else nmf will be nil */ qid = mf->qid; if(nelems > 0){ /* walk fid */ for(i=0; i<nelems && i<MAXWELEM; i++){ if((qid.type & QTDIR) == 0){ err = "not a directory"; break; } if(strcmp(elems[i], "..") == 0 || strcmp(elems[i], ".") == 0){ qid.type = QTDIR; qid.path = Qdir; Found: job->reply.wqid[i] = qid; job->reply.nwqid++; continue; } if(strcmp(elems[i], "cs") == 0){ qid.type = QTFILE; qid.path = Qcs; goto Found; } err = "file does not exist"; break; } } send: if(nmf != nil && (err!=nil || job->reply.nwqid<nelems)){ cleanmf(nmf); free(nmf->user); nmf->user = 0; nmf->busy = 0; nmf->fid = 0; } if(err == nil) mf->qid = qid; sendmsg(job, err); return err;}voidropen(Job *job, Mfile *mf)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -