#include <u.h>
#include <libc.h>
#include <fcall.h>
#include <thread.h>
#include <9p.h>
#include "dat.h"
#include "fns.h"
typedef struct Aux Aux;
struct Aux {
int off;
};
typedef struct Fs Fs;
struct Fs {
long inittime;
Netlog log;
Netlog tlslog;
};
static Fs theFs;
static char sbuf[1024];
static char tbuf[1024];
typedef struct Tab Tab;
struct Tab
{
char *name;
ulong mode;
uchar type;
// for directories: entries
int begin;
int end;
int parent;
};
Tab tab[] =
{
/* name mode type beg end parent */
/* Qroot */ "/", DMDIR|0555, QTDIR, Qdir, Qdir+1, Qroot,
/* in Qroot: */
/* Qdir */ "8021x", DMDIR|0555, QTDIR, Qctl, Qn, Qroot,
/* in Qdir: */
/* Qctl */ "ctl", 0666, 0, 0, 0, Qdir,
/* Qkeys */ "keys", 0444, 0, 0, 0, Qdir,
/* Qlog */ "log", 0444, 0, 0, 0, Qdir,
/* Qnote */ "note", 0444, 0, 0, 0, Qdir,
/* Qstats */ "stats", 0444, 0, 0, 0, Qdir,
/* Qstatus */ "status", 0444, 0, 0, 0, Qdir,
/* Qtslog */ "tlslog", 0444, 0, 0, 0, Qdir,
};
#define PATH(type, n) ((type)|((n)<<8))
#define TYPE(path) ((int)(path) & 0xFF)
#define NUM(path) ((uint)(path)>>8)
Channel *fsreqchan; /* chan(Req*) */
Channel *fsreqwaitchan; /* chan(nil) */
Channel *fsclunkchan; /* chan(Fid*) */
Channel *fsclunkwaitchan; /* chan(nil) */
enum
{
Closed,
Open,
};
char *statestr[] = {
"Closed",
"Open",
};
typedef struct Reader Reader;
struct Reader
{
int ref;
int state;
int num;
Req *rq;
Req **erq;
int qid;
};
int nreader;
Reader **reader;
static int newreader(void);
static void teardownreader(Netlog*, Reader*);
static void queuereq(Reader *, Req *);
static int
fillstat(ulong qid, Dir *d)
{
Tab *t;
ReadBuf *b;
if (qid < 0 || qid >= Qn)
return 0;
memset(d, 0, sizeof(Dir));
d->uid = "8021x";
d->gid = "8021x";
d->muid = "";
d->qid = (Qid){qid, 0, 0};
d->atime = time(0);
d->mtime = theFs.inittime;
t = &tab[qid];
d->name = t->name;
d->mode = t->mode;
d->qid.type = t->type;
switch(qid){
case Qstatus:
case Qkeys:
case Qnote:
d->mtime = getChangetime(qid);
break;
}
switch(qid){
case Qkeys:
b = getKeysbuf();
d->length = b->ndata;
break;
case Qnote:
b = getNotesbuf();
d->length = b->ndata;
break;
case Qstatus:
getPAEStatus(sbuf, sizeof(sbuf));
d->length = strlen(sbuf);
break;
}
return 1;
}
static void
fsattach(Req *r)
{
r->fid->qid = (Qid){Qroot, 0, QTDIR};
r->ofcall.qid = r->fid->qid;
r->fid->aux = emalloc9p(sizeof(Aux));
respond(r, nil);
}
static char*
fsclone(Fid *old, Fid *new)
{
Aux *na;
na = emalloc9p(sizeof(Aux));
*na = *((Aux*)old->aux);
new->aux = na;
return nil;
}
static int
lookupqid(char *name, Tab *dir)
{
Tab *t, *b, *e;
if (dir == nil)
return -1;
if(strcmp(name, "..") == 0)
return dir->parent;
b = &tab[dir->begin];
e = &tab[dir->end];
for (t = b; t < e; t++)
if (strcmp(name, t->name) == 0)
return t - &tab[0];
return -1;
}
static char*
fswalk1(Fid *fid, char *name, Qid *qid)
{
ulong p, i;
Tab *t;
p = fid->qid.path;
if (p < 0 || p >= Qn)
return "no such file or directory";
t = &tab[p];
if ((t->type & QTDIR) != QTDIR)
return "walk in non-directory";
i = lookupqid(name, t);
if (i >= 0){
*qid = (Qid){i, 0, tab[i].type};
return nil;
}
return "no such file or directory";
}
static void
readctl(Req *r)
{
char s[1024];
sprint(s, "802.1x ctl bla\n");
readstr(r, s);
}
static void
fsread(Req *r)
{
int j, n;
Fid *fid;
vlong offset;
uchar *p, *ep;
void *buf;
long count;
Dir d;
Aux *a;
ReadBuf *b;
ulong path;
fid = r->fid;
path = fid->qid.path;
offset = r->ifcall.offset;
count = r->ifcall.count;
buf = r->ofcall.data;
switch(TYPE(path)) {
case Qroot:
p = buf;
ep = p+count;
if(offset == 0) {
if(fillstat(Qdir, &d) && (n = convD2M(&d, p, ep-p)) > BIT16SZ)
p += n;
r->ofcall.count = p-(uchar*)buf;
}
respond(r, nil);
return;
case Qdir:
p = buf;
ep = p+count;
a = fid->aux;
if(offset == 0)
a->off = 2; /* skip root and Qdir */
for(j=a->off; j<Qn; j++) {
if(fillstat(j, &d)) {
if((n = convD2M(&d, p, ep-p)) <= BIT16SZ)
break;
p += n;
}
}
a->off = j;
r->ofcall.count = p-(uchar*)buf;
respond(r, nil);
return;
case Qkeys:
b = getKeysbuf();
readbuf(r, b->data, b->ndata);
respond(r, nil);
return;
case Qlog:
a = fid->aux;
r->ofcall.count = netlogread(&theFs.log, buf, count, offset, &a->off);
if (r->ofcall.count == 0)
queuereq(reader[NUM(path)], r);
else
respond(r, nil);
return;
case Qtlslog:
a = fid->aux;
r->ofcall.count = netlogread(&theFs.tlslog, buf, count, offset, &a->off);
if (r->ofcall.count == 0)
queuereq(reader[NUM(path)], r);
else
respond(r, nil);
return;
case Qnote:
b = getNotesbuf();
readbuf(r, b->data, b->ndata);
respond(r, nil);
return;
case Qstats:
r->ofcall.count = 0;
respond(r, nil);
return;
case Qstatus:
getPAEStatus(sbuf, sizeof(sbuf));
readstr(r, sbuf);
respond(r, nil);
return;
case Qctl:
readctl(r);
respond(r, nil);
return;
}
}
static char*
writectl(void *v, long count)
{
USED(v);
USED(count);
return nil;
}
static void
fswrite(Req *r)
{
Fid *fid;
fid = r->fid;
r->ofcall.count = r->ifcall.count;
if(fid->qid.path == Qctl) {
respond(r, writectl(r->ifcall.data, r->ifcall.count));
return;
}
respond(r, "permission denied");
return;
}
static void
fsstat(Req *r)
{
fillstat(TYPE((ulong)r->fid->qid.path), &r->d);
r->d.name = estrdup9p(r->d.name);
r->d.uid = estrdup9p(r->d.uid);
r->d.gid = estrdup9p(r->d.gid);
r->d.muid = estrdup9p(r->d.muid);
respond(r, nil);
}
static void
fsopen(Req *r)
{
int omode;
Fid *fid;
ulong path;
int n;
Aux *a;
Reader *c;
fid = r->fid;
omode = r->ifcall.mode;
r->ofcall.qid = (Qid){fid->qid.path, 0, fid->qid.type};
switch((ulong)fid->qid.path){
case Qctl:
if(omode&~(OTRUNC|OREAD|OWRITE|ORDWR))
respond(r, "permission denied");
else
respond(r, nil);
return;
case Qlog:
if(omode != OREAD)
respond(r, "permission denied");
n = newreader();
c = reader[n];
c->qid = Qlog;
c->state = Open;
path = PATH(Qlog, n);
netlogopen(&theFs.log);
r->fid->qid.path = path;
r->ofcall.qid.path = path;
a = r->fid->aux;
a->off = 0;
if(chatty9p)
fprint(2, "open log => path=%lux\n", path);
reader[NUM(path)]->ref++;
respond(r, nil);
return;
case Qtlslog:
if(omode != OREAD)
respond(r, "permission denied");
n = newreader();
c = reader[n];
c->qid = Qtlslog;
c->state = Open;
path = PATH(Qtlslog, n);
netlogopen(&theFs.tlslog);
r->fid->qid.path = path;
r->ofcall.qid.path = path;
a = r->fid->aux;
a->off = 0;
debugTLS++;
if(chatty9p)
fprint(2, "open tlslog => path=%lux debugTLS=%d\n", path, debugTLS);
reader[NUM(path)]->ref++;
respond(r, nil);
return;
case Qroot:
case Qdir:
case Qkeys:
case Qnote:
case Qstats:
case Qstatus:
if(omode == OREAD)
respond(r, nil);
else
respond(r, "permission denied");
return;
default:
respond(r, "no such file or directory");
}
}
static int
newreader(void)
{
int i;
Reader *c;
for(i=0; i<nreader; i++)
if(reader[i]->ref==0 && reader[i]->state == Closed)
return i;
if(nreader%16 == 0)
reader = erealloc9p(reader, (nreader+16)*sizeof(reader[0]));
c = emalloc9p(sizeof(Reader));
memset(c, 0, sizeof(*c));
c->num = nreader;
reader[nreader++] = c;
return c->num;
}
static void queuereq(Reader *c, Req *r)
{
if(c->rq==nil)
c->erq = &c->rq;
*c->erq = r;
r->aux = nil;
c->erq = (Req**)&r->aux;
}
Req*
findreq(Reader *c, Req *r)
{
Req **l;
for(l=&c->rq; *l; l=(Req**)&(*l)->aux){
if(*l == r){
*l = r->aux;
if(*l == nil)
c->erq = l;
return r;
}
}
return nil;
}
void
closereader(Netlog *l, Reader *c)
{
if(--c->ref)
return;
if(c->rq != nil)
logfatal(0, "ref count reached zero with requests pending (BUG)");
if(c->state != Closed)
teardownreader(l, c);
}
static void
teardownreader(Netlog *l, Reader *c)
{
c->state = Closed;
netlogclose(l);
}
static void
fsflush(Req *r)
{
int i;
for(i=0; i<nreader; i++)
if(findreq(reader[i], r->oldreq))
respond(r->oldreq, "interrupted");
respond(r, nil);
}
void
handlereader(Netlog *l, int qid)
{
Req *r;
int i;
void *buf;
long count;
vlong offset;
Reader *c;
Aux *a;
// syslog(0, logname, "handlereader %d nreader=%d", qid, nreader);
for(i=0; i<nreader; i++) {
c = reader[i];
// syslog(0, logname, "handlereader %d:%d state=%s qid=%d", qid, i, statestr[c->state], c->qid);
if (c->state == Closed)
continue;
else if (c->qid == qid) {
r = c->rq;
if(r != nil){
if(r->aux != nil)
logfatal(0, "more than one outstanding reader request (BUG)");
offset = r->ifcall.offset;
count = r->ifcall.count;
buf = r->ofcall.data;
a = r->fid->aux;
r->ofcall.count = netlogread(l, buf, count, offset, &a->off);
if (r->ofcall.count != 0) {
c->rq = nil;
respond(r, nil);
}
}
}
}
}
static void
fsnetproc(void*)
{
ulong path;
Alt a[5];
Fid *fid;
Req *r;
threadsetname("fsthread");
a[0].op = CHANRCV;
a[0].c = fsclunkchan;
a[0].v = &fid;
a[1].op = CHANRCV;
a[1].c = fsreqchan;
a[1].v = &r;
a[2].op = CHANRCV;
a[2].c = theFs.log.ping;
a[2].v = nil;
a[3].op = CHANRCV;
a[3].c = theFs.tlslog.ping;
a[3].v = nil;
a[4].op = CHANEND;
a[4].op = CHANEND;
for(;;){
switch(alt(a)){
case 0:
path = fid->qid.path;
if(fid->aux) {
free(fid->aux);
fid->aux = 0;
}
switch(TYPE(path)){
case Qlog:
if(chatty9p)
fprint(2, "close log => path=%lux\n", path);
if(fid->omode != -1)
closereader(&theFs.log, reader[NUM(path)]);
break;
case Qtlslog:
if(chatty9p)
fprint(2, "close tlslog => path=%lux\n", path);
debugTLS--;
if(fid->omode != -1)
closereader(&theFs.tlslog, reader[NUM(path)]);
break;
}
sendp(fsclunkwaitchan, nil);
break;
case 1:
switch(r->ifcall.type){
case Tattach:
fsattach(r);
break;
case Topen:
fsopen(r);
break;
case Tread:
fsread(r);
break;
case Twrite:
fswrite(r);
break;
case Tstat:
fsstat(r);
break;
case Tflush:
fsflush(r);
break;
default:
respond(r, "bug in fsthread");
break;
}
sendp(fsreqwaitchan, 0);
break;
case 2:
handlereader(&theFs.log, Qlog);
break;
case 3:
handlereader(&theFs.tlslog, Qtlslog);
break;
}
}
}
static void
fssend(Req *r)
{
sendp(fsreqchan, r);
recvp(fsreqwaitchan); /* avoids need to deal with spurious flushes */
}
static void
fsdestroyfid(Fid *fid)
{
sendp(fsclunkchan, fid);
recvp(fsclunkwaitchan);
}
static void
takedown(Srv*)
{
threadexitsall("done");
}
Srv fs = {
.attach= fsattach,
.clone= fsclone,
.walk1= fswalk1,
.open= fsopen,
.read= fsread,
.write= fswrite,
.stat= fsstat,
.flush= fssend,
.destroyfid= fsdestroyfid,
.end= takedown,
};
void
initFs(void)
{
theFs.inittime = time(0);
fsreqchan = chancreate(sizeof(Req*), 0);
fsreqwaitchan = chancreate(sizeof(void*), 0);
fsclunkchan = chancreate(sizeof(Fid*), 0);
fsclunkwaitchan = chancreate(sizeof(void*), 0);
netloginit(&theFs.log, "log");
netloginit(&theFs.tlslog, "tlslog");
// syslog(0, logname, "initFs &theFs.log=%p &theFs.tlslog=%p", &theFs.log, &theFs.tlslog);
procrfork(fsnetproc, nil, 8192, RFNAMEG|RFNOTEG);
}
int
loglog(char *fmt, ...)
{
int n;
va_list arg;
va_start(arg, fmt);
n = netlog(&theFs.log, fmt, arg);
va_end(arg);
return n;
}
int
tlslog(char *fmt, ...)
{
int n;
va_list arg;
va_start(arg, fmt);
n = netlog(&theFs.tlslog, fmt, arg);
va_end(arg);
return n;
}
|