Browse Source

Plan 9 from Bell Labs 2004-03-07

David du Colombier 20 years ago
parent
commit
5663412370

+ 19 - 14
dist/replica/plan9.db

@@ -543,7 +543,7 @@
 386/lib/libmemdraw.a - 664 sys sys 1073851273 291288
 386/lib/libmemlayer.a - 664 sys sys 1073851273 47636
 386/lib/libmp.a - 664 sys sys 1077940925 77700
-386/lib/libndb.a - 664 sys sys 1077636970 54474
+386/lib/libndb.a - 664 sys sys 1078626124 61198
 386/lib/libplumb.a - 664 sys sys 1073851274 18876
 386/lib/libregexp.a - 664 sys sys 1073851274 37502
 386/lib/libscribble.a - 664 sys sys 1073851274 107542
@@ -3413,7 +3413,7 @@ sys/include/memdraw.h - 664 sys sys 1039752978 5616
 sys/include/memlayer.h - 664 sys sys 1051031022 1851
 sys/include/mouse.h - 664 sys sys 1035232010 1003
 sys/include/mp.h - 664 sys sys 1014929065 4610
-sys/include/ndb.h - 664 sys sys 1077632684 4009
+sys/include/ndb.h - 664 sys sys 1078618596 4334
 sys/include/nfs3.h - 664 sys sys 1045589438 15082
 sys/include/plumb.h - 664 sys sys 1014929065 989
 sys/include/pool.h - 664 sys sys 1032058257 1156
@@ -4835,7 +4835,7 @@ sys/man/2/mouse - 664 sys sys 971455512 4966
 sys/man/2/mp - 664 sys sys 1071238964 10690
 sys/man/2/muldiv - 664 sys sys 984709633 639
 sys/man/2/nan - 664 sys sys 975084242 937
-sys/man/2/ndb - 664 sys sys 1077632681 8901
+sys/man/2/ndb - 664 sys sys 1078625843 9479
 sys/man/2/notify - 664 sys sys 1032058674 6376
 sys/man/2/object - 664 sys sys 944959695 3864
 sys/man/2/open - 664 sys sys 1015091524 3404
@@ -5468,7 +5468,7 @@ sys/src/9/port/portdat.h - 664 sys sys 1073324006 22707
 sys/src/9/port/portfns.h - 664 sys sys 1068215525 11376
 sys/src/9/port/portmkfile - 664 sys sys 1067722766 2098
 sys/src/9/port/print.c - 664 sys sys 1014931178 227
-sys/src/9/port/proc.c - 664 sys sys 1071247309 28305
+sys/src/9/port/proc.c - 664 sys sys 1078550254 28021
 sys/src/9/port/qio.c - 664 sys sys 1070287837 23562
 sys/src/9/port/qlock.c - 664 sys sys 1067722765 3196
 sys/src/9/port/rdb.c - 664 sys sys 1018721202 1698
@@ -9735,7 +9735,7 @@ sys/src/cmd/mv.c - 664 sys sys 1014926695 4276
 sys/src/cmd/ndb - 20000000775 sys sys 988249988 0
 sys/src/cmd/ndb/convDNS2M.c - 664 sys sys 1060612175 6862
 sys/src/cmd/ndb/convM2DNS.c - 664 sys sys 1060612175 7248
-sys/src/cmd/ndb/cs.c - 664 sys sys 1069206443 32930
+sys/src/cmd/ndb/cs.c - 664 sys sys 1078631715 33161
 sys/src/cmd/ndb/csgetval.c - 664 sys sys 957402051 1051
 sys/src/cmd/ndb/csquery.c - 664 sys sys 1014926159 1062
 sys/src/cmd/ndb/dblookup.c - 664 sys sys 1060612175 17896
@@ -12110,22 +12110,27 @@ sys/src/libmp/power/mpvecsub.s - 664 sys sys 950104732 1118
 sys/src/libmp/power/placeholder.c - 664 sys sys 944961747 0
 sys/src/libmp/test.c - 664 sys sys 964798440 12260
 sys/src/libndb - 20000000775 sys sys 1015013466 0
-sys/src/libndb/csgetval.c - 664 sys sys 1069206439 1322
+sys/src/libndb/csgetval.c - 664 sys sys 1078626122 1600
 sys/src/libndb/csipinfo.c - 664 sys sys 1069206439 1175
-sys/src/libndb/dnsquery.c - 664 sys sys 1069206439 2799
+sys/src/libndb/dnsquery.c - 664 sys sys 1078618597 2840
 sys/src/libndb/ipattr.c - 664 sys sys 953844690 586
-sys/src/libndb/mkfile - 664 sys sys 1035389780 424
-sys/src/libndb/ndbaux.c - 664 sys sys 1069206440 1600
-sys/src/libndb/ndbcache.c - 664 sys sys 1024156984 2227
+sys/src/libndb/mkfile - 664 sys sys 1078618596 513
+sys/src/libndb/ndbaux.c - 664 sys sys 1078618597 1518
+sys/src/libndb/ndbcache.c - 664 sys sys 1078618597 2164
 sys/src/libndb/ndbcat.c - 664 sys sys 950311789 224
-sys/src/libndb/ndbfree.c - 664 sys sys 944961749 233
-sys/src/libndb/ndbgetval.c - 664 sys sys 944961749 811
+sys/src/libndb/ndbconcatenate.c - 664 sys sys 1078618598 259
+sys/src/libndb/ndbdiscard.c - 664 sys sys 1078618598 436
+sys/src/libndb/ndbfree.c - 664 sys sys 1078618598 952
+sys/src/libndb/ndbgetipaddr.c - 664 sys sys 1078618598 813
+sys/src/libndb/ndbgetval.c - 664 sys sys 1078626122 1160
 sys/src/libndb/ndbhash.c - 664 sys sys 1069206440 4973
 sys/src/libndb/ndbhf.h - 664 sys sys 1015013485 746
-sys/src/libndb/ndbipinfo.c - 664 sys sys 1063853776 6483
-sys/src/libndb/ndblookval.c - 664 sys sys 944961750 655
+sys/src/libndb/ndbipinfo.c - 664 sys sys 1078618599 4640
+sys/src/libndb/ndblookval.c - 664 sys sys 1078626123 981
 sys/src/libndb/ndbopen.c - 664 sys sys 1069206441 2716
 sys/src/libndb/ndbparse.c - 664 sys sys 1069206440 1167
+sys/src/libndb/ndbreorder.c - 664 sys sys 1078618600 966
+sys/src/libndb/ndbsubstitute.c - 664 sys sys 1078618600 692
 sys/src/libplumb - 20000000775 sys sys 1014928082 0
 sys/src/libplumb/event.c - 664 sys sys 947358887 1861
 sys/src/libplumb/mesg.c - 644 sys sys 1014928082 6718

+ 26 - 0
dist/replica/plan9.log

@@ -14029,3 +14029,29 @@
 1078497028 4 c mips/include/ape/math.h - 664 sys sys 1078495287 2176
 1078497028 5 c power/include/ape/math.h - 664 sys sys 1078495287 2176
 1078497028 6 c sparc/include/ape/math.h - 664 sys sys 1078495288 2176
