new
This commit is contained in:
parent
ad017cfbf5
commit
d957951b75
27 changed files with 2521 additions and 0 deletions
13
src/cmd/ndb/mkfile
Normal file
13
src/cmd/ndb/mkfile
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
<$PLAN9/src/mkhdr
|
||||||
|
|
||||||
|
TARG=\
|
||||||
|
ndbmkdb\
|
||||||
|
ndbquery\
|
||||||
|
ndbmkhash\
|
||||||
|
ndbmkhosts\
|
||||||
|
ndbipquery\
|
||||||
|
|
||||||
|
LIB=$PLAN9/lib/libndb.a
|
||||||
|
|
||||||
|
<$PLAN9/src/mkmany
|
||||||
|
|
||||||
54
src/cmd/ndb/ndbipquery.c
Normal file
54
src/cmd/ndb/ndbipquery.c
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <bio.h>
|
||||||
|
#include <ndb.h>
|
||||||
|
#include <ip.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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);
|
||||||
|
}
|
||||||
203
src/cmd/ndb/ndbmkdb.c
Normal file
203
src/cmd/ndb/ndbmkdb.c
Normal file
|
|
@ -0,0 +1,203 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <bio.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
155
src/cmd/ndb/ndbmkhash.c
Normal file
155
src/cmd/ndb/ndbmkhash.c
Normal file
|
|
@ -0,0 +1,155 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <bio.h>
|
||||||
|
#include <ndb.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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);
|
||||||
|
}
|
||||||
233
src/cmd/ndb/ndbmkhosts.c
Normal file
233
src/cmd/ndb/ndbmkhosts.c
Normal file
|
|
@ -0,0 +1,233 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <bio.h>
|
||||||
|
#include <ndb.h>
|
||||||
|
#include <ip.h>
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
81
src/cmd/ndb/ndbquery.c
Normal file
81
src/cmd/ndb/ndbquery.c
Normal file
|
|
@ -0,0 +1,81 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <bio.h>
|
||||||
|
#include <ndb.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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);
|
||||||
|
}
|
||||||
107
src/libndb/csgetval.c
Normal file
107
src/libndb/csgetval.c
Normal file
|
|
@ -0,0 +1,107 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <bio.h>
|
||||||
|
#include <ndb.h>
|
||||||
|
#include <ndbhf.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*
|
||||||
|
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;
|
||||||
|
}
|
||||||
68
src/libndb/csipinfo.c
Normal file
68
src/libndb/csipinfo.c
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <bio.h>
|
||||||
|
#include <ndb.h>
|
||||||
|
#include <ndbhf.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
156
src/libndb/dnsquery.c
Normal file
156
src/libndb/dnsquery.c
Normal file
|
|
@ -0,0 +1,156 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <bio.h>
|
||||||
|
#include <ndb.h>
|
||||||
|
#include <ndbhf.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
46
src/libndb/ipattr.c
Normal file
46
src/libndb/ipattr.c
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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";
|
||||||
|
}
|
||||||
32
src/libndb/mkfile
Normal file
32
src/libndb/mkfile
Normal file
|
|
@ -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
|
||||||
94
src/libndb/ndbaux.c
Normal file
94
src/libndb/ndbaux.c
Normal file
|
|
@ -0,0 +1,94 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <bio.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <ndb.h>
|
||||||
|
#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;
|
||||||
|
}
|
||||||
144
src/libndb/ndbcache.c
Normal file
144
src/libndb/ndbcache.c
Normal file
|
|
@ -0,0 +1,144 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <bio.h>
|
||||||
|
#include <ndb.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
18
src/libndb/ndbcat.c
Normal file
18
src/libndb/ndbcat.c
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <bio.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <ndb.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
18
src/libndb/ndbconcatenate.c
Normal file
18
src/libndb/ndbconcatenate.c
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <bio.h>
|
||||||
|
#include <ndb.h>
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
}
|
||||||
29
src/libndb/ndbdiscard.c
Normal file
29
src/libndb/ndbdiscard.c
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <bio.h>
|
||||||
|
#include <ndb.h>
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
}
|
||||||
65
src/libndb/ndbfree.c
Normal file
65
src/libndb/ndbfree.c
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <bio.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <ndb.h>
|
||||||
|
#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;
|
||||||
|
}
|
||||||
47
src/libndb/ndbgetipaddr.c
Normal file
47
src/libndb/ndbgetipaddr.c
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <bio.h>
|
||||||
|
#include <ndb.h>
|
||||||
|
#include <ip.h>
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
}
|
||||||
75
src/libndb/ndbgetval.c
Normal file
75
src/libndb/ndbgetval.c
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <bio.h>
|
||||||
|
#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;
|
||||||
|
}
|
||||||
247
src/libndb/ndbhash.c
Normal file
247
src/libndb/ndbhash.c
Normal file
|
|
@ -0,0 +1,247 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <bio.h>
|
||||||
|
#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;
|
||||||
|
}
|
||||||
27
src/libndb/ndbhf.h
Normal file
27
src/libndb/ndbhf.h
Normal file
|
|
@ -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);
|
||||||
242
src/libndb/ndbipinfo.c
Normal file
242
src/libndb/ndbipinfo.c
Normal file
|
|
@ -0,0 +1,242 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <bio.h>
|
||||||
|
#include <ndb.h>
|
||||||
|
#include <ip.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
44
src/libndb/ndblookval.c
Normal file
44
src/libndb/ndblookval.c
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <bio.h>
|
||||||
|
#include <ip.h>
|
||||||
|
#include <ndb.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
174
src/libndb/ndbopen.c
Normal file
174
src/libndb/ndbopen.c
Normal file
|
|
@ -0,0 +1,174 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <bio.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <ndb.h>
|
||||||
|
#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;
|
||||||
|
}
|
||||||
57
src/libndb/ndbparse.c
Normal file
57
src/libndb/ndbparse.c
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <bio.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <ndb.h>
|
||||||
|
#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;
|
||||||
|
}
|
||||||
53
src/libndb/ndbreorder.c
Normal file
53
src/libndb/ndbreorder.c
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <bio.h>
|
||||||
|
#include <ndb.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
39
src/libndb/ndbsubstitute.c
Normal file
39
src/libndb/ndbsubstitute.c
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <bio.h>
|
||||||
|
#include <ndb.h>
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue