#include #include #include #include #include <9p.h> #include #include "a1.h" enum { Cachetime = 3 // secconds a value is cached locally for }; typedef struct Cache Cache; struct Cache { char *oid; // oid to read/write char *data; // data last read int ndata; // length of data long mtime; // tile data last fetched }; extern void loadmap(void); extern char *lookmap(char *); static int Net; static char *User; static int Numeric; static int Debug; static void responderrstr(Req *r) { char e[ERRMAX]; *e = 0; rerrstr(e, sizeof e); respond(r, e); } void mkent(File *f, char *oid) { File *nf; Cache *c; int depth; char *p, *name, *path; c = emalloc9p(sizeof(Cache)); memset(c, 0, sizeof(Cache)); c->oid = estrdup9p(oid); path = oid; depth = 1; incref(f); while(f && (p = strchr(path, '.'))){ *p = '\0'; if((name = lookmap(oid)) == nil) name = path; incref(f); if((nf = walkfile(f, name)) == nil) if((nf = createfile(f, name, User, DMDIR|0755, nil)) == nil) sysfatal("%s - cannot create directory\n", name); decref(f); f = nf; *p = '.'; path = p+1; depth++; } incref(f); if((name = lookmap(oid)) == nil) name = path; if((nf = walkfile(f, name)) == nil){ if((nf = createfile(f, name, User, 0666, c)) == nil) sysfatal("%s - cannot create file\n", name); } decref(f); decref(nf); } static int mktree(File *f, char *top) { Snmp s, r; memset(&s, 0, sizeof(s)); memset(&r, 0, sizeof(r)); s.vers = 0; s.private = 0; s.type = Pgetn; strcpy(s.pdu[0].objid, top); s.pdu[0].type = Anull; s.npdu = 1; r.eindex = 0; while(r.eindex == 0) { if(dosnmp(Net, &s, &r) < 0) return -1; if(Debug) fprint(2, "walk: %s\n", r.pdu[0].objid); if(strncmp(r.pdu[0].objid, top, strlen(top)) != 0) break; if(strcmp(s.pdu[0].objid, top) != 0) mkent(f, s.pdu[0].objid); strcpy(s.pdu[0].objid, r.pdu[0].objid); } return 0; } int flushcache(Cache *c) { Snmp s, r; memset(&s, 0, sizeof(s)); memset(&r, 0, sizeof(r)); s.private = 1; strcpy(s.pdu[0].objid, c->oid); s.type = Pset; s.npdu = 1; c->data[c->ndata-1] = 0; if(Sscan(&s.pdu[0], c->data) < 0) return -1; if(dosnmp(Net, &s, &r) < 0) return -1; return 0; } int fillcache(Cache *c) { Snmp s, r; memset(&s, 0, sizeof(s)); memset(&r, 0, sizeof(r)); s.type = Pget; strcpy(s.pdu[0].objid, c->oid); s.pdu[1].type = Anull; s.npdu = 1; if(dosnmp(Net, &s, &r) < 0) return -1; free(c->data); c->data = smprint("%A", &r); c->ndata = strlen(c->data); c->mtime = time(nil); return 0; } void fsread(Req *r) { Cache *c; vlong offset; long count; c = r->fid->file->aux; offset = r->ifcall.offset; count = r->ifcall.count; r->ofcall.count = 0; if(time(nil) - c->mtime > Cachetime) if(fillcache(c) < 0){ responderrstr(r); return; } if(offset >= c->ndata){ respond(r, nil); return; } if(offset+count >= c->ndata) count = c->ndata - offset; memmove(r->ofcall.data, c->data+offset, count); r->ofcall.count = count; respond(r, nil); } void fswrite(Req *r) { void *v; Cache *c; vlong offset; long count; c = r->fid->file->aux; offset = r->ifcall.offset; count = r->ifcall.count; if(offset+count >= c->ndata){ v = realloc(c->data, offset+count); if(v == nil){ responderrstr(r); return; } c->data = v; c->ndata = offset+count; r->fid->file->length = c->ndata; } memmove(c->data+offset, r->ifcall.data, count); r->ofcall.count = count; respond(r, nil); } void fsdestroyfid(Fid *fid) { Cache *c; if(!fid->file || !fid->file->aux) return; c = fid->file->aux; if((fid->omode &OWRITE) == OWRITE && c->data && c->ndata) if(flushcache(c) < 0) fprint(2, "%s set failed - %r\n", argv0); free(c->data); c->data = nil; c->ndata = 0; } Srv fs = { .read= fsread, .write= fswrite, .destroyfid= fsdestroyfid }; void usage(void) { fprint(2, "usage: %s [-n] [-s srvname] [-m mtpt] [-M snmp.oidmap] [-r root-oid] host\n", argv0); exits("usage"); } void main(int argc, char **argv) { char *top, *srv, *mnt; quotefmtinstall(); fmtinstall('A', Sfmt); fmtinstall('V', eipfmt); if((User = getuser()) == nil) sysfatal("$user not set\n"); srv = nil; mnt = "/n/snmp"; top = "1.3.6.1.2"; ARGBEGIN{ case 'd': Debug++; break; case 'D': chatty9p++; break; case 's': srv = EARGF(usage()); break; case 'm': mnt = EARGF(usage()); break; case 'n': Numeric++; break; case 'r': top = EARGF(usage()); break; default: usage(); }ARGEND; if(argc != 1) usage(); if(! Numeric) loadmap(); if((Net = dial(netmkaddr(argv[0], "udp", "snmp"), 0, 0, 0)) < 0) sysfatal("dial: %s: %r", argv[0]); fs.tree = alloctree(User, "snmp", DMDIR|0777, nil); if(mktree(fs.tree->root, top) < 0) sysfatal("traversal failed %r"); postmountsrv(&fs, srv, mnt, MREPL); exits(0); }