xref: /plan9/sys/src/cmd/ndb/dns.c (revision 530fef6600a0fb31e4c0a6ecda1320e97bcd937c)
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>
77dd7cddfSDavid du Colombier #include <ip.h>
89a747e4fSDavid du Colombier #include <pool.h>
93e12c5d1SDavid du Colombier #include "dns.h"
103e12c5d1SDavid du Colombier 
113e12c5d1SDavid du Colombier enum
123e12c5d1SDavid du Colombier {
139a747e4fSDavid du Colombier 	Maxrequest=		1024,
1476783259SDavid du Colombier 	Maxreply=		8192,		/* was 512 */
1576783259SDavid du Colombier 	Maxrrr=			32,		/* was 16 */
169a747e4fSDavid du Colombier 	Maxfdata=		8192,
173e12c5d1SDavid du Colombier 
18f46c709fSDavid du Colombier 	Defmaxage=		60*60,	/* default domain name max. age */
194f8f669cSDavid du Colombier 
209a747e4fSDavid du Colombier 	Qdir=			0,
213e12c5d1SDavid du Colombier 	Qdns=			1,
223e12c5d1SDavid du Colombier };
233e12c5d1SDavid du Colombier 
243e12c5d1SDavid du Colombier typedef struct Mfile	Mfile;
257dd7cddfSDavid du Colombier typedef struct Job	Job;
263e12c5d1SDavid du Colombier typedef struct Network	Network;
273e12c5d1SDavid du Colombier 
283e12c5d1SDavid du Colombier int vers;		/* incremented each clone/attach */
29adb31a62SDavid du Colombier 
30adb31a62SDavid du Colombier static volatile int stop;
313e12c5d1SDavid du Colombier 
32410ea80bSDavid du Colombier /* holds data to be returned via read of /net/dns, perhaps multiple reads */
333e12c5d1SDavid du Colombier struct Mfile
343e12c5d1SDavid du Colombier {
357dd7cddfSDavid du Colombier 	Mfile		*next;		/* next free mfile */
369a747e4fSDavid du Colombier 	int		ref;
377dd7cddfSDavid du Colombier 
389a747e4fSDavid du Colombier 	char		*user;
393e12c5d1SDavid du Colombier 	Qid		qid;
403e12c5d1SDavid du Colombier 	int		fid;
413e12c5d1SDavid du Colombier 
423e12c5d1SDavid du Colombier 	int		type;		/* reply type */
437dd7cddfSDavid du Colombier 	char		reply[Maxreply];
447dd7cddfSDavid du Colombier 	ushort		rr[Maxrrr];	/* offset of rr's */
457dd7cddfSDavid du Colombier 	ushort		nrr;		/* number of rr's */
463e12c5d1SDavid du Colombier };
473e12c5d1SDavid du Colombier 
484f8f669cSDavid du Colombier /*
494f8f669cSDavid du Colombier  *  active local requests
504f8f669cSDavid du Colombier  */
517dd7cddfSDavid du Colombier struct Job
527dd7cddfSDavid du Colombier {
537dd7cddfSDavid du Colombier 	Job	*next;
547dd7cddfSDavid du Colombier 	int	flushed;
557dd7cddfSDavid du Colombier 	Fcall	request;
567dd7cddfSDavid du Colombier 	Fcall	reply;
577dd7cddfSDavid du Colombier };
587dd7cddfSDavid du Colombier Lock	joblock;
597dd7cddfSDavid du Colombier Job	*joblist;
607dd7cddfSDavid du Colombier 
617dd7cddfSDavid du Colombier struct {
627dd7cddfSDavid du Colombier 	Lock;
637dd7cddfSDavid du Colombier 	Mfile	*inuse;		/* active mfile's */
647dd7cddfSDavid du Colombier } mfalloc;
657dd7cddfSDavid du Colombier 
664f8f669cSDavid du Colombier Cfg	cfg;
676b0d5c8bSDavid du Colombier int	debug;
684f8f669cSDavid du Colombier uchar	ipaddr[IPaddrlen];	/* my ip address */
694f8f669cSDavid du Colombier int	maxage = Defmaxage;
704f8f669cSDavid du Colombier int	mfd[2];
714f8f669cSDavid du Colombier int	needrefresh;
727dd7cddfSDavid du Colombier ulong	now;
73a41547ffSDavid du Colombier vlong	nowns;
744f8f669cSDavid du Colombier int	sendnotifies;
757dd7cddfSDavid du Colombier int	testing;
767dd7cddfSDavid du Colombier char	*trace;
774f8f669cSDavid du Colombier int	traceactivity;
78dc5a79c1SDavid du Colombier char	*zonerefreshprogram;
793e12c5d1SDavid du Colombier 
804f8f669cSDavid du Colombier char	*logfile = "dns";	/* or "dns.test" */
816b0d5c8bSDavid du Colombier char	*dbfile;
826b0d5c8bSDavid du Colombier char	mntpt[Maxpath];
834f8f669cSDavid du Colombier 
844f8f669cSDavid du Colombier int	fillreply(Mfile*, int);
854f8f669cSDavid du Colombier void	freejob(Job*);
864f8f669cSDavid du Colombier void	io(void);
874f8f669cSDavid du Colombier void	mountinit(char*, char*);
884f8f669cSDavid du Colombier Job*	newjob(void);
894f8f669cSDavid du Colombier void	rattach(Job*, Mfile*);
904f8f669cSDavid du Colombier void	rauth(Job*);
914f8f669cSDavid du Colombier void	rclunk(Job*, Mfile*);
924f8f669cSDavid du Colombier void	rcreate(Job*, Mfile*);
934f8f669cSDavid du Colombier void	rflush(Job*);
944f8f669cSDavid du Colombier void	ropen(Job*, Mfile*);
954f8f669cSDavid du Colombier void	rread(Job*, Mfile*);
964f8f669cSDavid du Colombier void	rremove(Job*, Mfile*);
974f8f669cSDavid du Colombier void	rstat(Job*, Mfile*);
984f8f669cSDavid du Colombier void	rversion(Job*);
994f8f669cSDavid du Colombier char*	rwalk(Job*, Mfile*);
1004f8f669cSDavid du Colombier void	rwrite(Job*, Mfile*, Request*);
1014f8f669cSDavid du Colombier void	rwstat(Job*, Mfile*);
1024f8f669cSDavid du Colombier void	sendmsg(Job*, char*);
1034f8f669cSDavid du Colombier void	setext(char*, int, char*);
1046b0d5c8bSDavid du Colombier 
1057dd7cddfSDavid du Colombier void
1067dd7cddfSDavid du Colombier usage(void)
1077dd7cddfSDavid du Colombier {
108a41547ffSDavid du Colombier 	fprint(2, "usage: %s [-FnorRst] [-a maxage] [-f ndb-file] [-N target] "
109410ea80bSDavid du Colombier 		"[-T forwip] [-x netmtpt] [-z refreshprog]\n", argv0);
1107dd7cddfSDavid du Colombier 	exits("usage");
1117dd7cddfSDavid du Colombier }
112219b2ee8SDavid du Colombier 
113410ea80bSDavid du Colombier int addforwtarg(char *);
114410ea80bSDavid du Colombier 
1153e12c5d1SDavid du Colombier void
1163e12c5d1SDavid du Colombier main(int argc, char *argv[])
1173e12c5d1SDavid du Colombier {
118c73252aeSDavid du Colombier 	int kid, pid;
1194f8f669cSDavid du Colombier 	char servefile[Maxpath], ext[Maxpath];
12014cc0f53SDavid du Colombier 	Dir *dir;
121219b2ee8SDavid du Colombier 
1224f8f669cSDavid du Colombier 	setnetmtpt(mntpt, sizeof mntpt, nil);
1237dd7cddfSDavid du Colombier 	ext[0] = 0;
1243e12c5d1SDavid du Colombier 	ARGBEGIN{
1254f8f669cSDavid du Colombier 	case 'a':
1264f8f669cSDavid du Colombier 		maxage = atol(EARGF(usage()));
1274f8f669cSDavid du Colombier 		if (maxage <= 0)
1284f8f669cSDavid du Colombier 			maxage = Defmaxage;
1294f8f669cSDavid du Colombier 		break;
1303e12c5d1SDavid du Colombier 	case 'd':
1313e12c5d1SDavid du Colombier 		debug = 1;
13239734e7eSDavid du Colombier 		traceactivity = 1;
1333e12c5d1SDavid du Colombier 		break;
134219b2ee8SDavid du Colombier 	case 'f':
1354f8f669cSDavid du Colombier 		dbfile = EARGF(usage());
1367dd7cddfSDavid du Colombier 		break;
137a41547ffSDavid du Colombier 	case 'F':
138a41547ffSDavid du Colombier 		cfg.justforw = cfg.resolver = 1;
139a41547ffSDavid du Colombier 		break;
1404f8f669cSDavid du Colombier 	case 'n':
1414f8f669cSDavid du Colombier 		sendnotifies = 1;
1424f8f669cSDavid du Colombier 		break;
1434f8f669cSDavid du Colombier 	case 'N':
1444f8f669cSDavid du Colombier 		target = atol(EARGF(usage()));
145a41547ffSDavid du Colombier 		if (target < 1000)
146a41547ffSDavid du Colombier 			target = 1000;
1474f8f669cSDavid du Colombier 		break;
1484f8f669cSDavid du Colombier 	case 'o':
1494f8f669cSDavid du Colombier 		cfg.straddle = 1;	/* straddle inside & outside networks */
1504fafed5dSDavid du Colombier 		break;
1517dd7cddfSDavid du Colombier 	case 'r':
1524f8f669cSDavid du Colombier 		cfg.resolver = 1;
153219b2ee8SDavid du Colombier 		break;
154b85a8364SDavid du Colombier 	case 'R':
155b85a8364SDavid du Colombier 		norecursion = 1;
156b85a8364SDavid du Colombier 		break;
1573e12c5d1SDavid du Colombier 	case 's':
1584f8f669cSDavid du Colombier 		cfg.serve = 1;		/* serve network */
1594f8f669cSDavid du Colombier 		cfg.cachedb = 1;
1606b0d5c8bSDavid du Colombier 		break;
1617dd7cddfSDavid du Colombier 	case 't':
1627dd7cddfSDavid du Colombier 		testing = 1;
1633e12c5d1SDavid du Colombier 		break;
164410ea80bSDavid du Colombier 	case 'T':
165410ea80bSDavid du Colombier 		addforwtarg(EARGF(usage()));
166410ea80bSDavid du Colombier 		break;
1674f8f669cSDavid du Colombier 	case 'x':
1684f8f669cSDavid du Colombier 		setnetmtpt(mntpt, sizeof mntpt, EARGF(usage()));
1694f8f669cSDavid du Colombier 		setext(ext, sizeof ext, mntpt);
1706b0d5c8bSDavid du Colombier 		break;
1714f8f669cSDavid du Colombier 	case 'z':
1724f8f669cSDavid du Colombier 		zonerefreshprogram = EARGF(usage());
173dc5a79c1SDavid du Colombier 		break;
1743e12c5d1SDavid du Colombier 	}ARGEND
1753e12c5d1SDavid du Colombier 	USED(argc);
1763e12c5d1SDavid du Colombier 	USED(argv);
1773e12c5d1SDavid du Colombier 
1784f8f669cSDavid du Colombier 	if(testing)
1794f8f669cSDavid du Colombier 		mainmem->flags |= POOL_NOREUSE | POOL_ANTAGONISM;
1806aaebd7dSDavid du Colombier 	mainmem->flags |= POOL_ANTAGONISM;
1817dd7cddfSDavid du Colombier 	rfork(RFREND|RFNOTEG);
1823e12c5d1SDavid du Colombier 
1834f8f669cSDavid du Colombier 	cfg.inside = (*mntpt == '\0' || strcmp(mntpt, "/net") == 0);
1844f8f669cSDavid du Colombier 
1857dd7cddfSDavid du Colombier 	/* start syslog before we fork */
1869a747e4fSDavid du Colombier 	fmtinstall('F', fcallfmt);
187219b2ee8SDavid du Colombier 	dninit();
18876783259SDavid du Colombier 	/* this really shouldn't be fatal */
1899a747e4fSDavid du Colombier 	if(myipaddr(ipaddr, mntpt) < 0)
1907dd7cddfSDavid du Colombier 		sysfatal("can't read my ip address");
191a41547ffSDavid du Colombier 	dnslog("starting %s%sdns %s%s%son %I's %s",
1924f8f669cSDavid du Colombier 		(cfg.straddle? "straddling ": ""),
1934f8f669cSDavid du Colombier 		(cfg.cachedb? "caching ": ""),
1944f8f669cSDavid du Colombier 		(cfg.serve?   "udp server ": ""),
195a41547ffSDavid du Colombier 		(cfg.justforw? "forwarding-only ": ""),
1964f8f669cSDavid du Colombier 		(cfg.resolver? "resolver ": ""), ipaddr, mntpt);
1977dd7cddfSDavid du Colombier 
1987dd7cddfSDavid du Colombier 	opendatabase();
199a41547ffSDavid du Colombier 	now = time(nil);		/* open time files before we fork */
200a41547ffSDavid du Colombier 	nowns = nsec();
2017dd7cddfSDavid du Colombier 
2024f8f669cSDavid du Colombier 	snprint(servefile, sizeof servefile, "#s/dns%s", ext);
20314cc0f53SDavid du Colombier 	dir = dirstat(servefile);
20414cc0f53SDavid du Colombier 	if (dir)
20514cc0f53SDavid du Colombier 		sysfatal("%s exists; another dns instance is running",
20614cc0f53SDavid du Colombier 			servefile);
20714cc0f53SDavid du Colombier 	free(dir);
20814cc0f53SDavid du Colombier //	unmount(servefile, mntpt);
20914cc0f53SDavid du Colombier //	remove(servefile);
21014cc0f53SDavid du Colombier 
211c73252aeSDavid du Colombier 	mountinit(servefile, mntpt);	/* forks, parent exits */
2127dd7cddfSDavid du Colombier 
2137dd7cddfSDavid du Colombier 	srand(now*getpid());
2147dd7cddfSDavid du Colombier 	db2cache(1);
215410ea80bSDavid du Colombier //	dnageallnever();
2167dd7cddfSDavid du Colombier 
2174f8f669cSDavid du Colombier 	if (cfg.straddle && !seerootns())
2184f8f669cSDavid du Colombier 		dnslog("straddle server misconfigured; can't see root name servers");
219c73252aeSDavid du Colombier 	/*
220c73252aeSDavid du Colombier 	 * fork without sharing heap.
221c73252aeSDavid du Colombier 	 * parent waits around for child to die, then forks & restarts.
222c73252aeSDavid du Colombier 	 * child may spawn udp server, notify procs, etc.; when it gets too
223c73252aeSDavid du Colombier 	 * big, it kills itself and any children.
224c73252aeSDavid du Colombier 	 * /srv/dns and /net/dns remain open and valid.
225c73252aeSDavid du Colombier 	 */
226c73252aeSDavid du Colombier 	for (;;) {
227c73252aeSDavid du Colombier 		kid = rfork(RFPROC|RFFDG|RFNOTEG);
228c73252aeSDavid du Colombier 		switch (kid) {
229c73252aeSDavid du Colombier 		case -1:
230c73252aeSDavid du Colombier 			sysfatal("fork failed: %r");
231c73252aeSDavid du Colombier 		case 0:
2324f8f669cSDavid du Colombier 			if(cfg.serve)
2337dd7cddfSDavid du Colombier 				dnudpserver(mntpt);
234dc5a79c1SDavid du Colombier 			if(sendnotifies)
235dc5a79c1SDavid du Colombier 				notifyproc();
2363e12c5d1SDavid du Colombier 			io();
237c73252aeSDavid du Colombier 			_exits("restart");
238c73252aeSDavid du Colombier 		default:
239c73252aeSDavid du Colombier 			while ((pid = waitpid()) != kid && pid != -1)
240c73252aeSDavid du Colombier 				continue;
241c73252aeSDavid du Colombier 			break;
242c73252aeSDavid du Colombier 		}
243c73252aeSDavid du Colombier 		dnslog("dns restarting");
244c73252aeSDavid du Colombier 	}
2453e12c5d1SDavid du Colombier }
2463e12c5d1SDavid du Colombier 
2477dd7cddfSDavid du Colombier /*
2484f8f669cSDavid du Colombier  *  if a mount point is specified, set the cs extension to be the mount point
2497dd7cddfSDavid du Colombier  *  with '_'s replacing '/'s
2507dd7cddfSDavid du Colombier  */
2513e12c5d1SDavid du Colombier void
2527dd7cddfSDavid du Colombier setext(char *ext, int n, char *p)
2537dd7cddfSDavid du Colombier {
2547dd7cddfSDavid du Colombier 	int i, c;
2557dd7cddfSDavid du Colombier 
2567dd7cddfSDavid du Colombier 	n--;
2577dd7cddfSDavid du Colombier 	for(i = 0; i < n; i++){
2587dd7cddfSDavid du Colombier 		c = p[i];
2597dd7cddfSDavid du Colombier 		if(c == 0)
2607dd7cddfSDavid du Colombier 			break;
2617dd7cddfSDavid du Colombier 		if(c == '/')
2627dd7cddfSDavid du Colombier 			c = '_';
2637dd7cddfSDavid du Colombier 		ext[i] = c;
2647dd7cddfSDavid du Colombier 	}
2657dd7cddfSDavid du Colombier 	ext[i] = 0;
2667dd7cddfSDavid du Colombier }
2677dd7cddfSDavid du Colombier 
2687dd7cddfSDavid du Colombier void
2697dd7cddfSDavid du Colombier mountinit(char *service, char *mntpt)
2703e12c5d1SDavid du Colombier {
2713e12c5d1SDavid du Colombier 	int f;
2723e12c5d1SDavid du Colombier 	int p[2];
2733e12c5d1SDavid du Colombier 	char buf[32];
2743e12c5d1SDavid du Colombier 
2753e12c5d1SDavid du Colombier 	if(pipe(p) < 0)
2767dd7cddfSDavid du Colombier 		abort(); /* "pipe failed" */;
277c73252aeSDavid du Colombier 	/* copy namespace to avoid a deadlock */
278219b2ee8SDavid du Colombier 	switch(rfork(RFFDG|RFPROC|RFNAMEG)){
279c73252aeSDavid du Colombier 	case 0:			/* child: hang around and (re)start main proc */
280219b2ee8SDavid du Colombier 		close(p[1]);
2816aaebd7dSDavid du Colombier 		procsetname("%s restarter", mntpt);
2823e12c5d1SDavid du Colombier 		break;
2833e12c5d1SDavid du Colombier 	case -1:
2847dd7cddfSDavid du Colombier 		abort(); /* "fork failed\n" */;
285c73252aeSDavid du Colombier 	default:		/* parent: make /srv/dns, mount it, exit */
286219b2ee8SDavid du Colombier 		close(p[0]);
287219b2ee8SDavid du Colombier 
2883e12c5d1SDavid du Colombier 		/*
2893e12c5d1SDavid du Colombier 		 *  make a /srv/dns
2903e12c5d1SDavid du Colombier 		 */
2913e12c5d1SDavid du Colombier 		f = create(service, 1, 0666);
2923e12c5d1SDavid du Colombier 		if(f < 0)
2937dd7cddfSDavid du Colombier 			abort(); /* service */;
2944f8f669cSDavid du Colombier 		snprint(buf, sizeof buf, "%d", p[1]);
2953e12c5d1SDavid du Colombier 		if(write(f, buf, strlen(buf)) != strlen(buf))
2967dd7cddfSDavid du Colombier 			abort(); /* "write %s", service */;
2973e12c5d1SDavid du Colombier 		close(f);
2983e12c5d1SDavid du Colombier 
2993e12c5d1SDavid du Colombier 		/*
3003e12c5d1SDavid du Colombier 		 *  put ourselves into the file system
3013e12c5d1SDavid du Colombier 		 */
3029a747e4fSDavid du Colombier 		if(mount(p[1], -1, mntpt, MAFTER, "") < 0)
3039a747e4fSDavid du Colombier 			fprint(2, "dns mount failed: %r\n");
304219b2ee8SDavid du Colombier 		_exits(0);
3053e12c5d1SDavid du Colombier 	}
3063e12c5d1SDavid du Colombier 	mfd[0] = mfd[1] = p[0];
3073e12c5d1SDavid du Colombier }
3083e12c5d1SDavid du Colombier 
3093e12c5d1SDavid du Colombier Mfile*
3107dd7cddfSDavid du Colombier newfid(int fid, int needunused)
3113e12c5d1SDavid du Colombier {
3123e12c5d1SDavid du Colombier 	Mfile *mf;
3133e12c5d1SDavid du Colombier 
3147dd7cddfSDavid du Colombier 	lock(&mfalloc);
3154f8f669cSDavid du Colombier 	for(mf = mfalloc.inuse; mf != nil; mf = mf->next)
3167dd7cddfSDavid du Colombier 		if(mf->fid == fid){
3177dd7cddfSDavid du Colombier 			unlock(&mfalloc);
3187dd7cddfSDavid du Colombier 			if(needunused)
3197dd7cddfSDavid du Colombier 				return nil;
3203e12c5d1SDavid du Colombier 			return mf;
3213e12c5d1SDavid du Colombier 		}
3229a747e4fSDavid du Colombier 	mf = emalloc(sizeof(*mf));
3233e12c5d1SDavid du Colombier 	mf->fid = fid;
324c73252aeSDavid du Colombier 	mf->user = estrdup("dummy");
325*530fef66SDavid du Colombier 	mf->next = mfalloc.inuse;
3267dd7cddfSDavid du Colombier 	mfalloc.inuse = mf;
3277dd7cddfSDavid du Colombier 	unlock(&mfalloc);
3283e12c5d1SDavid du Colombier 	return mf;
3293e12c5d1SDavid du Colombier }
3303e12c5d1SDavid du Colombier 
3313e12c5d1SDavid du Colombier void
3327dd7cddfSDavid du Colombier freefid(Mfile *mf)
3337dd7cddfSDavid du Colombier {
3347dd7cddfSDavid du Colombier 	Mfile **l;
3357dd7cddfSDavid du Colombier 
3367dd7cddfSDavid du Colombier 	lock(&mfalloc);
3374f8f669cSDavid du Colombier 	for(l = &mfalloc.inuse; *l != nil; l = &(*l)->next)
3387dd7cddfSDavid du Colombier 		if(*l == mf){
3397dd7cddfSDavid du Colombier 			*l = mf->next;
3406b0d5c8bSDavid du Colombier 			if(mf->user)
3419a747e4fSDavid du Colombier 				free(mf->user);
3424f8f669cSDavid du Colombier 			memset(mf, 0, sizeof *mf);	/* cause trouble */
3437dd7cddfSDavid du Colombier 			free(mf);
3447dd7cddfSDavid du Colombier 			unlock(&mfalloc);
3457dd7cddfSDavid du Colombier 			return;
3467dd7cddfSDavid du Colombier 		}
347*530fef66SDavid du Colombier 	unlock(&mfalloc);
3487dd7cddfSDavid du Colombier 	sysfatal("freeing unused fid");
3497dd7cddfSDavid du Colombier }
3507dd7cddfSDavid du Colombier 
3517dd7cddfSDavid du Colombier Mfile*
3527dd7cddfSDavid du Colombier copyfid(Mfile *mf, int fid)
3537dd7cddfSDavid du Colombier {
3547dd7cddfSDavid du Colombier 	Mfile *nmf;
3557dd7cddfSDavid du Colombier 
3567dd7cddfSDavid du Colombier 	nmf = newfid(fid, 1);
3577dd7cddfSDavid du Colombier 	if(nmf == nil)
3587dd7cddfSDavid du Colombier 		return nil;
3597dd7cddfSDavid du Colombier 	nmf->fid = fid;
360*530fef66SDavid du Colombier 	free(nmf->user);			/* estrdup("dummy") */
3619a747e4fSDavid du Colombier 	nmf->user = estrdup(mf->user);
3629a747e4fSDavid du Colombier 	nmf->qid.type = mf->qid.type;
3637dd7cddfSDavid du Colombier 	nmf->qid.path = mf->qid.path;
3647dd7cddfSDavid du Colombier 	nmf->qid.vers = vers++;
3657dd7cddfSDavid du Colombier 	return nmf;
3667dd7cddfSDavid du Colombier }
3677dd7cddfSDavid du Colombier 
3687dd7cddfSDavid du Colombier Job*
3697dd7cddfSDavid du Colombier newjob(void)
3707dd7cddfSDavid du Colombier {
3717dd7cddfSDavid du Colombier 	Job *job;
3727dd7cddfSDavid du Colombier 
3734f8f669cSDavid du Colombier 	job = emalloc(sizeof *job);
3747dd7cddfSDavid du Colombier 	lock(&joblock);
3757dd7cddfSDavid du Colombier 	job->next = joblist;
3767dd7cddfSDavid du Colombier 	joblist = job;
3777dd7cddfSDavid du Colombier 	job->request.tag = -1;
3787dd7cddfSDavid du Colombier 	unlock(&joblock);
3797dd7cddfSDavid du Colombier 	return job;
3807dd7cddfSDavid du Colombier }
3817dd7cddfSDavid du Colombier 
3827dd7cddfSDavid du Colombier void
3837dd7cddfSDavid du Colombier freejob(Job *job)
3847dd7cddfSDavid du Colombier {
3857dd7cddfSDavid du Colombier 	Job **l;
3867dd7cddfSDavid du Colombier 
3877dd7cddfSDavid du Colombier 	lock(&joblock);
3884f8f669cSDavid du Colombier 	for(l = &joblist; *l; l = &(*l)->next)
3894f8f669cSDavid du Colombier 		if(*l == job){
3907dd7cddfSDavid du Colombier 			*l = job->next;
3914f8f669cSDavid du Colombier 			memset(job, 0, sizeof *job);	/* cause trouble */
3927dd7cddfSDavid du Colombier 			free(job);
3937dd7cddfSDavid du Colombier 			break;
3947dd7cddfSDavid du Colombier 		}
3957dd7cddfSDavid du Colombier 	unlock(&joblock);
3967dd7cddfSDavid du Colombier }
3977dd7cddfSDavid du Colombier 
3987dd7cddfSDavid du Colombier void
3997dd7cddfSDavid du Colombier flushjob(int tag)
4007dd7cddfSDavid du Colombier {
4017dd7cddfSDavid du Colombier 	Job *job;
4027dd7cddfSDavid du Colombier 
4037dd7cddfSDavid du Colombier 	lock(&joblock);
4044f8f669cSDavid du Colombier 	for(job = joblist; job; job = job->next)
4057dd7cddfSDavid du Colombier 		if(job->request.tag == tag && job->request.type != Tflush){
4067dd7cddfSDavid du Colombier 			job->flushed = 1;
4077dd7cddfSDavid du Colombier 			break;
4087dd7cddfSDavid du Colombier 		}
4097dd7cddfSDavid du Colombier 	unlock(&joblock);
4107dd7cddfSDavid du Colombier }
4117dd7cddfSDavid du Colombier 
4127dd7cddfSDavid du Colombier void
4133e12c5d1SDavid du Colombier io(void)
4143e12c5d1SDavid du Colombier {
415225077b0SDavid du Colombier 	volatile long n;
416225077b0SDavid du Colombier 	volatile uchar mdata[IOHDRSZ + Maxfdata];
417225077b0SDavid du Colombier 	Job *volatile job;
418225077b0SDavid du Colombier 	Mfile *volatile mf;
419225077b0SDavid du Colombier 	volatile Request req;
4203e12c5d1SDavid du Colombier 
4214f8f669cSDavid du Colombier 	memset(&req, 0, sizeof req);
4223e12c5d1SDavid du Colombier 	/*
4233e12c5d1SDavid du Colombier 	 *  a slave process is sometimes forked to wait for replies from other
4243e12c5d1SDavid du Colombier 	 *  servers.  The master process returns immediately via a longjmp
425219b2ee8SDavid du Colombier 	 *  through 'mret'.
4263e12c5d1SDavid du Colombier 	 */
4277dd7cddfSDavid du Colombier 	if(setjmp(req.mret))
428b4b9fc2fSDavid du Colombier 		putactivity(0);
4293e12c5d1SDavid du Colombier 	req.isslave = 0;
430c73252aeSDavid du Colombier 	stop = 0;
431c73252aeSDavid du Colombier 	while(!stop){
432f2714ceaSDavid du Colombier 		procsetname("%d %s/dns Twrites of %d 9p rpcs read; %d alarms",
433f2714ceaSDavid du Colombier 			stats.qrecvd9p, mntpt, stats.qrecvd9prpc, stats.alarms);
4349a747e4fSDavid du Colombier 		n = read9pmsg(mfd[0], mdata, sizeof mdata);
4357dd7cddfSDavid du Colombier 		if(n<=0){
436adb31a62SDavid du Colombier 			dnslog("error reading 9P from %s: %r", mntpt);
437adb31a62SDavid du Colombier 			sleep(2000);		/* don't thrash */
4386aaebd7dSDavid du Colombier 			return;
4397dd7cddfSDavid du Colombier 		}
4404f8f669cSDavid du Colombier 
4416aaebd7dSDavid du Colombier 		stats.qrecvd9prpc++;
4427dd7cddfSDavid du Colombier 		job = newjob();
4439a747e4fSDavid du Colombier 		if(convM2S(mdata, n, &job->request) != n){
4447dd7cddfSDavid du Colombier 			freejob(job);
4457dd7cddfSDavid du Colombier 			continue;
4467dd7cddfSDavid du Colombier 		}
4477dd7cddfSDavid du Colombier 		mf = newfid(job->request.fid, 0);
448219b2ee8SDavid du Colombier 		if(debug)
4494f8f669cSDavid du Colombier 			dnslog("%F", &job->request);
4507dd7cddfSDavid du Colombier 
451b4b9fc2fSDavid du Colombier 		getactivity(&req, 0);
452254fe3d3SDavid du Colombier 		req.aborttime = time(nil) + Maxreqtm;
453f46c709fSDavid du Colombier 		req.from = "9p";
4547dd7cddfSDavid du Colombier 
4557dd7cddfSDavid du Colombier 		switch(job->request.type){
4563e12c5d1SDavid du Colombier 		default:
4574f8f669cSDavid du Colombier 			warning("unknown request type %d", job->request.type);
4583e12c5d1SDavid du Colombier 			break;
4599a747e4fSDavid du Colombier 		case Tversion:
4609a747e4fSDavid du Colombier 			rversion(job);
4613e12c5d1SDavid du Colombier 			break;
4629a747e4fSDavid du Colombier 		case Tauth:
4639a747e4fSDavid du Colombier 			rauth(job);
4643e12c5d1SDavid du Colombier 			break;
4653e12c5d1SDavid du Colombier 		case Tflush:
4667dd7cddfSDavid du Colombier 			rflush(job);
4673e12c5d1SDavid du Colombier 			break;
4683e12c5d1SDavid du Colombier 		case Tattach:
4697dd7cddfSDavid du Colombier 			rattach(job, mf);
4703e12c5d1SDavid du Colombier 			break;
4713e12c5d1SDavid du Colombier 		case Twalk:
4727dd7cddfSDavid du Colombier 			rwalk(job, mf);
4733e12c5d1SDavid du Colombier 			break;
4743e12c5d1SDavid du Colombier 		case Topen:
4757dd7cddfSDavid du Colombier 			ropen(job, mf);
4763e12c5d1SDavid du Colombier 			break;
4773e12c5d1SDavid du Colombier 		case Tcreate:
4787dd7cddfSDavid du Colombier 			rcreate(job, mf);
4793e12c5d1SDavid du Colombier 			break;
4803e12c5d1SDavid du Colombier 		case Tread:
4817dd7cddfSDavid du Colombier 			rread(job, mf);
4823e12c5d1SDavid du Colombier 			break;
4833e12c5d1SDavid du Colombier 		case Twrite:
484adb31a62SDavid du Colombier 			/* &req is handed to dnresolve() */
4857dd7cddfSDavid du Colombier 			rwrite(job, mf, &req);
4863e12c5d1SDavid du Colombier 			break;
4873e12c5d1SDavid du Colombier 		case Tclunk:
4887dd7cddfSDavid du Colombier 			rclunk(job, mf);
4893e12c5d1SDavid du Colombier 			break;
4903e12c5d1SDavid du Colombier 		case Tremove:
4917dd7cddfSDavid du Colombier 			rremove(job, mf);
4923e12c5d1SDavid du Colombier 			break;
4933e12c5d1SDavid du Colombier 		case Tstat:
4947dd7cddfSDavid du Colombier 			rstat(job, mf);
4953e12c5d1SDavid du Colombier 			break;
4963e12c5d1SDavid du Colombier 		case Twstat:
4977dd7cddfSDavid du Colombier 			rwstat(job, mf);
4983e12c5d1SDavid du Colombier 			break;
4993e12c5d1SDavid du Colombier 		}
5007dd7cddfSDavid du Colombier 
5017dd7cddfSDavid du Colombier 		freejob(job);
5027dd7cddfSDavid du Colombier 
5033e12c5d1SDavid du Colombier 		/*
5043e12c5d1SDavid du Colombier 		 *  slave processes die after replying
5053e12c5d1SDavid du Colombier 		 */
5067dd7cddfSDavid du Colombier 		if(req.isslave){
507b4b9fc2fSDavid du Colombier 			putactivity(0);
5083e12c5d1SDavid du Colombier 			_exits(0);
5097dd7cddfSDavid du Colombier 		}
5107dd7cddfSDavid du Colombier 
511b4b9fc2fSDavid du Colombier 		putactivity(0);
5127dd7cddfSDavid du Colombier 	}
513c73252aeSDavid du Colombier 	/* kill any udp server, notifier, etc. processes */
514c73252aeSDavid du Colombier 	postnote(PNGROUP, getpid(), "die");
515c73252aeSDavid du Colombier 	sleep(1000);
5163e12c5d1SDavid du Colombier }
5173e12c5d1SDavid du Colombier 
5183e12c5d1SDavid du Colombier void
5199a747e4fSDavid du Colombier rversion(Job *job)
520219b2ee8SDavid du Colombier {
5219a747e4fSDavid du Colombier 	if(job->request.msize > IOHDRSZ + Maxfdata)
5229a747e4fSDavid du Colombier 		job->reply.msize = IOHDRSZ + Maxfdata;
5239a747e4fSDavid du Colombier 	else
5249a747e4fSDavid du Colombier 		job->reply.msize = job->request.msize;
5259a747e4fSDavid du Colombier 	if(strncmp(job->request.version, "9P2000", 6) != 0)
5269a747e4fSDavid du Colombier 		sendmsg(job, "unknown 9P version");
5279a747e4fSDavid du Colombier 	else{
5289a747e4fSDavid du Colombier 		job->reply.version = "9P2000";
5297dd7cddfSDavid du Colombier 		sendmsg(job, 0);
530219b2ee8SDavid du Colombier 	}
5319a747e4fSDavid du Colombier }
532219b2ee8SDavid du Colombier 
533219b2ee8SDavid du Colombier void
5349a747e4fSDavid du Colombier rauth(Job *job)
5353e12c5d1SDavid du Colombier {
5363ff48bf5SDavid du Colombier 	sendmsg(job, "dns: authentication not required");
5377dd7cddfSDavid du Colombier }
5387dd7cddfSDavid du Colombier 
5399a747e4fSDavid du Colombier /*
5409a747e4fSDavid du Colombier  *  don't flush till all the slaves are done
5419a747e4fSDavid du Colombier  */
5427dd7cddfSDavid du Colombier void
5437dd7cddfSDavid du Colombier rflush(Job *job)
5447dd7cddfSDavid du Colombier {
5457dd7cddfSDavid du Colombier 	flushjob(job->request.oldtag);
5467dd7cddfSDavid du Colombier 	sendmsg(job, 0);
5473e12c5d1SDavid du Colombier }
5483e12c5d1SDavid du Colombier 
5493e12c5d1SDavid du Colombier void
5507dd7cddfSDavid du Colombier rattach(Job *job, Mfile *mf)
5513e12c5d1SDavid du Colombier {
5529a747e4fSDavid du Colombier 	if(mf->user != nil)
5539a747e4fSDavid du Colombier 		free(mf->user);
5549a747e4fSDavid du Colombier 	mf->user = estrdup(job->request.uname);
5553e12c5d1SDavid du Colombier 	mf->qid.vers = vers++;
5569a747e4fSDavid du Colombier 	mf->qid.type = QTDIR;
5579a747e4fSDavid du Colombier 	mf->qid.path = 0LL;
5587dd7cddfSDavid du Colombier 	job->reply.qid = mf->qid;
5597dd7cddfSDavid du Colombier 	sendmsg(job, 0);
5603e12c5d1SDavid du Colombier }
5613e12c5d1SDavid du Colombier 
5623e12c5d1SDavid du Colombier char*
5637dd7cddfSDavid du Colombier rwalk(Job *job, Mfile *mf)
5643e12c5d1SDavid du Colombier {
5654f8f669cSDavid du Colombier 	int i, nelems;
5663e12c5d1SDavid du Colombier 	char *err;
5679a747e4fSDavid du Colombier 	char **elems;
5689a747e4fSDavid du Colombier 	Mfile *nmf;
5699a747e4fSDavid du Colombier 	Qid qid;
5703e12c5d1SDavid du Colombier 
5713e12c5d1SDavid du Colombier 	err = 0;
5729a747e4fSDavid du Colombier 	nmf = nil;
5739a747e4fSDavid du Colombier 	elems  = job->request.wname;
5749a747e4fSDavid du Colombier 	nelems = job->request.nwname;
5759a747e4fSDavid du Colombier 	job->reply.nwqid = 0;
5769a747e4fSDavid du Colombier 
5779a747e4fSDavid du Colombier 	if(job->request.newfid != job->request.fid){
5789a747e4fSDavid du Colombier 		/* clone fid */
5799a747e4fSDavid du Colombier 		nmf = copyfid(mf, job->request.newfid);
5809a747e4fSDavid du Colombier 		if(nmf == nil){
5819a747e4fSDavid du Colombier 			err = "clone bad newfid";
5829a747e4fSDavid du Colombier 			goto send;
5839a747e4fSDavid du Colombier 		}
5849a747e4fSDavid du Colombier 		mf = nmf;
5859a747e4fSDavid du Colombier 	}
5869a747e4fSDavid du Colombier 	/* else nmf will be nil */
5879a747e4fSDavid du Colombier 
5889a747e4fSDavid du Colombier 	qid = mf->qid;
5894f8f669cSDavid du Colombier 	if(nelems > 0)
5909a747e4fSDavid du Colombier 		/* walk fid */
5919a747e4fSDavid du Colombier 		for(i=0; i<nelems && i<MAXWELEM; i++){
5929a747e4fSDavid du Colombier 			if((qid.type & QTDIR) == 0){
5933e12c5d1SDavid du Colombier 				err = "not a directory";
5949a747e4fSDavid du Colombier 				break;
5953e12c5d1SDavid du Colombier 			}
5964f8f669cSDavid du Colombier 			if (strcmp(elems[i], "..") == 0 ||
5974f8f669cSDavid du Colombier 			    strcmp(elems[i], ".") == 0){
5989a747e4fSDavid du Colombier 				qid.type = QTDIR;
5999a747e4fSDavid du Colombier 				qid.path = Qdir;
6009a747e4fSDavid du Colombier Found:
6019a747e4fSDavid du Colombier 				job->reply.wqid[i] = qid;
6029a747e4fSDavid du Colombier 				job->reply.nwqid++;
6039a747e4fSDavid du Colombier 				continue;
6043e12c5d1SDavid du Colombier 			}
6059a747e4fSDavid du Colombier 			if(strcmp(elems[i], "dns") == 0){
6069a747e4fSDavid du Colombier 				qid.type = QTFILE;
6079a747e4fSDavid du Colombier 				qid.path = Qdns;
6089a747e4fSDavid du Colombier 				goto Found;
6093e12c5d1SDavid du Colombier 			}
6109a747e4fSDavid du Colombier 			err = "file does not exist";
6119a747e4fSDavid du Colombier 			break;
6129a747e4fSDavid du Colombier 		}
6139a747e4fSDavid du Colombier 
6143e12c5d1SDavid du Colombier send:
6159a747e4fSDavid du Colombier 	if(nmf != nil && (err!=nil || job->reply.nwqid<nelems))
6169a747e4fSDavid du Colombier 		freefid(nmf);
6179a747e4fSDavid du Colombier 	if(err == nil)
6189a747e4fSDavid du Colombier 		mf->qid = qid;
6197dd7cddfSDavid du Colombier 	sendmsg(job, err);
6203e12c5d1SDavid du Colombier 	return err;
6213e12c5d1SDavid du Colombier }
6223e12c5d1SDavid du Colombier 
6233e12c5d1SDavid du Colombier void
6247dd7cddfSDavid du Colombier ropen(Job *job, Mfile *mf)
6253e12c5d1SDavid du Colombier {
6263e12c5d1SDavid du Colombier 	int mode;
6273e12c5d1SDavid du Colombier 	char *err;
6283e12c5d1SDavid du Colombier 
6293e12c5d1SDavid du Colombier 	err = 0;
6307dd7cddfSDavid du Colombier 	mode = job->request.mode;
6314f8f669cSDavid du Colombier 	if(mf->qid.type & QTDIR)
6323e12c5d1SDavid du Colombier 		if(mode)
6333e12c5d1SDavid du Colombier 			err = "permission denied";
6347dd7cddfSDavid du Colombier 	job->reply.qid = mf->qid;
6359a747e4fSDavid du Colombier 	job->reply.iounit = 0;
6367dd7cddfSDavid du Colombier 	sendmsg(job, err);
6373e12c5d1SDavid du Colombier }
6383e12c5d1SDavid du Colombier 
6393e12c5d1SDavid du Colombier void
6407dd7cddfSDavid du Colombier rcreate(Job *job, Mfile *mf)
6413e12c5d1SDavid du Colombier {
6423e12c5d1SDavid du Colombier 	USED(mf);
6437dd7cddfSDavid du Colombier 	sendmsg(job, "creation permission denied");
6443e12c5d1SDavid du Colombier }
6453e12c5d1SDavid du Colombier 
6463e12c5d1SDavid du Colombier void
6477dd7cddfSDavid du Colombier rread(Job *job, Mfile *mf)
6483e12c5d1SDavid du Colombier {
6494f8f669cSDavid du Colombier 	int i, n;
6506b0d5c8bSDavid du Colombier 	long clock;
6514f8f669cSDavid du Colombier 	ulong cnt;
6524f8f669cSDavid du Colombier 	vlong off;
6534f8f669cSDavid du Colombier 	char *err;
654254fe3d3SDavid du Colombier 	uchar buf[Maxfdata];
6554f8f669cSDavid du Colombier 	Dir dir;
6563e12c5d1SDavid du Colombier 
6573e12c5d1SDavid du Colombier 	n = 0;
6584f8f669cSDavid du Colombier 	err = nil;
6597dd7cddfSDavid du Colombier 	off = job->request.offset;
6607dd7cddfSDavid du Colombier 	cnt = job->request.count;
6614f8f669cSDavid du Colombier 	*buf = '\0';
6624f8f669cSDavid du Colombier 	job->reply.data = (char*)buf;
6639a747e4fSDavid du Colombier 	if(mf->qid.type & QTDIR){
6644f8f669cSDavid du Colombier 		clock = time(nil);
6653e12c5d1SDavid du Colombier 		if(off == 0){
6666aaebd7dSDavid du Colombier 			memset(&dir, 0, sizeof dir);
6679a747e4fSDavid du Colombier 			dir.name = "dns";
6689a747e4fSDavid du Colombier 			dir.qid.type = QTFILE;
6693e12c5d1SDavid du Colombier 			dir.qid.vers = vers;
6703e12c5d1SDavid du Colombier 			dir.qid.path = Qdns;
6713e12c5d1SDavid du Colombier 			dir.mode = 0666;
6723e12c5d1SDavid du Colombier 			dir.length = 0;
6734f8f669cSDavid du Colombier 			dir.uid = dir.gid = dir.muid = mf->user;
6744f8f669cSDavid du Colombier 			dir.atime = dir.mtime = clock;		/* wrong */
6759a747e4fSDavid du Colombier 			n = convD2M(&dir, buf, sizeof buf);
6763e12c5d1SDavid du Colombier 		}
6774f8f669cSDavid du Colombier 	} else if (off < 0)
6784f8f669cSDavid du Colombier 		err = "negative read offset";
6794f8f669cSDavid du Colombier 	else {
6804f8f669cSDavid du Colombier 		/* first offset will always be zero */
6817dd7cddfSDavid du Colombier 		for(i = 1; i <= mf->nrr; i++)
6827dd7cddfSDavid du Colombier 			if(mf->rr[i] > off)
6833e12c5d1SDavid du Colombier 				break;
6844f8f669cSDavid du Colombier 		if(i <= mf->nrr) {
6857dd7cddfSDavid du Colombier 			if(off + cnt > mf->rr[i])
6867dd7cddfSDavid du Colombier 				n = mf->rr[i] - off;
6877dd7cddfSDavid du Colombier 			else
6887dd7cddfSDavid du Colombier 				n = cnt;
6894f8f669cSDavid du Colombier 			assert(n >= 0);
6907dd7cddfSDavid du Colombier 			job->reply.data = mf->reply + off;
6913e12c5d1SDavid du Colombier 		}
6924f8f669cSDavid du Colombier 	}
6937dd7cddfSDavid du Colombier 	job->reply.count = n;
6947dd7cddfSDavid du Colombier 	sendmsg(job, err);
6953e12c5d1SDavid du Colombier }
6963e12c5d1SDavid du Colombier 
6973e12c5d1SDavid du Colombier void
6987dd7cddfSDavid du Colombier rwrite(Job *job, Mfile *mf, Request *req)
6993e12c5d1SDavid du Colombier {
7004f8f669cSDavid du Colombier 	int rooted, status, wantsav;
7017dd7cddfSDavid du Colombier 	long n;
7024f8f669cSDavid du Colombier 	ulong cnt;
7037dd7cddfSDavid du Colombier 	char *err, *p, *atype;
7047dd7cddfSDavid du Colombier 	RR *rp, *tp, *neg;
7053e12c5d1SDavid du Colombier 
7064f8f669cSDavid du Colombier 	err = nil;
7077dd7cddfSDavid du Colombier 	cnt = job->request.count;
7089a747e4fSDavid du Colombier 	if(mf->qid.type & QTDIR){
7093e12c5d1SDavid du Colombier 		err = "can't write directory";
7103e12c5d1SDavid du Colombier 		goto send;
7113e12c5d1SDavid du Colombier 	}
7124f8f669cSDavid du Colombier 	if (job->request.offset != 0) {
7134f8f669cSDavid du Colombier 		err = "writing at non-zero offset";
7144f8f669cSDavid du Colombier 		goto send;
7154f8f669cSDavid du Colombier 	}
7163e12c5d1SDavid du Colombier 	if(cnt >= Maxrequest){
7173e12c5d1SDavid du Colombier 		err = "request too long";
7183e12c5d1SDavid du Colombier 		goto send;
7193e12c5d1SDavid du Colombier 	}
7207dd7cddfSDavid du Colombier 	job->request.data[cnt] = 0;
7217dd7cddfSDavid du Colombier 	if(cnt > 0 && job->request.data[cnt-1] == '\n')
7227dd7cddfSDavid du Colombier 		job->request.data[cnt-1] = 0;
7233e12c5d1SDavid du Colombier 
7243e12c5d1SDavid du Colombier 	/*
7257dd7cddfSDavid du Colombier 	 *  special commands
726219b2ee8SDavid du Colombier 	 */
727410ea80bSDavid du Colombier //	dnslog("rwrite got: %s", job->request.data);
7284f8f669cSDavid du Colombier 	if(strcmp(job->request.data, "debug")==0){
729219b2ee8SDavid du Colombier 		debug ^= 1;
730219b2ee8SDavid du Colombier 		goto send;
7314f8f669cSDavid du Colombier 	} else if(strcmp(job->request.data, "dump")==0){
732219b2ee8SDavid du Colombier 		dndump("/lib/ndb/dnsdump");
733219b2ee8SDavid du Colombier 		goto send;
7344f8f669cSDavid du Colombier 	} else if(strcmp(job->request.data, "poolcheck")==0){
7359a747e4fSDavid du Colombier 		poolcheck(mainmem);
7369a747e4fSDavid du Colombier 		goto send;
7374f927735SDavid du Colombier 	} else if(strcmp(job->request.data, "refresh")==0){
7384f927735SDavid du Colombier 		needrefresh = 1;
7394f927735SDavid du Colombier 		goto send;
740c73252aeSDavid du Colombier 	} else if(strcmp(job->request.data, "restart")==0){
741c73252aeSDavid du Colombier 		stop = 1;
742c73252aeSDavid du Colombier 		goto send;
7434f927735SDavid du Colombier 	} else if(strcmp(job->request.data, "stats")==0){
7444f927735SDavid du Colombier 		dnstats("/lib/ndb/dnsstats");
7454f927735SDavid du Colombier 		goto send;
746f2714ceaSDavid du Colombier 	} else if(strncmp(job->request.data, "target ", 7)==0){
747f2714ceaSDavid du Colombier 		target = atol(job->request.data + 7);
74821abd8f2SDavid du Colombier 		dnslog("target set to %ld", target);
74921abd8f2SDavid du Colombier 		goto send;
75021abd8f2SDavid du Colombier 	} else if(strcmp(job->request.data, "age")==0){
75121abd8f2SDavid du Colombier 		dnslog("dump, age & dump forced");
75221abd8f2SDavid du Colombier 		dndump("/lib/ndb/dnsdump1");
75321abd8f2SDavid du Colombier 		dnforceage();
75421abd8f2SDavid du Colombier 		dndump("/lib/ndb/dnsdump2");
75521abd8f2SDavid du Colombier 		goto send;
756219b2ee8SDavid du Colombier 	}
757219b2ee8SDavid du Colombier 
758219b2ee8SDavid du Colombier 	/*
7597dd7cddfSDavid du Colombier 	 *  kill previous reply
7607dd7cddfSDavid du Colombier 	 */
7617dd7cddfSDavid du Colombier 	mf->nrr = 0;
7627dd7cddfSDavid du Colombier 	mf->rr[0] = 0;
7637dd7cddfSDavid du Colombier 
7647dd7cddfSDavid du Colombier 	/*
7653e12c5d1SDavid du Colombier 	 *  break up request (into a name and a type)
7663e12c5d1SDavid du Colombier 	 */
7677dd7cddfSDavid du Colombier 	atype = strchr(job->request.data, ' ');
7683e12c5d1SDavid du Colombier 	if(atype == 0){
7693e12c5d1SDavid du Colombier 		err = "illegal request";
7703e12c5d1SDavid du Colombier 		goto send;
7713e12c5d1SDavid du Colombier 	} else
7723e12c5d1SDavid du Colombier 		*atype++ = 0;
7733e12c5d1SDavid du Colombier 
7747dd7cddfSDavid du Colombier 	/*
7757dd7cddfSDavid du Colombier 	 *  tracing request
7767dd7cddfSDavid du Colombier 	 */
7777dd7cddfSDavid du Colombier 	if(strcmp(atype, "trace") == 0){
7787dd7cddfSDavid du Colombier 		if(trace)
7797dd7cddfSDavid du Colombier 			free(trace);
7807dd7cddfSDavid du Colombier 		if(*job->request.data)
7819a747e4fSDavid du Colombier 			trace = estrdup(job->request.data);
7827dd7cddfSDavid du Colombier 		else
7837dd7cddfSDavid du Colombier 			trace = 0;
7847dd7cddfSDavid du Colombier 		goto send;
7857dd7cddfSDavid du Colombier 	}
7867dd7cddfSDavid du Colombier 
7874f8f669cSDavid du Colombier 	/* normal request: domain [type] */
788a41547ffSDavid du Colombier 	stats.qrecvd9p++;
7893e12c5d1SDavid du Colombier 	mf->type = rrtype(atype);
7903e12c5d1SDavid du Colombier 	if(mf->type < 0){
7913e12c5d1SDavid du Colombier 		err = "unknown type";
7923e12c5d1SDavid du Colombier 		goto send;
7933e12c5d1SDavid du Colombier 	}
7943e12c5d1SDavid du Colombier 
7957dd7cddfSDavid du Colombier 	p = atype - 2;
7967dd7cddfSDavid du Colombier 	if(p >= job->request.data && *p == '.'){
7977dd7cddfSDavid du Colombier 		rooted = 1;
7987dd7cddfSDavid du Colombier 		*p = 0;
7997dd7cddfSDavid du Colombier 	} else
8007dd7cddfSDavid du Colombier 		rooted = 0;
8013e12c5d1SDavid du Colombier 
8027dd7cddfSDavid du Colombier 	p = job->request.data;
8037dd7cddfSDavid du Colombier 	if(*p == '!'){
8047dd7cddfSDavid du Colombier 		wantsav = 1;
8057dd7cddfSDavid du Colombier 		p++;
8067dd7cddfSDavid du Colombier 	} else
8077dd7cddfSDavid du Colombier 		wantsav = 0;
8084f8f669cSDavid du Colombier 
8099a747e4fSDavid du Colombier 	dncheck(0, 1);
8104f8f669cSDavid du Colombier 	status = 0;
8117dd7cddfSDavid du Colombier 	rp = dnresolve(p, Cin, mf->type, req, 0, 0, Recurse, rooted, &status);
8124f8f669cSDavid du Colombier 
8139a747e4fSDavid du Colombier 	dncheck(0, 1);
814*530fef66SDavid du Colombier 	lock(&dnlock);
8157dd7cddfSDavid du Colombier 	neg = rrremneg(&rp);
8167dd7cddfSDavid du Colombier 	if(neg){
8177dd7cddfSDavid du Colombier 		status = neg->negrcode;
8187dd7cddfSDavid du Colombier 		rrfreelist(neg);
8197dd7cddfSDavid du Colombier 	}
820*530fef66SDavid du Colombier 	unlock(&dnlock);
8214f8f669cSDavid du Colombier 
8224f8f669cSDavid du Colombier 	if(rp == nil)
823271b8d73SDavid du Colombier 		switch(status){
824271b8d73SDavid du Colombier 		case Rname:
8257dd7cddfSDavid du Colombier 			err = "name does not exist";
826271b8d73SDavid du Colombier 			break;
827271b8d73SDavid du Colombier 		case Rserver:
828271b8d73SDavid du Colombier 			err = "dns failure";
829271b8d73SDavid du Colombier 			break;
830271b8d73SDavid du Colombier 		default:
831271b8d73SDavid du Colombier 			err = "resource does not exist";
832271b8d73SDavid du Colombier 			break;
833271b8d73SDavid du Colombier 		}
8344f8f669cSDavid du Colombier 	else {
83534f77ae3SDavid du Colombier 		lock(&joblock);
83634f77ae3SDavid du Colombier 		if(!job->flushed){
8377dd7cddfSDavid du Colombier 			/* format data to be read later */
8387dd7cddfSDavid du Colombier 			n = 0;
8397dd7cddfSDavid du Colombier 			mf->nrr = 0;
8407dd7cddfSDavid du Colombier 			for(tp = rp; mf->nrr < Maxrrr-1 && n < Maxreply && tp &&
8417dd7cddfSDavid du Colombier 			    tsame(mf->type, tp->type); tp = tp->next){
8427dd7cddfSDavid du Colombier 				mf->rr[mf->nrr++] = n;
8437dd7cddfSDavid du Colombier 				if(wantsav)
8444f8f669cSDavid du Colombier 					n += snprint(mf->reply+n, Maxreply-n,
8454f8f669cSDavid du Colombier 						"%Q", tp);
8467dd7cddfSDavid du Colombier 				else
8474f8f669cSDavid du Colombier 					n += snprint(mf->reply+n, Maxreply-n,
8484f8f669cSDavid du Colombier 						"%R", tp);
8497dd7cddfSDavid du Colombier 			}
8507dd7cddfSDavid du Colombier 			mf->rr[mf->nrr] = n;
85134f77ae3SDavid du Colombier 		}
85234f77ae3SDavid du Colombier 		unlock(&joblock);
8537dd7cddfSDavid du Colombier 		rrfreelist(rp);
8547dd7cddfSDavid du Colombier 	}
8553e12c5d1SDavid du Colombier send:
8569a747e4fSDavid du Colombier 	dncheck(0, 1);
8577dd7cddfSDavid du Colombier 	job->reply.count = cnt;
8587dd7cddfSDavid du Colombier 	sendmsg(job, err);
8593e12c5d1SDavid du Colombier }
8603e12c5d1SDavid du Colombier 
8613e12c5d1SDavid du Colombier void
8627dd7cddfSDavid du Colombier rclunk(Job *job, Mfile *mf)
8633e12c5d1SDavid du Colombier {
8647dd7cddfSDavid du Colombier 	freefid(mf);
8657dd7cddfSDavid du Colombier 	sendmsg(job, 0);
8663e12c5d1SDavid du Colombier }
8673e12c5d1SDavid du Colombier 
8683e12c5d1SDavid du Colombier void
8697dd7cddfSDavid du Colombier rremove(Job *job, Mfile *mf)
8703e12c5d1SDavid du Colombier {
8713e12c5d1SDavid du Colombier 	USED(mf);
8727dd7cddfSDavid du Colombier 	sendmsg(job, "remove permission denied");
8733e12c5d1SDavid du Colombier }
8743e12c5d1SDavid du Colombier 
8753e12c5d1SDavid du Colombier void
8767dd7cddfSDavid du Colombier rstat(Job *job, Mfile *mf)
8773e12c5d1SDavid du Colombier {
8783e12c5d1SDavid du Colombier 	Dir dir;
8799a747e4fSDavid du Colombier 	uchar buf[IOHDRSZ+Maxfdata];
8803e12c5d1SDavid du Colombier 
8816aaebd7dSDavid du Colombier 	memset(&dir, 0, sizeof dir);
8829a747e4fSDavid du Colombier 	if(mf->qid.type & QTDIR){
8839a747e4fSDavid du Colombier 		dir.name = ".";
8849a747e4fSDavid du Colombier 		dir.mode = DMDIR|0555;
885219b2ee8SDavid du Colombier 	} else {
8869a747e4fSDavid du Colombier 		dir.name = "dns";
8873e12c5d1SDavid du Colombier 		dir.mode = 0666;
888219b2ee8SDavid du Colombier 	}
889219b2ee8SDavid du Colombier 	dir.qid = mf->qid;
8903e12c5d1SDavid du Colombier 	dir.length = 0;
8914f8f669cSDavid du Colombier 	dir.uid = dir.gid = dir.muid = mf->user;
8924f8f669cSDavid du Colombier 	dir.atime = dir.mtime = time(nil);
8939a747e4fSDavid du Colombier 	job->reply.nstat = convD2M(&dir, buf, sizeof buf);
8949a747e4fSDavid du Colombier 	job->reply.stat = buf;
8957dd7cddfSDavid du Colombier 	sendmsg(job, 0);
8963e12c5d1SDavid du Colombier }
8973e12c5d1SDavid du Colombier 
8983e12c5d1SDavid du Colombier void
8997dd7cddfSDavid du Colombier rwstat(Job *job, Mfile *mf)
9003e12c5d1SDavid du Colombier {
9013e12c5d1SDavid du Colombier 	USED(mf);
9027dd7cddfSDavid du Colombier 	sendmsg(job, "wstat permission denied");
9033e12c5d1SDavid du Colombier }
9043e12c5d1SDavid du Colombier 
9053e12c5d1SDavid du Colombier void
9067dd7cddfSDavid du Colombier sendmsg(Job *job, char *err)
9073e12c5d1SDavid du Colombier {
9083e12c5d1SDavid du Colombier 	int n;
9099a747e4fSDavid du Colombier 	uchar mdata[IOHDRSZ + Maxfdata];
9109a747e4fSDavid du Colombier 	char ename[ERRMAX];
9113e12c5d1SDavid du Colombier 
9123e12c5d1SDavid du Colombier 	if(err){
9137dd7cddfSDavid du Colombier 		job->reply.type = Rerror;
9144f8f669cSDavid du Colombier 		snprint(ename, sizeof ename, "dns: %s", err);
9159a747e4fSDavid du Colombier 		job->reply.ename = ename;
9164f8f669cSDavid du Colombier 	}else
9177dd7cddfSDavid du Colombier 		job->reply.type = job->request.type+1;
9187dd7cddfSDavid du Colombier 	job->reply.tag = job->request.tag;
9199a747e4fSDavid du Colombier 	n = convS2M(&job->reply, mdata, sizeof mdata);
9209a747e4fSDavid du Colombier 	if(n == 0){
9214f8f669cSDavid du Colombier 		warning("sendmsg convS2M of %F returns 0", &job->reply);
9229a747e4fSDavid du Colombier 		abort();
9233e12c5d1SDavid du Colombier 	}
9249a747e4fSDavid du Colombier 	lock(&joblock);
9259a747e4fSDavid du Colombier 	if(job->flushed == 0)
9269a747e4fSDavid du Colombier 		if(write(mfd[1], mdata, n)!=n)
9279a747e4fSDavid du Colombier 			sysfatal("mount write");
9287dd7cddfSDavid du Colombier 	unlock(&joblock);
9299a747e4fSDavid du Colombier 	if(debug)
9304f8f669cSDavid du Colombier 		dnslog("%F %d", &job->reply, n);
9313e12c5d1SDavid du Colombier }
9323e12c5d1SDavid du Colombier 
9333e12c5d1SDavid du Colombier /*
9347dd7cddfSDavid du Colombier  *  the following varies between dnsdebug and dns
9353e12c5d1SDavid du Colombier  */
9363e12c5d1SDavid du Colombier void
9377dd7cddfSDavid du Colombier logreply(int id, uchar *addr, DNSmsg *mp)
9383e12c5d1SDavid du Colombier {
9397dd7cddfSDavid du Colombier 	RR *rp;
9403e12c5d1SDavid du Colombier 
9414f8f669cSDavid du Colombier 	dnslog("%d: rcvd %I flags:%s%s%s%s%s", id, addr,
9427dd7cddfSDavid du Colombier 		mp->flags & Fauth? " auth": "",
9437dd7cddfSDavid du Colombier 		mp->flags & Ftrunc? " trunc": "",
9447dd7cddfSDavid du Colombier 		mp->flags & Frecurse? " rd": "",
9457dd7cddfSDavid du Colombier 		mp->flags & Fcanrec? " ra": "",
9464f8f669cSDavid du Colombier 		(mp->flags & (Fauth|Rmask)) == (Fauth|Rname)? " nx": "");
9477dd7cddfSDavid du Colombier 	for(rp = mp->qd; rp != nil; rp = rp->next)
9484f8f669cSDavid du Colombier 		dnslog("%d: rcvd %I qd %s", id, addr, rp->owner->name);
9497dd7cddfSDavid du Colombier 	for(rp = mp->an; rp != nil; rp = rp->next)
9504f8f669cSDavid du Colombier 		dnslog("%d: rcvd %I an %R", id, addr, rp);
9517dd7cddfSDavid du Colombier 	for(rp = mp->ns; rp != nil; rp = rp->next)
9524f8f669cSDavid du Colombier 		dnslog("%d: rcvd %I ns %R", id, addr, rp);
9537dd7cddfSDavid du Colombier 	for(rp = mp->ar; rp != nil; rp = rp->next)
9544f8f669cSDavid du Colombier 		dnslog("%d: rcvd %I ar %R", id, addr, rp);
9553e12c5d1SDavid du Colombier }
9567dd7cddfSDavid du Colombier 
9577dd7cddfSDavid du Colombier void
9587dd7cddfSDavid du Colombier logsend(int id, int subid, uchar *addr, char *sname, char *rname, int type)
9597dd7cddfSDavid du Colombier {
9607dd7cddfSDavid du Colombier 	char buf[12];
9617dd7cddfSDavid du Colombier 
9624f8f669cSDavid du Colombier 	dnslog("[%d] %d.%d: sending to %I/%s %s %s",
9634f8f669cSDavid du Colombier 		getpid(), id, subid, addr, sname, rname,
9644f8f669cSDavid du Colombier 		rrname(type, buf, sizeof buf));
9657dd7cddfSDavid du Colombier }
9667dd7cddfSDavid du Colombier 
9677dd7cddfSDavid du Colombier RR*
9687dd7cddfSDavid du Colombier getdnsservers(int class)
9697dd7cddfSDavid du Colombier {
9707dd7cddfSDavid du Colombier 	return dnsservers(class);
9713e12c5d1SDavid du Colombier }
972