#include <u.h>
#include <libc.h>
#include <fcall.h>
#include <thread.h>
#include <9p.h>
#include <bio.h>
#include <ndb.h>
#include "ber.h"
#include "ndbutil.h"
#include "snmp.h"
#include "fs.h"
Tree *fstree;
/* no auth, just mount the selected host */
void
fsattach(Req *r)
{
char *host;
File *f;
host = strdup(r->ifcall.aname);
error(DEBUG,"fsattach(): mount %s as %s\n",host,r->fid->file->name);
if (strncmp(host,"all",3) != 0 ) {
/* test if the machine exists */
f = walkfile(fstree->root,host);
if ( f == nil ) {
werrstr("fsattach(): error: host %s not registered",host);
free(host);
responderror(r);
return;
}
} else {
f = fstree->root;
}
r->fid->file = f;
incref(r->fid->file);
r->ofcall.qid = f->qid;
r->fid->qid = r->ofcall.qid;
free(host);
respond(r,nil);
return;
}
/* we store snmpinfo temporally in f->aux, to get long walks */
/* and we free'd them as soon as are completly readed */
/* root->name should be the host as it appears in ndb */
/* file->name should be the oid in the dotted or name form */
void
fsread(Req *r)
{
File *f,*root;
vlong offset;
long count;
Session *s;
Packet *p;
char *aux;
Bytes *ptr;
f = r->fid->file;
root = f->parent;
offset = r->ifcall.offset;
count = r->ifcall.count;
ptr = (Bytes*)f->aux;
/* fill the bytes with the collected data */
if( f->aux == nil ) {
s = mksession(root->name);
p = mkpacket(root->name,f->name,nil);
aux = (void*)dosnmp(s,p);
f->aux = (void*)makebytes((uchar*)aux, strlen(aux)+1);
ptr = (Bytes*)f->aux;
free(aux);
freepacket(p);
freesession(s);
}
if (offset >= ptr->len ) {
r->ofcall.count = 0;
freebytes(ptr);
f->aux = nil;
respond(r, nil);
return;
}
if(offset+count >= ptr->len)
count = ptr->len - offset;
memmove(r->ofcall.data, ptr->data+offset, count);
r->ofcall.count = count;
/* free the content each time it is completly
readed we don't want to cache */
if ( count == ptr->len) {
freebytes(ptr);
f->aux = nil;
}
respond(r,nil);
}
void
fswrite(Req *r)
{
File *f,*root;
vlong offset;
long count;
Session *s;
Packet *p;
char *host, *oid, *val,*aux;
f = r->fid->file;
root = f->parent;
offset = r->ifcall.offset;
count = r->ifcall.count;
if( f->aux == nil ) {
host = strdup(root->name);
oid= strdup(f->name);
val = (char*)emalloc(count+1);
memcpy(val,r->ifcall.data, count);
val[count] = '\0';
s = mksession(host);
p = mkpacket(host,oid,val);
free(host);
free(oid);
free(val);
aux =(char*)dosnmp(s,p); /*store a possible error */
f->aux = (void*)makebytes((uchar*)aux, strlen(aux));
freepacket(p);
freesession(s);
free(aux);
r->ofcall.count = count;
respond(r, nil);
return;
}
respond(r,"file should be empty, read it first");
return;
}
void
fscreate(Req *r)
{
File *f;
File *nf;
f = r->fid->file;
if(nf = createfile(f, r->ifcall.name, r->fid->uid, r->ifcall.perm, nil)){
r->fid->file = nf;
r->ofcall.qid = nf->qid;
respond(r, nil);
return;
}
respond(r, Ecreate);
return;
}
Srv fs = {
.attach= fsattach,
.read= fsread,
.write= fswrite,
.create= fscreate,
};
Session*
mksession(char *host) {
Session *s;
char *aux;
s = (Session*)emalloc(sizeof(Session));
s->host=strdup(host);
s->port=strdup(DPORT);
aux = ndbget(host,"rocomm");
s->rocomm = (aux != nil )? strdup(aux) : strdup(DROCOMM); free(aux);
aux = ndbget(host,"rwcomm");
s->rwcomm = (aux != nil )? strdup(aux) : strdup(DRWCOMM); free(aux);
aux = ndbget(host,"timeout");
s->timeout = (aux != nil )? atoi(aux) : DTIMEOUT; free(aux);
aux = ndbget(host,"retries");
s->retries = (aux != nil )? atoi(aux) : DRETRIES; free(aux);
error(DEBUG,"mksession(): Host = %s comm = %s timeout = %d",s->host,s->rocomm,s->timeout);
return s;
}
Packet*
mkpacket(char *host, char *ooid, char *val)
{
Packet *p;
char *aux;
char *oid;
int i,j,op;
char *oids[MAX_OID];
p = (Packet*)emalloc(sizeof(Packet));
aux= ndbget(host,"version");
p->ver = (aux != nil )? atoi(aux) : DVERSION; free(aux);
oid = strdup(ooid);
if ( val != nil )
op = 4; // SetRequest type
else
op = ndbgetop(host,oid);
switch(op) {
case 0:
p->pdu.type = GetRequest;
break;
case 1:
p->pdu.type = GetNextRequest;
break;
case 2:
p->pdu.type = WalkRequest;
break;
case 3:
p->pdu.type = GetBulkRequest;
break;
case 4:
p->pdu.type = SetRequest;
break;
default:
error(DEBUG,"mkpacket(): unknown op type %d",op);
break;
}
p->pdu.errstat=0;
p->pdu.erridx=0;
aux = ndbget(host,"nrep");
p->pdu.nrep = (aux != nil )? atoi(aux) : DNREP; free(aux);
aux = ndbget(host,"maxrep");
p->pdu.maxrep = (aux != nil )? atoi(aux) : DNREP; free(aux);
i=getfields(oid, oids, MAX_OID, 0,",");
if ( i == 0 ) {
i=1;
oids[0] = oid;
}
p->pdu.nbind=i;
p->pdu.varbind = (Tuple*)emalloc(sizeof(Tuple)*(p->pdu.nbind));
for(j=0;j<i;j++) {
p->pdu.varbind[j].oid= resolve(oids[j]);
p->pdu.varbind[j].value= (val == nil ) ? nil : strdup(val);
}
free(oid);
return p;
}
/* search ndb file for system configuration */
/* and creates initial fs layout */
int
fsinit(char *user)
{
File *ndir;
File *nf;
Qid q;
Ndbtuple *ht, *pht; /* host tuple and pointer to ht*/
Ndbtuple *ot, *pot; /* oid tuple and pointer to ot*/
char *sys = "sys";
char *oid = "oid";
fs.tree = alloctree(nil, nil, DMDIR|0777, fsdestroyfile);
fstree = fs.tree;
q = fs.tree->root->qid;
/* for each snmp enabled hosts .... */
ht = ndbipinfo(NDB, "snmp", "enabled", &sys, 1);
for(pht = ht; pht; pht = pht->entry) {
ndir = createfile(fs.tree->root,pht->val,user,DMDIR|0777,nil);
error(DEBUG,"fsinit(): NDIR %s QID = %d",pht->val, ndir->qid.path);
/*... fill oid layout of each host */
ot = ndbipinfo(NDB, "sys", pht->val, &oid, 1);
for(pot=ot;pot; pot = pot->entry) {
nf = createfile(ndir,pot->val,user,0666,nil);
error(DEBUG,"fsinit(): NF %s, QID = %d",pot->val, nf->qid.path);
}
ndbfree(ot);
}
ndbfree(ht);
return 1;
}
void
fsdestroyfile(File *f)
{
Bytes *ptr;
ptr = (Bytes*)f->aux;
if(ptr)
freebytes(ptr);
}
void
usage(void)
{
fprint(2, "usage: snmpfs [-D] [-a addr] [-s srvname] [-m mtpt] [-n ndb]\n");
exits("usage");
}
void
threadmain(int argc, char **argv)
{
char *addr = nil;
char *srvname = nil;
char *mtpt = nil;
char *ndbfile = nil;
rfork(RFNOTEG);
ARGBEGIN{
case 'D':
chatty9p++;
DEBUG++;
break;
case 'a':
addr = EARGF(usage());
break;
case 's':
srvname = EARGF(usage());
break;
case 'm':
mtpt = EARGF(usage());
break;
case 'n':
ndbfile= ARGF();
break;
default:
usage();
}ARGEND;
if(argc)
usage();
if(chatty9p)
fprint(2, "ramsrv.nopipe %d srvname %s mtpt %s\n", fs.nopipe, srvname, mtpt);
if(addr == nil && srvname == nil && mtpt == nil)
sysfatal("must specify -a, -s, or -m option");
if(addr)
listensrv(&fs, addr);
/* NDB came from ndbutil.h */
if ( ndbfile == nil )
ndbfile = smprint("/lib/ndb/local");
NDB = ndbopen(ndbfile);
fsinit("gdiaz");
if(srvname || mtpt)
threadpostmountsrv(&fs, srvname, mtpt, MREPL|MCREATE);
exits(0);
}
|