commit d957951b75df08a9bb0293e3e13ff87759afbb92 from: rsc date: Fri Feb 11 19:41:16 2005 UTC new commit - ad017cfbf5530cfc3ae2fafd723cdade2a4405f6 commit + d957951b75df08a9bb0293e3e13ff87759afbb92 blob - /dev/null blob + 9bbcfd319aa8c43487c22878124b4bb720ac1d82 (mode 644) --- /dev/null +++ src/cmd/ndb/mkfile @@ -0,0 +1,13 @@ +<$PLAN9/src/mkhdr + +TARG=\ + ndbmkdb\ + ndbquery\ + ndbmkhash\ + ndbmkhosts\ + ndbipquery\ + +LIB=$PLAN9/lib/libndb.a + +<$PLAN9/src/mkmany + blob - /dev/null blob + c2859dcab5a8e596e7ea245b23ac17eb16eea883 (mode 644) --- /dev/null +++ src/cmd/ndb/ndbipquery.c @@ -0,0 +1,54 @@ +#include +#include +#include +#include +#include + +/* + * search the database for matches + */ + +void +usage(void) +{ + fprint(2, "usage: ipquery attr value rattribute\n"); + exits("usage"); +} + +void +search(Ndb *db, char *attr, char *val, char **rattr, int nrattr) +{ + Ndbtuple *t; + + t = ndbipinfo(db, attr, val, rattr, nrattr); + for(; t; t = t->entry) + print("%s=%s ", t->attr, t->val); + print("\n"); + ndbfree(t); +} + +void +main(int argc, char **argv) +{ + Ndb *db; + char *dbfile = 0; + + ARGBEGIN{ + case 'f': + dbfile = ARGF(); + break; + }ARGEND; + + if(argc < 3) + usage(); + + db = ndbopen(dbfile); + if(db == 0){ + fprint(2, "no db files\n"); + exits("no db"); + } + search(db, argv[0], argv[1], argv+2, argc-2); + ndbclose(db); + + exits(0); +} blob - /dev/null blob + e19685a63b99e3d96464190c290559409598791e (mode 644) --- /dev/null +++ src/cmd/ndb/ndbmkdb.c @@ -0,0 +1,203 @@ +#include +#include +#include +#include + +Biobuf in; +Biobuf out; + +enum +{ + Empty, + Sys, + Dk, + Ip, + Domain, +}; + +int +iscomment(char *name) +{ + return *name == '#'; +} + +/* + * is this a fully specified datakit name? + */ +int +isdk(char *name) +{ + int slash; + + slash = 0; + for(; *name; name++){ + if(isalnum(*name)) + continue; + if(*name == '/'){ + slash = 1; + continue; + } + return 0; + } + return slash; +} + +/* + * Is this an internet domain name? + */ +int +isdomain(char *name) +{ + int dot = 0; + int alpha = 0; + + for(; *name; name++){ + if(isalpha(*name) || *name == '-'){ + alpha = 1; + continue; + } + if(*name == '.'){ + dot = 1; + continue; + } + if(isdigit(*name)) + continue; + return 0; + } + return dot && alpha; +} + +/* + * is this an ip address? + */ +int +isip(char *name) +{ + int dot = 0; + + for(; *name; name++){ + if(*name == '.'){ + dot = 1; + continue; + } + if(isdigit(*name)) + continue; + return 0; + } + return dot; +} + +char tup[64][64]; +int ttype[64]; +int ntup; + +void +tprint(void) +{ + int i, tab; + char *p; + + tab = 0; + for(i = 0; i < ntup; i++){ + if(ttype[i] == Sys){ + Bprint(&out, "sys = %s\n", tup[i]); + tab = 1; + ttype[i] = Empty; + break; + } + } + for(i = 0; i < ntup; i++){ + if(ttype[i] == Empty) + continue; + if(tab) + Bprint(&out, "\t"); + tab = 1; + + switch(ttype[i]){ + case Domain: + Bprint(&out, "dom=%s\n", tup[i]); + break; + case Ip: + Bprint(&out, "ip=%s\n", tup[i]); + break; + case Dk: + p = strrchr(tup[i], '/'); + if(p){ + p++; + if((*p == 'C' || *p == 'R') + && strncmp(tup[i], "nj/astro/", p-tup[i]) == 0) + Bprint(&out, "flavor=console "); + } + Bprint(&out, "dk=%s\n", tup[i]); + break; + case Sys: + Bprint(&out, "sys=%s\n", tup[i]); + break; + } + } +} + +#define NFIELDS 64 + +/* + * make a database file from a merged uucp/inet database + */ +void +main(void) +{ + int n, i, j; + char *l; + char *fields[NFIELDS]; + int ftype[NFIELDS]; + int same, match; + + Binit(&in, 0, OREAD); + Binit(&out, 1, OWRITE); + ntup = 0; + while(l = Brdline(&in, '\n')){ + l[Blinelen(&in)-1] = 0; + n = getfields(l, fields, NFIELDS, 1, " \t"); + same = 0; + for(i = 0; i < n; i++){ + if(iscomment(fields[i])){ + n = i; + break; + } + if(isdomain(fields[i])){ + ftype[i] = Domain; + for(j = 0; j < ntup; j++) + if(ttype[j] == Domain && strcmp(fields[i], tup[j]) == 0){ + same = 1; + ftype[i] = Empty; + break; + } + } else if(isip(fields[i])) + ftype[i] = Ip; + else if(isdk(fields[i])) + ftype[i] = Dk; + else + ftype[i] = Sys; + } + if(!same && ntup){ + tprint(); + ntup = 0; + } + for(i = 0; i < n; i++){ + match = 0; + for(j = 0; j < ntup; j++){ + if(ftype[i] == ttype[j] && strcmp(fields[i], tup[j]) == 0){ + match = 1; + break; + } + } + if(!match){ + ttype[ntup] = ftype[i]; + strcpy(tup[ntup], fields[i]); + ntup++; + } + } + } + if(ntup) + tprint(); + exits(0); +} blob - /dev/null blob + 507bd7c7809b9dae8f87b92697855ff84637dd07 (mode 644) --- /dev/null +++ src/cmd/ndb/ndbmkhash.c @@ -0,0 +1,155 @@ +#include +#include +#include +#include + +/* + * make the hash table completely in memory and then write as a file + */ + +uchar *ht; +ulong hlen; +Ndb *db; +ulong nextchain; + +char* +syserr(void) +{ + static char buf[ERRMAX]; + + errstr(buf, sizeof buf); + return buf; +} + +void +enter(char *val, ulong dboff) +{ + ulong h; + uchar *last; + ulong ptr; + + h = ndbhash(val, hlen); + h *= NDBPLEN; + last = &ht[h]; + ptr = NDBGETP(last); + if(ptr == NDBNAP){ + NDBPUTP(dboff, last); + return; + } + + if(ptr & NDBCHAIN){ + /* walk the chain to the last entry */ + for(;;){ + ptr &= ~NDBCHAIN; + last = &ht[ptr+NDBPLEN]; + ptr = NDBGETP(last); + if(ptr == NDBNAP){ + NDBPUTP(dboff, last); + return; + } + if(!(ptr & NDBCHAIN)){ + NDBPUTP(nextchain|NDBCHAIN, last); + break; + } + } + } else + NDBPUTP(nextchain|NDBCHAIN, last); + + /* add a chained entry */ + NDBPUTP(ptr, &ht[nextchain]); + NDBPUTP(dboff, &ht[nextchain + NDBPLEN]); + nextchain += 2*NDBPLEN; +} + +uchar nbuf[16*1024]; + +void +main(int argc, char **argv) +{ + Ndbtuple *t, *nt; + int n; + Dir *d; + uchar buf[8]; + char file[128]; + int fd; + ulong off; + uchar *p; + + if(argc != 3){ + fprint(2, "mkhash: usage file attribute\n"); + exits("usage"); + } + db = ndbopen(argv[1]); + if(db == 0){ + fprint(2, "mkhash: can't open %s\n", argv[1]); + exits(syserr()); + } + + /* try a bigger than normal buffer */ + Binits(&db->b, Bfildes(&db->b), OREAD, nbuf, sizeof(nbuf)); + + /* count entries to calculate hash size */ + n = 0; + + while(nt = ndbparse(db)){ + for(t = nt; t; t = t->entry){ + if(strcmp(t->attr, argv[2]) == 0) + n++; + } + ndbfree(nt); + } + + /* allocate an array large enough for worst case */ + hlen = 2*n+1; + n = hlen*NDBPLEN + hlen*2*NDBPLEN; + ht = mallocz(n, 1); + if(ht == 0){ + fprint(2, "mkhash: not enough memory\n"); + exits(syserr()); + } + for(p = ht; p < &ht[n]; p += NDBPLEN) + NDBPUTP(NDBNAP, p); + nextchain = hlen*NDBPLEN; + + /* create the in core hash table */ + Bseek(&db->b, 0, 0); + off = 0; + while(nt = ndbparse(db)){ + for(t = nt; t; t = t->entry){ + if(strcmp(t->attr, argv[2]) == 0) + enter(t->val, off); + } + ndbfree(nt); + off = Boffset(&db->b); + } + + /* create the hash file */ + snprint(file, sizeof(file), "%s.%s", argv[1], argv[2]); + fd = create(file, ORDWR, 0664); + if(fd < 0){ + fprint(2, "mkhash: can't create %s\n", file); + exits(syserr()); + } + NDBPUTUL(db->mtime, buf); + NDBPUTUL(hlen, buf+NDBULLEN); + if(write(fd, buf, NDBHLEN) != NDBHLEN){ + fprint(2, "mkhash: writing %s\n", file); + exits(syserr()); + } + if(write(fd, ht, nextchain) != nextchain){ + fprint(2, "mkhash: writing %s\n", file); + exits(syserr()); + } + close(fd); + + /* make sure file didn't change while we were making the hash */ + d = dirstat(argv[1]); + if(d == nil || d->qid.path != db->qid.path + || d->qid.vers != db->qid.vers){ + fprint(2, "mkhash: %s changed underfoot\n", argv[1]); + remove(file); + exits("changed"); + } + + exits(0); +} blob - /dev/null blob + 46f9f978f814f2caa04b147edcdf431e21dd9a88 (mode 644) --- /dev/null +++ src/cmd/ndb/ndbmkhosts.c @@ -0,0 +1,233 @@ +#include +#include +#include +#include +#include + +typedef struct x +{ + Ndbtuple *t; + Ndbtuple *it; + Ndbtuple *nt; +} X; + +X x[4096]; +int nx; +char *domname = "research.att.com"; +int domnamlen; + +char* +upper(char *x) +{ + char *p; + int c; + + for(p = x; c = *p; p++) + *p = toupper(c); + return x; +} + +void +printArecord(int fd, X *p) +{ + Ndbtuple *nt; + char *c; + char *dom = 0; + char *curdom = 0; + int i, cdlen = 0; + int mxweight = 0; + + if(p->nt) { + return; + } + for(nt=p->t; nt; nt = nt->entry) { + /* we are only going to handle things in the specified domain */ + c = strchr(nt->val, '.'); + if (c==0 || strcmp(++c, domname)!=0) + continue; + i = c - nt->val - 1; + if(strcmp(nt->attr, "dom") == 0) { + curdom = nt->val; + cdlen = i; + if (dom == 0) { + dom = curdom; + fprint(fd, "%-.*s%.*s IN A %s\n", i, nt->val, 15-i, " ", p->it->val); + } else + fprint(fd, "%-.*s%.*s IN CNAME %s.\n", i, nt->val, 15-i, " ", dom); + } else if(strcmp(nt->attr, "mx") == 0) { + if (curdom != 0) + fprint(fd, "%-.*s%.*s MX %d %s.\n", cdlen, curdom, 15-cdlen, " ", mxweight++, nt->val); + } + } +} + +void +printentry(int fd, X *p) +{ + Ndbtuple *nt; + + if(p->nt) + return; + fprint(fd, "%s ", p->it->val); + for(nt = p->t; nt; nt = nt->entry) + if(strcmp(nt->attr, "dom") == 0) + fprint(fd, " %s", nt->val); + for(nt = p->t; nt; nt = nt->entry) + if(strcmp(nt->attr, "sys") == 0) + fprint(fd, " %s", nt->val); + fprint(fd, "\n"); +} + +void +printsys(int fd, X *p) +{ + Ndbtuple *nt; + + for(nt = p->t; nt; nt = nt->entry) + if(strcmp(nt->attr, "dom") == 0) + fprint(fd, "%s\n", nt->val); +} + +void +printtxt(int fd, X *p) +{ + int i; + Ndbtuple *nt; + + if(p->nt){ + for(;;){ + i = strlen(p->it->val); + if(strcmp(p->it->val+i-2, ".0") == 0) + p->it->val[i-2] = 0; + else + break; + } + fprint(fd, "\nNET : %s : %s\n", p->it->val, upper(p->nt->val)); + return; + } + fprint(fd, "HOST : %s :", p->it->val); + i = 0; + for(nt = p->t; nt; nt = nt->entry) + if(strcmp(nt->attr, "dom") == 0){ + if(i++ == 0) + fprint(fd, " %s", upper(nt->val)); + else + fprint(fd, ", %s", upper(nt->val)); + } + fprint(fd, "\n"); +} + +void +parse(char *file) +{ + int i; + Ndb *db; + Ndbtuple *t, *nt, *tt, *ipnett; + char *p; + + db = ndbopen(file); + if(db == 0) + exits("no database"); + while(t = ndbparse(db)){ + for(nt = t; nt; nt = nt->entry){ + if(strcmp(nt->attr, "ip") == 0) + break; + if(strcmp(nt->attr, "flavor") == 0 + && strcmp(nt->val, "console") == 0) + return; + } + if(nt == 0){ + ndbfree(t); + continue; + } + + /* dump anything not on our nets */ + ipnett = 0; + for(tt = t; tt; tt = tt->entry){ + if(strcmp(tt->attr, "ipnet") == 0){ + ipnett = tt; + break; + } + if(strcmp(tt->attr, "dom") == 0){ + i = strlen(tt->val); + p = tt->val+i-domnamlen; + if(p >= tt->val && strcmp(p, domname) == 0) + break; + } + } + if(tt == 0){ + ndbfree(t); + continue; + } + + for(; nt; nt = nt->entry){ + if(strcmp(nt->attr, "ip") != 0) + continue; + x[nx].it = nt; + x[nx].nt = ipnett; + x[nx++].t = t; + } + } +} + +void +main(int argc, char *argv[]) +{ + int i, fd; + char fn[128]; + + if (argc>1) + domname = argv[1]; + domnamlen = strlen(domname); + if(argc > 2){ + for(i = 2; i < argc; i++) + parse(argv[i]); + } else { + parse(unsharp("#9/ndb/local")); + parse(unsharp("#9/ndb/friends")); + } + +// sprint(fn, "/lib/ndb/hosts.%-.21s", domname); +// fd = create(fn, OWRITE, 0664); +// if(fd < 0){ +// fprint(2, "can't create %s: %r\n", fn); +// exits("boom"); +// } +// for(i = 0; i < nx; i++) +// printentry(fd, &x[i]); +// close(fd); +// + + sprint(fn, "/lib/ndb/db.%-.24s", domname); + fd = create(fn, OWRITE, 0664); + if(fd < 0){ + fprint(2, "can't create %s: %r\n", fn); + exits("boom"); + } + fprint(fd, "; This file is generated automatically, do not edit!\n"); + for(i = 0; i < nx; i++) + printArecord(fd, &x[i]); + close(fd); + + sprint(fn, "/lib/ndb/equiv.%-.21s", domname); + fd = create(fn, OWRITE, 0664); + if(fd < 0){ + fprint(2, "can't create %s: %r\n", fn); + exits("boom"); + } + for(i = 0; i < nx; i++) + printsys(fd, &x[i]); + close(fd); + + sprint(fn, "/lib/ndb/txt.%-.23s", domname); + fd = create(fn, OWRITE, 0664); + if(fd < 0){ + fprint(2, "can't create %s: %r\n", fn); + exits("boom"); + } + for(i = 0; i < nx; i++) + printtxt(fd, &x[i]); + close(fd); + + exits(0); +} blob - /dev/null blob + 65bc04720bd103d653764dfa648aff0e1808d0b3 (mode 644) --- /dev/null +++ src/cmd/ndb/ndbquery.c @@ -0,0 +1,81 @@ +#include +#include +#include +#include + +/* + * search the database for matches + */ +void +usage(void) +{ + fprint(2, "usage: query attr value [returned attribute]\n"); + exits("usage"); +} + +void +search(Ndb *db, char *attr, char *val, char *rattr) +{ + Ndbs s; + Ndbtuple *t; + Ndbtuple *nt; + char *p; + + if(rattr){ + p = ndbgetvalue(db, &s, attr, val, rattr, nil); + if(p){ + print("%s\n", p); + free(p); + } + return; + } + + t = ndbsearch(db, &s, attr, val); + while(t){ + for(nt = t; nt; nt = nt->entry) + print("%s=%s ", nt->attr, nt->val); + print("\n"); + ndbfree(t); + t = ndbsnext(&s, attr, val); + } +} + +void +main(int argc, char **argv) +{ + char *rattr = 0; + Ndb *db; + char *dbfile = 0; + int reps = 1; + + ARGBEGIN{ + case 'f': + dbfile = ARGF(); + break; + }ARGEND; + + switch(argc){ + case 4: + reps = atoi(argv[3]); + /* fall through */ + case 3: + rattr = argv[2]; + break; + case 2: + rattr = 0; + break; + default: + usage(); + } + + db = ndbopen(dbfile); + if(db == 0){ + fprint(2, "no db files\n"); + exits("no db"); + } + while(reps--) + search(db, argv[0], argv[1], rattr); + ndbclose(db); + + exits(0); +} blob - /dev/null blob + 22705adecbbaf2d112081b8297999e562969b40b (mode 644) --- /dev/null +++ src/libndb/csgetval.c @@ -0,0 +1,107 @@ +#include +#include +#include +#include +#include + +/* + * search for a tuple that has the given 'attr=val' and also 'rattr=x'. + * copy 'x' into 'buf' and return the whole tuple. + * + * return 0 if not found. + */ +char* +csgetvalue(char *netroot, char *attr, char *val, char *rattr, Ndbtuple **pp) +{ + Ndbtuple *t, *first, *last; + int n, linefound; + char line[1024]; + int fd; + int oops = 0; + char *rv; + + if(pp) + *pp = nil; + rv = nil; + + if(netroot) + snprint(line, sizeof(line), "%s/cs", netroot); + else + strcpy(line, "/net/cs"); + fd = open(line, ORDWR); + if(fd < 0) + return 0; + seek(fd, 0, 0); + snprint(line, sizeof(line), "!%s=%s %s=*", attr, val, rattr); + if(write(fd, line, strlen(line)) < 0){ + close(fd); + return 0; + } + seek(fd, 0, 0); + + first = last = 0; + linefound = 0; + for(;;){ + n = read(fd, line, sizeof(line)-2); + if(n <= 0) + break; + line[n] = '\n'; + line[n+1] = 0; + + t = _ndbparseline(line); + if(t == 0) + continue; + if(first) + last->entry = t; + else + first = t; + last = t; + + while(last->entry) + last = last->entry; + + for(; t; t = t->entry){ + if(linefound == 0){ + if(strcmp(rattr, t->attr) == 0){ + linefound = 1; + rv = strdup(t->val); + } + } + } + } + close(fd); + + if(oops){ + werrstr("buffer too short"); + ndbfree(first); + return nil; + } + + if(pp){ + setmalloctag(first, getcallerpc(&netroot)); + *pp = first; + } else + ndbfree(first); + + return rv; +} + +Ndbtuple* +csgetval(char *netroot, char *attr, char *val, char *rattr, char *buf) +{ + Ndbtuple *t; + char *p; + + p = csgetvalue(netroot, attr, val, rattr, &t); + if(p == nil){ + if(buf != nil) + *buf = 0; + } else { + if(buf != nil){ + strncpy(buf, p, Ndbvlen-1); + buf[Ndbvlen-1] = 0; + } + free(p); + } + return t; +} blob - /dev/null blob + 76f3d8e0950f8ef77da2517fb47f02e56acfc8f3 (mode 644) --- /dev/null +++ src/libndb/csipinfo.c @@ -0,0 +1,68 @@ +#include +#include +#include +#include +#include + +/* + * look up the ip attributes 'list' for an entry that has the + * given 'attr=val' and a 'ip=' tuples. + * + * return nil if not found. + */ +Ndbtuple* +csipinfo(char *netroot, char *attr, char *val, char **list, int n) +{ + Ndbtuple *t, *first, *last; + int i; + char line[1024]; + int fd; + char *p, *e; + + if(netroot) + snprint(line, sizeof(line), "%s/cs", netroot); + else + strcpy(line, "/net/cs"); + fd = open(line, ORDWR); + if(fd < 0) + return 0; + seek(fd, 0, 0); + e = line + sizeof(line); + p = seprint(line, e, "!ipinfo %s=%s", attr, val); + for(i = 0; i < n; i++){ + if(*list == nil) + break; + p = seprint(p, e, " %s", *list++); + } + + if(write(fd, line, strlen(line)) < 0){ + close(fd); + return 0; + } + seek(fd, 0, 0); + + first = last = 0; + for(;;){ + n = read(fd, line, sizeof(line)-2); + if(n <= 0) + break; + line[n] = '\n'; + line[n+1] = 0; + + t = _ndbparseline(line); + if(t == 0) + continue; + if(first) + last->entry = t; + else + first = t; + last = t; + + while(last->entry) + last = last->entry; + } + close(fd); + + setmalloctag(first, getcallerpc(&netroot)); + return first; +} blob - /dev/null blob + 4cf8735ad3ae38e94c85028d2cbcbf04dd138e84 (mode 644) --- /dev/null +++ src/libndb/dnsquery.c @@ -0,0 +1,156 @@ +#include +#include +#include +#include +#include + +static void nstrcpy(char*, char*, int); +static void mkptrname(char*, char*, int); +static Ndbtuple *doquery(int, char *dn, char *type); + +/* + * search for a tuple that has the given 'attr=val' and also 'rattr=x'. + * copy 'x' into 'buf' and return the whole tuple. + * + * return 0 if not found. + */ +Ndbtuple* +dnsquery(char *net, char *val, char *type) +{ + char rip[128]; + char *p; + Ndbtuple *t; + int fd; + + /* if the address is V4 or V6 null address, give up early vwhoi*/ + if(strcmp(val, "::") == 0 || strcmp(val, "0.0.0.0") == 0) + return nil; + + if(net == nil) + net = "/net"; + snprint(rip, sizeof(rip), "%s/dns", net); + fd = open(rip, ORDWR); + if(fd < 0){ + if(strcmp(net, "/net") == 0) + snprint(rip, sizeof(rip), "/srv/dns"); + else { + snprint(rip, sizeof(rip), "/srv/dns%s", net); + p = strrchr(rip, '/'); + *p = '_'; + } + fd = open(rip, ORDWR); + if(fd < 0) + return nil; + if(mount(fd, -1, net, MBEFORE, "") < 0){ + close(fd); + return nil; + } + /* fd is now closed */ + snprint(rip, sizeof(rip), "%s/dns", net); + fd = open(rip, ORDWR); + if(fd < 0) + return nil; + } + + /* zero out the error string */ + werrstr(""); + + /* if this is a reverse lookup, first lookup the domain name */ + if(strcmp(type, "ptr") == 0){ + mkptrname(val, rip, sizeof rip); + t = doquery(fd, rip, "ptr"); + } else + t = doquery(fd, val, type); + + close(fd); + return t; +} + +/* + * convert address into a reverse lookup address + */ +static void +mkptrname(char *ip, char *rip, int rlen) +{ + char buf[128]; + char *p, *np; + int len; + + if(strstr(ip, "in-addr.arpa") || strstr(ip, "IN-ADDR.ARPA")){ + nstrcpy(rip, ip, rlen); + return; + } + + nstrcpy(buf, ip, sizeof buf); + for(p = buf; *p; p++) + ; + *p = '.'; + np = rip; + len = 0; + while(p >= buf){ + len++; + p--; + if(*p == '.'){ + memmove(np, p+1, len); + np += len; + len = 0; + } + } + memmove(np, p+1, len); + np += len; + strcpy(np, "in-addr.arpa"); +} + +static void +nstrcpy(char *to, char *from, int len) +{ + strncpy(to, from, len); + to[len-1] = 0; +} + +static Ndbtuple* +doquery(int fd, char *dn, char *type) +{ + char buf[1024]; + int n; + Ndbtuple *t, *first, *last; + + seek(fd, 0, 0); + snprint(buf, sizeof(buf), "!%s %s", dn, type); + if(write(fd, buf, strlen(buf)) < 0) + return nil; + + seek(fd, 0, 0); + + first = last = nil; + + for(;;){ + n = read(fd, buf, sizeof(buf)-2); + if(n <= 0) + break; + if(buf[n-1] != '\n') + buf[n++] = '\n'; /* ndbparsline needs a trailing new line */ + buf[n] = 0; + + /* check for the error condition */ + if(buf[0] == '!'){ + werrstr("%s", buf+1); + return nil; + } + + t = _ndbparseline(buf); + if(t != nil){ + if(first) + last->entry = t; + else + first = t; + last = t; + + while(last->entry) + last = last->entry; + } + } + + setmalloctag(first, getcallerpc(&fd)); + return first; +} blob - /dev/null blob + d23d5ee09e5048016ad664cb4abbcce2665197d5 (mode 644) --- /dev/null +++ src/libndb/ipattr.c @@ -0,0 +1,46 @@ +#include +#include + +/* + * return ndb attribute type of an ip name + */ +char* +ipattr(char *name) +{ + char *p, c; + int dot = 0; + int alpha = 0; + int colon = 0; + int hex = 0; + + for(p = name; *p; p++){ + c = *p; + if(isdigit(c)) + continue; + if(isxdigit(c)) + hex = 1; + else if(isalpha(c) || c == '-') + alpha = 1; + else if(c == '.') + dot = 1; + else if(c == ':') + colon = 1; + else + return "sys"; + } + + if(alpha){ + if(dot) + return "dom"; + else + return "sys"; + } + + if(colon) + return "ip"; /* ip v6 */ + + if(dot && !hex) + return "ip"; + else + return "sys"; +} blob - /dev/null blob + a49cd5e01e43fdfbaa7eacd2143905f8d9c9cbc5 (mode 644) --- /dev/null +++ src/libndb/mkfile @@ -0,0 +1,32 @@ +<$PLAN9/src/mkhdr + +LIB=libndb.a +OFILES=\ +# csgetval.$O\ +# csipinfo.$O\ +# dnsquery.$O\ + ipattr.$O\ + ndbaux.$O\ + ndbcache.$O\ + ndbcat.$O\ + ndbconcatenate.$O\ + ndbdiscard.$O\ + ndbfree.$O\ + ndbgetipaddr.$O\ + ndbgetval.$O\ + ndbhash.$O\ + ndbipinfo.$O\ + ndblookval.$O\ + ndbopen.$O\ + ndbparse.$O\ + ndbreorder.$O\ + ndbsubstitute.$O\ + +HFILES=\ + $PLAN9/include/ndb.h\ + ndbhf.h + +<$PLAN9/src/mksyslib + +$O.out: testipinfo.$O + $LD $prereq blob - /dev/null blob + 94246fc6a97f1da8ba6c0752ce6afa1fea0b664a (mode 644) --- /dev/null +++ src/libndb/ndbaux.c @@ -0,0 +1,94 @@ +#include +#include +#include +#include +#include +#include "ndbhf.h" + + +/* + * parse a single tuple + */ +char* +_ndbparsetuple(char *cp, Ndbtuple **tp) +{ + char *p; + int len; + Ndbtuple *t; + + /* a '#' starts a comment lasting till new line */ + EATWHITE(cp); + if(*cp == '#' || *cp == '\n') + return 0; + + t = ndbnew(nil, nil); + setmalloctag(t, getcallerpc(&cp)); + *tp = t; + + /* parse attribute */ + p = cp; + while(*cp != '=' && !ISWHITE(*cp) && *cp != '\n') + cp++; + len = cp - p; + if(len >= Ndbalen) + len = Ndbalen-1; + strncpy(t->attr, p, len); + + /* parse value */ + EATWHITE(cp); + if(*cp == '='){ + cp++; + if(*cp == '"'){ + p = ++cp; + while(*cp != '\n' && *cp != '"') + cp++; + len = cp - p; + if(*cp == '"') + cp++; + } else if(*cp == '#'){ + len = 0; + } else { + p = cp; + while(!ISWHITE(*cp) && *cp != '\n') + cp++; + len = cp - p; + } + ndbsetval(t, p, len); + } + + return cp; +} + +/* + * parse all tuples in a line. we assume that the + * line ends in a '\n'. + * + * the tuples are linked as a list using ->entry and + * as a ring using ->line. + */ +Ndbtuple* +_ndbparseline(char *cp) +{ + Ndbtuple *t; + Ndbtuple *first, *last; + + first = last = 0; + while(*cp != '#' && *cp != '\n'){ + t = 0; + cp = _ndbparsetuple(cp, &t); + if(cp == 0) + break; + if(first){ + last->line = t; + last->entry = t; + } else + first = t; + last = t; + t->line = 0; + t->entry = 0; + } + if(first) + last->line = first; + setmalloctag(first, getcallerpc(&cp)); + return first; +} blob - /dev/null blob + 701d63ebc87c3bed690a5e117d7f261ca00365a2 (mode 644) --- /dev/null +++ src/libndb/ndbcache.c @@ -0,0 +1,144 @@ +#include +#include +#include +#include + +struct Ndbcache +{ + Ndbcache *next; + char *attr; + char *val; + Ndbs s; + Ndbtuple *t; +}; + +enum +{ + Maxcached= 128, +}; + +static void +ndbcachefree(Ndbcache *c) +{ + free(c->val); + free(c->attr); + if(c->t) + ndbfree(c->t); + free(c); +} + +static Ndbtuple* +ndbcopy(Ndb *db, Ndbtuple *from_t, Ndbs *from_s, Ndbs *to_s) +{ + Ndbtuple *first, *to_t, *last, *line; + int newline; + + *to_s = *from_s; + to_s->t = nil; + to_s->db = db; + + newline = 1; + last = nil; + first = nil; + line = nil; + for(; from_t != nil; from_t = from_t->entry){ + to_t = ndbnew(from_t->attr, from_t->val); + + /* have s point to matching tuple */ + if(from_s->t == from_t) + to_s->t = to_t; + + if(newline) + line = to_t; + else + last->line = to_t; + + if(last != nil) + last->entry = to_t; + else { + first = to_t; + line = to_t; + } + to_t->entry = nil; + to_t->line = line; + last = to_t; + newline = from_t->line != from_t->entry; + } + return first; +} + +/* + * if found, move to front + */ +int +_ndbcachesearch(Ndb *db, Ndbs *s, char *attr, char *val, Ndbtuple **t) +{ + Ndbcache *c, **l; + + *t = nil; + c = nil; + for(l = &db->cache; *l != nil; l = &(*l)->next){ + c = *l; + if(strcmp(c->attr, attr) == 0 && strcmp(c->val, val) == 0) + break; + } + if(*l == nil) + return -1; + + /* move to front */ + *l = c->next; + c->next = db->cache; + db->cache = c; + + *t = ndbcopy(db, c->t, &c->s, s); + return 0; +} + +Ndbtuple* +_ndbcacheadd(Ndb *db, Ndbs *s, char *attr, char *val, Ndbtuple *t) +{ + Ndbcache *c, **l; + + c = mallocz(sizeof *c, 1); + if(c == nil) + return nil; + c->attr = strdup(attr); + if(c->attr == nil) + goto err; + c->val = strdup(val); + if(c->val == nil) + goto err; + c->t = ndbcopy(db, t, s, &c->s); + if(c->t == nil && t != nil) + goto err; + + /* add to front */ + c->next = db->cache; + db->cache = c; + + /* trim list */ + if(db->ncache < Maxcached){ + db->ncache++; + return t; + } + for(l = &db->cache; (*l)->next; l = &(*l)->next) + ; + c = *l; + *l = nil; +err: + ndbcachefree(c); + return t; +} + +void +_ndbcacheflush(Ndb *db) +{ + Ndbcache *c; + + while(db->cache != nil){ + c = db->cache; + db->cache = c->next; + ndbcachefree(c); + } + db->ncache = 0; +} blob - /dev/null blob + 61ef5e47b117bcc646e1e266b7b523a1731b72ec (mode 644) --- /dev/null +++ src/libndb/ndbcat.c @@ -0,0 +1,18 @@ +#include +#include +#include +#include +#include + +Ndb* +ndbcat(Ndb *a, Ndb *b) +{ + Ndb *db = a; + + if(a == nil) + return b; + while(a->next != nil) + a = a->next; + a->next = b; + return db; +} blob - /dev/null blob + 3725f181b3ae33cdedcb842ea39564dd8aa0ac2b (mode 644) --- /dev/null +++ src/libndb/ndbconcatenate.c @@ -0,0 +1,18 @@ +#include +#include +#include +#include + +/* concatenate two tuples */ +Ndbtuple* +ndbconcatenate(Ndbtuple *a, Ndbtuple *b) +{ + Ndbtuple *t; + + if(a == nil) + return b; + for(t = a; t->entry; t = t->entry) + ; + t->entry = b; + return a; +} blob - /dev/null blob + 9b2fc0c98fc02c3271eb576050048d75563221bf (mode 644) --- /dev/null +++ src/libndb/ndbdiscard.c @@ -0,0 +1,29 @@ +#include +#include +#include +#include + +/* remove a from t and free it */ +Ndbtuple* +ndbdiscard(Ndbtuple *t, Ndbtuple *a) +{ + Ndbtuple *nt; + + /* unchain a */ + for(nt = t; nt != nil; nt = nt->entry){ + if(nt->line == a) + nt->line = a->line; + if(nt->entry == a) + nt->entry = a->entry; + } + + /* a may be start of chain */ + if(t == a) + t = a->entry; + + /* free a */ + a->entry = nil; + ndbfree(a); + + return t; +} blob - /dev/null blob + 647bff03c0c17f7b5bbfcfea492c058f567eae07 (mode 644) --- /dev/null +++ src/libndb/ndbfree.c @@ -0,0 +1,65 @@ +#include +#include +#include +#include +#include +#include "ndbhf.h" + +/* + * free a parsed entry + */ +void +ndbfree(Ndbtuple *t) +{ + Ndbtuple *tn; + + for(; t; t = tn){ + tn = t->entry; + if(t->val != t->valbuf){ + free(t->val); + } + free(t); + } +} + +/* + * set a value in a tuple + */ +void +ndbsetval(Ndbtuple *t, char *val, int n) +{ + if(n < Ndbvlen){ + if(t->val != t->valbuf){ + free(t->val); + t->val = t->valbuf; + } + } else { + if(t->val != t->valbuf) + t->val = realloc(t->val, n+1); + else + t->val = malloc(n+1); + if(t->val == nil) + sysfatal("ndbsetval %r"); + } + strncpy(t->val, val, n); + t->val[n] = 0; +} + +/* + * allocate a tuple + */ +Ndbtuple* +ndbnew(char *attr, char *val) +{ + Ndbtuple *t; + + t = mallocz(sizeof(*t), 1); + if(t == nil) + sysfatal("ndbnew %r"); + if(attr != nil) + strncpy(t->attr, attr, sizeof(t->attr)-1); + t->val = t->valbuf; + if(val != nil) + ndbsetval(t, val, strlen(val)); + return t; +} blob - /dev/null blob + f076cd9c80e4648c564f579afad8c620d0a22a0e (mode 644) --- /dev/null +++ src/libndb/ndbgetipaddr.c @@ -0,0 +1,47 @@ +#include +#include +#include +#include +#include + +/* return list of ip addresses for a name */ +Ndbtuple* +ndbgetipaddr(Ndb *db, char *val) +{ + char *attr, *p; + Ndbtuple *it, *first, *last, *next; + Ndbs s; + + /* already an IP address? */ + attr = ipattr(val); + if(strcmp(attr, "ip") == 0){ + it = ndbnew("ip", val); + return it; + } + + /* look it up */ + p = ndbgetvalue(db, &s, attr, val, "ip", &it); + if(p == nil) + return nil; + free(p); + + /* remove the non-ip entries */ + first = last = nil; + for(; it; it = next){ + next = it->entry; + if(strcmp(it->attr, "ip") == 0){ + if(first == nil) + first = it; + else + last->entry = it; + it->entry = nil; + it->line = first; + last = it; + } else { + it->entry = nil; + ndbfree(it); + } + } + + return first; +} blob - /dev/null blob + 2c66b2065b36fb9106a1a2ab41f307c8cfdd3423 (mode 644) --- /dev/null +++ src/libndb/ndbgetval.c @@ -0,0 +1,75 @@ +#include +#include +#include +#include "ndb.h" + +/* + * search for a tuple that has the given 'attr=val' and also 'rattr=x'. + * copy 'x' into 'buf' and return the whole tuple. + * + * return 0 if not found. + */ +char* +ndbgetvalue(Ndb *db, Ndbs *s, char *attr, char *val, char *rattr, Ndbtuple **pp) +{ + Ndbtuple *t, *nt; + char *rv; + Ndbs temps; + + if(s == nil) + s = &temps; + if(pp) + *pp = nil; + t = ndbsearch(db, s, attr, val); + while(t){ + /* first look on same line (closer binding) */ + nt = s->t; + for(;;){ + if(strcmp(rattr, nt->attr) == 0){ + rv = strdup(nt->val); + if(pp != nil) + *pp = t; + else + ndbfree(t); + return rv; + } + nt = nt->line; + if(nt == s->t) + break; + } + /* search whole tuple */ + for(nt = t; nt; nt = nt->entry){ + if(strcmp(rattr, nt->attr) == 0){ + rv = strdup(nt->val); + if(pp != nil) + *pp = t; + else + ndbfree(t); + return rv; + } + } + ndbfree(t); + t = ndbsnext(s, attr, val); + } + return nil; +} + +Ndbtuple* +ndbgetval(Ndb *db, Ndbs *s, char *attr, char *val, char *rattr, char *buf) +{ + Ndbtuple *t; + char *p; + + p = ndbgetvalue(db, s, attr, val, rattr, &t); + if(p == nil){ + if(buf != nil) + *buf = 0; + } else { + if(buf != nil){ + strncpy(buf, p, Ndbvlen-1); + buf[Ndbvlen-1] = 0; + } + free(p); + } + return t; +} blob - /dev/null blob + a6965cdbc8f4b19a0da46e368e6317daf82b3f34 (mode 644) --- /dev/null +++ src/libndb/ndbhash.c @@ -0,0 +1,247 @@ +#include +#include +#include +#include "ndb.h" +#include "ndbhf.h" + +enum { + Dptr, /* pointer to database file */ + Cptr, /* pointer to first chain entry */ + Cptr1, /* pointer to second chain entry */ +}; + +/* + * generate a hash value for an ascii string (val) given + * a hash table length (hlen) + */ +ulong +ndbhash(char *vp, int hlen) +{ + ulong hash; + uchar *val = (uchar*)vp; + + for(hash = 0; *val; val++) + hash = (hash*13) + *val-'a'; + return hash % hlen; +} + +/* + * read a hash file with buffering + */ +static uchar* +hfread(Ndbhf *hf, long off, int len) +{ + if(off < hf->off || off + len > hf->off + hf->len){ + if(seek(hf->fd, off, 0) < 0 + || (hf->len = read(hf->fd, hf->buf, sizeof(hf->buf))) < len){ + hf->off = -1; + return 0; + } + hf->off = off; + } + return &hf->buf[off-hf->off]; +} + +/* + * return an opened hash file if one exists for the + * attribute and if it is current vis-a-vis the data + * base file + */ +static Ndbhf* +hfopen(Ndb *db, char *attr) +{ + Ndbhf *hf; + char buf[sizeof(hf->attr)+sizeof(db->file)+2]; + uchar *p; + Dir *d; + + /* try opening the data base if it's closed */ + if(db->mtime==0 && ndbreopen(db) < 0) + return 0; + + /* if the database has changed, throw out hash files and reopen db */ + if((d = dirfstat(Bfildes(&db->b))) == nil || db->qid.path != d->qid.path + || db->qid.vers != d->qid.vers){ + if(ndbreopen(db) < 0){ + free(d); + return 0; + } + } + free(d); + + if(db->nohash) + return 0; + + /* see if a hash file exists for this attribute */ + for(hf = db->hf; hf; hf= hf->next){ + if(strcmp(hf->attr, attr) == 0) + return hf; + } + + /* create a new one */ + hf = (Ndbhf*)malloc(sizeof(Ndbhf)); + if(hf == 0) + return 0; + memset(hf, 0, sizeof(Ndbhf)); + + /* compare it to the database file */ + strncpy(hf->attr, attr, sizeof(hf->attr)-1); + sprint(buf, "%s.%s", db->file, hf->attr); + hf->fd = open(buf, OREAD); + if(hf->fd >= 0){ + hf->len = 0; + hf->off = 0; + p = hfread(hf, 0, 2*NDBULLEN); + if(p){ + hf->dbmtime = NDBGETUL(p); + hf->hlen = NDBGETUL(p+NDBULLEN); + if(hf->dbmtime == db->mtime){ + hf->next = db->hf; + db->hf = hf; + return hf; + } + } + close(hf->fd); + } + + free(hf); + return 0; +} + +/* + * return the first matching entry + */ +Ndbtuple* +ndbsearch(Ndb *db, Ndbs *s, char *attr, char *val) +{ + uchar *p; + Ndbtuple *t; + Ndbhf *hf; + + hf = hfopen(db, attr); + + memset(s, 0, sizeof(*s)); + if(_ndbcachesearch(db, s, attr, val, &t) == 0){ + /* found in cache */ + if(t != nil) + return t; /* answer from this file */ + if(db->next == nil) + return nil; + return ndbsearch(db->next, s, attr, val); + } + + s->db = db; + s->hf = hf; + if(s->hf){ + s->ptr = ndbhash(val, s->hf->hlen)*NDBPLEN; + p = hfread(s->hf, s->ptr+NDBHLEN, NDBPLEN); + if(p == 0) + return _ndbcacheadd(db, s, attr, val, nil); + s->ptr = NDBGETP(p); + s->type = Cptr1; + } else if(db->length > 128*1024){ + print("Missing or out of date hash file %s.%s.\n", db->file, attr); + /* syslog(0, "ndb", "Missing or out of date hash file %s.%s.", db->file, attr); */ + + /* advance search to next db file */ + s->ptr = NDBNAP; + _ndbcacheadd(db, s, attr, val, nil); + if(db->next == 0) + return nil; + return ndbsearch(db->next, s, attr, val); + } else { + s->ptr = 0; + s->type = Dptr; + } + t = ndbsnext(s, attr, val); + _ndbcacheadd(db, s, attr, val, (t != nil && s->db == db)?t:nil); + setmalloctag(t, getcallerpc(&db)); + return t; +} + +static Ndbtuple* +match(Ndbtuple *t, char *attr, char *val) +{ + Ndbtuple *nt; + + for(nt = t; nt; nt = nt->entry) + if(strcmp(attr, nt->attr) == 0 + && strcmp(val, nt->val) == 0) + return nt; + return 0; +} + +/* + * return the next matching entry in the hash chain + */ +Ndbtuple* +ndbsnext(Ndbs *s, char *attr, char *val) +{ + Ndbtuple *t; + Ndb *db; + uchar *p; + + db = s->db; + if(s->ptr == NDBNAP) + goto nextfile; + + for(;;){ + if(s->type == Dptr){ + if(Bseek(&db->b, s->ptr, 0) < 0) + break; + t = ndbparse(db); + s->ptr = Boffset(&db->b); + if(t == 0) + break; + if(s->t = match(t, attr, val)) + return t; + ndbfree(t); + } else if(s->type == Cptr){ + if(Bseek(&db->b, s->ptr, 0) < 0) + break; + s->ptr = s->ptr1; + s->type = Cptr1; + t = ndbparse(db); + if(t == 0) + break; + if(s->t = match(t, attr, val)) + return t; + ndbfree(t); + } else if(s->type == Cptr1){ + if(s->ptr & NDBCHAIN){ /* hash chain continuation */ + s->ptr &= ~NDBCHAIN; + p = hfread(s->hf, s->ptr+NDBHLEN, 2*NDBPLEN); + if(p == 0) + break; + s->ptr = NDBGETP(p); + s->ptr1 = NDBGETP(p+NDBPLEN); + s->type = Cptr; + } else { /* end of hash chain */ + if(Bseek(&db->b, s->ptr, 0) < 0) + break; + s->ptr = NDBNAP; + t = ndbparse(db); + if(t == 0) + break; + if(s->t = match(t, attr, val)){ + setmalloctag(t, getcallerpc(&s)); + return t; + } + ndbfree(t); + break; + } + } + } + +nextfile: + + /* nothing left to search? */ + s->ptr = NDBNAP; + if(db->next == 0) + return 0; + + /* advance search to next db file */ + t = ndbsearch(db->next, s, attr, val); + setmalloctag(t, getcallerpc(&s)); + return t; +} blob - /dev/null blob + 4505d13bda5ce55c85fc25dc9c7ba6258e0e477b (mode 644) --- /dev/null +++ src/libndb/ndbhf.h @@ -0,0 +1,27 @@ +/* a hash file */ +struct Ndbhf +{ + Ndbhf *next; + + int fd; + ulong dbmtime; /* mtime of data base */ + int hlen; /* length (in entries) of hash table */ + char attr[Ndbalen]; /* attribute hashed */ + + uchar buf[256]; /* hash file buffer */ + long off; /* offset of first byte of buffer */ + int len; /* length of valid data in buffer */ +}; + +char* _ndbparsetuple(char*, Ndbtuple**); +Ndbtuple* _ndbparseline(char*); + +#define ISWHITE(x) ((x) == ' ' || (x) == '\t' || (x) == '\r') +#define EATWHITE(x) while(ISWHITE(*(x)))(x)++ + +extern Ndbtuple *_ndbtfree; + +/* caches */ +void _ndbcacheflush(Ndb *db); +int _ndbcachesearch(Ndb *db, Ndbs *s, char *attr, char *val, Ndbtuple **t); +Ndbtuple* _ndbcacheadd(Ndb *db, Ndbs *s, char *attr, char *val, Ndbtuple *t); blob - /dev/null blob + 5cdc24b5f580b00785c6a4f210bab5bd8700fcda (mode 644) --- /dev/null +++ src/libndb/ndbipinfo.c @@ -0,0 +1,242 @@ +#include +#include +#include +#include +#include + +enum +{ + Ffound= 1<<0, + Fignore=1<<1, + Faddr= 1<<2, +}; + +static Ndbtuple* filter(Ndb *db, Ndbtuple *t, Ndbtuple *f); +static Ndbtuple* mkfilter(int argc, char **argv); +static int filtercomplete(Ndbtuple *f); +static Ndbtuple* toipaddr(Ndb *db, Ndbtuple *t); +static int prefixlen(uchar *ip); +static Ndbtuple* subnet(Ndb *db, uchar *net, Ndbtuple *f, int prefix); + +/* make a filter to be used in filter */ +static Ndbtuple* +mkfilter(int argc, char **argv) +{ + Ndbtuple *t, *first, *last; + char *p; + + last = first = nil; + while(argc-- > 0){ + t = ndbnew(0, 0); + if(first) + last->entry = t; + else + first = t; + last = t; + p = *argv++; + if(*p == '@'){ + t->ptr |= Faddr; + p++; + } + strncpy(t->attr, p, sizeof(t->attr)-1); + } + return first; +} + +/* return true if every pair of filter has been used */ +static int +filtercomplete(Ndbtuple *f) +{ + for(; f; f = f->entry) + if((f->ptr & Fignore) == 0) + return 0; + return 1; +} + +/* set the attribute of all entries in a tuple */ +static Ndbtuple* +setattr(Ndbtuple *t, char *attr) +{ + Ndbtuple *nt; + + for(nt = t; nt; nt = nt->entry) + strcpy(nt->attr, attr); + return t; +} + +/* + * return only the attr/value pairs in t maching the filter, f. + * others are freed. line structure is preserved. + */ +static Ndbtuple* +filter(Ndb *db, Ndbtuple *t, Ndbtuple *f) +{ + Ndbtuple *nt, *nf, *next; + + /* filter out what we don't want */ + for(nt = t; nt; nt = next){ + next = nt->entry; + + /* look through filter */ + for(nf = f; nf != nil; nf = nf->entry){ + if(!(nf->ptr&Fignore) && strcmp(nt->attr, nf->attr) == 0) + break; + } + if(nf == nil){ + /* remove nt from t */ + t = ndbdiscard(t, nt); + } else { + if(nf->ptr & Faddr) + t = ndbsubstitute(t, nt, setattr(ndbgetipaddr(db, nt->val), nt->attr)); + nf->ptr |= Ffound; + } + } + + /* remember filter etnries that matched */ + for(nf = f; nf != nil; nf = nf->entry) + if(nf->ptr & Ffound) + nf->ptr = (nf->ptr & ~Ffound) | Fignore; + + return t; +} + +static int +prefixlen(uchar *ip) +{ + int y, i; + + for(y = IPaddrlen-1; y >= 0; y--) + for(i = 8; i > 0; i--) + if(ip[y] & (1<<(8-i))) + return y*8 + i; + return 0; +} + +/* + * look through a containing subset + */ +static Ndbtuple* +subnet(Ndb *db, uchar *net, Ndbtuple *f, int prefix) +{ + Ndbs s; + Ndbtuple *t, *nt, *xt; + char netstr[128]; + uchar mask[IPaddrlen]; + int masklen; + + t = nil; + sprint(netstr, "%I", net); + nt = ndbsearch(db, &s, "ip", netstr); + while(nt != nil){ + xt = ndbfindattr(nt, nt, "ipnet"); + if(xt){ + xt = ndbfindattr(nt, nt, "ipmask"); + if(xt) + parseipmask(mask, xt->val); + else + ipmove(mask, defmask(net)); + masklen = prefixlen(mask); + if(masklen <= prefix) + t = ndbconcatenate(t, filter(db, nt, f)); + } else + ndbfree(nt); + nt = ndbsnext(&s, "ip", netstr); + } + return t; +} + +/* + * fill in all the requested attributes for a system. + * if the system's entry doesn't have all required, + * walk through successively more inclusive networks + * for inherited attributes. + */ +Ndbtuple* +ndbipinfo(Ndb *db, char *attr, char *val, char **alist, int n) +{ + Ndbtuple *t, *nt, *f; + Ndbs s; + char *ipstr; + uchar net[IPaddrlen]; + uchar ip[IPaddrlen]; + int prefix, smallestprefix; + int force; + + /* just in case */ + fmtinstall('I', eipfmt); + fmtinstall('M', eipfmt); + + /* get needed attributes */ + f = mkfilter(n, alist); + + /* + * first look for a matching entry with an ip address + */ + t = nil; + ipstr = ndbgetvalue(db, &s, attr, val, "ip", &nt); + if(ipstr == nil){ + /* none found, make one up */ + if(strcmp(attr, "ip") != 0) + return nil; + t = ndbnew("ip", val); + t->line = t; + t->entry = nil; + parseip(net, val); + } else { + /* found one */ + while(nt != nil){ + nt = ndbreorder(nt, s.t); + t = ndbconcatenate(t, nt); + nt = ndbsnext(&s, attr, val); + } + parseip(net, ipstr); + free(ipstr); + } + ipmove(ip, net); + t = filter(db, t, f); + + /* + * now go through subnets to fill in any missing attributes + */ + if(isv4(net)){ + prefix = 127; + smallestprefix = 100; + force = 0; + } else { + /* in v6, the last 8 bytes have no structure (we hope) */ + prefix = 64; + smallestprefix = 2; + memset(net+8, 0, 8); + force = 1; + } + + /* + * to find a containing network, keep turning off + * the lower bit and look for a network with + * that address and a shorter mask. tedius but + * complete, we may need to find a trick to speed this up. + */ + for(; prefix >= smallestprefix; prefix--){ + if(filtercomplete(f)) + break; + if(!force && (net[prefix/8] & (1<<(7-(prefix%8)))) == 0) + continue; + force = 0; + net[prefix/8] &= ~(1<<(7-(prefix%8))); + t = ndbconcatenate(t, subnet(db, net, f, prefix)); + } + + /* + * if there's an unfulfilled ipmask, make one up + */ + nt = ndbfindattr(f, f, "ipmask"); + if(nt && !(nt->ptr & Fignore)){ + char x[64]; + + snprint(x, sizeof(x), "%M", defmask(ip)); + t = ndbconcatenate(t, ndbnew("ipmask", x)); + } + + ndbfree(f); + return t; +} blob - /dev/null blob + 012bc4b2b81db242b24a3fa130ed84a6e2d57b4a (mode 644) --- /dev/null +++ src/libndb/ndblookval.c @@ -0,0 +1,44 @@ +#include +#include +#include +#include +#include + +/* + * Look for a pair with the given attribute. look first on the same line, + * then in the whole entry. + */ +Ndbtuple* +ndbfindattr(Ndbtuple *entry, Ndbtuple *line, char *attr) +{ + Ndbtuple *nt; + + /* first look on same line (closer binding) */ + for(nt = line; nt;){ + if(strcmp(attr, nt->attr) == 0) + return nt; + nt = nt->line; + if(nt == line) + break; + } + + /* search whole tuple */ + for(nt = entry; nt; nt = nt->entry) + if(strcmp(attr, nt->attr) == 0) + return nt; + + return nil; +} + +Ndbtuple* +ndblookval(Ndbtuple *entry, Ndbtuple *line, char *attr, char *to) +{ + Ndbtuple *t; + + t = ndbfindattr(entry, line, attr); + if(t != nil){ + strncpy(to, t->val, Ndbvlen-1); + to[Ndbvlen-1] = 0; + } + return t; +} blob - /dev/null blob + d504702ee99ebd6b6ed6f1ea3ef35c0b8891092b (mode 644) --- /dev/null +++ src/libndb/ndbopen.c @@ -0,0 +1,174 @@ +#include +#include +#include +#include +#include +#include "ndbhf.h" + +static Ndb* doopen(char*); +static void hffree(Ndb*); + +static char *deffile = "/lib/ndb/local"; + +/* + * the database entry in 'file' indicates the list of files + * that makeup the database. Open each one and search in + * the same order. + */ +Ndb* +ndbopen(char *file) +{ + Ndb *db, *first, *last; + Ndbs s; + Ndbtuple *t, *nt; + + if(file == 0) + file = deffile; + db = doopen(file); + if(db == 0) + return 0; + first = last = db; + t = ndbsearch(db, &s, "database", ""); + Bseek(&db->b, 0, 0); + if(t == 0) + return db; + for(nt = t; nt; nt = nt->entry){ + if(strcmp(nt->attr, "file") != 0) + continue; + if(strcmp(nt->val, file) == 0){ + /* default file can be reordered in the list */ + if(first->next == 0) + continue; + if(strcmp(first->file, file) == 0){ + db = first; + first = first->next; + last->next = db; + db->next = 0; + last = db; + } + continue; + } + db = doopen(nt->val); + if(db == 0) + continue; + last->next = db; + last = db; + } + ndbfree(t); + return first; +} + +/* + * open a single file + */ +static Ndb* +doopen(char *file) +{ + Ndb *db; + + db = (Ndb*)malloc(sizeof(Ndb)); + if(db == 0) + return 0; + memset(db, 0, sizeof(Ndb)); + strncpy(db->file, file, sizeof(db->file)-1); + + if(ndbreopen(db) < 0){ + free(db); + return 0; + } + + return db; +} + +/* + * dump any cached information, forget the hash tables, and reopen a single file + */ +int +ndbreopen(Ndb *db) +{ + int fd; + Dir *d; + + /* forget what we know about the open files */ + if(db->mtime){ + _ndbcacheflush(db); + hffree(db); + close(Bfildes(&db->b)); + Bterm(&db->b); + db->mtime = 0; + } + + /* try the open again */ + fd = open(db->file, OREAD); + if(fd < 0) + return -1; + d = dirfstat(fd); + if(d == nil){ + close(fd); + return -1; + } + + db->qid = d->qid; + db->mtime = d->mtime; + db->length = d->length; + Binit(&db->b, fd, OREAD); + free(d); + return 0; +} + +/* + * close the database files + */ +void +ndbclose(Ndb *db) +{ + Ndb *nextdb; + + for(; db; db = nextdb){ + nextdb = db->next; + _ndbcacheflush(db); + hffree(db); + close(Bfildes(&db->b)); + Bterm(&db->b); + free(db); + } +} + +/* + * free the hash files belonging to a db + */ +static void +hffree(Ndb *db) +{ + Ndbhf *hf, *next; + + for(hf = db->hf; hf; hf = next){ + next = hf->next; + close(hf->fd); + free(hf); + } + db->hf = 0; +} + +/* + * return true if any part of the database has changed + */ +int +ndbchanged(Ndb *db) +{ + Ndb *ndb; + Dir *d; + + for(ndb = db; ndb != nil; ndb = ndb->next){ + d = dirfstat(Bfildes(&db->b)); + if(d == nil) + continue; + if(ndb->qid.path != d->qid.path + || ndb->qid.vers != d->qid.vers){ + free(d); + return 1; + } + free(d); + } + return 0; +} blob - /dev/null blob + 86a108dce3598c71fb005032fb21228c4166c52b (mode 644) --- /dev/null +++ src/libndb/ndbparse.c @@ -0,0 +1,57 @@ +#include +#include +#include +#include +#include +#include "ndbhf.h" + +/* + * Parse a data base entry. Entries may span multiple + * lines. An entry starts on a left margin. All subsequent + * lines must be indented by white space. An entry consists + * of tuples of the forms: + * attribute-name + * attribute-name=value + * attribute-name="value with white space" + * + * The parsing returns a 2-dimensional structure. The first + * dimension joins all tuples. All tuples on the same line + * form a ring along the second dimension. + */ + +/* + * parse the next entry in the file + */ +Ndbtuple* +ndbparse(Ndb *db) +{ + char *line; + Ndbtuple *t; + Ndbtuple *first, *last; + int len; + + first = last = 0; + for(;;){ + if((line = Brdline(&db->b, '\n')) == 0) + break; + len = Blinelen(&db->b); + if(line[len-1] != '\n') + break; + if(first && !ISWHITE(*line) && *line != '#'){ + Bseek(&db->b, -len, 1); + break; + } + t = _ndbparseline(line); + if(t == 0) + continue; + if(first) + last->entry = t; + else + first = t; + last = t; + while(last->entry) + last = last->entry; + } + setmalloctag(first, getcallerpc(&db)); + return first; +} blob - /dev/null blob + 167d0a0acd48418b21fecfb5d774d8040c603de8 (mode 644) --- /dev/null +++ src/libndb/ndbreorder.c @@ -0,0 +1,53 @@ +#include +#include +#include +#include + +/* + * reorder the tuple to put x's line first in the entry and x fitst in its line + */ +Ndbtuple* +ndbreorder(Ndbtuple *t, Ndbtuple *x) +{ + Ndbtuple *nt; + Ndbtuple *last, *prev; + + /* if x is first, we're done */ + if(x == t) + return t; + + /* find end of x's line */ + for(last = x; last->line == last->entry; last = last->line) + ; + + /* rotate to make this line first */ + if(last->line != t){ + + /* detach this line and everything after it from the entry */ + for(nt = t; nt->entry != last->line; nt = nt->entry) + ; + nt->entry = nil; + + /* switch */ + for(nt = last; nt->entry != nil; nt = nt->entry) + ; + nt->entry = t; + } + + /* rotate line to make x first */ + if(x != last->line){ + + /* find entry before x */ + for(prev = last; prev->line != x; prev = prev->line); + ; + + /* detach line */ + nt = last->entry; + last->entry = last->line; + + /* reattach */ + prev->entry = nt; + } + + return x; +} blob - /dev/null blob + 46f6371231b82517dd646b7cd3c4a56ecc3016a1 (mode 644) --- /dev/null +++ src/libndb/ndbsubstitute.c @@ -0,0 +1,39 @@ +#include +#include +#include +#include + +/* replace a in t with b, the line structure in b is lost, c'est la vie */ +Ndbtuple* +ndbsubstitute(Ndbtuple *t, Ndbtuple *a, Ndbtuple *b) +{ + Ndbtuple *nt; + + if(a == b) + return t; + if(b == nil) + return ndbdiscard(t, a); + + /* all pointers to a become pointers to b */ + for(nt = t; nt != nil; nt = nt->entry){ + if(nt->line == a) + nt->line = b; + if(nt->entry == a) + nt->entry = b; + } + + /* end of b chain points to a's successors */ + for(nt = b; nt->entry; nt = nt->entry){ + nt->line = nt->entry; + } + nt->line = a->line; + nt->entry = a->entry; + + a->entry = nil; + ndbfree(a); + + if(a == t) + return b; + else + return t; +}