+1078551037 0 c sys/src/9/port/proc.c - 664 sys sys 1078550254 28021
+1078583444 0 c sys/src/cmd/ndb/cs.c - 664 sys sys 1078582417 33093
+1078619438 0 c 386/lib/libndb.a - 664 sys sys 1078618600 59934
+1078619438 1 c sys/include/ndb.h - 664 sys sys 1078618596 4334
+1078619438 2 c sys/src/libndb/csgetval.c - 664 sys sys 1078618596 1514
+1078619438 3 c sys/src/libndb/dnsquery.c - 664 sys sys 1078618597 2840
+1078619438 4 c sys/src/libndb/mkfile - 664 sys sys 1078618596 513
+1078619438 5 c sys/src/libndb/ndbaux.c - 664 sys sys 1078618597 1518
+1078619438 6 c sys/src/libndb/ndbcache.c - 664 sys sys 1078618597 2164
+1078619438 7 a sys/src/libndb/ndbconcatenate.c - 664 sys sys 1078618598 259
+1078619438 8 a sys/src/libndb/ndbdiscard.c - 664 sys sys 1078618598 436
+1078619438 9 c sys/src/libndb/ndbfree.c - 664 sys sys 1078618598 952
+1078619438 10 a sys/src/libndb/ndbgetipaddr.c - 664 sys sys 1078618598 813
+1078619438 11 c sys/src/libndb/ndbgetval.c - 664 sys sys 1078618599 984
+1078619438 12 c sys/src/libndb/ndbipinfo.c - 664 sys sys 1078618599 4640
+1078619438 13 c sys/src/libndb/ndblookval.c - 664 sys sys 1078618599 815
+1078619438 14 a sys/src/libndb/ndbreorder.c - 664 sys sys 1078618600 966
+1078619438 15 a sys/src/libndb/ndbsubstitute.c - 664 sys sys 1078618600 692
+1078621239 0 c sys/man/2/ndb - 664 sys sys 1078620018 9313
+1078621239 1 c sys/src/cmd/ndb/cs.c - 664 sys sys 1078620182 33161
+1078626641 0 c 386/lib/libndb.a - 664 sys sys 1078626124 61198
+1078626641 1 c sys/man/2/ndb - 664 sys sys 1078625843 9479
+1078626641 2 c sys/src/libndb/csgetval.c - 664 sys sys 1078626122 1600
+1078626641 3 c sys/src/libndb/ndbgetval.c - 664 sys sys 1078626122 1160
+1078626641 4 c sys/src/libndb/ndblookval.c - 664 sys sys 1078626123 981
+1078632040 0 c sys/src/cmd/ndb/cs.c - 664 sys sys 1078631715 33161

+ 11 - 5
sys/include/ndb.h

@@ -43,11 +43,12 @@ struct Ndb
  */
 struct Ndbtuple
 {
-	char		attr[Ndbalen];	/* attribute name */
-	char		val[Ndbvlen];	/* value(s) */
-	Ndbtuple	*entry;		/* next tuple in this entry */
-	Ndbtuple	*line;		/* next tuple on this line */
-	ulong		ptr;		/* (for the application - starts 0) */
+	char		attr[Ndbalen];		/* attribute name */
+	char		*val;			/* value(s) */
+	Ndbtuple	*entry;			/* next tuple in this entry */
+	Ndbtuple	*line;			/* next tuple on this line */
+	ulong		ptr;			/* (for the application - starts 0) */
+	char		valbuf[Ndbvlen];	/* initial allocation for value */
 };
 
 /*
@@ -121,6 +122,7 @@ struct Ndbs
 #define NDB_IPlen 16
 
 Ndbtuple*	csgetval(char*, char*, char*, char*, char*);
+Ndbtuple*	csgetvalue(char*, char*, char*, char*, char*, int);
 Ndbtuple*	csipinfo(char*, char*, char*, char**, int);
 Ndbtuple*	dnsquery(char*, char*, char*);
 char*		ipattr(char*);
@@ -132,14 +134,18 @@ Ndbtuple*	ndbdiscard(Ndbtuple*, Ndbtuple*);
 void		ndbfree(Ndbtuple*);
 Ndbtuple*	ndbgetipaddr(Ndb*, char*);
 Ndbtuple*	ndbgetval(Ndb*, Ndbs*, char*, char*, char*, char*);
+Ndbtuple*	ndbgetvalue(Ndb*, Ndbs*, char*, char*, char*, char*, int);
 ulong		ndbhash(char*, int);
 Ndbtuple*	ndbipinfo(Ndb*, char*, char*, char**, int);
 Ndbtuple*	ndblookval(Ndbtuple*, Ndbtuple*, char*, char*);
+Ndbtuple*	ndblookvalue(Ndbtuple*, Ndbtuple*, char*, char*, int);
+Ndbtuple*	ndbnew(char*, char*);
 Ndb*		ndbopen(char*);
 Ndbtuple*	ndbparse(Ndb*);
 int		ndbreopen(Ndb*);
 Ndbtuple*	ndbreorder(Ndbtuple*, Ndbtuple*);
 Ndbtuple*	ndbsearch(Ndb*, Ndbs*, char*, char*);
 long		ndbseek(Ndb*, long);
+void		ndbsetval(Ndbtuple*, char*, int);
 Ndbtuple*	ndbsnext(Ndbs*, char*, char*);
 Ndbtuple*	ndbsubstitute(Ndbtuple*, Ndbtuple*, Ndbtuple*);

+ 44 - 16
sys/man/2/ndb

@@ -1,6 +1,6 @@
 .TH NDB 2
 .SH NAME
-ndbopen, ndbcat, ndbchanged, ndbclose, ndbreopen, ndbsearch, ndbsnext, ndbgetval, ndbfree, ipattr, ndbgetipaddr, ndbipinfo, csipinfo, ndbhash, ndbparse, csgetval, ndblookval, dnsquery, ndbdiscard, ndbconcatenate, ndbreorder, ndbsubstitute \- network database
+ndbopen, ndbcat, ndbchanged, ndbclose, ndbreopen, ndbsearch, ndbsnext, ndbgetvalue, ndbfree, ipattr, ndbgetipaddr, ndbipinfo, csipinfo, ndbhash, ndbparse, csgetvalue, ndblookvalue, dnsquery, ndbdiscard, ndbconcatenate, ndbreorder, ndbsubstitute, ndbgetval, csgetval, ndblookval \- network database
 .SH SYNOPSIS
 .B #include <u.h>
 .br
@@ -33,13 +33,14 @@ Ndbtuple*	ndbsearch(Ndb *db, Ndbs *s, char *attr, char *val)
 Ndbtuple*	ndbsnext(Ndbs *s, char *attr, char *val)
 .PP
 .B
-Ndbtuple*	ndbgetval(Ndb *db, Ndbs *s, char *attr, char *val,
+Ndbtuple*	ndbgetvalue(Ndb *db, Ndbs *s, char *attr, char *val,
 .br
 .B
-		char *rattr, char *buf)
+		char *rattr, char *buf, int buflen)
 .PP
 .B
-Ndbtuple*	csgetval(char *netroot, char *attr, char *val, char *rattr, char *buf)
+Ndbtuple*	csgetvalue(char *netroot, char *attr, char *val, char *rattr,
+		char *buf, int buflen)
 .PP
 .B
 char*	ipattr(char *name)
@@ -67,7 +68,8 @@ Ndbtuple*	ndbparse(Ndb *db)
 Ndbtuple*	dnsquery(char *netroot, char *domainname, char *type)
 .PP
 .B
-Ndbtuple*	ndblookval(Ndbtuple *entry, Ndbtuple *line, char *attr, char *to)
+Ndbtuple*	ndblookvalue(Ndbtuple *entry, Ndbtuple *line, char *attr,
+		char *to, int tolen)
 .PP
 .B
 void	ndbfree(Ndbtuple *db)
@@ -136,10 +138,11 @@ On failure they return zero.
 typedef struct Ndbtuple Ndbtuple;
 struct Ndbtuple {
         char      attr[Ndbalen];
-        char      val[Ndbvlen];
+        char      *val;
         Ndbtuple  *entry;
         Ndbtuple  *line;
         ulong     ptr;    /* for the application; starts 0 */
