577 lines
9.3 KiB
C
577 lines
9.3 KiB
C
#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");
|
|
}
|