9fans - fans of the OS Plan 9 from Bell Labs
 help / color / mirror / Atom feed
From: erik quanstrom <quanstro@quanstro.net>
To: 9fans@9fans.net
Subject: Re: [9fans] ndb database checker: ndb/vrfy
Date: Thu, 28 Oct 2010 20:21:33 -0400	[thread overview]
Message-ID: <6123ab808334949061e338f78be021b9@plug.quanstro.net> (raw)
In-Reply-To: <88f0178840512f08eb010c723b458fb5@plug.quanstro.net>

[-- Attachment #1: Type: text/plain, Size: 74 bytes --]

i have no idea why the yacc source wasn't included.
here it is.

- erik

[-- Attachment #2: vrfy.y --]
[-- Type: text/plain, Size: 9646 bytes --]

%{
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <ip.h>

typedef struct T T;
struct T{
	T	*next;
	T	*down;
	char	*s;
	char	*t;
	int	line;
	char	*file;
};
#pragma	varargck	type	"T"	T*

Biobuf	in;
char	*file;
char	*ipmask;
int	line;
int	factotum;
T	*dblist;
T	*ll0;
T	**ll;
T	*tab0;
T	**tab;
int	fd;

extern	int	yyparse(void);
extern	void	yyerror(char*, ...);

char*
nonil(char *s)
{
	if(s == nil)
		return "";
	return s;
}

int
Tfmt(Fmt *f)
{
	int sharp;
	T *t, *t0;

	t0 = va_arg(f->args, T*);
	sharp = f->flags & FmtSharp;
	for(; t0 != nil; t0 = t0->down){
		if((t = t0) != nil)
			fmtprint(f, "%s=%s", t->s, nonil(t->t));
		while(t = t->next)
			fmtprint(f, " %s=%s", t->s, nonil(t->t));
		if(sharp == 0)
			break;
		if(t0->down != nil)
			fmtprint(f, "\n");
	}
	return 0;
}

T*
newt(char *s, char *t)
{
	T *x;
	x = malloc(sizeof *x);
	if(x == nil)
		sysfatal("malloc: %r");
	memset(x, 0, sizeof *x);
	x->s = s;
	x->t = t;
	x->line = line;
	x->file = file;
	return x;
}

static char *nakedtab[] = {
	"database",
	"soa",
	"trampok",
};

int
cknaked(char *s)
{
	int i;

	for(i = 0; i < nelem(nakedtab); i++)
		if(strcmp(nakedtab[i], s) == 0)
			return 0;
	yyerror("naked token %s", s);
	return -1;
}

%}

%union{
	T	*t;
	char	*s;
}

%type	<s>	rhs
%token	<s>	S
%start	db
%%
db	:
	| db '\n'
	| db tuples '\n'
	;
tuples:	tuple {
		*tab = ll0;
		tab = &ll0->down;

		ll0 = nil;
		ll = &ll0;
	}
	| tuple tuples
	;
tuple:	S rhs {
		T *x;

		if($2 == nil)
			cknaked($1);
		x = *ll = newt($1, $2);
		ll = &x->next;
	}
	;
rhs:		{ $$ = nil; }
	| '=' S	{ $$ = $2; }
	;
%%
void
freet(T *t)
{
	T *n, *d;

	for(; t != nil; t = d){
		d = t->down;
		for(; t != nil; t = n){
			n = t->next;
			free(t->s);
			free(t->t);
			free(t);
		}
	}
}

void
yyinit(char *f)
{
	file = f;
	line = 1;
	fd = open(file, OREAD);
	if(fd == -1)
		sysfatal("open: %r");
	if(Binit(&in, fd, OREAD) == -1)
		sysfatal("Binit: %r");

	freet(tab0);
	ll0 = nil;
	tab0 = nil;

	ll = &ll0;
	tab = &tab0;
}

void
yyerror(char *fmt, ...)
{
	char buf[256], *p, *e;
	va_list arg;
	static int nerrors;

	e = buf + sizeof buf;
	va_start(arg, fmt);
	p = seprint(buf, e, "%s:%d ", file, line);
	p = vseprint(p, e, fmt, arg);
	p = seprint(p, e, "\n");
	va_end(arg);
	write(2, buf, p - buf);
	nerrors++;
	if(nerrors > 5)
		sysfatal("too many errors");
}

void
tokerror(T *t, char *fmt, ...)
{
	char buf[256], *p, *e;
	va_list arg;
	static int nerrors;

	e = buf + sizeof buf;
	va_start(arg, fmt);
	p = seprint(buf, e, "%s:%d ", t->file, t->line);
	p = vseprint(p, e, fmt, arg);
	p = seprint(p, e, "\n");
	va_end(arg);
	write(2, buf, p - buf);
}

enum{
	Base,
	Seeneq,
};

int
yylex(void)
{
	char buf[128], *s;
	int c, i;
	Rune r;
	static int state = Base;
	static int quoting;

	if(quoting != 0){
		yyerror("bad quote");
		quoting = 0;
	}
	i = 0;
again:
	c = Bgetrune(&in);
	if(c == Beof)
		return 0;
	r = c;
	switch(r){
	case '
':
	case '\0':
		yyerror("bad character %#ux\n", r);
		goto again;
	case '#':
		for(;;){
			switch(Bgetrune(&in)){
			case Beof:
				yyerror("EOF in comment");
				return 0;
			case '\n':
				Bungetrune(&in);
				goto again;
			}
		}
	case '\n':
		if(state != Base){
			Bungetrune(&in);
			goto tok;
		}
		line++;
		switch(Bgetrune(&in)){
		case Beof:
			return '\n';
		case ' ':
		case '\t':
			goto again;
		}
		Bungetrune(&in);
		return '\n';
	case ' ':
	case '\t':
		if(state != Base){
			Bungetrune(&in);
			goto tok;
		}
		goto again;
	case '=':
		if(state != Base)
			break;
		state = Seeneq;
		return '=';
	default:
		break;
	}

	/* token */
	if(r == '"'){
		quoting = 1;
		c = Bgetrune(&in);
		r = c;
	}
	for(;;){
		if(i >= sizeof buf - UTFmax - 1){
			yyerror("token too long");
			break;
		}
		i += runetochar(buf + i, &r);
		c = Bgetrune(&in);
		if(c == Beof)
			break;
		r = c;
		switch(r){
		case '
':
		case '\0':
			yyerror("bad character %#ux\n", r);
			goto tok;
		case ' ':
		case '\t':
			if(quoting)
				break;
		case '\n':
			Bungetrune(&in);
			goto tok;
		case '=':
			if(state == Base){
				Bungetrune(&in);
				goto tok;
			}
			break;
		case '\'':
			if(factotum)
				goto quote;
			break;
		case '"':
			if(!factotum)
			if(quoting == 1){
				quoting = 0;
				goto tok;
			}
			break;
		case '#':
			yyerror("# in token");
		}
	}
tok:
	if(state == Base && i == 0)
		yyerror("name is nil");
	if(state == Seeneq)
		state = Base;
	buf[i] = 0;
	s = strdup(buf);
	if(s == nil)
		sysfatal("malloc: %r");
	yylval.s = s;
	return S;

quote:
	quoting = 1;
	for(;;){
		/* extra space for ' if quoting fails.  ndb is wierd */
		if(i >= sizeof buf - UTFmax - 1 - 1){
			yyerror("token too long");
			break;
		}
		i += runetochar(buf + i, &r);

		c = Bgetrune(&in);
		if(c == Beof)
			break;
		r = c;
		switch(r){
		case '\n':
			/* wierd!  this is actually what ndb does */
			Bungetrune(&in);
			memmove(buf, buf + 1, i);
			buf[0] = '\'';
			goto tok;
		case '\'':
			if(Bgetrune(&in) == '\'')
				break;
			Bungetrune(&in);
			goto tok;
		}
	}
	goto tok;
}

void
go(char *file)
{
	yyinit(file);
	yyparse();
	close(fd);
}

int
parseipxmask(uchar *ip, uchar *m, char *s0)
{
	uchar tmp[IPaddrlen];
	char *msk, s[4*8+4];

	snprint(s, sizeof s, "%s", s0);
	msk = strchr(s, '/');
	if(msk == nil){
		if(parseipmask(m, "/120") == -1)
			return -1;
	}else{
		if(parseipmask(m, msk) == -1)
			return -1;
		*msk = 0;
	}
	if(parseip(tmp, s) == -1)
		return -1;
	maskip(tmp, m, ip);
	return 0;
}

void
checkip(void)
{
	uchar m0[IPaddrlen], mask[IPaddrlen], ip1[IPaddrlen], m1[IPaddrlen];
	int havemsk;
	T *d, *t;

	havemsk = 0;
	if(ipmask != nil)
	if(parseipxmask(m0, mask, ipmask) == 0)
		havemsk = 1;
	for(d = tab0; d != nil; d = d->down)
		for(t = d; t != nil; t = t->next){
			if(strcmp(t->s, "ip") != 0)
				continue;
			if(parseip(ip1, t->t) == -1){
				tokerror(t, "bad ip %T", d);
				continue;
			}
			if(havemsk == 0)
				continue;
			maskip(ip1, mask, m1);
			if(ipcmp(m0, m1) != 0)
				tokerror(t, "wrong file: %I", t, ip1);
		}
}

typedef struct {
	uchar	ea[IPaddrlen];
	T	*d[10];
	int	nd;
} B;

static	B	*btab;
static	uint	nbtab;
static	uint	nbtaba;

int
addrcmp(uchar *a, uchar *b)
{
	int d;

	d = memcmp(a, b, IPaddrlen);
	if(d > 0)
		return 1;
	if(d < 0)
		return -1;
	return 0;
}

static B*
bsearch(uchar *ea)
{
	B *tab, *m;
	int n, i, d;

	tab = btab;
	for(n = nbtab; n > 0;){
		i = n/2;
		m = tab+i;
		d = addrcmp(m->ea, ea);
		if(d == 0)
			return m;
		if(d < 0){
			tab += i+1;
			n -= i+1;
		}else
			n = i;
	}
	return nil;
}

void
binsert(B *m, T *d, uchar *ea)
{
	char buf[256], *p, *e;
	int i;
	T **x;

	if(m == nil){
		if(nbtab + 1 >= nbtaba){
			nbtaba = nbtab + 1 << 1;
			btab = realloc(btab, sizeof btab[0]*nbtaba);
			if(btab == nil)
				sysfatal("realloc: %r");
		}
		for(m=btab+nbtab; m > btab && addrcmp(m[-1].ea, ea) > 0; m--)
			m[0] = m[-1];
		m->nd = 0;
		memcpy(m->ea, ea, IPaddrlen);
		nbtab++;
	}
	m->d[m->nd++] = d;
	if(m->nd > 1){
		x = m->d;
		p = buf;
		e = buf + sizeof buf;
		for(i = 0; i < m->nd - 1; i++)
			p = seprint(p, e, "%s:%d ", x[i]->file, x[i]->line);
		tokerror(d, "duplicate ea %E %s", m->ea, buf);
	}
}

void
prdb(void)
{
	int i;

	for(i = 0; i < nbtab; i++)
		print("%E\n", btab[i].ea);
}

void
checkether(void)
{
	uchar ea[IPaddrlen];
	T *d, *t;

	for(d = tab0; d != nil; d = d->down)
		for(t = d; t != nil; t = t->next){
			if(strcmp(t->s, "ether") != 0)
				continue;
			if(strspn(t->t, "0123456789abcdef") != 12)
				tokerror(t, "bad ea %s", t->t);
			parseether(ea, t->t);
			binsert(bsearch(ea), d, ea);
		}
}

static char *soaattr[] = {
	"refresh",
	"ttl",
	"ns",
	"mx",
	"pref",
	"mbox",
};

static char *cattrtab[] = {
	"clog",			/* only in consoledb */
	"console",
	"dev",
	"gid",
	"group",
	"speed",
	"uid",
	"openondemand",
};

static char *xattrtab[] = {
	"auth",
	"authdom",
	"bootf",
	"cname",
	"console",
	"database",
	"dns",
	"dnsdomain",
	"dom",
	"el",
	"ether",
	"file",
	"fs",
	"gw",
	"imap",
	"ip",
	"ipgw",
	"ipmask",
	"ipnet",
	"mb",
	"mbox",
	"mx",
	"ns",
	"pref",
	"proto",
	"refresh",
	"smtp",
	"soa",
	"sys",
	"trampok",
	"ttl",
	"txtrr",

	"pri",
	"srv",
	"weight",

	"gre",
	"il",
	"ipv4proto",
	"port",
	"protocol",
	"restricted",
	"tcp",
	"udp",

	"uid",
	"hostid"
};

char	**attrtab	= xattrtab;
int	nattrtab	= nelem(xattrtab);

void
checkattrs(void)
{
	int i;
	T *d, *t;

	for(d = tab0; d != nil; d = d->down)
		for(t = d; t != nil; t = t->next){
			for(i = 0; i < nattrtab; i++)
				if(strcmp(t->s, attrtab[i]) == 0)
					break;
			if(i == nattrtab)
				tokerror(t, "unknown attr %s", t->s);
		}
}

void
usage(void)
{
	fprint(2, "usage: ndb/vrfy [-m ip/mask]  [file ...]\n");
	exits("usage");
}

void
main(int argc, char **argv)
{
	int i;

	fmtinstall('T', Tfmt);
	fmtinstall('I', eipfmt);
	fmtinstall('M', eipfmt);
	fmtinstall('E', eipfmt);
	ARGBEGIN{
	case 'c':
		attrtab = cattrtab;
		nattrtab = nelem(cattrtab);
		break;
	case 'm':
		ipmask = EARGF(usage());
		break;
	default:
		usage();
	}ARGEND
	for(i = 0; i < argc; i++){
		go(argv[i]);
		checkip();
		checkether();
		checkattrs();
	}

	exits("");
}

      reply	other threads:[~2010-10-29  0:21 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-10-28 23:14 erik quanstrom
2010-10-29  0:21 ` erik quanstrom [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=6123ab808334949061e338f78be021b9@plug.quanstro.net \
    --to=quanstro@quanstro.net \
    --cc=9fans@9fans.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).