xref: /plan9/sys/src/cmd/ndb/cs.c (revision 7dd7cddf99dd7472612f1413b4da293630e6b1bc)
13e12c5d1SDavid du Colombier #include <u.h>
23e12c5d1SDavid du Colombier #include <libc.h>
3219b2ee8SDavid du Colombier #include <auth.h>
43e12c5d1SDavid du Colombier #include <fcall.h>
53e12c5d1SDavid du Colombier #include <bio.h>
63e12c5d1SDavid du Colombier #include <ctype.h>
73e12c5d1SDavid du Colombier #include <ndb.h>
83e12c5d1SDavid du Colombier #include <ip.h>
93e12c5d1SDavid du Colombier 
103e12c5d1SDavid du Colombier enum
113e12c5d1SDavid du Colombier {
12219b2ee8SDavid du Colombier 	Nreply=			8,
133e12c5d1SDavid du Colombier 	Maxreply=		256,
14*7dd7cddfSDavid du Colombier 	Maxrequest=		128,
15*7dd7cddfSDavid du Colombier 	Maxpath=		128,
16*7dd7cddfSDavid du Colombier 	Ncache=			8,		/* size of cache */
17*7dd7cddfSDavid du Colombier 	Secvalid=		120,		/* seconds a cache entry is valid */
183e12c5d1SDavid du Colombier 
193e12c5d1SDavid du Colombier 	Qcs=			1,
203e12c5d1SDavid du Colombier };
213e12c5d1SDavid du Colombier 
223e12c5d1SDavid du Colombier typedef struct Mfile	Mfile;
23219b2ee8SDavid du Colombier typedef struct Mlist	Mlist;
243e12c5d1SDavid du Colombier typedef struct Network	Network;
25*7dd7cddfSDavid du Colombier typedef struct Flushreq	Flushreq;
26*7dd7cddfSDavid du Colombier typedef struct CacheEntry	CacheEntry;
27*7dd7cddfSDavid du Colombier typedef struct Job	Job;
283e12c5d1SDavid du Colombier 
293e12c5d1SDavid du Colombier int vers;		/* incremented each clone/attach */
303e12c5d1SDavid du Colombier 
313e12c5d1SDavid du Colombier struct Mfile
323e12c5d1SDavid du Colombier {
333e12c5d1SDavid du Colombier 	int		busy;
34219b2ee8SDavid du Colombier 
353e12c5d1SDavid du Colombier 	char		user[NAMELEN];
363e12c5d1SDavid du Colombier 	Qid		qid;
373e12c5d1SDavid du Colombier 	int		fid;
383e12c5d1SDavid du Colombier 
39219b2ee8SDavid du Colombier 	int		nreply;
40219b2ee8SDavid du Colombier 	char		*reply[Nreply];
41219b2ee8SDavid du Colombier 	int		replylen[Nreply];
42219b2ee8SDavid du Colombier };
43219b2ee8SDavid du Colombier 
44219b2ee8SDavid du Colombier struct Mlist
45219b2ee8SDavid du Colombier {
46219b2ee8SDavid du Colombier 	Mlist	*next;
47219b2ee8SDavid du Colombier 	Mfile	mf;
483e12c5d1SDavid du Colombier };
493e12c5d1SDavid du Colombier 
50*7dd7cddfSDavid du Colombier struct CacheEntry
51*7dd7cddfSDavid du Colombier {
52*7dd7cddfSDavid du Colombier 	ulong		expire;
53*7dd7cddfSDavid du Colombier 	char		*question;
54*7dd7cddfSDavid du Colombier 	char		err[ERRLEN];
55*7dd7cddfSDavid du Colombier 	int		nreply;
56*7dd7cddfSDavid du Colombier 	char		*reply[Nreply];
57*7dd7cddfSDavid du Colombier 	int		replylen[Nreply];
58*7dd7cddfSDavid du Colombier };
59*7dd7cddfSDavid du Colombier struct {
60*7dd7cddfSDavid du Colombier 	Lock;
61*7dd7cddfSDavid du Colombier 	CacheEntry	e[Ncache];
62*7dd7cddfSDavid du Colombier 	int 		next;		/* next cache entry to use */
63*7dd7cddfSDavid du Colombier } cache;
64*7dd7cddfSDavid du Colombier 
65*7dd7cddfSDavid du Colombier //
66*7dd7cddfSDavid du Colombier //  active requests
67*7dd7cddfSDavid du Colombier //
68*7dd7cddfSDavid du Colombier struct Job
69*7dd7cddfSDavid du Colombier {
70*7dd7cddfSDavid du Colombier 	Job	*next;
71*7dd7cddfSDavid du Colombier 	int	flushed;
72*7dd7cddfSDavid du Colombier 	Fcall	request;
73*7dd7cddfSDavid du Colombier 	Fcall	reply;
74*7dd7cddfSDavid du Colombier };
75*7dd7cddfSDavid du Colombier Lock	joblock;
76*7dd7cddfSDavid du Colombier Job	*joblist;
77*7dd7cddfSDavid du Colombier 
78219b2ee8SDavid du Colombier Mlist	*mlist;
793e12c5d1SDavid du Colombier int	mfd[2];
803e12c5d1SDavid du Colombier char	user[NAMELEN];
813e12c5d1SDavid du Colombier int	debug;
82*7dd7cddfSDavid du Colombier int	paranoia;
833e12c5d1SDavid du Colombier jmp_buf	masterjmp;	/* return through here after a slave process has been created */
843e12c5d1SDavid du Colombier int	*isslave;	/* *isslave non-zero means this is a slave process */
85bd389b36SDavid du Colombier char	*dbfile;
86*7dd7cddfSDavid du Colombier Ndb	*db, *netdb;
873e12c5d1SDavid du Colombier 
88*7dd7cddfSDavid du Colombier void	rsession(Job*);
89*7dd7cddfSDavid du Colombier void	rnop(Job*);
90*7dd7cddfSDavid du Colombier void	rflush(Job*);
91*7dd7cddfSDavid du Colombier void	rattach(Job*, Mfile*);
92*7dd7cddfSDavid du Colombier void	rclone(Job*, Mfile*);
93*7dd7cddfSDavid du Colombier char*	rwalk(Job*, Mfile*);
94*7dd7cddfSDavid du Colombier void	rclwalk(Job*, Mfile*);
95*7dd7cddfSDavid du Colombier void	ropen(Job*, Mfile*);
96*7dd7cddfSDavid du Colombier void	rcreate(Job*, Mfile*);
97*7dd7cddfSDavid du Colombier void	rread(Job*, Mfile*);
98*7dd7cddfSDavid du Colombier void	rwrite(Job*, Mfile*);
99*7dd7cddfSDavid du Colombier void	rclunk(Job*, Mfile*);
100*7dd7cddfSDavid du Colombier void	rremove(Job*, Mfile*);
101*7dd7cddfSDavid du Colombier void	rstat(Job*, Mfile*);
102*7dd7cddfSDavid du Colombier void	rwstat(Job*, Mfile*);
1033e12c5d1SDavid du Colombier void	rauth(void);
104*7dd7cddfSDavid du Colombier void	sendmsg(Job*, char*);
1053e12c5d1SDavid du Colombier void	error(char*);
106*7dd7cddfSDavid du Colombier void	mountinit(char*, char*);
1073e12c5d1SDavid du Colombier void	io(void);
108*7dd7cddfSDavid du Colombier void	ndbinit(void);
109*7dd7cddfSDavid du Colombier void	netinit(int);
1103e12c5d1SDavid du Colombier void	netadd(char*);
111*7dd7cddfSDavid du Colombier int	lookup(Mfile*, char*, char*, char*, char*);
112219b2ee8SDavid du Colombier char	*genquery(Mfile*, char*);
113*7dd7cddfSDavid du Colombier char*	ipinfoquery(Mfile*, char**, int);
114bd389b36SDavid du Colombier int	needproto(Network*, Ndbtuple*);
1153e12c5d1SDavid du Colombier Ndbtuple*	lookval(Ndbtuple*, Ndbtuple*, char*, char*);
1163e12c5d1SDavid du Colombier Ndbtuple*	reorder(Ndbtuple*, Ndbtuple*);
117*7dd7cddfSDavid du Colombier void	ipid(void);
118*7dd7cddfSDavid du Colombier void	readipinterfaces(void);
119*7dd7cddfSDavid du Colombier void*	emalloc(int);
120*7dd7cddfSDavid du Colombier Job*	newjob(void);
121*7dd7cddfSDavid du Colombier void	freejob(Job*);
122*7dd7cddfSDavid du Colombier void	setext(char*, int, char*);
1233e12c5d1SDavid du Colombier 
124bd389b36SDavid du Colombier extern void	paralloc(void);
125bd389b36SDavid du Colombier 
1263e12c5d1SDavid du Colombier char *mname[]={
1273e12c5d1SDavid du Colombier 	[Tnop]		"Tnop",
1283e12c5d1SDavid du Colombier 	[Tsession]	"Tsession",
1293e12c5d1SDavid du Colombier 	[Tflush]	"Tflush",
1303e12c5d1SDavid du Colombier 	[Tattach]	"Tattach",
1313e12c5d1SDavid du Colombier 	[Tclone]	"Tclone",
1323e12c5d1SDavid du Colombier 	[Twalk]		"Twalk",
1333e12c5d1SDavid du Colombier 	[Topen]		"Topen",
1343e12c5d1SDavid du Colombier 	[Tcreate]	"Tcreate",
1353e12c5d1SDavid du Colombier 	[Tclunk]	"Tclunk",
1363e12c5d1SDavid du Colombier 	[Tread]		"Tread",
1373e12c5d1SDavid du Colombier 	[Twrite]	"Twrite",
1383e12c5d1SDavid du Colombier 	[Tremove]	"Tremove",
1393e12c5d1SDavid du Colombier 	[Tstat]		"Tstat",
1403e12c5d1SDavid du Colombier 	[Twstat]	"Twstat",
1413e12c5d1SDavid du Colombier 			0,
1423e12c5d1SDavid du Colombier };
1433e12c5d1SDavid du Colombier 
144bd389b36SDavid du Colombier Lock	dblock;		/* mutex on database operations */
145*7dd7cddfSDavid du Colombier Lock	netlock;	/* mutex for netinit() */
146bd389b36SDavid du Colombier 
147219b2ee8SDavid du Colombier char	*logfile = "cs";
148*7dd7cddfSDavid du Colombier char	*paranoiafile = "cs.paranoia";
149219b2ee8SDavid du Colombier 
150*7dd7cddfSDavid du Colombier char	mntpt[Maxpath];
151*7dd7cddfSDavid du Colombier char	netndb[Maxpath];
152*7dd7cddfSDavid du Colombier 
153*7dd7cddfSDavid du Colombier void
154*7dd7cddfSDavid du Colombier usage(void)
155*7dd7cddfSDavid du Colombier {
156*7dd7cddfSDavid du Colombier 	fprint(2, "usage: %s [-d] [-f ndb-file] [-x netmtpt] [-n]\n", argv0);
157*7dd7cddfSDavid du Colombier 	exits("usage");
158*7dd7cddfSDavid du Colombier }
159219b2ee8SDavid du Colombier 
1603e12c5d1SDavid du Colombier void
1613e12c5d1SDavid du Colombier main(int argc, char *argv[])
1623e12c5d1SDavid du Colombier {
163*7dd7cddfSDavid du Colombier 	char servefile[Maxpath];
164219b2ee8SDavid du Colombier 	int justsetname;
165*7dd7cddfSDavid du Colombier 	char *p;
166*7dd7cddfSDavid du Colombier 	char ext[Maxpath];
1673e12c5d1SDavid du Colombier 
168219b2ee8SDavid du Colombier 	justsetname = 0;
169*7dd7cddfSDavid du Colombier 	setnetmtpt(mntpt, sizeof(mntpt), nil);
170*7dd7cddfSDavid du Colombier 	ext[0] = 0;
1713e12c5d1SDavid du Colombier 	ARGBEGIN{
1723e12c5d1SDavid du Colombier 	case 'd':
1733e12c5d1SDavid du Colombier 		debug = 1;
1743e12c5d1SDavid du Colombier 		break;
175bd389b36SDavid du Colombier 	case 'f':
176*7dd7cddfSDavid du Colombier 		p = ARGF();
177*7dd7cddfSDavid du Colombier 		if(p == nil)
178*7dd7cddfSDavid du Colombier 			usage();
179*7dd7cddfSDavid du Colombier 		dbfile = p;
180*7dd7cddfSDavid du Colombier 		break;
181*7dd7cddfSDavid du Colombier 	case 'x':
182*7dd7cddfSDavid du Colombier 		p = ARGF();
183*7dd7cddfSDavid du Colombier 		if(p == nil)
184*7dd7cddfSDavid du Colombier 			usage();
185*7dd7cddfSDavid du Colombier 		setnetmtpt(mntpt, sizeof(mntpt), p);
186*7dd7cddfSDavid du Colombier 		setext(ext, sizeof(ext), mntpt);
187bd389b36SDavid du Colombier 		break;
188219b2ee8SDavid du Colombier 	case 'n':
189219b2ee8SDavid du Colombier 		justsetname = 1;
190219b2ee8SDavid du Colombier 		break;
1913e12c5d1SDavid du Colombier 	}ARGEND
1923e12c5d1SDavid du Colombier 	USED(argc);
1933e12c5d1SDavid du Colombier 	USED(argv);
1943e12c5d1SDavid du Colombier 
195*7dd7cddfSDavid du Colombier 	rfork(RFREND|RFNOTEG);
196*7dd7cddfSDavid du Colombier 
197*7dd7cddfSDavid du Colombier 	snprint(servefile, sizeof(servefile), "#s/cs%s", ext);
198*7dd7cddfSDavid du Colombier 	snprint(netndb, sizeof(netndb), "%s/ndb", mntpt);
199*7dd7cddfSDavid du Colombier 	unmount(servefile, mntpt);
200*7dd7cddfSDavid du Colombier 	remove(servefile);
201*7dd7cddfSDavid du Colombier 
202*7dd7cddfSDavid du Colombier 	fmtinstall('E', eipconv);
203*7dd7cddfSDavid du Colombier 	fmtinstall('I', eipconv);
204*7dd7cddfSDavid du Colombier 	fmtinstall('M', eipconv);
205*7dd7cddfSDavid du Colombier 	fmtinstall('F', fcallconv);
206*7dd7cddfSDavid du Colombier 
207*7dd7cddfSDavid du Colombier 	ndbinit();
208*7dd7cddfSDavid du Colombier 	netinit(0);
209*7dd7cddfSDavid du Colombier 
210*7dd7cddfSDavid du Colombier 	if(!justsetname){
211*7dd7cddfSDavid du Colombier 		mountinit(servefile, mntpt);
212*7dd7cddfSDavid du Colombier 		io();
213*7dd7cddfSDavid du Colombier 	}
214219b2ee8SDavid du Colombier 	exits(0);
215219b2ee8SDavid du Colombier }
216219b2ee8SDavid du Colombier 
217*7dd7cddfSDavid du Colombier /*
218*7dd7cddfSDavid du Colombier  *  if a mount point is specified, set the cs extention to be the mount point
219*7dd7cddfSDavid du Colombier  *  with '_'s replacing '/'s
220*7dd7cddfSDavid du Colombier  */
221*7dd7cddfSDavid du Colombier void
222*7dd7cddfSDavid du Colombier setext(char *ext, int n, char *p)
223*7dd7cddfSDavid du Colombier {
224*7dd7cddfSDavid du Colombier 	int i, c;
2253e12c5d1SDavid du Colombier 
226*7dd7cddfSDavid du Colombier 	n--;
227*7dd7cddfSDavid du Colombier 	for(i = 0; i < n; i++){
228*7dd7cddfSDavid du Colombier 		c = p[i];
229*7dd7cddfSDavid du Colombier 		if(c == 0)
230*7dd7cddfSDavid du Colombier 			break;
231*7dd7cddfSDavid du Colombier 		if(c == '/')
232*7dd7cddfSDavid du Colombier 			c = '_';
233*7dd7cddfSDavid du Colombier 		ext[i] = c;
234*7dd7cddfSDavid du Colombier 	}
235*7dd7cddfSDavid du Colombier 	ext[i] = 0;
2363e12c5d1SDavid du Colombier }
2373e12c5d1SDavid du Colombier 
2383e12c5d1SDavid du Colombier void
239*7dd7cddfSDavid du Colombier mountinit(char *service, char *mntpt)
2403e12c5d1SDavid du Colombier {
2413e12c5d1SDavid du Colombier 	int f;
2423e12c5d1SDavid du Colombier 	int p[2];
2433e12c5d1SDavid du Colombier 	char buf[32];
2443e12c5d1SDavid du Colombier 
2453e12c5d1SDavid du Colombier 	if(pipe(p) < 0)
2463e12c5d1SDavid du Colombier 		error("pipe failed");
247219b2ee8SDavid du Colombier 	switch(rfork(RFFDG|RFPROC|RFNAMEG)){
2483e12c5d1SDavid du Colombier 	case 0:
249219b2ee8SDavid du Colombier 		close(p[1]);
2503e12c5d1SDavid du Colombier 		break;
2513e12c5d1SDavid du Colombier 	case -1:
2523e12c5d1SDavid du Colombier 		error("fork failed\n");
2533e12c5d1SDavid du Colombier 	default:
2543e12c5d1SDavid du Colombier 		/*
2553e12c5d1SDavid du Colombier 		 *  make a /srv/cs
2563e12c5d1SDavid du Colombier 		 */
2573e12c5d1SDavid du Colombier 		f = create(service, 1, 0666);
2583e12c5d1SDavid du Colombier 		if(f < 0)
2593e12c5d1SDavid du Colombier 			error(service);
260bd389b36SDavid du Colombier 		snprint(buf, sizeof(buf), "%d", p[1]);
2613e12c5d1SDavid du Colombier 		if(write(f, buf, strlen(buf)) != strlen(buf))
262219b2ee8SDavid du Colombier 			error("write /srv/cs");
2633e12c5d1SDavid du Colombier 		close(f);
2643e12c5d1SDavid du Colombier 
2653e12c5d1SDavid du Colombier 		/*
2663e12c5d1SDavid du Colombier 		 *  put ourselves into the file system
2673e12c5d1SDavid du Colombier 		 */
268219b2ee8SDavid du Colombier 		close(p[0]);
269*7dd7cddfSDavid du Colombier 		if(mount(p[1], mntpt, MAFTER, "") < 0)
2703e12c5d1SDavid du Colombier 			error("mount failed\n");
271219b2ee8SDavid du Colombier 		_exits(0);
2723e12c5d1SDavid du Colombier 	}
2733e12c5d1SDavid du Colombier 	mfd[0] = mfd[1] = p[0];
2743e12c5d1SDavid du Colombier }
2753e12c5d1SDavid du Colombier 
276*7dd7cddfSDavid du Colombier void
277*7dd7cddfSDavid du Colombier ndbinit(void)
278*7dd7cddfSDavid du Colombier {
279*7dd7cddfSDavid du Colombier 	db = ndbopen(dbfile);
280*7dd7cddfSDavid du Colombier 	if(db == nil)
281*7dd7cddfSDavid du Colombier 		error("can't open network database");
282*7dd7cddfSDavid du Colombier 
283*7dd7cddfSDavid du Colombier 	netdb = ndbopen(netndb);
284*7dd7cddfSDavid du Colombier 	if(netdb != nil){
285*7dd7cddfSDavid du Colombier 		netdb->nohash = 1;
286*7dd7cddfSDavid du Colombier 		db = ndbcat(netdb, db);
287*7dd7cddfSDavid du Colombier 	}
288*7dd7cddfSDavid du Colombier }
289*7dd7cddfSDavid du Colombier 
2903e12c5d1SDavid du Colombier Mfile*
2913e12c5d1SDavid du Colombier newfid(int fid)
2923e12c5d1SDavid du Colombier {
293219b2ee8SDavid du Colombier 	Mlist *f, *ff;
2943e12c5d1SDavid du Colombier 	Mfile *mf;
2953e12c5d1SDavid du Colombier 
296219b2ee8SDavid du Colombier 	ff = 0;
297219b2ee8SDavid du Colombier 	for(f = mlist; f; f = f->next)
298219b2ee8SDavid du Colombier 		if(f->mf.busy && f->mf.fid == fid)
299219b2ee8SDavid du Colombier 			return &f->mf;
300219b2ee8SDavid du Colombier 		else if(!ff && !f->mf.busy)
301219b2ee8SDavid du Colombier 			ff = f;
302219b2ee8SDavid du Colombier 	if(ff == 0){
303*7dd7cddfSDavid du Colombier 		ff = emalloc(sizeof *f);
304219b2ee8SDavid du Colombier 		ff->next = mlist;
305219b2ee8SDavid du Colombier 		mlist = ff;
3063e12c5d1SDavid du Colombier 	}
307219b2ee8SDavid du Colombier 	mf = &ff->mf;
308219b2ee8SDavid du Colombier 	memset(mf, 0, sizeof *mf);
3093e12c5d1SDavid du Colombier 	mf->fid = fid;
3103e12c5d1SDavid du Colombier 	return mf;
3113e12c5d1SDavid du Colombier }
3123e12c5d1SDavid du Colombier 
313*7dd7cddfSDavid du Colombier Job*
314*7dd7cddfSDavid du Colombier newjob(void)
315*7dd7cddfSDavid du Colombier {
316*7dd7cddfSDavid du Colombier 	Job *job;
317*7dd7cddfSDavid du Colombier 
318*7dd7cddfSDavid du Colombier 	job = mallocz(sizeof(Job), 1);
319*7dd7cddfSDavid du Colombier 	lock(&joblock);
320*7dd7cddfSDavid du Colombier 	job->next = joblist;
321*7dd7cddfSDavid du Colombier 	joblist = job;
322*7dd7cddfSDavid du Colombier 	job->request.tag = -1;
323*7dd7cddfSDavid du Colombier 	unlock(&joblock);
324*7dd7cddfSDavid du Colombier 	return job;
325*7dd7cddfSDavid du Colombier }
326*7dd7cddfSDavid du Colombier 
327*7dd7cddfSDavid du Colombier void
328*7dd7cddfSDavid du Colombier freejob(Job *job)
329*7dd7cddfSDavid du Colombier {
330*7dd7cddfSDavid du Colombier 	Job **l;
331*7dd7cddfSDavid du Colombier 
332*7dd7cddfSDavid du Colombier 	lock(&joblock);
333*7dd7cddfSDavid du Colombier 	for(l = &joblist; *l; l = &(*l)->next){
334*7dd7cddfSDavid du Colombier 		if((*l) == job){
335*7dd7cddfSDavid du Colombier 			*l = job->next;
336*7dd7cddfSDavid du Colombier 			free(job);
337*7dd7cddfSDavid du Colombier 			break;
338*7dd7cddfSDavid du Colombier 		}
339*7dd7cddfSDavid du Colombier 	}
340*7dd7cddfSDavid du Colombier 	unlock(&joblock);
341*7dd7cddfSDavid du Colombier }
342*7dd7cddfSDavid du Colombier 
343*7dd7cddfSDavid du Colombier void
344*7dd7cddfSDavid du Colombier flushjob(int tag)
345*7dd7cddfSDavid du Colombier {
346*7dd7cddfSDavid du Colombier 	Job *job;
347*7dd7cddfSDavid du Colombier 
348*7dd7cddfSDavid du Colombier 	lock(&joblock);
349*7dd7cddfSDavid du Colombier 	for(job = joblist; job; job = job->next){
350*7dd7cddfSDavid du Colombier 		if(job->request.tag == tag && job->request.type != Tflush){
351*7dd7cddfSDavid du Colombier 			job->flushed = 1;
352*7dd7cddfSDavid du Colombier 			break;
353*7dd7cddfSDavid du Colombier 		}
354*7dd7cddfSDavid du Colombier 	}
355*7dd7cddfSDavid du Colombier 	unlock(&joblock);
356*7dd7cddfSDavid du Colombier }
357*7dd7cddfSDavid du Colombier 
3583e12c5d1SDavid du Colombier void
3593e12c5d1SDavid du Colombier io(void)
3603e12c5d1SDavid du Colombier {
3613e12c5d1SDavid du Colombier 	long n;
3623e12c5d1SDavid du Colombier 	Mfile *mf;
3633e12c5d1SDavid du Colombier 	int slaveflag;
3643e12c5d1SDavid du Colombier 	char mdata[MAXFDATA + MAXMSG];
365*7dd7cddfSDavid du Colombier 	Job *job;
3663e12c5d1SDavid du Colombier 
3673e12c5d1SDavid du Colombier 	/*
3683e12c5d1SDavid du Colombier 	 *  if we ask dns to fulfill requests,
3693e12c5d1SDavid du Colombier 	 *  a slave process is created to wait for replies.  The
3703e12c5d1SDavid du Colombier 	 *  master process returns immediately via a longjmp's
3713e12c5d1SDavid du Colombier 	 *  through 'masterjmp'.
3723e12c5d1SDavid du Colombier 	 *
3733e12c5d1SDavid du Colombier 	 *  *isslave is a pointer into the call stack to a variable
3743e12c5d1SDavid du Colombier 	 *  that tells whether or not the current process is a slave.
3753e12c5d1SDavid du Colombier 	 */
3763e12c5d1SDavid du Colombier 	slaveflag = 0;		/* init slave variable */
3773e12c5d1SDavid du Colombier 	isslave = &slaveflag;
3783e12c5d1SDavid du Colombier 	setjmp(masterjmp);
3793e12c5d1SDavid du Colombier 
3803e12c5d1SDavid du Colombier 	for(;;){
381219b2ee8SDavid du Colombier 		n = read9p(mfd[0], mdata, sizeof mdata);
3823e12c5d1SDavid du Colombier 		if(n<=0)
3833e12c5d1SDavid du Colombier 			error("mount read");
384*7dd7cddfSDavid du Colombier 		job = newjob();
385*7dd7cddfSDavid du Colombier 		if(convM2S(mdata, &job->request, n) == 0){
386219b2ee8SDavid du Colombier 			syslog(1, logfile, "format error %ux %ux %ux %ux %ux", mdata[0], mdata[1], mdata[2], mdata[3], mdata[4]);
387*7dd7cddfSDavid du Colombier 			freejob(job);
3883e12c5d1SDavid du Colombier 			continue;
3893e12c5d1SDavid du Colombier 		}
390*7dd7cddfSDavid du Colombier 		if(job->request.fid<0)
3913e12c5d1SDavid du Colombier 			error("fid out of range");
392bd389b36SDavid du Colombier 		lock(&dblock);
393*7dd7cddfSDavid du Colombier 		mf = newfid(job->request.fid);
394219b2ee8SDavid du Colombier 		if(debug)
395*7dd7cddfSDavid du Colombier 			syslog(0, logfile, "%F", &job->request);
3963e12c5d1SDavid du Colombier 
3973e12c5d1SDavid du Colombier 
398*7dd7cddfSDavid du Colombier 		switch(job->request.type){
3993e12c5d1SDavid du Colombier 		default:
400*7dd7cddfSDavid du Colombier 			syslog(1, logfile, "unknown request type %d", job->request.type);
4013e12c5d1SDavid du Colombier 			break;
4023e12c5d1SDavid du Colombier 		case Tsession:
403*7dd7cddfSDavid du Colombier 			rsession(job);
4043e12c5d1SDavid du Colombier 			break;
4053e12c5d1SDavid du Colombier 		case Tnop:
406*7dd7cddfSDavid du Colombier 			rnop(job);
4073e12c5d1SDavid du Colombier 			break;
4083e12c5d1SDavid du Colombier 		case Tflush:
409*7dd7cddfSDavid du Colombier 			rflush(job);
4103e12c5d1SDavid du Colombier 			break;
4113e12c5d1SDavid du Colombier 		case Tattach:
412*7dd7cddfSDavid du Colombier 			rattach(job, mf);
4133e12c5d1SDavid du Colombier 			break;
4143e12c5d1SDavid du Colombier 		case Tclone:
415*7dd7cddfSDavid du Colombier 			rclone(job, mf);
4163e12c5d1SDavid du Colombier 			break;
4173e12c5d1SDavid du Colombier 		case Twalk:
418*7dd7cddfSDavid du Colombier 			rwalk(job, mf);
4193e12c5d1SDavid du Colombier 			break;
4203e12c5d1SDavid du Colombier 		case Tclwalk:
421*7dd7cddfSDavid du Colombier 			rclwalk(job, mf);
4223e12c5d1SDavid du Colombier 			break;
4233e12c5d1SDavid du Colombier 		case Topen:
424*7dd7cddfSDavid du Colombier 			ropen(job, mf);
4253e12c5d1SDavid du Colombier 			break;
4263e12c5d1SDavid du Colombier 		case Tcreate:
427*7dd7cddfSDavid du Colombier 			rcreate(job, mf);
4283e12c5d1SDavid du Colombier 			break;
4293e12c5d1SDavid du Colombier 		case Tread:
430*7dd7cddfSDavid du Colombier 			rread(job, mf);
4313e12c5d1SDavid du Colombier 			break;
4323e12c5d1SDavid du Colombier 		case Twrite:
433*7dd7cddfSDavid du Colombier 			rwrite(job, mf);
4343e12c5d1SDavid du Colombier 			break;
4353e12c5d1SDavid du Colombier 		case Tclunk:
436*7dd7cddfSDavid du Colombier 			rclunk(job, mf);
4373e12c5d1SDavid du Colombier 			break;
4383e12c5d1SDavid du Colombier 		case Tremove:
439*7dd7cddfSDavid du Colombier 			rremove(job, mf);
4403e12c5d1SDavid du Colombier 			break;
4413e12c5d1SDavid du Colombier 		case Tstat:
442*7dd7cddfSDavid du Colombier 			rstat(job, mf);
4433e12c5d1SDavid du Colombier 			break;
4443e12c5d1SDavid du Colombier 		case Twstat:
445*7dd7cddfSDavid du Colombier 			rwstat(job, mf);
4463e12c5d1SDavid du Colombier 			break;
4473e12c5d1SDavid du Colombier 		}
448bd389b36SDavid du Colombier 		unlock(&dblock);
449*7dd7cddfSDavid du Colombier 
450*7dd7cddfSDavid du Colombier 		freejob(job);
451*7dd7cddfSDavid du Colombier 
4523e12c5d1SDavid du Colombier 		/*
4533e12c5d1SDavid du Colombier 		 *  slave processes die after replying
4543e12c5d1SDavid du Colombier 		 */
455219b2ee8SDavid du Colombier 		if(*isslave){
456219b2ee8SDavid du Colombier 			if(debug)
457219b2ee8SDavid du Colombier 				syslog(0, logfile, "slave death %d", getpid());
4583e12c5d1SDavid du Colombier 			_exits(0);
4593e12c5d1SDavid du Colombier 		}
4603e12c5d1SDavid du Colombier 	}
461219b2ee8SDavid du Colombier }
462219b2ee8SDavid du Colombier 
463219b2ee8SDavid du Colombier void
464*7dd7cddfSDavid du Colombier rsession(Job *job)
465219b2ee8SDavid du Colombier {
466*7dd7cddfSDavid du Colombier 	memset(job->reply.authid, 0, sizeof(job->reply.authid));
467*7dd7cddfSDavid du Colombier 	memset(job->reply.authdom, 0, sizeof(job->reply.authdom));
468*7dd7cddfSDavid du Colombier 	memset(job->reply.chal, 0, sizeof(job->reply.chal));
469*7dd7cddfSDavid du Colombier 	sendmsg(job, 0);
470219b2ee8SDavid du Colombier }
4713e12c5d1SDavid du Colombier 
4723e12c5d1SDavid du Colombier void
473*7dd7cddfSDavid du Colombier rnop(Job *job)
4743e12c5d1SDavid du Colombier {
475*7dd7cddfSDavid du Colombier 	sendmsg(job, 0);
476*7dd7cddfSDavid du Colombier }
477*7dd7cddfSDavid du Colombier 
478*7dd7cddfSDavid du Colombier /*
479*7dd7cddfSDavid du Colombier  *  don't flush till all the slaves are done
480*7dd7cddfSDavid du Colombier  */
481*7dd7cddfSDavid du Colombier void
482*7dd7cddfSDavid du Colombier rflush(Job *job)
483*7dd7cddfSDavid du Colombier {
484*7dd7cddfSDavid du Colombier 	flushjob(job->request.oldtag);
485*7dd7cddfSDavid du Colombier 	sendmsg(job, 0);
4863e12c5d1SDavid du Colombier }
4873e12c5d1SDavid du Colombier 
4883e12c5d1SDavid du Colombier void
489*7dd7cddfSDavid du Colombier rattach(Job *job, Mfile *mf)
4903e12c5d1SDavid du Colombier {
4913e12c5d1SDavid du Colombier 	if(mf->busy == 0){
4923e12c5d1SDavid du Colombier 		mf->busy = 1;
493*7dd7cddfSDavid du Colombier 		strcpy(mf->user, job->request.uname);
4943e12c5d1SDavid du Colombier 	}
4953e12c5d1SDavid du Colombier 	mf->qid.vers = vers++;
4963e12c5d1SDavid du Colombier 	mf->qid.path = CHDIR;
497*7dd7cddfSDavid du Colombier 	job->reply.qid = mf->qid;
498*7dd7cddfSDavid du Colombier 	sendmsg(job, 0);
4993e12c5d1SDavid du Colombier }
5003e12c5d1SDavid du Colombier 
5013e12c5d1SDavid du Colombier void
502*7dd7cddfSDavid du Colombier rclone(Job *job, Mfile *mf)
5033e12c5d1SDavid du Colombier {
5043e12c5d1SDavid du Colombier 	Mfile *nmf;
5053e12c5d1SDavid du Colombier 	char *err=0;
5063e12c5d1SDavid du Colombier 
507*7dd7cddfSDavid du Colombier 	if(job->request.newfid<0){
5083e12c5d1SDavid du Colombier 		err = "clone nfid out of range";
5093e12c5d1SDavid du Colombier 		goto send;
5103e12c5d1SDavid du Colombier 	}
511*7dd7cddfSDavid du Colombier 	nmf = newfid(job->request.newfid);
5123e12c5d1SDavid du Colombier 	if(nmf->busy){
5133e12c5d1SDavid du Colombier 		err = "clone to used channel";
5143e12c5d1SDavid du Colombier 		goto send;
5153e12c5d1SDavid du Colombier 	}
5163e12c5d1SDavid du Colombier 	*nmf = *mf;
517*7dd7cddfSDavid du Colombier 	nmf->fid = job->request.newfid;
5183e12c5d1SDavid du Colombier 	nmf->qid.vers = vers++;
5193e12c5d1SDavid du Colombier     send:
520*7dd7cddfSDavid du Colombier 	sendmsg(job, err);
5213e12c5d1SDavid du Colombier }
5223e12c5d1SDavid du Colombier 
5233e12c5d1SDavid du Colombier void
524*7dd7cddfSDavid du Colombier rclwalk(Job *job, Mfile *mf)
5253e12c5d1SDavid du Colombier {
5263e12c5d1SDavid du Colombier 	Mfile *nmf;
5273e12c5d1SDavid du Colombier 
528*7dd7cddfSDavid du Colombier 	if(job->request.newfid<0){
529*7dd7cddfSDavid du Colombier 		sendmsg(job, "clone nfid out of range");
5303e12c5d1SDavid du Colombier 		return;
5313e12c5d1SDavid du Colombier 	}
532*7dd7cddfSDavid du Colombier 	nmf = newfid(job->request.newfid);
5333e12c5d1SDavid du Colombier 	if(nmf->busy){
534*7dd7cddfSDavid du Colombier 		sendmsg(job, "clone to used channel");
5353e12c5d1SDavid du Colombier 		return;
5363e12c5d1SDavid du Colombier 	}
5373e12c5d1SDavid du Colombier 	*nmf = *mf;
538*7dd7cddfSDavid du Colombier 	nmf->fid = job->request.newfid;
539*7dd7cddfSDavid du Colombier 	job->request.fid = job->request.newfid;
5403e12c5d1SDavid du Colombier 	nmf->qid.vers = vers++;
541*7dd7cddfSDavid du Colombier 	if(rwalk(job, nmf))
5423e12c5d1SDavid du Colombier 		nmf->busy = 0;
5433e12c5d1SDavid du Colombier }
5443e12c5d1SDavid du Colombier 
5453e12c5d1SDavid du Colombier char*
546*7dd7cddfSDavid du Colombier rwalk(Job *job, Mfile *mf)
5473e12c5d1SDavid du Colombier {
5483e12c5d1SDavid du Colombier 	char *err;
5493e12c5d1SDavid du Colombier 	char *name;
5503e12c5d1SDavid du Colombier 
5513e12c5d1SDavid du Colombier 	err = 0;
552*7dd7cddfSDavid du Colombier 	name = job->request.name;
5533e12c5d1SDavid du Colombier 	if((mf->qid.path & CHDIR) == 0){
5543e12c5d1SDavid du Colombier 		err = "not a directory";
5553e12c5d1SDavid du Colombier 		goto send;
5563e12c5d1SDavid du Colombier 	}
5573e12c5d1SDavid du Colombier 	if(strcmp(name, ".") == 0){
5583e12c5d1SDavid du Colombier 		mf->qid.path = CHDIR;
5593e12c5d1SDavid du Colombier 		goto send;
5603e12c5d1SDavid du Colombier 	}
5613e12c5d1SDavid du Colombier 	if(strcmp(name, "cs") == 0){
5623e12c5d1SDavid du Colombier 		mf->qid.path = Qcs;
5633e12c5d1SDavid du Colombier 		goto send;
5643e12c5d1SDavid du Colombier 	}
5653e12c5d1SDavid du Colombier 	err = "nonexistent file";
5663e12c5d1SDavid du Colombier     send:
567*7dd7cddfSDavid du Colombier 	job->reply.qid = mf->qid;
568*7dd7cddfSDavid du Colombier 	sendmsg(job, err);
5693e12c5d1SDavid du Colombier 	return err;
5703e12c5d1SDavid du Colombier }
5713e12c5d1SDavid du Colombier 
5723e12c5d1SDavid du Colombier void
573*7dd7cddfSDavid du Colombier ropen(Job *job, Mfile *mf)
5743e12c5d1SDavid du Colombier {
5753e12c5d1SDavid du Colombier 	int mode;
5763e12c5d1SDavid du Colombier 	char *err;
5773e12c5d1SDavid du Colombier 
5783e12c5d1SDavid du Colombier 	err = 0;
579*7dd7cddfSDavid du Colombier 	mode = job->request.mode;
5803e12c5d1SDavid du Colombier 	if(mf->qid.path & CHDIR){
5813e12c5d1SDavid du Colombier 		if(mode)
5823e12c5d1SDavid du Colombier 			err = "permission denied";
5833e12c5d1SDavid du Colombier 	}
584*7dd7cddfSDavid du Colombier 	job->reply.qid = mf->qid;
585*7dd7cddfSDavid du Colombier 	sendmsg(job, err);
5863e12c5d1SDavid du Colombier }
5873e12c5d1SDavid du Colombier 
5883e12c5d1SDavid du Colombier void
589*7dd7cddfSDavid du Colombier rcreate(Job *job, Mfile *mf)
5903e12c5d1SDavid du Colombier {
5913e12c5d1SDavid du Colombier 	USED(mf);
592*7dd7cddfSDavid du Colombier 	sendmsg(job, "creation permission denied");
5933e12c5d1SDavid du Colombier }
5943e12c5d1SDavid du Colombier 
5953e12c5d1SDavid du Colombier void
596*7dd7cddfSDavid du Colombier rread(Job *job, Mfile *mf)
5973e12c5d1SDavid du Colombier {
598219b2ee8SDavid du Colombier 	int i, n, cnt;
599219b2ee8SDavid du Colombier 	long off, toff, clock;
6003e12c5d1SDavid du Colombier 	Dir dir;
6013e12c5d1SDavid du Colombier 	char buf[MAXFDATA];
6023e12c5d1SDavid du Colombier 	char *err;
6033e12c5d1SDavid du Colombier 
6043e12c5d1SDavid du Colombier 	n = 0;
6053e12c5d1SDavid du Colombier 	err = 0;
606*7dd7cddfSDavid du Colombier 	off = job->request.offset;
607*7dd7cddfSDavid du Colombier 	cnt = job->request.count;
6083e12c5d1SDavid du Colombier 	if(mf->qid.path & CHDIR){
6093e12c5d1SDavid du Colombier 		if(off%DIRLEN || cnt%DIRLEN){
6103e12c5d1SDavid du Colombier 			err = "bad offset";
6113e12c5d1SDavid du Colombier 			goto send;
6123e12c5d1SDavid du Colombier 		}
6133e12c5d1SDavid du Colombier 		clock = time(0);
6143e12c5d1SDavid du Colombier 		if(off == 0){
6153e12c5d1SDavid du Colombier 			memmove(dir.name, "cs", NAMELEN);
6163e12c5d1SDavid du Colombier 			dir.qid.vers = vers;
6173e12c5d1SDavid du Colombier 			dir.qid.path = Qcs;
6183e12c5d1SDavid du Colombier 			dir.mode = 0666;
6193e12c5d1SDavid du Colombier 			dir.length = 0;
6203e12c5d1SDavid du Colombier 			strcpy(dir.uid, mf->user);
6213e12c5d1SDavid du Colombier 			strcpy(dir.gid, mf->user);
6223e12c5d1SDavid du Colombier 			dir.atime = clock;	/* wrong */
6233e12c5d1SDavid du Colombier 			dir.mtime = clock;	/* wrong */
6243e12c5d1SDavid du Colombier 			convD2M(&dir, buf+n);
6253e12c5d1SDavid du Colombier 			n += DIRLEN;
6263e12c5d1SDavid du Colombier 		}
627*7dd7cddfSDavid du Colombier 		job->reply.data = buf;
6283e12c5d1SDavid du Colombier 	} else {
629219b2ee8SDavid du Colombier 		toff = 0;
630219b2ee8SDavid du Colombier 		for(i = 0; mf->reply[i] && i < mf->nreply; i++){
631219b2ee8SDavid du Colombier 			n = mf->replylen[i];
632219b2ee8SDavid du Colombier 			if(off < toff + n)
633219b2ee8SDavid du Colombier 				break;
634219b2ee8SDavid du Colombier 			toff += n;
6353e12c5d1SDavid du Colombier 		}
636219b2ee8SDavid du Colombier 		if(i >= mf->nreply){
637219b2ee8SDavid du Colombier 			n = 0;
638219b2ee8SDavid du Colombier 			goto send;
639219b2ee8SDavid du Colombier 		}
640*7dd7cddfSDavid du Colombier 		job->reply.data = mf->reply[i] + (off - toff);
641219b2ee8SDavid du Colombier 		if(cnt > toff - off + n)
642219b2ee8SDavid du Colombier 			n = toff - off + n;
643219b2ee8SDavid du Colombier 		else
644219b2ee8SDavid du Colombier 			n = cnt;
6453e12c5d1SDavid du Colombier 	}
6463e12c5d1SDavid du Colombier send:
647*7dd7cddfSDavid du Colombier 	job->reply.count = n;
648*7dd7cddfSDavid du Colombier 	sendmsg(job, err);
649*7dd7cddfSDavid du Colombier }
650*7dd7cddfSDavid du Colombier 
651*7dd7cddfSDavid du Colombier CacheEntry*
652*7dd7cddfSDavid du Colombier nextcache(char *question, ulong now)
653*7dd7cddfSDavid du Colombier {
654*7dd7cddfSDavid du Colombier 	CacheEntry *cp;
655*7dd7cddfSDavid du Colombier 	int i;
656*7dd7cddfSDavid du Colombier 
657*7dd7cddfSDavid du Colombier 	cp = &cache.e[cache.next];
658*7dd7cddfSDavid du Colombier 	cache.next = (cache.next + 1)%Ncache;
659*7dd7cddfSDavid du Colombier 	cp->expire = now + 120;
660*7dd7cddfSDavid du Colombier 
661*7dd7cddfSDavid du Colombier 	/* out with the old air */
662*7dd7cddfSDavid du Colombier 	if(cp->question){
663*7dd7cddfSDavid du Colombier 		free(cp->question);
664*7dd7cddfSDavid du Colombier 		cp->question = 0;
665*7dd7cddfSDavid du Colombier 	}
666*7dd7cddfSDavid du Colombier 	for(i = 0; i < cp->nreply; i++)
667*7dd7cddfSDavid du Colombier 		free(cp->reply[i]);
668*7dd7cddfSDavid du Colombier 	cp->err[0] = 0;
669*7dd7cddfSDavid du Colombier 	cp->nreply = 0;
670*7dd7cddfSDavid du Colombier 
671*7dd7cddfSDavid du Colombier 	/* in with the new */
672*7dd7cddfSDavid du Colombier 	cp->question = question;
673*7dd7cddfSDavid du Colombier 	return cp;
674*7dd7cddfSDavid du Colombier }
675*7dd7cddfSDavid du Colombier 
676*7dd7cddfSDavid du Colombier CacheEntry*
677*7dd7cddfSDavid du Colombier searchcache(char *question, ulong now)
678*7dd7cddfSDavid du Colombier {
679*7dd7cddfSDavid du Colombier 	CacheEntry *cp;
680*7dd7cddfSDavid du Colombier 
681*7dd7cddfSDavid du Colombier 	for(cp = cache.e; cp < &cache.e[Ncache]; cp++){
682*7dd7cddfSDavid du Colombier 		if(cp->expire > now)
683*7dd7cddfSDavid du Colombier 		if(strcmp(question, cp->question) == 0)
684*7dd7cddfSDavid du Colombier 			return cp;
685*7dd7cddfSDavid du Colombier 	}
686*7dd7cddfSDavid du Colombier 	return 0;
6873e12c5d1SDavid du Colombier }
6883e12c5d1SDavid du Colombier 
6893e12c5d1SDavid du Colombier void
690*7dd7cddfSDavid du Colombier rwrite(Job *job, Mfile *mf)
6913e12c5d1SDavid du Colombier {
6923e12c5d1SDavid du Colombier 	int cnt, n;
693*7dd7cddfSDavid du Colombier 	char *question, *err, errbuf[ERRLEN];
694*7dd7cddfSDavid du Colombier 	char *field[4];
695*7dd7cddfSDavid du Colombier 	int i, rv;
696*7dd7cddfSDavid du Colombier 	ulong now;
697*7dd7cddfSDavid du Colombier 	CacheEntry *cp;
6983e12c5d1SDavid du Colombier 
699*7dd7cddfSDavid du Colombier 	now = time(0);
7003e12c5d1SDavid du Colombier 	err = 0;
701*7dd7cddfSDavid du Colombier 	cnt = job->request.count;
7023e12c5d1SDavid du Colombier 	if(mf->qid.path & CHDIR){
7033e12c5d1SDavid du Colombier 		err = "can't write directory";
7043e12c5d1SDavid du Colombier 		goto send;
7053e12c5d1SDavid du Colombier 	}
7063e12c5d1SDavid du Colombier 	if(cnt >= Maxrequest){
7073e12c5d1SDavid du Colombier 		err = "request too long";
7083e12c5d1SDavid du Colombier 		goto send;
7093e12c5d1SDavid du Colombier 	}
710*7dd7cddfSDavid du Colombier 	job->request.data[cnt] = 0;
7113e12c5d1SDavid du Colombier 
7123e12c5d1SDavid du Colombier 	/*
713219b2ee8SDavid du Colombier 	 *  toggle debugging
714219b2ee8SDavid du Colombier 	 */
715*7dd7cddfSDavid du Colombier 	if(strncmp(job->request.data, "debug", 5)==0){
716219b2ee8SDavid du Colombier 		debug ^= 1;
717219b2ee8SDavid du Colombier 		syslog(1, logfile, "debug %d", debug);
718219b2ee8SDavid du Colombier 		goto send;
719219b2ee8SDavid du Colombier 	}
720219b2ee8SDavid du Colombier 
721219b2ee8SDavid du Colombier 	/*
722*7dd7cddfSDavid du Colombier 	 *  toggle debugging
723*7dd7cddfSDavid du Colombier 	 */
724*7dd7cddfSDavid du Colombier 	if(strncmp(job->request.data, "paranoia", 8)==0){
725*7dd7cddfSDavid du Colombier 		paranoia ^= 1;
726*7dd7cddfSDavid du Colombier 		syslog(1, logfile, "paranoia %d", paranoia);
727*7dd7cddfSDavid du Colombier 		goto send;
728*7dd7cddfSDavid du Colombier 	}
729*7dd7cddfSDavid du Colombier 
730*7dd7cddfSDavid du Colombier 	/*
7313e12c5d1SDavid du Colombier 	 *  add networks to the default list
7323e12c5d1SDavid du Colombier 	 */
733*7dd7cddfSDavid du Colombier 	if(strncmp(job->request.data, "add ", 4)==0){
734*7dd7cddfSDavid du Colombier 		if(job->request.data[cnt-1] == '\n')
735*7dd7cddfSDavid du Colombier 			job->request.data[cnt-1] = 0;
736*7dd7cddfSDavid du Colombier 		netadd(job->request.data+4);
737*7dd7cddfSDavid du Colombier 		readipinterfaces();
738*7dd7cddfSDavid du Colombier 		goto send;
739*7dd7cddfSDavid du Colombier 	}
740*7dd7cddfSDavid du Colombier 
741*7dd7cddfSDavid du Colombier 	/*
742*7dd7cddfSDavid du Colombier 	 *  refresh all state
743*7dd7cddfSDavid du Colombier 	 */
744*7dd7cddfSDavid du Colombier 	if(strncmp(job->request.data, "refresh", 7)==0){
745*7dd7cddfSDavid du Colombier 		netinit(1);
746*7dd7cddfSDavid du Colombier 		for(i = 0; i < Ncache; i++)
747*7dd7cddfSDavid du Colombier 			cache.e[i].expire = 0;
7483e12c5d1SDavid du Colombier 		goto send;
7493e12c5d1SDavid du Colombier 	}
7503e12c5d1SDavid du Colombier 
7513e12c5d1SDavid du Colombier 	/*
752219b2ee8SDavid du Colombier 	 *  look for a general query
753219b2ee8SDavid du Colombier 	 */
754*7dd7cddfSDavid du Colombier 	if(*job->request.data == '!'){
755*7dd7cddfSDavid du Colombier 		err = genquery(mf, job->request.data+1);
756219b2ee8SDavid du Colombier 		goto send;
757219b2ee8SDavid du Colombier 	}
758219b2ee8SDavid du Colombier 
759*7dd7cddfSDavid du Colombier 	/* start transaction with a clean slate */
760*7dd7cddfSDavid du Colombier 	for(i = 0; i < Nreply; i++){
761*7dd7cddfSDavid du Colombier 		if(mf->reply[i])
762*7dd7cddfSDavid du Colombier 			free(mf->reply[i]);
763*7dd7cddfSDavid du Colombier 		mf->reply[i] = 0;
764*7dd7cddfSDavid du Colombier 		mf->replylen[i] = 0;
765*7dd7cddfSDavid du Colombier 	}
766*7dd7cddfSDavid du Colombier 	mf->nreply = 0;
767*7dd7cddfSDavid du Colombier 
768*7dd7cddfSDavid du Colombier 	if(debug)
769*7dd7cddfSDavid du Colombier 		syslog(0, logfile, "write %s", job->request.data);
770*7dd7cddfSDavid du Colombier 	if(paranoia)
771*7dd7cddfSDavid du Colombier 		syslog(0, paranoiafile, "write %s by %s", job->request.data, mf->user);
772*7dd7cddfSDavid du Colombier 
773*7dd7cddfSDavid du Colombier 	/* first try cache */
774*7dd7cddfSDavid du Colombier 	lock(&cache);
775*7dd7cddfSDavid du Colombier 	cp = searchcache(job->request.data, now);
776*7dd7cddfSDavid du Colombier 	if(cp){
777*7dd7cddfSDavid du Colombier 		if(cp->err[0]){
778*7dd7cddfSDavid du Colombier 			memmove(errbuf, cp->err, ERRLEN);
779*7dd7cddfSDavid du Colombier 			err = errbuf;
780*7dd7cddfSDavid du Colombier 		} else {
781*7dd7cddfSDavid du Colombier 			for(i = 0; i < cp->nreply; i++){
782*7dd7cddfSDavid du Colombier 				mf->reply[i] = strdup(cp->reply[i]);
783*7dd7cddfSDavid du Colombier 				mf->replylen[i] = strlen(cp->reply[i]);
784*7dd7cddfSDavid du Colombier 			}
785*7dd7cddfSDavid du Colombier 			mf->nreply = cp->nreply;
786*7dd7cddfSDavid du Colombier 		}
787*7dd7cddfSDavid du Colombier 		unlock(&cache);
788*7dd7cddfSDavid du Colombier 		goto send;
789*7dd7cddfSDavid du Colombier 	}
790*7dd7cddfSDavid du Colombier 	unlock(&cache);
791*7dd7cddfSDavid du Colombier 
792219b2ee8SDavid du Colombier 	/*
7933e12c5d1SDavid du Colombier 	 *  break up name
7943e12c5d1SDavid du Colombier 	 */
795*7dd7cddfSDavid du Colombier 	question = strdup(job->request.data);
796*7dd7cddfSDavid du Colombier 	n = getfields(job->request.data, field, 4, 1, "!");
7973e12c5d1SDavid du Colombier 	rv = -1;
7983e12c5d1SDavid du Colombier 	switch(n){
7993e12c5d1SDavid du Colombier 	case 1:
800*7dd7cddfSDavid du Colombier 		rv = lookup(mf, "net", field[0], 0, 0);
8013e12c5d1SDavid du Colombier 		break;
8023e12c5d1SDavid du Colombier 	case 2:
803*7dd7cddfSDavid du Colombier 		rv = lookup(mf, field[0], field[1], 0, 0);
8043e12c5d1SDavid du Colombier 		break;
8053e12c5d1SDavid du Colombier 	case 3:
806*7dd7cddfSDavid du Colombier 		rv = lookup(mf, field[0], field[1], field[2], 0);
807*7dd7cddfSDavid du Colombier 		break;
808*7dd7cddfSDavid du Colombier 	case 4:
809*7dd7cddfSDavid du Colombier 		rv = lookup(mf, field[0], field[1], field[2], field[3]);
8103e12c5d1SDavid du Colombier 		break;
8113e12c5d1SDavid du Colombier 	}
8123e12c5d1SDavid du Colombier 
813*7dd7cddfSDavid du Colombier 	lock(&cache);
814*7dd7cddfSDavid du Colombier 	cp = nextcache(question, now);
815*7dd7cddfSDavid du Colombier 	if(rv < 0){
8163e12c5d1SDavid du Colombier 		err = "can't translate address";
817*7dd7cddfSDavid du Colombier 		errstr(errbuf);
818*7dd7cddfSDavid du Colombier 		if(strstr(errbuf, "dns:"))
819*7dd7cddfSDavid du Colombier 			err = errbuf;
820*7dd7cddfSDavid du Colombier 		strncpy(cp->err, err, ERRLEN);
821*7dd7cddfSDavid du Colombier 	} else {
822*7dd7cddfSDavid du Colombier 		for(i = 0; i < mf->nreply; i++)
823*7dd7cddfSDavid du Colombier 			cp->reply[i] = strdup(mf->reply[i]);
824*7dd7cddfSDavid du Colombier 		cp->nreply = mf->nreply;
825*7dd7cddfSDavid du Colombier 	}
826*7dd7cddfSDavid du Colombier 	unlock(&cache);
8273e12c5d1SDavid du Colombier 
8283e12c5d1SDavid du Colombier     send:
829*7dd7cddfSDavid du Colombier 	job->reply.count = cnt;
830*7dd7cddfSDavid du Colombier 	sendmsg(job, err);
8313e12c5d1SDavid du Colombier }
8323e12c5d1SDavid du Colombier 
8333e12c5d1SDavid du Colombier void
834*7dd7cddfSDavid du Colombier rclunk(Job *job, Mfile *mf)
8353e12c5d1SDavid du Colombier {
836219b2ee8SDavid du Colombier 	int i;
837219b2ee8SDavid du Colombier 
838219b2ee8SDavid du Colombier 	for(i = 0; i < mf->nreply; i++)
839219b2ee8SDavid du Colombier 		free(mf->reply[i]);
840*7dd7cddfSDavid du Colombier 	mf->nreply = 0;
841*7dd7cddfSDavid du Colombier 
8423e12c5d1SDavid du Colombier 	mf->busy = 0;
8433e12c5d1SDavid du Colombier 	mf->fid = 0;
844*7dd7cddfSDavid du Colombier 	sendmsg(job, 0);
8453e12c5d1SDavid du Colombier }
8463e12c5d1SDavid du Colombier 
8473e12c5d1SDavid du Colombier void
848*7dd7cddfSDavid du Colombier rremove(Job *job, Mfile *mf)
8493e12c5d1SDavid du Colombier {
8503e12c5d1SDavid du Colombier 	USED(mf);
851*7dd7cddfSDavid du Colombier 	sendmsg(job, "remove permission denied");
8523e12c5d1SDavid du Colombier }
8533e12c5d1SDavid du Colombier 
8543e12c5d1SDavid du Colombier void
855*7dd7cddfSDavid du Colombier rstat(Job *job, Mfile *mf)
8563e12c5d1SDavid du Colombier {
8573e12c5d1SDavid du Colombier 	Dir dir;
8583e12c5d1SDavid du Colombier 
859219b2ee8SDavid du Colombier 	if(mf->qid.path & CHDIR){
860219b2ee8SDavid du Colombier 		strcpy(dir.name, ".");
861219b2ee8SDavid du Colombier 		dir.mode = CHDIR|0555;
862219b2ee8SDavid du Colombier 	} else {
863219b2ee8SDavid du Colombier 		strcpy(dir.name, "cs");
8643e12c5d1SDavid du Colombier 		dir.mode = 0666;
865219b2ee8SDavid du Colombier 	}
866219b2ee8SDavid du Colombier 	dir.qid = mf->qid;
8673e12c5d1SDavid du Colombier 	dir.length = 0;
8683e12c5d1SDavid du Colombier 	strcpy(dir.uid, mf->user);
8693e12c5d1SDavid du Colombier 	strcpy(dir.gid, mf->user);
8703e12c5d1SDavid du Colombier 	dir.atime = dir.mtime = time(0);
871*7dd7cddfSDavid du Colombier 	convD2M(&dir, (char*)job->reply.stat);
872*7dd7cddfSDavid du Colombier 	sendmsg(job, 0);
8733e12c5d1SDavid du Colombier }
8743e12c5d1SDavid du Colombier 
8753e12c5d1SDavid du Colombier void
876*7dd7cddfSDavid du Colombier rwstat(Job *job, Mfile *mf)
8773e12c5d1SDavid du Colombier {
8783e12c5d1SDavid du Colombier 	USED(mf);
879*7dd7cddfSDavid du Colombier 	sendmsg(job, "wstat permission denied");
8803e12c5d1SDavid du Colombier }
8813e12c5d1SDavid du Colombier 
8823e12c5d1SDavid du Colombier void
883*7dd7cddfSDavid du Colombier sendmsg(Job *job, char *err)
8843e12c5d1SDavid du Colombier {
8853e12c5d1SDavid du Colombier 	int n;
8863e12c5d1SDavid du Colombier 	char mdata[MAXFDATA + MAXMSG];
8873e12c5d1SDavid du Colombier 
8883e12c5d1SDavid du Colombier 	if(err){
889*7dd7cddfSDavid du Colombier 		job->reply.type = Rerror;
890*7dd7cddfSDavid du Colombier 		snprint(job->reply.ename, sizeof(job->reply.ename), "cs: %s", err);
8913e12c5d1SDavid du Colombier 	}else{
892*7dd7cddfSDavid du Colombier 		job->reply.type = job->request.type+1;
893*7dd7cddfSDavid du Colombier 		job->reply.fid = job->request.fid;
8943e12c5d1SDavid du Colombier 	}
895*7dd7cddfSDavid du Colombier 	job->reply.tag = job->request.tag;
896*7dd7cddfSDavid du Colombier 	n = convS2M(&job->reply, mdata);
897219b2ee8SDavid du Colombier 	if(n == 0){
898*7dd7cddfSDavid du Colombier 		syslog(1, logfile, "sendmsg convS2M of %F returns 0", &job->reply);
899219b2ee8SDavid du Colombier 		abort();
900219b2ee8SDavid du Colombier 	}
901*7dd7cddfSDavid du Colombier 	lock(&joblock);
902*7dd7cddfSDavid du Colombier 	if(job->flushed == 0)
903219b2ee8SDavid du Colombier 		if(write9p(mfd[1], mdata, n)!=n)
9043e12c5d1SDavid du Colombier 			error("mount write");
905*7dd7cddfSDavid du Colombier 	unlock(&joblock);
906219b2ee8SDavid du Colombier 	if(debug)
907*7dd7cddfSDavid du Colombier 		syslog(0, logfile, "%F %d", &job->reply, n);
9083e12c5d1SDavid du Colombier }
9093e12c5d1SDavid du Colombier 
9103e12c5d1SDavid du Colombier void
9113e12c5d1SDavid du Colombier error(char *s)
9123e12c5d1SDavid du Colombier {
913bd389b36SDavid du Colombier 	syslog(1, "cs", "%s: %r", s);
914bd389b36SDavid du Colombier 	_exits(0);
9153e12c5d1SDavid du Colombier }
9163e12c5d1SDavid du Colombier 
9173e12c5d1SDavid du Colombier /*
9183e12c5d1SDavid du Colombier  *  Network specific translators
9193e12c5d1SDavid du Colombier  */
920219b2ee8SDavid du Colombier Ndbtuple*	iplookup(Network*, char*, char*, int);
921*7dd7cddfSDavid du Colombier char*		iptrans(Ndbtuple*, Network*, char*, char*);
922219b2ee8SDavid du Colombier Ndbtuple*	telcolookup(Network*, char*, char*, int);
923*7dd7cddfSDavid du Colombier char*		telcotrans(Ndbtuple*, Network*, char*, char*);
924*7dd7cddfSDavid du Colombier Ndbtuple*	dnsiplookup(char*, Ndbs*);
9253e12c5d1SDavid du Colombier 
9263e12c5d1SDavid du Colombier struct Network
9273e12c5d1SDavid du Colombier {
9283e12c5d1SDavid du Colombier 	char		*net;
9293e12c5d1SDavid du Colombier 	int		nolookup;
930219b2ee8SDavid du Colombier 	Ndbtuple	*(*lookup)(Network*, char*, char*, int);
931*7dd7cddfSDavid du Colombier 	char		*(*trans)(Ndbtuple*, Network*, char*, char*);
9323e12c5d1SDavid du Colombier 	int		needproto;
9333e12c5d1SDavid du Colombier 	Network		*next;
934*7dd7cddfSDavid du Colombier 	int		considered;
9353e12c5d1SDavid du Colombier };
9363e12c5d1SDavid du Colombier 
937*7dd7cddfSDavid du Colombier enum
938*7dd7cddfSDavid du Colombier {
939*7dd7cddfSDavid du Colombier 	Nil,
940*7dd7cddfSDavid du Colombier 	Ntcp,
941*7dd7cddfSDavid du Colombier 	Nudp,
942*7dd7cddfSDavid du Colombier 	Nicmp,
943*7dd7cddfSDavid du Colombier 	Nrudp,
944*7dd7cddfSDavid du Colombier 	Ntelco,
9453e12c5d1SDavid du Colombier };
9463e12c5d1SDavid du Colombier 
947*7dd7cddfSDavid du Colombier /*
948*7dd7cddfSDavid du Colombier  *  net doesn't apply to udp, icmp, or telco (for speed)
949*7dd7cddfSDavid du Colombier  */
950*7dd7cddfSDavid du Colombier Network network[] = {
951*7dd7cddfSDavid du Colombier [Nil]		{ "il",		0, iplookup,	iptrans,	1, 0, 0, },
952*7dd7cddfSDavid du Colombier [Ntcp]		{ "tcp",	0, iplookup,	iptrans,	0, 0, 0, },
953*7dd7cddfSDavid du Colombier [Nudp]		{ "udp",	0, iplookup,	iptrans,	0, 0, 1, },
954*7dd7cddfSDavid du Colombier [Nicmp]		{ "icmp",	0, iplookup,	iptrans,	0, 0, 1, },
955*7dd7cddfSDavid du Colombier [Nrudp]		{ "rudp",	0, iplookup,	iptrans,	0, 0, 1, },
956*7dd7cddfSDavid du Colombier [Ntelco]	{ "telco",	0, telcolookup,	telcotrans,	0, 0, 1, },
957*7dd7cddfSDavid du Colombier 		{ 0,		0,  0,		0,		0, 0, 0, },
958*7dd7cddfSDavid du Colombier };
959*7dd7cddfSDavid du Colombier 
960*7dd7cddfSDavid du Colombier Lock ipifclock;
961*7dd7cddfSDavid du Colombier Ipifc *ipifcs;
962*7dd7cddfSDavid du Colombier 
9633e12c5d1SDavid du Colombier char	eaddr[Ndbvlen];		/* ascii ethernet address */
9643e12c5d1SDavid du Colombier char	ipaddr[Ndbvlen];	/* ascii internet address */
965*7dd7cddfSDavid du Colombier uchar	ipa[IPaddrlen];		/* binary internet address */
966*7dd7cddfSDavid du Colombier char	mysysname[Ndbvlen];
9673e12c5d1SDavid du Colombier 
9683e12c5d1SDavid du Colombier Network *netlist;		/* networks ordered by preference */
9693e12c5d1SDavid du Colombier Network *last;
9703e12c5d1SDavid du Colombier 
971*7dd7cddfSDavid du Colombier static int
972*7dd7cddfSDavid du Colombier isvalidip(uchar *ip)
973*7dd7cddfSDavid du Colombier {
974*7dd7cddfSDavid du Colombier 	return ipcmp(ip, IPnoaddr) != 0 && ipcmp(ip, v4prefix) != 0;
975*7dd7cddfSDavid du Colombier }
9763e12c5d1SDavid du Colombier 
977*7dd7cddfSDavid du Colombier void
978*7dd7cddfSDavid du Colombier readipinterfaces(void)
979*7dd7cddfSDavid du Colombier {
980*7dd7cddfSDavid du Colombier 	Ipifc *ifc;
981*7dd7cddfSDavid du Colombier 
982*7dd7cddfSDavid du Colombier 	lock(&ipifclock);
983*7dd7cddfSDavid du Colombier 	ipifcs = readipifc(mntpt, ipifcs);
984*7dd7cddfSDavid du Colombier 	unlock(&ipifclock);
985*7dd7cddfSDavid du Colombier 	for(ifc = ipifcs; ifc; ifc = ifc->next){
986*7dd7cddfSDavid du Colombier 		if(isvalidip(ifc->ip)){
987*7dd7cddfSDavid du Colombier 			ipmove(ipa, ifc->ip);
988*7dd7cddfSDavid du Colombier 			sprint(ipaddr, "%I", ipa);
989*7dd7cddfSDavid du Colombier 			if(debug)
990*7dd7cddfSDavid du Colombier 				syslog(0, "dns", "ipaddr is %s\n", ipaddr);
991*7dd7cddfSDavid du Colombier 			break;
992*7dd7cddfSDavid du Colombier 		}
993*7dd7cddfSDavid du Colombier 	}
994*7dd7cddfSDavid du Colombier }
9953e12c5d1SDavid du Colombier 
9963e12c5d1SDavid du Colombier /*
997*7dd7cddfSDavid du Colombier  *  get the system name
9983e12c5d1SDavid du Colombier  */
9993e12c5d1SDavid du Colombier void
10003e12c5d1SDavid du Colombier ipid(void)
10013e12c5d1SDavid du Colombier {
10023e12c5d1SDavid du Colombier 	uchar addr[6];
10033e12c5d1SDavid du Colombier 	Ndbtuple *t;
1004219b2ee8SDavid du Colombier 	char *p, *attr;
10053e12c5d1SDavid du Colombier 	Ndbs s;
10063e12c5d1SDavid du Colombier 	int f;
1007*7dd7cddfSDavid du Colombier 	char buf[Maxpath];
10083e12c5d1SDavid du Colombier 
10093e12c5d1SDavid du Colombier 
1010219b2ee8SDavid du Colombier 	/* use environment, ether addr, or ipaddr to get system name */
1011*7dd7cddfSDavid du Colombier 	if(*mysysname == 0){
1012*7dd7cddfSDavid du Colombier 		/*
1013*7dd7cddfSDavid du Colombier 		 *  environment has priority.
1014*7dd7cddfSDavid du Colombier 		 *
1015*7dd7cddfSDavid du Colombier 		 *  on the sgi power the default system name
1016*7dd7cddfSDavid du Colombier 		 *  is the ip address.  ignore that.
1017*7dd7cddfSDavid du Colombier 		 *
1018*7dd7cddfSDavid du Colombier 		 */
1019219b2ee8SDavid du Colombier 		p = getenv("sysname");
1020219b2ee8SDavid du Colombier 		if(p){
1021219b2ee8SDavid du Colombier 			attr = ipattr(p);
1022219b2ee8SDavid du Colombier 			if(strcmp(attr, "ip") != 0)
1023*7dd7cddfSDavid du Colombier 				strcpy(mysysname, p);
10243e12c5d1SDavid du Colombier 		}
10253e12c5d1SDavid du Colombier 
10263e12c5d1SDavid du Colombier 		/*
1027*7dd7cddfSDavid du Colombier 		 *  the /net/ndb contains what the network
1028*7dd7cddfSDavid du Colombier 		 *  figured out from DHCP.  use that name if
1029*7dd7cddfSDavid du Colombier 		 *  there is one.
10303e12c5d1SDavid du Colombier 		 */
1031*7dd7cddfSDavid du Colombier 		if(*mysysname == 0 && netdb != nil){
1032*7dd7cddfSDavid du Colombier 			ndbreopen(netdb);
1033*7dd7cddfSDavid du Colombier 			for(t = ndbparse(netdb); t != nil; t = t->entry){
1034*7dd7cddfSDavid du Colombier 				if(strcmp(t->attr, "sys") == 0){
1035*7dd7cddfSDavid du Colombier 					strcpy(mysysname, t->val);
10363e12c5d1SDavid du Colombier 					break;
10373e12c5d1SDavid du Colombier 				}
1038*7dd7cddfSDavid du Colombier 			}
1039*7dd7cddfSDavid du Colombier 			ndbfree(t);
1040*7dd7cddfSDavid du Colombier 		}
1041*7dd7cddfSDavid du Colombier 
1042*7dd7cddfSDavid du Colombier 		/* next network database, ip address, and ether address to find a name */
1043*7dd7cddfSDavid du Colombier 		if(*mysysname == 0){
1044*7dd7cddfSDavid du Colombier 			t = nil;
1045*7dd7cddfSDavid du Colombier 			if(isvalidip(ipa))
1046*7dd7cddfSDavid du Colombier 				t = ndbgetval(db, &s, "ip", ipaddr, "sys", mysysname);
1047*7dd7cddfSDavid du Colombier 			else {
1048*7dd7cddfSDavid du Colombier 				for(f = 0; f < 3; f++){
1049*7dd7cddfSDavid du Colombier 					snprint(buf, sizeof buf, "%s/ether%d", mntpt, f);
1050*7dd7cddfSDavid du Colombier 					if(myetheraddr(addr, buf) >= 0){
1051*7dd7cddfSDavid du Colombier 						snprint(eaddr, sizeof(eaddr), "%E", addr);
1052*7dd7cddfSDavid du Colombier 						t = ndbgetval(db, &s, "ether", eaddr, "sys",
1053*7dd7cddfSDavid du Colombier 							mysysname);
1054*7dd7cddfSDavid du Colombier 						if(t != nil)
1055*7dd7cddfSDavid du Colombier 							break;
1056*7dd7cddfSDavid du Colombier 					}
1057*7dd7cddfSDavid du Colombier 				}
1058*7dd7cddfSDavid du Colombier 			}
1059*7dd7cddfSDavid du Colombier 			ndbfree(t);
1060*7dd7cddfSDavid du Colombier 		}
1061*7dd7cddfSDavid du Colombier 
1062*7dd7cddfSDavid du Colombier 		/* set /dev/mysysname if we now know it */
1063*7dd7cddfSDavid du Colombier 		if(*mysysname){
1064*7dd7cddfSDavid du Colombier 			f = open("/dev/sysname", OWRITE);
1065*7dd7cddfSDavid du Colombier 			if(f >= 0){
1066*7dd7cddfSDavid du Colombier 				write(f, mysysname, strlen(mysysname));
10673e12c5d1SDavid du Colombier 				close(f);
10683e12c5d1SDavid du Colombier 			}
10693e12c5d1SDavid du Colombier 		}
10703e12c5d1SDavid du Colombier 	}
10713e12c5d1SDavid du Colombier }
10723e12c5d1SDavid du Colombier 
10733e12c5d1SDavid du Colombier /*
10743e12c5d1SDavid du Colombier  *  Set up a list of default networks by looking for
10753e12c5d1SDavid du Colombier  *  /net/ * /clone.
10763e12c5d1SDavid du Colombier  */
10773e12c5d1SDavid du Colombier void
1078*7dd7cddfSDavid du Colombier netinit(int background)
10793e12c5d1SDavid du Colombier {
1080*7dd7cddfSDavid du Colombier 	char clone[Maxpath];
10813e12c5d1SDavid du Colombier 	Dir d;
10823e12c5d1SDavid du Colombier 	Network *np;
1083*7dd7cddfSDavid du Colombier 	static int working;
1084*7dd7cddfSDavid du Colombier 
1085*7dd7cddfSDavid du Colombier 	if(background){
1086*7dd7cddfSDavid du Colombier 		switch(rfork(RFPROC|RFNOTEG|RFMEM|RFNOWAIT)){
1087*7dd7cddfSDavid du Colombier 		case 0:
1088*7dd7cddfSDavid du Colombier 			break;
1089*7dd7cddfSDavid du Colombier 		default:
1090*7dd7cddfSDavid du Colombier 			return;
1091*7dd7cddfSDavid du Colombier 		}
1092*7dd7cddfSDavid du Colombier 		lock(&netlock);
1093*7dd7cddfSDavid du Colombier 	}
10943e12c5d1SDavid du Colombier 
10953e12c5d1SDavid du Colombier 	/* add the mounted networks to the default list */
10963e12c5d1SDavid du Colombier 	for(np = network; np->net; np++){
1097*7dd7cddfSDavid du Colombier 		if(np->considered)
1098*7dd7cddfSDavid du Colombier 			continue;
1099*7dd7cddfSDavid du Colombier 		snprint(clone, sizeof(clone), "%s/%s/clone", mntpt, np->net);
11003e12c5d1SDavid du Colombier 		if(dirstat(clone, &d) < 0)
11013e12c5d1SDavid du Colombier 			continue;
11023e12c5d1SDavid du Colombier 		if(netlist)
11033e12c5d1SDavid du Colombier 			last->next = np;
11043e12c5d1SDavid du Colombier 		else
11053e12c5d1SDavid du Colombier 			netlist = np;
11063e12c5d1SDavid du Colombier 		last = np;
11073e12c5d1SDavid du Colombier 		np->next = 0;
1108*7dd7cddfSDavid du Colombier 		np->considered = 1;
11093e12c5d1SDavid du Colombier 	}
11103e12c5d1SDavid du Colombier 
1111*7dd7cddfSDavid du Colombier 	/* find out what our ip address is */
1112*7dd7cddfSDavid du Colombier 	readipinterfaces();
11133e12c5d1SDavid du Colombier 
1114*7dd7cddfSDavid du Colombier 	/* set the system name if we need to, these says ip is all we have */
11153e12c5d1SDavid du Colombier 	ipid();
11163e12c5d1SDavid du Colombier 
1117219b2ee8SDavid du Colombier 	if(debug)
1118*7dd7cddfSDavid du Colombier 		syslog(0, logfile, "mysysname %s eaddr %s ipaddr %s ipa %I\n",
1119*7dd7cddfSDavid du Colombier 			mysysname, eaddr, ipaddr, ipa);
1120*7dd7cddfSDavid du Colombier 
1121*7dd7cddfSDavid du Colombier 	if(background){
1122*7dd7cddfSDavid du Colombier 		unlock(&netlock);
1123*7dd7cddfSDavid du Colombier 		_exits(0);
1124*7dd7cddfSDavid du Colombier 	}
11253e12c5d1SDavid du Colombier }
11263e12c5d1SDavid du Colombier 
11273e12c5d1SDavid du Colombier /*
11283e12c5d1SDavid du Colombier  *  add networks to the standard list
11293e12c5d1SDavid du Colombier  */
11303e12c5d1SDavid du Colombier void
11313e12c5d1SDavid du Colombier netadd(char *p)
11323e12c5d1SDavid du Colombier {
11333e12c5d1SDavid du Colombier 	Network *np;
11343e12c5d1SDavid du Colombier 	char *field[12];
11353e12c5d1SDavid du Colombier 	int i, n;
11363e12c5d1SDavid du Colombier 
1137*7dd7cddfSDavid du Colombier 	n = getfields(p, field, 12, 1, " ");
11383e12c5d1SDavid du Colombier 	for(i = 0; i < n; i++){
11393e12c5d1SDavid du Colombier 		for(np = network; np->net; np++){
11403e12c5d1SDavid du Colombier 			if(strcmp(field[i], np->net) != 0)
11413e12c5d1SDavid du Colombier 				continue;
1142*7dd7cddfSDavid du Colombier 			if(np->considered)
11433e12c5d1SDavid du Colombier 				break;
11443e12c5d1SDavid du Colombier 			if(netlist)
11453e12c5d1SDavid du Colombier 				last->next = np;
11463e12c5d1SDavid du Colombier 			else
11473e12c5d1SDavid du Colombier 				netlist = np;
11483e12c5d1SDavid du Colombier 			last = np;
11493e12c5d1SDavid du Colombier 			np->next = 0;
1150*7dd7cddfSDavid du Colombier 			np->considered = 1;
11513e12c5d1SDavid du Colombier 		}
11523e12c5d1SDavid du Colombier 	}
11533e12c5d1SDavid du Colombier }
11543e12c5d1SDavid du Colombier 
11553e12c5d1SDavid du Colombier /*
1156219b2ee8SDavid du Colombier  *  make a tuple
1157219b2ee8SDavid du Colombier  */
1158219b2ee8SDavid du Colombier Ndbtuple*
1159219b2ee8SDavid du Colombier mktuple(char *attr, char *val)
1160219b2ee8SDavid du Colombier {
1161219b2ee8SDavid du Colombier 	Ndbtuple *t;
1162219b2ee8SDavid du Colombier 
1163*7dd7cddfSDavid du Colombier 	t = emalloc(sizeof(Ndbtuple));
1164219b2ee8SDavid du Colombier 	strcpy(t->attr, attr);
1165219b2ee8SDavid du Colombier 	strncpy(t->val, val, sizeof(t->val));
1166219b2ee8SDavid du Colombier 	t->val[sizeof(t->val)-1] = 0;
1167219b2ee8SDavid du Colombier 	t->line = t;
1168219b2ee8SDavid du Colombier 	t->entry = 0;
1169219b2ee8SDavid du Colombier 	return t;
1170219b2ee8SDavid du Colombier }
1171219b2ee8SDavid du Colombier 
1172219b2ee8SDavid du Colombier /*
11733e12c5d1SDavid du Colombier  *  lookup a request.  the network "net" means we should pick the
11743e12c5d1SDavid du Colombier  *  best network to get there.
11753e12c5d1SDavid du Colombier  */
11763e12c5d1SDavid du Colombier int
1177*7dd7cddfSDavid du Colombier lookup(Mfile *mf, char *net, char *host, char *serv, char *rem)
11783e12c5d1SDavid du Colombier {
1179219b2ee8SDavid du Colombier 	Network *np, *p;
1180219b2ee8SDavid du Colombier 	char *cp;
1181219b2ee8SDavid du Colombier 	Ndbtuple *nt, *t;
1182219b2ee8SDavid du Colombier 	char reply[Maxreply];
11833e12c5d1SDavid du Colombier 
11843e12c5d1SDavid du Colombier 	/* open up the standard db files */
11853e12c5d1SDavid du Colombier 	if(db == 0)
1186*7dd7cddfSDavid du Colombier 		ndbinit();
11873e12c5d1SDavid du Colombier 	if(db == 0)
11883e12c5d1SDavid du Colombier 		error("can't open network database\n");
11893e12c5d1SDavid du Colombier 
1190219b2ee8SDavid du Colombier 	nt = 0;
11913e12c5d1SDavid du Colombier 	if(strcmp(net, "net") == 0){
11923e12c5d1SDavid du Colombier 		/*
11933e12c5d1SDavid du Colombier 		 *  go through set of default nets
11943e12c5d1SDavid du Colombier 		 */
11953e12c5d1SDavid du Colombier 		for(np = netlist; np; np = np->next){
1196219b2ee8SDavid du Colombier 			nt = (*np->lookup)(np, host, serv, 0);
1197219b2ee8SDavid du Colombier 			if(nt){
1198219b2ee8SDavid du Colombier 				if(needproto(np, nt) == 0)
1199219b2ee8SDavid du Colombier 					break;
1200219b2ee8SDavid du Colombier 				ndbfree(nt);
1201219b2ee8SDavid du Colombier 				nt = 0;
1202bd389b36SDavid du Colombier 			}
12033e12c5d1SDavid du Colombier 		}
12043e12c5d1SDavid du Colombier 
12053e12c5d1SDavid du Colombier 		/*
12063e12c5d1SDavid du Colombier 		 *   try first net that requires no table lookup
12073e12c5d1SDavid du Colombier 		 */
1208219b2ee8SDavid du Colombier 		if(nt == 0)
12093e12c5d1SDavid du Colombier 			for(np = netlist; np; np = np->next){
12103e12c5d1SDavid du Colombier 				if(np->nolookup && *host != '$'){
1211219b2ee8SDavid du Colombier 					nt = (*np->lookup)(np, host, serv, 1);
1212219b2ee8SDavid du Colombier 					if(nt)
12133e12c5d1SDavid du Colombier 						break;
12143e12c5d1SDavid du Colombier 				}
12153e12c5d1SDavid du Colombier 			}
12163e12c5d1SDavid du Colombier 
1217219b2ee8SDavid du Colombier 		if(nt == 0)
12183e12c5d1SDavid du Colombier 			return -1;
1219219b2ee8SDavid du Colombier 
1220219b2ee8SDavid du Colombier 		/*
1221219b2ee8SDavid du Colombier 		 *  create replies
1222219b2ee8SDavid du Colombier 		 */
1223219b2ee8SDavid du Colombier 		for(p = np; p; p = p->next){
1224219b2ee8SDavid du Colombier 			for(t = nt; mf->nreply < Nreply && t; t = t->entry){
1225219b2ee8SDavid du Colombier 				if(needproto(p, nt) < 0)
1226219b2ee8SDavid du Colombier 					continue;
1227*7dd7cddfSDavid du Colombier 				cp = (*p->trans)(t, p, serv, rem);
1228219b2ee8SDavid du Colombier 				if(cp){
1229219b2ee8SDavid du Colombier 					mf->replylen[mf->nreply] = strlen(cp);
1230219b2ee8SDavid du Colombier 					mf->reply[mf->nreply++] = cp;
1231219b2ee8SDavid du Colombier 				}
1232219b2ee8SDavid du Colombier 			}
1233219b2ee8SDavid du Colombier 		}
1234219b2ee8SDavid du Colombier 		for(p = netlist; mf->nreply < Nreply && p != np; p = p->next){
1235219b2ee8SDavid du Colombier 			for(t = nt; mf->nreply < Nreply && t; t = t->entry){
1236219b2ee8SDavid du Colombier 				if(needproto(p, nt) < 0)
1237219b2ee8SDavid du Colombier 					continue;
1238*7dd7cddfSDavid du Colombier 				cp = (*p->trans)(t, p, serv, rem);
1239219b2ee8SDavid du Colombier 				if(cp){
1240219b2ee8SDavid du Colombier 					mf->replylen[mf->nreply] = strlen(cp);
1241219b2ee8SDavid du Colombier 					mf->reply[mf->nreply++] = cp;
1242219b2ee8SDavid du Colombier 				}
1243219b2ee8SDavid du Colombier 			}
1244219b2ee8SDavid du Colombier 		}
1245219b2ee8SDavid du Colombier 		ndbfree(nt);
1246219b2ee8SDavid du Colombier 		return 0;
12473e12c5d1SDavid du Colombier 	} else {
12483e12c5d1SDavid du Colombier 		/*
12493e12c5d1SDavid du Colombier 		 *  look on a specific network
12503e12c5d1SDavid du Colombier 		 */
1251219b2ee8SDavid du Colombier 		for(p = network; p->net; p++){
1252219b2ee8SDavid du Colombier 			if(strcmp(p->net, net) == 0){
1253219b2ee8SDavid du Colombier 				nt = (*p->lookup)(p, host, serv, 1);
1254219b2ee8SDavid du Colombier 				if (nt == 0)
1255219b2ee8SDavid du Colombier 					return -1;
1256219b2ee8SDavid du Colombier 
1257219b2ee8SDavid du Colombier 				/* create replies */
1258219b2ee8SDavid du Colombier 				for(t = nt; mf->nreply < Nreply && t; t = t->entry){
1259*7dd7cddfSDavid du Colombier 					cp = (*p->trans)(t, p, serv, rem);
1260219b2ee8SDavid du Colombier 					if(cp){
1261219b2ee8SDavid du Colombier 						mf->replylen[mf->nreply] = strlen(cp);
1262219b2ee8SDavid du Colombier 						mf->reply[mf->nreply++] = cp;
1263219b2ee8SDavid du Colombier 					}
1264219b2ee8SDavid du Colombier 				}
1265219b2ee8SDavid du Colombier 				ndbfree(nt);
1266219b2ee8SDavid du Colombier 				return 0;
12673e12c5d1SDavid du Colombier 			}
12683e12c5d1SDavid du Colombier 		}
12693e12c5d1SDavid du Colombier 	}
12703e12c5d1SDavid du Colombier 
12713e12c5d1SDavid du Colombier 	/*
1272219b2ee8SDavid du Colombier 	 *  not a known network, don't translate host or service
12733e12c5d1SDavid du Colombier 	 */
12743e12c5d1SDavid du Colombier 	if(serv)
1275*7dd7cddfSDavid du Colombier 		snprint(reply, sizeof(reply), "%s/%s/clone %s!%s",
1276*7dd7cddfSDavid du Colombier 			mntpt, net, host, serv);
1277bd389b36SDavid du Colombier 	else
1278*7dd7cddfSDavid du Colombier 		snprint(reply, sizeof(reply), "%s/%s/clone %s",
1279*7dd7cddfSDavid du Colombier 			mntpt, net, host);
1280219b2ee8SDavid du Colombier 	mf->reply[0] = strdup(reply);
1281219b2ee8SDavid du Colombier 	mf->replylen[0] = strlen(reply);
1282219b2ee8SDavid du Colombier 	mf->nreply = 1;
12833e12c5d1SDavid du Colombier 	return 0;
12843e12c5d1SDavid du Colombier }
12853e12c5d1SDavid du Colombier 
12863e12c5d1SDavid du Colombier /*
12873e12c5d1SDavid du Colombier  *  see if we can use this protocol
12883e12c5d1SDavid du Colombier  */
12893e12c5d1SDavid du Colombier int
12903e12c5d1SDavid du Colombier needproto(Network *np, Ndbtuple *t)
12913e12c5d1SDavid du Colombier {
12923e12c5d1SDavid du Colombier 	if(np->needproto == 0)
12933e12c5d1SDavid du Colombier 		return 0;
12943e12c5d1SDavid du Colombier 	for(; t; t = t->entry)
12953e12c5d1SDavid du Colombier 		if(strcmp(t->attr, "proto")==0 && strcmp(t->val, np->net)==0)
12963e12c5d1SDavid du Colombier 			return 0;
12973e12c5d1SDavid du Colombier 	return -1;
12983e12c5d1SDavid du Colombier }
12993e12c5d1SDavid du Colombier 
13003e12c5d1SDavid du Colombier /*
13013e12c5d1SDavid du Colombier  *  translate an ip service name into a port number.  If it's a numeric port
13023e12c5d1SDavid du Colombier  *  number, look for restricted access.
13033e12c5d1SDavid du Colombier  *
13043e12c5d1SDavid du Colombier  *  the service '*' needs no translation.
13053e12c5d1SDavid du Colombier  */
13063e12c5d1SDavid du Colombier char*
13073e12c5d1SDavid du Colombier ipserv(Network *np, char *name, char *buf)
13083e12c5d1SDavid du Colombier {
13093e12c5d1SDavid du Colombier 	char *p;
13103e12c5d1SDavid du Colombier 	int alpha = 0;
13113e12c5d1SDavid du Colombier 	int restr = 0;
13123e12c5d1SDavid du Colombier 	char port[Ndbvlen];
13133e12c5d1SDavid du Colombier 	Ndbtuple *t, *nt;
13143e12c5d1SDavid du Colombier 	Ndbs s;
13153e12c5d1SDavid du Colombier 
13163e12c5d1SDavid du Colombier 	/* '*' means any service */
13173e12c5d1SDavid du Colombier 	if(strcmp(name, "*")==0){
13183e12c5d1SDavid du Colombier 		strcpy(buf, name);
13193e12c5d1SDavid du Colombier 		return buf;
13203e12c5d1SDavid du Colombier 	}
13213e12c5d1SDavid du Colombier 
13223e12c5d1SDavid du Colombier 	/*  see if it's numeric or symbolic */
13233e12c5d1SDavid du Colombier 	port[0] = 0;
13243e12c5d1SDavid du Colombier 	for(p = name; *p; p++){
13253e12c5d1SDavid du Colombier 		if(isdigit(*p))
13263e12c5d1SDavid du Colombier 			;
13273e12c5d1SDavid du Colombier 		else if(isalpha(*p) || *p == '-' || *p == '$')
13283e12c5d1SDavid du Colombier 			alpha = 1;
13293e12c5d1SDavid du Colombier 		else
13303e12c5d1SDavid du Colombier 			return 0;
13313e12c5d1SDavid du Colombier 	}
13323e12c5d1SDavid du Colombier 	if(alpha){
13333e12c5d1SDavid du Colombier 		t = ndbgetval(db, &s, np->net, name, "port", port);
13343e12c5d1SDavid du Colombier 		if(t == 0)
13353e12c5d1SDavid du Colombier 			return 0;
13363e12c5d1SDavid du Colombier 	} else {
13373e12c5d1SDavid du Colombier 		t = ndbgetval(db, &s, "port", name, "port", port);
13383e12c5d1SDavid du Colombier 		if(t == 0){
13393e12c5d1SDavid du Colombier 			strncpy(port, name, sizeof(port));
13403e12c5d1SDavid du Colombier 			port[sizeof(port)-1] = 0;
13413e12c5d1SDavid du Colombier 		}
13423e12c5d1SDavid du Colombier 	}
13433e12c5d1SDavid du Colombier 
13443e12c5d1SDavid du Colombier 	if(t){
13453e12c5d1SDavid du Colombier 		for(nt = t; nt; nt = nt->entry)
13463e12c5d1SDavid du Colombier 			if(strcmp(nt->attr, "restricted") == 0)
13473e12c5d1SDavid du Colombier 				restr = 1;
13483e12c5d1SDavid du Colombier 		ndbfree(t);
13493e12c5d1SDavid du Colombier 	}
13503e12c5d1SDavid du Colombier 	sprint(buf, "%s%s", port, restr ? "!r" : "");
13513e12c5d1SDavid du Colombier 	return buf;
13523e12c5d1SDavid du Colombier }
13533e12c5d1SDavid du Colombier 
13543e12c5d1SDavid du Colombier /*
1355*7dd7cddfSDavid du Colombier  *  lookup an ip attribute
13563e12c5d1SDavid du Colombier  */
1357*7dd7cddfSDavid du Colombier int
1358*7dd7cddfSDavid du Colombier ipattrlookup(Ndb *db, char *ipa, char *attr, char *val)
13593e12c5d1SDavid du Colombier {
13603e12c5d1SDavid du Colombier 
1361*7dd7cddfSDavid du Colombier 	Ndbtuple *t, *nt;
1362*7dd7cddfSDavid du Colombier 	char *alist[2];
13633e12c5d1SDavid du Colombier 
1364*7dd7cddfSDavid du Colombier 	alist[0] = attr;
1365*7dd7cddfSDavid du Colombier 	t = ndbipinfo(db, "ip", ipa, alist, 1);
1366*7dd7cddfSDavid du Colombier 	if(t == nil)
1367*7dd7cddfSDavid du Colombier 		return 0;
1368*7dd7cddfSDavid du Colombier 	for(nt = t; nt != nil; nt = nt->entry)
1369*7dd7cddfSDavid du Colombier 		if(strcmp(nt->attr, attr) == 0){
1370*7dd7cddfSDavid du Colombier 			strcpy(val, nt->val);
13713e12c5d1SDavid du Colombier 			ndbfree(t);
1372*7dd7cddfSDavid du Colombier 			return 1;
1373219b2ee8SDavid du Colombier 		}
13743e12c5d1SDavid du Colombier 
1375*7dd7cddfSDavid du Colombier 	/* we shouldn't get here */
13763e12c5d1SDavid du Colombier 	ndbfree(t);
1377*7dd7cddfSDavid du Colombier 	return 0;
13783e12c5d1SDavid du Colombier }
13793e12c5d1SDavid du Colombier 
13803e12c5d1SDavid du Colombier /*
13813e12c5d1SDavid du Colombier  *  lookup (and translate) an ip destination
13823e12c5d1SDavid du Colombier  */
1383219b2ee8SDavid du Colombier Ndbtuple*
1384219b2ee8SDavid du Colombier iplookup(Network *np, char *host, char *serv, int nolookup)
13853e12c5d1SDavid du Colombier {
13863e12c5d1SDavid du Colombier 	char *attr;
1387*7dd7cddfSDavid du Colombier 	Ndbtuple *t, *nt;
13883e12c5d1SDavid du Colombier 	Ndbs s;
13893e12c5d1SDavid du Colombier 	char ts[Ndbvlen+1];
13903e12c5d1SDavid du Colombier 	char th[Ndbvlen+1];
13913e12c5d1SDavid du Colombier 	char dollar[Ndbvlen+1];
1392*7dd7cddfSDavid du Colombier 	uchar ip[IPaddrlen];
1393*7dd7cddfSDavid du Colombier 	uchar net[IPaddrlen];
1394*7dd7cddfSDavid du Colombier 	uchar tnet[IPaddrlen];
1395*7dd7cddfSDavid du Colombier 	Ipifc *ifc;
13963e12c5d1SDavid du Colombier 
1397219b2ee8SDavid du Colombier 	USED(nolookup);
1398219b2ee8SDavid du Colombier 
13993e12c5d1SDavid du Colombier 	/*
14003e12c5d1SDavid du Colombier 	 *  start with the service since it's the most likely to fail
14013e12c5d1SDavid du Colombier 	 *  and costs the least
14023e12c5d1SDavid du Colombier 	 */
1403*7dd7cddfSDavid du Colombier 	if(serv==0 || ipserv(np, serv, ts) == 0){
1404*7dd7cddfSDavid du Colombier 		werrstr("can't translate address");
1405219b2ee8SDavid du Colombier 		return 0;
1406*7dd7cddfSDavid du Colombier 	}
14073e12c5d1SDavid du Colombier 
14083e12c5d1SDavid du Colombier 	/* for dial strings with no host */
1409219b2ee8SDavid du Colombier 	if(strcmp(host, "*") == 0)
1410219b2ee8SDavid du Colombier 		return mktuple("ip", "*");
14113e12c5d1SDavid du Colombier 
14123e12c5d1SDavid du Colombier 	/*
1413*7dd7cddfSDavid du Colombier 	 *  hack till we go v6 :: = 0.0.0.0
1414*7dd7cddfSDavid du Colombier 	 */
1415*7dd7cddfSDavid du Colombier 	if(strcmp("::", host) == 0)
1416*7dd7cddfSDavid du Colombier 		return mktuple("ip", "*");
1417*7dd7cddfSDavid du Colombier 
1418*7dd7cddfSDavid du Colombier 	/*
14193e12c5d1SDavid du Colombier 	 *  '$' means the rest of the name is an attribute that we
14203e12c5d1SDavid du Colombier 	 *  need to search for
14213e12c5d1SDavid du Colombier 	 */
14223e12c5d1SDavid du Colombier 	if(*host == '$'){
1423*7dd7cddfSDavid du Colombier 		if(ipattrlookup(db, ipaddr, host+1, dollar))
14243e12c5d1SDavid du Colombier 			host = dollar;
14253e12c5d1SDavid du Colombier 	}
14263e12c5d1SDavid du Colombier 
14273e12c5d1SDavid du Colombier 	/*
1428*7dd7cddfSDavid du Colombier 	 *  turn '[ip address]' into just 'ip address'
1429*7dd7cddfSDavid du Colombier 	 */
1430*7dd7cddfSDavid du Colombier 	if(*host == '[' && host[strlen(host)-1] == ']'){
1431*7dd7cddfSDavid du Colombier 		host++;
1432*7dd7cddfSDavid du Colombier 		host[strlen(host)-1] = 0;
1433*7dd7cddfSDavid du Colombier 	}
1434*7dd7cddfSDavid du Colombier 
1435*7dd7cddfSDavid du Colombier 	/*
14363e12c5d1SDavid du Colombier 	 *  just accept addresses
14373e12c5d1SDavid du Colombier 	 */
1438219b2ee8SDavid du Colombier 	attr = ipattr(host);
1439219b2ee8SDavid du Colombier 	if(strcmp(attr, "ip") == 0)
1440219b2ee8SDavid du Colombier 		return mktuple("ip", host);
14413e12c5d1SDavid du Colombier 
14423e12c5d1SDavid du Colombier 	/*
14433e12c5d1SDavid du Colombier 	 *  give the domain name server the first opportunity to
1444bd389b36SDavid du Colombier 	 *  resolve domain names.  if that fails try the database.
14453e12c5d1SDavid du Colombier 	 */
14463e12c5d1SDavid du Colombier 	t = 0;
14473e12c5d1SDavid du Colombier 	if(strcmp(attr, "dom") == 0)
1448*7dd7cddfSDavid du Colombier 		t = dnsiplookup(host, &s);
14493e12c5d1SDavid du Colombier 	if(t == 0)
14503e12c5d1SDavid du Colombier 		t = ndbgetval(db, &s, attr, host, "ip", th);
14513e12c5d1SDavid du Colombier 	if(t == 0)
1452*7dd7cddfSDavid du Colombier 		t = dnsiplookup(host, &s);
1453*7dd7cddfSDavid du Colombier 	if(t == 0 && strcmp(attr, "dom") != 0)
1454*7dd7cddfSDavid du Colombier 		t = dnsiplookup(host, &s);
1455*7dd7cddfSDavid du Colombier 	if(t == 0)
1456219b2ee8SDavid du Colombier 		return 0;
1457bd389b36SDavid du Colombier 
1458bd389b36SDavid du Colombier 	/*
1459bd389b36SDavid du Colombier 	 *  reorder the tuple to have the matched line first and
1460bd389b36SDavid du Colombier 	 *  save that in the request structure.
1461bd389b36SDavid du Colombier 	 */
1462*7dd7cddfSDavid du Colombier 	t = reorder(t, s.t);
1463*7dd7cddfSDavid du Colombier 
1464*7dd7cddfSDavid du Colombier 	/*
1465*7dd7cddfSDavid du Colombier 	 * reorder according to our interfaces
1466*7dd7cddfSDavid du Colombier 	 */
1467*7dd7cddfSDavid du Colombier 	lock(&ipifclock);
1468*7dd7cddfSDavid du Colombier 	for(ifc = ipifcs; ifc; ifc = ifc->next){
1469*7dd7cddfSDavid du Colombier 		maskip(ifc->ip, ifc->mask, net);
1470*7dd7cddfSDavid du Colombier 		for(nt = t; nt; nt = nt->entry){
1471*7dd7cddfSDavid du Colombier 			if(strcmp(nt->attr, "ip") != 0)
1472*7dd7cddfSDavid du Colombier 				continue;
1473*7dd7cddfSDavid du Colombier 			parseip(ip, nt->val);
1474*7dd7cddfSDavid du Colombier 			maskip(ip, ifc->mask, tnet);
1475*7dd7cddfSDavid du Colombier 			if(memcmp(net, tnet, IPaddrlen) == 0){
1476*7dd7cddfSDavid du Colombier 				t = reorder(t, nt);
1477*7dd7cddfSDavid du Colombier 				unlock(&ipifclock);
1478*7dd7cddfSDavid du Colombier 				return t;
1479*7dd7cddfSDavid du Colombier 			}
1480*7dd7cddfSDavid du Colombier 		}
1481*7dd7cddfSDavid du Colombier 	}
1482*7dd7cddfSDavid du Colombier 	unlock(&ipifclock);
1483*7dd7cddfSDavid du Colombier 
1484*7dd7cddfSDavid du Colombier 	return t;
14853e12c5d1SDavid du Colombier }
14863e12c5d1SDavid du Colombier 
14873e12c5d1SDavid du Colombier /*
14883e12c5d1SDavid du Colombier  *  translate an ip address
14893e12c5d1SDavid du Colombier  */
1490219b2ee8SDavid du Colombier char*
1491*7dd7cddfSDavid du Colombier iptrans(Ndbtuple *t, Network *np, char *serv, char *rem)
14923e12c5d1SDavid du Colombier {
14933e12c5d1SDavid du Colombier 	char ts[Ndbvlen+1];
1494219b2ee8SDavid du Colombier 	char reply[Maxreply];
1495*7dd7cddfSDavid du Colombier 	char x[Ndbvlen+1];
14963e12c5d1SDavid du Colombier 
1497219b2ee8SDavid du Colombier 	if(strcmp(t->attr, "ip") != 0)
14983e12c5d1SDavid du Colombier 		return 0;
1499219b2ee8SDavid du Colombier 
1500219b2ee8SDavid du Colombier 	if(serv == 0 || ipserv(np, serv, ts) == 0)
1501219b2ee8SDavid du Colombier 		return 0;
1502219b2ee8SDavid du Colombier 
1503*7dd7cddfSDavid du Colombier 	if(rem != nil)
1504*7dd7cddfSDavid du Colombier 		snprint(x, sizeof(x), "!%s", rem);
1505*7dd7cddfSDavid du Colombier 	else
1506*7dd7cddfSDavid du Colombier 		*x = 0;
1507219b2ee8SDavid du Colombier 	if(*t->val == '*')
1508*7dd7cddfSDavid du Colombier 		snprint(reply, sizeof(reply), "%s/%s/clone %s%s",
1509*7dd7cddfSDavid du Colombier 			mntpt, np->net, ts, x);
1510219b2ee8SDavid du Colombier 	else
1511*7dd7cddfSDavid du Colombier 		snprint(reply, sizeof(reply), "%s/%s/clone %s!%s%s",
1512*7dd7cddfSDavid du Colombier 			mntpt, np->net, t->val, ts, x);
1513219b2ee8SDavid du Colombier 
1514219b2ee8SDavid du Colombier 	return strdup(reply);
15153e12c5d1SDavid du Colombier }
15163e12c5d1SDavid du Colombier 
15173e12c5d1SDavid du Colombier 
1518219b2ee8SDavid du Colombier /*
1519219b2ee8SDavid du Colombier  *  lookup a telephone number
1520219b2ee8SDavid du Colombier  */
1521219b2ee8SDavid du Colombier Ndbtuple*
1522219b2ee8SDavid du Colombier telcolookup(Network *np, char *host, char *serv, int nolookup)
1523219b2ee8SDavid du Colombier {
1524219b2ee8SDavid du Colombier 	Ndbtuple *t;
1525219b2ee8SDavid du Colombier 	Ndbs s;
1526219b2ee8SDavid du Colombier 	char th[Ndbvlen+1];
1527219b2ee8SDavid du Colombier 
1528219b2ee8SDavid du Colombier 	USED(np, nolookup, serv);
1529219b2ee8SDavid du Colombier 
1530219b2ee8SDavid du Colombier 	t = ndbgetval(db, &s, "sys", host, "telco", th);
1531219b2ee8SDavid du Colombier 	if(t == 0)
1532219b2ee8SDavid du Colombier 		return mktuple("telco", host);
1533219b2ee8SDavid du Colombier 
1534219b2ee8SDavid du Colombier 	return reorder(t, s.t);
1535219b2ee8SDavid du Colombier }
1536219b2ee8SDavid du Colombier 
1537219b2ee8SDavid du Colombier /*
1538219b2ee8SDavid du Colombier  *  translate a telephone address
1539219b2ee8SDavid du Colombier  */
1540219b2ee8SDavid du Colombier char*
1541*7dd7cddfSDavid du Colombier telcotrans(Ndbtuple *t, Network *np, char *serv, char *rem)
1542219b2ee8SDavid du Colombier {
1543219b2ee8SDavid du Colombier 	char reply[Maxreply];
1544*7dd7cddfSDavid du Colombier 	char x[Ndbvlen+1];
1545219b2ee8SDavid du Colombier 
1546219b2ee8SDavid du Colombier 	if(strcmp(t->attr, "telco") != 0)
1547219b2ee8SDavid du Colombier 		return 0;
1548219b2ee8SDavid du Colombier 
1549*7dd7cddfSDavid du Colombier 	if(rem != nil)
1550*7dd7cddfSDavid du Colombier 		snprint(x, sizeof(x), "!%s", rem);
1551219b2ee8SDavid du Colombier 	else
1552*7dd7cddfSDavid du Colombier 		*x = 0;
1553*7dd7cddfSDavid du Colombier 	if(serv)
1554*7dd7cddfSDavid du Colombier 		snprint(reply, sizeof(reply), "%s/%s/clone %s!%s%s", mntpt, np->net,
1555*7dd7cddfSDavid du Colombier 			t->val, serv, x);
1556*7dd7cddfSDavid du Colombier 	else
1557*7dd7cddfSDavid du Colombier 		snprint(reply, sizeof(reply), "%s/%s/clone %s%s", mntpt, np->net,
1558*7dd7cddfSDavid du Colombier 			t->val, x);
1559219b2ee8SDavid du Colombier 	return strdup(reply);
1560219b2ee8SDavid du Colombier }
15613e12c5d1SDavid du Colombier 
15623e12c5d1SDavid du Colombier /*
15633e12c5d1SDavid du Colombier  *  reorder the tuple to put x's line first in the entry
15643e12c5d1SDavid du Colombier  */
15653e12c5d1SDavid du Colombier Ndbtuple*
15663e12c5d1SDavid du Colombier reorder(Ndbtuple *t, Ndbtuple *x)
15673e12c5d1SDavid du Colombier {
15683e12c5d1SDavid du Colombier 	Ndbtuple *nt;
15693e12c5d1SDavid du Colombier 	Ndbtuple *line;
15703e12c5d1SDavid du Colombier 
1571219b2ee8SDavid du Colombier 	/* find start of this entry's line */
1572219b2ee8SDavid du Colombier 	for(line = x; line->entry == line->line; line = line->line)
15733e12c5d1SDavid du Colombier 		;
1574219b2ee8SDavid du Colombier 	line = line->line;
1575219b2ee8SDavid du Colombier 	if(line == t)
1576219b2ee8SDavid du Colombier 		return t;	/* already the first line */
15773e12c5d1SDavid du Colombier 
1578219b2ee8SDavid du Colombier 	/* remove this line and everything after it from the entry */
1579219b2ee8SDavid du Colombier 	for(nt = t; nt->entry != line; nt = nt->entry)
1580219b2ee8SDavid du Colombier 		;
1581219b2ee8SDavid du Colombier 	nt->entry = 0;
15823e12c5d1SDavid du Colombier 
1583219b2ee8SDavid du Colombier 	/* make that the start of the entry */
1584219b2ee8SDavid du Colombier 	for(nt = line; nt->entry; nt = nt->entry)
1585219b2ee8SDavid du Colombier 		;
15863e12c5d1SDavid du Colombier 	nt->entry = t;
15873e12c5d1SDavid du Colombier 	return line;
15883e12c5d1SDavid du Colombier }
15893e12c5d1SDavid du Colombier 
15903e12c5d1SDavid du Colombier /*
15913e12c5d1SDavid du Colombier  *  create a slave process to handle a request to avoid one request blocking
1592*7dd7cddfSDavid du Colombier  *  another.  parent returns to job loop.
15933e12c5d1SDavid du Colombier  */
15943e12c5d1SDavid du Colombier void
15953e12c5d1SDavid du Colombier slave(void)
15963e12c5d1SDavid du Colombier {
15973e12c5d1SDavid du Colombier 	if(*isslave)
15983e12c5d1SDavid du Colombier 		return;		/* we're already a slave process */
15993e12c5d1SDavid du Colombier 
16003e12c5d1SDavid du Colombier 	switch(rfork(RFPROC|RFNOTEG|RFMEM|RFNOWAIT)){
16013e12c5d1SDavid du Colombier 	case -1:
16023e12c5d1SDavid du Colombier 		break;
16033e12c5d1SDavid du Colombier 	case 0:
1604219b2ee8SDavid du Colombier 		if(debug)
1605219b2ee8SDavid du Colombier 			syslog(0, logfile, "slave %d", getpid());
16063e12c5d1SDavid du Colombier 		*isslave = 1;
16073e12c5d1SDavid du Colombier 		break;
16083e12c5d1SDavid du Colombier 	default:
16093e12c5d1SDavid du Colombier 		longjmp(masterjmp, 1);
16103e12c5d1SDavid du Colombier 	}
16113e12c5d1SDavid du Colombier 
1612219b2ee8SDavid du Colombier }
1613219b2ee8SDavid du Colombier 
16143e12c5d1SDavid du Colombier /*
16153e12c5d1SDavid du Colombier  *  call the dns process and have it try to translate a name
16163e12c5d1SDavid du Colombier  */
16173e12c5d1SDavid du Colombier Ndbtuple*
1618*7dd7cddfSDavid du Colombier dnsiplookup(char *host, Ndbs *s)
16193e12c5d1SDavid du Colombier {
16203e12c5d1SDavid du Colombier 	char buf[Ndbvlen + 4];
1621*7dd7cddfSDavid du Colombier 	Ndbtuple *t;
16223e12c5d1SDavid du Colombier 
1623bd389b36SDavid du Colombier 	unlock(&dblock);
1624bd389b36SDavid du Colombier 
16253e12c5d1SDavid du Colombier 	/* save the name before starting a slave */
1626*7dd7cddfSDavid du Colombier 	snprint(buf, sizeof(buf), "%s", host);
16273e12c5d1SDavid du Colombier 
16283e12c5d1SDavid du Colombier 	slave();
16293e12c5d1SDavid du Colombier 
1630*7dd7cddfSDavid du Colombier 	if(strcmp(ipattr(buf), "ip") == 0)
1631*7dd7cddfSDavid du Colombier 		t = dnsquery(mntpt, buf, "ptr");
1632*7dd7cddfSDavid du Colombier 	else
1633*7dd7cddfSDavid du Colombier 		t = dnsquery(mntpt, buf, "ip");
16343e12c5d1SDavid du Colombier 	s->t = t;
1635*7dd7cddfSDavid du Colombier 
1636bd389b36SDavid du Colombier 	lock(&dblock);
16373e12c5d1SDavid du Colombier 	return t;
16383e12c5d1SDavid du Colombier }
1639219b2ee8SDavid du Colombier 
1640219b2ee8SDavid du Colombier int
1641219b2ee8SDavid du Colombier qmatch(Ndbtuple *t, char **attr, char **val, int n)
1642219b2ee8SDavid du Colombier {
1643219b2ee8SDavid du Colombier 	int i, found;
1644219b2ee8SDavid du Colombier 	Ndbtuple *nt;
1645219b2ee8SDavid du Colombier 
1646219b2ee8SDavid du Colombier 	for(i = 1; i < n; i++){
1647219b2ee8SDavid du Colombier 		found = 0;
1648219b2ee8SDavid du Colombier 		for(nt = t; nt; nt = nt->entry)
1649219b2ee8SDavid du Colombier 			if(strcmp(attr[i], nt->attr) == 0)
1650219b2ee8SDavid du Colombier 				if(strcmp(val[i], "*") == 0
1651219b2ee8SDavid du Colombier 				|| strcmp(val[i], nt->val) == 0){
1652219b2ee8SDavid du Colombier 					found = 1;
1653219b2ee8SDavid du Colombier 					break;
1654219b2ee8SDavid du Colombier 				}
1655219b2ee8SDavid du Colombier 		if(found == 0)
1656219b2ee8SDavid du Colombier 			break;
1657219b2ee8SDavid du Colombier 	}
1658219b2ee8SDavid du Colombier 	return i == n;
1659219b2ee8SDavid du Colombier }
1660219b2ee8SDavid du Colombier 
1661219b2ee8SDavid du Colombier void
1662219b2ee8SDavid du Colombier qreply(Mfile *mf, Ndbtuple *t)
1663219b2ee8SDavid du Colombier {
1664219b2ee8SDavid du Colombier 	int i;
1665219b2ee8SDavid du Colombier 	Ndbtuple *nt;
1666*7dd7cddfSDavid du Colombier 	char buf[2048];
1667219b2ee8SDavid du Colombier 
1668219b2ee8SDavid du Colombier 	buf[0] = 0;
1669219b2ee8SDavid du Colombier 	for(nt = t; mf->nreply < Nreply && nt; nt = nt->entry){
1670219b2ee8SDavid du Colombier 		strcat(buf, nt->attr);
1671219b2ee8SDavid du Colombier 		strcat(buf, "=");
1672219b2ee8SDavid du Colombier 		strcat(buf, nt->val);
1673219b2ee8SDavid du Colombier 		i = strlen(buf);
1674219b2ee8SDavid du Colombier 		if(nt->line != nt->entry || sizeof(buf) - i < 2*Ndbvlen+2){
1675219b2ee8SDavid du Colombier 			mf->replylen[mf->nreply] = strlen(buf);
1676219b2ee8SDavid du Colombier 			mf->reply[mf->nreply++] = strdup(buf);
1677219b2ee8SDavid du Colombier 			buf[0] = 0;
1678219b2ee8SDavid du Colombier 		} else
1679219b2ee8SDavid du Colombier 			strcat(buf, " ");
1680219b2ee8SDavid du Colombier 	}
1681219b2ee8SDavid du Colombier }
1682219b2ee8SDavid du Colombier 
1683*7dd7cddfSDavid du Colombier enum
1684*7dd7cddfSDavid du Colombier {
1685*7dd7cddfSDavid du Colombier 	Maxattr=	32,
1686*7dd7cddfSDavid du Colombier };
1687*7dd7cddfSDavid du Colombier 
1688219b2ee8SDavid du Colombier /*
1689*7dd7cddfSDavid du Colombier  *  generic query lookup.  The query is of one of the following
1690*7dd7cddfSDavid du Colombier  *  forms:
1691*7dd7cddfSDavid du Colombier  *
1692*7dd7cddfSDavid du Colombier  *  attr1=val1 attr2=val2 attr3=val3 ...
1693*7dd7cddfSDavid du Colombier  *
1694*7dd7cddfSDavid du Colombier  *  returns the matching tuple
1695*7dd7cddfSDavid du Colombier  *
1696*7dd7cddfSDavid du Colombier  *  ipinfo attr=val attr1 attr2 attr3 ...
1697*7dd7cddfSDavid du Colombier  *
1698*7dd7cddfSDavid du Colombier  *  is like ipinfo and returns the attr{1-n}
1699*7dd7cddfSDavid du Colombier  *  associated with the ip address.
1700219b2ee8SDavid du Colombier  */
1701219b2ee8SDavid du Colombier char*
1702219b2ee8SDavid du Colombier genquery(Mfile *mf, char *query)
1703219b2ee8SDavid du Colombier {
1704219b2ee8SDavid du Colombier 	int i, n;
1705219b2ee8SDavid du Colombier 	char *p;
1706*7dd7cddfSDavid du Colombier 	char *attr[Maxattr];
1707*7dd7cddfSDavid du Colombier 	char *val[Maxattr];
1708219b2ee8SDavid du Colombier 	Ndbtuple *t;
1709219b2ee8SDavid du Colombier 	Ndbs s;
1710219b2ee8SDavid du Colombier 
1711*7dd7cddfSDavid du Colombier 	n = getfields(query, attr, 32, 1, " ");
1712219b2ee8SDavid du Colombier 	if(n == 0)
1713219b2ee8SDavid du Colombier 		return "bad query";
1714219b2ee8SDavid du Colombier 
1715*7dd7cddfSDavid du Colombier 	if(strcmp(attr[0], "ipinfo") == 0)
1716*7dd7cddfSDavid du Colombier 		return ipinfoquery(mf, attr, n);
1717*7dd7cddfSDavid du Colombier 
1718219b2ee8SDavid du Colombier 	/* parse pairs */
1719219b2ee8SDavid du Colombier 	for(i = 0; i < n; i++){
1720219b2ee8SDavid du Colombier 		p = strchr(attr[i], '=');
1721219b2ee8SDavid du Colombier 		if(p == 0)
1722219b2ee8SDavid du Colombier 			return "bad query";
1723219b2ee8SDavid du Colombier 		*p++ = 0;
1724219b2ee8SDavid du Colombier 		val[i] = p;
1725219b2ee8SDavid du Colombier 	}
1726219b2ee8SDavid du Colombier 
1727219b2ee8SDavid du Colombier 	/* give dns a chance */
1728219b2ee8SDavid du Colombier 	if((strcmp(attr[0], "dom") == 0 || strcmp(attr[0], "ip") == 0) && val[0]){
1729*7dd7cddfSDavid du Colombier 		t = dnsiplookup(val[0], &s);
1730219b2ee8SDavid du Colombier 		if(t){
1731219b2ee8SDavid du Colombier 			if(qmatch(t, attr, val, n)){
1732219b2ee8SDavid du Colombier 				qreply(mf, t);
1733219b2ee8SDavid du Colombier 				ndbfree(t);
1734219b2ee8SDavid du Colombier 				return 0;
1735219b2ee8SDavid du Colombier 			}
1736219b2ee8SDavid du Colombier 			ndbfree(t);
1737219b2ee8SDavid du Colombier 		}
1738219b2ee8SDavid du Colombier 	}
1739219b2ee8SDavid du Colombier 
1740219b2ee8SDavid du Colombier 	/* first pair is always the key.  It can't be a '*' */
1741219b2ee8SDavid du Colombier 	t = ndbsearch(db, &s, attr[0], val[0]);
1742219b2ee8SDavid du Colombier 
1743219b2ee8SDavid du Colombier 	/* search is the and of all the pairs */
1744219b2ee8SDavid du Colombier 	while(t){
1745219b2ee8SDavid du Colombier 		if(qmatch(t, attr, val, n)){
1746219b2ee8SDavid du Colombier 			qreply(mf, t);
1747219b2ee8SDavid du Colombier 			ndbfree(t);
1748219b2ee8SDavid du Colombier 			return 0;
1749219b2ee8SDavid du Colombier 		}
1750219b2ee8SDavid du Colombier 
1751219b2ee8SDavid du Colombier 		ndbfree(t);
1752219b2ee8SDavid du Colombier 		t = ndbsnext(&s, attr[0], val[0]);
1753219b2ee8SDavid du Colombier 	}
1754219b2ee8SDavid du Colombier 
1755219b2ee8SDavid du Colombier 	return "no match";
1756219b2ee8SDavid du Colombier }
1757*7dd7cddfSDavid du Colombier 
1758*7dd7cddfSDavid du Colombier /*
1759*7dd7cddfSDavid du Colombier  *  resolve an ip address
1760*7dd7cddfSDavid du Colombier  */
1761*7dd7cddfSDavid du Colombier static Ndbtuple*
1762*7dd7cddfSDavid du Colombier ipresolve(char *attr, char *host)
1763*7dd7cddfSDavid du Colombier {
1764*7dd7cddfSDavid du Colombier 	Ndbtuple *t, *nt, **l;
1765*7dd7cddfSDavid du Colombier 
1766*7dd7cddfSDavid du Colombier 	t = iplookup(&network[Ntcp], host, "*", 0);
1767*7dd7cddfSDavid du Colombier 	for(l = &t; *l != nil; ){
1768*7dd7cddfSDavid du Colombier 		nt = *l;
1769*7dd7cddfSDavid du Colombier 		if(strcmp(nt->attr, "ip") != 0){
1770*7dd7cddfSDavid du Colombier 			*l = nt->entry;
1771*7dd7cddfSDavid du Colombier 			nt->entry = nil;
1772*7dd7cddfSDavid du Colombier 			ndbfree(nt);
1773*7dd7cddfSDavid du Colombier 			continue;
1774*7dd7cddfSDavid du Colombier 		}
1775*7dd7cddfSDavid du Colombier 		strcpy(nt->attr, attr);
1776*7dd7cddfSDavid du Colombier 		l = &nt->entry;
1777*7dd7cddfSDavid du Colombier 	}
1778*7dd7cddfSDavid du Colombier 	return t;
1779*7dd7cddfSDavid du Colombier }
1780*7dd7cddfSDavid du Colombier 
1781*7dd7cddfSDavid du Colombier char*
1782*7dd7cddfSDavid du Colombier ipinfoquery(Mfile *mf, char **list, int n)
1783*7dd7cddfSDavid du Colombier {
1784*7dd7cddfSDavid du Colombier 	int i, nresolve;
1785*7dd7cddfSDavid du Colombier 	int resolve[Maxattr];
1786*7dd7cddfSDavid du Colombier 	Ndbtuple *t, *nt, **l;
1787*7dd7cddfSDavid du Colombier 	char *attr, *val;
1788*7dd7cddfSDavid du Colombier 
1789*7dd7cddfSDavid du Colombier 	/* skip 'ipinfo' */
1790*7dd7cddfSDavid du Colombier 	list++; n--;
1791*7dd7cddfSDavid du Colombier 
1792*7dd7cddfSDavid du Colombier 	if(n < 2)
1793*7dd7cddfSDavid du Colombier 		return "bad query";
1794*7dd7cddfSDavid du Colombier 
1795*7dd7cddfSDavid du Colombier 	/* get search attribute=value */
1796*7dd7cddfSDavid du Colombier 	attr = *list++; n--;
1797*7dd7cddfSDavid du Colombier 	val = strchr(attr, '=');
1798*7dd7cddfSDavid du Colombier 	if(val == nil)
1799*7dd7cddfSDavid du Colombier 		return "bad query";
1800*7dd7cddfSDavid du Colombier 	*val++ = 0;
1801*7dd7cddfSDavid du Colombier 
1802*7dd7cddfSDavid du Colombier 	/*
1803*7dd7cddfSDavid du Colombier 	 *  don't let ndbipinfo resolve the addresses, we're
1804*7dd7cddfSDavid du Colombier 	 *  better at it.
1805*7dd7cddfSDavid du Colombier 	 */
1806*7dd7cddfSDavid du Colombier 	nresolve = 0;
1807*7dd7cddfSDavid du Colombier 	for(i = 0; i < n; i++)
1808*7dd7cddfSDavid du Colombier 		if(*list[i] == '@'){
1809*7dd7cddfSDavid du Colombier 			list[i]++;
1810*7dd7cddfSDavid du Colombier 			resolve[i] = 1;
1811*7dd7cddfSDavid du Colombier 			nresolve++;
1812*7dd7cddfSDavid du Colombier 		} else
1813*7dd7cddfSDavid du Colombier 			resolve[i] = 0;
1814*7dd7cddfSDavid du Colombier 
1815*7dd7cddfSDavid du Colombier 	t = ndbipinfo(db, attr, val, list, n);
1816*7dd7cddfSDavid du Colombier 	if(t == nil)
1817*7dd7cddfSDavid du Colombier 		return "no match";
1818*7dd7cddfSDavid du Colombier 
1819*7dd7cddfSDavid du Colombier 	if(nresolve != 0){
1820*7dd7cddfSDavid du Colombier 		for(l = &t; *l != nil;){
1821*7dd7cddfSDavid du Colombier 			nt = *l;
1822*7dd7cddfSDavid du Colombier 
1823*7dd7cddfSDavid du Colombier 			/* already an address? */
1824*7dd7cddfSDavid du Colombier 			if(strcmp(ipattr(nt->val), "ip") == 0){
1825*7dd7cddfSDavid du Colombier 				l = &(*l)->entry;
1826*7dd7cddfSDavid du Colombier 				continue;
1827*7dd7cddfSDavid du Colombier 			}
1828*7dd7cddfSDavid du Colombier 
1829*7dd7cddfSDavid du Colombier 			/* user wants it resolved? */
1830*7dd7cddfSDavid du Colombier 			for(i = 0; i < n; i++)
1831*7dd7cddfSDavid du Colombier 				if(strcmp(list[i], nt->attr) == 0)
1832*7dd7cddfSDavid du Colombier 					break;
1833*7dd7cddfSDavid du Colombier 			if(i >= n || resolve[i] == 0){
1834*7dd7cddfSDavid du Colombier 				l = &(*l)->entry;
1835*7dd7cddfSDavid du Colombier 				continue;
1836*7dd7cddfSDavid du Colombier 			}
1837*7dd7cddfSDavid du Colombier 
1838*7dd7cddfSDavid du Colombier 			/* resolve address and replace entry */
1839*7dd7cddfSDavid du Colombier 			*l = ipresolve(nt->attr, nt->val);
1840*7dd7cddfSDavid du Colombier 			while(*l != nil)
1841*7dd7cddfSDavid du Colombier 				l = &(*l)->entry;
1842*7dd7cddfSDavid du Colombier 			*l = nt->entry;
1843*7dd7cddfSDavid du Colombier 
1844*7dd7cddfSDavid du Colombier 			nt->entry = nil;
1845*7dd7cddfSDavid du Colombier 			ndbfree(nt);
1846*7dd7cddfSDavid du Colombier 		}
1847*7dd7cddfSDavid du Colombier 	}
1848*7dd7cddfSDavid du Colombier 
1849*7dd7cddfSDavid du Colombier 	/* make it all one line */
1850*7dd7cddfSDavid du Colombier 	for(nt = t; nt != nil; nt = nt->entry){
1851*7dd7cddfSDavid du Colombier 		if(nt->entry == nil)
1852*7dd7cddfSDavid du Colombier 			nt->line = t;
1853*7dd7cddfSDavid du Colombier 		else
1854*7dd7cddfSDavid du Colombier 			nt->line = nt->entry;
1855*7dd7cddfSDavid du Colombier 	}
1856*7dd7cddfSDavid du Colombier 
1857*7dd7cddfSDavid du Colombier 	qreply(mf, t);
1858*7dd7cddfSDavid du Colombier 
1859*7dd7cddfSDavid du Colombier 	return nil;
1860*7dd7cddfSDavid du Colombier }
1861*7dd7cddfSDavid du Colombier 
1862*7dd7cddfSDavid du Colombier void*
1863*7dd7cddfSDavid du Colombier emalloc(int size)
1864*7dd7cddfSDavid du Colombier {
1865*7dd7cddfSDavid du Colombier 	void *x;
1866*7dd7cddfSDavid du Colombier 
1867*7dd7cddfSDavid du Colombier 	x = malloc(size);
1868*7dd7cddfSDavid du Colombier 	if(x == nil)
1869*7dd7cddfSDavid du Colombier 		abort();
1870*7dd7cddfSDavid du Colombier 	memset(x, 0, size);
1871*7dd7cddfSDavid du Colombier 	return x;
1872*7dd7cddfSDavid du Colombier }
1873