Plan 9 from Bell Labs’s /usr/web/sources/contrib/steve/root/sys/src/cmd/snmpfs/snmpsrv.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


#include <u.h>
#include <libc.h>
#include <fcall.h>
#include <thread.h>
#include <9p.h>
#include <ip.h>
#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);
}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.