+        char      valbuf[Ndbvlen];  /* initial allocation for val */
 };
 .EE
 .LP
@@ -186,23 +189,21 @@ field points to the pair within the entry matched by the
 or
 .IR ndbsnext .
 .PP
-.I Ndbgetval
+.I Ndbgetvalue
 searches the database for an entry containing not only an
 attribute/value pair,
 .IR attr = val ,
 but also a pair with the attribute
 .IR rattr .
-If successful, it copies the value associated with
+If successful, it copies up to
+.I buflen
+bytes of the value associated with
 .I rattr
 into
 .IR buf .
-.I Buf
-must point to an area at least
-.I Ndbvlen
-long.
-.I Csgetval
+.I Csgetvalue
 is like
-.I ndbgetval
+.I ndbgetvalue
 but queries the connection server
 instead of looking directly at the database.
 Its first argument specifies the network root to use.
@@ -373,13 +374,15 @@ name servers.  Returns domain name
 and name server
 .RI ( ns )
 .PP
-.I Ndblookval
+.I Ndblookvalue
 searches 
 .I entry
 for the tuple
 with attribute
 .IR attr ,
-copies the value into
+copies up to
+.I tolen
+bytes of the value into
 .IR to ,
 and returns a pointer to the tuple.
 If
@@ -452,3 +455,28 @@ is freed.
 .SH DIAGNOSTICS
 These routines set
 .IR errstr .
+.IR Ndbgetvalue ,
+.IR csgetvalue ,
+and
+.I ndblookvalue
+set
+.I errstr
+to
+.B "return value truncated"
+if the buffer provided isn't long enough for the
+returned value.
+.SH BUGS
+.IR Ndbgetval ,
+.IR csgetval ,
+and
+.I ndblookval
+are deprecated versions of
+.IR ndbgetvalue ,
+.IR csgetvalue ,
+and
+.IR ndblookvalue .
+They expect a fixed 64 byte long result
+buffer and existed when the values of a
+.I Ndbtuple
+structure where fixed length.
+

+ 13 - 24
sys/src/9/port/proc.c

@@ -7,7 +7,8 @@
 #include	"edf.h"
 #include	<trace.h>
 
-int	coopsched = 1;
+int	coopsched;
+int	schedgain = 30;	/* units in seconds */
 int	nrdy;
 Ref	noteidalloc;
 
@@ -33,18 +34,11 @@ enum
 {
 	Q=10,
 	DQ=4,
+	Scaling=2,
 };
 
 Schedq	runq[Nrq];
 ulong	runvec;
-static int	quanta[Npriq] =
-{
-	Q+19*DQ, Q+18*DQ, Q+17*DQ, Q+16*DQ,
-	Q+15*DQ, Q+14*DQ, Q+13*DQ, Q+12*DQ,
-	Q+11*DQ, Q+10*DQ, Q+ 9*DQ, Q+ 8*DQ,
-	Q+ 7*DQ, Q+ 6*DQ, Q+ 5*DQ, Q+ 4*DQ,
-	Q+ 3*DQ, Q+ 2*DQ, Q+ 1*DQ, Q+ 0*DQ,
-};
 
 char *statename[] =
 {	/* BUG: generate automatically */
@@ -155,6 +149,7 @@ sched(void)
 	}
 	if(p != m->readied)
 		m->schedticks = m->ticks + HZ/10;
+	m->readied = 0;
 	up = p;
 	up->state = Running;
 	up->mach = MACHP(m->machno);
@@ -259,12 +254,12 @@ void
 updatecpu(Proc *p)
 {
 	int n, t, ocpu;
-	enum { D = 30*HZ };
+	int D = schedgain*HZ*Scaling;
 
 	if(p->edf)
 		return;
 
-	t = MACHP(0)->ticks;
+	t = MACHP(0)->ticks*Scaling + Scaling/2;
 	n = t - p->lastupdate;
 	p->lastupdate = t;
 
@@ -429,16 +424,16 @@ void
 yield(void)
 {
 	if(anyready()){
-		/* pretend we just used 10ms */
-		up->lastupdate -= HZ/100;
+		/* pretend we just used 1/2 tick */
+		up->lastupdate -= Scaling/2;  
 		sched();
 	}
 }
 
 /*
- * move up any process waiting more than its quanta
- * called once per clock tick on processor 0.
- * we reduce this to once per second via blaancetime.
+ *  recalculate priorities once a second.  We need to do this
+ *  since priorities will otherwise only be recalculated when
+ *  the running process blocks.
  */
 ulong balancetime;
 
@@ -631,12 +626,8 @@ newproc(void)
 	p->mp = 0;
 	p->wired = 0;
 	procpriority(p, PriNormal, 0);
-
-	/* a priori, somewhere below interactive but above the cpu hogs */
-	p->cpu = 1000000/(5*MACHP(0)->load+1);
-	if(p->cpu > 1000)
-		p->cpu = 1000;
-	p->priority = reprioritize(p);
+	p->cpu = 0;
+	p->lastupdate = MACHP(0)->ticks*Scaling;
 	p->edf = nil;
 
 	return p;
@@ -686,10 +677,8 @@ procpriority(Proc *p, int pri, int fixed)
 	p->basepri = pri;
 	p->priority = pri;
 	if(fixed){
-		// p->quanta = 0xfffff;
 		p->fixedpri = 1;
 	} else {
-		// p->quanta = quanta[pri];
 		p->fixedpri = 0;
 	}
 }

+ 77 - 80
sys/src/cmd/ndb/cs.c

@@ -6,6 +6,7 @@
 #include <ctype.h>
 #include <ndb.h>
 #include <ip.h>
