xref: /plan9/sys/src/cmd/ndb/dns.c (revision 98813beef1db23409911a4b339e6bb9c03d0a5c0)
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 
2827acba7cSDavid du Colombier extern	ulong	start;
2927acba7cSDavid du Colombier 
303e12c5d1SDavid du Colombier int vers;		/* incremented each clone/attach */
31adb31a62SDavid du Colombier 
32adb31a62SDavid du Colombier static volatile int stop;
333e12c5d1SDavid du Colombier 
34410ea80bSDavid du Colombier /* holds data to be returned via read of /net/dns, perhaps multiple reads */
353e12c5d1SDavid du Colombier struct Mfile
363e12c5d1SDavid du Colombier {
377dd7cddfSDavid du Colombier 	Mfile		*next;		/* next free mfile */
389a747e4fSDavid du Colombier 	int		ref;
397dd7cddfSDavid du Colombier 
409a747e4fSDavid du Colombier 	char		*user;
413e12c5d1SDavid du Colombier 	Qid		qid;
423e12c5d1SDavid du Colombier 	int		fid;
433e12c5d1SDavid du Colombier 
443e12c5d1SDavid du Colombier 	int		type;		/* reply type */
457dd7cddfSDavid du Colombier 	char		reply[Maxreply];
467dd7cddfSDavid du Colombier 	ushort		rr[Maxrrr];	/* offset of rr's */
477dd7cddfSDavid du Colombier 	ushort		nrr;		/* number of rr's */
483e12c5d1SDavid du Colombier };
493e12c5d1SDavid du Colombier 
504f8f669cSDavid du Colombier /*
514f8f669cSDavid du Colombier  *  active local requests
524f8f669cSDavid du Colombier  */
537dd7cddfSDavid du Colombier struct Job
547dd7cddfSDavid du Colombier {
557dd7cddfSDavid du Colombier 	Job	*next;
567dd7cddfSDavid du Colombier 	int	flushed;
577dd7cddfSDavid du Colombier 	Fcall	request;
587dd7cddfSDavid du Colombier 	Fcall	reply;
597dd7cddfSDavid du Colombier };
607dd7cddfSDavid du Colombier Lock	joblock;
617dd7cddfSDavid du Colombier Job	*joblist;
627dd7cddfSDavid du Colombier 
637dd7cddfSDavid du Colombier struct {
647dd7cddfSDavid du Colombier 	Lock;
657dd7cddfSDavid du Colombier 	Mfile	*inuse;		/* active mfile's */
667dd7cddfSDavid du Colombier } mfalloc;
677dd7cddfSDavid du Colombier 
684f8f669cSDavid du Colombier Cfg	cfg;
696b0d5c8bSDavid du Colombier int	debug;
704f8f669cSDavid du Colombier uchar	ipaddr[IPaddrlen];	/* my ip address */
714f8f669cSDavid du Colombier int	maxage = Defmaxage;
724f8f669cSDavid du Colombier int	mfd[2];
734f8f669cSDavid du Colombier int	needrefresh;
747dd7cddfSDavid du Colombier ulong	now;
75a41547ffSDavid du Colombier vlong	nowns;
764f8f669cSDavid du Colombier int	sendnotifies;
777dd7cddfSDavid du Colombier int	testing;
787dd7cddfSDavid du Colombier char	*trace;
794f8f669cSDavid du Colombier int	traceactivity;
80dc5a79c1SDavid du Colombier char	*zonerefreshprogram;
813e12c5d1SDavid du Colombier 
824f8f669cSDavid du Colombier char	*logfile = "dns";	/* or "dns.test" */
836b0d5c8bSDavid du Colombier char	*dbfile;
846b0d5c8bSDavid du Colombier char	mntpt[Maxpath];
854f8f669cSDavid du Colombier 
86d9924332SDavid du Colombier int	addforwtarg(char *);
874f8f669cSDavid du Colombier int	fillreply(Mfile*, int);
884f8f669cSDavid du Colombier void	freejob(Job*);
894f8f669cSDavid du Colombier void	io(void);
904f8f669cSDavid du Colombier void	mountinit(char*, char*);
914f8f669cSDavid du Colombier Job*	newjob(void);
924f8f669cSDavid du Colombier void	rattach(Job*, Mfile*);
934f8f669cSDavid du Colombier void	rauth(Job*);
944f8f669cSDavid du Colombier void	rclunk(Job*, Mfile*);
954f8f669cSDavid du Colombier void	rcreate(Job*, Mfile*);
964f8f669cSDavid du Colombier void	rflush(Job*);
974f8f669cSDavid du Colombier void	ropen(Job*, Mfile*);
984f8f669cSDavid du Colombier void	rread(Job*, Mfile*);
994f8f669cSDavid du Colombier void	rremove(Job*, Mfile*);
1004f8f669cSDavid du Colombier void	rstat(Job*, Mfile*);
1014f8f669cSDavid du Colombier void	rversion(Job*);
1024f8f669cSDavid du Colombier char*	rwalk(Job*, Mfile*);
1034f8f669cSDavid du Colombier void	rwrite(Job*, Mfile*, Request*);
1044f8f669cSDavid du Colombier void	rwstat(Job*, Mfile*);
1054f8f669cSDavid du Colombier void	sendmsg(Job*, char*);
1064f8f669cSDavid du Colombier void	setext(char*, int, char*);
1076b0d5c8bSDavid du Colombier 
108d9924332SDavid du Colombier static char *lookupqueryold(Job*, Mfile*, Request*, char*, char*, int, int);
109d9924332SDavid du Colombier static char *lookupquerynew(Job*, Mfile*, Request*, char*, char*, int, int);
110d9924332SDavid du Colombier static char *respond(Job*, Mfile*, RR*, char*, int, int);
111d9924332SDavid du Colombier 
1127dd7cddfSDavid du Colombier void
usage(void)1137dd7cddfSDavid du Colombier usage(void)
1147dd7cddfSDavid du Colombier {
115a41547ffSDavid du Colombier 	fprint(2, "usage: %s [-FnorRst] [-a maxage] [-f ndb-file] [-N target] "
116410ea80bSDavid du Colombier 		"[-T forwip] [-x netmtpt] [-z refreshprog]\n", argv0);
1177dd7cddfSDavid du Colombier 	exits("usage");
1187dd7cddfSDavid du Colombier }
119219b2ee8SDavid du Colombier 
1203e12c5d1SDavid du Colombier void
justremount(char * service,char * mntpt)12127acba7cSDavid du Colombier justremount(char *service, char *mntpt)
12227acba7cSDavid du Colombier {
12327acba7cSDavid du Colombier 	int f;
12427acba7cSDavid du Colombier 
12527acba7cSDavid du Colombier 	f = open(service, ORDWR);
12627acba7cSDavid du Colombier 	if(f < 0)
12727acba7cSDavid du Colombier 		abort(); 	/* service */;
12827acba7cSDavid du Colombier 	while (mount(f, -1, mntpt, MAFTER, "") < 0) {
12927acba7cSDavid du Colombier 		dnslog("dns mount -a on %s failed: %r", mntpt);
13027acba7cSDavid du Colombier 		sleep(5000);
13127acba7cSDavid du Colombier 	}
13227acba7cSDavid du Colombier }
13327acba7cSDavid du Colombier 
13427acba7cSDavid du Colombier void
main(int argc,char * argv[])1353e12c5d1SDavid du Colombier main(int argc, char *argv[])
1363e12c5d1SDavid du Colombier {
137c73252aeSDavid du Colombier 	int kid, pid;
1384f8f669cSDavid du Colombier 	char servefile[Maxpath], ext[Maxpath];
13914cc0f53SDavid du Colombier 	Dir *dir;
140219b2ee8SDavid du Colombier 
1414f8f669cSDavid du Colombier 	setnetmtpt(mntpt, sizeof mntpt, nil);
1427dd7cddfSDavid du Colombier 	ext[0] = 0;
1433e12c5d1SDavid du Colombier 	ARGBEGIN{
1444f8f669cSDavid du Colombier 	case 'a':
1454f8f669cSDavid du Colombier 		maxage = atol(EARGF(usage()));
1464f8f669cSDavid du Colombier 		if (maxage <= 0)
1474f8f669cSDavid du Colombier 			maxage = Defmaxage;
1484f8f669cSDavid du Colombier 		break;
1493e12c5d1SDavid du Colombier 	case 'd':
1503e12c5d1SDavid du Colombier 		debug = 1;
15139734e7eSDavid du Colombier 		traceactivity = 1;
1523e12c5d1SDavid du Colombier 		break;
153219b2ee8SDavid du Colombier 	case 'f':
1544f8f669cSDavid du Colombier 		dbfile = EARGF(usage());
1557dd7cddfSDavid du Colombier 		break;
156a41547ffSDavid du Colombier 	case 'F':
157a41547ffSDavid du Colombier 		cfg.justforw = cfg.resolver = 1;
158a41547ffSDavid du Colombier 		break;
1594f8f669cSDavid du Colombier 	case 'n':
1604f8f669cSDavid du Colombier 		sendnotifies = 1;
1614f8f669cSDavid du Colombier 		break;
1624f8f669cSDavid du Colombier 	case 'N':
1634f8f669cSDavid du Colombier 		target = atol(EARGF(usage()));
164a41547ffSDavid du Colombier 		if (target < 1000)
165a41547ffSDavid du Colombier 			target = 1000;
1664f8f669cSDavid du Colombier 		break;
1674f8f669cSDavid du Colombier 	case 'o':
1684f8f669cSDavid du Colombier 		cfg.straddle = 1;	/* straddle inside & outside networks */
1694fafed5dSDavid du Colombier 		break;
1707dd7cddfSDavid du Colombier 	case 'r':
1714f8f669cSDavid du Colombier 		cfg.resolver = 1;
172219b2ee8SDavid du Colombier 		break;
173b85a8364SDavid du Colombier 	case 'R':
174b85a8364SDavid du Colombier 		norecursion = 1;
175b85a8364SDavid du Colombier 		break;
1763e12c5d1SDavid du Colombier 	case 's':
1774f8f669cSDavid du Colombier 		cfg.serve = 1;		/* serve network */
1784f8f669cSDavid du Colombier 		cfg.cachedb = 1;
1796b0d5c8bSDavid du Colombier 		break;
1807dd7cddfSDavid du Colombier 	case 't':
1817dd7cddfSDavid du Colombier 		testing = 1;
1823e12c5d1SDavid du Colombier 		break;
183410ea80bSDavid du Colombier 	case 'T':
184410ea80bSDavid du Colombier 		addforwtarg(EARGF(usage()));
185410ea80bSDavid du Colombier 		break;
1864f8f669cSDavid du Colombier 	case 'x':
1874f8f669cSDavid du Colombier 		setnetmtpt(mntpt, sizeof mntpt, EARGF(usage()));
1884f8f669cSDavid du Colombier 		setext(ext, sizeof ext, mntpt);
1896b0d5c8bSDavid du Colombier 		break;
1904f8f669cSDavid du Colombier 	case 'z':
1914f8f669cSDavid du Colombier 		zonerefreshprogram = EARGF(usage());
192dc5a79c1SDavid du Colombier 		break;
193345fff32SDavid du Colombier 	default:
194345fff32SDavid du Colombier 		usage();
195345fff32SDavid du Colombier 		break;
1963e12c5d1SDavid du Colombier 	}ARGEND
197345fff32SDavid du Colombier 	if(argc != 0)
198345fff32SDavid du Colombier 		usage();
1993e12c5d1SDavid du Colombier 
2004f8f669cSDavid du Colombier 	if(testing)
2014f8f669cSDavid du Colombier 		mainmem->flags |= POOL_NOREUSE | POOL_ANTAGONISM;
2026aaebd7dSDavid du Colombier 	mainmem->flags |= POOL_ANTAGONISM;
2037dd7cddfSDavid du Colombier 	rfork(RFREND|RFNOTEG);
2043e12c5d1SDavid du Colombier 
2054f8f669cSDavid du Colombier 	cfg.inside = (*mntpt == '\0' || strcmp(mntpt, "/net") == 0);
2064f8f669cSDavid du Colombier 
2077dd7cddfSDavid du Colombier 	/* start syslog before we fork */
2089a747e4fSDavid du Colombier 	fmtinstall('F', fcallfmt);
209219b2ee8SDavid du Colombier 	dninit();
21076783259SDavid du Colombier 	/* this really shouldn't be fatal */
2119a747e4fSDavid du Colombier 	if(myipaddr(ipaddr, mntpt) < 0)
2127dd7cddfSDavid du Colombier 		sysfatal("can't read my ip address");
213a41547ffSDavid du Colombier 	dnslog("starting %s%sdns %s%s%son %I's %s",
2144f8f669cSDavid du Colombier 		(cfg.straddle? "straddling ": ""),
2154f8f669cSDavid du Colombier 		(cfg.cachedb? "caching ": ""),
2164f8f669cSDavid du Colombier 		(cfg.serve?   "udp server ": ""),
217a41547ffSDavid du Colombier 		(cfg.justforw? "forwarding-only ": ""),
2184f8f669cSDavid du Colombier 		(cfg.resolver? "resolver ": ""), ipaddr, mntpt);
2197dd7cddfSDavid du Colombier 
2207dd7cddfSDavid du Colombier 	opendatabase();
221a41547ffSDavid du Colombier 	now = time(nil);		/* open time files before we fork */
222a41547ffSDavid du Colombier 	nowns = nsec();
2237dd7cddfSDavid du Colombier 
2244f8f669cSDavid du Colombier 	snprint(servefile, sizeof servefile, "#s/dns%s", ext);
22514cc0f53SDavid du Colombier 	dir = dirstat(servefile);
22614cc0f53SDavid du Colombier 	if (dir)
22714cc0f53SDavid du Colombier 		sysfatal("%s exists; another dns instance is running",
22814cc0f53SDavid du Colombier 			servefile);
22914cc0f53SDavid du Colombier 	free(dir);
23014cc0f53SDavid du Colombier 
23127acba7cSDavid du Colombier 	/* don't unmount here; could deadlock */
23227acba7cSDavid du Colombier //	while (unmount(servefile, mntpt) >= 0)
23327acba7cSDavid du Colombier //		;
234c73252aeSDavid du Colombier 	mountinit(servefile, mntpt);	/* forks, parent exits */
2357dd7cddfSDavid du Colombier 
2367dd7cddfSDavid du Colombier 	srand(now*getpid());
2377dd7cddfSDavid du Colombier 	db2cache(1);
23859f7772cSDavid du Colombier //	dnageallnever();
2397dd7cddfSDavid du Colombier 
2404f8f669cSDavid du Colombier 	if (cfg.straddle && !seerootns())
24159f7772cSDavid du Colombier 		dnslog("straddle server misconfigured; can't resolve root name servers");
242c73252aeSDavid du Colombier 	/*
243c73252aeSDavid du Colombier 	 * fork without sharing heap.
244c73252aeSDavid du Colombier 	 * parent waits around for child to die, then forks & restarts.
245c73252aeSDavid du Colombier 	 * child may spawn udp server, notify procs, etc.; when it gets too
24627acba7cSDavid du Colombier 	 * big or too old, it kills itself and any children.
24727acba7cSDavid du Colombier 	 *
24827acba7cSDavid du Colombier 	 * /srv/dns remains open and valid, but /net/dns was only mounted in
24927acba7cSDavid du Colombier 	 * a child's separate namespace from 9p service, to avoid a deadlock
25027acba7cSDavid du Colombier 	 * from serving our own namespace, so we must remount it upon restart,
25127acba7cSDavid du Colombier 	 * in a separate process and namespace.
252c73252aeSDavid du Colombier 	 */
253c73252aeSDavid du Colombier 	for (;;) {
25427acba7cSDavid du Colombier 		start = time(nil);
25527acba7cSDavid du Colombier 		/* don't unmount here; could deadlock */
25627acba7cSDavid du Colombier //		unmount(servefile, mntpt);
25727acba7cSDavid du Colombier 		kid = rfork(RFPROC|RFFDG|RFNOTEG|RFNAMEG);
258c73252aeSDavid du Colombier 		switch (kid) {
259c73252aeSDavid du Colombier 		case -1:
260c73252aeSDavid du Colombier 			sysfatal("fork failed: %r");
261c73252aeSDavid du Colombier 		case 0:
2624f8f669cSDavid du Colombier 			if(cfg.serve)
2637dd7cddfSDavid du Colombier 				dnudpserver(mntpt);
264dc5a79c1SDavid du Colombier 			if(sendnotifies)
265dc5a79c1SDavid du Colombier 				notifyproc();
26627acba7cSDavid du Colombier 			io();		/* serve 9p; return implies restart */
267c73252aeSDavid du Colombier 			_exits("restart");
26827acba7cSDavid du Colombier 		}
26927acba7cSDavid du Colombier 		sleep(1000);	/* wait for 9p service to start */
27027acba7cSDavid du Colombier 		justremount(servefile, mntpt);
271c73252aeSDavid du Colombier 		while ((pid = waitpid()) != kid && pid != -1)
272c73252aeSDavid du Colombier 			continue;
27327acba7cSDavid du Colombier 		dnslog("restarting");
274c73252aeSDavid du Colombier 	}
2753e12c5d1SDavid du Colombier }
2763e12c5d1SDavid du Colombier 
2777dd7cddfSDavid du Colombier /*
2784f8f669cSDavid du Colombier  *  if a mount point is specified, set the cs extension to be the mount point
2797dd7cddfSDavid du Colombier  *  with '_'s replacing '/'s
2807dd7cddfSDavid du Colombier  */
2813e12c5d1SDavid du Colombier void
setext(char * ext,int n,char * p)2827dd7cddfSDavid du Colombier setext(char *ext, int n, char *p)
2837dd7cddfSDavid du Colombier {
2847dd7cddfSDavid du Colombier 	int i, c;
2857dd7cddfSDavid du Colombier 
2867dd7cddfSDavid du Colombier 	n--;
2877dd7cddfSDavid du Colombier 	for(i = 0; i < n; i++){
2887dd7cddfSDavid du Colombier 		c = p[i];
2897dd7cddfSDavid du Colombier 		if(c == 0)
2907dd7cddfSDavid du Colombier 			break;
2917dd7cddfSDavid du Colombier 		if(c == '/')
2927dd7cddfSDavid du Colombier 			c = '_';
2937dd7cddfSDavid du Colombier 		ext[i] = c;
2947dd7cddfSDavid du Colombier 	}
2957dd7cddfSDavid du Colombier 	ext[i] = 0;
2967dd7cddfSDavid du Colombier }
2977dd7cddfSDavid du Colombier 
2987dd7cddfSDavid du Colombier void
mountinit(char * service,char * mntpt)2997dd7cddfSDavid du Colombier mountinit(char *service, char *mntpt)
3003e12c5d1SDavid du Colombier {
3013e12c5d1SDavid du Colombier 	int f;
3023e12c5d1SDavid du Colombier 	int p[2];
3033e12c5d1SDavid du Colombier 	char buf[32];
3043e12c5d1SDavid du Colombier 
3053e12c5d1SDavid du Colombier 	if(pipe(p) < 0)
3067dd7cddfSDavid du Colombier 		abort(); /* "pipe failed" */;
30727acba7cSDavid du Colombier 	switch(rfork(RFFDG|RFPROC)){
308c73252aeSDavid du Colombier 	case 0:			/* child: hang around and (re)start main proc */
309219b2ee8SDavid du Colombier 		close(p[1]);
3106aaebd7dSDavid du Colombier 		procsetname("%s restarter", mntpt);
31127acba7cSDavid du Colombier 		mfd[0] = mfd[1] = p[0];
3123e12c5d1SDavid du Colombier 		break;
3133e12c5d1SDavid du Colombier 	case -1:
3147dd7cddfSDavid du Colombier 		abort(); /* "fork failed\n" */;
315c73252aeSDavid du Colombier 	default:		/* parent: make /srv/dns, mount it, exit */
316219b2ee8SDavid du Colombier 		close(p[0]);
317219b2ee8SDavid du Colombier 
3183e12c5d1SDavid du Colombier 		/*
3193e12c5d1SDavid du Colombier 		 *  make a /srv/dns
3203e12c5d1SDavid du Colombier 		 */
3213e12c5d1SDavid du Colombier 		f = create(service, 1, 0666);
3223e12c5d1SDavid du Colombier 		if(f < 0)
3237dd7cddfSDavid du Colombier 			abort(); /* service */;
3244f8f669cSDavid du Colombier 		snprint(buf, sizeof buf, "%d", p[1]);
3253e12c5d1SDavid du Colombier 		if(write(f, buf, strlen(buf)) != strlen(buf))
3267dd7cddfSDavid du Colombier 			abort(); /* "write %s", service */;
3273e12c5d1SDavid du Colombier 		close(f);
3283e12c5d1SDavid du Colombier 
3293e12c5d1SDavid du Colombier 		/*
3303e12c5d1SDavid du Colombier 		 *  put ourselves into the file system
33127acba7cSDavid du Colombier 		 *  it's too soon; we need 9p service running.
3323e12c5d1SDavid du Colombier 		 */
33327acba7cSDavid du Colombier //		if(mount(p[1], -1, mntpt, MAFTER, "") < 0)
33427acba7cSDavid du Colombier //			dnslog("dns mount -a on %s failed: %r", mntpt);
33527acba7cSDavid du Colombier 		close(p[1]);
336219b2ee8SDavid du Colombier 		_exits(0);
3373e12c5d1SDavid du Colombier 	}
3383e12c5d1SDavid du Colombier }
3393e12c5d1SDavid du Colombier 
3403e12c5d1SDavid du Colombier Mfile*
newfid(int fid,int needunused)3417dd7cddfSDavid du Colombier newfid(int fid, int needunused)
3423e12c5d1SDavid du Colombier {
3433e12c5d1SDavid du Colombier 	Mfile *mf;
3443e12c5d1SDavid du Colombier 
3457dd7cddfSDavid du Colombier 	lock(&mfalloc);
3464f8f669cSDavid du Colombier 	for(mf = mfalloc.inuse; mf != nil; mf = mf->next)
3477dd7cddfSDavid du Colombier 		if(mf->fid == fid){
3487dd7cddfSDavid du Colombier 			unlock(&mfalloc);
3497dd7cddfSDavid du Colombier 			if(needunused)
3507dd7cddfSDavid du Colombier 				return nil;
3513e12c5d1SDavid du Colombier 			return mf;
3523e12c5d1SDavid du Colombier 		}
3539a747e4fSDavid du Colombier 	mf = emalloc(sizeof(*mf));
3543e12c5d1SDavid du Colombier 	mf->fid = fid;
355c73252aeSDavid du Colombier 	mf->user = estrdup("dummy");
356530fef66SDavid du Colombier 	mf->next = mfalloc.inuse;
3577dd7cddfSDavid du Colombier 	mfalloc.inuse = mf;
3587dd7cddfSDavid du Colombier 	unlock(&mfalloc);
3593e12c5d1SDavid du Colombier 	return mf;
3603e12c5d1SDavid du Colombier }
3613e12c5d1SDavid du Colombier 
3623e12c5d1SDavid du Colombier void
freefid(Mfile * mf)3637dd7cddfSDavid du Colombier freefid(Mfile *mf)
3647dd7cddfSDavid du Colombier {
3657dd7cddfSDavid du Colombier 	Mfile **l;
3667dd7cddfSDavid du Colombier 
3677dd7cddfSDavid du Colombier 	lock(&mfalloc);
3684f8f669cSDavid du Colombier 	for(l = &mfalloc.inuse; *l != nil; l = &(*l)->next)
3697dd7cddfSDavid du Colombier 		if(*l == mf){
3707dd7cddfSDavid du Colombier 			*l = mf->next;
3716b0d5c8bSDavid du Colombier 			if(mf->user)
3729a747e4fSDavid du Colombier 				free(mf->user);
3734f8f669cSDavid du Colombier 			memset(mf, 0, sizeof *mf);	/* cause trouble */
3747dd7cddfSDavid du Colombier 			free(mf);
3757dd7cddfSDavid du Colombier 			unlock(&mfalloc);
3767dd7cddfSDavid du Colombier 			return;
3777dd7cddfSDavid du Colombier 		}
378530fef66SDavid du Colombier 	unlock(&mfalloc);
3797dd7cddfSDavid du Colombier 	sysfatal("freeing unused fid");
3807dd7cddfSDavid du Colombier }
3817dd7cddfSDavid du Colombier 
3827dd7cddfSDavid du Colombier Mfile*
copyfid(Mfile * mf,int fid)3837dd7cddfSDavid du Colombier copyfid(Mfile *mf, int fid)
3847dd7cddfSDavid du Colombier {
3857dd7cddfSDavid du Colombier 	Mfile *nmf;
3867dd7cddfSDavid du Colombier 
3877dd7cddfSDavid du Colombier 	nmf = newfid(fid, 1);
3887dd7cddfSDavid du Colombier 	if(nmf == nil)
3897dd7cddfSDavid du Colombier 		return nil;
3907dd7cddfSDavid du Colombier 	nmf->fid = fid;
391530fef66SDavid du Colombier 	free(nmf->user);			/* estrdup("dummy") */
3929a747e4fSDavid du Colombier 	nmf->user = estrdup(mf->user);
3939a747e4fSDavid du Colombier 	nmf->qid.type = mf->qid.type;
3947dd7cddfSDavid du Colombier 	nmf->qid.path = mf->qid.path;
3957dd7cddfSDavid du Colombier 	nmf->qid.vers = vers++;
3967dd7cddfSDavid du Colombier 	return nmf;
3977dd7cddfSDavid du Colombier }
3987dd7cddfSDavid du Colombier 
3997dd7cddfSDavid du Colombier Job*
newjob(void)4007dd7cddfSDavid du Colombier newjob(void)
4017dd7cddfSDavid du Colombier {
4027dd7cddfSDavid du Colombier 	Job *job;
4037dd7cddfSDavid du Colombier 
4044f8f669cSDavid du Colombier 	job = emalloc(sizeof *job);
4057dd7cddfSDavid du Colombier 	lock(&joblock);
4067dd7cddfSDavid du Colombier 	job->next = joblist;
4077dd7cddfSDavid du Colombier 	joblist = job;
4087dd7cddfSDavid du Colombier 	job->request.tag = -1;
4097dd7cddfSDavid du Colombier 	unlock(&joblock);
4107dd7cddfSDavid du Colombier 	return job;
4117dd7cddfSDavid du Colombier }
4127dd7cddfSDavid du Colombier 
4137dd7cddfSDavid du Colombier void
freejob(Job * job)4147dd7cddfSDavid du Colombier freejob(Job *job)
4157dd7cddfSDavid du Colombier {
4167dd7cddfSDavid du Colombier 	Job **l;
4177dd7cddfSDavid du Colombier 
4187dd7cddfSDavid du Colombier 	lock(&joblock);
4194f8f669cSDavid du Colombier 	for(l = &joblist; *l; l = &(*l)->next)
4204f8f669cSDavid du Colombier 		if(*l == job){
4217dd7cddfSDavid du Colombier 			*l = job->next;
4224f8f669cSDavid du Colombier 			memset(job, 0, sizeof *job);	/* cause trouble */
4237dd7cddfSDavid du Colombier 			free(job);
4247dd7cddfSDavid du Colombier 			break;
4257dd7cddfSDavid du Colombier 		}
4267dd7cddfSDavid du Colombier 	unlock(&joblock);
4277dd7cddfSDavid du Colombier }
4287dd7cddfSDavid du Colombier 
4297dd7cddfSDavid du Colombier void
flushjob(int tag)4307dd7cddfSDavid du Colombier flushjob(int tag)
4317dd7cddfSDavid du Colombier {
4327dd7cddfSDavid du Colombier 	Job *job;
4337dd7cddfSDavid du Colombier 
4347dd7cddfSDavid du Colombier 	lock(&joblock);
4354f8f669cSDavid du Colombier 	for(job = joblist; job; job = job->next)
4367dd7cddfSDavid du Colombier 		if(job->request.tag == tag && job->request.type != Tflush){
4377dd7cddfSDavid du Colombier 			job->flushed = 1;
4387dd7cddfSDavid du Colombier 			break;
4397dd7cddfSDavid du Colombier 		}
4407dd7cddfSDavid du Colombier 	unlock(&joblock);
4417dd7cddfSDavid du Colombier }
4427dd7cddfSDavid du Colombier 
4437dd7cddfSDavid du Colombier void
io(void)4443e12c5d1SDavid du Colombier io(void)
4453e12c5d1SDavid du Colombier {
446225077b0SDavid du Colombier 	volatile long n;
447225077b0SDavid du Colombier 	volatile uchar mdata[IOHDRSZ + Maxfdata];
448225077b0SDavid du Colombier 	Job *volatile job;
449225077b0SDavid du Colombier 	Mfile *volatile mf;
450225077b0SDavid du Colombier 	volatile Request req;
4513e12c5d1SDavid du Colombier 
4524f8f669cSDavid du Colombier 	memset(&req, 0, sizeof req);
4533e12c5d1SDavid du Colombier 	/*
4543e12c5d1SDavid du Colombier 	 *  a slave process is sometimes forked to wait for replies from other
4553e12c5d1SDavid du Colombier 	 *  servers.  The master process returns immediately via a longjmp
456219b2ee8SDavid du Colombier 	 *  through 'mret'.
4573e12c5d1SDavid du Colombier 	 */
4587dd7cddfSDavid du Colombier 	if(setjmp(req.mret))
459b4b9fc2fSDavid du Colombier 		putactivity(0);
4603e12c5d1SDavid du Colombier 	req.isslave = 0;
461c73252aeSDavid du Colombier 	stop = 0;
462c73252aeSDavid du Colombier 	while(!stop){
463f2714ceaSDavid du Colombier 		procsetname("%d %s/dns Twrites of %d 9p rpcs read; %d alarms",
464f2714ceaSDavid du Colombier 			stats.qrecvd9p, mntpt, stats.qrecvd9prpc, stats.alarms);
4659a747e4fSDavid du Colombier 		n = read9pmsg(mfd[0], mdata, sizeof mdata);
4667dd7cddfSDavid du Colombier 		if(n<=0){
467adb31a62SDavid du Colombier 			dnslog("error reading 9P from %s: %r", mntpt);
468e02f7f02SDavid du Colombier 			sleep(2000);	/* don't thrash after read error */
4696aaebd7dSDavid du Colombier 			return;
4707dd7cddfSDavid du Colombier 		}
4714f8f669cSDavid du Colombier 
4726aaebd7dSDavid du Colombier 		stats.qrecvd9prpc++;
4737dd7cddfSDavid du Colombier 		job = newjob();
4749a747e4fSDavid du Colombier 		if(convM2S(mdata, n, &job->request) != n){
4757dd7cddfSDavid du Colombier 			freejob(job);
4767dd7cddfSDavid du Colombier 			continue;
4777dd7cddfSDavid du Colombier 		}
4787dd7cddfSDavid du Colombier 		mf = newfid(job->request.fid, 0);
479219b2ee8SDavid du Colombier 		if(debug)
4804f8f669cSDavid du Colombier 			dnslog("%F", &job->request);
4817dd7cddfSDavid du Colombier 
482b4b9fc2fSDavid du Colombier 		getactivity(&req, 0);
483e02f7f02SDavid du Colombier 		req.aborttime = timems() + Maxreqtm;
484f46c709fSDavid du Colombier 		req.from = "9p";
4857dd7cddfSDavid du Colombier 
4867dd7cddfSDavid du Colombier 		switch(job->request.type){
4873e12c5d1SDavid du Colombier 		default:
4884f8f669cSDavid du Colombier 			warning("unknown request type %d", job->request.type);
4893e12c5d1SDavid du Colombier 			break;
4909a747e4fSDavid du Colombier 		case Tversion:
4919a747e4fSDavid du Colombier 			rversion(job);
4923e12c5d1SDavid du Colombier 			break;
4939a747e4fSDavid du Colombier 		case Tauth:
4949a747e4fSDavid du Colombier 			rauth(job);
4953e12c5d1SDavid du Colombier 			break;
4963e12c5d1SDavid du Colombier 		case Tflush:
4977dd7cddfSDavid du Colombier 			rflush(job);
4983e12c5d1SDavid du Colombier 			break;
4993e12c5d1SDavid du Colombier 		case Tattach:
5007dd7cddfSDavid du Colombier 			rattach(job, mf);
5013e12c5d1SDavid du Colombier 			break;
5023e12c5d1SDavid du Colombier 		case Twalk:
5037dd7cddfSDavid du Colombier 			rwalk(job, mf);
5043e12c5d1SDavid du Colombier 			break;
5053e12c5d1SDavid du Colombier 		case Topen:
5067dd7cddfSDavid du Colombier 			ropen(job, mf);
5073e12c5d1SDavid du Colombier 			break;
5083e12c5d1SDavid du Colombier 		case Tcreate:
5097dd7cddfSDavid du Colombier 			rcreate(job, mf);
5103e12c5d1SDavid du Colombier 			break;
5113e12c5d1SDavid du Colombier 		case Tread:
5127dd7cddfSDavid du Colombier 			rread(job, mf);
5133e12c5d1SDavid du Colombier 			break;
5143e12c5d1SDavid du Colombier 		case Twrite:
515adb31a62SDavid du Colombier 			/* &req is handed to dnresolve() */
5167dd7cddfSDavid du Colombier 			rwrite(job, mf, &req);
5173e12c5d1SDavid du Colombier 			break;
5183e12c5d1SDavid du Colombier 		case Tclunk:
5197dd7cddfSDavid du Colombier 			rclunk(job, mf);
5203e12c5d1SDavid du Colombier 			break;
5213e12c5d1SDavid du Colombier 		case Tremove:
5227dd7cddfSDavid du Colombier 			rremove(job, mf);
5233e12c5d1SDavid du Colombier 			break;
5243e12c5d1SDavid du Colombier 		case Tstat:
5257dd7cddfSDavid du Colombier 			rstat(job, mf);
5263e12c5d1SDavid du Colombier 			break;
5273e12c5d1SDavid du Colombier 		case Twstat:
5287dd7cddfSDavid du Colombier 			rwstat(job, mf);
5293e12c5d1SDavid du Colombier 			break;
5303e12c5d1SDavid du Colombier 		}
5317dd7cddfSDavid du Colombier 
5327dd7cddfSDavid du Colombier 		freejob(job);
5337dd7cddfSDavid du Colombier 
5343e12c5d1SDavid du Colombier 		/*
5353e12c5d1SDavid du Colombier 		 *  slave processes die after replying
5363e12c5d1SDavid du Colombier 		 */
5377dd7cddfSDavid du Colombier 		if(req.isslave){
538b4b9fc2fSDavid du Colombier 			putactivity(0);
5393e12c5d1SDavid du Colombier 			_exits(0);
5407dd7cddfSDavid du Colombier 		}
5417dd7cddfSDavid du Colombier 
542b4b9fc2fSDavid du Colombier 		putactivity(0);
5437dd7cddfSDavid du Colombier 	}
544c73252aeSDavid du Colombier 	/* kill any udp server, notifier, etc. processes */
545c73252aeSDavid du Colombier 	postnote(PNGROUP, getpid(), "die");
546c73252aeSDavid du Colombier 	sleep(1000);
5473e12c5d1SDavid du Colombier }
5483e12c5d1SDavid du Colombier 
5493e12c5d1SDavid du Colombier void
rversion(Job * job)5509a747e4fSDavid du Colombier rversion(Job *job)
551219b2ee8SDavid du Colombier {
5529a747e4fSDavid du Colombier 	if(job->request.msize > IOHDRSZ + Maxfdata)
5539a747e4fSDavid du Colombier 		job->reply.msize = IOHDRSZ + Maxfdata;
5549a747e4fSDavid du Colombier 	else
5559a747e4fSDavid du Colombier 		job->reply.msize = job->request.msize;
5569a747e4fSDavid du Colombier 	if(strncmp(job->request.version, "9P2000", 6) != 0)
5579a747e4fSDavid du Colombier 		sendmsg(job, "unknown 9P version");
5589a747e4fSDavid du Colombier 	else{
5599a747e4fSDavid du Colombier 		job->reply.version = "9P2000";
5607dd7cddfSDavid du Colombier 		sendmsg(job, 0);
561219b2ee8SDavid du Colombier 	}
5629a747e4fSDavid du Colombier }
563219b2ee8SDavid du Colombier 
564219b2ee8SDavid du Colombier void
rauth(Job * job)5659a747e4fSDavid du Colombier rauth(Job *job)
5663e12c5d1SDavid du Colombier {
5673ff48bf5SDavid du Colombier 	sendmsg(job, "dns: authentication not required");
5687dd7cddfSDavid du Colombier }
5697dd7cddfSDavid du Colombier 
5709a747e4fSDavid du Colombier /*
5719a747e4fSDavid du Colombier  *  don't flush till all the slaves are done
5729a747e4fSDavid du Colombier  */
5737dd7cddfSDavid du Colombier void
rflush(Job * job)5747dd7cddfSDavid du Colombier rflush(Job *job)
5757dd7cddfSDavid du Colombier {
5767dd7cddfSDavid du Colombier 	flushjob(job->request.oldtag);
5777dd7cddfSDavid du Colombier 	sendmsg(job, 0);
5783e12c5d1SDavid du Colombier }
5793e12c5d1SDavid du Colombier 
5803e12c5d1SDavid du Colombier void
rattach(Job * job,Mfile * mf)5817dd7cddfSDavid du Colombier rattach(Job *job, Mfile *mf)
5823e12c5d1SDavid du Colombier {
5839a747e4fSDavid du Colombier 	if(mf->user != nil)
5849a747e4fSDavid du Colombier 		free(mf->user);
5859a747e4fSDavid du Colombier 	mf->user = estrdup(job->request.uname);
5863e12c5d1SDavid du Colombier 	mf->qid.vers = vers++;
5879a747e4fSDavid du Colombier 	mf->qid.type = QTDIR;
5889a747e4fSDavid du Colombier 	mf->qid.path = 0LL;
5897dd7cddfSDavid du Colombier 	job->reply.qid = mf->qid;
5907dd7cddfSDavid du Colombier 	sendmsg(job, 0);
5913e12c5d1SDavid du Colombier }
5923e12c5d1SDavid du Colombier 
5933e12c5d1SDavid du Colombier char*
rwalk(Job * job,Mfile * mf)5947dd7cddfSDavid du Colombier rwalk(Job *job, Mfile *mf)
5953e12c5d1SDavid du Colombier {
5964f8f669cSDavid du Colombier 	int i, nelems;
5973e12c5d1SDavid du Colombier 	char *err;
5989a747e4fSDavid du Colombier 	char **elems;
5999a747e4fSDavid du Colombier 	Mfile *nmf;
6009a747e4fSDavid du Colombier 	Qid qid;
6013e12c5d1SDavid du Colombier 
6023e12c5d1SDavid du Colombier 	err = 0;
6039a747e4fSDavid du Colombier 	nmf = nil;
6049a747e4fSDavid du Colombier 	elems  = job->request.wname;
6059a747e4fSDavid du Colombier 	nelems = job->request.nwname;
6069a747e4fSDavid du Colombier 	job->reply.nwqid = 0;
6079a747e4fSDavid du Colombier 
6089a747e4fSDavid du Colombier 	if(job->request.newfid != job->request.fid){
6099a747e4fSDavid du Colombier 		/* clone fid */
6109a747e4fSDavid du Colombier 		nmf = copyfid(mf, job->request.newfid);
6119a747e4fSDavid du Colombier 		if(nmf == nil){
6129a747e4fSDavid du Colombier 			err = "clone bad newfid";
6139a747e4fSDavid du Colombier 			goto send;
6149a747e4fSDavid du Colombier 		}
6159a747e4fSDavid du Colombier 		mf = nmf;
6169a747e4fSDavid du Colombier 	}
6179a747e4fSDavid du Colombier 	/* else nmf will be nil */
6189a747e4fSDavid du Colombier 
6199a747e4fSDavid du Colombier 	qid = mf->qid;
6204f8f669cSDavid du Colombier 	if(nelems > 0)
6219a747e4fSDavid du Colombier 		/* walk fid */
6229a747e4fSDavid du Colombier 		for(i=0; i<nelems && i<MAXWELEM; i++){
6239a747e4fSDavid du Colombier 			if((qid.type & QTDIR) == 0){
6243e12c5d1SDavid du Colombier 				err = "not a directory";
6259a747e4fSDavid du Colombier 				break;
6263e12c5d1SDavid du Colombier 			}
6274f8f669cSDavid du Colombier 			if (strcmp(elems[i], "..") == 0 ||
6284f8f669cSDavid du Colombier 			    strcmp(elems[i], ".") == 0){
6299a747e4fSDavid du Colombier 				qid.type = QTDIR;
6309a747e4fSDavid du Colombier 				qid.path = Qdir;
6319a747e4fSDavid du Colombier Found:
6329a747e4fSDavid du Colombier 				job->reply.wqid[i] = qid;
6339a747e4fSDavid du Colombier 				job->reply.nwqid++;
6349a747e4fSDavid du Colombier 				continue;
6353e12c5d1SDavid du Colombier 			}
6369a747e4fSDavid du Colombier 			if(strcmp(elems[i], "dns") == 0){
6379a747e4fSDavid du Colombier 				qid.type = QTFILE;
6389a747e4fSDavid du Colombier 				qid.path = Qdns;
6399a747e4fSDavid du Colombier 				goto Found;
6403e12c5d1SDavid du Colombier 			}
6419a747e4fSDavid du Colombier 			err = "file does not exist";
6429a747e4fSDavid du Colombier 			break;
6439a747e4fSDavid du Colombier 		}
6449a747e4fSDavid du Colombier 
6453e12c5d1SDavid du Colombier send:
6469a747e4fSDavid du Colombier 	if(nmf != nil && (err!=nil || job->reply.nwqid<nelems))
6479a747e4fSDavid du Colombier 		freefid(nmf);
6489a747e4fSDavid du Colombier 	if(err == nil)
6499a747e4fSDavid du Colombier 		mf->qid = qid;
6507dd7cddfSDavid du Colombier 	sendmsg(job, err);
6513e12c5d1SDavid du Colombier 	return err;
6523e12c5d1SDavid du Colombier }
6533e12c5d1SDavid du Colombier 
6543e12c5d1SDavid du Colombier void
ropen(Job * job,Mfile * mf)6557dd7cddfSDavid du Colombier ropen(Job *job, Mfile *mf)
6563e12c5d1SDavid du Colombier {
6573e12c5d1SDavid du Colombier 	int mode;
6583e12c5d1SDavid du Colombier 	char *err;
6593e12c5d1SDavid du Colombier 
6603e12c5d1SDavid du Colombier 	err = 0;
6617dd7cddfSDavid du Colombier 	mode = job->request.mode;
6624f8f669cSDavid du Colombier 	if(mf->qid.type & QTDIR)
6633e12c5d1SDavid du Colombier 		if(mode)
6643e12c5d1SDavid du Colombier 			err = "permission denied";
6657dd7cddfSDavid du Colombier 	job->reply.qid = mf->qid;
6669a747e4fSDavid du Colombier 	job->reply.iounit = 0;
6677dd7cddfSDavid du Colombier 	sendmsg(job, err);
6683e12c5d1SDavid du Colombier }
6693e12c5d1SDavid du Colombier 
6703e12c5d1SDavid du Colombier void
rcreate(Job * job,Mfile * mf)6717dd7cddfSDavid du Colombier rcreate(Job *job, Mfile *mf)
6723e12c5d1SDavid du Colombier {
6733e12c5d1SDavid du Colombier 	USED(mf);
6747dd7cddfSDavid du Colombier 	sendmsg(job, "creation permission denied");
6753e12c5d1SDavid du Colombier }
6763e12c5d1SDavid du Colombier 
6773e12c5d1SDavid du Colombier void
rread(Job * job,Mfile * mf)6787dd7cddfSDavid du Colombier rread(Job *job, Mfile *mf)
6793e12c5d1SDavid du Colombier {
6804f8f669cSDavid du Colombier 	int i, n;
6816b0d5c8bSDavid du Colombier 	long clock;
6824f8f669cSDavid du Colombier 	ulong cnt;
6834f8f669cSDavid du Colombier 	vlong off;
6844f8f669cSDavid du Colombier 	char *err;
685254fe3d3SDavid du Colombier 	uchar buf[Maxfdata];
6864f8f669cSDavid du Colombier 	Dir dir;
6873e12c5d1SDavid du Colombier 
6883e12c5d1SDavid du Colombier 	n = 0;
6894f8f669cSDavid du Colombier 	err = nil;
6907dd7cddfSDavid du Colombier 	off = job->request.offset;
6917dd7cddfSDavid du Colombier 	cnt = job->request.count;
6924f8f669cSDavid du Colombier 	*buf = '\0';
6934f8f669cSDavid du Colombier 	job->reply.data = (char*)buf;
6949a747e4fSDavid du Colombier 	if(mf->qid.type & QTDIR){
6954f8f669cSDavid du Colombier 		clock = time(nil);
6963e12c5d1SDavid du Colombier 		if(off == 0){
6976aaebd7dSDavid du Colombier 			memset(&dir, 0, sizeof dir);
6989a747e4fSDavid du Colombier 			dir.name = "dns";
6999a747e4fSDavid du Colombier 			dir.qid.type = QTFILE;
7003e12c5d1SDavid du Colombier 			dir.qid.vers = vers;
7013e12c5d1SDavid du Colombier 			dir.qid.path = Qdns;
7023e12c5d1SDavid du Colombier 			dir.mode = 0666;
7033e12c5d1SDavid du Colombier 			dir.length = 0;
7044f8f669cSDavid du Colombier 			dir.uid = dir.gid = dir.muid = mf->user;
7054f8f669cSDavid du Colombier 			dir.atime = dir.mtime = clock;		/* wrong */
7069a747e4fSDavid du Colombier 			n = convD2M(&dir, buf, sizeof buf);
7073e12c5d1SDavid du Colombier 		}
7084f8f669cSDavid du Colombier 	} else if (off < 0)
7094f8f669cSDavid du Colombier 		err = "negative read offset";
7104f8f669cSDavid du Colombier 	else {
7114f8f669cSDavid du Colombier 		/* first offset will always be zero */
7127dd7cddfSDavid du Colombier 		for(i = 1; i <= mf->nrr; i++)
7137dd7cddfSDavid du Colombier 			if(mf->rr[i] > off)
7143e12c5d1SDavid du Colombier 				break;
7154f8f669cSDavid du Colombier 		if(i <= mf->nrr) {
7167dd7cddfSDavid du Colombier 			if(off + cnt > mf->rr[i])
7177dd7cddfSDavid du Colombier 				n = mf->rr[i] - off;
7187dd7cddfSDavid du Colombier 			else
7197dd7cddfSDavid du Colombier 				n = cnt;
7204f8f669cSDavid du Colombier 			assert(n >= 0);
7217dd7cddfSDavid du Colombier 			job->reply.data = mf->reply + off;
7223e12c5d1SDavid du Colombier 		}
7234f8f669cSDavid du Colombier 	}
7247dd7cddfSDavid du Colombier 	job->reply.count = n;
7257dd7cddfSDavid du Colombier 	sendmsg(job, err);
7263e12c5d1SDavid du Colombier }
7273e12c5d1SDavid du Colombier 
7283e12c5d1SDavid du Colombier void
rwrite(Job * job,Mfile * mf,Request * req)7297dd7cddfSDavid du Colombier rwrite(Job *job, Mfile *mf, Request *req)
7303e12c5d1SDavid du Colombier {
731d9924332SDavid du Colombier 	int rooted, wantsav, send;
7324f8f669cSDavid du Colombier 	ulong cnt;
7337dd7cddfSDavid du Colombier 	char *err, *p, *atype;
734d9924332SDavid du Colombier 	char errbuf[ERRMAX];
7353e12c5d1SDavid du Colombier 
7364f8f669cSDavid du Colombier 	err = nil;
7377dd7cddfSDavid du Colombier 	cnt = job->request.count;
738d9924332SDavid du Colombier 	send = 1;
739d9924332SDavid du Colombier 	if(mf->qid.type & QTDIR)
7403e12c5d1SDavid du Colombier 		err = "can't write directory";
741d9924332SDavid du Colombier 	else if (job->request.offset != 0)
7424f8f669cSDavid du Colombier 		err = "writing at non-zero offset";
743d9924332SDavid du Colombier 	else if(cnt >= Maxrequest)
7443e12c5d1SDavid du Colombier 		err = "request too long";
745d9924332SDavid du Colombier 	else
746d9924332SDavid du Colombier 		send = 0;
747d9924332SDavid du Colombier 	if (send)
7483e12c5d1SDavid du Colombier 		goto send;
749d9924332SDavid du Colombier 
7507dd7cddfSDavid du Colombier 	job->request.data[cnt] = 0;
7517dd7cddfSDavid du Colombier 	if(cnt > 0 && job->request.data[cnt-1] == '\n')
7527dd7cddfSDavid du Colombier 		job->request.data[cnt-1] = 0;
7533e12c5d1SDavid du Colombier 
7543e12c5d1SDavid du Colombier 	/*
7557dd7cddfSDavid du Colombier 	 *  special commands
756219b2ee8SDavid du Colombier 	 */
757410ea80bSDavid du Colombier //	dnslog("rwrite got: %s", job->request.data);
758d9924332SDavid du Colombier 	send = 1;
759d9924332SDavid du Colombier 	if(strcmp(job->request.data, "age")==0){
76021abd8f2SDavid du Colombier 		dnslog("dump, age & dump forced");
76121abd8f2SDavid du Colombier 		dndump("/lib/ndb/dnsdump1");
76221abd8f2SDavid du Colombier 		dnforceage();
76321abd8f2SDavid du Colombier 		dndump("/lib/ndb/dnsdump2");
764d9924332SDavid du Colombier 	} else if(strcmp(job->request.data, "debug")==0)
765d9924332SDavid du Colombier 		debug ^= 1;
766d9924332SDavid du Colombier 	else if(strcmp(job->request.data, "dump")==0)
767d9924332SDavid du Colombier 		dndump("/lib/ndb/dnsdump");
768d9924332SDavid du Colombier 	else if(strcmp(job->request.data, "poolcheck")==0)
769d9924332SDavid du Colombier 		poolcheck(mainmem);
770d9924332SDavid du Colombier 	else if(strcmp(job->request.data, "refresh")==0)
771d9924332SDavid du Colombier 		needrefresh = 1;
772d9924332SDavid du Colombier 	else if(strcmp(job->request.data, "restart")==0)
773d9924332SDavid du Colombier 		stop = 1;
774d9924332SDavid du Colombier 	else if(strcmp(job->request.data, "stats")==0)
775d9924332SDavid du Colombier 		dnstats("/lib/ndb/dnsstats");
776d9924332SDavid du Colombier 	else if(strncmp(job->request.data, "target ", 7)==0){
777d9924332SDavid du Colombier 		target = atol(job->request.data + 7);
778d9924332SDavid du Colombier 		dnslog("target set to %ld", target);
779d9924332SDavid du Colombier 	} else
780d9924332SDavid du Colombier 		send = 0;
781d9924332SDavid du Colombier 	if (send)
78221abd8f2SDavid du Colombier 		goto send;
783219b2ee8SDavid du Colombier 
784219b2ee8SDavid du Colombier 	/*
7857dd7cddfSDavid du Colombier 	 *  kill previous reply
7867dd7cddfSDavid du Colombier 	 */
7877dd7cddfSDavid du Colombier 	mf->nrr = 0;
7887dd7cddfSDavid du Colombier 	mf->rr[0] = 0;
7897dd7cddfSDavid du Colombier 
7907dd7cddfSDavid du Colombier 	/*
7913e12c5d1SDavid du Colombier 	 *  break up request (into a name and a type)
7923e12c5d1SDavid du Colombier 	 */
7937dd7cddfSDavid du Colombier 	atype = strchr(job->request.data, ' ');
7943e12c5d1SDavid du Colombier 	if(atype == 0){
795d9924332SDavid du Colombier 		snprint(errbuf, sizeof errbuf, "illegal request %s",
796d9924332SDavid du Colombier 			job->request.data);
797d9924332SDavid du Colombier 		err = errbuf;
7983e12c5d1SDavid du Colombier 		goto send;
7993e12c5d1SDavid du Colombier 	} else
8003e12c5d1SDavid du Colombier 		*atype++ = 0;
8013e12c5d1SDavid du Colombier 
8027dd7cddfSDavid du Colombier 	/*
8037dd7cddfSDavid du Colombier 	 *  tracing request
8047dd7cddfSDavid du Colombier 	 */
8057dd7cddfSDavid du Colombier 	if(strcmp(atype, "trace") == 0){
8067dd7cddfSDavid du Colombier 		if(trace)
8077dd7cddfSDavid du Colombier 			free(trace);
8087dd7cddfSDavid du Colombier 		if(*job->request.data)
8099a747e4fSDavid du Colombier 			trace = estrdup(job->request.data);
8107dd7cddfSDavid du Colombier 		else
8117dd7cddfSDavid du Colombier 			trace = 0;
8127dd7cddfSDavid du Colombier 		goto send;
8137dd7cddfSDavid du Colombier 	}
8147dd7cddfSDavid du Colombier 
8154f8f669cSDavid du Colombier 	/* normal request: domain [type] */
816a41547ffSDavid du Colombier 	stats.qrecvd9p++;
8173e12c5d1SDavid du Colombier 	mf->type = rrtype(atype);
8183e12c5d1SDavid du Colombier 	if(mf->type < 0){
819d9924332SDavid du Colombier 		snprint(errbuf, sizeof errbuf, "unknown type %s", atype);
820d9924332SDavid du Colombier 		err = errbuf;
8213e12c5d1SDavid du Colombier 		goto send;
8223e12c5d1SDavid du Colombier 	}
8233e12c5d1SDavid du Colombier 
8247dd7cddfSDavid du Colombier 	p = atype - 2;
8257dd7cddfSDavid du Colombier 	if(p >= job->request.data && *p == '.'){
8267dd7cddfSDavid du Colombier 		rooted = 1;
8277dd7cddfSDavid du Colombier 		*p = 0;
8287dd7cddfSDavid du Colombier 	} else
8297dd7cddfSDavid du Colombier 		rooted = 0;
8303e12c5d1SDavid du Colombier 
8317dd7cddfSDavid du Colombier 	p = job->request.data;
8327dd7cddfSDavid du Colombier 	if(*p == '!'){
8337dd7cddfSDavid du Colombier 		wantsav = 1;
8347dd7cddfSDavid du Colombier 		p++;
8357dd7cddfSDavid du Colombier 	} else
8367dd7cddfSDavid du Colombier 		wantsav = 0;
8374f8f669cSDavid du Colombier 
838d9924332SDavid du Colombier 	err = lookupqueryold(job, mf, req, errbuf, p, wantsav, rooted);
839d9924332SDavid du Colombier send:
8409a747e4fSDavid du Colombier 	dncheck(0, 1);
841d9924332SDavid du Colombier 	job->reply.count = cnt;
842d9924332SDavid du Colombier 	sendmsg(job, err);
843d9924332SDavid du Colombier }
844d9924332SDavid du Colombier 
845d9924332SDavid du Colombier /*
846d9924332SDavid du Colombier  * dnsdebug calls
847d9924332SDavid du Colombier  *	rr = dnresolve(buf, Cin, type, &req, 0, 0, Recurse, rooted, 0);
848d9924332SDavid du Colombier  * which generates a UDP query, which eventually calls
849d9924332SDavid du Colombier  *	dnserver(&reqmsg, &repmsg, &req, buf, rcode);
850d9924332SDavid du Colombier  * which calls
851d9924332SDavid du Colombier  *	rp = dnresolve(name, Cin, type, req, &mp->an, 0, recurse, 1, 0);
852d9924332SDavid du Colombier  *
853d9924332SDavid du Colombier  * but here we just call dnresolve directly.
854d9924332SDavid du Colombier  */
855d9924332SDavid du Colombier static char *
lookupqueryold(Job * job,Mfile * mf,Request * req,char * errbuf,char * p,int wantsav,int rooted)856d9924332SDavid du Colombier lookupqueryold(Job *job, Mfile *mf, Request *req, char *errbuf, char *p,
857d9924332SDavid du Colombier 	int wantsav, int rooted)
858d9924332SDavid du Colombier {
859d9924332SDavid du Colombier 	int status;
860d9924332SDavid du Colombier 	RR *rp, *neg;
861d9924332SDavid du Colombier 
862d9924332SDavid du Colombier 	dncheck(0, 1);
863d9924332SDavid du Colombier 	status = Rok;
8647dd7cddfSDavid du Colombier 	rp = dnresolve(p, Cin, mf->type, req, 0, 0, Recurse, rooted, &status);
8654f8f669cSDavid du Colombier 
8669a747e4fSDavid du Colombier 	dncheck(0, 1);
867530fef66SDavid du Colombier 	lock(&dnlock);
8687dd7cddfSDavid du Colombier 	neg = rrremneg(&rp);
8697dd7cddfSDavid du Colombier 	if(neg){
8707dd7cddfSDavid du Colombier 		status = neg->negrcode;
8717dd7cddfSDavid du Colombier 		rrfreelist(neg);
8727dd7cddfSDavid du Colombier 	}
873530fef66SDavid du Colombier 	unlock(&dnlock);
8744f8f669cSDavid du Colombier 
875d9924332SDavid du Colombier 	return respond(job, mf, rp, errbuf, status, wantsav);
876d9924332SDavid du Colombier }
877d9924332SDavid du Colombier 
878d9924332SDavid du Colombier static char *
respond(Job * job,Mfile * mf,RR * rp,char * errbuf,int status,int wantsav)879d9924332SDavid du Colombier respond(Job *job, Mfile *mf, RR *rp, char *errbuf, int status, int wantsav)
880d9924332SDavid du Colombier {
881d9924332SDavid du Colombier 	long n;
882d9924332SDavid du Colombier 	RR *tp;
883d9924332SDavid du Colombier 
8844f8f669cSDavid du Colombier 	if(rp == nil)
885271b8d73SDavid du Colombier 		switch(status){
886271b8d73SDavid du Colombier 		case Rname:
887d9924332SDavid du Colombier 			return "name does not exist";
888271b8d73SDavid du Colombier 		case Rserver:
889d9924332SDavid du Colombier 			return "dns failure";
890d9924332SDavid du Colombier 		case Rok:
891271b8d73SDavid du Colombier 		default:
892d9924332SDavid du Colombier 			snprint(errbuf, ERRMAX,
893d9924332SDavid du Colombier 				"resource does not exist; negrcode %d", status);
894d9924332SDavid du Colombier 			return errbuf;
895271b8d73SDavid du Colombier 		}
896d9924332SDavid du Colombier 
89734f77ae3SDavid du Colombier 	lock(&joblock);
89834f77ae3SDavid du Colombier 	if(!job->flushed){
8997dd7cddfSDavid du Colombier 		/* format data to be read later */
9007dd7cddfSDavid du Colombier 		n = 0;
9017dd7cddfSDavid du Colombier 		mf->nrr = 0;
9027dd7cddfSDavid du Colombier 		for(tp = rp; mf->nrr < Maxrrr-1 && n < Maxreply && tp &&
9037dd7cddfSDavid du Colombier 		    tsame(mf->type, tp->type); tp = tp->next){
9047dd7cddfSDavid du Colombier 			mf->rr[mf->nrr++] = n;
9057dd7cddfSDavid du Colombier 			if(wantsav)
906d9924332SDavid du Colombier 				n += snprint(mf->reply+n, Maxreply-n, "%Q", tp);
9077dd7cddfSDavid du Colombier 			else
908d9924332SDavid du Colombier 				n += snprint(mf->reply+n, Maxreply-n, "%R", tp);
9097dd7cddfSDavid du Colombier 		}
9107dd7cddfSDavid du Colombier 		mf->rr[mf->nrr] = n;
91134f77ae3SDavid du Colombier 	}
91234f77ae3SDavid du Colombier 	unlock(&joblock);
9137dd7cddfSDavid du Colombier 	rrfreelist(rp);
914d9924332SDavid du Colombier 	return nil;
9157dd7cddfSDavid du Colombier }
916d9924332SDavid du Colombier 
917*98813beeSDavid du Colombier #ifdef notused
918d9924332SDavid du Colombier /* simulate what dnsudpserver does */
919d9924332SDavid du Colombier static char *
lookupquerynew(Job * job,Mfile * mf,Request * req,char * errbuf,char * p,int wantsav,int)920d9924332SDavid du Colombier lookupquerynew(Job *job, Mfile *mf, Request *req, char *errbuf, char *p,
921d9924332SDavid du Colombier 	int wantsav, int)
922d9924332SDavid du Colombier {
923d9924332SDavid du Colombier 	char *err;
924*98813beeSDavid du Colombier 	uchar buf[Udphdrsize + Maxpayload];
925d9924332SDavid du Colombier 	DNSmsg *mp;
926d9924332SDavid du Colombier 	DNSmsg repmsg;
927d9924332SDavid du Colombier 	RR *rp;
928d9924332SDavid du Colombier 
9299a747e4fSDavid du Colombier 	dncheck(0, 1);
930d9924332SDavid du Colombier 
931d9924332SDavid du Colombier 	memset(&repmsg, 0, sizeof repmsg);
932d9924332SDavid du Colombier 	rp = rralloc(mf->type);
933d9924332SDavid du Colombier 	rp->owner = dnlookup(p, Cin, 1);
934d9924332SDavid du Colombier 	mp = newdnsmsg(rp, Frecurse|Oquery, (ushort)rand());
935d9924332SDavid du Colombier 
936*98813beeSDavid du Colombier 	/* BUG: buf is srcip, yet it's uninitialised */
937d9924332SDavid du Colombier 	dnserver(mp, &repmsg, req, buf, Rok);
938d9924332SDavid du Colombier 
939d9924332SDavid du Colombier 	freeanswers(mp);
940d9924332SDavid du Colombier 	err = respond(job, mf, repmsg.an, errbuf, Rok, wantsav);
941d9924332SDavid du Colombier 	repmsg.an = nil;		/* freed above */
942d9924332SDavid du Colombier 	freeanswers(&repmsg);
943d9924332SDavid du Colombier 	return err;
9443e12c5d1SDavid du Colombier }
945*98813beeSDavid du Colombier #endif
9463e12c5d1SDavid du Colombier 
9473e12c5d1SDavid du Colombier void
rclunk(Job * job,Mfile * mf)9487dd7cddfSDavid du Colombier rclunk(Job *job, Mfile *mf)
9493e12c5d1SDavid du Colombier {
9507dd7cddfSDavid du Colombier 	freefid(mf);
9517dd7cddfSDavid du Colombier 	sendmsg(job, 0);
9523e12c5d1SDavid du Colombier }
9533e12c5d1SDavid du Colombier 
9543e12c5d1SDavid du Colombier void
rremove(Job * job,Mfile * mf)9557dd7cddfSDavid du Colombier rremove(Job *job, Mfile *mf)
9563e12c5d1SDavid du Colombier {
9573e12c5d1SDavid du Colombier 	USED(mf);
9587dd7cddfSDavid du Colombier 	sendmsg(job, "remove permission denied");
9593e12c5d1SDavid du Colombier }
9603e12c5d1SDavid du Colombier 
9613e12c5d1SDavid du Colombier void
rstat(Job * job,Mfile * mf)9627dd7cddfSDavid du Colombier rstat(Job *job, Mfile *mf)
9633e12c5d1SDavid du Colombier {
9643e12c5d1SDavid du Colombier 	Dir dir;
9659a747e4fSDavid du Colombier 	uchar buf[IOHDRSZ+Maxfdata];
9663e12c5d1SDavid du Colombier 
9676aaebd7dSDavid du Colombier 	memset(&dir, 0, sizeof dir);
9689a747e4fSDavid du Colombier 	if(mf->qid.type & QTDIR){
9699a747e4fSDavid du Colombier 		dir.name = ".";
9709a747e4fSDavid du Colombier 		dir.mode = DMDIR|0555;
971219b2ee8SDavid du Colombier 	} else {
9729a747e4fSDavid du Colombier 		dir.name = "dns";
9733e12c5d1SDavid du Colombier 		dir.mode = 0666;
974219b2ee8SDavid du Colombier 	}
975219b2ee8SDavid du Colombier 	dir.qid = mf->qid;
9763e12c5d1SDavid du Colombier 	dir.length = 0;
9774f8f669cSDavid du Colombier 	dir.uid = dir.gid = dir.muid = mf->user;
9784f8f669cSDavid du Colombier 	dir.atime = dir.mtime = time(nil);
9799a747e4fSDavid du Colombier 	job->reply.nstat = convD2M(&dir, buf, sizeof buf);
9809a747e4fSDavid du Colombier 	job->reply.stat = buf;
9817dd7cddfSDavid du Colombier 	sendmsg(job, 0);
9823e12c5d1SDavid du Colombier }
9833e12c5d1SDavid du Colombier 
9843e12c5d1SDavid du Colombier void
rwstat(Job * job,Mfile * mf)9857dd7cddfSDavid du Colombier rwstat(Job *job, Mfile *mf)
9863e12c5d1SDavid du Colombier {
9873e12c5d1SDavid du Colombier 	USED(mf);
9887dd7cddfSDavid du Colombier 	sendmsg(job, "wstat permission denied");
9893e12c5d1SDavid du Colombier }
9903e12c5d1SDavid du Colombier 
9913e12c5d1SDavid du Colombier void
sendmsg(Job * job,char * err)9927dd7cddfSDavid du Colombier sendmsg(Job *job, char *err)
9933e12c5d1SDavid du Colombier {
9943e12c5d1SDavid du Colombier 	int n;
9959a747e4fSDavid du Colombier 	uchar mdata[IOHDRSZ + Maxfdata];
9969a747e4fSDavid du Colombier 	char ename[ERRMAX];
9973e12c5d1SDavid du Colombier 
9983e12c5d1SDavid du Colombier 	if(err){
9997dd7cddfSDavid du Colombier 		job->reply.type = Rerror;
10004f8f669cSDavid du Colombier 		snprint(ename, sizeof ename, "dns: %s", err);
10019a747e4fSDavid du Colombier 		job->reply.ename = ename;
10024f8f669cSDavid du Colombier 	}else
10037dd7cddfSDavid du Colombier 		job->reply.type = job->request.type+1;
10047dd7cddfSDavid du Colombier 	job->reply.tag = job->request.tag;
10059a747e4fSDavid du Colombier 	n = convS2M(&job->reply, mdata, sizeof mdata);
10069a747e4fSDavid du Colombier 	if(n == 0){
10074f8f669cSDavid du Colombier 		warning("sendmsg convS2M of %F returns 0", &job->reply);
10089a747e4fSDavid du Colombier 		abort();
10093e12c5d1SDavid du Colombier 	}
10109a747e4fSDavid du Colombier 	lock(&joblock);
10119a747e4fSDavid du Colombier 	if(job->flushed == 0)
10129a747e4fSDavid du Colombier 		if(write(mfd[1], mdata, n)!=n)
10139a747e4fSDavid du Colombier 			sysfatal("mount write");
10147dd7cddfSDavid du Colombier 	unlock(&joblock);
10159a747e4fSDavid du Colombier 	if(debug)
10164f8f669cSDavid du Colombier 		dnslog("%F %d", &job->reply, n);
10173e12c5d1SDavid du Colombier }
10183e12c5d1SDavid du Colombier 
10193e12c5d1SDavid du Colombier /*
10207dd7cddfSDavid du Colombier  *  the following varies between dnsdebug and dns
10213e12c5d1SDavid du Colombier  */
10223e12c5d1SDavid du Colombier void
logreply(int id,uchar * addr,DNSmsg * mp)10237dd7cddfSDavid du Colombier logreply(int id, uchar *addr, DNSmsg *mp)
10243e12c5d1SDavid du Colombier {
10257dd7cddfSDavid du Colombier 	RR *rp;
10263e12c5d1SDavid du Colombier 
10274f8f669cSDavid du Colombier 	dnslog("%d: rcvd %I flags:%s%s%s%s%s", id, addr,
10287dd7cddfSDavid du Colombier 		mp->flags & Fauth? " auth": "",
10297dd7cddfSDavid du Colombier 		mp->flags & Ftrunc? " trunc": "",
10307dd7cddfSDavid du Colombier 		mp->flags & Frecurse? " rd": "",
10317dd7cddfSDavid du Colombier 		mp->flags & Fcanrec? " ra": "",
10324f8f669cSDavid du Colombier 		(mp->flags & (Fauth|Rmask)) == (Fauth|Rname)? " nx": "");
10337dd7cddfSDavid du Colombier 	for(rp = mp->qd; rp != nil; rp = rp->next)
10344f8f669cSDavid du Colombier 		dnslog("%d: rcvd %I qd %s", id, addr, rp->owner->name);
10357dd7cddfSDavid du Colombier 	for(rp = mp->an; rp != nil; rp = rp->next)
10364f8f669cSDavid du Colombier 		dnslog("%d: rcvd %I an %R", id, addr, rp);
10377dd7cddfSDavid du Colombier 	for(rp = mp->ns; rp != nil; rp = rp->next)
10384f8f669cSDavid du Colombier 		dnslog("%d: rcvd %I ns %R", id, addr, rp);
10397dd7cddfSDavid du Colombier 	for(rp = mp->ar; rp != nil; rp = rp->next)
10404f8f669cSDavid du Colombier 		dnslog("%d: rcvd %I ar %R", id, addr, rp);
10413e12c5d1SDavid du Colombier }
10427dd7cddfSDavid du Colombier 
10437dd7cddfSDavid du Colombier void
logsend(int id,int subid,uchar * addr,char * sname,char * rname,int type)10447dd7cddfSDavid du Colombier logsend(int id, int subid, uchar *addr, char *sname, char *rname, int type)
10457dd7cddfSDavid du Colombier {
10467dd7cddfSDavid du Colombier 	char buf[12];
10477dd7cddfSDavid du Colombier 
10484f8f669cSDavid du Colombier 	dnslog("[%d] %d.%d: sending to %I/%s %s %s",
10494f8f669cSDavid du Colombier 		getpid(), id, subid, addr, sname, rname,
10504f8f669cSDavid du Colombier 		rrname(type, buf, sizeof buf));
10517dd7cddfSDavid du Colombier }
10527dd7cddfSDavid du Colombier 
10537dd7cddfSDavid du Colombier RR*
getdnsservers(int class)10547dd7cddfSDavid du Colombier getdnsservers(int class)
10557dd7cddfSDavid du Colombier {
10567dd7cddfSDavid du Colombier 	return dnsservers(class);
10573e12c5d1SDavid du Colombier }
1058