hlfw.ca

registry

Download patch

ref: fc67b2fbbcfdbb28721d0217f21ead09ab6c279f
parent: e246a76f85e93963124f0420f437719b6b2c825c
author: halfwit <michaelmisch1985@gmail.com>
date: Thu Oct 12 01:38:55 PDT 2023

Update structure, add in some of svcfs

--- a/README.md
+++ /dev/null
@@ -1,102 +1,0 @@
-# Registry
-
-This is an interpretation of the Inferno Registry, for Plan9-like systems
-
-## Configuration
-
-Update your ipnet in /lib/ndb/local
-```
-ipnet=mynetwork ip=192.168.1.0 ipmask=255.255.255.0
-    ipgw=192.168.1.1
-    dns=1.1.1.1
-    auth=authy
-    registry=authy <---
-    fs=servy
-    cpu=crunchy
-```
-
-This is used by ndb/registry to find your network regfs
-
-Add the following to your /cfg/$sysname/cpurc, where $sysname matches what you entered above.
-
-```
-# Assuming you add a "registry" port mapping
-aux/svcfs -m /mnt/services /adm/services
-aux/listen1 -t tcp!*!registry /bin/exportfs -r /mnt/services
-```
-## Pieces
-
-Below are the main parts. Basic setup only requires an ndb/registry instance and ndb/regquery
-
-### aux/svcfs
-
-Usage: `aux/svcfs [-r] [-m mtpt] servicesfile`
-
-`svcfs` will periodically check a service is still alive with a gradual backoff, capping off at hourly.
-`svcfs` manages the contents of a file, `/adm/services`, which it will read in on startup
-It serves up on `/mnt/services`, making a new directory creates a new service,
-The dir contains many of the following files: 
- - addr
- - status (ok/down)
- - uptime
- - description
- - fd0/fd1 (?)
-
-Services may be read by anyone, but can only be modified by the creator or registry owner. Request must come from users in the same authdom.
-
-### ndb/registry 
-
-Usage: `ndb/registry [-r] [-s srvname]`
-- `-r` do not parse /cfg/$sysname/registry
-- `-s` Alternate address for Registry server
-
-Registry connects to a `svcfs`, by default checking for an entry in your local ipnet=. 
-It parses `/cfg/$sysname/registry`, an ndb-formatted list of local services. 
-
-```
-## /cfg/mysystem/registry
-
-# Local-only service, this is not written to the svcfs
-service=myservice
-    addr=tcp!myserver!19293
-    description='My local-only service'
-    local=true
-
-# Network-shared service, this is written to the svcfs
-service=mysharedservice
-    addr=tcp!myserver!19294
-    description='My shared service'
-```
-
-In addition to the above style of service tuples, we could also handle local pseudo-services:
-
-```
-service='!g'
-    addr=local!/bin/gcli
-    description='Search Google from the command line'
-    local=true
-
-service=plumber
-    addr=local!/srv/plumb
-    description='Local plumber instance'
-    local=true
-```
-
-The point of which is more for bookkeeping, populating menus in an automated way, etc
-
-### ndb/regquery 
-Usage: `nbd/regquery [-m mtpt] [-a] [query]`
-
-Connects to `mtpt`, by default at `/mnt/registry` and issues a search for the given query. If no value is passed in, all entries will be returned.
-
-- `-a` returns all services that match query, regardless of whether they are live or not
-
-Searches are for partial matches, searching for `"speaker"` will return `"outside-speaker-front"` and `"living-room-speaker"`, for example.
-
-### ndb/regdebug
-Like regquery, but issues queries directly to the given svcfs
-
-## Future
-- The code!
-- Libraries for services to publish services
-- Integration into `cpurc`
--- a/dns.h
+++ /dev/null
@@ -1,568 +1,0 @@
-#define NS2MS(ns) ((ns) / 1000000L)
-#define S2MS(s)   ((s)  * 1000LL)
-
-#define timems()	NS2MS(nsec())
-
-typedef struct Ndbtuple Ndbtuple;
-
-enum
-{
-	/* RR types; see: http://www.iana.org/assignments/dns-parameters */
-	Ta=		1,
-	Tns=		2,
-	Tmd=		3,
-	Tmf=		4,
-	Tcname=		5,
-	Tsoa=		6,
-	Tmb=		7,
-	Tmg=		8,
-	Tmr=		9,
-	Tnull=		10,
-	Twks=		11,
-	Tptr=		12,
-	Thinfo=		13,
-	Tminfo=		14,
-	Tmx=		15,
-	Ttxt=		16,
-	Trp=		17,
-	Tafsdb=		18,
-	Tx25=		19,
-	Tisdn=		20,
-	Trt=		21,
-	Tnsap=		22,
-	Tnsapptr=	23,
-	Tsig=		24,
-	Tkey=		25,
-	Tpx=		26,
-	Tgpos=		27,
-	Taaaa=		28,
-	Tloc=		29,
-	Tnxt=		30,
-	Teid=		31,
-	Tnimloc=	32,
-	Tsrv=		33,
-	Tatma=		34,
-	Tnaptr=		35,
-	Tkx=		36,
-	Tcert=		37,
-	Ta6=		38,
-	Tdname=		39,
-	Tsink=		40,
-	Topt=		41,
-	Tapl=		42,
-	Tds=		43,
-	Tsshfp=		44,
-	Tipseckey=	45,
-	Trrsig=		46,
-	Tnsec=		47,
-	Tdnskey=	48,
-
-	Tspf=		99,
-	Tuinfo=		100,
-	Tuid=		101,
-	Tgid=		102,
-	Tunspec=	103,
-
-	/* query types (all RR types are also queries) */
-	Ttkey=	249,	/* transaction key */
-	Ttsig=	250,	/* transaction signature */
-	Tixfr=	251,	/* incremental zone transfer */
-	Taxfr=	252,	/* zone transfer */
-	Tmailb=	253,	/* { Tmb, Tmg, Tmr } */
-	Tmaila= 254,	/* obsolete */
-	Tall=	255,	/* all records */
-
-	/* classes */
-	Csym=	0,	/* internal symbols */
-	Cin=	1,	/* internet */
-	Ccs,		/* CSNET (obsolete) */
-	Cch,		/* Chaos net */
-	Chs,		/* Hesiod (?) */
-
-	/* class queries (all class types are also queries) */
-	Call=	255,	/* all classes */
-
-	/* opcodes */
-	Oquery=		0<<11,		/* normal query */
-	Oinverse=	1<<11,		/* inverse query (retired) */
-	Ostatus=	2<<11,		/* status request */
-	Onotify=	4<<11,		/* notify slaves of updates */
-	Oupdate=	5<<11,
-	Omask=		0xf<<11,	/* mask for opcode */
-
-	/* response codes */
-	Rok=		0,
-	Rformat=	1,	/* format error */
-	Rserver=	2,	/* server failure (e.g. no answer from something) */
-	Rname=		3,	/* bad name */
-	Runimplimented=	4,	/* unimplemented */
-	Rrefused=	5,	/* we don't like you */
-	Ryxdomain=	6,	/* name exists when it should not */
-	Ryxrrset=	7,	/* rr set exists when it should not */
-	Rnxrrset=	8,	/* rr set that should exist does not */
-	Rnotauth=	9,	/* not authoritative */
-	Rnotzone=	10,	/* name not in zone */
-	Rbadvers=	16,	/* bad opt version */
-/*	Rbadsig=	16, */	/* also tsig signature failure */
-	Rbadkey=	17,		/* key not recognized */
-	Rbadtime=	18,		/* signature out of time window */
-	Rbadmode=	19,		/* bad tkey mode */
-	Rbadname=	20,		/* duplicate key name */
-	Rbadalg=	21,		/* algorithm not supported */
-	Rmask=		0x1f,	/* mask for response */
-	Rtimeout=	1<<5,	/* timeout sending (for internal use only) */
-
-	/* bits in flag word (other than opcode and response) */
-	Fresp=		1<<15,	/* message is a response */
-	Fauth=		1<<10,	/* true if an authoritative response */
-	Ftrunc=		1<<9,	/* truncated message */
-	Frecurse=	1<<8,	/* request recursion */
-	Fcanrec=	1<<7,	/* server can recurse */
-
-	Domlen=		256,	/* max domain name length (with NULL) */
-	Labellen=	64,	/* max domain label length (with NULL) */
-	Strlen=		256,	/* max string length (with NULL) */
-
-	/* time to live values (in seconds) */
-	Min=		60,
-	Hour=		60*Min,		/* */
-	Day=		24*Hour,	/* Ta, Tmx */
-	Week=		7*Day,		/* Tsoa, Tns */
-	Year=		52*Week,
-	DEFTTL=		Day,
-
-	/* reserved time (can't be timed out earlier) */
-	Reserved=	5*Min,
-
-	/* packet sizes */
-	Maxudp=		512,	/* maximum bytes per udp message sent */
-	Maxudpin=	2048,	/* maximum bytes per udp message rcv'd */
-
-	/* length of domain name hash table */
-	HTLEN= 		4*1024,
-
-	Maxpath=	128,	/* size of mntpt */
-	Maxlcks=	10,	/* max. query-type locks per domain name */
-	Maxauth=	16,	/* proto for auth */
-	Maxremote=	256,    /* For registry, if you're more popular than this... */
-	Maxmdns=	255,	/* Limits for mDNS messages */
-	Maxdial= 	271,	/* port + trns + !! + host */
-
-	RRmagic=	0xdeadbabe,
-	DNmagic=	0xa110a110,
-
-	/* parallelism: tune; was 32; allow lots */
-	Maxactive=	250,
-
-	/* tune; was 60*1000; keep it short */
-	Maxreqtm=	8*1000,	/* max. ms to process a request */
-
-	Notauthoritative = 0,
-	Authoritative,
-};
-
-typedef struct Area	Area;
-typedef struct Block	Block;
-typedef struct Cert	Cert;
-typedef struct DN	DN;
-typedef struct DNSmsg	DNSmsg;
-typedef struct Key	Key;
-typedef struct Null	Null;
-typedef struct RR	RR;
-typedef struct Request	Request;
-typedef struct SOA	SOA;
-typedef struct Server	Server;
-typedef struct Svc	Svc;
-typedef struct Sig	Sig;
-typedef struct Srv	Srv;
-typedef struct Txt	Txt;
-
-/*
- *  a structure to track a request and any slave process handling it
- */
-struct Request
-{
-	int	isslave;	/* pid of slave */
-	uvlong	aborttime;	/* time in ms at which we give up */
-	jmp_buf	mret;		/* where master jumps to after starting a slave */
-	int	id;
-	char	*from;		/* who asked us? */
-	void	*aux;
-};
-
-/*
- *  a domain name
- */
-struct DN
-{
-	DN	*next;		/* hash collision list */
-	ulong	magic;
-	char	*name;		/* owner */
-	RR	*rr;		/* resource records off this name */
-	ulong	referenced;	/* time last referenced */
-	ulong	ordinal;
-	ushort	class;		/* RR class */
-	uchar	respcode;	/* response code */
-	uchar	mark;		/* for mark and sweep */
-};
-
-/*
- *  security info
- */
-struct Block
-{
-	int	dlen;
-	uchar	*data;
-};
-struct Key
-{
-	int	flags;
-	int	proto;
-	int	alg;
-	Block;
-};
-struct Cert
-{
-	int	type;
-	int	tag;
-	int	alg;
-	Block;
-};
-struct Sig
-{
-	Cert;
-	int	labels;
-	ulong	ttl;
-	ulong	exp;
-	ulong	incep;
-	DN	*signer;
-};
-struct Null
-{
-	Block;
-};
-
-/*
- *  text strings
- */
-struct Txt
-{
-	Txt	*next;
-	char	*p;
-};
-
-/*
- * registry service
- */
-struct Svc
-{
-	int	id;		/* for server tracking */
-	Svc 	*next;
-	char	labl[Maxmdns];	/* Use mDNS limits */
-	char	host[Maxmdns];	/* host ip */
-	char	mtpt[Maxpath];
-	char	auth[Maxauth];
-	char	trns[16]; 	/* transport tcp/ssh/gopher/carrierpidgeon */
-	char	port[8];	/* 9fs, numerical, etc - switch to #? */
-	uchar	perm; 		/* flag: from db */
-};
-
-/*
- *  an unpacked resource record
- */
-struct RR
-{
-	RR	*next;
-	ulong	magic;
-	DN	*owner;		/* domain that owns this resource record */
-	uintptr	pc;		/* for tracking memory allocation */
-	ulong	ttl;		/* time to live to be passed on */
-	ulong	expire;		/* time this entry expires locally */
-	ulong	marker;		/* used locally when scanning rrlists */
-	ushort	type;		/* RR type */
-	ushort	query;		/* query type is in response to */
-	uchar	auth;		/* flag: authoritative */
-	uchar	db;		/* flag: from database */
-	uchar	cached;		/* flag: rr in cache */
-	uchar	negative;	/* flag: this is a cached negative response */
-
-	union {			/* discriminated by negative & type */
-		DN	*negsoaowner;	/* soa for cached negative response */
-		DN	*host;	/* hostname - soa, cname, mb, md, mf, mx, ns, srv */
-		DN	*cpu;	/* cpu type - hinfo */
-		DN	*mb;	/* mailbox - mg, minfo */
-		DN	*ip;	/* ip address - a, aaaa */
-		DN	*rp;	/* rp arg - rp */
-		uintptr	arg0;	/* arg[01] are compared to find dups in dn.c */
-	};
-	union {			/* discriminated by negative & type */
-		int	negrcode; /* response code for cached negative resp. */
-		DN	*rmb;	/* responsible maibox - minfo, soa, rp */
-		DN	*ptr;	/* pointer to domain name - ptr */
-		DN	*os;	/* operating system - hinfo */
-		ulong	pref;	/* preference value - mx */
-		ulong	local;	/* ns served from local database - ns */
-		ushort	port;	/* - srv */
-		uintptr	arg1;	/* arg[01] are compared to find dups in dn.c */
-	};
-	union {			/* discriminated by type */
-		SOA	*soa;	/* soa timers - soa */
-		Srv	*srv;
-		Key	*key;
-		Cert	*cert;
-		Sig	*sig;
-		Null	*null;
-		Txt	*txt;
-	};
-};
-
-/*
- *  list of servers
- */
-struct Server
-{
-	Server	*next;
-	char	*name;
-};
-
-/*
- *  timers for a start-of-authority record.  all ulongs are in seconds.
- */
-struct SOA
-{
-	ulong	serial;		/* zone serial # */
-	ulong	refresh;	/* zone refresh interval */
-	ulong	retry;		/* zone retry interval */
-	ulong	expire;		/* time to expiration */
-	ulong	minttl;		/* min. time to live for any entry */
-
-	Server	*slaves;	/* slave servers */
-};
-
-/*
- * srv (service location) record (rfc2782):
- * _service._proto.name ttl class(IN) 'SRV' priority weight port target
- */
-struct Srv
-{
-	ushort	pri;
-	ushort	weight;
-};
-
-typedef struct Rrlist Rrlist;
-struct Rrlist
-{
-	int	count;
-	RR	*rrs;
-};
-
-/*
- *  domain messages
- */
-struct DNSmsg
-{
-	ushort	id;
-	int	flags;
-	int	qdcount;	/* questions */
-	RR 	*qd;
-	int	ancount;	/* answers */
-	RR	*an;
-	int	nscount;	/* name servers */
-	RR	*ns;
-	int	arcount;	/* hints */
-	RR	*ar;
-};
-
-/*
- *  definition of local area for dblookup
- */
-struct Area
-{
-	Area	*next;
-
-	int	len;		/* strlen(area->soarr->owner->name) */
-	RR	*soarr;		/* soa defining this area */
-	int	neednotify;
-	int	needrefresh;
-};
-
-typedef struct Cfg Cfg;
-struct Cfg {
-	int	cachedb;
-	int	resolver;
-	int	justforw;	/* flag: pure resolver, just forward queries */
-	int	serve;		/* flag: serve udp queries */
-	int	inside;
-	int	straddle;
-};
-
-/* (udp) query stats */
-typedef struct {
-	QLock;
-	ulong	slavehiwat;	/* procs */
-	ulong	qrecvd9p;	/* query counts */
-	ulong	qrecvdudp;
-	ulong	qsent;
-	ulong	qrecvd9prpc;	/* packet count */
-	ulong	alarms;
-	/* reply times by count */
-	ulong	under10ths[3*10+2];	/* under n*0.1 seconds, n is index */
-	ulong	tmout;
-	ulong	tmoutcname;
-	ulong	tmoutv6;
-
-	ulong	answinmem;	/* answers in memory */
-	ulong	negans;		/* negative answers received */
-	ulong	negserver;	/* neg ans with Rserver set */
-	ulong	negbaddeleg;	/* neg ans with bad delegations */
-	ulong	negbdnoans;	/* ⋯ and no answers */
-	ulong	negnorname;	/* neg ans with no Rname set */
-	ulong	negcached;	/* neg ans cached */
-} Stats;
-
-Stats stats;
-
-enum
-{
-	Recurse,
-	Dontrecurse,
-	NOneg,
-	OKneg,
-};
-
-extern Cfg	cfg;
-extern char	*dbfile;
-extern int	debug;
-extern Area	*delegated;
-extern char	*logfile;
-extern int	maxage;		/* age of oldest entry in cache (secs) */
-extern char	mntpt[];
-extern int	needrefresh;
-extern int	norecursion;
-extern ulong	now;		/* time base */
-extern vlong	nowns;
-extern Area	*owned;
-extern int	sendnotifies;
-extern ulong	target;
-extern char	*trace;
-extern int	traceactivity;
-extern char	*zonerefreshprogram;
-extern Svc  	*registry;
-extern int 	rfd[Maxremote];
-
-#pragma	varargck	type	"R"	RR*
-#pragma	varargck	type	"Q"	RR*
-#pragma varargck 	type 	"G" 	Svc*
-#pragma varargck	type	"D"	Svc*
-#pragma varargck	type	"N"	Svc*
-
-/* dn.c */
-extern char	*rrtname[];
-extern char	*rname[];
-extern unsigned	nrname;
-extern char	*opname[];
-extern Lock	dnlock;
-
-void	abort(); /* char*, ... */;
-void	addserver(Server**, char*);
-Server*	copyserverlist(Server*);
-void	db2cache(int);
-void	dnage(DN*);
-void	dnageall(int);
-void	dnagedb(void);
-void	dnagenever(DN *);
-void	dnauthdb(void);
-void	dndump(char*);
-void	dninit(void);
-DN*	dnlookup(char*, int, int);
-DN*	idnlookup(char*, int, int);
-DN*	ipalookup(uchar*, int, int);
-void	dnptr(uchar*, uchar*, char*, int, int, int);
-void	dnpurge(void);
-void	dnslog(char*, ...);
-void	dnstats(char *file);
-void*	emalloc(int);
-char*	estrdup(char*);
-void	freeanswers(DNSmsg *mp);
-void	freeserverlist(Server*);
-int	getactivity(Request*, int);
-Area*	inmyarea(char*);
-void	putactivity(int);
-void	reg2cache(void);
-void	regconnect(void);
-char*	rstr2cache(char*, int);
-Svc*	rstr2svc(char*);
-char*	rstrdtch(char*);
-char*	rstrupdt(char*);
-RR*	randomize(RR*);
-void	reglog(char*, ...);
-RR*	rralloc(int);
-void	rrattach(RR*, int);
-int	rravfmt(Fmt*);
-RR*	rrcat(RR**, RR*);
-RR**	rrcopy(RR*, RR**);
-int	rrfmt(Fmt*);
-void	rrfree(RR*);
-void	rrfreelist(RR*);
-RR*	rrlookup(DN*, int, int);
-char*	rrname(int, char*, int);
-RR*	rrremneg(RR**);
-RR*	rrremtype(RR**, int);
-RR*	rrremowner(RR**, DN*);
-RR*	rrremfilter(RR**, int (*)(RR*, void*), void*);
-int	rrsupported(int);
-int	rrtype(char*);
-void	slave(Request*);
-int	subsume(char*, char*);
-int	tsame(int, int);
-void	unique(RR*);
-void	warning(char*, ...);
-
-
-/* dnarea.c */
-void	refresh_areas(Area*);
-void	freearea(Area**);
-void	addarea(DN *dp, RR *rp, Ndbtuple *t);
-
-/* dblookup.c */
-int	baddelegation(RR*, RR*, uchar*);
-RR*	dblookup(char*, int, int, int, int);
-RR*	dnsservers(int);
-RR*	domainlist(int);
-int	insideaddr(char *dom);
-int	insidens(uchar *ip);
-int	myip(uchar *ip);
-int	opendatabase(void);
-int	outsidensip(int, uchar *ip);
-
-/* dns.c */
-char*	walkup(char*);
-RR*	getdnsservers(int);
-void	logreply(int, uchar*, DNSmsg*);
-void	logsend(int, int, uchar*, char*, char*, int);
-
-/* dnresolve.c */
-RR*	dnresolve(char*, int, int, Request*, RR**, int, int, int, int*);
-int	udpport(char *);
-int	mkreq(DN *dp, int type, uchar *buf, int flags, ushort reqno);
-int	seerootns(void);
-void	initdnsmsg(DNSmsg *mp, RR *rp, int flags, ushort reqno);
-
-/* dnserver.c */
-void	dnserver(DNSmsg*, DNSmsg*, Request*, uchar *, int);
-void	dnudpserver(char*);
-
-/* dnnotify.c */
-void	dnnotify(DNSmsg*, DNSmsg*, Request*);
-void	notifyproc(void);
-
-/* reglookup.c */
-int	openregistry(void);
-
-/* convDNS2M.c */
-int	convDNS2M(DNSmsg*, uchar*, int);
-
-/* convM2DNS.c */
-char*	convM2DNS(uchar*, int, DNSmsg*, int*);
-
-#pragma varargck argpos dnslog 1
--- a/lib/reglookup.c
+++ /dev/null
@@ -1,213 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <ndb.h>
-#include "dns.h"
-
-static Ndb	*db;
-static QLock	dblock;
-
-int
-openregistry(void)
-{
-	if(db != nil)
-		return 0;
-
-	db = ndbopen(dbfile);
-	return db!=nil ? 0: -1;
-}
-
-static void
-attach(Svc* svc, int persist)
-{
-	svc->perm = !!persist;
-
-	if(registry != nil){
-		svc->next = registry;
-	}
-
-	svc->next = registry;
-	registry = svc;
-}
-
-static char*
-detach(char *dial)
-{
-	Svc *c, *last = 0;
-	char buf[Maxdial]; /* trns is capped at 16, port 8 */
-
-	for(c = registry; c; c = c->next){
-		snprint(buf, Maxdial, "%s!%s!%s", c->trns, c->host, c->port);
-		if(strcmp(buf, dial)==0){
-			if(last == 0)
-				registry = c->next;
-			else
-				last->next = c->next;
-			free(c);
-			return 0;
-		}
-		last = c;
-	}
-
-	return "found no matching service";
-}
-
-static void
-host2svc(Svc *svc, char *dial)
-{
-	int n;
-
-	/* 
-	 * entry host=tcp!mything!9fs
-	 * for now, tokenize but we should allow short strings
-     */
-	n = strcspn(dial, "!");
-	if(n < 1)
-		strcpy(svc->trns, "tcp");
-	else
-		strecpy(svc->trns, svc->trns+n+1, dial);
-	dial = dial + n + 1;
-
-	n = strcspn(dial, "!");
-	strecpy(svc->host, svc->host+n+1, dial);
-
-	dial = dial + n + 1;
-	if(sizeof(dial) < 1)
-		strcpy(svc->port, "9fs");
-	else if(sizeof(dial) > 8)
-		/* If this starts happening, we should bump the number */
-		strecpy(svc->port, svc->port + 8, dial);
-	else
-		strcpy(svc->port, dial);
-}
-
-static void
-dbtuple2cache(Ndbtuple *t, int persist)
-{
-	Ndbtuple *et, *nt;
-	Svc *svc;
-
-
-	for(et = t; et; et = et->entry)
-		if(strncmp(et->attr, "serv", 4)==0){
-			svc = emalloc(sizeof(*svc));
-			host2svc(svc, et->val);
-			for(nt = et->entry; nt; nt = nt->entry)
-				if(strcmp(nt->attr, "label")==0)
-					strecpy(svc->labl, svc->labl+Maxmdns, nt->val);
-				else if(strcmp(nt->attr, "auth")==0)
-					strecpy(svc->auth, svc->auth+Maxauth, nt->val);
-				else if(strcmp(nt->attr, "mtpt")==0)
-					strecpy(svc->mtpt, svc->mtpt+Maxpath, nt->val);
-			attach(svc, persist);
-		};
-}
-
-static void
-dbfile2cache(Ndb *db)
-{
-	Ndbtuple *t;
-
-	if(debug)
-		reglog("reading %s", db->file);
-	Bseek(&db->b, 0, 0);
-	while(t = ndbparse(db)){
-		dbtuple2cache(t, 1);
-		ndbfree(t);
-	}
-
-
-}
-
-Svc*
-rstr2svc(char *entry)
-{
-	Svc *svc;
-	char *args[7];
-	
-	int i, n;
-
-	n = tokenize(entry, args, 7);
-
-	svc = emalloc(sizeof(*svc));
-	host2svc(svc, estrdup(args[0]));
-
-	for(i = 1; i < n - 1; i++)
-		if(strcmp(args[i], "label")==0)	
-			strecpy(svc->labl, svc->labl+Maxmdns, args[++i]);
-		else if(strcmp(args[i], "auth")==0)
-			strecpy(svc->auth, svc->auth+Maxauth, args[++i]);
-		else if(strcmp(args[i], "mtpt")==0)
-			strecpy(svc->mtpt, svc->mtpt+Maxpath, args[++i]);
-
-	return svc;
-}
-
-char*
-rstr2cache(char *entry, int persist)
-{
-	Svc *svc;
-
-	svc = rstr2svc(entry);
-	attach(svc, persist);
-	return 0;
-}
-
-char*
-rstrdtch(char *svc)
-{
-	return detach(svc);
-}
-
-/* e.g. update tcp!foo!9fs label newlabel */
-char*
-rstrupdt(char *entry)
-{
-	Svc *c, *svc = 0;
-	char *args[7], buf[Maxdial];
-	int i, n;
-
-	n = tokenize(entry, args, 7);
-
-	/* Find our service */
-	for(c = registry; c; c = c->next){
-		snprint(buf, Maxdial, "%s!%s!%s", c->trns, c->host, c->port);
-		if(strcmp(buf, args[0])==0){
-			svc = c;
-			break;
-		}
-	}
-	
-	if(svc == 0)
-		return "found no matching service";
-
-	for(i = 1; i < n - 1; i++)
-		if(strcmp(args[i], "label")==0)
-			strecpy(svc->labl, svc->labl+Maxmdns, args[++i]);
-		else if(strcmp(args[i], "auth")==0)
-			strecpy(svc->auth, svc->auth+Maxauth, args[++i]);
-		else if(strcmp(args[i], "mtpt")==0)
-			strecpy(svc->mtpt, svc->mtpt+Maxpath, args[++i]);
-
-	return 0;
-}
-
-void
-reg2cache(void)
-{
-	Ndb *ndb;
-	
-	qlock(&dblock);
-	if(openregistry() < 0){
-		qunlock(&dblock);
-		return;
-	}
-	
-	if(debug)
-		syslog(0, logfile, "building cache from db");
-			
-	for(ndb = db; ndb; ndb = ndb->next)
-		dbfile2cache(ndb);
-
-	qunlock(&dblock);
-}
--- a/mkfile
+++ /dev/null
@@ -1,16 +1,0 @@
-# registry mkfile
-</$objtype/mkfile
-
-TARG =	\
-	registry\
-	regquery\
-
-HFILES = dns.h /$objtype/lib/libndb.a
-
-BIN=/$objtype/bin/ndb
-
-</sys/src/cmd/mkmany
-
-$O.registry: registry.$O reglookup.$O
-	$LD -o $target $prereq
-
--- a/ndb/registry.c
+++ /dev/null
@@ -1,967 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <auth.h>
-#include <fcall.h>
-#include <bio.h>
-#include <ip.h>
-#include "dns.h"
-
-enum
-{
-	Maxrequest=		1024,
-	Maxreply=		8192,
-	Maxrecords=		192,
-	Maxfdata=		8192,
-
-	Qdir=			0,
-	Qreg=			1,
-};
-
-typedef struct Mfile	Mfile;
-typedef struct Job	Job;
-typedef struct Records  Records;
-
-struct Mfile
-{
-	Mfile	*next;
-
-	char	*user;
-	Qid	qid;
-	int	fid;
-	int	bare;
-
-	char	reply[Maxreply];
-	ushort	rr[Maxrecords]; /* offset of record */
-	ushort	nrr;		/* number of records */	
-};
-
-/*
- *  active requests
- */
-struct Job
-{
-	Job	*next;
-	int	flushed;
-	Fcall	request;
-	Fcall	reply;
-};
-Lock	joblock;
-Job	*joblist;
-
-struct {
-	Lock;
-	Mfile	*inuse;		/* active mfile's */
-} mfalloc;
-
-Svc	*registry;
-int	vers;
-int	debug;
-char	*dbfile = "/lib/ndb/registry";
-char	*reguser;
-char	mtpt[Maxpath];
-int	rfd[Maxremote];
-int	mfd[2];
-char	*logfile = "registry";
-
-void	rversion(Job*);
-void	rflush(Job*);
-void	rattach(Job*, Mfile*);
-char*	rwalk(Job*, Mfile*);
-void	ropen(Job*, Mfile*);
-void	rcreate(Job*, Mfile*);
-void	rread(Job*, Mfile*);
-void	rwrite(Job*, Mfile*);
-void	rclunk(Job*, Mfile*);
-void	rremove(Job*, Mfile*);
-void	rstat(Job*, Mfile*);
-void	rwstat(Job*, Mfile*);
-void	rauth(Job*);
-void	mountinit(char*, char*);
-void	setext(char*, int, char*);
-void	io(void);
-
-static char*	resolve(char*, ...);
-static char*	addsvc(char*);
-static char*	rmsvc(char*);
-static char*	updatesvc(char*);
-static void	refresh(void);
-static void	regdump(char*);
-static void	sendmsg(Job*, char*);
-
-static int	scanfmt(Fmt*);
-static int	srvfmt(Fmt*);
-static int	dumpfmt(Fmt*);
-
-static char* query(Job*, Mfile*, char*, int);
-static char* resolvequery(Job*, Mfile*, char*, int);
-
-void
-usage(void)
-{
-	fprint(2, "usage: %s [-xrd] [-f ndb-file]\n", argv0);
-	exits("usage");
-}
-
-void
-main(int argc, char* argv[])
-{
-	char servefile[Maxpath], ext[Maxpath];
-	Dir *dir;
-	ext[0] = 0;
-
-	setnetmtpt(mtpt, sizeof mtpt, nil);
-
-	ARGBEGIN{
-	case 'd':
-		debug = 1;
-		break;
-	case 'f':
-		dbfile = EARGF(usage());
-		break;
-	case 'x':
-		setnetmtpt(mtpt, sizeof mtpt, EARGF(usage()));
-		setext(ext, sizeof ext, mtpt);
-		break;
-	} ARGEND;
-	if(argc != 0)
-		usage();
-    
-
-
-	rfork(RFREND|RFNOTEG);
-
-	fmtinstall('F', fcallfmt);
-	fmtinstall('G', srvfmt);
-	fmtinstall('N', scanfmt);
-	fmtinstall('D', dumpfmt);
-
-	reglog("starting registry on %s", mtpt);
-
-	if(openregistry())
-		sysfatal("unable to open db file");
-
-	reguser = estrdup(getuser());
-	seprint(servefile, servefile+Maxpath, "#s/registry%s", ext);
-	
-	dir = dirstat(servefile);
-	if (dir)
-		sysfatal("%s exists; another registry instance is running", servefile);
-	free(dir);
-
-	mountinit(servefile, mtpt);
-	reg2cache();
-	io();
-
-	_exits(0);
-}
-
-void
-setext(char *ext, int n, char *p)
-{
-	int i, c;
-
-	n--;
-	for(i = 0; i < n; i++){
-		c = p[i];
-		if(c == 0)
-			break;
-		if(c == '/')
-			c = '_';
-		ext[i] = c;
-	}
-	ext[i] = 0;
-}
-
-void
-mountinit(char *service, char *mtpt)
-{
-	int f;
-	int p[2];
-	char buf[32];
-
-	if(pipe(p) < 0)
-		sysfatal("pipe failed: %r");
-
-	/*
-	 *  make a /srv/registry
-	 */
-	if((f = create(service, OWRITE|ORCLOSE, 0666)) < 0)
-		sysfatal("create %s failed: %r", service);
-	snprint(buf, sizeof buf, "%d", p[1]);
-	if(write(f, buf, strlen(buf)) != strlen(buf))
-		sysfatal("write %s failed: %r", service);
-
-	/* copy namespace to avoid a deadlock */
-	switch(rfork(RFFDG|RFPROC|RFNAMEG)){
-	case 0:			/* child: start main proc */
-		close(p[1]);
-		procsetname("%s", mtpt);
-		break;
-	case -1:
-		sysfatal("fork failed: %r");
-	default:		/* parent: make /srv/registry, mount it, exit */
-		close(p[0]);
-
-		/*
-		 *  put ourselves into the file system
-		 */
-		if(mount(p[1], -1, mtpt, MAFTER, "") < 0)
-			fprint(2, "registry mount failed: %r\n");
-		_exits(0);
-	}
-	mfd[0] = mfd[1] = p[0];
-}
-
-Mfile*
-newfid(int fid, int needunused)
-{
-	Mfile *mf;
-
-	lock(&mfalloc);
-	for(mf = mfalloc.inuse; mf != nil; mf = mf->next)
-		if(mf->fid == fid){
-			unlock(&mfalloc);
-			if(needunused)
-				return nil;
-			return mf;
-		}
-	mf = emalloc(sizeof(*mf));
-	mf->fid = fid;
-	mf->qid.vers = vers;
-	mf->qid.type = QTDIR;
-	mf->qid.path = 0LL;
-	mf->user = estrdup(reguser);
-	mf->next = mfalloc.inuse;
-	mfalloc.inuse = mf;
-	mf->bare = 1;
-	unlock(&mfalloc);
-	return mf;
-}
-
-void
-freefid(Mfile *mf)
-{
-	Mfile **l;
-
-	lock(&mfalloc);
-	for(l = &mfalloc.inuse; *l != nil; l = &(*l)->next)
-		if(*l == mf){
-			*l = mf->next;
-			free(mf->user);
-			memset(mf, 0, sizeof *mf);	/* cause trouble */
-			free(mf);
-			unlock(&mfalloc);
-			return;
-		}
-	unlock(&mfalloc);
-	sysfatal("freeing unused fid");
-}
-
-Mfile*
-copyfid(Mfile *mf, int fid)
-{
-	Mfile *nmf;
-
-	nmf = newfid(fid, 1);
-	if(nmf == nil)
-		return nil;
-	nmf->fid = fid;
-	free(nmf->user);
-	nmf->user = estrdup(mf->user);
-	nmf->qid.type = mf->qid.type;
-	nmf->qid.path = mf->qid.path;
-	nmf->qid.vers = vers++;
-	return nmf;
-}
-
-Job*
-newjob(void)
-{
-	Job *job;
-
-	job = emalloc(sizeof *job);
-	lock(&joblock);
-	job->next = joblist;
-	joblist = job;
-	job->request.tag = -1;
-	unlock(&joblock);
-	return job;
-}
-
-void
-freejob(Job *job)
-{
-	Job **l;
-
-	lock(&joblock);
-	for(l = &joblist; *l; l = &(*l)->next)
-		if(*l == job){
-			*l = job->next;
-			memset(job, 0, sizeof *job);	/* cause trouble */
-			free(job);
-			break;
-		}
-	unlock(&joblock);
-}
-
-void
-flushjob(int tag)
-{
-	Job *job;
-
-	lock(&joblock);
-	for(job = joblist; job; job = job->next)
-		if(job->request.tag == tag && job->request.type != Tflush){
-			job->flushed = 1;
-			break;
-		}
-	unlock(&joblock);
-}
-
-void
-io(void)
-{
-	long n;
-	Mfile *mf;
-	uchar mdata[IOHDRSZ + Maxfdata];
-	Job *job;
-
-	while((n = read9pmsg(mfd[0], mdata, sizeof mdata)) != 0){
-		if(n < 0){
-			syslog(1, logfile, "error reading 9P from %s: %r", mtpt);
-			break;
-		}
-
-		job = newjob();
-		if(convM2S(mdata, n, &job->request) != n){
-			reglog("format error %ux %ux %ux %ux %ux",
-				mdata[0], mdata[1], mdata[2], mdata[3], mdata[4]);
-			freejob(job);
-			break;
-		}
-		mf = newfid(job->request.fid, 0);
-		if(debug)
-			reglog("%F", &job->request);
-
-		switch(job->request.type){
-		default:
-			warning("unknown request type %d", job->request.type);
-			break;
-		case Tversion:
-			rversion(job);
-			break;
-		case Tauth:
-			rauth(job);
-			break;
-		case Tflush:
-			rflush(job);
-			break;
-		case Tattach:
-			rattach(job, mf);
-			break;
-		case Twalk:
-			rwalk(job, mf);
-			break;
-		case Topen:
-			ropen(job, mf);
-			break;
-		case Tcreate:
-			rcreate(job, mf);
-			break;
-		case Tread:
-			rread(job, mf);
-			break;
-		case Twrite:
-			rwrite(job, mf);
-			break;
-		case Tclunk:
-			rclunk(job, mf);
-			break;
-		case Tremove:
-			rremove(job, mf);
-			break;
-		case Tstat:
-			rstat(job, mf);
-			break;
-		case Twstat:
-			rwstat(job, mf);
-			break;
-		}
-
-		freejob(job);
-	}
-}
-
-void
-rversion(Job *job)
-{
-	if(job->request.msize > IOHDRSZ + Maxfdata)
-		job->reply.msize = IOHDRSZ + Maxfdata;
-	else
-		job->reply.msize = job->request.msize;
-	job->reply.version = "9P2000";
-	if(strncmp(job->request.version, "9P", 2) != 0)
-		job->reply.version = "unknown";
-	sendmsg(job, nil);
-}
-
-void
-rauth(Job *job)
-{
-	sendmsg(job, "registry: authentication not required");
-}
-
-void
-rflush(Job *job)
-{
-	flushjob(job->request.oldtag);
-	sendmsg(job, 0);
-}
-
-void
-rattach(Job *job, Mfile *mf)
-{
-	if(mf->user != nil)
-		free(mf->user);
-	mf->user = estrdup(job->request.uname);
-	mf->qid.vers = vers++;
-	mf->qid.type = QTDIR;
-	mf->qid.path = 0LL;
-	job->reply.qid = mf->qid;
-	sendmsg(job, 0);
-}
-
-char*
-rwalk(Job *job, Mfile *mf)
-{
-	int i, nelems;
-	char *err;
-	char **elems;
-	Mfile *nmf;
-	Qid qid;
-
-	err = 0;
-	nmf = nil;
-	elems = job->request.wname;
-	nelems = job->request.nwname;
-	job->reply.nwqid = 0;
-
-	if(job->request.newfid != job->request.fid){
-		/* clone fid */
-		nmf = copyfid(mf, job->request.newfid);
-		if(nmf == nil){
-			err = "clone bad newfid";
-			goto send;
-		}
-		mf = nmf;
-	}
-	/* else nmf will be nil */
-
-	qid = mf->qid;
-	if(nelems > 0){
-		/* walk fid */
-		for(i=0; i<nelems && i<MAXWELEM; i++){
-			if((qid.type & QTDIR) == 0){
-				err = "not a directory";
-				break;
-			}
-			if(strcmp(elems[i], "..") == 0 || strcmp(elems[i], ".") == 0){
-				qid.type = QTDIR;
-				qid.path = Qdir;
-    Found:
-				job->reply.wqid[i] = qid;
-				job->reply.nwqid++;
-				continue;
-			}
-			if(strcmp(elems[i], "registry") == 0){
-				qid.type = QTFILE;
-				qid.path = Qreg;
-				goto Found;
-			}
-			err = "file does not exist";
-			break;
-		}
-	}
-
-    send:
-	if(nmf != nil && (err!=nil || job->reply.nwqid<nelems))
-		freefid(nmf);
-	if(err == nil)
-		mf->qid = qid;
-	sendmsg(job, err);
-	return err;
-}
-
-void
-ropen(Job *job, Mfile *mf)
-{
-	int mode;
-	char *err;
-
-	err = 0;
-	mode = job->request.mode;
-	if(mf->qid.type & QTDIR)
-		if(mode)
-			err = "permission denied";
-	job->reply.qid = mf->qid;
-	job->reply.iounit = 0;
-	sendmsg(job, err);
-}
-
-void
-rcreate(Job *job, Mfile *mf)
-{
-	USED(mf);
-	sendmsg(job, "creation permission denied");
-}
-
-void rclunk(Job *job, Mfile *mf)
-{
-	freefid(mf);
-	sendmsg(job, 0);
-}
-
-void
-rremove(Job *job, Mfile *mf)
-{
-	USED(mf);
-	sendmsg(job, "remove permission denied");
-}
-
-void 
-rread(Job *job, Mfile *mf)
-{
-	int i, n;
-	long clock;
-	ulong cnt;
-	vlong off;
-	char *err;
-	uchar buf[Maxfdata];
-	Dir dir;
-
-	n = 0;
-	err = nil;
-	off = job->request.offset;
-	cnt = job->request.count;
-	*buf = '\0';
-	job->reply.data = (char*)buf;
-	if(mf->qid.type & QTDIR){
-		clock = time(nil);
-		if(off == 0){
-			memset(&dir, 0, sizeof dir);
-			dir.name = "registry";
-			dir.qid.type = QTFILE;
-			dir.qid.vers = vers;
-			dir.qid.path = Qreg;
-			dir.mode = 0666;
-			dir.length = 0;
-			dir.uid = dir.gid = dir.muid = mf->user;
-			dir.atime = dir.mtime = clock;
-			n = convD2M(&dir, buf, sizeof buf);
-		}
-	} else if (off < 0)
-		err = "negative read offset";
-	else {
-		if(mf->bare)
-			query(job, mf, "all", 0);
-		for(i = 1; i < mf->nrr; i++)
-			if(mf->rr[i] > off)
-				break;
-		if(i <= mf->nrr){
-			if(off + cnt > mf->rr[i])
-				n = mf->rr[i] - off;
-			else
-				n = cnt;
-			assert(n >= 0);
-			job->reply.data = mf->reply + off;
-		}
-	}
-	job->reply.count = n;
-	sendmsg(job, err);	
-}
-
-void 
-rwrite(Job *job, Mfile *mf)
-{
-	int send, pipe2rc;
-	ulong cnt;	
-	char *err, *atype;
-	char errbuf[ERRMAX];
-	
-	err = nil;
-	cnt = job->request.count;
-	send = 1;
-	if(mf->qid.type & QTDIR)
-		err = "can't write directory";
-	else if (job->request.offset != 0)
-		err = "writing at non-zero offset";
-	else if (cnt >= Maxrequest)
-		err = "request too long";
-	else
-		send = 0;
-	if(send)
-		goto send;
-
-	job->request.data[cnt] = 0;
-	if(cnt > 0 && job->request.data[cnt-1] == '\n')
-		job->request.data[cnt-1] = 0;
-
-	if(strcmp(mf->user, "none") == 0 || strcmp(mf->user, reguser) != 0)
-		goto query; /* We don't want remote clients to modify our local */
-
-	/*
-	 * special commands
-	 */
-	send = 1;
-	if(strcmp(job->request.data, "debug")==0)
-		debug ^= 1;
-	else if(strcmp(job->request.data, "dump")==0)
-		regdump("/lib/ndb/regdump");
-	else if (strcmp(job->request.data, "refresh")==0)
-		refresh();
-	else if (strncmp(job->request.data, "add ", 4)==0)
-		err = addsvc(job->request.data + 4);
-	else if (strncmp(job->request.data, "rm ", 3)==0)
-		err = rmsvc(job->request.data + 3);
-	else if (strncmp(job->request.data, "update ", 7)==0)
-		err = updatesvc(job->request.data + 7);
-	else
-		send = 0;
-	if (send)
-		goto send;
-
-query:
-	/*
-	 *	kill previous reply
-	 */
-	mf->nrr = 0;
-	mf->rr[0] = 0;
-	pipe2rc = 0;
-	
-	atype = strchr(job->request.data, ' ');
-	if(atype == 0){
-		snprint(errbuf, sizeof errbuf, "illegal request %s", job->request.data);
-		err = errbuf;
-		goto send;
-	} else
-		*atype++ = 0;
-
-	if(strcmp(atype, "svc") == 0)
-		pipe2rc++;
-	else if(strcmp(atype, "scan") != 0){
-		snprint(errbuf, sizeof errbuf, "unknown query %s", atype);
-		err = errbuf;
-		goto send;
-	}
-
-	err = query(job, mf,job->request.data, pipe2rc);
-send:
-	mf->bare = 0;
-	job->reply.count = cnt;
-	sendmsg(job, err);
-}
-
-void
-rstat(Job *job, Mfile *mf)
-{
-	Dir dir;
-	uchar buf[IOHDRSZ+Maxfdata];
-	
-	memset(&dir, 0, sizeof dir);
-	if(mf->qid.type & QTDIR){
-		dir.name = ".";
-		dir.mode = DMDIR|0555;
-	}else{
-		dir.name = "registry";
-		dir.mode = 0666;
-	}
-	dir.qid = mf->qid;
-	dir.length = 0;
-	dir.uid = dir.gid = dir.muid = mf->user;
-	dir.atime = dir.mtime = time(nil);
-	job->reply.nstat = convD2M(&dir, buf, sizeof buf);
-	job->reply.stat = buf;
-	sendmsg(job, 0);
-}
-
-void
-rwstat(Job *job, Mfile *mf)
-{
-	USED(mf);
-	sendmsg(job, "wstat permission denied");
-}
-
-static char *
-resolvequery(Job *job, Mfile *mf, char *p, int pipe2rc)
-{
-	int match, i;
-	int n;
-	Svc *c;
-
-	char cmd[256];
-	char buf[8192+1];
-
-	lock(&joblock);
-	if(!job->flushed){
-		match = n = 0;
-		mf->nrr = 0;
-
-		snprint(cmd, sizeof(cmd), "%s %s", p, ((pipe2rc)?"svc":"scan"));
-
-		for(i = 0; i < Maxremote && !match && rfd[i] > 1; i++){
-			seek(rfd[i], 0, 0);
-			write(rfd[i], cmd, sizeof cmd);
-
-			seek(rfd[i], 0, 0);
-			while(read(rfd[i], buf, sizeof(buf)-1) > 0){	
-				match = 1;
-				c = rstr2svc(buf);
-				mf->rr[mf->nrr++] = n;
-				if(pipe2rc)
-					n += snprint(mf->reply+n, Maxreply-n, "%G", c);
-				else
-					n += snprint(mf->reply+n, Maxreply-n, "%N", c);
-				free(c);
-			}
-		}
-	}
-	unlock(&joblock);
-
-	return 0;
-}
-
-static char *
-query(Job *job, Mfile *mf, char *p, int pipe2rc)
-{
-	int n;
-
-	Svc *c;
-	lock(&joblock);
-	if(!job->flushed){
-		n = 0;
-		mf->nrr = 0;
-		for(c = registry; c && n < Maxreply; c = c->next)
-			if((strncmp(p, c->labl, strlen(p))==0) || (strcmp(p, "all")==0)){
-				mf->rr[mf->nrr++] = n;
-				if(pipe2rc)
-					n += snprint(mf->reply+n, Maxreply-n, "%G", c);
-				else
-					n += snprint(mf->reply+n, Maxreply-n, "%N", c);
-			}
-		mf->rr[mf->nrr] = n;
-	}
-	unlock(&joblock);
-	return nil;
-}
-
-static void
-sendmsg(Job *job, char *err)
-{
-	int n;
-	uchar mdata[IOHDRSZ+Maxfdata];
-	char ename[ERRMAX];
-
-	if(err){
-		job->reply.type = Rerror;
-		snprint(ename, sizeof ename, "registry: %s", err);
-		job->reply.ename = ename;
-	}else
-		job->reply.type = job->request.type+1;
-	job->reply.tag = job->request.tag;
-	n = convS2M(&job->reply, mdata, sizeof mdata);
-	if(n == 0){
-		warning("sendmsg convS2M of %F returns 0", &job->reply);
-		abort();
-	}
-	lock(&joblock);
-	if(job->flushed == 0)
-		if(write(mfd[1], mdata, n)!=n)
-			sysfatal("mount write");
-	unlock(&joblock);
-	if(debug)
-		reglog("%F %d", &job->reply, n);
-}
-
-static void
-regdump(char *file)
-{
-	Svc *rp;
-	int fd;
-
-	fd = create(file, OWRITE, 0666);
-	if(fd < 0)
-		return;
-	lock(&mfalloc);
-	for(rp = registry; rp; rp = rp->next)
-		fprint(fd, "%D\n\n", rp);
-	unlock(&mfalloc);
-	close(fd);
-}
-
-static void
-refresh(void)
-{	
-	Svc *c;
-	char dial[Maxdial];
-
-	for(c = registry; c; c = c->next){
-		/* Don't remove the ones we've added since startup */
-		if(!c->perm)
-			continue;
-		snprint(dial, Maxdial, "%s!%s!%s", c->trns, c->host, c->port);
-		rmsvc(dial);
-		/* Reset so we don't have messy loops */
-		c = registry;
-	}
-	reg2cache();
-}
-
-static char *
-resolve(char *cmd, ...)
-{
-	int n;
-	char fullcmd[256];
-	char buf[8192+1];
-	va_list arg;
-	
-	va_start(arg, cmd);
-	vseprint(fullcmd, fullcmd+sizeof(fullcmd), cmd, arg);
-	va_end(arg);
-
-	/* We only operate on our local rfd */
-	seek(rfd[0], 0, 0);
-	write(rfd[0], fullcmd, sizeof fullcmd);
-
-	seek(rfd[0], 0, 0);
-	while((n = read(rfd[0], buf, sizeof(buf)-1)) > 0){
-		buf[n++] = '\n';
-		write(1, buf, n);
-	}
-	return buf;
-}
-
-static char *
-addsvc(char *args)
-{
-	if(debug)
-		reglog("Adding entry: %s", args);
-
-	return rstr2cache(args, 0);
-}
-
-static char *
-rmsvc(char *args)
-{
-	if(debug)
-		reglog("Removing entry: %s", args);
-	return rstrdtch(args);
-}
-
-static char *
-updatesvc(char *args)
-{
-	if(debug)
-		reglog("Updating entry: %s", args);
-	return rstrupdt(args);
-}
-
-void
-warning(char *fmt, ...)
-{
-	char regerr[256];
-	va_list arg;
-
-	va_start(arg, fmt);
-	vseprint(regerr, regerr+sizeof(regerr), fmt, arg);
-	va_end(arg);
-	syslog(1, logfile, regerr);
-}
-
-void
-reglog(char *fmt, ...)
-{
-	char regerr[256];
-	va_list arg;
-	
-	va_start(arg, fmt);
-	vseprint(regerr, regerr+sizeof(regerr), fmt, arg);
-	va_end(arg);
-	syslog(0, logfile, regerr);
-}
-
-void*
-emalloc(int size)
-{
-	void *x;
-
-	x = malloc(size);
-	if(x == nil)
-		sysfatal("out of memory");
-	memset(x, 0, size);
-	return x;
-}
-
-char*
-estrdup(char *s)
-{
-	int size;
-	char *p;
-
-	size = strlen(s);
-	p = malloc(size+1);
-	if(p == nil)
-		sysfatal("out of memory");
-	memmove(p, s, size);
-	p[size] = 0;
-	return p;
-}
-
-static int
-srvfmt(Fmt *f)
-{
-	Svc *r;
-	char mf[Maxpath+1], auth[7];
-	
-	r = va_arg(f->args, Svc*);
-	mf[0] = 0;
-	auth[0] = 0;
-		
-	if(strcmp(r->mtpt, "")!= 0)
-		snprint(mf, sizeof(r->mtpt)+1, " %s", r->mtpt);
-
-	if(strcmp(r->auth, "none")==0)
-		snprint(auth, 4, "srv");
-	else
-		snprint(auth, 7, "srvtls");
-
-	return fmtprint(f, "%s!%s!%s\n",
-		r->trns, r->host, r->port);
-}
-
-static int
-scanfmt(Fmt *f)
-{
-	Svc *r;
-	char mf[Maxpath+6]; /* pad for our tuple attrs */
-
-	mf[0] = 0;
-	r = va_arg(f->args, Svc*);
-	if(strcmp(r->mtpt, "")!=0)
-		snprint(mf, sizeof(r->mtpt)+6, " mtpt=%s", r->mtpt);
-	return fmtprint(f, "service=%s!%s!%s label='%s' auth=%s%s\n",
-		r->trns, r->host, r->port, r->labl, r->auth, mf);
-}
-
-static int
-dumpfmt(Fmt *f)
-{
-	Svc *r;
-	char mf[Maxpath+7]; /* pad for our tuple attrs */
-
-	r = va_arg(f->args, Svc*);
-	if(r->mtpt != 0)
-		snprint(mf, sizeof(r->mtpt) + 7, "\n\tmtpt=%s", r->mtpt);
-	return fmtprint(f, "service=%s!%s!%s\n\tlabel=%s\n\tauth=%s%s",
-		r->trns, r->host, r->port, r->labl, r->auth, mf);
-}
-
--- a/ndb/regquery.c
+++ /dev/null
@@ -1,67 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <ctype.h>
-#include <ndb.h>
-#include "dns.h"
-#include "ip.h"
-
-void
-usage(void)
-{
-	fprint(2, "usage: regquery [-s] [-f registry] query\n");
-	exits("usage");
-}
-
-static void
-queryregistry(int fd, char *line, int n)
-{
-	char buf[8192+1];
-
-	seek(fd, 0, 0);
-	write(fd, line, n);
-
-	seek(fd, 0, 0);
-	while((n = read(fd, buf, sizeof(buf)-1)) > 0)
-		write(1, buf, n);
-}
-
-static void
-query(int fd, char *q, int pipe2rc)
-{
-	char arg[260];
-
-	if(strlen(q) > 255)
-		sysfatal("query too long");
-
-	sprint(arg, "%s %s", q, (pipe2rc) ? "svc":"scan");
-	queryregistry(fd, arg, sizeof(arg));
-}
-
-void
-main(int argc, char *argv[])
-{
-	int fd, pipe2rc = 0;
-	char *rst  = "/net/registry";
-
-	ARGBEGIN {
-	case 's':
-		pipe2rc++;
-		break;
-	case 'f':
-		rst = EARGF(usage());
-		break;
-	default:
-		usage();
-	} ARGEND;
-
-	if(argc != 1)
-		usage();
-
-	fd = open(rst, ORDWR);
-	if(fd < 0)
-		sysfatal("can't open %s: %r", rst);
-
-	query(fd, argv[0], pipe2rc);
-	exits(0);
-}