summaryrefslogtreecommitdiff
path: root/sys/src/cmd/9nfs/nfsserver.c
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/9nfs/nfsserver.c
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/9nfs/nfsserver.c')
-rwxr-xr-xsys/src/cmd/9nfs/nfsserver.c655
1 files changed, 655 insertions, 0 deletions
diff --git a/sys/src/cmd/9nfs/nfsserver.c b/sys/src/cmd/9nfs/nfsserver.c
new file mode 100755
index 000000000..6951dfeb1
--- /dev/null
+++ b/sys/src/cmd/9nfs/nfsserver.c
@@ -0,0 +1,655 @@
+#include "all.h"
+
+/*
+ * Cf. /lib/rfc/rfc1094
+ */
+
+static int nfsnull(int, Rpccall*, Rpccall*);
+static int nfsgetattr(int, Rpccall*, Rpccall*);
+static int nfssetattr(int, Rpccall*, Rpccall*);
+static int nfsroot(int, Rpccall*, Rpccall*);
+static int nfslookup(int, Rpccall*, Rpccall*);
+static int nfsreadlink(int, Rpccall*, Rpccall*);
+static int nfsread(int, Rpccall*, Rpccall*);
+static int nfswritecache(int, Rpccall*, Rpccall*);
+static int nfswrite(int, Rpccall*, Rpccall*);
+static int nfscreate(int, Rpccall*, Rpccall*);
+static int nfsremove(int, Rpccall*, Rpccall*);
+static int nfsrename(int, Rpccall*, Rpccall*);
+static int nfslink(int, Rpccall*, Rpccall*);
+static int nfssymlink(int, Rpccall*, Rpccall*);
+static int nfsmkdir(int, Rpccall*, Rpccall*);
+static int nfsrmdir(int, Rpccall*, Rpccall*);
+static int nfsreaddir(int, Rpccall*, Rpccall*);
+static int nfsstatfs(int, Rpccall*, Rpccall*);
+
+Procmap nfsproc[] = {
+ 0, nfsnull, /* void */
+ 1, nfsgetattr, /* Fhandle */
+ 2, nfssetattr, /* Fhandle, Sattr */
+ 3, nfsroot, /* void */
+ 4, nfslookup, /* Fhandle, String */
+ 5, nfsreadlink, /* Fhandle */
+ 6, nfsread, /* Fhandle, long, long, long */
+ 7, nfswritecache,/* void */
+ 8, nfswrite, /* Fhandle, long, long, long, String */
+ 9, nfscreate, /* Fhandle, String, Sattr */
+ 10, nfsremove, /* Fhandle, String */
+ 11, nfsrename, /* Fhandle, String, Fhandle, String */
+ 12, nfslink, /* Fhandle, Fhandle, String */
+ 13, nfssymlink, /* Fhandle, String, String, Sattr */
+ 14, nfsmkdir, /* Fhandle, String, Sattr */
+ 15, nfsrmdir, /* Fhandle, String */
+ 16, nfsreaddir, /* Fhandle, long, long */
+ 17, nfsstatfs, /* Fhandle */
+ 0, 0
+};
+
+void nfsinit(int, char**);
+extern void mntinit(int, char**);
+extern Procmap mntproc[];
+
+Progmap progmap[] = {
+ 100005, 1, mntinit, mntproc,
+ 100003, 2, nfsinit, nfsproc,
+ 0, 0, 0,
+};
+
+int myport = 2049;
+long nfstime;
+int conftime;
+
+void
+main(int argc, char *argv[])
+{
+ server(argc, argv, myport, progmap);
+}
+
+static void
+doalarm(void)
+{
+ nfstime = time(0);
+ mnttimer(nfstime);
+ if(conftime+5*60 < nfstime){
+ conftime = nfstime;
+ readunixidmaps(config);
+ }
+}
+
+void
+nfsinit(int argc, char **argv)
+{
+ /*
+ * mntinit will have already parsed our options.
+ */
+ USED(argc, argv);
+ clog("nfs file server init\n");
+ rpcalarm = doalarm;
+ nfstime = time(0);
+}
+
+static int
+nfsnull(int n, Rpccall *cmd, Rpccall *reply)
+{
+ USED(n, reply);
+ chat("nfsnull...");
+ showauth(&cmd->cred);
+ chat("OK\n");
+ return 0;
+}
+
+static int
+nfsgetattr(int n, Rpccall *cmd, Rpccall *reply)
+{
+ Xfid *xf;
+ Dir dir;
+ uchar *dataptr = reply->results;
+
+ chat("getattr...");
+ if(n != FHSIZE)
+ return garbage(reply, "bad count");
+ xf = rpc2xfid(cmd, &dir);
+ if(xf == 0)
+ return error(reply, NFSERR_STALE);
+ chat("%s...", xf->xp->name);
+ PLONG(NFS_OK);
+ dataptr += dir2fattr(cmd->up, &dir, dataptr);
+ chat("OK\n");
+ return dataptr - (uchar *)reply->results;
+}
+
+static int
+nfssetattr(int n, Rpccall *cmd, Rpccall *reply)
+{
+ Xfid *xf;
+ Dir dir, nd;
+ Sattr sattr;
+ int r;
+ uchar *argptr = cmd->args;
+ uchar *dataptr = reply->results;
+
+ chat("setattr...");
+ if(n <= FHSIZE)
+ return garbage(reply, "count too small");
+ xf = rpc2xfid(cmd, &dir);
+ argptr += FHSIZE;
+ argptr += convM2sattr(argptr, &sattr);
+ if(argptr != &((uchar *)cmd->args)[n])
+ return garbage(reply, "bad count");
+ chat("mode=0%lo,u=%ld,g=%ld,size=%ld,atime=%ld,mtime=%ld...",
+ sattr.mode, sattr.uid, sattr.gid, sattr.size,
+ sattr.atime, sattr.mtime);
+ if(xf == 0)
+ return error(reply, NFSERR_STALE);
+ if(sattr.uid != NOATTR || sattr.gid != NOATTR)
+ return error(reply, NFSERR_PERM);
+ if(sattr.size == 0){
+ if(xf->xp->s != xf->xp->parent->s){
+ if(xfauthremove(xf, cmd->user) < 0)
+ return error(reply, NFSERR_PERM);
+ }else if(dir.length && xfopen(xf, Trunc|Oread|Owrite) < 0)
+ return error(reply, NFSERR_PERM);
+ }else if(sattr.size != NOATTR)
+ return error(reply, NFSERR_PERM);
+ r = 0;
+ nulldir(&nd);
+ if(sattr.mode != NOATTR)
+ ++r, nd.mode = (dir.mode & ~0777) | (sattr.mode & 0777);
+ if(sattr.atime != NOATTR)
+ ++r, nd.atime = sattr.atime;
+ if(sattr.mtime != NOATTR)
+ ++r, nd.mtime = sattr.mtime;
+ chat("sattr.mode=%luo dir.mode=%luo nd.mode=%luo...", sattr.mode, dir.mode, nd.mode);
+ if(r){
+ r = xfwstat(xf, &nd);
+ if(r < 0)
+ return error(reply, NFSERR_PERM);
+ }
+ if(xfstat(xf, &dir) < 0)
+ return error(reply, NFSERR_STALE);
+ PLONG(NFS_OK);
+ dataptr += dir2fattr(cmd->up, &dir, dataptr);
+ chat("OK\n");
+ return dataptr - (uchar *)reply->results;
+}
+
+static int
+nfsroot(int n, Rpccall *cmd, Rpccall *reply)
+{
+ USED(n, reply);
+ chat("nfsroot...");
+ showauth(&cmd->cred);
+ chat("OK\n");
+ return 0;
+}
+
+static int
+nfslookup(int n, Rpccall *cmd, Rpccall *reply)
+{
+ Xfile *xp;
+ Xfid *xf, *newxf;
+ String elem;
+ Dir dir;
+ uchar *argptr = cmd->args;
+ uchar *dataptr = reply->results;
+
+ chat("lookup...");
+ if(n <= FHSIZE)
+ return garbage(reply, "count too small");
+ xf = rpc2xfid(cmd, 0);
+ argptr += FHSIZE;
+ argptr += string2S(argptr, &elem);
+ if(argptr != &((uchar *)cmd->args)[n])
+ return garbage(reply, "bad count");
+ if(xf == 0)
+ return error(reply, NFSERR_STALE);
+ xp = xf->xp;
+ if(!(xp->qid.type & QTDIR))
+ return error(reply, NFSERR_NOTDIR);
+ chat("%s -> \"%.*s\"...", xp->name, utfnlen(elem.s, elem.n), elem.s);
+ if(xp->s->noauth == 0 && xp->parent == xp && elem.s[0] == '#')
+ newxf = xfauth(xp, &elem);
+ else
+ newxf = xfwalkcr(Twalk, xf, &elem, 0);
+ if(newxf == 0)
+ return error(reply, NFSERR_NOENT);
+ if(xfstat(newxf, &dir) < 0)
+ return error(reply, NFSERR_IO);
+ PLONG(NFS_OK);
+ dataptr += xp2fhandle(newxf->xp, dataptr);
+ dataptr += dir2fattr(cmd->up, &dir, dataptr);
+ chat("OK\n");
+ return dataptr - (uchar *)reply->results;
+}
+
+static int
+nfsreadlink(int n, Rpccall *cmd, Rpccall *reply)
+{
+ USED(n, reply);
+ chat("readlink...");
+ showauth(&cmd->cred);
+ return error(reply, NFSERR_NOENT);
+}
+
+static int
+nfsread(int n, Rpccall *cmd, Rpccall *reply)
+{
+ Session *s;
+ Xfid *xf;
+ Dir dir;
+ int offset, count;
+ uchar *argptr = cmd->args;
+ uchar *dataptr = reply->results;
+ uchar *readptr = dataptr + 4 + 17*4 + 4;
+
+ chat("read...");
+ if(n != FHSIZE+12)
+ return garbage(reply, "bad count");
+ xf = rpc2xfid(cmd, 0);
+ argptr += FHSIZE;
+ offset = GLONG();
+ count = GLONG();
+ if(xf == 0)
+ return error(reply, NFSERR_STALE);
+ chat("%s %d %d...", xf->xp->name, offset, count);
+ if(xf->xp->s != xf->xp->parent->s){
+ count = xfauthread(xf, offset, readptr, count);
+ }else{
+ if(xfopen(xf, Oread) < 0)
+ return error(reply, NFSERR_PERM);
+ if(count > 8192)
+ count = 8192;
+ s = xf->xp->s;
+ setfid(s, xf->opfid);
+ xf->opfid->tstale = nfstime + 60;
+ s->f.offset = offset;
+ s->f.count = count;
+ if(xmesg(s, Tread) < 0)
+ return error(reply, NFSERR_IO);
+ count = s->f.count;
+ memmove(readptr, s->f.data, count);
+ }
+ if(xfstat(xf, &dir) < 0)
+ return error(reply, NFSERR_IO);
+ PLONG(NFS_OK);
+ dataptr += dir2fattr(cmd->up, &dir, dataptr);
+ PLONG(count);
+ dataptr += ROUNDUP(count);
+ chat("%d OK\n", count);
+ return dataptr - (uchar *)reply->results;
+}
+
+static int
+nfswritecache(int n, Rpccall *cmd, Rpccall *reply)
+{
+ USED(n, reply);
+ chat("writecache...");
+ showauth(&cmd->cred);
+ chat("OK\n");
+ return 0;
+}
+
+static int
+nfswrite(int n, Rpccall *cmd, Rpccall *reply)
+{
+ Session *s;
+ Xfid *xf;
+ Dir dir;
+ int offset, count;
+ uchar *argptr = cmd->args;
+ uchar *dataptr = reply->results;
+
+ chat("write...");
+ if(n < FHSIZE+16)
+ return garbage(reply, "count too small");
+ xf = rpc2xfid(cmd, 0);
+ argptr += FHSIZE + 4;
+ offset = GLONG();
+ argptr += 4;
+ count = GLONG();
+ if(xf == 0)
+ return error(reply, NFSERR_STALE);
+ chat("%s %d %d...", xf->xp->name, offset, count);
+ if(xf->xp->s != xf->xp->parent->s){
+ if(xfauthwrite(xf, offset, argptr, count) < 0)
+ return error(reply, NFSERR_IO);
+ }else{
+ if(xfopen(xf, Owrite) < 0)
+ return error(reply, NFSERR_PERM);
+ s = xf->xp->s;
+ setfid(s, xf->opfid);
+ xf->opfid->tstale = nfstime + 60;
+ s->f.offset = offset;
+ s->f.count = count;
+ s->f.data = (char *)argptr;
+ if(xmesg(s, Twrite) < 0)
+ return error(reply, NFSERR_IO);
+ }
+ if(xfstat(xf, &dir) < 0)
+ return error(reply, NFSERR_IO);
+ PLONG(NFS_OK);
+ dataptr += dir2fattr(cmd->up, &dir, dataptr);
+ chat("OK\n");
+ return dataptr - (uchar *)reply->results;
+}
+
+static int
+creat(int n, Rpccall *cmd, Rpccall *reply, int chdir)
+{
+ Xfid *xf, *newxf;
+ Xfile *xp;
+ String elem;
+ Dir dir; Sattr sattr;
+ uchar *argptr = cmd->args;
+ uchar *dataptr = reply->results;
+ int trunced;
+
+ if(n <= FHSIZE)
+ return garbage(reply, "count too small");
+ xf = rpc2xfid(cmd, 0);
+ argptr += FHSIZE;
+ argptr += string2S(argptr, &elem);
+ argptr += convM2sattr(argptr, &sattr);
+ if(argptr != &((uchar *)cmd->args)[n])
+ return garbage(reply, "bad count");
+ if(xf == 0)
+ return error(reply, NFSERR_STALE);
+ xp = xf->xp;
+ if(!(xp->qid.type & QTDIR))
+ return error(reply, NFSERR_NOTDIR);
+ chat("%s/%.*s...", xp->name, utfnlen(elem.s, elem.n), elem.s);
+ trunced = 0;
+ if(xp->parent == xp && elem.s[0] == '#'){
+ newxf = xfauth(xp, &elem);
+ if(newxf == 0)
+ return error(reply, NFSERR_PERM);
+ if(xfauthremove(newxf, cmd->user) < 0)
+ return error(reply, NFSERR_PERM);
+ trunced = 1;
+ }else
+ newxf = xfwalkcr(Twalk, xf, &elem, 0);
+ if(newxf == 0){
+ newxf = xfwalkcr(Tcreate, xf, &elem, chdir|(sattr.mode&0777));
+ if(newxf)
+ trunced = 1;
+ else
+ newxf = xfwalkcr(Twalk, xf, &elem, 0);
+ }
+ if(newxf == 0)
+ return error(reply, NFSERR_PERM);
+ if(!trunced && chdir)
+ return error(reply, NFSERR_EXIST);
+ if(!trunced && xfopen(newxf, Trunc|Oread|Owrite) < 0)
+ return error(reply, NFSERR_PERM);
+ if(xfstat(newxf, &dir) < 0)
+ return error(reply, NFSERR_IO);
+
+ PLONG(NFS_OK);
+ dataptr += xp2fhandle(newxf->xp, dataptr);
+ dataptr += dir2fattr(cmd->up, &dir, dataptr);
+ chat("OK\n");
+ return dataptr - (uchar *)reply->results;
+}
+
+static int
+nfscreate(int n, Rpccall *cmd, Rpccall *reply)
+{
+ chat("create...");
+ return creat(n, cmd, reply, 0);
+}
+
+static int
+remov(int n, Rpccall *cmd, Rpccall *reply)
+{
+ Session *s;
+ Xfile *xp;
+ Xfid *xf, *newxf;
+ String elem;
+ Fid *nfid;
+ uchar *argptr = cmd->args;
+ uchar *dataptr = reply->results;
+
+ if(n <= FHSIZE)
+ return garbage(reply, "count too small");
+ xf = rpc2xfid(cmd, 0);
+ argptr += FHSIZE;
+ argptr += string2S(argptr, &elem);
+ if(argptr != &((uchar *)cmd->args)[n])
+ return garbage(reply, "bad count");
+ if(xf == 0)
+ return error(reply, NFSERR_STALE);
+ xp = xf->xp;
+ if(!(xp->qid.type & QTDIR))
+ return error(reply, NFSERR_NOTDIR);
+ chat("%s/%.*s...", xp->name, utfnlen(elem.s, elem.n), elem.s);
+ if(xp->s->noauth == 0 && xp->parent == xp && elem.s[0] == '#')
+ return error(reply, NFSERR_PERM);
+ newxf = xfwalkcr(Twalk, xf, &elem, 0);
+ if(newxf == 0)
+ return error(reply, NFSERR_NOENT);
+ s = xp->s;
+ nfid = newfid(s);
+ setfid(s, newxf->urfid);
+ s->f.newfid = nfid - s->fids;
+ s->f.nwname = 0;
+ if(xmesg(s, Twalk) < 0){
+ putfid(s, nfid);
+ return error(reply, NFSERR_IO);
+ }
+ s->f.fid = nfid - s->fids;
+ if(xmesg(s, Tremove) < 0){
+ putfid(s, nfid);
+ return error(reply, NFSERR_PERM);
+ }
+ putfid(s, nfid);
+ xpclear(newxf->xp);
+ PLONG(NFS_OK);
+ chat("OK\n");
+ return dataptr - (uchar *)reply->results;
+}
+
+static int
+nfsremove(int n, Rpccall *cmd, Rpccall *reply)
+{
+ chat("remove...");
+ return remov(n, cmd, reply);
+}
+
+static int
+nfsrename(int n, Rpccall *cmd, Rpccall *reply)
+{
+ Xfid *xf, *newxf;
+ Xfile *xp;
+ uchar *fromdir, *todir;
+ String fromelem, toelem;
+ Dir dir;
+ uchar *argptr = cmd->args;
+ uchar *dataptr = reply->results;
+
+ chat("rename...");
+ if(n <= FHSIZE)
+ return garbage(reply, "count too small");
+ xf = rpc2xfid(cmd, 0);
+ fromdir = argptr;
+ argptr += FHSIZE;
+ argptr += string2S(argptr, &fromelem);
+ todir = argptr;
+ argptr += FHSIZE;
+ argptr += string2S(argptr, &toelem);
+ if(argptr != &((uchar *)cmd->args)[n])
+ return garbage(reply, "bad count");
+ if(xf == 0)
+ return error(reply, NFSERR_STALE);
+ xp = xf->xp;
+ if(!(xp->qid.type & QTDIR))
+ return error(reply, NFSERR_NOTDIR);
+ if(memcmp(fromdir, todir, FHSIZE) != 0)
+ return error(reply, NFSERR_NXIO);
+ newxf = xfwalkcr(Twalk, xf, &fromelem, 0);
+ if(newxf == 0)
+ return error(reply, NFSERR_NOENT);
+ if(xfstat(newxf, &dir) < 0)
+ return error(reply, NFSERR_IO);
+
+ if(xp->parent == xp && toelem.s[0] == '#')
+ return error(reply, NFSERR_PERM);
+ nulldir(&dir);
+ dir.name = toelem.s;
+ if(xfwstat(newxf, &dir) < 0)
+ return error(reply, NFSERR_PERM);
+ PLONG(NFS_OK);
+ chat("OK\n");
+ return dataptr - (uchar *)reply->results;
+}
+
+static int
+nfslink(int n, Rpccall *cmd, Rpccall *reply)
+{
+ USED(n, reply);
+ chat("link...");
+ showauth(&cmd->cred);
+ return error(reply, NFSERR_NOENT);
+}
+
+static int
+nfssymlink(int n, Rpccall *cmd, Rpccall *reply)
+{
+ USED(n, reply);
+ chat("symlink...");
+ showauth(&cmd->cred);
+ return error(reply, NFSERR_NOENT);
+}
+
+static int
+nfsmkdir(int n, Rpccall *cmd, Rpccall *reply)
+{
+ chat("mkdir...");
+ return creat(n, cmd, reply, DMDIR);
+}
+
+static int
+nfsrmdir(int n, Rpccall *cmd, Rpccall *reply)
+{
+ chat("rmdir...");
+ return remov(n, cmd, reply);
+}
+
+static int
+nfsreaddir(int n, Rpccall *cmd, Rpccall *reply)
+{
+ Session *s;
+ Xfid *xf;
+ Dir dir;
+ char *rdata;
+ int k, offset, count, sfcount, entries, dsize;
+ uchar *argptr = cmd->args;
+ uchar *dataptr = reply->results;
+
+ chat("readdir...");
+ if(n != FHSIZE+8)
+ return garbage(reply, "bad count");
+ xf = rpc2xfid(cmd, 0);
+ argptr += FHSIZE;
+ offset = GLONG();
+ count = GLONG();
+ if(xf == 0)
+ return error(reply, NFSERR_STALE);
+ chat("%s (%ld) %d %d...", xf->xp->name, xf->offset, offset, count);
+ s = xf->xp->s;
+ if((xf->mode & Open) && xf->offset > offset)
+ xfclose(xf);
+ if(xfopen(xf, Oread) < 0)
+ return error(reply, NFSERR_PERM);
+ while(xf->offset < offset){ /* if we reopened, xf->offset will be zero */
+ sfcount = offset - xf->offset;
+ if(sfcount > messagesize-IOHDRSZ)
+ sfcount = messagesize-IOHDRSZ;
+ setfid(s, xf->opfid);
+ s->f.offset = xf->offset;
+ s->f.count = sfcount;
+ if(xmesg(s, Tread) < 0){
+ xfclose(xf);
+ return error(reply, NFSERR_IO);
+ }
+ if(s->f.count <= BIT16SZ)
+ break;
+ xf->offset += s->f.count;
+ }
+ if(count > messagesize-IOHDRSZ)
+ count = messagesize-IOHDRSZ;
+ PLONG(NFS_OK);
+ entries = 0;
+ while(count > 16){ /* at least 16 bytes required; we don't know size of name */
+chat("top of loop\n");
+ setfid(s, xf->opfid);
+ s->f.offset = xf->offset;
+ s->f.count = count; /* as good a guess as any */
+ if(xmesg(s, Tread) < 0){
+ xfclose(xf);
+ return error(reply, NFSERR_IO);
+ }
+ sfcount = s->f.count;
+ if(sfcount <= BIT16SZ)
+ break;
+ xf->offset += sfcount;
+chat("count %d data 0x%p\n", s->f.count, s->f.data);
+ rdata = s->f.data;
+ /* now have a buffer of Plan 9 directories; unpack into NFS thingies */
+ while(sfcount >= 0){
+ dsize = convM2D((uchar*)rdata, sfcount, &dir, (char*)s->statbuf);
+ if(dsize <= BIT16SZ){
+ count = 0; /* force break from outer loop */
+ break;
+ }
+ offset += dsize;
+ k = strlen(dir.name);
+ if(count < 16+ROUNDUP(k)){
+ count = 0; /* force break from outer loop */
+ break;
+ }
+ PLONG(TRUE);
+ PLONG(dir.qid.path);
+ PLONG(k);
+ PPTR(dir.name, k);
+ PLONG(offset);
+ count -= 16+ROUNDUP(k);
+ rdata += dsize;
+ sfcount -= dsize;
+ }
+ }
+ PLONG(FALSE);
+ if(s->f.count <= 0){
+ xfclose(xf);
+ chat("eof...");
+ PLONG(TRUE);
+ }else
+ PLONG(FALSE);
+ chat("%d OK\n", entries);
+ return dataptr - (uchar *)reply->results;
+}
+
+static int
+nfsstatfs(int n, Rpccall *cmd, Rpccall *reply)
+{
+ uchar *dataptr = reply->results;
+ enum {
+ Xfersize = 2048,
+ Maxlong = (long)((1ULL<<31) - 1),
+ Maxfreeblks = Maxlong / Xfersize,
+ };
+
+ chat("statfs...");
+ showauth(&cmd->cred);
+ if(n != FHSIZE)
+ return garbage(reply, "bad count");
+ PLONG(NFS_OK);
+ PLONG(4096); /* tsize (fs block size) */
+ PLONG(Xfersize); /* bsize (optimal transfer size) */
+ PLONG(Maxfreeblks); /* blocks in fs */
+ PLONG(Maxfreeblks); /* bfree to root*/
+ PLONG(Maxfreeblks); /* bavail (free to mortals) */
+ chat("OK\n");
+ /*conftime = 0;
+ readunixidmaps(config);*/
+ return dataptr - (uchar *)reply->results;
+}