From mboxrd@z Thu Jan 1 00:00:00 1970 From: erik quanstrom Date: Thu, 28 Oct 2010 20:21:33 -0400 To: 9fans@9fans.net Message-ID: <6123ab808334949061e338f78be021b9@plug.quanstro.net> In-Reply-To: <88f0178840512f08eb010c723b458fb5@plug.quanstro.net> References: <88f0178840512f08eb010c723b458fb5@plug.quanstro.net> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="upas-uumwhdomqirmqpiwequiwzxlpk" Subject: Re: [9fans] ndb database checker: ndb/vrfy Topicbox-Message-UUID: 70ec7986-ead6-11e9-9d60-3106f5b1d025 This is a multi-part message in MIME format. --upas-uumwhdomqirmqpiwequiwzxlpk Content-Disposition: inline Content-Type: text/plain; charset="US-ASCII" Content-Transfer-Encoding: 7bit i have no idea why the yacc source wasn't included. here it is. - erik --upas-uumwhdomqirmqpiwequiwzxlpk Content-Disposition: attachment; filename=vrfy.y Content-Type: text/plain; charset="US-ASCII" Content-Transfer-Encoding: 7bit %{ #include #include #include #include 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 rhs %token 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(""); } --upas-uumwhdomqirmqpiwequiwzxlpk--