diff options
author | Russ Cox <rsc@swtch.com> | 2008-07-20 03:23:19 -0400 |
---|---|---|
committer | Russ Cox <rsc@swtch.com> | 2008-07-20 03:23:19 -0400 |
commit | 78a779a3834cf39d7c0bcd93a15824b29df947a3 (patch) | |
tree | 7ebe47a874a3864f8e990567554b0df956590650 /src/cmd/9660srv/main.c | |
parent | 29e9b5683ec8d610140da9118e8f004f74bc6c77 (diff) | |
download | plan9port-78a779a3834cf39d7c0bcd93a15824b29df947a3.tar.gz plan9port-78a779a3834cf39d7c0bcd93a15824b29df947a3.tar.bz2 plan9port-78a779a3834cf39d7c0bcd93a15824b29df947a3.zip |
9660srv: import from Plan 9
Diffstat (limited to 'src/cmd/9660srv/main.c')
-rw-r--r-- | src/cmd/9660srv/main.c | 576 |
1 files changed, 576 insertions, 0 deletions
diff --git a/src/cmd/9660srv/main.c b/src/cmd/9660srv/main.c new file mode 100644 index 00000000..c3e5d9c9 --- /dev/null +++ b/src/cmd/9660srv/main.c @@ -0,0 +1,576 @@ +#include <u.h> +#include <libc.h> +#include <auth.h> +#include <fcall.h> +#include "dat.h" +#include "fns.h" + +enum +{ + Maxfdata = 8192, + Maxiosize = IOHDRSZ+Maxfdata, +}; + +void io(int); +void rversion(void); +void rattach(void); +void rauth(void); +void rclunk(void); +void rcreate(void); +void rflush(void); +void ropen(void); +void rread(void); +void rremove(void); +void rsession(void); +void rstat(void); +void rwalk(void); +void rwrite(void); +void rwstat(void); + +static int openflags(int); +static void usage(void); + +#define Reqsize (sizeof(Fcall)+Maxfdata) + +Fcall *req; +Fcall *rep; + +uchar mdata[Maxiosize]; +char fdata[Maxfdata]; +uchar statbuf[STATMAX]; +int errno; + + +extern Xfsub *xsublist[]; +extern int nclust; + +jmp_buf err_lab[16]; +int nerr_lab; +char err_msg[ERRMAX]; + +int chatty; +int nojoliet; +int noplan9; +int norock; + +void (*fcalls[])(void) = { + [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, +}; + +void +main(int argc, char **argv) +{ + int srvfd, pipefd[2], stdio; + Xfsub **xs; + char *mtpt; + + stdio = 0; + mtpt = nil; + ARGBEGIN { + case '9': + noplan9 = 1; + break; + case 'c': + nclust = atoi(EARGF(usage())); + if (nclust <= 0) + sysfatal("nclust %d non-positive", nclust); + break; + case 'f': + deffile = EARGF(usage()); + break; + case 'r': + norock = 1; + break; + case 's': + stdio = 1; + break; + case 'v': + chatty = 1; + break; + case 'J': + nojoliet = 1; + break; + case 'm': + mtpt = EARGF(usage()); + break; + default: + usage(); + } ARGEND + + switch(argc) { + case 0: + break; + case 1: + srvname = argv[0]; + break; + default: + usage(); + } + + iobuf_init(); + for(xs=xsublist; *xs; xs++) + (*(*xs)->reset)(); + + if(stdio) { + pipefd[0] = 0; + pipefd[1] = 1; + } else { + close(0); + close(1); + open("/dev/null", OREAD); + open("/dev/null", OWRITE); + if(pipe(pipefd) < 0) + panic(1, "pipe"); + + if(post9pservice(pipefd[0], srvname, mtpt) < 0) + sysfatal("post9pservice: %r"); + close(pipefd[0]); + } + srvfd = pipefd[1]; + + switch(rfork(RFNOWAIT|RFNOTEG|RFFDG|RFPROC)){ + case -1: + panic(1, "fork"); + default: + _exits(0); + case 0: + break; + } + + io(srvfd); + exits(0); +} + +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"); +} + +static void +usage(void) +{ + fprint(2, "usage: %s [-v] [-9Jr] [-s] [-f devicefile] [srvname]\n", argv0); + exits("usage"); +} + +void +error(char *p) +{ + strecpy(err_msg, err_msg+sizeof err_msg, p); + nexterror(); +} + +void +nexterror(void) +{ + longjmp(err_lab[--nerr_lab], 1); +} + +void* +ealloc(long n) +{ + void *p; + + p = malloc(n); + if(p == 0) + error("no memory"); + return p; +} + +void +setnames(Dir *d, char *n) +{ + d->name = n; + d->uid = n+Maxname; + d->gid = n+Maxname*2; + d->muid = n+Maxname*3; + + d->name[0] = '\0'; + d->uid[0] = '\0'; + d->gid[0] = '\0'; + d->muid[0] = '\0'; +} + +void +rversion(void) +{ + if(req->msize > Maxiosize) + rep->msize = Maxiosize; + else + rep->msize = req->msize; + rep->version = "9P2000"; +} + +void +rauth(void) +{ + error("9660srv: authentication not required"); +} + +void +rflush(void) +{ +} + +void +rattach(void) +{ + Xfs *xf; + Xfile *root; + Xfsub **xs; + + chat("attach(fid=%d,uname=\"%s\",aname=\"%s\")...", + req->fid, req->uname, req->aname); + + if(waserror()){ + xfile(req->fid, Clunk); + nexterror(); + } + root = xfile(req->fid, Clean); + root->qid = (Qid){0, 0, QTDIR}; + root->xf = xf = ealloc(sizeof(Xfs)); + memset(xf, 0, sizeof(Xfs)); + xf->ref = 1; + xf->d = getxdata(req->aname); + + for(xs=xsublist; *xs; xs++) + if((*(*xs)->attach)(root) >= 0){ + poperror(); + xf->s = *xs; + xf->rootqid = root->qid; + rep->qid = root->qid; + return; + } + error("unknown format"); +} + +Xfile* +doclone(Xfile *of, int newfid) +{ + Xfile *nf, *next; + + nf = xfile(newfid, Clean); + if(waserror()){ + xfile(newfid, Clunk); + nexterror(); + } + next = nf->next; + *nf = *of; + nf->next = next; + nf->fid = newfid; + refxfs(nf->xf, 1); + if(nf->len){ + nf->ptr = ealloc(nf->len); + memmove(nf->ptr, of->ptr, nf->len); + }else + nf->ptr = of->ptr; + (*of->xf->s->clone)(of, nf); + poperror(); + return nf; +} + +void +rwalk(void) +{ + Xfile *f, *nf; + Isofile *oldptr; + int oldlen; + Qid oldqid; + + rep->nwqid = 0; + nf = nil; + f = xfile(req->fid, Asis); + if(req->fid != req->newfid) + f = nf = doclone(f, req->newfid); + + /* save old state in case of error */ + oldqid = f->qid; + oldlen = f->len; + oldptr = f->ptr; + if(oldlen){ + oldptr = ealloc(oldlen); + memmove(oldptr, f->ptr, oldlen); + } + + if(waserror()){ + if(nf != nil) + xfile(req->newfid, Clunk); + if(rep->nwqid == req->nwname){ + if(oldlen) + free(oldptr); + }else{ + /* restore previous state */ + f->qid = oldqid; + if(f->len) + free(f->ptr); + f->ptr = oldptr; + f->len = oldlen; + } + if(rep->nwqid==req->nwname || rep->nwqid > 0){ + err_msg[0] = '\0'; + return; + } + nexterror(); + } + + for(rep->nwqid=0; rep->nwqid < req->nwname && rep->nwqid < MAXWELEM; rep->nwqid++){ + chat("\twalking %s\n", req->wname[rep->nwqid]); + if(!(f->qid.type & QTDIR)){ + chat("\tnot dir: type=%#x\n", f->qid.type); + error("walk in non-directory"); + } + + if(strcmp(req->wname[rep->nwqid], "..")==0){ + if(f->qid.path != f->xf->rootqid.path) + (*f->xf->s->walkup)(f); + }else + (*f->xf->s->walk)(f, req->wname[rep->nwqid]); + rep->wqid[rep->nwqid] = f->qid; + } + poperror(); + if(oldlen) + free(oldptr); +} + +void +ropen(void) +{ + Xfile *f; + + f = xfile(req->fid, Asis); + if(f->flags&Omodes) + error("open on open file"); + if(req->mode&ORCLOSE) + error("no removes"); + (*f->xf->s->open)(f, req->mode); + f->flags = openflags(req->mode); + rep->qid = f->qid; + rep->iounit = 0; +} + +void +rcreate(void) +{ + error("no creates"); +/* + Xfile *f; + + if(strcmp(req->name, ".") == 0 || strcmp(req->name, "..") == 0) + error("create . or .."); + f = xfile(req->fid, Asis); + if(f->flags&Omodes) + error("create on open file"); + if(!(f->qid.path&CHDIR)) + error("create in non-directory"); + (*f->xf->s->create)(f, req->name, req->perm, req->mode); + chat("f->qid=0x%8.8lux...", f->qid.path); + f->flags = openflags(req->mode); + rep->qid = f->qid; +*/ +} + +void +rread(void) +{ + Xfile *f; + + f=xfile(req->fid, Asis); + if (!(f->flags&Oread)) + error("file not opened for reading"); + if(f->qid.type & QTDIR) + rep->count = (*f->xf->s->readdir)(f, (uchar*)fdata, req->offset, req->count); + else + rep->count = (*f->xf->s->read)(f, fdata, req->offset, req->count); + rep->data = fdata; +} + +void +rwrite(void) +{ + Xfile *f; + + f=xfile(req->fid, Asis); + if(!(f->flags&Owrite)) + error("file not opened for writing"); + rep->count = (*f->xf->s->write)(f, req->data, req->offset, req->count); +} + +void +rclunk(void) +{ + Xfile *f; + + if(!waserror()){ + f = xfile(req->fid, Asis); + (*f->xf->s->clunk)(f); + poperror(); + } + xfile(req->fid, Clunk); +} + +void +rremove(void) +{ + error("no removes"); +} + +void +rstat(void) +{ + Xfile *f; + Dir dir; + + chat("stat(fid=%d)...", req->fid); + f=xfile(req->fid, Asis); + setnames(&dir, fdata); + (*f->xf->s->stat)(f, &dir); + if(chatty) + showdir(2, &dir); + rep->nstat = convD2M(&dir, statbuf, sizeof statbuf); + rep->stat = statbuf; +} + +void +rwstat(void) +{ + error("no wstat"); +} + +static int +openflags(int mode) +{ + int flags = 0; + + switch(mode & ~(OTRUNC|OCEXEC|ORCLOSE)){ + case OREAD: + case OEXEC: + flags = Oread; break; + case OWRITE: + flags = Owrite; break; + case ORDWR: + flags = Oread|Owrite; break; + } + if(mode & ORCLOSE) + flags |= Orclose; + return flags; +} + +void +showdir(int fd, Dir *s) +{ + char a_time[32], m_time[32]; + char *p; + + strcpy(a_time, ctime(s->atime)); + if(p=strchr(a_time, '\n')) /* assign = */ + *p = 0; + strcpy(m_time, ctime(s->mtime)); + if(p=strchr(m_time, '\n')) /* assign = */ + *p = 0; + fprint(fd, "name=\"%s\" qid=(0x%llux,%lud) type=%d dev=%d \ +mode=0x%8.8lux=0%luo atime=%s mtime=%s length=%lld uid=\"%s\" gid=\"%s\"...", + s->name, s->qid.path, s->qid.vers, s->type, s->dev, + s->mode, s->mode, + a_time, m_time, s->length, s->uid, s->gid); +} + +#define SIZE 1024 + +void +chat(char *fmt, ...) +{ + va_list arg; + + if(chatty){ + va_start(arg, fmt); + vfprint(2, fmt, arg); + va_end(arg); + } +} + +void +panic(int rflag, char *fmt, ...) +{ + va_list arg; + char buf[SIZE]; int n; + + n = sprint(buf, "%s %d: ", argv0, getpid()); + va_start(arg, fmt); + vseprint(buf+n, buf+SIZE, fmt, arg); + va_end(arg); + fprint(2, (rflag ? "%s: %r\n" : "%s\n"), buf); + if(chatty){ + fprint(2, "abort\n"); + abort(); + } + exits("panic"); +} |