aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/9660srv/main.c
diff options
context:
space:
mode:
authorRuss Cox <rsc@swtch.com>2008-07-20 03:23:19 -0400
committerRuss Cox <rsc@swtch.com>2008-07-20 03:23:19 -0400
commit78a779a3834cf39d7c0bcd93a15824b29df947a3 (patch)
tree7ebe47a874a3864f8e990567554b0df956590650 /src/cmd/9660srv/main.c
parent29e9b5683ec8d610140da9118e8f004f74bc6c77 (diff)
downloadplan9port-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.c576
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");
+}