mirror of
https://github.com/9fans/plan9port.git
synced 2025-01-15 11:20:03 +00:00
428 lines
7.3 KiB
C
428 lines
7.3 KiB
C
/*
|
|
* Simple read-only NFS v3 server.
|
|
* Runs every request in its own thread.
|
|
* Expects client to provide the fsxxx routines in nfs3srv.h.
|
|
*/
|
|
#include <u.h>
|
|
#include <libc.h>
|
|
#include <thread.h>
|
|
#include <sunrpc.h>
|
|
#include <nfs3.h>
|
|
#include "nfs3srv.h"
|
|
|
|
static SunStatus
|
|
authunixunpack(SunRpc *rpc, SunAuthUnix *au)
|
|
{
|
|
uchar *p, *ep;
|
|
SunAuthInfo *ai;
|
|
|
|
ai = &rpc->cred;
|
|
if(ai->flavor != SunAuthSys)
|
|
return SunAuthTooWeak;
|
|
p = ai->data;
|
|
ep = p+ai->ndata;
|
|
if(sunauthunixunpack(p, ep, &p, au) < 0)
|
|
return SunGarbageArgs;
|
|
if(au->uid == 0)
|
|
au->uid = -1;
|
|
if(au->gid == 0)
|
|
au->gid = -1;
|
|
|
|
return SunSuccess;
|
|
}
|
|
|
|
static int
|
|
rnull(SunMsg *m)
|
|
{
|
|
NfsMount3RNull rx;
|
|
|
|
memset(&rx, 0, sizeof rx);
|
|
return sunmsgreply(m, &rx.call);
|
|
}
|
|
|
|
static int
|
|
rmnt(SunMsg *m)
|
|
{
|
|
Nfs3Handle nh;
|
|
NfsMount3RMnt rx;
|
|
SunAuthUnix au;
|
|
int ok;
|
|
|
|
if((ok = authunixunpack(&m->rpc, &au)) != SunSuccess)
|
|
return sunmsgreplyerror(m, ok);
|
|
|
|
/* ignore file system path and return the dump tree */
|
|
|
|
memset(&rx, 0, sizeof rx);
|
|
rx.nauth = 0;
|
|
rx.status = 0;
|
|
memset(&nh, 0, sizeof nh);
|
|
fsgetroot(&nh);
|
|
rx.handle = nh.h;
|
|
rx.len = nh.len;
|
|
|
|
return sunmsgreply(m, &rx.call);
|
|
}
|
|
|
|
static int
|
|
rumnt(SunMsg *m)
|
|
{
|
|
NfsMount3RUmnt rx;
|
|
|
|
/* ignore */
|
|
|
|
memset(&rx, 0, sizeof rx);
|
|
return sunmsgreply(m, &rx.call);
|
|
}
|
|
|
|
static int
|
|
rumntall(SunMsg *m)
|
|
{
|
|
NfsMount3RUmntall rx;
|
|
|
|
/* ignore */
|
|
|
|
memset(&rx, 0, sizeof rx);
|
|
return sunmsgreply(m, &rx.call);
|
|
}
|
|
|
|
static int
|
|
rexport(SunMsg *m)
|
|
{
|
|
NfsMount3RExport rx;
|
|
|
|
/* ignore */
|
|
|
|
memset(&rx, 0, sizeof rx);
|
|
rx.count = 0;
|
|
return sunmsgreply(m, &rx.call);
|
|
}
|
|
|
|
static void
|
|
rmount3(void *v)
|
|
{
|
|
SunMsg *m;
|
|
|
|
m = v;
|
|
switch(m->call->type){
|
|
default:
|
|
sunmsgreplyerror(m, SunProcUnavail);
|
|
case NfsMount3CallTNull:
|
|
rnull(m);
|
|
break;
|
|
case NfsMount3CallTMnt:
|
|
rmnt(m);
|
|
break;
|
|
case NfsMount3CallTDump:
|
|
rmnt(m);
|
|
break;
|
|
case NfsMount3CallTUmnt:
|
|
rumnt(m);
|
|
break;
|
|
case NfsMount3CallTUmntall:
|
|
rumntall(m);
|
|
break;
|
|
case NfsMount3CallTExport:
|
|
rexport(m);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
mount3proc(void *v)
|
|
{
|
|
Channel *c;
|
|
SunMsg *m;
|
|
|
|
threadsetname("mount1");
|
|
c = v;
|
|
while((m=recvp(c)) != nil)
|
|
threadcreate(rmount3, m, SunStackSize);
|
|
}
|
|
|
|
static int
|
|
senderror(SunMsg *m, SunCall *rc, Nfs3Status status)
|
|
{
|
|
/* knows that status is first field in all replies */
|
|
((Nfs3RGetattr*)rc)->status = status;
|
|
return sunmsgreply(m, rc);
|
|
}
|
|
|
|
static int
|
|
rnull0(SunMsg *m)
|
|
{
|
|
Nfs3RNull rx;
|
|
|
|
memset(&rx, 0, sizeof rx);
|
|
return sunmsgreply(m, &rx.call);
|
|
}
|
|
|
|
static int
|
|
rgetattr(SunMsg *m)
|
|
{
|
|
Nfs3TGetattr *tx = (Nfs3TGetattr*)m->call;
|
|
Nfs3RGetattr rx;
|
|
SunAuthUnix au;
|
|
int ok;
|
|
|
|
if((ok = authunixunpack(&m->rpc, &au)) != SunSuccess)
|
|
return sunmsgreplyerror(m, ok);
|
|
|
|
memset(&rx, 0, sizeof rx);
|
|
rx.status = fsgetattr(&au, &tx->handle, &rx.attr);
|
|
return sunmsgreply(m, &rx.call);
|
|
}
|
|
|
|
static int
|
|
rlookup(SunMsg *m)
|
|
{
|
|
Nfs3TLookup *tx = (Nfs3TLookup*)m->call;
|
|
Nfs3RLookup rx;
|
|
SunAuthUnix au;
|
|
int ok;
|
|
|
|
if((ok = authunixunpack(&m->rpc, &au)) != SunSuccess)
|
|
return sunmsgreplyerror(m, ok);
|
|
|
|
memset(&rx, 0, sizeof rx);
|
|
rx.status = fsgetattr(&au, &tx->handle, &rx.dirAttr);
|
|
if(rx.status != Nfs3Ok)
|
|
return sunmsgreply(m, &rx.call);
|
|
rx.haveDirAttr = 1;
|
|
rx.status = fslookup(&au, &tx->handle, tx->name, &rx.handle);
|
|
if(rx.status != Nfs3Ok)
|
|
return sunmsgreply(m, &rx.call);
|
|
rx.status = fsgetattr(&au, &rx.handle, &rx.attr);
|
|
if(rx.status != Nfs3Ok)
|
|
return sunmsgreply(m, &rx.call);
|
|
rx.haveAttr = 1;
|
|
return sunmsgreply(m, &rx.call);
|
|
}
|
|
|
|
static int
|
|
raccess(SunMsg *m)
|
|
{
|
|
Nfs3TAccess *tx = (Nfs3TAccess*)m->call;
|
|
Nfs3RAccess rx;
|
|
SunAuthUnix au;
|
|
int ok;
|
|
|
|
if((ok = authunixunpack(&m->rpc, &au)) != SunSuccess)
|
|
return sunmsgreplyerror(m, ok);
|
|
|
|
memset(&rx, 0, sizeof rx);
|
|
rx.haveAttr = 1;
|
|
rx.status = fsaccess(&au, &tx->handle, tx->access, &rx.access, &rx.attr);
|
|
return sunmsgreply(m, &rx.call);
|
|
}
|
|
|
|
static int
|
|
rreadlink(SunMsg *m)
|
|
{
|
|
Nfs3RReadlink rx;
|
|
Nfs3TReadlink *tx = (Nfs3TReadlink*)m->call;
|
|
SunAuthUnix au;
|
|
int ok;
|
|
|
|
if((ok = authunixunpack(&m->rpc, &au)) != SunSuccess)
|
|
return sunmsgreplyerror(m, ok);
|
|
|
|
memset(&rx, 0, sizeof rx);
|
|
rx.haveAttr = 0;
|
|
rx.data = nil;
|
|
rx.status = fsreadlink(&au, &tx->handle, &rx.data);
|
|
sunmsgreply(m, &rx.call);
|
|
free(rx.data);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
rread(SunMsg *m)
|
|
{
|
|
Nfs3TRead *tx = (Nfs3TRead*)m->call;
|
|
Nfs3RRead rx;
|
|
SunAuthUnix au;
|
|
int ok;
|
|
|
|
if((ok = authunixunpack(&m->rpc, &au)) != SunSuccess)
|
|
return sunmsgreplyerror(m, ok);
|
|
|
|
memset(&rx, 0, sizeof rx);
|
|
rx.haveAttr = 0;
|
|
rx.data = nil;
|
|
rx.status = fsreadfile(&au, &tx->handle, tx->count, tx->offset, &rx.data, &rx.count, &rx.eof);
|
|
if(rx.status == Nfs3Ok)
|
|
rx.ndata = rx.count;
|
|
|
|
sunmsgreply(m, &rx.call);
|
|
free(rx.data);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
rreaddir(SunMsg *m)
|
|
{
|
|
Nfs3TReadDir *tx = (Nfs3TReadDir*)m->call;
|
|
Nfs3RReadDir rx;
|
|
SunAuthUnix au;
|
|
int ok;
|
|
|
|
if((ok = authunixunpack(&m->rpc, &au)) != SunSuccess)
|
|
return sunmsgreplyerror(m, ok);
|
|
|
|
memset(&rx, 0, sizeof rx);
|
|
rx.status = fsreaddir(&au, &tx->handle, tx->count, tx->cookie, &rx.data, &rx.count, &rx.eof);
|
|
sunmsgreply(m, &rx.call);
|
|
free(rx.data);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
rreaddirplus(SunMsg *m)
|
|
{
|
|
Nfs3RReadDirPlus rx;
|
|
|
|
memset(&rx, 0, sizeof rx);
|
|
rx.status = Nfs3ErrNotSupp;
|
|
sunmsgreply(m, &rx.call);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
rfsstat(SunMsg *m)
|
|
{
|
|
Nfs3RFsStat rx;
|
|
|
|
/* just make something up */
|
|
memset(&rx, 0, sizeof rx);
|
|
rx.status = Nfs3Ok;
|
|
rx.haveAttr = 0;
|
|
rx.totalBytes = 1000000000;
|
|
rx.freeBytes = 0;
|
|
rx.availBytes = 0;
|
|
rx.totalFiles = 100000;
|
|
rx.freeFiles = 0;
|
|
rx.availFiles = 0;
|
|
rx.invarSec = 0;
|
|
return sunmsgreply(m, &rx.call);
|
|
}
|
|
|
|
static int
|
|
rfsinfo(SunMsg *m)
|
|
{
|
|
Nfs3RFsInfo rx;
|
|
|
|
/* just make something up */
|
|
memset(&rx, 0, sizeof rx);
|
|
rx.status = Nfs3Ok;
|
|
rx.haveAttr = 0;
|
|
rx.readMax = MaxDataSize;
|
|
rx.readPref = MaxDataSize;
|
|
rx.readMult = MaxDataSize;
|
|
rx.writeMax = MaxDataSize;
|
|
rx.writePref = MaxDataSize;
|
|
rx.writeMult = MaxDataSize;
|
|
rx.readDirPref = MaxDataSize;
|
|
rx.maxFileSize = 1LL<<60;
|
|
rx.timePrec.sec = 1;
|
|
rx.timePrec.nsec = 0;
|
|
rx.flags = Nfs3FsHomogeneous|Nfs3FsCanSetTime;
|
|
return sunmsgreply(m, &rx.call);
|
|
}
|
|
|
|
static int
|
|
rpathconf(SunMsg *m)
|
|
{
|
|
Nfs3RPathconf rx;
|
|
|
|
memset(&rx, 0, sizeof rx);
|
|
rx.status = Nfs3Ok;
|
|
rx.haveAttr = 0;
|
|
rx.maxLink = 1;
|
|
rx.maxName = 1024;
|
|
rx.noTrunc = 1;
|
|
rx.chownRestricted = 0;
|
|
rx.caseInsensitive = 0;
|
|
rx.casePreserving = 1;
|
|
return sunmsgreply(m, &rx.call);
|
|
}
|
|
|
|
static int
|
|
rrofs(SunMsg *m)
|
|
{
|
|
uchar buf[512]; /* clumsy hack*/
|
|
|
|
memset(buf, 0, sizeof buf);
|
|
return senderror(m, (SunCall*)buf, Nfs3ErrRoFs);
|
|
}
|
|
|
|
|
|
static void
|
|
rnfs3(void *v)
|
|
{
|
|
SunMsg *m;
|
|
|
|
m = v;
|
|
switch(m->call->type){
|
|
default:
|
|
abort();
|
|
case Nfs3CallTNull:
|
|
rnull0(m);
|
|
break;
|
|
case Nfs3CallTGetattr:
|
|
rgetattr(m);
|
|
break;
|
|
case Nfs3CallTLookup:
|
|
rlookup(m);
|
|
break;
|
|
case Nfs3CallTAccess:
|
|
raccess(m);
|
|
break;
|
|
case Nfs3CallTReadlink:
|
|
rreadlink(m);
|
|
break;
|
|
case Nfs3CallTRead:
|
|
rread(m);
|
|
break;
|
|
case Nfs3CallTReadDir:
|
|
rreaddir(m);
|
|
break;
|
|
case Nfs3CallTReadDirPlus:
|
|
rreaddirplus(m);
|
|
break;
|
|
case Nfs3CallTFsStat:
|
|
rfsstat(m);
|
|
break;
|
|
case Nfs3CallTFsInfo:
|
|
rfsinfo(m);
|
|
break;
|
|
case Nfs3CallTPathconf:
|
|
rpathconf(m);
|
|
break;
|
|
case Nfs3CallTSetattr:
|
|
case Nfs3CallTWrite:
|
|
case Nfs3CallTCreate:
|
|
case Nfs3CallTMkdir:
|
|
case Nfs3CallTSymlink:
|
|
case Nfs3CallTMknod:
|
|
case Nfs3CallTRemove:
|
|
case Nfs3CallTRmdir:
|
|
case Nfs3CallTLink:
|
|
case Nfs3CallTCommit:
|
|
rrofs(m);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
nfs3proc(void *v)
|
|
{
|
|
Channel *c;
|
|
SunMsg *m;
|
|
|
|
c = v;
|
|
threadsetname("nfs3");
|
|
while((m = recvp(c)) != nil)
|
|
threadcreate(rnfs3, m, SunStackSize);
|
|
}
|
|
|