+#include <String.h>
 
 enum
 {
@@ -14,6 +15,8 @@ enum
 	Maxrequest=		128,
 	Maxpath=		128,
 	Maxfdata=		8192,
+	Maxhost=		64,		/* maximum host name size */
+	Maxservice=		64,		/* maximum service name size */
 
 	Qdir=			0,
 	Qcs=			1,
@@ -152,12 +155,13 @@ enum
 	Nil,
 	Nudp,
 	Nicmp,
+	Nicmpv6,
 	Nrudp,
 	Ntelco,
 };
 
 /*
- *  net doesn't apply to udp, icmp, or telco (for speed)
+>  *  net doesn't apply to (r)udp, icmp(v6), or telco (for speed)
  */
 Network network[] = {
 [Nilfast]	{ "il",		iplookup,	iptrans,	0, 1 },
@@ -165,6 +169,7 @@ Network network[] = {
 [Nil]		{ "il",		iplookup,	iptrans,	0, 0 },
 [Nudp]		{ "udp",	iplookup,	iptrans,	1, 0 },
 [Nicmp]		{ "icmp",	iplookup,	iptrans,	1, 0 },
+[Nicmpv6]	{ "icmpv6",	iplookup,	iptrans,	1, 0 },
 [Nrudp]		{ "rudp",	iplookup,	iptrans,	1, 0 },
 [Ntelco]	{ "telco",	telcolookup,	telcotrans,	1, 0 },
 		{ 0 },
@@ -173,14 +178,22 @@ Network network[] = {
 Lock ipifclock;
 Ipifc *ipifcs;
 
-char	eaddr[Ndbvlen];		/* ascii ethernet address */
-char	ipaddr[Ndbvlen];	/* ascii internet address */
+char	eaddr[16];		/* ascii ethernet address */
+char	ipaddr[64];		/* ascii internet address */
 uchar	ipa[IPaddrlen];		/* binary internet address */
-char	mysysname[Ndbvlen];
+char	*mysysname;
 
 Network *netlist;		/* networks ordered by preference */
 Network *last;
 
+static void
+nstrcpy(char *to, char *from, int len)
+{
+	strncpy(to, from, len);
+	to[len-1] = 0;
+}
+
+
 void
 usage(void)
 {
@@ -957,9 +970,8 @@ ipid(void)
 	int f;
 	char buf[Maxpath];
 
-
 	/* use environment, ether addr, or ipaddr to get system name */
-	if(*mysysname == 0){
+	if(mysysname == 0){
 		/*
 		 *  environment has priority.
 		 *
@@ -971,7 +983,7 @@ ipid(void)
 		if(p){
 			attr = ipattr(p);
 			if(strcmp(attr, "ip") != 0)
-				strcpy(mysysname, p);
+				mysysname = strdup(p);
 		}
 
 		/*
@@ -979,11 +991,11 @@ ipid(void)
 		 *  figured out from DHCP.  use that name if
 		 *  there is one. 
 		 */
-		if(*mysysname == 0 && netdb != nil){
+		if(mysysname == 0 && netdb != nil){
 			ndbreopen(netdb);
 			for(tt = t = ndbparse(netdb); t != nil; t = t->entry){
 				if(strcmp(t->attr, "sys") == 0){
-					strcpy(mysysname, t->val);
+					mysysname = strdup(t->val);
 					break;
 				}
 			}
@@ -991,32 +1003,37 @@ ipid(void)
 		}
 
 		/* next network database, ip address, and ether address to find a name */
-		if(*mysysname == 0){
+		if(mysysname == 0){
 			t = nil;
 			if(isvalidip(ipa))
-				t = ndbgetval(db, &s, "ip", ipaddr, "sys", mysysname);
-			else {
+				t = ndbgetvalue(db, &s, "ip", ipaddr, "sys", nil, 0);
+			if(t == nil){
 				for(f = 0; f < 3; f++){
 					snprint(buf, sizeof buf, "%s/ether%d", mntpt, f);
 					if(myetheraddr(addr, buf) >= 0){
 						snprint(eaddr, sizeof(eaddr), "%E", addr);
-						t = ndbgetval(db, &s, "ether", eaddr, "sys",
-							mysysname);
+						t = ndbgetvalue(db, &s, "ether", eaddr, "sys",
+							nil, 0);
 						if(t != nil)
 							break;
 					}
 				}
 			}
+			for(tt = t; tt != nil; tt = tt->entry)
+				if(strcmp(t->attr, "sys") == 0){
+					mysysname = strdup(t->val);
+					break;
+				}
 			ndbfree(t);
 		}
 
 		/* nothing else worked, use the ip address */
-		if(*mysysname == 0 && isvalidip(ipa))
-			strcpy(mysysname, ipaddr);
+		if(mysysname == 0 && isvalidip(ipa))
+			mysysname = strdup(ipaddr);
 					
 
 		/* set /dev/sysname if we now know it */
-		if(*mysysname){
+		if(mysysname){
 			f = open("/dev/sysname", OWRITE);
 			if(f >= 0){
 				write(f, mysysname, strlen(mysysname));
@@ -1071,7 +1088,7 @@ netinit(int background)
 
 	if(debug)
 		syslog(0, logfile, "mysysname %s eaddr %s ipaddr %s ipa %I\n",
-			mysysname, eaddr, ipaddr, ipa);
+			mysysname?mysysname:"???", eaddr, ipaddr, ipa);
 
 	if(background){
 		unlock(&netlock);
@@ -1107,23 +1124,6 @@ netadd(char *p)
 	}
 }
 
-/*
- *  make a tuple
- */
-Ndbtuple*
-mktuple(char *attr, char *val)
-{
-	Ndbtuple *t;
-
-	t = emalloc(sizeof(Ndbtuple));
-	strcpy(t->attr, attr);
-	strncpy(t->val, val, sizeof(t->val));
-	t->val[sizeof(t->val)-1] = 0;
-	t->line = t;
-	t->entry = 0;
-	return t;
-}
-
 int
 lookforproto(Ndbtuple *t, char *proto)
 {
@@ -1195,22 +1195,23 @@ lookup(Mfile *mf)
 	 */
 	if(mf->nreply != 0)
 		return 0;
-
 	/*
 	 *  look for a specific network
 	 */
-	for(np = netlist; np->net != nil; np++){
+	for(np = netlist; np && np->net != nil; np++){
 		if(np->fasttimeouthack)
 			continue;
 		if(strcmp(np->net, mf->net) == 0)
 			break;
 	}
 
-	if(np->net != nil){
+	if(np && np->net != nil){
 		/*
 		 *  known network
 		 */
+syslog(0, logfile, "specific lookup %s", np->net);
 		nt = (*np->lookup)(np, mf->host, mf->serv, 1);
+syslog(0, logfile, "returned %p", nt);
 		for(t = nt; mf->nreply < Nreply && t; t = t->entry){
 			cp = (*np->trans)(t, np, mf->serv, mf->rem, 0);
 			if(cp){
@@ -1245,12 +1246,12 @@ lookup(Mfile *mf)
  *  the service '*' needs no translation.
  */
 char*
-ipserv(Network *np, char *name, char *buf)
+ipserv(Network *np, char *name, char *buf, int blen)
 {
 	char *p;
 	int alpha = 0;
 	int restr = 0;
-	char port[Ndbvlen];
+	char port[10];
 	Ndbtuple *t, *nt;
 	Ndbs s;
 
@@ -1271,7 +1272,7 @@ ipserv(Network *np, char *name, char *buf)
 			return 0;
 	}
 	if(alpha){
-		t = ndbgetval(db, &s, np->net, name, "port", port);
+		t = ndbgetvalue(db, &s, np->net, name, "port", port, sizeof(port));
 		if(t == 0)
 			return 0;
 	} else {
@@ -1280,11 +1281,9 @@ ipserv(Network *np, char *name, char *buf)
 		 */
 		t = nil;
 		if(atoi(name) < 1024 && strcmp(np->net, "tcp") == 0)
-			t = ndbgetval(db, &s, "port", name, "port", port);
-		if(t == nil){
-			strncpy(port, name, sizeof(port));
-			port[sizeof(port)-1] = 0;
-		}
+			t = ndbgetvalue(db, &s, "port", name, "port", port, sizeof(port));
+		if(t == nil)
+			nstrcpy(port, name, sizeof(port));
 	}
 
 	if(t){
@@ -1293,7 +1292,7 @@ ipserv(Network *np, char *name, char *buf)
 				restr = 1;
 		ndbfree(t);
 	}
-	sprint(buf, "%s%s", port, restr ? "!r" : ""); 
+	snprint(buf, blen, "%s%s", port, restr ? "!r" : ""); 
 	return buf;
 }
 
@@ -1301,7 +1300,7 @@ ipserv(Network *np, char *name, char *buf)
  *  lookup an ip attribute
  */
 int
-ipattrlookup(Ndb *db, char *ipa, char *attr, char *val)
+ipattrlookup(Ndb *db, char *ipa, char *attr, char *val, int vlen)
 {
 	
 	Ndbtuple *t, *nt;
@@ -1313,7 +1312,7 @@ ipattrlookup(Ndb *db, char *ipa, char *attr, char *val)
 		return 0;
 	for(nt = t; nt != nil; nt = nt->entry){
 		if(strcmp(nt->attr, attr) == 0){
-			strcpy(val, nt->val);
+			nstrcpy(val, nt->val, vlen);
 			ndbfree(t);
 			return 1;
 		}
@@ -1333,9 +1332,9 @@ iplookup(Network *np, char *host, char *serv, int nolookup)
 	char *attr;
 	Ndbtuple *t, *nt;
 	Ndbs s;
-	char ts[Ndbvlen+1];
-	char th[Ndbvlen+1];
-	char dollar[Ndbvlen+1];
+	char ts[Maxservice];
+	char th[Maxhost];
+	char dollar[Maxhost];
 	uchar ip[IPaddrlen];
 	uchar net[IPaddrlen];
 	uchar tnet[IPaddrlen];
@@ -1349,27 +1348,27 @@ iplookup(Network *np, char *host, char *serv, int nolookup)
 	 *  and costs the least
 	 */
 	werrstr("can't translate address");
-	if(serv==0 || ipserv(np, serv, ts) == 0){
+	if(serv==0 || ipserv(np, serv, ts, sizeof ts) == 0){
 		werrstr("can't translate service");
 		return 0;
 	}
 
 	/* for dial strings with no host */
 	if(strcmp(host, "*") == 0)
-		return mktuple("ip", "*");
+		return ndbnew("ip", "*");
 
 	/*
 	 *  hack till we go v6 :: = 0.0.0.0
 	 */
 	if(strcmp("::", host) == 0)
-		return mktuple("ip", "*");
+		return ndbnew("ip", "*");
 
 	/*
 	 *  '$' means the rest of the name is an attribute that we
 	 *  need to search for
 	 */
 	if(*host == '$'){
-		if(ipattrlookup(db, ipaddr, host+1, dollar))
+		if(ipattrlookup(db, ipaddr, host+1, dollar, sizeof dollar))
 			host = dollar;
 	}
 
@@ -1386,7 +1385,7 @@ iplookup(Network *np, char *host, char *serv, int nolookup)
 	 */
 	attr = ipattr(host);
 	if(strcmp(attr, "ip") == 0)
-		return mktuple("ip", host);
+		return ndbnew("ip", host);
 
 	/*
 	 *  give the domain name server the first opportunity to
@@ -1397,11 +1396,9 @@ iplookup(Network *np, char *host, char *serv, int nolookup)
 	if(strcmp(attr, "dom") == 0)
 		t = dnsiplookup(host, &s);
 	if(t == 0)
-		t = ndbgetval(db, &s, attr, host, "ip", th);
+		t = ndbgetvalue(db, &s, attr, host, "ip", th, sizeof(th));
 	if(t == 0)
 		t = dnsiplookup(host, &s);
-	if(t == 0 && strcmp(attr, "dom") != 0)
-		t = dnsiplookup(host, &s);
 	if(t == 0)
 		return 0;
 
@@ -1442,14 +1439,14 @@ iplookup(Network *np, char *host, char *serv, int nolookup)
 char*
 iptrans(Ndbtuple *t, Network *np, char *serv, char *rem, int hack)
 {
-	char ts[Ndbvlen+1];
+	char ts[Maxservice];
 	char reply[Maxreply];
-	char x[Ndbvlen+1];
+	char x[Maxservice];
 
 	if(strcmp(t->attr, "ip") != 0)
 		return 0;
 
-	if(serv == 0 || ipserv(np, serv, ts) == 0){
+	if(serv == 0 || ipserv(np, serv, ts, sizeof ts) == 0){
 		werrstr("can't translate service");
 		return 0;
 	}
@@ -1476,14 +1473,14 @@ telcolookup(Network *np, char *host, char *serv, int nolookup)
 {
 	Ndbtuple *t;
 	Ndbs s;
-	char th[Ndbvlen+1];
+	char th[Maxhost];
 
 	USED(np, nolookup, serv);
 
 	werrstr("can't translate address");
-	t = ndbgetval(db, &s, "sys", host, "telco", th);
+	t = ndbgetvalue(db, &s, "sys", host, "telco", th, sizeof(th));
 	if(t == 0)
-		return mktuple("telco", host);
+		return ndbnew("telco", host);
 
 	return reorder(t, s.t);
 }
@@ -1495,7 +1492,7 @@ char*
 telcotrans(Ndbtuple *t, Network *np, char *serv, char *rem, int)
 {
 	char reply[Maxreply];
-	char x[Ndbvlen+1];
+	char x[Maxservice];
 
 	if(strcmp(t->attr, "telco") != 0)
 		return 0;
@@ -1571,7 +1568,7 @@ slave(void)
 Ndbtuple*
 dnsiplookup(char *host, Ndbs *s)
 {
-	char buf[Ndbvlen + 4];
+	char buf[Maxreply];
 	Ndbtuple *t;
 
 	unlock(&dblock);
@@ -1623,23 +1620,23 @@ qmatch(Ndbtuple *t, char **attr, char **val, int n)
 void
 qreply(Mfile *mf, Ndbtuple *t)
 {
-	int i;
 	Ndbtuple *nt;
-	char buf[2048];
+	String *s;
 
-	buf[0] = 0;
+	s = s_new();
 	for(nt = t; mf->nreply < Nreply && nt; nt = nt->entry){
-		strcat(buf, nt->attr);
-		strcat(buf, "=");
-		strcat(buf, nt->val);
-		i = strlen(buf);
-		if(nt->line != nt->entry || sizeof(buf) - i < 2*Ndbvlen+2){
-			mf->replylen[mf->nreply] = strlen(buf);
-			mf->reply[mf->nreply++] = strdup(buf);
-			buf[0] = 0;
+		s_append(s, nt->attr);
+		s_append(s, "=");
+		s_append(s, nt->val);
+
+		if(nt->line != nt->entry){
+			mf->replylen[mf->nreply] = s_len(s);
+			mf->reply[mf->nreply++] = strdup(s_to_c(s));
+			s_restart(s);
 		} else
-			strcat(buf, " ");
+			s_append(s, " ");
 	}
+	s_free(s);
 }
 
 enum

+ 14 - 3
sys/src/libndb/csgetval.c

@@ -11,7 +11,7 @@
  *  return 0 if not found.
  */
 Ndbtuple*
-csgetval(char *netroot, char *attr, char *val, char *rattr, char *buf)
+csgetvalue(char *netroot, char *attr, char *val, char *rattr, char *buf, int len)
 {
 	Ndbtuple *t, *first, *last;
 	int n, linefound;
@@ -35,6 +35,7 @@ csgetval(char *netroot, char *attr, char *val, char *rattr, char *buf)
 	}
 	seek(fd, 0, 0);
 
+	werrstr("");
 	first = last = 0;
 	linefound = 0;
 	for(;;){
@@ -58,8 +59,12 @@ csgetval(char *netroot, char *attr, char *val, char *rattr, char *buf)
 
 		for(; t; t = t->entry){
 			if(buf[0] == 0 || linefound == 0)
-				if(strcmp(rattr, t->attr) == 0)
-					strcpy(buf, t->val);
+				if(strcmp(rattr, t->attr) == 0){
+					strncpy(buf, t->val, len);
+					buf[len-1] = 0;
+					if(strlen(t->val) >= len)
+						werrstr("return value truncated");
+				}
 			if(linefound == 0)
 				if(strcmp(attr, t->attr) == 0)
 					linefound = 1;
@@ -70,3 +75,9 @@ csgetval(char *netroot, char *attr, char *val, char *rattr, char *buf)
 	setmalloctag(first, getcallerpc(&netroot));
 	return first;
 }
+
+Ndbtuple*
+csgetval(char *netroot, char *attr, char *val, char *rattr, char *buf)
+{
+	return csgetvalue(netroot, attr, val, rattr, buf, Ndbvlen);
+}

+ 11 - 11
sys/src/libndb/dnsquery.c

@@ -4,8 +4,8 @@
 #include <ndb.h>
 #include <ndbhf.h>
 
-static void nstrcpy(char*, char*);
-static void mkptrname(char*, char*);
+static void nstrcpy(char*, char*, int);
+static void mkptrname(char*, char*, int);
 static Ndbtuple *doquery(int, char *dn, char *type);
 
 /*
@@ -17,7 +17,7 @@ static Ndbtuple *doquery(int, char *dn, char *type);
 Ndbtuple*
 dnsquery(char *net, char *val, char *type)
 {
-	char rip[Ndbvlen];
+	char rip[128];
 	char *p;
 	Ndbtuple *t;
 	int fd;
@@ -57,7 +57,7 @@ dnsquery(char *net, char *val, char *type)
 
 	/* if this is a reverse lookup, first lookup the domain name */
 	if(strcmp(type, "ptr") == 0){
-		mkptrname(val, rip);
+		mkptrname(val, rip, sizeof rip);
 		t = doquery(fd, rip, "ptr");
 	} else
 		t = doquery(fd, val, type);
@@ -70,18 +70,18 @@ dnsquery(char *net, char *val, char *type)
  *  convert address into a reverse lookup address
  */
 static void
-mkptrname(char *ip, char *rip)
+mkptrname(char *ip, char *rip, int rlen)
 {
-	char buf[Ndbvlen];
+	char buf[128];
 	char *p, *np;
 	int len;
 
 	if(strstr(ip, "in-addr.arpa") || strstr(ip, "IN-ADDR.ARPA")){
-		nstrcpy(rip, ip);
+		nstrcpy(rip, ip, rlen);
 		return;
 	}
 
-	nstrcpy(buf, ip);
+	nstrcpy(buf, ip, sizeof buf);
 	for(p = buf; *p; p++)
 		;
 	*p = '.';
@@ -102,10 +102,10 @@ mkptrname(char *ip, char *rip)
 }
 
 static void
-nstrcpy(char *to, char *from)
+nstrcpy(char *to, char *from, int len)
 {
-	strncpy(to, from, Ndbvlen-1);
-	to[Ndbvlen-1] = 0;
+	strncpy(to, from, len);
+	to[len-1] = 0;
 }
 
 static Ndbtuple*

+ 14 - 9
sys/src/libndb/mkfile

@@ -2,20 +2,25 @@
 
 LIB=/$objtype/lib/libndb.a
 OFILES=\
-	ndbhash.$O\
-	ndbopen.$O\
-	ndbparse.$O\
+	csgetval.$O\
+	csipinfo.$O\
+	dnsquery.$O\
+	ipattr.$O\
+	ndbaux.$O\
 	ndbcache.$O\
 	ndbcat.$O\
-	ndbgetval.$O\
-	ndbaux.$O\
+	ndbconcatenate.$O\
+	ndbdiscard.$O\
 	ndbfree.$O\
-	ipattr.$O\
+	ndbgetipaddr.$O\
+	ndbgetval.$O\
+	ndbhash.$O\
 	ndbipinfo.$O\
 	ndblookval.$O\
-	csgetval.$O\
-	csipinfo.$O\
-	dnsquery.$O\
+	ndbopen.$O\
+	ndbparse.$O\
+	ndbreorder.$O\
+	ndbsubstitute.$O\
 
 HFILES=\
 	/sys/include/ndb.h\

+ 2 - 6
sys/src/libndb/ndbaux.c

@@ -21,9 +21,7 @@ _ndbparsetuple(char *cp, Ndbtuple **tp)
 	if(*cp == '#' || *cp == '\n')
 		return 0;
 
-	t = mallocz(sizeof(Ndbtuple), 1);
-	if(t == nil)
-		return nil;
+	t = ndbnew(nil, nil);
 	setmalloctag(t, getcallerpc(&cp));
 	*tp = t;
 
@@ -56,9 +54,7 @@ _ndbparsetuple(char *cp, Ndbtuple **tp)
 				cp++;
 			len = cp - p;
 		}
-		if(len >= Ndbvlen)
-			len = Ndbvlen;
-		strncpy(t->val, p, len);
+		ndbsetval(t, p, len);
 	}
 
 	return cp;

+ 1 - 6
sys/src/libndb/ndbcache.c

@@ -42,12 +42,7 @@ ndbcopy(Ndb *db, Ndbtuple *from_t, Ndbs *from_s, Ndbs *to_s)
 	first = nil;
 	line = nil;
 	for(; from_t != nil; from_t = from_t->entry){
-		to_t = malloc(sizeof *to_t);
-		if(to_t == nil){
-			ndbfree(first);
-			return nil;
-		}
-		*to_t = *from_t;
+		to_t = ndbnew(from_t->attr, from_t->val);
 
 		/* have s point to matching tuple */
 		if(from_s->t == from_t)

+ 18 - 0
sys/src/libndb/ndbconcatenate.c

@@ -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 - 0
sys/src/libndb/ndbdiscard.c

@@ -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;
+}

+ 45 - 0
sys/src/libndb/ndbfree.c

@@ -15,6 +15,51 @@ ndbfree(Ndbtuple *t)
 
 	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 - 0
sys/src/libndb/ndbgetipaddr.c

@@ -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;
+	Ndbtuple *it, *first, *last, *next;
+	Ndbs s;
+	char buf[Ndbvlen];
+
+	/* already an IP address? */
+	attr = ipattr(val);
+	if(strcmp(attr, "ip") == 0){
+		it = ndbnew("ip", val);
+		return it;
+	}
+
+	/* look it up */
+	it = ndbgetvalue(db, &s, attr, val, "ip", buf, sizeof(buf));
+	if(it == nil)
+		return nil;
+
+	/* 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;
+}

+ 16 - 3
sys/src/libndb/ndbgetval.c

@@ -10,17 +10,21 @@
  *  return 0 if not found.
  */
 Ndbtuple*
-ndbgetval(Ndb *db, Ndbs *s, char *attr, char *val, char *rattr, char *buf)
+ndbgetvalue(Ndb *db, Ndbs *s, char *attr, char *val, char *rattr, char *buf, int len)
 {
 	Ndbtuple *t, *nt;
 
+	werrstr("");
 	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){
-				strncpy(buf, nt->val, Ndbvlen);
+				strncpy(buf, nt->val, len);
+				buf[len-1] = 0;
+				if(strlen(nt->val) >= len)
+					werrstr("return value truncated");
 				return t;
 			}
 			nt = nt->line;
@@ -30,7 +34,10 @@ ndbgetval(Ndb *db, Ndbs *s, char *attr, char *val, char *rattr, char *buf)
 		/* search whole tuple */
 		for(nt = t; nt; nt = nt->entry)
 			if(strcmp(rattr, nt->attr) == 0){
-				strncpy(buf, nt->val, Ndbvlen);
+				strncpy(buf, nt->val, len);
+				buf[len-1] = 0;
+				if(strlen(nt->val) >= len)
+					werrstr("return value truncated");
 				return t;
 			}
 		ndbfree(t);
@@ -38,3 +45,9 @@ ndbgetval(Ndb *db, Ndbs *s, char *attr, char *val, char *rattr, char *buf)
 	}
 	return 0;
 }
+
+Ndbtuple*
+ndbgetval(Ndb *db, Ndbs *s, char *attr, char *val, char *rattr, char *buf)
+{
+	return ndbgetvalue(db, s, attr, val, rattr, buf, Ndbvlen);
+}

+ 100 - 223
sys/src/libndb/ndbipinfo.c

@@ -1,179 +1,102 @@
 #include <u.h>
 #include <libc.h>
 #include <bio.h>
-#include <ip.h>
 #include <ndb.h>
+#include <ip.h>
 
-typedef struct Attr Attr;
-struct Attr
+enum
 {
-	Attr		*next;
-	int		addronly;
-	char		*attr;
-	Ndbtuple	*first;	
-	Ndbtuple	*last;
-	int		masklen;
+	Ffound=	1<<0,
+	Fignore=1<<1,
+	Faddr=	1<<2,
 };
 
-#ifdef DEBUGGING
-static void
-prtuple(char *tag, Ndbtuple *t)
-{
-	print("%s tag\n\t", tag);
-	for(; t != nil; t = t->entry){
-		print("%s=%s ", t->attr, t->val);
-		if(t->entry != t->line){
-			if(t->entry != nil)
-				print("\n\t");
-			else
-				print("\n");
-		}
-	}
-}
-#endif DEBUGGING
+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);
 
-/*
- *  reorder the tuple to put x's line first in the entry
- */
+/* make a filter to be used in filter */
 static Ndbtuple*
-reorder(Ndbtuple *t, Ndbtuple *x)
+mkfilter(int argc, char **argv)
 {
-	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;
+	Ndbtuple *t, *first, *last;
+	char *p;
 
-		/* reattach */
-		prev->entry = nt;
+	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 x;
+/* 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;
 }
 
-/*
- *  lookup an ip addresses
- */
+/* set the attribute of all entries in a tuple */
 static Ndbtuple*
-toipaddr(Ndb *db, Ndbtuple *t)
+setattr(Ndbtuple *t, char *attr)
 {
-	Ndbtuple *xt, *nt, **l;
-	char buf[Ndbvlen];
-	Ndbs s;
-	char *attr;
-
-	attr = ipattr(t->val);
-	if(strcmp(attr, "ip") == 0)
-		return t;
-
-	nt = ndbgetval(db, &s, attr, t->val, "ip", buf);
-	if(nt == nil)
-		return 0;
-	nt = reorder(nt, s.t);
-
-	/* throw out non ip twoples */
-	l = &nt;
-	while(*l != nil){
-		xt = *l;
-		if(strcmp(xt->attr, "ip") != 0){
-			/* unlink */
-			*l = xt->entry;
-			xt->entry = nil;
-
-			/* free */
-			ndbfree(xt);
-			continue;
-		}
-		strcpy(xt->attr, t->attr);
-		l = &xt->entry;
-	}
+	Ndbtuple *nt;
 
-	ndbfree(t);
-	return nt;
+	for(nt = t; nt; nt = nt->entry)
+		strcpy(nt->attr, attr);
+	return t;
 }
 
 /*
- *  Mine the entry for the desired attributes.  Longer masks
- *  take priority.
+ *  return only the attr/value pairs in t maching the filter, f.
+ *  others are freed.  line structure is preserved.
  */
 static Ndbtuple*
-mine(Ndb *db, Ndbtuple *t, Attr *a, int masklen, int *needed)
+filter(Ndb *db, Ndbtuple *t, Ndbtuple *f)
 {
-	Ndbtuple **l, *nt;
-
-	for(; a != nil; a = a->next){
-		for(l = &t; *l != nil;){
-			nt = *l;
-			if(strcmp(a->attr, nt->attr) != 0){
-				l = &nt->entry;
-				continue;
-			}
+	Ndbtuple *nt, *nf, *next;
 
-			if(a->first){
-				/* longer masks replace shorter */
-				if(masklen > a->masklen){
-					ndbfree(a->first);
-					a->first = nil;
-					a->last = nil;
-					(*needed)++;
-				} else if(a->masklen > masklen) {
-					l = &nt->entry;
-					continue;
-				}
-			}
+	/* filter out what we don't want */
+	for(nt = t; nt; nt = next){
+		next = nt->entry;
 
-			/* unchain tuple from t */
-			*l = nt->entry;
-			nt->entry = nil;
-
-			if(a->addronly)
-				nt = toipaddr(db, nt);
-			if(nt == nil)
-				continue;
-
-			/* chain tuple into the Attr */
-			if(a->last)
-				a->last->entry = nt;
-			else
-				a->first = nt;
-			while(nt->entry)
-				nt = nt->entry;
-			a->last = nt;
-			a->masklen = masklen;
-			(*needed)--;
+		/* 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;
 }
 
@@ -190,34 +113,35 @@ prefixlen(uchar *ip)
 }
 
 /*
- *  look for all networks whose masks are shorter than lastlen
- *  and whose IP address matches net.
+ *  look through a containing subset
  */
-static void
-subnet(Ndb *db, uchar *net, Attr *a, int prefix, int *needed)
+static Ndbtuple*
+subnet(Ndb *db, uchar *net, Ndbtuple *f, int prefix)
 {
 	Ndbs s;
-	Ndbtuple *t;
+	Ndbtuple *t, *nt;
 	char netstr[Ndbvlen];
 	char maskstr[Ndbvlen];
 	uchar mask[IPaddrlen];
 	int masklen;
 
+	t = nil;
 	sprint(netstr, "%I", net);
-	t = ndbsearch(db, &s, "ip", netstr);
-	while(t != nil){
-		if(ndblookval(t, t, "ipnet", maskstr) != nil){
-			if(ndblookval(t, t, "ipmask", maskstr))
+	nt = ndbsearch(db, &s, "ip", netstr);
+	while(nt != nil){
+		if(ndblookval(nt, nt, "ipnet", maskstr) != nil){
+			if(ndblookval(nt, nt, "ipmask", maskstr))
 				parseipmask(mask, maskstr);
 			else
 				ipmove(mask, defmask(net));
 			masklen = prefixlen(mask);
 			if(masklen <= prefix)
-				t = mine(db, t, a, masklen, needed);
-		}
-		ndbfree(t);
-		t = ndbsnext(&s, "ip", netstr);
+				t = ndbconcatenate(t, filter(db, nt, f));
+		} else
+			ndbfree(nt);
+		nt = ndbsnext(&s, "ip", netstr);
 	}
+	return t;
 }
 
 /*
@@ -229,13 +153,9 @@ subnet(Ndb *db, uchar *net, Attr *a, int prefix, int *needed)
 Ndbtuple*
 ndbipinfo(Ndb *db, char *attr, char *val, char **alist, int n)
 {
-	Ndbtuple *t, *nt, **lt;
+	Ndbtuple *t, *nt, *f;
 	Ndbs s;
-	char *p;
-	Attr *a, *list, **l;
-	int i, needed;
 	char ipstr[Ndbvlen];
-	uchar ip[IPaddrlen];
 	uchar net[IPaddrlen];
 	int prefix, smallestprefix;
 	int force;
@@ -245,63 +165,40 @@ ndbipinfo(Ndb *db, char *attr, char *val, char **alist, int n)
 	fmtinstall('M', eipfmt);
 
 	/* get needed attributes */
-	needed = 0;
-	l = &list;
-	for(i = 0; i < n; i++){
-		p = *alist++;
-		if(p == nil)
-			break;
-		a = mallocz(sizeof(*a), 1);
-		if(a == nil)
-			break;
-		if(*p == '@'){
-			a->addronly = 1;
-			p++;
-		}
-		a->attr = p;
-		*l = a;
-		l = &(*l)->next;
-		needed++;
-	}
+	f = mkfilter(n, alist);
 
 	/*
 	 *  first look for a matching entry with an ip address
 	 */
-	t = ndbgetval(db, &s, attr, val, "ip", ipstr);
-	if(t == nil){
+	t = nil;
+	nt = ndbgetval(db, &s, attr, val, "ip", ipstr);
+	if(nt == nil){
 		/* none found, make one up */
 		if(strcmp(attr, "ip") != 0)
 			return nil;
-		strncpy(ipstr, val, sizeof(ipstr)-1);
-		ip[sizeof(ip)-1] = 0;
-		t = malloc(sizeof(*t));
-		strcpy(t->attr, "ip");
-		strcpy(t->val, ipstr);
+		t = ndbnew("ip", val);
 		t->line = t;
 		t->entry = nil;
-		t = mine(db, t, list, 128, &needed);
-		ndbfree(t);
 	} else {
 		/* found one */
-		while(t != nil){
-			t = reorder(t, s.t);
-			t = mine(db, t, list, 128, &needed);
-			ndbfree(t);
-			t = ndbsnext(&s, attr, val);
+		while(nt != nil){
+			nt = ndbreorder(nt, s.t);
+			t = ndbconcatenate(t, nt);
+			nt = ndbsnext(&s, attr, val);
 		}
 	}
-	parseip(ip, ipstr);
-	ipmove(net, ip);
+	t = filter(db, t, f);
+	parseip(net, ipstr);
 
 	/*
 	 *  now go through subnets to fill in any missing attributes
 	 */
-	if(isv4(ip)){
+	if(isv4(net)){
 		prefix = 127;
 		smallestprefix = 100;
 		force = 0;
 	} else {
-		/* in v6, the last 8 bytes have no structure */
+		/* in v6, the last 8 bytes have no structure (we hope) */
 		prefix = 64;
 		smallestprefix = 2;
 		memset(net+8, 0, 8);
@@ -315,35 +212,15 @@ ndbipinfo(Ndb *db, char *attr, char *val, char **alist, int n)
 	 *  complete, we may need to find a trick to speed this up.
 	 */
 	for(; prefix >= smallestprefix; prefix--){
-		if(needed == 0)
+		if(filtercomplete(f))
 			break;
 		if(!force && (net[prefix/8] & (1<<(7-(prefix%8)))) == 0)
 			continue;
 		force = 0;
 		net[prefix/8] &= ~(1<<(7-(prefix%8)));
-		subnet(db, net, list, prefix, &needed);
-	}
-
-	/*
-	 *  chain together the results and free the list
-	 */
-	lt = &t;
-	while(list != nil){
-		a = list;
-		list = a->next;
-		*lt = a->first;
-		if(*lt == nil && strcmp(a->attr, "ipmask") == 0){
-			/* add a default ipmask if we need one */
-			*lt = mallocz(sizeof( Ndbtuple), 1);
-			strcpy((*lt)->attr, "ipmask");
-			snprint((*lt)->val, sizeof((*lt)->val), "%M", defmask(ip));
-		}
-		while(nt = *lt){
-			nt->line = nt->entry;
-			lt = &nt->entry;
-		}
-		free(a);
+		t = ndbconcatenate(t, subnet(db, net, f, prefix));
 	}
 
+	ndbfree(f);
 	return t;
 }

+ 16 - 3
sys/src/libndb/ndblookval.c

@@ -9,14 +9,18 @@
  *  then in the whole entry.
  */
 Ndbtuple*
-ndblookval(Ndbtuple *entry, Ndbtuple *line, char *attr, char *to)
+ndblookvalue(Ndbtuple *entry, Ndbtuple *line, char *attr, char *to, int len)
 {
 	Ndbtuple *nt;
 
 	/* first look on same line (closer binding) */
+	werrstr("");
 	for(nt = line;;){
 		if(strcmp(attr, nt->attr) == 0){
-			strncpy(to, nt->val, Ndbvlen);
+			strncpy(to, nt->val, len);
+			to[len-1] = 0;
+			if(strlen(nt->val) >= len)
+				werrstr("return value truncated");
 			return nt;
 		}
 		nt = nt->line;
@@ -27,8 +31,17 @@ ndblookval(Ndbtuple *entry, Ndbtuple *line, char *attr, char *to)
 	/* search whole tuple */
 	for(nt = entry; nt; nt = nt->entry)
 		if(strcmp(attr, nt->attr) == 0){
-			strncpy(to, nt->val, Ndbvlen);
+			strncpy(to, nt->val, len);
+			to[len-1] = 0;
+			if(strlen(nt->val) >= len)
+				werrstr("return value truncated");
 			return nt;
 		}
 	return 0;
 }
+
+Ndbtuple*
+ndblookval(Ndbtuple *entry, Ndbtuple *line, char *attr, char *to)
+{
+	return ndblookvalue(entry, line, attr, to, Ndbvlen);
+}

+ 53 - 0
sys/src/libndb/ndbreorder.c

@@ -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 - 0
sys/src/libndb/ndbsubstitute.c

@@ -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;
+}