xref: /plan9/sys/src/cmd/ndb/dns.c (revision 4f8f669ce30aa840f020b0b32ad38c5b9f2b3b4a)
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,
147dd7cddfSDavid du Colombier 	Maxreply=		512,
157dd7cddfSDavid du Colombier 	Maxrrr=			16,
169a747e4fSDavid du Colombier 	Maxfdata=		8192,
173e12c5d1SDavid du Colombier 
18*4f8f669cSDavid du Colombier 	Defmaxage=		60*60,		/* 1 hour */
19*4f8f669cSDavid 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 */
293e12c5d1SDavid du Colombier 
303e12c5d1SDavid du Colombier struct Mfile
313e12c5d1SDavid du Colombier {
327dd7cddfSDavid du Colombier 	Mfile		*next;		/* next free mfile */
339a747e4fSDavid du Colombier 	int		ref;
347dd7cddfSDavid du Colombier 
359a747e4fSDavid du Colombier 	char		*user;
363e12c5d1SDavid du Colombier 	Qid		qid;
373e12c5d1SDavid du Colombier 	int		fid;
383e12c5d1SDavid du Colombier 
393e12c5d1SDavid du Colombier 	int		type;		/* reply type */
407dd7cddfSDavid du Colombier 	char		reply[Maxreply];
417dd7cddfSDavid du Colombier 	ushort		rr[Maxrrr];	/* offset of rr's */
427dd7cddfSDavid du Colombier 	ushort		nrr;		/* number of rr's */
433e12c5d1SDavid du Colombier };
443e12c5d1SDavid du Colombier 
45*4f8f669cSDavid du Colombier /*
46*4f8f669cSDavid du Colombier  *  active local requests
47*4f8f669cSDavid du Colombier  */
487dd7cddfSDavid du Colombier struct Job
497dd7cddfSDavid du Colombier {
507dd7cddfSDavid du Colombier 	Job	*next;
517dd7cddfSDavid du Colombier 	int	flushed;
527dd7cddfSDavid du Colombier 	Fcall	request;
537dd7cddfSDavid du Colombier 	Fcall	reply;
547dd7cddfSDavid du Colombier };
557dd7cddfSDavid du Colombier Lock	joblock;
567dd7cddfSDavid du Colombier Job	*joblist;
577dd7cddfSDavid du Colombier 
587dd7cddfSDavid du Colombier struct {
597dd7cddfSDavid du Colombier 	Lock;
607dd7cddfSDavid du Colombier 	Mfile	*inuse;		/* active mfile's */
617dd7cddfSDavid du Colombier } mfalloc;
627dd7cddfSDavid du Colombier 
63*4f8f669cSDavid du Colombier Cfg	cfg;
646b0d5c8bSDavid du Colombier int	debug;
65*4f8f669cSDavid du Colombier uchar	ipaddr[IPaddrlen];	/* my ip address */
66*4f8f669cSDavid du Colombier int	maxage = Defmaxage;
67*4f8f669cSDavid du Colombier int	mfd[2];
68*4f8f669cSDavid du Colombier int	needrefresh;
697dd7cddfSDavid du Colombier ulong	now;
70*4f8f669cSDavid du Colombier int	sendnotifies;
717dd7cddfSDavid du Colombier int	testing;
727dd7cddfSDavid du Colombier char	*trace;
73*4f8f669cSDavid du Colombier int	traceactivity;
74dc5a79c1SDavid du Colombier char	*zonerefreshprogram;
753e12c5d1SDavid du Colombier 
76*4f8f669cSDavid du Colombier char	*logfile = "dns";	/* or "dns.test" */
776b0d5c8bSDavid du Colombier char	*dbfile;
786b0d5c8bSDavid du Colombier char	mntpt[Maxpath];
79*4f8f669cSDavid du Colombier 
80*4f8f669cSDavid du Colombier int	fillreply(Mfile*, int);
81*4f8f669cSDavid du Colombier void	freejob(Job*);
82*4f8f669cSDavid du Colombier void	io(void);
83*4f8f669cSDavid du Colombier void	mountinit(char*, char*);
84*4f8f669cSDavid du Colombier Job*	newjob(void);
85*4f8f669cSDavid du Colombier void	rattach(Job*, Mfile*);
86*4f8f669cSDavid du Colombier void	rauth(Job*);
87*4f8f669cSDavid du Colombier void	rclunk(Job*, Mfile*);
88*4f8f669cSDavid du Colombier void	rcreate(Job*, Mfile*);
89*4f8f669cSDavid du Colombier void	rflush(Job*);
90*4f8f669cSDavid du Colombier void	ropen(Job*, Mfile*);
91*4f8f669cSDavid du Colombier void	rread(Job*, Mfile*);
92*4f8f669cSDavid du Colombier void	rremove(Job*, Mfile*);
93*4f8f669cSDavid du Colombier void	rstat(Job*, Mfile*);
94*4f8f669cSDavid du Colombier void	rversion(Job*);
95*4f8f669cSDavid du Colombier char*	rwalk(Job*, Mfile*);
96*4f8f669cSDavid du Colombier void	rwrite(Job*, Mfile*, Request*);
97*4f8f669cSDavid du Colombier void	rwstat(Job*, Mfile*);
98*4f8f669cSDavid du Colombier void	sendmsg(Job*, char*);
99*4f8f669cSDavid du Colombier void	setext(char*, int, char*);
1006b0d5c8bSDavid du Colombier 
1017dd7cddfSDavid du Colombier void
1027dd7cddfSDavid du Colombier usage(void)
1037dd7cddfSDavid du Colombier {
104*4f8f669cSDavid du Colombier 	fprint(2, "usage: %s [-norRst] [-a maxage] [-f ndb-file] [-N target] "
105*4f8f669cSDavid du Colombier 		"[-x netmtpt] [-z refreshprog]\n", argv0);
1067dd7cddfSDavid du Colombier 	exits("usage");
1077dd7cddfSDavid du Colombier }
108219b2ee8SDavid du Colombier 
1093e12c5d1SDavid du Colombier void
1103e12c5d1SDavid du Colombier main(int argc, char *argv[])
1113e12c5d1SDavid du Colombier {
112*4f8f669cSDavid du Colombier 	char	servefile[Maxpath], ext[Maxpath];
113219b2ee8SDavid du Colombier 
114*4f8f669cSDavid du Colombier 	setnetmtpt(mntpt, sizeof mntpt, nil);
1157dd7cddfSDavid du Colombier 	ext[0] = 0;
1163e12c5d1SDavid du Colombier 	ARGBEGIN{
117*4f8f669cSDavid du Colombier 	case 'a':
118*4f8f669cSDavid du Colombier 		maxage = atol(EARGF(usage()));
119*4f8f669cSDavid du Colombier 		if (maxage <= 0)
120*4f8f669cSDavid du Colombier 			maxage = Defmaxage;
121*4f8f669cSDavid du Colombier 		break;
1223e12c5d1SDavid du Colombier 	case 'd':
1233e12c5d1SDavid du Colombier 		debug = 1;
12439734e7eSDavid du Colombier 		traceactivity = 1;
1253e12c5d1SDavid du Colombier 		break;
126219b2ee8SDavid du Colombier 	case 'f':
127*4f8f669cSDavid du Colombier 		dbfile = EARGF(usage());
1287dd7cddfSDavid du Colombier 		break;
129*4f8f669cSDavid du Colombier 	case 'n':
130*4f8f669cSDavid du Colombier 		sendnotifies = 1;
131*4f8f669cSDavid du Colombier 		break;
132*4f8f669cSDavid du Colombier 	case 'N':
133*4f8f669cSDavid du Colombier 		target = atol(EARGF(usage()));
134*4f8f669cSDavid du Colombier 		if (target < 100)
135*4f8f669cSDavid du Colombier 			target = 100;
136*4f8f669cSDavid du Colombier 		break;
137*4f8f669cSDavid du Colombier 	case 'o':
138*4f8f669cSDavid du Colombier 		cfg.straddle = 1;	/* straddle inside & outside networks */
1394fafed5dSDavid du Colombier 		break;
1407dd7cddfSDavid du Colombier 	case 'r':
141*4f8f669cSDavid du Colombier 		cfg.resolver = 1;
142219b2ee8SDavid du Colombier 		break;
143b85a8364SDavid du Colombier 	case 'R':
144b85a8364SDavid du Colombier 		norecursion = 1;
145b85a8364SDavid du Colombier 		break;
1463e12c5d1SDavid du Colombier 	case 's':
147*4f8f669cSDavid du Colombier 		cfg.serve = 1;		/* serve network */
148*4f8f669cSDavid du Colombier 		cfg.cachedb = 1;
1496b0d5c8bSDavid du Colombier 		break;
1507dd7cddfSDavid du Colombier 	case 't':
1517dd7cddfSDavid du Colombier 		testing = 1;
1523e12c5d1SDavid du Colombier 		break;
153*4f8f669cSDavid du Colombier 	case 'x':
154*4f8f669cSDavid du Colombier 		setnetmtpt(mntpt, sizeof mntpt, EARGF(usage()));
155*4f8f669cSDavid du Colombier 		setext(ext, sizeof ext, mntpt);
1566b0d5c8bSDavid du Colombier 		break;
157*4f8f669cSDavid du Colombier 	case 'z':
158*4f8f669cSDavid du Colombier 		zonerefreshprogram = EARGF(usage());
159dc5a79c1SDavid du Colombier 		break;
1603e12c5d1SDavid du Colombier 	}ARGEND
1613e12c5d1SDavid du Colombier 	USED(argc);
1623e12c5d1SDavid du Colombier 	USED(argv);
1633e12c5d1SDavid du Colombier 
164*4f8f669cSDavid du Colombier 	if(testing)
165*4f8f669cSDavid du Colombier 		mainmem->flags |= POOL_NOREUSE | POOL_ANTAGONISM;
1667dd7cddfSDavid du Colombier 	rfork(RFREND|RFNOTEG);
1673e12c5d1SDavid du Colombier 
168*4f8f669cSDavid du Colombier 	cfg.inside = (*mntpt == '\0' || strcmp(mntpt, "/net") == 0);
169*4f8f669cSDavid du Colombier 
1707dd7cddfSDavid du Colombier 	/* start syslog before we fork */
1719a747e4fSDavid du Colombier 	fmtinstall('F', fcallfmt);
172219b2ee8SDavid du Colombier 	dninit();
1739a747e4fSDavid du Colombier 	if(myipaddr(ipaddr, mntpt) < 0)
1747dd7cddfSDavid du Colombier 		sysfatal("can't read my ip address");
175*4f8f669cSDavid du Colombier 	dnslog("starting %s%sdns %s%son %I's %s",
176*4f8f669cSDavid du Colombier 		(cfg.straddle? "straddling ": ""),
177*4f8f669cSDavid du Colombier 		(cfg.cachedb? "caching ": ""),
178*4f8f669cSDavid du Colombier 		(cfg.serve?   "udp server ": ""),
179*4f8f669cSDavid du Colombier 		(cfg.resolver? "resolver ": ""), ipaddr, mntpt);
1807dd7cddfSDavid du Colombier 
1817dd7cddfSDavid du Colombier 	opendatabase();
1827dd7cddfSDavid du Colombier 
183*4f8f669cSDavid du Colombier 	snprint(servefile, sizeof servefile, "#s/dns%s", ext);
1847dd7cddfSDavid du Colombier 	unmount(servefile, mntpt);
1857dd7cddfSDavid du Colombier 	remove(servefile);
1867dd7cddfSDavid du Colombier 	mountinit(servefile, mntpt);
1877dd7cddfSDavid du Colombier 
188*4f8f669cSDavid du Colombier 	now = time(nil);
1897dd7cddfSDavid du Colombier 	srand(now*getpid());
1907dd7cddfSDavid du Colombier 	db2cache(1);
1917dd7cddfSDavid du Colombier 
192*4f8f669cSDavid du Colombier 	if (cfg.straddle && !seerootns())
193*4f8f669cSDavid du Colombier 		dnslog("straddle server misconfigured; can't see root name servers");
194*4f8f669cSDavid du Colombier 	if(cfg.serve)
1957dd7cddfSDavid du Colombier 		dnudpserver(mntpt);
196dc5a79c1SDavid du Colombier 	if(sendnotifies)
197dc5a79c1SDavid du Colombier 		notifyproc();
198dc5a79c1SDavid du Colombier 
1993e12c5d1SDavid du Colombier 	io();
200*4f8f669cSDavid du Colombier 	dnslog("io returned, exiting");
2013e12c5d1SDavid du Colombier 	exits(0);
2023e12c5d1SDavid du Colombier }
2033e12c5d1SDavid du Colombier 
2047dd7cddfSDavid du Colombier /*
205*4f8f669cSDavid du Colombier  *  if a mount point is specified, set the cs extension to be the mount point
2067dd7cddfSDavid du Colombier  *  with '_'s replacing '/'s
2077dd7cddfSDavid du Colombier  */
2083e12c5d1SDavid du Colombier void
2097dd7cddfSDavid du Colombier setext(char *ext, int n, char *p)
2107dd7cddfSDavid du Colombier {
2117dd7cddfSDavid du Colombier 	int i, c;
2127dd7cddfSDavid du Colombier 
2137dd7cddfSDavid du Colombier 	n--;
2147dd7cddfSDavid du Colombier 	for(i = 0; i < n; i++){
2157dd7cddfSDavid du Colombier 		c = p[i];
2167dd7cddfSDavid du Colombier 		if(c == 0)
2177dd7cddfSDavid du Colombier 			break;
2187dd7cddfSDavid du Colombier 		if(c == '/')
2197dd7cddfSDavid du Colombier 			c = '_';
2207dd7cddfSDavid du Colombier 		ext[i] = c;
2217dd7cddfSDavid du Colombier 	}
2227dd7cddfSDavid du Colombier 	ext[i] = 0;
2237dd7cddfSDavid du Colombier }
2247dd7cddfSDavid du Colombier 
2257dd7cddfSDavid du Colombier void
2267dd7cddfSDavid du Colombier mountinit(char *service, char *mntpt)
2273e12c5d1SDavid du Colombier {
2283e12c5d1SDavid du Colombier 	int f;
2293e12c5d1SDavid du Colombier 	int p[2];
2303e12c5d1SDavid du Colombier 	char buf[32];
2313e12c5d1SDavid du Colombier 
2323e12c5d1SDavid du Colombier 	if(pipe(p) < 0)
2337dd7cddfSDavid du Colombier 		abort(); /* "pipe failed" */;
234219b2ee8SDavid du Colombier 	switch(rfork(RFFDG|RFPROC|RFNAMEG)){
2353e12c5d1SDavid du Colombier 	case 0:
236219b2ee8SDavid du Colombier 		close(p[1]);
237*4f8f669cSDavid du Colombier 		procsetname("main");
2383e12c5d1SDavid du Colombier 		break;
2393e12c5d1SDavid du Colombier 	case -1:
2407dd7cddfSDavid du Colombier 		abort(); /* "fork failed\n" */;
2413e12c5d1SDavid du Colombier 	default:
242219b2ee8SDavid du Colombier 		close(p[0]);
243219b2ee8SDavid du Colombier 
2443e12c5d1SDavid du Colombier 		/*
2453e12c5d1SDavid du Colombier 		 *  make a /srv/dns
2463e12c5d1SDavid du Colombier 		 */
2473e12c5d1SDavid du Colombier 		f = create(service, 1, 0666);
2483e12c5d1SDavid du Colombier 		if(f < 0)
2497dd7cddfSDavid du Colombier 			abort(); /* service */;
250*4f8f669cSDavid du Colombier 		snprint(buf, sizeof buf, "%d", p[1]);
2513e12c5d1SDavid du Colombier 		if(write(f, buf, strlen(buf)) != strlen(buf))
2527dd7cddfSDavid du Colombier 			abort(); /* "write %s", service */;
2533e12c5d1SDavid du Colombier 		close(f);
2543e12c5d1SDavid du Colombier 
2553e12c5d1SDavid du Colombier 		/*
2563e12c5d1SDavid du Colombier 		 *  put ourselves into the file system
2573e12c5d1SDavid du Colombier 		 */
2589a747e4fSDavid du Colombier 		if(mount(p[1], -1, mntpt, MAFTER, "") < 0)
2599a747e4fSDavid du Colombier 			fprint(2, "dns mount failed: %r\n");
260219b2ee8SDavid du Colombier 		_exits(0);
2613e12c5d1SDavid du Colombier 	}
2623e12c5d1SDavid du Colombier 	mfd[0] = mfd[1] = p[0];
2633e12c5d1SDavid du Colombier }
2643e12c5d1SDavid du Colombier 
2653e12c5d1SDavid du Colombier Mfile*
2667dd7cddfSDavid du Colombier newfid(int fid, int needunused)
2673e12c5d1SDavid du Colombier {
2683e12c5d1SDavid du Colombier 	Mfile *mf;
2693e12c5d1SDavid du Colombier 
2707dd7cddfSDavid du Colombier 	lock(&mfalloc);
271*4f8f669cSDavid du Colombier 	for(mf = mfalloc.inuse; mf != nil; mf = mf->next)
2727dd7cddfSDavid du Colombier 		if(mf->fid == fid){
2737dd7cddfSDavid du Colombier 			unlock(&mfalloc);
2747dd7cddfSDavid du Colombier 			if(needunused)
2757dd7cddfSDavid du Colombier 				return nil;
2763e12c5d1SDavid du Colombier 			return mf;
2773e12c5d1SDavid du Colombier 		}
2789a747e4fSDavid du Colombier 	mf = emalloc(sizeof(*mf));
2797dd7cddfSDavid du Colombier 	if(mf == nil)
2807dd7cddfSDavid du Colombier 		sysfatal("out of memory");
2813e12c5d1SDavid du Colombier 	mf->fid = fid;
2827dd7cddfSDavid du Colombier 	mf->next = mfalloc.inuse;
2837dd7cddfSDavid du Colombier 	mfalloc.inuse = mf;
2847dd7cddfSDavid du Colombier 	unlock(&mfalloc);
2853e12c5d1SDavid du Colombier 	return mf;
2863e12c5d1SDavid du Colombier }
2873e12c5d1SDavid du Colombier 
2883e12c5d1SDavid du Colombier void
2897dd7cddfSDavid du Colombier freefid(Mfile *mf)
2907dd7cddfSDavid du Colombier {
2917dd7cddfSDavid du Colombier 	Mfile **l;
2927dd7cddfSDavid du Colombier 
2937dd7cddfSDavid du Colombier 	lock(&mfalloc);
294*4f8f669cSDavid du Colombier 	for(l = &mfalloc.inuse; *l != nil; l = &(*l)->next)
2957dd7cddfSDavid du Colombier 		if(*l == mf){
2967dd7cddfSDavid du Colombier 			*l = mf->next;
2976b0d5c8bSDavid du Colombier 			if(mf->user)
2989a747e4fSDavid du Colombier 				free(mf->user);
299*4f8f669cSDavid du Colombier 			memset(mf, 0, sizeof *mf);	/* cause trouble */
3007dd7cddfSDavid du Colombier 			free(mf);
3017dd7cddfSDavid du Colombier 			unlock(&mfalloc);
3027dd7cddfSDavid du Colombier 			return;
3037dd7cddfSDavid du Colombier 		}
3047dd7cddfSDavid du Colombier 	sysfatal("freeing unused fid");
3057dd7cddfSDavid du Colombier }
3067dd7cddfSDavid du Colombier 
3077dd7cddfSDavid du Colombier Mfile*
3087dd7cddfSDavid du Colombier copyfid(Mfile *mf, int fid)
3097dd7cddfSDavid du Colombier {
3107dd7cddfSDavid du Colombier 	Mfile *nmf;
3117dd7cddfSDavid du Colombier 
3127dd7cddfSDavid du Colombier 	nmf = newfid(fid, 1);
3137dd7cddfSDavid du Colombier 	if(nmf == nil)
3147dd7cddfSDavid du Colombier 		return nil;
3157dd7cddfSDavid du Colombier 	nmf->fid = fid;
3169a747e4fSDavid du Colombier 	nmf->user = estrdup(mf->user);
3179a747e4fSDavid du Colombier 	nmf->qid.type = mf->qid.type;
3187dd7cddfSDavid du Colombier 	nmf->qid.path = mf->qid.path;
3197dd7cddfSDavid du Colombier 	nmf->qid.vers = vers++;
3207dd7cddfSDavid du Colombier 	return nmf;
3217dd7cddfSDavid du Colombier }
3227dd7cddfSDavid du Colombier 
3237dd7cddfSDavid du Colombier Job*
3247dd7cddfSDavid du Colombier newjob(void)
3257dd7cddfSDavid du Colombier {
3267dd7cddfSDavid du Colombier 	Job *job;
3277dd7cddfSDavid du Colombier 
328*4f8f669cSDavid du Colombier 	job = emalloc(sizeof *job);
3297dd7cddfSDavid du Colombier 	lock(&joblock);
3307dd7cddfSDavid du Colombier 	job->next = joblist;
3317dd7cddfSDavid du Colombier 	joblist = job;
3327dd7cddfSDavid du Colombier 	job->request.tag = -1;
3337dd7cddfSDavid du Colombier 	unlock(&joblock);
3347dd7cddfSDavid du Colombier 	return job;
3357dd7cddfSDavid du Colombier }
3367dd7cddfSDavid du Colombier 
3377dd7cddfSDavid du Colombier void
3387dd7cddfSDavid du Colombier freejob(Job *job)
3397dd7cddfSDavid du Colombier {
3407dd7cddfSDavid du Colombier 	Job **l;
3417dd7cddfSDavid du Colombier 
3427dd7cddfSDavid du Colombier 	lock(&joblock);
343*4f8f669cSDavid du Colombier 	for(l = &joblist; *l; l = &(*l)->next)
344*4f8f669cSDavid du Colombier 		if(*l == job){
3457dd7cddfSDavid du Colombier 			*l = job->next;
346*4f8f669cSDavid du Colombier 			memset(job, 0, sizeof *job);	/* cause trouble */
3477dd7cddfSDavid du Colombier 			free(job);
3487dd7cddfSDavid du Colombier 			break;
3497dd7cddfSDavid du Colombier 		}
3507dd7cddfSDavid du Colombier 	unlock(&joblock);
3517dd7cddfSDavid du Colombier }
3527dd7cddfSDavid du Colombier 
3537dd7cddfSDavid du Colombier void
3547dd7cddfSDavid du Colombier flushjob(int tag)
3557dd7cddfSDavid du Colombier {
3567dd7cddfSDavid du Colombier 	Job *job;
3577dd7cddfSDavid du Colombier 
3587dd7cddfSDavid du Colombier 	lock(&joblock);
359*4f8f669cSDavid du Colombier 	for(job = joblist; job; job = job->next)
3607dd7cddfSDavid du Colombier 		if(job->request.tag == tag && job->request.type != Tflush){
3617dd7cddfSDavid du Colombier 			job->flushed = 1;
3627dd7cddfSDavid du Colombier 			break;
3637dd7cddfSDavid du Colombier 		}
3647dd7cddfSDavid du Colombier 	unlock(&joblock);
3657dd7cddfSDavid du Colombier }
3667dd7cddfSDavid du Colombier 
3677dd7cddfSDavid du Colombier void
3683e12c5d1SDavid du Colombier io(void)
3693e12c5d1SDavid du Colombier {
3703e12c5d1SDavid du Colombier 	long n;
3713e12c5d1SDavid du Colombier 	Mfile *mf;
3729a747e4fSDavid du Colombier 	uchar mdata[IOHDRSZ + Maxfdata];
3733e12c5d1SDavid du Colombier 	Request req;
3747dd7cddfSDavid du Colombier 	Job *job;
3753e12c5d1SDavid du Colombier 
376*4f8f669cSDavid du Colombier 	memset(&req, 0, sizeof req);
3773e12c5d1SDavid du Colombier 	/*
3783e12c5d1SDavid du Colombier 	 *  a slave process is sometimes forked to wait for replies from other
3793e12c5d1SDavid du Colombier 	 *  servers.  The master process returns immediately via a longjmp
380219b2ee8SDavid du Colombier 	 *  through 'mret'.
3813e12c5d1SDavid du Colombier 	 */
3827dd7cddfSDavid du Colombier 	if(setjmp(req.mret))
383b4b9fc2fSDavid du Colombier 		putactivity(0);
384*4f8f669cSDavid du Colombier 	procsetname("main 9p reading loop");
3853e12c5d1SDavid du Colombier 	req.isslave = 0;
3867dd7cddfSDavid du Colombier 	for(;;){
3879a747e4fSDavid du Colombier 		n = read9pmsg(mfd[0], mdata, sizeof mdata);
3887dd7cddfSDavid du Colombier 		if(n<=0){
389*4f8f669cSDavid du Colombier 			dnslog("error reading mntpt: %r");
3907dd7cddfSDavid du Colombier 			exits(0);
3917dd7cddfSDavid du Colombier 		}
392*4f8f669cSDavid du Colombier 
3937dd7cddfSDavid du Colombier 		job = newjob();
3949a747e4fSDavid du Colombier 		if(convM2S(mdata, n, &job->request) != n){
3957dd7cddfSDavid du Colombier 			freejob(job);
3967dd7cddfSDavid du Colombier 			continue;
3977dd7cddfSDavid du Colombier 		}
3987dd7cddfSDavid du Colombier 		mf = newfid(job->request.fid, 0);
399219b2ee8SDavid du Colombier 		if(debug)
400*4f8f669cSDavid du Colombier 			dnslog("%F", &job->request);
4017dd7cddfSDavid du Colombier 
402b4b9fc2fSDavid du Colombier 		getactivity(&req, 0);
403*4f8f669cSDavid du Colombier 		req.aborttime = now + Maxreqtm;
4047dd7cddfSDavid du Colombier 
4057dd7cddfSDavid du Colombier 		switch(job->request.type){
4063e12c5d1SDavid du Colombier 		default:
407*4f8f669cSDavid du Colombier 			warning("unknown request type %d", job->request.type);
4083e12c5d1SDavid du Colombier 			break;
4099a747e4fSDavid du Colombier 		case Tversion:
4109a747e4fSDavid du Colombier 			rversion(job);
4113e12c5d1SDavid du Colombier 			break;
4129a747e4fSDavid du Colombier 		case Tauth:
4139a747e4fSDavid du Colombier 			rauth(job);
4143e12c5d1SDavid du Colombier 			break;
4153e12c5d1SDavid du Colombier 		case Tflush:
4167dd7cddfSDavid du Colombier 			rflush(job);
4173e12c5d1SDavid du Colombier 			break;
4183e12c5d1SDavid du Colombier 		case Tattach:
4197dd7cddfSDavid du Colombier 			rattach(job, mf);
4203e12c5d1SDavid du Colombier 			break;
4213e12c5d1SDavid du Colombier 		case Twalk:
4227dd7cddfSDavid du Colombier 			rwalk(job, mf);
4233e12c5d1SDavid du Colombier 			break;
4243e12c5d1SDavid du Colombier 		case Topen:
4257dd7cddfSDavid du Colombier 			ropen(job, mf);
4263e12c5d1SDavid du Colombier 			break;
4273e12c5d1SDavid du Colombier 		case Tcreate:
4287dd7cddfSDavid du Colombier 			rcreate(job, mf);
4293e12c5d1SDavid du Colombier 			break;
4303e12c5d1SDavid du Colombier 		case Tread:
4317dd7cddfSDavid du Colombier 			rread(job, mf);
4323e12c5d1SDavid du Colombier 			break;
4333e12c5d1SDavid du Colombier 		case Twrite:
4347dd7cddfSDavid du Colombier 			rwrite(job, mf, &req);
4353e12c5d1SDavid du Colombier 			break;
4363e12c5d1SDavid du Colombier 		case Tclunk:
4377dd7cddfSDavid du Colombier 			rclunk(job, mf);
4383e12c5d1SDavid du Colombier 			break;
4393e12c5d1SDavid du Colombier 		case Tremove:
4407dd7cddfSDavid du Colombier 			rremove(job, mf);
4413e12c5d1SDavid du Colombier 			break;
4423e12c5d1SDavid du Colombier 		case Tstat:
4437dd7cddfSDavid du Colombier 			rstat(job, mf);
4443e12c5d1SDavid du Colombier 			break;
4453e12c5d1SDavid du Colombier 		case Twstat:
4467dd7cddfSDavid du Colombier 			rwstat(job, mf);
4473e12c5d1SDavid du Colombier 			break;
4483e12c5d1SDavid du Colombier 		}
4497dd7cddfSDavid du Colombier 
4507dd7cddfSDavid du Colombier 		freejob(job);
4517dd7cddfSDavid du Colombier 
4523e12c5d1SDavid du Colombier 		/*
4533e12c5d1SDavid du Colombier 		 *  slave processes die after replying
4543e12c5d1SDavid du Colombier 		 */
4557dd7cddfSDavid du Colombier 		if(req.isslave){
456b4b9fc2fSDavid du Colombier 			putactivity(0);
4573e12c5d1SDavid du Colombier 			_exits(0);
4587dd7cddfSDavid du Colombier 		}
4597dd7cddfSDavid du Colombier 
460b4b9fc2fSDavid du Colombier 		putactivity(0);
4617dd7cddfSDavid du Colombier 	}
4623e12c5d1SDavid du Colombier }
4633e12c5d1SDavid du Colombier 
4643e12c5d1SDavid du Colombier void
4659a747e4fSDavid du Colombier rversion(Job *job)
466219b2ee8SDavid du Colombier {
4679a747e4fSDavid du Colombier 	if(job->request.msize > IOHDRSZ + Maxfdata)
4689a747e4fSDavid du Colombier 		job->reply.msize = IOHDRSZ + Maxfdata;
4699a747e4fSDavid du Colombier 	else
4709a747e4fSDavid du Colombier 		job->reply.msize = job->request.msize;
4719a747e4fSDavid du Colombier 	if(strncmp(job->request.version, "9P2000", 6) != 0)
4729a747e4fSDavid du Colombier 		sendmsg(job, "unknown 9P version");
4739a747e4fSDavid du Colombier 	else{
4749a747e4fSDavid du Colombier 		job->reply.version = "9P2000";
4757dd7cddfSDavid du Colombier 		sendmsg(job, 0);
476219b2ee8SDavid du Colombier 	}
4779a747e4fSDavid du Colombier }
478219b2ee8SDavid du Colombier 
479219b2ee8SDavid du Colombier void
4809a747e4fSDavid du Colombier rauth(Job *job)
4813e12c5d1SDavid du Colombier {
4823ff48bf5SDavid du Colombier 	sendmsg(job, "dns: authentication not required");
4837dd7cddfSDavid du Colombier }
4847dd7cddfSDavid du Colombier 
4859a747e4fSDavid du Colombier /*
4869a747e4fSDavid du Colombier  *  don't flush till all the slaves are done
4879a747e4fSDavid du Colombier  */
4887dd7cddfSDavid du Colombier void
4897dd7cddfSDavid du Colombier rflush(Job *job)
4907dd7cddfSDavid du Colombier {
4917dd7cddfSDavid du Colombier 	flushjob(job->request.oldtag);
4927dd7cddfSDavid du Colombier 	sendmsg(job, 0);
4933e12c5d1SDavid du Colombier }
4943e12c5d1SDavid du Colombier 
4953e12c5d1SDavid du Colombier void
4967dd7cddfSDavid du Colombier rattach(Job *job, Mfile *mf)
4973e12c5d1SDavid du Colombier {
4989a747e4fSDavid du Colombier 	if(mf->user != nil)
4999a747e4fSDavid du Colombier 		free(mf->user);
5009a747e4fSDavid du Colombier 	mf->user = estrdup(job->request.uname);
5013e12c5d1SDavid du Colombier 	mf->qid.vers = vers++;
5029a747e4fSDavid du Colombier 	mf->qid.type = QTDIR;
5039a747e4fSDavid du Colombier 	mf->qid.path = 0LL;
5047dd7cddfSDavid du Colombier 	job->reply.qid = mf->qid;
5057dd7cddfSDavid du Colombier 	sendmsg(job, 0);
5063e12c5d1SDavid du Colombier }
5073e12c5d1SDavid du Colombier 
5083e12c5d1SDavid du Colombier char*
5097dd7cddfSDavid du Colombier rwalk(Job *job, Mfile *mf)
5103e12c5d1SDavid du Colombier {
511*4f8f669cSDavid du Colombier 	int i, nelems;
5123e12c5d1SDavid du Colombier 	char *err;
5139a747e4fSDavid du Colombier 	char **elems;
5149a747e4fSDavid du Colombier 	Mfile *nmf;
5159a747e4fSDavid du Colombier 	Qid qid;
5163e12c5d1SDavid du Colombier 
5173e12c5d1SDavid du Colombier 	err = 0;
5189a747e4fSDavid du Colombier 	nmf = nil;
5199a747e4fSDavid du Colombier 	elems  = job->request.wname;
5209a747e4fSDavid du Colombier 	nelems = job->request.nwname;
5219a747e4fSDavid du Colombier 	job->reply.nwqid = 0;
5229a747e4fSDavid du Colombier 
5239a747e4fSDavid du Colombier 	if(job->request.newfid != job->request.fid){
5249a747e4fSDavid du Colombier 		/* clone fid */
5259a747e4fSDavid du Colombier 		nmf = copyfid(mf, job->request.newfid);
5269a747e4fSDavid du Colombier 		if(nmf == nil){
5279a747e4fSDavid du Colombier 			err = "clone bad newfid";
5289a747e4fSDavid du Colombier 			goto send;
5299a747e4fSDavid du Colombier 		}
5309a747e4fSDavid du Colombier 		mf = nmf;
5319a747e4fSDavid du Colombier 	}
5329a747e4fSDavid du Colombier 	/* else nmf will be nil */
5339a747e4fSDavid du Colombier 
5349a747e4fSDavid du Colombier 	qid = mf->qid;
535*4f8f669cSDavid du Colombier 	if(nelems > 0)
5369a747e4fSDavid du Colombier 		/* walk fid */
5379a747e4fSDavid du Colombier 		for(i=0; i<nelems && i<MAXWELEM; i++){
5389a747e4fSDavid du Colombier 			if((qid.type & QTDIR) == 0){
5393e12c5d1SDavid du Colombier 				err = "not a directory";
5409a747e4fSDavid du Colombier 				break;
5413e12c5d1SDavid du Colombier 			}
542*4f8f669cSDavid du Colombier 			if (strcmp(elems[i], "..") == 0 ||
543*4f8f669cSDavid du Colombier 			    strcmp(elems[i], ".") == 0){
5449a747e4fSDavid du Colombier 				qid.type = QTDIR;
5459a747e4fSDavid du Colombier 				qid.path = Qdir;
5469a747e4fSDavid du Colombier Found:
5479a747e4fSDavid du Colombier 				job->reply.wqid[i] = qid;
5489a747e4fSDavid du Colombier 				job->reply.nwqid++;
5499a747e4fSDavid du Colombier 				continue;
5503e12c5d1SDavid du Colombier 			}
5519a747e4fSDavid du Colombier 			if(strcmp(elems[i], "dns") == 0){
5529a747e4fSDavid du Colombier 				qid.type = QTFILE;
5539a747e4fSDavid du Colombier 				qid.path = Qdns;
5549a747e4fSDavid du Colombier 				goto Found;
5553e12c5d1SDavid du Colombier 			}
5569a747e4fSDavid du Colombier 			err = "file does not exist";
5579a747e4fSDavid du Colombier 			break;
5589a747e4fSDavid du Colombier 		}
5599a747e4fSDavid du Colombier 
5603e12c5d1SDavid du Colombier send:
5619a747e4fSDavid du Colombier 	if(nmf != nil && (err!=nil || job->reply.nwqid<nelems))
5629a747e4fSDavid du Colombier 		freefid(nmf);
5639a747e4fSDavid du Colombier 	if(err == nil)
5649a747e4fSDavid du Colombier 		mf->qid = qid;
5657dd7cddfSDavid du Colombier 	sendmsg(job, err);
5663e12c5d1SDavid du Colombier 	return err;
5673e12c5d1SDavid du Colombier }
5683e12c5d1SDavid du Colombier 
5693e12c5d1SDavid du Colombier void
5707dd7cddfSDavid du Colombier ropen(Job *job, Mfile *mf)
5713e12c5d1SDavid du Colombier {
5723e12c5d1SDavid du Colombier 	int mode;
5733e12c5d1SDavid du Colombier 	char *err;
5743e12c5d1SDavid du Colombier 
5753e12c5d1SDavid du Colombier 	err = 0;
5767dd7cddfSDavid du Colombier 	mode = job->request.mode;
577*4f8f669cSDavid du Colombier 	if(mf->qid.type & QTDIR)
5783e12c5d1SDavid du Colombier 		if(mode)
5793e12c5d1SDavid du Colombier 			err = "permission denied";
5807dd7cddfSDavid du Colombier 	job->reply.qid = mf->qid;
5819a747e4fSDavid du Colombier 	job->reply.iounit = 0;
5827dd7cddfSDavid du Colombier 	sendmsg(job, err);
5833e12c5d1SDavid du Colombier }
5843e12c5d1SDavid du Colombier 
5853e12c5d1SDavid du Colombier void
5867dd7cddfSDavid du Colombier rcreate(Job *job, Mfile *mf)
5873e12c5d1SDavid du Colombier {
5883e12c5d1SDavid du Colombier 	USED(mf);
5897dd7cddfSDavid du Colombier 	sendmsg(job, "creation permission denied");
5903e12c5d1SDavid du Colombier }
5913e12c5d1SDavid du Colombier 
5923e12c5d1SDavid du Colombier void
5937dd7cddfSDavid du Colombier rread(Job *job, Mfile *mf)
5943e12c5d1SDavid du Colombier {
595*4f8f669cSDavid du Colombier 	int i, n;
5966b0d5c8bSDavid du Colombier 	long clock;
597*4f8f669cSDavid du Colombier 	ulong cnt;
598*4f8f669cSDavid du Colombier 	vlong off;
599*4f8f669cSDavid du Colombier 	char *err;
600*4f8f669cSDavid du Colombier 	uchar buf[Maxfdata];
601*4f8f669cSDavid du Colombier 	Dir dir;
6023e12c5d1SDavid du Colombier 
6033e12c5d1SDavid du Colombier 	n = 0;
604*4f8f669cSDavid du Colombier 	err = nil;
6057dd7cddfSDavid du Colombier 	off = job->request.offset;
6067dd7cddfSDavid du Colombier 	cnt = job->request.count;
607*4f8f669cSDavid du Colombier 	*buf = '\0';
608*4f8f669cSDavid du Colombier 	job->reply.data = (char*)buf;
6099a747e4fSDavid du Colombier 	if(mf->qid.type & QTDIR){
610*4f8f669cSDavid du Colombier 		clock = time(nil);
6113e12c5d1SDavid du Colombier 		if(off == 0){
6129a747e4fSDavid du Colombier 			dir.name = "dns";
6139a747e4fSDavid du Colombier 			dir.qid.type = QTFILE;
6143e12c5d1SDavid du Colombier 			dir.qid.vers = vers;
6153e12c5d1SDavid du Colombier 			dir.qid.path = Qdns;
6163e12c5d1SDavid du Colombier 			dir.mode = 0666;
6173e12c5d1SDavid du Colombier 			dir.length = 0;
618*4f8f669cSDavid du Colombier 			dir.uid = dir.gid = dir.muid = mf->user;
619*4f8f669cSDavid du Colombier 			dir.atime = dir.mtime = clock;		/* wrong */
6209a747e4fSDavid du Colombier 			n = convD2M(&dir, buf, sizeof buf);
6213e12c5d1SDavid du Colombier 		}
622*4f8f669cSDavid du Colombier 	} else if (off < 0)
623*4f8f669cSDavid du Colombier 		err = "negative read offset";
624*4f8f669cSDavid du Colombier 	else {
625*4f8f669cSDavid du Colombier 		/* first offset will always be zero */
6267dd7cddfSDavid du Colombier 		for(i = 1; i <= mf->nrr; i++)
6277dd7cddfSDavid du Colombier 			if(mf->rr[i] > off)
6283e12c5d1SDavid du Colombier 				break;
629*4f8f669cSDavid du Colombier 		if(i <= mf->nrr) {
6307dd7cddfSDavid du Colombier 			if(off + cnt > mf->rr[i])
6317dd7cddfSDavid du Colombier 				n = mf->rr[i] - off;
6327dd7cddfSDavid du Colombier 			else
6337dd7cddfSDavid du Colombier 				n = cnt;
634*4f8f669cSDavid du Colombier 			assert(n >= 0);
6357dd7cddfSDavid du Colombier 			job->reply.data = mf->reply + off;
6363e12c5d1SDavid du Colombier 		}
637*4f8f669cSDavid du Colombier 	}
6387dd7cddfSDavid du Colombier 	job->reply.count = n;
6397dd7cddfSDavid du Colombier 	sendmsg(job, err);
6403e12c5d1SDavid du Colombier }
6413e12c5d1SDavid du Colombier 
6423e12c5d1SDavid du Colombier void
6437dd7cddfSDavid du Colombier rwrite(Job *job, Mfile *mf, Request *req)
6443e12c5d1SDavid du Colombier {
645*4f8f669cSDavid du Colombier 	int rooted, status, wantsav;
6467dd7cddfSDavid du Colombier 	long n;
647*4f8f669cSDavid du Colombier 	ulong cnt;
6487dd7cddfSDavid du Colombier 	char *err, *p, *atype;
6497dd7cddfSDavid du Colombier 	RR *rp, *tp, *neg;
6503e12c5d1SDavid du Colombier 
651*4f8f669cSDavid du Colombier 	err = nil;
6527dd7cddfSDavid du Colombier 	cnt = job->request.count;
6539a747e4fSDavid du Colombier 	if(mf->qid.type & QTDIR){
6543e12c5d1SDavid du Colombier 		err = "can't write directory";
6553e12c5d1SDavid du Colombier 		goto send;
6563e12c5d1SDavid du Colombier 	}
657*4f8f669cSDavid du Colombier 	if (job->request.offset != 0) {
658*4f8f669cSDavid du Colombier 		err = "writing at non-zero offset";
659*4f8f669cSDavid du Colombier 		goto send;
660*4f8f669cSDavid du Colombier 	}
6613e12c5d1SDavid du Colombier 	if(cnt >= Maxrequest){
6623e12c5d1SDavid du Colombier 		err = "request too long";
6633e12c5d1SDavid du Colombier 		goto send;
6643e12c5d1SDavid du Colombier 	}
6657dd7cddfSDavid du Colombier 	job->request.data[cnt] = 0;
6667dd7cddfSDavid du Colombier 	if(cnt > 0 && job->request.data[cnt-1] == '\n')
6677dd7cddfSDavid du Colombier 		job->request.data[cnt-1] = 0;
6683e12c5d1SDavid du Colombier 
6693e12c5d1SDavid du Colombier 	/*
6707dd7cddfSDavid du Colombier 	 *  special commands
671219b2ee8SDavid du Colombier 	 */
672*4f8f669cSDavid du Colombier 	if(strcmp(job->request.data, "debug")==0){
673219b2ee8SDavid du Colombier 		debug ^= 1;
674219b2ee8SDavid du Colombier 		goto send;
675*4f8f669cSDavid du Colombier 	} else if(strcmp(job->request.data, "dump")==0){
676219b2ee8SDavid du Colombier 		dndump("/lib/ndb/dnsdump");
677219b2ee8SDavid du Colombier 		goto send;
678*4f8f669cSDavid du Colombier 	} else if(strcmp(job->request.data, "refresh")==0){
6797dd7cddfSDavid du Colombier 		needrefresh = 1;
6807dd7cddfSDavid du Colombier 		goto send;
681*4f8f669cSDavid du Colombier 	} else if(strcmp(job->request.data, "poolcheck")==0){
6829a747e4fSDavid du Colombier 		poolcheck(mainmem);
6839a747e4fSDavid du Colombier 		goto send;
684219b2ee8SDavid du Colombier 	}
685219b2ee8SDavid du Colombier 
686219b2ee8SDavid du Colombier 	/*
6877dd7cddfSDavid du Colombier 	 *  kill previous reply
6887dd7cddfSDavid du Colombier 	 */
6897dd7cddfSDavid du Colombier 	mf->nrr = 0;
6907dd7cddfSDavid du Colombier 	mf->rr[0] = 0;
6917dd7cddfSDavid du Colombier 
6927dd7cddfSDavid du Colombier 	/*
6933e12c5d1SDavid du Colombier 	 *  break up request (into a name and a type)
6943e12c5d1SDavid du Colombier 	 */
6957dd7cddfSDavid du Colombier 	atype = strchr(job->request.data, ' ');
6963e12c5d1SDavid du Colombier 	if(atype == 0){
6973e12c5d1SDavid du Colombier 		err = "illegal request";
6983e12c5d1SDavid du Colombier 		goto send;
6993e12c5d1SDavid du Colombier 	} else
7003e12c5d1SDavid du Colombier 		*atype++ = 0;
7013e12c5d1SDavid du Colombier 
7027dd7cddfSDavid du Colombier 	/*
7037dd7cddfSDavid du Colombier 	 *  tracing request
7047dd7cddfSDavid du Colombier 	 */
7057dd7cddfSDavid du Colombier 	if(strcmp(atype, "trace") == 0){
7067dd7cddfSDavid du Colombier 		if(trace)
7077dd7cddfSDavid du Colombier 			free(trace);
7087dd7cddfSDavid du Colombier 		if(*job->request.data)
7099a747e4fSDavid du Colombier 			trace = estrdup(job->request.data);
7107dd7cddfSDavid du Colombier 		else
7117dd7cddfSDavid du Colombier 			trace = 0;
7127dd7cddfSDavid du Colombier 		goto send;
7137dd7cddfSDavid du Colombier 	}
7147dd7cddfSDavid du Colombier 
715*4f8f669cSDavid du Colombier 	/* normal request: domain [type] */
7163e12c5d1SDavid du Colombier 	mf->type = rrtype(atype);
7173e12c5d1SDavid du Colombier 	if(mf->type < 0){
7183e12c5d1SDavid du Colombier 		err = "unknown type";
7193e12c5d1SDavid du Colombier 		goto send;
7203e12c5d1SDavid du Colombier 	}
7213e12c5d1SDavid du Colombier 
7227dd7cddfSDavid du Colombier 	p = atype - 2;
7237dd7cddfSDavid du Colombier 	if(p >= job->request.data && *p == '.'){
7247dd7cddfSDavid du Colombier 		rooted = 1;
7257dd7cddfSDavid du Colombier 		*p = 0;
7267dd7cddfSDavid du Colombier 	} else
7277dd7cddfSDavid du Colombier 		rooted = 0;
7283e12c5d1SDavid du Colombier 
7297dd7cddfSDavid du Colombier 	p = job->request.data;
7307dd7cddfSDavid du Colombier 	if(*p == '!'){
7317dd7cddfSDavid du Colombier 		wantsav = 1;
7327dd7cddfSDavid du Colombier 		p++;
7337dd7cddfSDavid du Colombier 	} else
7347dd7cddfSDavid du Colombier 		wantsav = 0;
735*4f8f669cSDavid du Colombier 
7369a747e4fSDavid du Colombier 	dncheck(0, 1);
737*4f8f669cSDavid du Colombier 	status = 0;
7387dd7cddfSDavid du Colombier 	rp = dnresolve(p, Cin, mf->type, req, 0, 0, Recurse, rooted, &status);
739*4f8f669cSDavid du Colombier 
7409a747e4fSDavid du Colombier 	dncheck(0, 1);
7417dd7cddfSDavid du Colombier 	neg = rrremneg(&rp);
7427dd7cddfSDavid du Colombier 	if(neg){
7437dd7cddfSDavid du Colombier 		status = neg->negrcode;
7447dd7cddfSDavid du Colombier 		rrfreelist(neg);
7457dd7cddfSDavid du Colombier 	}
746*4f8f669cSDavid du Colombier 
747*4f8f669cSDavid du Colombier 	if(rp == nil)
748271b8d73SDavid du Colombier 		switch(status){
749271b8d73SDavid du Colombier 		case Rname:
7507dd7cddfSDavid du Colombier 			err = "name does not exist";
751271b8d73SDavid du Colombier 			break;
752271b8d73SDavid du Colombier 		case Rserver:
753271b8d73SDavid du Colombier 			err = "dns failure";
754271b8d73SDavid du Colombier 			break;
755271b8d73SDavid du Colombier 		default:
756271b8d73SDavid du Colombier 			err = "resource does not exist";
757271b8d73SDavid du Colombier 			break;
758271b8d73SDavid du Colombier 		}
759*4f8f669cSDavid du Colombier 	else {
76034f77ae3SDavid du Colombier 		lock(&joblock);
76134f77ae3SDavid du Colombier 		if(!job->flushed){
7627dd7cddfSDavid du Colombier 			/* format data to be read later */
7637dd7cddfSDavid du Colombier 			n = 0;
7647dd7cddfSDavid du Colombier 			mf->nrr = 0;
7657dd7cddfSDavid du Colombier 			for(tp = rp; mf->nrr < Maxrrr-1 && n < Maxreply && tp &&
7667dd7cddfSDavid du Colombier 			    tsame(mf->type, tp->type); tp = tp->next){
7677dd7cddfSDavid du Colombier 				mf->rr[mf->nrr++] = n;
7687dd7cddfSDavid du Colombier 				if(wantsav)
769*4f8f669cSDavid du Colombier 					n += snprint(mf->reply+n, Maxreply-n,
770*4f8f669cSDavid du Colombier 						"%Q", tp);
7717dd7cddfSDavid du Colombier 				else
772*4f8f669cSDavid du Colombier 					n += snprint(mf->reply+n, Maxreply-n,
773*4f8f669cSDavid du Colombier 						"%R", tp);
7747dd7cddfSDavid du Colombier 			}
7757dd7cddfSDavid du Colombier 			mf->rr[mf->nrr] = n;
77634f77ae3SDavid du Colombier 		}
77734f77ae3SDavid du Colombier 		unlock(&joblock);
7787dd7cddfSDavid du Colombier 		rrfreelist(rp);
7797dd7cddfSDavid du Colombier 	}
7803e12c5d1SDavid du Colombier send:
7819a747e4fSDavid du Colombier 	dncheck(0, 1);
7827dd7cddfSDavid du Colombier 	job->reply.count = cnt;
7837dd7cddfSDavid du Colombier 	sendmsg(job, err);
7843e12c5d1SDavid du Colombier }
7853e12c5d1SDavid du Colombier 
7863e12c5d1SDavid du Colombier void
7877dd7cddfSDavid du Colombier rclunk(Job *job, Mfile *mf)
7883e12c5d1SDavid du Colombier {
7897dd7cddfSDavid du Colombier 	freefid(mf);
7907dd7cddfSDavid du Colombier 	sendmsg(job, 0);
7913e12c5d1SDavid du Colombier }
7923e12c5d1SDavid du Colombier 
7933e12c5d1SDavid du Colombier void
7947dd7cddfSDavid du Colombier rremove(Job *job, Mfile *mf)
7953e12c5d1SDavid du Colombier {
7963e12c5d1SDavid du Colombier 	USED(mf);
7977dd7cddfSDavid du Colombier 	sendmsg(job, "remove permission denied");
7983e12c5d1SDavid du Colombier }
7993e12c5d1SDavid du Colombier 
8003e12c5d1SDavid du Colombier void
8017dd7cddfSDavid du Colombier rstat(Job *job, Mfile *mf)
8023e12c5d1SDavid du Colombier {
8033e12c5d1SDavid du Colombier 	Dir dir;
8049a747e4fSDavid du Colombier 	uchar buf[IOHDRSZ+Maxfdata];
8053e12c5d1SDavid du Colombier 
8069a747e4fSDavid du Colombier 	if(mf->qid.type & QTDIR){
8079a747e4fSDavid du Colombier 		dir.name = ".";
8089a747e4fSDavid du Colombier 		dir.mode = DMDIR|0555;
809219b2ee8SDavid du Colombier 	} else {
8109a747e4fSDavid du Colombier 		dir.name = "dns";
8113e12c5d1SDavid du Colombier 		dir.mode = 0666;
812219b2ee8SDavid du Colombier 	}
813219b2ee8SDavid du Colombier 	dir.qid = mf->qid;
8143e12c5d1SDavid du Colombier 	dir.length = 0;
815*4f8f669cSDavid du Colombier 	dir.uid = dir.gid = dir.muid = mf->user;
816*4f8f669cSDavid du Colombier 	dir.atime = dir.mtime = time(nil);
8179a747e4fSDavid du Colombier 	job->reply.nstat = convD2M(&dir, buf, sizeof buf);
8189a747e4fSDavid du Colombier 	job->reply.stat = buf;
8197dd7cddfSDavid du Colombier 	sendmsg(job, 0);
8203e12c5d1SDavid du Colombier }
8213e12c5d1SDavid du Colombier 
8223e12c5d1SDavid du Colombier void
8237dd7cddfSDavid du Colombier rwstat(Job *job, Mfile *mf)
8243e12c5d1SDavid du Colombier {
8253e12c5d1SDavid du Colombier 	USED(mf);
8267dd7cddfSDavid du Colombier 	sendmsg(job, "wstat permission denied");
8273e12c5d1SDavid du Colombier }
8283e12c5d1SDavid du Colombier 
8293e12c5d1SDavid du Colombier void
8307dd7cddfSDavid du Colombier sendmsg(Job *job, char *err)
8313e12c5d1SDavid du Colombier {
8323e12c5d1SDavid du Colombier 	int n;
8339a747e4fSDavid du Colombier 	uchar mdata[IOHDRSZ + Maxfdata];
8349a747e4fSDavid du Colombier 	char ename[ERRMAX];
8353e12c5d1SDavid du Colombier 
8363e12c5d1SDavid du Colombier 	if(err){
8377dd7cddfSDavid du Colombier 		job->reply.type = Rerror;
838*4f8f669cSDavid du Colombier 		snprint(ename, sizeof ename, "dns: %s", err);
8399a747e4fSDavid du Colombier 		job->reply.ename = ename;
840*4f8f669cSDavid du Colombier 	}else
8417dd7cddfSDavid du Colombier 		job->reply.type = job->request.type+1;
8427dd7cddfSDavid du Colombier 	job->reply.tag = job->request.tag;
8439a747e4fSDavid du Colombier 	n = convS2M(&job->reply, mdata, sizeof mdata);
8449a747e4fSDavid du Colombier 	if(n == 0){
845*4f8f669cSDavid du Colombier 		warning("sendmsg convS2M of %F returns 0", &job->reply);
8469a747e4fSDavid du Colombier 		abort();
8473e12c5d1SDavid du Colombier 	}
8489a747e4fSDavid du Colombier 	lock(&joblock);
8499a747e4fSDavid du Colombier 	if(job->flushed == 0)
8509a747e4fSDavid du Colombier 		if(write(mfd[1], mdata, n)!=n)
8519a747e4fSDavid du Colombier 			sysfatal("mount write");
8527dd7cddfSDavid du Colombier 	unlock(&joblock);
8539a747e4fSDavid du Colombier 	if(debug)
854*4f8f669cSDavid du Colombier 		dnslog("%F %d", &job->reply, n);
8553e12c5d1SDavid du Colombier }
8563e12c5d1SDavid du Colombier 
8573e12c5d1SDavid du Colombier /*
8587dd7cddfSDavid du Colombier  *  the following varies between dnsdebug and dns
8593e12c5d1SDavid du Colombier  */
8603e12c5d1SDavid du Colombier void
8617dd7cddfSDavid du Colombier logreply(int id, uchar *addr, DNSmsg *mp)
8623e12c5d1SDavid du Colombier {
8637dd7cddfSDavid du Colombier 	RR *rp;
8643e12c5d1SDavid du Colombier 
865*4f8f669cSDavid du Colombier 	dnslog("%d: rcvd %I flags:%s%s%s%s%s", id, addr,
8667dd7cddfSDavid du Colombier 		mp->flags & Fauth? " auth": "",
8677dd7cddfSDavid du Colombier 		mp->flags & Ftrunc? " trunc": "",
8687dd7cddfSDavid du Colombier 		mp->flags & Frecurse? " rd": "",
8697dd7cddfSDavid du Colombier 		mp->flags & Fcanrec? " ra": "",
870*4f8f669cSDavid du Colombier 		(mp->flags & (Fauth|Rmask)) == (Fauth|Rname)? " nx": "");
8717dd7cddfSDavid du Colombier 	for(rp = mp->qd; rp != nil; rp = rp->next)
872*4f8f669cSDavid du Colombier 		dnslog("%d: rcvd %I qd %s", id, addr, rp->owner->name);
8737dd7cddfSDavid du Colombier 	for(rp = mp->an; rp != nil; rp = rp->next)
874*4f8f669cSDavid du Colombier 		dnslog("%d: rcvd %I an %R", id, addr, rp);
8757dd7cddfSDavid du Colombier 	for(rp = mp->ns; rp != nil; rp = rp->next)
876*4f8f669cSDavid du Colombier 		dnslog("%d: rcvd %I ns %R", id, addr, rp);
8777dd7cddfSDavid du Colombier 	for(rp = mp->ar; rp != nil; rp = rp->next)
878*4f8f669cSDavid du Colombier 		dnslog("%d: rcvd %I ar %R", id, addr, rp);
8793e12c5d1SDavid du Colombier }
8807dd7cddfSDavid du Colombier 
8817dd7cddfSDavid du Colombier void
8827dd7cddfSDavid du Colombier logsend(int id, int subid, uchar *addr, char *sname, char *rname, int type)
8837dd7cddfSDavid du Colombier {
8847dd7cddfSDavid du Colombier 	char buf[12];
8857dd7cddfSDavid du Colombier 
886*4f8f669cSDavid du Colombier 	dnslog("[%d] %d.%d: sending to %I/%s %s %s",
887*4f8f669cSDavid du Colombier 		getpid(), id, subid, addr, sname, rname,
888*4f8f669cSDavid du Colombier 		rrname(type, buf, sizeof buf));
8897dd7cddfSDavid du Colombier }
8907dd7cddfSDavid du Colombier 
8917dd7cddfSDavid du Colombier RR*
8927dd7cddfSDavid du Colombier getdnsservers(int class)
8937dd7cddfSDavid du Colombier {
8947dd7cddfSDavid du Colombier 	return dnsservers(class);
8953e12c5d1SDavid du Colombier }
896