xref: /plan9/sys/src/cmd/ndb/cs.c (revision 3ff48bf5ed603850fcd251ddf13025d23d693782)
13e12c5d1SDavid du Colombier #include <u.h>
23e12c5d1SDavid du Colombier #include <libc.h>
3219b2ee8SDavid du Colombier #include <auth.h>
43e12c5d1SDavid du Colombier #include <fcall.h>
53e12c5d1SDavid du Colombier #include <bio.h>
63e12c5d1SDavid du Colombier #include <ctype.h>
73e12c5d1SDavid du Colombier #include <ndb.h>
83e12c5d1SDavid du Colombier #include <ip.h>
93e12c5d1SDavid du Colombier 
103e12c5d1SDavid du Colombier enum
113e12c5d1SDavid du Colombier {
1280ee5cbfSDavid du Colombier 	Nreply=			20,
133e12c5d1SDavid du Colombier 	Maxreply=		256,
147dd7cddfSDavid du Colombier 	Maxrequest=		128,
157dd7cddfSDavid du Colombier 	Maxpath=		128,
169a747e4fSDavid du Colombier 	Maxfdata=		8192,
173e12c5d1SDavid du Colombier 
189a747e4fSDavid du Colombier 	Qdir=			0,
193e12c5d1SDavid du Colombier 	Qcs=			1,
203e12c5d1SDavid du Colombier };
213e12c5d1SDavid du Colombier 
223e12c5d1SDavid du Colombier typedef struct Mfile	Mfile;
23219b2ee8SDavid du Colombier typedef struct Mlist	Mlist;
243e12c5d1SDavid du Colombier typedef struct Network	Network;
257dd7cddfSDavid du Colombier typedef struct Flushreq	Flushreq;
267dd7cddfSDavid du Colombier typedef struct Job	Job;
273e12c5d1SDavid du Colombier 
283e12c5d1SDavid du Colombier int vers;		/* incremented each clone/attach */
293e12c5d1SDavid du Colombier 
303e12c5d1SDavid du Colombier struct Mfile
313e12c5d1SDavid du Colombier {
323e12c5d1SDavid du Colombier 	int		busy;
33219b2ee8SDavid du Colombier 
349a747e4fSDavid du Colombier 	char		*user;
353e12c5d1SDavid du Colombier 	Qid		qid;
363e12c5d1SDavid du Colombier 	int		fid;
373e12c5d1SDavid du Colombier 
3880ee5cbfSDavid du Colombier 	/*
3980ee5cbfSDavid du Colombier 	 *  current request
4080ee5cbfSDavid du Colombier 	 */
4180ee5cbfSDavid du Colombier 	char		*net;
4280ee5cbfSDavid du Colombier 	char		*host;
4380ee5cbfSDavid du Colombier 	char		*serv;
4480ee5cbfSDavid du Colombier 	char		*rem;
4580ee5cbfSDavid du Colombier 
4680ee5cbfSDavid du Colombier 	/*
4780ee5cbfSDavid du Colombier 	 *  result of the last lookup
4880ee5cbfSDavid du Colombier 	 */
4980ee5cbfSDavid du Colombier 	Network		*nextnet;
50219b2ee8SDavid du Colombier 	int		nreply;
51219b2ee8SDavid du Colombier 	char		*reply[Nreply];
52219b2ee8SDavid du Colombier 	int		replylen[Nreply];
53219b2ee8SDavid du Colombier };
54219b2ee8SDavid du Colombier 
55219b2ee8SDavid du Colombier struct Mlist
56219b2ee8SDavid du Colombier {
57219b2ee8SDavid du Colombier 	Mlist	*next;
58219b2ee8SDavid du Colombier 	Mfile	mf;
593e12c5d1SDavid du Colombier };
603e12c5d1SDavid du Colombier 
619a747e4fSDavid du Colombier 
627dd7cddfSDavid du Colombier //
637dd7cddfSDavid du Colombier //  active requests
647dd7cddfSDavid du Colombier //
657dd7cddfSDavid du Colombier struct Job
667dd7cddfSDavid du Colombier {
677dd7cddfSDavid du Colombier 	Job	*next;
687dd7cddfSDavid du Colombier 	int	flushed;
697dd7cddfSDavid du Colombier 	Fcall	request;
707dd7cddfSDavid du Colombier 	Fcall	reply;
717dd7cddfSDavid du Colombier };
727dd7cddfSDavid du Colombier Lock	joblock;
737dd7cddfSDavid du Colombier Job	*joblist;
747dd7cddfSDavid du Colombier 
75219b2ee8SDavid du Colombier Mlist	*mlist;
763e12c5d1SDavid du Colombier int	mfd[2];
773e12c5d1SDavid du Colombier int	debug;
787dd7cddfSDavid du Colombier int	paranoia;
793e12c5d1SDavid du Colombier jmp_buf	masterjmp;	/* return through here after a slave process has been created */
803e12c5d1SDavid du Colombier int	*isslave;	/* *isslave non-zero means this is a slave process */
81bd389b36SDavid du Colombier char	*dbfile;
827dd7cddfSDavid du Colombier Ndb	*db, *netdb;
833e12c5d1SDavid du Colombier 
849a747e4fSDavid du Colombier void	rversion(Job*);
857dd7cddfSDavid du Colombier void	rflush(Job*);
867dd7cddfSDavid du Colombier void	rattach(Job*, Mfile*);
877dd7cddfSDavid du Colombier char*	rwalk(Job*, Mfile*);
887dd7cddfSDavid du Colombier void	ropen(Job*, Mfile*);
897dd7cddfSDavid du Colombier void	rcreate(Job*, Mfile*);
907dd7cddfSDavid du Colombier void	rread(Job*, Mfile*);
917dd7cddfSDavid du Colombier void	rwrite(Job*, Mfile*);
927dd7cddfSDavid du Colombier void	rclunk(Job*, Mfile*);
937dd7cddfSDavid du Colombier void	rremove(Job*, Mfile*);
947dd7cddfSDavid du Colombier void	rstat(Job*, Mfile*);
957dd7cddfSDavid du Colombier void	rwstat(Job*, Mfile*);
969a747e4fSDavid du Colombier void	rauth(Job*);
977dd7cddfSDavid du Colombier void	sendmsg(Job*, char*);
983e12c5d1SDavid du Colombier void	error(char*);
997dd7cddfSDavid du Colombier void	mountinit(char*, char*);
1003e12c5d1SDavid du Colombier void	io(void);
1017dd7cddfSDavid du Colombier void	ndbinit(void);
1027dd7cddfSDavid du Colombier void	netinit(int);
1033e12c5d1SDavid du Colombier void	netadd(char*);
104219b2ee8SDavid du Colombier char	*genquery(Mfile*, char*);
1057dd7cddfSDavid du Colombier char*	ipinfoquery(Mfile*, char**, int);
106bd389b36SDavid du Colombier int	needproto(Network*, Ndbtuple*);
1079a747e4fSDavid du Colombier int	lookup(Mfile*);
1083e12c5d1SDavid du Colombier Ndbtuple*	reorder(Ndbtuple*, Ndbtuple*);
1097dd7cddfSDavid du Colombier void	ipid(void);
1107dd7cddfSDavid du Colombier void	readipinterfaces(void);
1117dd7cddfSDavid du Colombier void*	emalloc(int);
1129a747e4fSDavid du Colombier char*	estrdup(char*);
1137dd7cddfSDavid du Colombier Job*	newjob(void);
1147dd7cddfSDavid du Colombier void	freejob(Job*);
1157dd7cddfSDavid du Colombier void	setext(char*, int, char*);
11680ee5cbfSDavid du Colombier void	cleanmf(Mfile*);
1173e12c5d1SDavid du Colombier 
118bd389b36SDavid du Colombier extern void	paralloc(void);
119bd389b36SDavid du Colombier 
120bd389b36SDavid du Colombier Lock	dblock;		/* mutex on database operations */
1217dd7cddfSDavid du Colombier Lock	netlock;	/* mutex for netinit() */
122bd389b36SDavid du Colombier 
123219b2ee8SDavid du Colombier char	*logfile = "cs";
1247dd7cddfSDavid du Colombier char	*paranoiafile = "cs.paranoia";
125219b2ee8SDavid du Colombier 
1267dd7cddfSDavid du Colombier char	mntpt[Maxpath];
1277dd7cddfSDavid du Colombier char	netndb[Maxpath];
1287dd7cddfSDavid du Colombier 
12980ee5cbfSDavid du Colombier /*
13080ee5cbfSDavid du Colombier  *  Network specific translators
13180ee5cbfSDavid du Colombier  */
13280ee5cbfSDavid du Colombier Ndbtuple*	iplookup(Network*, char*, char*, int);
13380ee5cbfSDavid du Colombier char*		iptrans(Ndbtuple*, Network*, char*, char*, int);
13480ee5cbfSDavid du Colombier Ndbtuple*	telcolookup(Network*, char*, char*, int);
13580ee5cbfSDavid du Colombier char*		telcotrans(Ndbtuple*, Network*, char*, char*, int);
13680ee5cbfSDavid du Colombier Ndbtuple*	dnsiplookup(char*, Ndbs*);
13780ee5cbfSDavid du Colombier 
13880ee5cbfSDavid du Colombier struct Network
13980ee5cbfSDavid du Colombier {
14080ee5cbfSDavid du Colombier 	char		*net;
14180ee5cbfSDavid du Colombier 	Ndbtuple	*(*lookup)(Network*, char*, char*, int);
14280ee5cbfSDavid du Colombier 	char		*(*trans)(Ndbtuple*, Network*, char*, char*, int);
14380ee5cbfSDavid du Colombier 	int		considered;
14480ee5cbfSDavid du Colombier 	int		fasttimeouthack;
14580ee5cbfSDavid du Colombier 	Network		*next;
14680ee5cbfSDavid du Colombier };
14780ee5cbfSDavid du Colombier 
14880ee5cbfSDavid du Colombier enum
14980ee5cbfSDavid du Colombier {
15080ee5cbfSDavid du Colombier 	Nilfast,
15180ee5cbfSDavid du Colombier 	Ntcp,
15280ee5cbfSDavid du Colombier 	Nil,
15380ee5cbfSDavid du Colombier 	Nudp,
15480ee5cbfSDavid du Colombier 	Nicmp,
15580ee5cbfSDavid du Colombier 	Nrudp,
15680ee5cbfSDavid du Colombier 	Ntelco,
15780ee5cbfSDavid du Colombier };
15880ee5cbfSDavid du Colombier 
15980ee5cbfSDavid du Colombier /*
16080ee5cbfSDavid du Colombier  *  net doesn't apply to udp, icmp, or telco (for speed)
16180ee5cbfSDavid du Colombier  */
16280ee5cbfSDavid du Colombier Network network[] = {
16380ee5cbfSDavid du Colombier [Nilfast]	{ "il",		iplookup,	iptrans,	0, 1 },
16480ee5cbfSDavid du Colombier [Ntcp]		{ "tcp",	iplookup,	iptrans,	0, 0 },
16580ee5cbfSDavid du Colombier [Nil]		{ "il",		iplookup,	iptrans,	0, 0 },
16680ee5cbfSDavid du Colombier [Nudp]		{ "udp",	iplookup,	iptrans,	1, 0 },
16780ee5cbfSDavid du Colombier [Nicmp]		{ "icmp",	iplookup,	iptrans,	1, 0 },
16880ee5cbfSDavid du Colombier [Nrudp]		{ "rudp",	iplookup,	iptrans,	1, 0 },
16980ee5cbfSDavid du Colombier [Ntelco]	{ "telco",	telcolookup,	telcotrans,	1, 0 },
17080ee5cbfSDavid du Colombier 		{ 0 },
17180ee5cbfSDavid du Colombier };
17280ee5cbfSDavid du Colombier 
17380ee5cbfSDavid du Colombier Lock ipifclock;
17480ee5cbfSDavid du Colombier Ipifc *ipifcs;
17580ee5cbfSDavid du Colombier 
17680ee5cbfSDavid du Colombier char	eaddr[Ndbvlen];		/* ascii ethernet address */
17780ee5cbfSDavid du Colombier char	ipaddr[Ndbvlen];	/* ascii internet address */
17880ee5cbfSDavid du Colombier uchar	ipa[IPaddrlen];		/* binary internet address */
17980ee5cbfSDavid du Colombier char	mysysname[Ndbvlen];
18080ee5cbfSDavid du Colombier 
18180ee5cbfSDavid du Colombier Network *netlist;		/* networks ordered by preference */
18280ee5cbfSDavid du Colombier Network *last;
18380ee5cbfSDavid du Colombier 
1847dd7cddfSDavid du Colombier void
1857dd7cddfSDavid du Colombier usage(void)
1867dd7cddfSDavid du Colombier {
1877dd7cddfSDavid du Colombier 	fprint(2, "usage: %s [-d] [-f ndb-file] [-x netmtpt] [-n]\n", argv0);
1887dd7cddfSDavid du Colombier 	exits("usage");
1897dd7cddfSDavid du Colombier }
190219b2ee8SDavid du Colombier 
1913e12c5d1SDavid du Colombier void
1923e12c5d1SDavid du Colombier main(int argc, char *argv[])
1933e12c5d1SDavid du Colombier {
1947dd7cddfSDavid du Colombier 	char servefile[Maxpath];
195219b2ee8SDavid du Colombier 	int justsetname;
1967dd7cddfSDavid du Colombier 	char *p;
1977dd7cddfSDavid du Colombier 	char ext[Maxpath];
1983e12c5d1SDavid du Colombier 
199219b2ee8SDavid du Colombier 	justsetname = 0;
2007dd7cddfSDavid du Colombier 	setnetmtpt(mntpt, sizeof(mntpt), nil);
2017dd7cddfSDavid du Colombier 	ext[0] = 0;
2023e12c5d1SDavid du Colombier 	ARGBEGIN{
2033e12c5d1SDavid du Colombier 	case 'd':
2043e12c5d1SDavid du Colombier 		debug = 1;
2053e12c5d1SDavid du Colombier 		break;
206bd389b36SDavid du Colombier 	case 'f':
2077dd7cddfSDavid du Colombier 		p = ARGF();
2087dd7cddfSDavid du Colombier 		if(p == nil)
2097dd7cddfSDavid du Colombier 			usage();
2107dd7cddfSDavid du Colombier 		dbfile = p;
2117dd7cddfSDavid du Colombier 		break;
2127dd7cddfSDavid du Colombier 	case 'x':
2137dd7cddfSDavid du Colombier 		p = ARGF();
2147dd7cddfSDavid du Colombier 		if(p == nil)
2157dd7cddfSDavid du Colombier 			usage();
2167dd7cddfSDavid du Colombier 		setnetmtpt(mntpt, sizeof(mntpt), p);
2177dd7cddfSDavid du Colombier 		setext(ext, sizeof(ext), mntpt);
218bd389b36SDavid du Colombier 		break;
219219b2ee8SDavid du Colombier 	case 'n':
220219b2ee8SDavid du Colombier 		justsetname = 1;
221219b2ee8SDavid du Colombier 		break;
2223e12c5d1SDavid du Colombier 	}ARGEND
2233e12c5d1SDavid du Colombier 	USED(argc);
2243e12c5d1SDavid du Colombier 	USED(argv);
2253e12c5d1SDavid du Colombier 
2267dd7cddfSDavid du Colombier 	rfork(RFREND|RFNOTEG);
2277dd7cddfSDavid du Colombier 
2287dd7cddfSDavid du Colombier 	snprint(servefile, sizeof(servefile), "#s/cs%s", ext);
2297dd7cddfSDavid du Colombier 	snprint(netndb, sizeof(netndb), "%s/ndb", mntpt);
2307dd7cddfSDavid du Colombier 	unmount(servefile, mntpt);
2317dd7cddfSDavid du Colombier 	remove(servefile);
2327dd7cddfSDavid du Colombier 
2339a747e4fSDavid du Colombier 	fmtinstall('E', eipfmt);
2349a747e4fSDavid du Colombier 	fmtinstall('I', eipfmt);
2359a747e4fSDavid du Colombier 	fmtinstall('M', eipfmt);
2369a747e4fSDavid du Colombier 	fmtinstall('F', fcallfmt);
2377dd7cddfSDavid du Colombier 
2387dd7cddfSDavid du Colombier 	ndbinit();
2397dd7cddfSDavid du Colombier 	netinit(0);
2407dd7cddfSDavid du Colombier 
2417dd7cddfSDavid du Colombier 	if(!justsetname){
2427dd7cddfSDavid du Colombier 		mountinit(servefile, mntpt);
2437dd7cddfSDavid du Colombier 		io();
2447dd7cddfSDavid du Colombier 	}
245219b2ee8SDavid du Colombier 	exits(0);
246219b2ee8SDavid du Colombier }
247219b2ee8SDavid du Colombier 
2487dd7cddfSDavid du Colombier /*
2497dd7cddfSDavid du Colombier  *  if a mount point is specified, set the cs extention to be the mount point
2507dd7cddfSDavid du Colombier  *  with '_'s replacing '/'s
2517dd7cddfSDavid du Colombier  */
2527dd7cddfSDavid du Colombier void
2537dd7cddfSDavid du Colombier setext(char *ext, int n, char *p)
2547dd7cddfSDavid du Colombier {
2557dd7cddfSDavid du Colombier 	int i, c;
2563e12c5d1SDavid du Colombier 
2577dd7cddfSDavid du Colombier 	n--;
2587dd7cddfSDavid du Colombier 	for(i = 0; i < n; i++){
2597dd7cddfSDavid du Colombier 		c = p[i];
2607dd7cddfSDavid du Colombier 		if(c == 0)
2617dd7cddfSDavid du Colombier 			break;
2627dd7cddfSDavid du Colombier 		if(c == '/')
2637dd7cddfSDavid du Colombier 			c = '_';
2647dd7cddfSDavid du Colombier 		ext[i] = c;
2657dd7cddfSDavid du Colombier 	}
2667dd7cddfSDavid du Colombier 	ext[i] = 0;
2673e12c5d1SDavid du Colombier }
2683e12c5d1SDavid du Colombier 
2693e12c5d1SDavid du Colombier void
2707dd7cddfSDavid du Colombier mountinit(char *service, char *mntpt)
2713e12c5d1SDavid du Colombier {
2723e12c5d1SDavid du Colombier 	int f;
2733e12c5d1SDavid du Colombier 	int p[2];
2743e12c5d1SDavid du Colombier 	char buf[32];
2753e12c5d1SDavid du Colombier 
2763e12c5d1SDavid du Colombier 	if(pipe(p) < 0)
2773e12c5d1SDavid du Colombier 		error("pipe failed");
278219b2ee8SDavid du Colombier 	switch(rfork(RFFDG|RFPROC|RFNAMEG)){
2793e12c5d1SDavid du Colombier 	case 0:
280219b2ee8SDavid du Colombier 		close(p[1]);
2813e12c5d1SDavid du Colombier 		break;
2823e12c5d1SDavid du Colombier 	case -1:
2833e12c5d1SDavid du Colombier 		error("fork failed\n");
2843e12c5d1SDavid du Colombier 	default:
2853e12c5d1SDavid du Colombier 		/*
2863e12c5d1SDavid du Colombier 		 *  make a /srv/cs
2873e12c5d1SDavid du Colombier 		 */
2883e12c5d1SDavid du Colombier 		f = create(service, 1, 0666);
2893e12c5d1SDavid du Colombier 		if(f < 0)
2903e12c5d1SDavid du Colombier 			error(service);
291bd389b36SDavid du Colombier 		snprint(buf, sizeof(buf), "%d", p[1]);
2923e12c5d1SDavid du Colombier 		if(write(f, buf, strlen(buf)) != strlen(buf))
293219b2ee8SDavid du Colombier 			error("write /srv/cs");
2943e12c5d1SDavid du Colombier 		close(f);
2953e12c5d1SDavid du Colombier 
2963e12c5d1SDavid du Colombier 		/*
2973e12c5d1SDavid du Colombier 		 *  put ourselves into the file system
2983e12c5d1SDavid du Colombier 		 */
299219b2ee8SDavid du Colombier 		close(p[0]);
3009a747e4fSDavid du Colombier 		if(mount(p[1], -1, mntpt, MAFTER, "") < 0)
3013e12c5d1SDavid du Colombier 			error("mount failed\n");
302219b2ee8SDavid du Colombier 		_exits(0);
3033e12c5d1SDavid du Colombier 	}
3043e12c5d1SDavid du Colombier 	mfd[0] = mfd[1] = p[0];
3053e12c5d1SDavid du Colombier }
3063e12c5d1SDavid du Colombier 
3077dd7cddfSDavid du Colombier void
3087dd7cddfSDavid du Colombier ndbinit(void)
3097dd7cddfSDavid du Colombier {
3107dd7cddfSDavid du Colombier 	db = ndbopen(dbfile);
3117dd7cddfSDavid du Colombier 	if(db == nil)
3127dd7cddfSDavid du Colombier 		error("can't open network database");
3137dd7cddfSDavid du Colombier 
3147dd7cddfSDavid du Colombier 	netdb = ndbopen(netndb);
3157dd7cddfSDavid du Colombier 	if(netdb != nil){
3167dd7cddfSDavid du Colombier 		netdb->nohash = 1;
3177dd7cddfSDavid du Colombier 		db = ndbcat(netdb, db);
3187dd7cddfSDavid du Colombier 	}
3197dd7cddfSDavid du Colombier }
3207dd7cddfSDavid du Colombier 
3213e12c5d1SDavid du Colombier Mfile*
3223e12c5d1SDavid du Colombier newfid(int fid)
3233e12c5d1SDavid du Colombier {
324219b2ee8SDavid du Colombier 	Mlist *f, *ff;
3253e12c5d1SDavid du Colombier 	Mfile *mf;
3263e12c5d1SDavid du Colombier 
327219b2ee8SDavid du Colombier 	ff = 0;
328219b2ee8SDavid du Colombier 	for(f = mlist; f; f = f->next)
329219b2ee8SDavid du Colombier 		if(f->mf.busy && f->mf.fid == fid)
330219b2ee8SDavid du Colombier 			return &f->mf;
331219b2ee8SDavid du Colombier 		else if(!ff && !f->mf.busy)
332219b2ee8SDavid du Colombier 			ff = f;
333219b2ee8SDavid du Colombier 	if(ff == 0){
3347dd7cddfSDavid du Colombier 		ff = emalloc(sizeof *f);
335219b2ee8SDavid du Colombier 		ff->next = mlist;
336219b2ee8SDavid du Colombier 		mlist = ff;
3373e12c5d1SDavid du Colombier 	}
338219b2ee8SDavid du Colombier 	mf = &ff->mf;
339219b2ee8SDavid du Colombier 	memset(mf, 0, sizeof *mf);
3403e12c5d1SDavid du Colombier 	mf->fid = fid;
3413e12c5d1SDavid du Colombier 	return mf;
3423e12c5d1SDavid du Colombier }
3433e12c5d1SDavid du Colombier 
3447dd7cddfSDavid du Colombier Job*
3457dd7cddfSDavid du Colombier newjob(void)
3467dd7cddfSDavid du Colombier {
3477dd7cddfSDavid du Colombier 	Job *job;
3487dd7cddfSDavid du Colombier 
3497dd7cddfSDavid du Colombier 	job = mallocz(sizeof(Job), 1);
3507dd7cddfSDavid du Colombier 	lock(&joblock);
3517dd7cddfSDavid du Colombier 	job->next = joblist;
3527dd7cddfSDavid du Colombier 	joblist = job;
3537dd7cddfSDavid du Colombier 	job->request.tag = -1;
3547dd7cddfSDavid du Colombier 	unlock(&joblock);
3557dd7cddfSDavid du Colombier 	return job;
3567dd7cddfSDavid du Colombier }
3577dd7cddfSDavid du Colombier 
3587dd7cddfSDavid du Colombier void
3597dd7cddfSDavid du Colombier freejob(Job *job)
3607dd7cddfSDavid du Colombier {
3617dd7cddfSDavid du Colombier 	Job **l;
3627dd7cddfSDavid du Colombier 
3637dd7cddfSDavid du Colombier 	lock(&joblock);
3647dd7cddfSDavid du Colombier 	for(l = &joblist; *l; l = &(*l)->next){
3657dd7cddfSDavid du Colombier 		if((*l) == job){
3667dd7cddfSDavid du Colombier 			*l = job->next;
3677dd7cddfSDavid du Colombier 			free(job);
3687dd7cddfSDavid du Colombier 			break;
3697dd7cddfSDavid du Colombier 		}
3707dd7cddfSDavid du Colombier 	}
3717dd7cddfSDavid du Colombier 	unlock(&joblock);
3727dd7cddfSDavid du Colombier }
3737dd7cddfSDavid du Colombier 
3747dd7cddfSDavid du Colombier void
3757dd7cddfSDavid du Colombier flushjob(int tag)
3767dd7cddfSDavid du Colombier {
3777dd7cddfSDavid du Colombier 	Job *job;
3787dd7cddfSDavid du Colombier 
3797dd7cddfSDavid du Colombier 	lock(&joblock);
3807dd7cddfSDavid du Colombier 	for(job = joblist; job; job = job->next){
3817dd7cddfSDavid du Colombier 		if(job->request.tag == tag && job->request.type != Tflush){
3827dd7cddfSDavid du Colombier 			job->flushed = 1;
3837dd7cddfSDavid du Colombier 			break;
3847dd7cddfSDavid du Colombier 		}
3857dd7cddfSDavid du Colombier 	}
3867dd7cddfSDavid du Colombier 	unlock(&joblock);
3877dd7cddfSDavid du Colombier }
3887dd7cddfSDavid du Colombier 
3893e12c5d1SDavid du Colombier void
3903e12c5d1SDavid du Colombier io(void)
3913e12c5d1SDavid du Colombier {
3923e12c5d1SDavid du Colombier 	long n;
3933e12c5d1SDavid du Colombier 	Mfile *mf;
3943e12c5d1SDavid du Colombier 	int slaveflag;
3959a747e4fSDavid du Colombier 	uchar mdata[IOHDRSZ + Maxfdata];
3967dd7cddfSDavid du Colombier 	Job *job;
3973e12c5d1SDavid du Colombier 
3983e12c5d1SDavid du Colombier 	/*
3993e12c5d1SDavid du Colombier 	 *  if we ask dns to fulfill requests,
4003e12c5d1SDavid du Colombier 	 *  a slave process is created to wait for replies.  The
4019a747e4fSDavid du Colombier 	 *  master process returns immediately via a longjmp
4023e12c5d1SDavid du Colombier 	 *  through 'masterjmp'.
4033e12c5d1SDavid du Colombier 	 *
4043e12c5d1SDavid du Colombier 	 *  *isslave is a pointer into the call stack to a variable
4053e12c5d1SDavid du Colombier 	 *  that tells whether or not the current process is a slave.
4063e12c5d1SDavid du Colombier 	 */
4073e12c5d1SDavid du Colombier 	slaveflag = 0;		/* init slave variable */
4083e12c5d1SDavid du Colombier 	isslave = &slaveflag;
4093e12c5d1SDavid du Colombier 	setjmp(masterjmp);
4103e12c5d1SDavid du Colombier 
4113e12c5d1SDavid du Colombier 	for(;;){
4129a747e4fSDavid du Colombier 		n = read9pmsg(mfd[0], mdata, sizeof mdata);
4133e12c5d1SDavid du Colombier 		if(n<=0)
4143e12c5d1SDavid du Colombier 			error("mount read");
4157dd7cddfSDavid du Colombier 		job = newjob();
4169a747e4fSDavid du Colombier 		if(convM2S(mdata, n, &job->request) != n){
417219b2ee8SDavid du Colombier 			syslog(1, logfile, "format error %ux %ux %ux %ux %ux", mdata[0], mdata[1], mdata[2], mdata[3], mdata[4]);
4187dd7cddfSDavid du Colombier 			freejob(job);
4193e12c5d1SDavid du Colombier 			continue;
4203e12c5d1SDavid du Colombier 		}
4217dd7cddfSDavid du Colombier 		if(job->request.fid<0)
4223e12c5d1SDavid du Colombier 			error("fid out of range");
423bd389b36SDavid du Colombier 		lock(&dblock);
4247dd7cddfSDavid du Colombier 		mf = newfid(job->request.fid);
425219b2ee8SDavid du Colombier 		if(debug)
4267dd7cddfSDavid du Colombier 			syslog(0, logfile, "%F", &job->request);
4273e12c5d1SDavid du Colombier 
4283e12c5d1SDavid du Colombier 
4297dd7cddfSDavid du Colombier 		switch(job->request.type){
4303e12c5d1SDavid du Colombier 		default:
4317dd7cddfSDavid du Colombier 			syslog(1, logfile, "unknown request type %d", job->request.type);
4323e12c5d1SDavid du Colombier 			break;
4339a747e4fSDavid du Colombier 		case Tversion:
4349a747e4fSDavid du Colombier 			rversion(job);
4353e12c5d1SDavid du Colombier 			break;
4369a747e4fSDavid du Colombier 		case Tauth:
4379a747e4fSDavid du Colombier 			rauth(job);
4383e12c5d1SDavid du Colombier 			break;
4393e12c5d1SDavid du Colombier 		case Tflush:
4407dd7cddfSDavid du Colombier 			rflush(job);
4413e12c5d1SDavid du Colombier 			break;
4423e12c5d1SDavid du Colombier 		case Tattach:
4437dd7cddfSDavid du Colombier 			rattach(job, mf);
4443e12c5d1SDavid du Colombier 			break;
4453e12c5d1SDavid du Colombier 		case Twalk:
4467dd7cddfSDavid du Colombier 			rwalk(job, mf);
4473e12c5d1SDavid du Colombier 			break;
4483e12c5d1SDavid du Colombier 		case Topen:
4497dd7cddfSDavid du Colombier 			ropen(job, mf);
4503e12c5d1SDavid du Colombier 			break;
4513e12c5d1SDavid du Colombier 		case Tcreate:
4527dd7cddfSDavid du Colombier 			rcreate(job, mf);
4533e12c5d1SDavid du Colombier 			break;
4543e12c5d1SDavid du Colombier 		case Tread:
4557dd7cddfSDavid du Colombier 			rread(job, mf);
4563e12c5d1SDavid du Colombier 			break;
4573e12c5d1SDavid du Colombier 		case Twrite:
4587dd7cddfSDavid du Colombier 			rwrite(job, mf);
4593e12c5d1SDavid du Colombier 			break;
4603e12c5d1SDavid du Colombier 		case Tclunk:
4617dd7cddfSDavid du Colombier 			rclunk(job, mf);
4623e12c5d1SDavid du Colombier 			break;
4633e12c5d1SDavid du Colombier 		case Tremove:
4647dd7cddfSDavid du Colombier 			rremove(job, mf);
4653e12c5d1SDavid du Colombier 			break;
4663e12c5d1SDavid du Colombier 		case Tstat:
4677dd7cddfSDavid du Colombier 			rstat(job, mf);
4683e12c5d1SDavid du Colombier 			break;
4693e12c5d1SDavid du Colombier 		case Twstat:
4707dd7cddfSDavid du Colombier 			rwstat(job, mf);
4713e12c5d1SDavid du Colombier 			break;
4723e12c5d1SDavid du Colombier 		}
473bd389b36SDavid du Colombier 		unlock(&dblock);
4747dd7cddfSDavid du Colombier 
4757dd7cddfSDavid du Colombier 		freejob(job);
4767dd7cddfSDavid du Colombier 
4773e12c5d1SDavid du Colombier 		/*
4783e12c5d1SDavid du Colombier 		 *  slave processes die after replying
4793e12c5d1SDavid du Colombier 		 */
480219b2ee8SDavid du Colombier 		if(*isslave){
481219b2ee8SDavid du Colombier 			if(debug)
482219b2ee8SDavid du Colombier 				syslog(0, logfile, "slave death %d", getpid());
4833e12c5d1SDavid du Colombier 			_exits(0);
4843e12c5d1SDavid du Colombier 		}
4853e12c5d1SDavid du Colombier 	}
486219b2ee8SDavid du Colombier }
487219b2ee8SDavid du Colombier 
488219b2ee8SDavid du Colombier void
4899a747e4fSDavid du Colombier rversion(Job *job)
490219b2ee8SDavid du Colombier {
4919a747e4fSDavid du Colombier 	if(job->request.msize > IOHDRSZ + Maxfdata)
4929a747e4fSDavid du Colombier 		job->reply.msize = IOHDRSZ + Maxfdata;
4939a747e4fSDavid du Colombier 	else
4949a747e4fSDavid du Colombier 		job->reply.msize = job->request.msize;
4959a747e4fSDavid du Colombier 	if(strncmp(job->request.version, "9P2000", 6) != 0)
4969a747e4fSDavid du Colombier 		sendmsg(job, "unknown 9P version");
4979a747e4fSDavid du Colombier 	else{
4989a747e4fSDavid du Colombier 		job->reply.version = "9P2000";
4997dd7cddfSDavid du Colombier 		sendmsg(job, 0);
500219b2ee8SDavid du Colombier 	}
5019a747e4fSDavid du Colombier }
5023e12c5d1SDavid du Colombier 
5033e12c5d1SDavid du Colombier void
5049a747e4fSDavid du Colombier rauth(Job *job)
5053e12c5d1SDavid du Colombier {
506*3ff48bf5SDavid du Colombier 	sendmsg(job, "cs: authentication not required");
5077dd7cddfSDavid du Colombier }
5087dd7cddfSDavid du Colombier 
5097dd7cddfSDavid du Colombier /*
5107dd7cddfSDavid du Colombier  *  don't flush till all the slaves are done
5117dd7cddfSDavid du Colombier  */
5127dd7cddfSDavid du Colombier void
5137dd7cddfSDavid du Colombier rflush(Job *job)
5147dd7cddfSDavid du Colombier {
5157dd7cddfSDavid du Colombier 	flushjob(job->request.oldtag);
5167dd7cddfSDavid du Colombier 	sendmsg(job, 0);
5173e12c5d1SDavid du Colombier }
5183e12c5d1SDavid du Colombier 
5193e12c5d1SDavid du Colombier void
5207dd7cddfSDavid du Colombier rattach(Job *job, Mfile *mf)
5213e12c5d1SDavid du Colombier {
5223e12c5d1SDavid du Colombier 	if(mf->busy == 0){
5233e12c5d1SDavid du Colombier 		mf->busy = 1;
5249a747e4fSDavid du Colombier 		mf->user = estrdup(job->request.uname);
5253e12c5d1SDavid du Colombier 	}
5263e12c5d1SDavid du Colombier 	mf->qid.vers = vers++;
5279a747e4fSDavid du Colombier 	mf->qid.type = QTDIR;
5289a747e4fSDavid du Colombier 	mf->qid.path = 0LL;
5297dd7cddfSDavid du Colombier 	job->reply.qid = mf->qid;
5307dd7cddfSDavid du Colombier 	sendmsg(job, 0);
5313e12c5d1SDavid du Colombier }
5323e12c5d1SDavid du Colombier 
5333e12c5d1SDavid du Colombier 
5343e12c5d1SDavid du Colombier char*
5357dd7cddfSDavid du Colombier rwalk(Job *job, Mfile *mf)
5363e12c5d1SDavid du Colombier {
5373e12c5d1SDavid du Colombier 	char *err;
5389a747e4fSDavid du Colombier 	char **elems;
5399a747e4fSDavid du Colombier 	int nelems;
5409a747e4fSDavid du Colombier 	int i;
5419a747e4fSDavid du Colombier 	Mfile *nmf;
5429a747e4fSDavid du Colombier 	Qid qid;
5433e12c5d1SDavid du Colombier 
5443e12c5d1SDavid du Colombier 	err = 0;
5459a747e4fSDavid du Colombier 	nmf = nil;
5469a747e4fSDavid du Colombier 	elems = job->request.wname;
5479a747e4fSDavid du Colombier 	nelems = job->request.nwname;
5489a747e4fSDavid du Colombier 	job->reply.nwqid = 0;
5499a747e4fSDavid du Colombier 
5509a747e4fSDavid du Colombier 	if(job->request.newfid != job->request.fid){
5519a747e4fSDavid du Colombier 		/* clone fid */
5529a747e4fSDavid du Colombier 		if(job->request.newfid<0){
5539a747e4fSDavid du Colombier 			err = "clone newfid out of range";
5549a747e4fSDavid du Colombier 			goto send;
5559a747e4fSDavid du Colombier 		}
5569a747e4fSDavid du Colombier 		nmf = newfid(job->request.newfid);
5579a747e4fSDavid du Colombier 		if(nmf->busy){
5589a747e4fSDavid du Colombier 			nmf = nil;
5599a747e4fSDavid du Colombier 			err = "clone to used channel";
5609a747e4fSDavid du Colombier 			goto send;
5619a747e4fSDavid du Colombier 		}
5629a747e4fSDavid du Colombier 		*nmf = *mf;
5639a747e4fSDavid du Colombier 		nmf->user = estrdup(mf->user);
5649a747e4fSDavid du Colombier 		nmf->fid = job->request.newfid;
5659a747e4fSDavid du Colombier 		nmf->qid.vers = vers++;
5669a747e4fSDavid du Colombier 		mf = nmf;
5679a747e4fSDavid du Colombier 	}
5689a747e4fSDavid du Colombier 	/* else nmf will be nil */
5699a747e4fSDavid du Colombier 
5709a747e4fSDavid du Colombier 	qid = mf->qid;
5719a747e4fSDavid du Colombier 	if(nelems > 0){
5729a747e4fSDavid du Colombier 		/* walk fid */
5739a747e4fSDavid du Colombier 		for(i=0; i<nelems && i<MAXWELEM; i++){
5749a747e4fSDavid du Colombier 			if((qid.type & QTDIR) == 0){
5753e12c5d1SDavid du Colombier 				err = "not a directory";
5769a747e4fSDavid du Colombier 				break;
5773e12c5d1SDavid du Colombier 			}
5789a747e4fSDavid du Colombier 			if(strcmp(elems[i], "..") == 0 || strcmp(elems[i], ".") == 0){
5799a747e4fSDavid du Colombier 				qid.type = QTDIR;
5809a747e4fSDavid du Colombier 				qid.path = Qdir;
5819a747e4fSDavid du Colombier     Found:
5829a747e4fSDavid du Colombier 				job->reply.wqid[i] = qid;
5839a747e4fSDavid du Colombier 				job->reply.nwqid++;
5849a747e4fSDavid du Colombier 				continue;
5853e12c5d1SDavid du Colombier 			}
5869a747e4fSDavid du Colombier 			if(strcmp(elems[i], "cs") == 0){
5879a747e4fSDavid du Colombier 				qid.type = QTFILE;
5889a747e4fSDavid du Colombier 				qid.path = Qcs;
5899a747e4fSDavid du Colombier 				goto Found;
5903e12c5d1SDavid du Colombier 			}
5919a747e4fSDavid du Colombier 			err = "file does not exist";
5929a747e4fSDavid du Colombier 			break;
5939a747e4fSDavid du Colombier 		}
5949a747e4fSDavid du Colombier 	}
5959a747e4fSDavid du Colombier 
5963e12c5d1SDavid du Colombier     send:
5979a747e4fSDavid du Colombier 	if(nmf != nil && (err!=nil || job->reply.nwqid<nelems)){
5989a747e4fSDavid du Colombier 		nmf->busy = 0;
5999a747e4fSDavid du Colombier 		nmf->fid = 0;
6009a747e4fSDavid du Colombier 	}
6019a747e4fSDavid du Colombier 	if(err == nil)
6029a747e4fSDavid du Colombier 		mf->qid = qid;
6037dd7cddfSDavid du Colombier 	sendmsg(job, err);
6043e12c5d1SDavid du Colombier 	return err;
6053e12c5d1SDavid du Colombier }
6063e12c5d1SDavid du Colombier 
6073e12c5d1SDavid du Colombier void
6087dd7cddfSDavid du Colombier ropen(Job *job, Mfile *mf)
6093e12c5d1SDavid du Colombier {
6103e12c5d1SDavid du Colombier 	int mode;
6113e12c5d1SDavid du Colombier 	char *err;
6123e12c5d1SDavid du Colombier 
6133e12c5d1SDavid du Colombier 	err = 0;
6147dd7cddfSDavid du Colombier 	mode = job->request.mode;
6159a747e4fSDavid du Colombier 	if(mf->qid.type & QTDIR){
6163e12c5d1SDavid du Colombier 		if(mode)
6173e12c5d1SDavid du Colombier 			err = "permission denied";
6189a747e4fSDavid du Colombier 	}
6197dd7cddfSDavid du Colombier 	job->reply.qid = mf->qid;
6209a747e4fSDavid du Colombier 	job->reply.iounit = 0;
6217dd7cddfSDavid du Colombier 	sendmsg(job, err);
6223e12c5d1SDavid du Colombier }
6233e12c5d1SDavid du Colombier 
6243e12c5d1SDavid du Colombier void
6257dd7cddfSDavid du Colombier rcreate(Job *job, Mfile *mf)
6263e12c5d1SDavid du Colombier {
6273e12c5d1SDavid du Colombier 	USED(mf);
6287dd7cddfSDavid du Colombier 	sendmsg(job, "creation permission denied");
6293e12c5d1SDavid du Colombier }
6303e12c5d1SDavid du Colombier 
6313e12c5d1SDavid du Colombier void
6327dd7cddfSDavid du Colombier rread(Job *job, Mfile *mf)
6333e12c5d1SDavid du Colombier {
634219b2ee8SDavid du Colombier 	int i, n, cnt;
635219b2ee8SDavid du Colombier 	long off, toff, clock;
6363e12c5d1SDavid du Colombier 	Dir dir;
6379a747e4fSDavid du Colombier 	uchar buf[Maxfdata];
6383e12c5d1SDavid du Colombier 	char *err;
6393e12c5d1SDavid du Colombier 
6403e12c5d1SDavid du Colombier 	n = 0;
6413e12c5d1SDavid du Colombier 	err = 0;
6427dd7cddfSDavid du Colombier 	off = job->request.offset;
6437dd7cddfSDavid du Colombier 	cnt = job->request.count;
6449a747e4fSDavid du Colombier 	if(mf->qid.type & QTDIR){
6453e12c5d1SDavid du Colombier 		clock = time(0);
6463e12c5d1SDavid du Colombier 		if(off == 0){
6479a747e4fSDavid du Colombier 			dir.name = "cs";
6489a747e4fSDavid du Colombier 			dir.qid.type = QTFILE;
6493e12c5d1SDavid du Colombier 			dir.qid.vers = vers;
6503e12c5d1SDavid du Colombier 			dir.qid.path = Qcs;
6513e12c5d1SDavid du Colombier 			dir.mode = 0666;
6523e12c5d1SDavid du Colombier 			dir.length = 0;
6539a747e4fSDavid du Colombier 			dir.uid = mf->user;
6549a747e4fSDavid du Colombier 			dir.gid = mf->user;
6559a747e4fSDavid du Colombier 			dir.muid = mf->user;
6563e12c5d1SDavid du Colombier 			dir.atime = clock;	/* wrong */
6573e12c5d1SDavid du Colombier 			dir.mtime = clock;	/* wrong */
6589a747e4fSDavid du Colombier 			n = convD2M(&dir, buf, sizeof buf);
6593e12c5d1SDavid du Colombier 		}
6609a747e4fSDavid du Colombier 		job->reply.data = (char*)buf;
6613e12c5d1SDavid du Colombier 	} else {
66280ee5cbfSDavid du Colombier 		for(;;){
66380ee5cbfSDavid du Colombier 			/* look for an answer at the right offset */
664219b2ee8SDavid du Colombier 			toff = 0;
665219b2ee8SDavid du Colombier 			for(i = 0; mf->reply[i] && i < mf->nreply; i++){
666219b2ee8SDavid du Colombier 				n = mf->replylen[i];
667219b2ee8SDavid du Colombier 				if(off < toff + n)
668219b2ee8SDavid du Colombier 					break;
669219b2ee8SDavid du Colombier 				toff += n;
6703e12c5d1SDavid du Colombier 			}
67180ee5cbfSDavid du Colombier 			if(i < mf->nreply)
67280ee5cbfSDavid du Colombier 				break;		/* got something to return */
67380ee5cbfSDavid du Colombier 
67480ee5cbfSDavid du Colombier 			/* try looking up more answers */
67580ee5cbfSDavid du Colombier 			if(lookup(mf) == 0){
67680ee5cbfSDavid du Colombier 				/* no more */
677219b2ee8SDavid du Colombier 				n = 0;
678219b2ee8SDavid du Colombier 				goto send;
679219b2ee8SDavid du Colombier 			}
68080ee5cbfSDavid du Colombier 		}
68180ee5cbfSDavid du Colombier 
68280ee5cbfSDavid du Colombier 		/* give back a single reply (or part of one) */
6837dd7cddfSDavid du Colombier 		job->reply.data = mf->reply[i] + (off - toff);
684219b2ee8SDavid du Colombier 		if(cnt > toff - off + n)
685219b2ee8SDavid du Colombier 			n = toff - off + n;
686219b2ee8SDavid du Colombier 		else
687219b2ee8SDavid du Colombier 			n = cnt;
6883e12c5d1SDavid du Colombier 	}
6893e12c5d1SDavid du Colombier send:
6907dd7cddfSDavid du Colombier 	job->reply.count = n;
6917dd7cddfSDavid du Colombier 	sendmsg(job, err);
6927dd7cddfSDavid du Colombier }
69380ee5cbfSDavid du Colombier void
69480ee5cbfSDavid du Colombier cleanmf(Mfile *mf)
6957dd7cddfSDavid du Colombier {
6967dd7cddfSDavid du Colombier 	int i;
6977dd7cddfSDavid du Colombier 
6989a747e4fSDavid du Colombier 	if(mf->net != nil){
69980ee5cbfSDavid du Colombier 		free(mf->net);
70080ee5cbfSDavid du Colombier 		mf->net = nil;
7019a747e4fSDavid du Colombier 	}
7029a747e4fSDavid du Colombier 	if(mf->host != nil){
70380ee5cbfSDavid du Colombier 		free(mf->host);
70480ee5cbfSDavid du Colombier 		mf->host = nil;
7059a747e4fSDavid du Colombier 	}
7069a747e4fSDavid du Colombier 	if(mf->serv != nil){
70780ee5cbfSDavid du Colombier 		free(mf->serv);
70880ee5cbfSDavid du Colombier 		mf->serv = nil;
7099a747e4fSDavid du Colombier 	}
7109a747e4fSDavid du Colombier 	if(mf->rem != nil){
71180ee5cbfSDavid du Colombier 		free(mf->rem);
71280ee5cbfSDavid du Colombier 		mf->rem = nil;
7139a747e4fSDavid du Colombier 	}
7149a747e4fSDavid du Colombier 	if(mf->user != nil){
7159a747e4fSDavid du Colombier 		free(mf->user);
7169a747e4fSDavid du Colombier 		mf->user = nil;
7179a747e4fSDavid du Colombier 	}
71880ee5cbfSDavid du Colombier 	for(i = 0; i < mf->nreply; i++){
71980ee5cbfSDavid du Colombier 		free(mf->reply[i]);
72080ee5cbfSDavid du Colombier 		mf->reply[i] = nil;
72180ee5cbfSDavid du Colombier 		mf->replylen[i] = 0;
7227dd7cddfSDavid du Colombier 	}
72380ee5cbfSDavid du Colombier 	mf->nreply = 0;
72480ee5cbfSDavid du Colombier 	mf->nextnet = netlist;
7253e12c5d1SDavid du Colombier }
7263e12c5d1SDavid du Colombier 
7273e12c5d1SDavid du Colombier void
7287dd7cddfSDavid du Colombier rwrite(Job *job, Mfile *mf)
7293e12c5d1SDavid du Colombier {
7303e12c5d1SDavid du Colombier 	int cnt, n;
73180ee5cbfSDavid du Colombier 	char *err;
7327dd7cddfSDavid du Colombier 	char *field[4];
7333e12c5d1SDavid du Colombier 
7343e12c5d1SDavid du Colombier 	err = 0;
7357dd7cddfSDavid du Colombier 	cnt = job->request.count;
7369a747e4fSDavid du Colombier 	if(mf->qid.type & QTDIR){
7373e12c5d1SDavid du Colombier 		err = "can't write directory";
7383e12c5d1SDavid du Colombier 		goto send;
7393e12c5d1SDavid du Colombier 	}
7403e12c5d1SDavid du Colombier 	if(cnt >= Maxrequest){
7413e12c5d1SDavid du Colombier 		err = "request too long";
7423e12c5d1SDavid du Colombier 		goto send;
7433e12c5d1SDavid du Colombier 	}
7447dd7cddfSDavid du Colombier 	job->request.data[cnt] = 0;
7453e12c5d1SDavid du Colombier 
7463e12c5d1SDavid du Colombier 	/*
747219b2ee8SDavid du Colombier 	 *  toggle debugging
748219b2ee8SDavid du Colombier 	 */
7497dd7cddfSDavid du Colombier 	if(strncmp(job->request.data, "debug", 5)==0){
750219b2ee8SDavid du Colombier 		debug ^= 1;
751219b2ee8SDavid du Colombier 		syslog(1, logfile, "debug %d", debug);
752219b2ee8SDavid du Colombier 		goto send;
753219b2ee8SDavid du Colombier 	}
754219b2ee8SDavid du Colombier 
755219b2ee8SDavid du Colombier 	/*
7567dd7cddfSDavid du Colombier 	 *  toggle debugging
7577dd7cddfSDavid du Colombier 	 */
7587dd7cddfSDavid du Colombier 	if(strncmp(job->request.data, "paranoia", 8)==0){
7597dd7cddfSDavid du Colombier 		paranoia ^= 1;
7607dd7cddfSDavid du Colombier 		syslog(1, logfile, "paranoia %d", paranoia);
7617dd7cddfSDavid du Colombier 		goto send;
7627dd7cddfSDavid du Colombier 	}
7637dd7cddfSDavid du Colombier 
7647dd7cddfSDavid du Colombier 	/*
7653e12c5d1SDavid du Colombier 	 *  add networks to the default list
7663e12c5d1SDavid du Colombier 	 */
7677dd7cddfSDavid du Colombier 	if(strncmp(job->request.data, "add ", 4)==0){
7687dd7cddfSDavid du Colombier 		if(job->request.data[cnt-1] == '\n')
7697dd7cddfSDavid du Colombier 			job->request.data[cnt-1] = 0;
7707dd7cddfSDavid du Colombier 		netadd(job->request.data+4);
7717dd7cddfSDavid du Colombier 		readipinterfaces();
7727dd7cddfSDavid du Colombier 		goto send;
7737dd7cddfSDavid du Colombier 	}
7747dd7cddfSDavid du Colombier 
7757dd7cddfSDavid du Colombier 	/*
7767dd7cddfSDavid du Colombier 	 *  refresh all state
7777dd7cddfSDavid du Colombier 	 */
7787dd7cddfSDavid du Colombier 	if(strncmp(job->request.data, "refresh", 7)==0){
7797dd7cddfSDavid du Colombier 		netinit(1);
7803e12c5d1SDavid du Colombier 		goto send;
7813e12c5d1SDavid du Colombier 	}
7823e12c5d1SDavid du Colombier 
78380ee5cbfSDavid du Colombier 	/* start transaction with a clean slate */
78480ee5cbfSDavid du Colombier 	cleanmf(mf);
78580ee5cbfSDavid du Colombier 
7863e12c5d1SDavid du Colombier 	/*
787219b2ee8SDavid du Colombier 	 *  look for a general query
788219b2ee8SDavid du Colombier 	 */
7897dd7cddfSDavid du Colombier 	if(*job->request.data == '!'){
7907dd7cddfSDavid du Colombier 		err = genquery(mf, job->request.data+1);
791219b2ee8SDavid du Colombier 		goto send;
792219b2ee8SDavid du Colombier 	}
793219b2ee8SDavid du Colombier 
7947dd7cddfSDavid du Colombier 	if(debug)
7957dd7cddfSDavid du Colombier 		syslog(0, logfile, "write %s", job->request.data);
7967dd7cddfSDavid du Colombier 	if(paranoia)
7977dd7cddfSDavid du Colombier 		syslog(0, paranoiafile, "write %s by %s", job->request.data, mf->user);
7987dd7cddfSDavid du Colombier 
799219b2ee8SDavid du Colombier 	/*
8003e12c5d1SDavid du Colombier 	 *  break up name
8013e12c5d1SDavid du Colombier 	 */
8027dd7cddfSDavid du Colombier 	n = getfields(job->request.data, field, 4, 1, "!");
8033e12c5d1SDavid du Colombier 	switch(n){
8043e12c5d1SDavid du Colombier 	case 1:
80580ee5cbfSDavid du Colombier 		mf->net = strdup("net");
80680ee5cbfSDavid du Colombier 		mf->host = strdup(field[0]);
8077dd7cddfSDavid du Colombier 		break;
8087dd7cddfSDavid du Colombier 	case 4:
80980ee5cbfSDavid du Colombier 		mf->rem = strdup(field[3]);
81080ee5cbfSDavid du Colombier 		/* fall through */
81180ee5cbfSDavid du Colombier 	case 3:
81280ee5cbfSDavid du Colombier 		mf->serv = strdup(field[2]);
81380ee5cbfSDavid du Colombier 		/* fall through */
81480ee5cbfSDavid du Colombier 	case 2:
81580ee5cbfSDavid du Colombier 		mf->host = strdup(field[1]);
81680ee5cbfSDavid du Colombier 		mf->net = strdup(field[0]);
8173e12c5d1SDavid du Colombier 		break;
8183e12c5d1SDavid du Colombier 	}
8193e12c5d1SDavid du Colombier 
82080ee5cbfSDavid du Colombier 	/*
82180ee5cbfSDavid du Colombier 	 *  do the first net worth of lookup
82280ee5cbfSDavid du Colombier 	 */
82380ee5cbfSDavid du Colombier 	if(lookup(mf) == 0)
8243e12c5d1SDavid du Colombier 		err = "can't translate address";
8253e12c5d1SDavid du Colombier send:
8267dd7cddfSDavid du Colombier 	job->reply.count = cnt;
8277dd7cddfSDavid du Colombier 	sendmsg(job, err);
8283e12c5d1SDavid du Colombier }
8293e12c5d1SDavid du Colombier 
8303e12c5d1SDavid du Colombier void
8317dd7cddfSDavid du Colombier rclunk(Job *job, Mfile *mf)
8323e12c5d1SDavid du Colombier {
83380ee5cbfSDavid du Colombier 	cleanmf(mf);
8343e12c5d1SDavid du Colombier 	mf->busy = 0;
8353e12c5d1SDavid du Colombier 	mf->fid = 0;
8367dd7cddfSDavid du Colombier 	sendmsg(job, 0);
8373e12c5d1SDavid du Colombier }
8383e12c5d1SDavid du Colombier 
8393e12c5d1SDavid du Colombier void
8407dd7cddfSDavid du Colombier rremove(Job *job, Mfile *mf)
8413e12c5d1SDavid du Colombier {
8423e12c5d1SDavid du Colombier 	USED(mf);
8437dd7cddfSDavid du Colombier 	sendmsg(job, "remove permission denied");
8443e12c5d1SDavid du Colombier }
8453e12c5d1SDavid du Colombier 
8463e12c5d1SDavid du Colombier void
8477dd7cddfSDavid du Colombier rstat(Job *job, Mfile *mf)
8483e12c5d1SDavid du Colombier {
8493e12c5d1SDavid du Colombier 	Dir dir;
8509a747e4fSDavid du Colombier 	uchar buf[IOHDRSZ+Maxfdata];
8513e12c5d1SDavid du Colombier 
8529a747e4fSDavid du Colombier 	if(mf->qid.type & QTDIR){
8539a747e4fSDavid du Colombier 		dir.name = ".";
8549a747e4fSDavid du Colombier 		dir.mode = DMDIR|0555;
855219b2ee8SDavid du Colombier 	} else {
8569a747e4fSDavid du Colombier 		dir.name = "cs";
8573e12c5d1SDavid du Colombier 		dir.mode = 0666;
858219b2ee8SDavid du Colombier 	}
859219b2ee8SDavid du Colombier 	dir.qid = mf->qid;
8603e12c5d1SDavid du Colombier 	dir.length = 0;
8619a747e4fSDavid du Colombier 	dir.uid = mf->user;
8629a747e4fSDavid du Colombier 	dir.gid = mf->user;
8639a747e4fSDavid du Colombier 	dir.muid = mf->user;
8643e12c5d1SDavid du Colombier 	dir.atime = dir.mtime = time(0);
8659a747e4fSDavid du Colombier 	job->reply.nstat = convD2M(&dir, buf, sizeof buf);
8669a747e4fSDavid du Colombier 	job->reply.stat = buf;
8677dd7cddfSDavid du Colombier 	sendmsg(job, 0);
8683e12c5d1SDavid du Colombier }
8693e12c5d1SDavid du Colombier 
8703e12c5d1SDavid du Colombier void
8717dd7cddfSDavid du Colombier rwstat(Job *job, Mfile *mf)
8723e12c5d1SDavid du Colombier {
8733e12c5d1SDavid du Colombier 	USED(mf);
8747dd7cddfSDavid du Colombier 	sendmsg(job, "wstat permission denied");
8753e12c5d1SDavid du Colombier }
8763e12c5d1SDavid du Colombier 
8773e12c5d1SDavid du Colombier void
8787dd7cddfSDavid du Colombier sendmsg(Job *job, char *err)
8793e12c5d1SDavid du Colombier {
8803e12c5d1SDavid du Colombier 	int n;
8819a747e4fSDavid du Colombier 	uchar mdata[IOHDRSZ + Maxfdata];
8829a747e4fSDavid du Colombier 	char ename[ERRMAX];
8833e12c5d1SDavid du Colombier 
8843e12c5d1SDavid du Colombier 	if(err){
8857dd7cddfSDavid du Colombier 		job->reply.type = Rerror;
8869a747e4fSDavid du Colombier 		snprint(ename, sizeof(ename), "cs: %s", err);
8879a747e4fSDavid du Colombier 		job->reply.ename = ename;
8883e12c5d1SDavid du Colombier 	}else{
8897dd7cddfSDavid du Colombier 		job->reply.type = job->request.type+1;
8903e12c5d1SDavid du Colombier 	}
8917dd7cddfSDavid du Colombier 	job->reply.tag = job->request.tag;
8929a747e4fSDavid du Colombier 	n = convS2M(&job->reply, mdata, sizeof mdata);
893219b2ee8SDavid du Colombier 	if(n == 0){
8947dd7cddfSDavid du Colombier 		syslog(1, logfile, "sendmsg convS2M of %F returns 0", &job->reply);
895219b2ee8SDavid du Colombier 		abort();
896219b2ee8SDavid du Colombier 	}
8977dd7cddfSDavid du Colombier 	lock(&joblock);
8987dd7cddfSDavid du Colombier 	if(job->flushed == 0)
8999a747e4fSDavid du Colombier 		if(write(mfd[1], mdata, n)!=n)
9003e12c5d1SDavid du Colombier 			error("mount write");
9017dd7cddfSDavid du Colombier 	unlock(&joblock);
902219b2ee8SDavid du Colombier 	if(debug)
9037dd7cddfSDavid du Colombier 		syslog(0, logfile, "%F %d", &job->reply, n);
9043e12c5d1SDavid du Colombier }
9053e12c5d1SDavid du Colombier 
9063e12c5d1SDavid du Colombier void
9073e12c5d1SDavid du Colombier error(char *s)
9083e12c5d1SDavid du Colombier {
909bd389b36SDavid du Colombier 	syslog(1, "cs", "%s: %r", s);
910bd389b36SDavid du Colombier 	_exits(0);
9113e12c5d1SDavid du Colombier }
9123e12c5d1SDavid du Colombier 
9137dd7cddfSDavid du Colombier static int
9147dd7cddfSDavid du Colombier isvalidip(uchar *ip)
9157dd7cddfSDavid du Colombier {
9167dd7cddfSDavid du Colombier 	return ipcmp(ip, IPnoaddr) != 0 && ipcmp(ip, v4prefix) != 0;
9177dd7cddfSDavid du Colombier }
9183e12c5d1SDavid du Colombier 
9197dd7cddfSDavid du Colombier void
9207dd7cddfSDavid du Colombier readipinterfaces(void)
9217dd7cddfSDavid du Colombier {
9229a747e4fSDavid du Colombier 	Ipifc *nifc;
9239a747e4fSDavid du Colombier 	Iplifc *lifc;
9247dd7cddfSDavid du Colombier 
9259a747e4fSDavid du Colombier 	ipifcs = readipifc(mntpt, ipifcs, -1);
9269a747e4fSDavid du Colombier 	for(nifc = ipifcs; nifc; nifc = nifc->next)
9279a747e4fSDavid du Colombier 		for(lifc = nifc->lifc; lifc; lifc = lifc->next)
9289a747e4fSDavid du Colombier 			if(ipcmp(lifc->ip, IPnoaddr) != 0){
9299a747e4fSDavid du Colombier 				ipmove(ipa, lifc->ip);
9307dd7cddfSDavid du Colombier 				sprint(ipaddr, "%I", ipa);
9317dd7cddfSDavid du Colombier 				if(debug)
9327dd7cddfSDavid du Colombier 					syslog(0, "dns", "ipaddr is %s\n", ipaddr);
933*3ff48bf5SDavid du Colombier 				return;
9347dd7cddfSDavid du Colombier 			}
9359a747e4fSDavid du Colombier 	ipmove(ipa, IPnoaddr);
9367dd7cddfSDavid du Colombier }
9373e12c5d1SDavid du Colombier 
9383e12c5d1SDavid du Colombier /*
9397dd7cddfSDavid du Colombier  *  get the system name
9403e12c5d1SDavid du Colombier  */
9413e12c5d1SDavid du Colombier void
9423e12c5d1SDavid du Colombier ipid(void)
9433e12c5d1SDavid du Colombier {
9443e12c5d1SDavid du Colombier 	uchar addr[6];
9453e12c5d1SDavid du Colombier 	Ndbtuple *t;
946219b2ee8SDavid du Colombier 	char *p, *attr;
9473e12c5d1SDavid du Colombier 	Ndbs s;
9483e12c5d1SDavid du Colombier 	int f;
9497dd7cddfSDavid du Colombier 	char buf[Maxpath];
9503e12c5d1SDavid du Colombier 
9513e12c5d1SDavid du Colombier 
952219b2ee8SDavid du Colombier 	/* use environment, ether addr, or ipaddr to get system name */
9537dd7cddfSDavid du Colombier 	if(*mysysname == 0){
9547dd7cddfSDavid du Colombier 		/*
9557dd7cddfSDavid du Colombier 		 *  environment has priority.
9567dd7cddfSDavid du Colombier 		 *
9577dd7cddfSDavid du Colombier 		 *  on the sgi power the default system name
9587dd7cddfSDavid du Colombier 		 *  is the ip address.  ignore that.
9597dd7cddfSDavid du Colombier 		 *
9607dd7cddfSDavid du Colombier 		 */
961219b2ee8SDavid du Colombier 		p = getenv("sysname");
962219b2ee8SDavid du Colombier 		if(p){
963219b2ee8SDavid du Colombier 			attr = ipattr(p);
964219b2ee8SDavid du Colombier 			if(strcmp(attr, "ip") != 0)
9657dd7cddfSDavid du Colombier 				strcpy(mysysname, p);
9663e12c5d1SDavid du Colombier 		}
9673e12c5d1SDavid du Colombier 
9683e12c5d1SDavid du Colombier 		/*
9697dd7cddfSDavid du Colombier 		 *  the /net/ndb contains what the network
9707dd7cddfSDavid du Colombier 		 *  figured out from DHCP.  use that name if
9717dd7cddfSDavid du Colombier 		 *  there is one.
9723e12c5d1SDavid du Colombier 		 */
9737dd7cddfSDavid du Colombier 		if(*mysysname == 0 && netdb != nil){
9747dd7cddfSDavid du Colombier 			ndbreopen(netdb);
9757dd7cddfSDavid du Colombier 			for(t = ndbparse(netdb); t != nil; t = t->entry){
9767dd7cddfSDavid du Colombier 				if(strcmp(t->attr, "sys") == 0){
9777dd7cddfSDavid du Colombier 					strcpy(mysysname, t->val);
9783e12c5d1SDavid du Colombier 					break;
9793e12c5d1SDavid du Colombier 				}
9807dd7cddfSDavid du Colombier 			}
9817dd7cddfSDavid du Colombier 			ndbfree(t);
9827dd7cddfSDavid du Colombier 		}
9837dd7cddfSDavid du Colombier 
9847dd7cddfSDavid du Colombier 		/* next network database, ip address, and ether address to find a name */
9857dd7cddfSDavid du Colombier 		if(*mysysname == 0){
9867dd7cddfSDavid du Colombier 			t = nil;
9877dd7cddfSDavid du Colombier 			if(isvalidip(ipa))
9887dd7cddfSDavid du Colombier 				t = ndbgetval(db, &s, "ip", ipaddr, "sys", mysysname);
9897dd7cddfSDavid du Colombier 			else {
9907dd7cddfSDavid du Colombier 				for(f = 0; f < 3; f++){
9917dd7cddfSDavid du Colombier 					snprint(buf, sizeof buf, "%s/ether%d", mntpt, f);
9927dd7cddfSDavid du Colombier 					if(myetheraddr(addr, buf) >= 0){
9937dd7cddfSDavid du Colombier 						snprint(eaddr, sizeof(eaddr), "%E", addr);
9947dd7cddfSDavid du Colombier 						t = ndbgetval(db, &s, "ether", eaddr, "sys",
9957dd7cddfSDavid du Colombier 							mysysname);
9967dd7cddfSDavid du Colombier 						if(t != nil)
9977dd7cddfSDavid du Colombier 							break;
9987dd7cddfSDavid du Colombier 					}
9997dd7cddfSDavid du Colombier 				}
10007dd7cddfSDavid du Colombier 			}
10017dd7cddfSDavid du Colombier 			ndbfree(t);
10027dd7cddfSDavid du Colombier 		}
10037dd7cddfSDavid du Colombier 
100480ee5cbfSDavid du Colombier 		/* nothing else worked, use the ip address */
100580ee5cbfSDavid du Colombier 		if(*mysysname == 0 && isvalidip(ipa))
100680ee5cbfSDavid du Colombier 			strcpy(mysysname, ipaddr);
100780ee5cbfSDavid du Colombier 
100880ee5cbfSDavid du Colombier 
10097dd7cddfSDavid du Colombier 		/* set /dev/mysysname if we now know it */
10107dd7cddfSDavid du Colombier 		if(*mysysname){
10117dd7cddfSDavid du Colombier 			f = open("/dev/sysname", OWRITE);
10127dd7cddfSDavid du Colombier 			if(f >= 0){
10137dd7cddfSDavid du Colombier 				write(f, mysysname, strlen(mysysname));
10143e12c5d1SDavid du Colombier 				close(f);
10153e12c5d1SDavid du Colombier 			}
10163e12c5d1SDavid du Colombier 		}
10173e12c5d1SDavid du Colombier 	}
10183e12c5d1SDavid du Colombier }
10193e12c5d1SDavid du Colombier 
10203e12c5d1SDavid du Colombier /*
10213e12c5d1SDavid du Colombier  *  Set up a list of default networks by looking for
10223e12c5d1SDavid du Colombier  *  /net/ * /clone.
10233e12c5d1SDavid du Colombier  */
10243e12c5d1SDavid du Colombier void
10257dd7cddfSDavid du Colombier netinit(int background)
10263e12c5d1SDavid du Colombier {
10277dd7cddfSDavid du Colombier 	char clone[Maxpath];
10283e12c5d1SDavid du Colombier 	Network *np;
10297dd7cddfSDavid du Colombier 	static int working;
10307dd7cddfSDavid du Colombier 
10317dd7cddfSDavid du Colombier 	if(background){
10327dd7cddfSDavid du Colombier 		switch(rfork(RFPROC|RFNOTEG|RFMEM|RFNOWAIT)){
10337dd7cddfSDavid du Colombier 		case 0:
10347dd7cddfSDavid du Colombier 			break;
10357dd7cddfSDavid du Colombier 		default:
10367dd7cddfSDavid du Colombier 			return;
10377dd7cddfSDavid du Colombier 		}
10387dd7cddfSDavid du Colombier 		lock(&netlock);
10397dd7cddfSDavid du Colombier 	}
10403e12c5d1SDavid du Colombier 
10413e12c5d1SDavid du Colombier 	/* add the mounted networks to the default list */
10423e12c5d1SDavid du Colombier 	for(np = network; np->net; np++){
10437dd7cddfSDavid du Colombier 		if(np->considered)
10447dd7cddfSDavid du Colombier 			continue;
10457dd7cddfSDavid du Colombier 		snprint(clone, sizeof(clone), "%s/%s/clone", mntpt, np->net);
10469a747e4fSDavid du Colombier 		if(access(clone, AEXIST) < 0)
10473e12c5d1SDavid du Colombier 			continue;
10483e12c5d1SDavid du Colombier 		if(netlist)
10493e12c5d1SDavid du Colombier 			last->next = np;
10503e12c5d1SDavid du Colombier 		else
10513e12c5d1SDavid du Colombier 			netlist = np;
10523e12c5d1SDavid du Colombier 		last = np;
10533e12c5d1SDavid du Colombier 		np->next = 0;
10547dd7cddfSDavid du Colombier 		np->considered = 1;
10553e12c5d1SDavid du Colombier 	}
10563e12c5d1SDavid du Colombier 
10577dd7cddfSDavid du Colombier 	/* find out what our ip address is */
10587dd7cddfSDavid du Colombier 	readipinterfaces();
10593e12c5d1SDavid du Colombier 
10607dd7cddfSDavid du Colombier 	/* set the system name if we need to, these says ip is all we have */
10613e12c5d1SDavid du Colombier 	ipid();
10623e12c5d1SDavid du Colombier 
1063219b2ee8SDavid du Colombier 	if(debug)
10647dd7cddfSDavid du Colombier 		syslog(0, logfile, "mysysname %s eaddr %s ipaddr %s ipa %I\n",
10657dd7cddfSDavid du Colombier 			mysysname, eaddr, ipaddr, ipa);
10667dd7cddfSDavid du Colombier 
10677dd7cddfSDavid du Colombier 	if(background){
10687dd7cddfSDavid du Colombier 		unlock(&netlock);
10697dd7cddfSDavid du Colombier 		_exits(0);
10707dd7cddfSDavid du Colombier 	}
10713e12c5d1SDavid du Colombier }
10723e12c5d1SDavid du Colombier 
10733e12c5d1SDavid du Colombier /*
10743e12c5d1SDavid du Colombier  *  add networks to the standard list
10753e12c5d1SDavid du Colombier  */
10763e12c5d1SDavid du Colombier void
10773e12c5d1SDavid du Colombier netadd(char *p)
10783e12c5d1SDavid du Colombier {
10793e12c5d1SDavid du Colombier 	Network *np;
10803e12c5d1SDavid du Colombier 	char *field[12];
10813e12c5d1SDavid du Colombier 	int i, n;
10823e12c5d1SDavid du Colombier 
10837dd7cddfSDavid du Colombier 	n = getfields(p, field, 12, 1, " ");
10843e12c5d1SDavid du Colombier 	for(i = 0; i < n; i++){
10853e12c5d1SDavid du Colombier 		for(np = network; np->net; np++){
10863e12c5d1SDavid du Colombier 			if(strcmp(field[i], np->net) != 0)
10873e12c5d1SDavid du Colombier 				continue;
10887dd7cddfSDavid du Colombier 			if(np->considered)
10893e12c5d1SDavid du Colombier 				break;
10903e12c5d1SDavid du Colombier 			if(netlist)
10913e12c5d1SDavid du Colombier 				last->next = np;
10923e12c5d1SDavid du Colombier 			else
10933e12c5d1SDavid du Colombier 				netlist = np;
10943e12c5d1SDavid du Colombier 			last = np;
10953e12c5d1SDavid du Colombier 			np->next = 0;
10967dd7cddfSDavid du Colombier 			np->considered = 1;
10973e12c5d1SDavid du Colombier 		}
10983e12c5d1SDavid du Colombier 	}
10993e12c5d1SDavid du Colombier }
11003e12c5d1SDavid du Colombier 
11013e12c5d1SDavid du Colombier /*
1102219b2ee8SDavid du Colombier  *  make a tuple
1103219b2ee8SDavid du Colombier  */
1104219b2ee8SDavid du Colombier Ndbtuple*
1105219b2ee8SDavid du Colombier mktuple(char *attr, char *val)
1106219b2ee8SDavid du Colombier {
1107219b2ee8SDavid du Colombier 	Ndbtuple *t;
1108219b2ee8SDavid du Colombier 
11097dd7cddfSDavid du Colombier 	t = emalloc(sizeof(Ndbtuple));
1110219b2ee8SDavid du Colombier 	strcpy(t->attr, attr);
1111219b2ee8SDavid du Colombier 	strncpy(t->val, val, sizeof(t->val));
1112219b2ee8SDavid du Colombier 	t->val[sizeof(t->val)-1] = 0;
1113219b2ee8SDavid du Colombier 	t->line = t;
1114219b2ee8SDavid du Colombier 	t->entry = 0;
1115219b2ee8SDavid du Colombier 	return t;
1116219b2ee8SDavid du Colombier }
1117219b2ee8SDavid du Colombier 
111880ee5cbfSDavid du Colombier int
111980ee5cbfSDavid du Colombier lookforproto(Ndbtuple *t, char *proto)
112080ee5cbfSDavid du Colombier {
112180ee5cbfSDavid du Colombier 	for(; t != nil; t = t->entry)
112280ee5cbfSDavid du Colombier 		if(strcmp(t->attr, "proto") == 0 && strcmp(t->val, proto) == 0)
112380ee5cbfSDavid du Colombier 			return 1;
112480ee5cbfSDavid du Colombier 	return 0;
112580ee5cbfSDavid du Colombier }
112680ee5cbfSDavid du Colombier 
1127219b2ee8SDavid du Colombier /*
11283e12c5d1SDavid du Colombier  *  lookup a request.  the network "net" means we should pick the
11293e12c5d1SDavid du Colombier  *  best network to get there.
11303e12c5d1SDavid du Colombier  */
11313e12c5d1SDavid du Colombier int
113280ee5cbfSDavid du Colombier lookup(Mfile *mf)
11333e12c5d1SDavid du Colombier {
113480ee5cbfSDavid du Colombier 	Network *np;
1135219b2ee8SDavid du Colombier 	char *cp;
1136219b2ee8SDavid du Colombier 	Ndbtuple *nt, *t;
1137219b2ee8SDavid du Colombier 	char reply[Maxreply];
113880ee5cbfSDavid du Colombier 	int i, rv;
113980ee5cbfSDavid du Colombier 	int hack;
11403e12c5d1SDavid du Colombier 
11413e12c5d1SDavid du Colombier 	/* open up the standard db files */
11423e12c5d1SDavid du Colombier 	if(db == 0)
11437dd7cddfSDavid du Colombier 		ndbinit();
11443e12c5d1SDavid du Colombier 	if(db == 0)
114580ee5cbfSDavid du Colombier 		error("can't open mf->network database\n");
11463e12c5d1SDavid du Colombier 
114780ee5cbfSDavid du Colombier 	rv = 0;
114880ee5cbfSDavid du Colombier 
114980ee5cbfSDavid du Colombier 	if(mf->net == nil)
115080ee5cbfSDavid du Colombier 		return 0;	/* must have been a genquery */
115180ee5cbfSDavid du Colombier 
115280ee5cbfSDavid du Colombier 	if(strcmp(mf->net, "net") == 0){
11533e12c5d1SDavid du Colombier 		/*
11543e12c5d1SDavid du Colombier 		 *  go through set of default nets
11553e12c5d1SDavid du Colombier 		 */
115680ee5cbfSDavid du Colombier 		for(np = mf->nextnet; np; np = np->next){
115780ee5cbfSDavid du Colombier 			nt = (*np->lookup)(np, mf->host, mf->serv, 1);
115880ee5cbfSDavid du Colombier 			if(nt == nil)
1159219b2ee8SDavid du Colombier 				continue;
116080ee5cbfSDavid du Colombier 			hack = np->fasttimeouthack && !lookforproto(nt, np->net);
116180ee5cbfSDavid du Colombier 			for(t = nt; mf->nreply < Nreply && t; t = t->entry){
116280ee5cbfSDavid du Colombier 				cp = (*np->trans)(t, np, mf->serv, mf->rem, hack);
1163219b2ee8SDavid du Colombier 				if(cp){
116480ee5cbfSDavid du Colombier 					/* avoid duplicates */
116580ee5cbfSDavid du Colombier 					for(i = 0; i < mf->nreply; i++)
116680ee5cbfSDavid du Colombier 						if(strcmp(mf->reply[i], cp) == 0)
116780ee5cbfSDavid du Colombier 							break;
116880ee5cbfSDavid du Colombier 					if(i == mf->nreply){
116980ee5cbfSDavid du Colombier 						/* save the reply */
1170219b2ee8SDavid du Colombier 						mf->replylen[mf->nreply] = strlen(cp);
1171219b2ee8SDavid du Colombier 						mf->reply[mf->nreply++] = cp;
117280ee5cbfSDavid du Colombier 						rv++;
1173219b2ee8SDavid du Colombier 					}
1174219b2ee8SDavid du Colombier 				}
1175219b2ee8SDavid du Colombier 			}
1176219b2ee8SDavid du Colombier 			ndbfree(nt);
117780ee5cbfSDavid du Colombier 			np = np->next;
117880ee5cbfSDavid du Colombier 			break;
117980ee5cbfSDavid du Colombier 		}
118080ee5cbfSDavid du Colombier 		mf->nextnet = np;
118180ee5cbfSDavid du Colombier 		return rv;
118280ee5cbfSDavid du Colombier 	}
118380ee5cbfSDavid du Colombier 
118480ee5cbfSDavid du Colombier 	/*
118580ee5cbfSDavid du Colombier 	 *  if not /net, we only get one lookup
118680ee5cbfSDavid du Colombier 	 */
118780ee5cbfSDavid du Colombier 	if(mf->nreply != 0)
1188219b2ee8SDavid du Colombier 		return 0;
118980ee5cbfSDavid du Colombier 
119080ee5cbfSDavid du Colombier 	/*
119180ee5cbfSDavid du Colombier 	 *  look for a specific network
119280ee5cbfSDavid du Colombier 	 */
119380ee5cbfSDavid du Colombier 	for(np = netlist; np->net != nil; np++){
119480ee5cbfSDavid du Colombier 		if(np->fasttimeouthack)
119580ee5cbfSDavid du Colombier 			continue;
119680ee5cbfSDavid du Colombier 		if(strcmp(np->net, mf->net) == 0)
119780ee5cbfSDavid du Colombier 			break;
119880ee5cbfSDavid du Colombier 	}
119980ee5cbfSDavid du Colombier 
120080ee5cbfSDavid du Colombier 	if(np->net != nil){
120180ee5cbfSDavid du Colombier 		/*
120280ee5cbfSDavid du Colombier 		 *  known network
120380ee5cbfSDavid du Colombier 		 */
120480ee5cbfSDavid du Colombier 		nt = (*np->lookup)(np, mf->host, mf->serv, 1);
120580ee5cbfSDavid du Colombier 		for(t = nt; mf->nreply < Nreply && t; t = t->entry){
120680ee5cbfSDavid du Colombier 			cp = (*np->trans)(t, np, mf->serv, mf->rem, 0);
120780ee5cbfSDavid du Colombier 			if(cp){
120880ee5cbfSDavid du Colombier 				mf->replylen[mf->nreply] = strlen(cp);
120980ee5cbfSDavid du Colombier 				mf->reply[mf->nreply++] = cp;
121080ee5cbfSDavid du Colombier 				rv++;
121180ee5cbfSDavid du Colombier 			}
121280ee5cbfSDavid du Colombier 		}
121380ee5cbfSDavid du Colombier 		ndbfree(nt);
121480ee5cbfSDavid du Colombier 		return rv;
12153e12c5d1SDavid du Colombier 	} else {
12163e12c5d1SDavid du Colombier 		/*
1217219b2ee8SDavid du Colombier 		 *  not a known network, don't translate host or service
12183e12c5d1SDavid du Colombier 		 */
121980ee5cbfSDavid du Colombier 		if(mf->serv)
12207dd7cddfSDavid du Colombier 			snprint(reply, sizeof(reply), "%s/%s/clone %s!%s",
122180ee5cbfSDavid du Colombier 				mntpt, mf->net, mf->host, mf->serv);
1222bd389b36SDavid du Colombier 		else
12237dd7cddfSDavid du Colombier 			snprint(reply, sizeof(reply), "%s/%s/clone %s",
122480ee5cbfSDavid du Colombier 				mntpt, mf->net, mf->host);
1225219b2ee8SDavid du Colombier 		mf->reply[0] = strdup(reply);
1226219b2ee8SDavid du Colombier 		mf->replylen[0] = strlen(reply);
1227219b2ee8SDavid du Colombier 		mf->nreply = 1;
122880ee5cbfSDavid du Colombier 		return 1;
12293e12c5d1SDavid du Colombier 	}
12303e12c5d1SDavid du Colombier }
12313e12c5d1SDavid du Colombier 
12323e12c5d1SDavid du Colombier /*
12333e12c5d1SDavid du Colombier  *  translate an ip service name into a port number.  If it's a numeric port
12343e12c5d1SDavid du Colombier  *  number, look for restricted access.
12353e12c5d1SDavid du Colombier  *
12363e12c5d1SDavid du Colombier  *  the service '*' needs no translation.
12373e12c5d1SDavid du Colombier  */
12383e12c5d1SDavid du Colombier char*
12393e12c5d1SDavid du Colombier ipserv(Network *np, char *name, char *buf)
12403e12c5d1SDavid du Colombier {
12413e12c5d1SDavid du Colombier 	char *p;
12423e12c5d1SDavid du Colombier 	int alpha = 0;
12433e12c5d1SDavid du Colombier 	int restr = 0;
12443e12c5d1SDavid du Colombier 	char port[Ndbvlen];
12453e12c5d1SDavid du Colombier 	Ndbtuple *t, *nt;
12463e12c5d1SDavid du Colombier 	Ndbs s;
12473e12c5d1SDavid du Colombier 
12483e12c5d1SDavid du Colombier 	/* '*' means any service */
12493e12c5d1SDavid du Colombier 	if(strcmp(name, "*")==0){
12503e12c5d1SDavid du Colombier 		strcpy(buf, name);
12513e12c5d1SDavid du Colombier 		return buf;
12523e12c5d1SDavid du Colombier 	}
12533e12c5d1SDavid du Colombier 
12543e12c5d1SDavid du Colombier 	/*  see if it's numeric or symbolic */
12553e12c5d1SDavid du Colombier 	port[0] = 0;
12563e12c5d1SDavid du Colombier 	for(p = name; *p; p++){
12573e12c5d1SDavid du Colombier 		if(isdigit(*p))
12589a747e4fSDavid du Colombier 			{}
12593e12c5d1SDavid du Colombier 		else if(isalpha(*p) || *p == '-' || *p == '$')
12603e12c5d1SDavid du Colombier 			alpha = 1;
12613e12c5d1SDavid du Colombier 		else
12623e12c5d1SDavid du Colombier 			return 0;
12633e12c5d1SDavid du Colombier 	}
12643e12c5d1SDavid du Colombier 	if(alpha){
12653e12c5d1SDavid du Colombier 		t = ndbgetval(db, &s, np->net, name, "port", port);
12663e12c5d1SDavid du Colombier 		if(t == 0)
12673e12c5d1SDavid du Colombier 			return 0;
12683e12c5d1SDavid du Colombier 	} else {
12693e12c5d1SDavid du Colombier 		t = ndbgetval(db, &s, "port", name, "port", port);
12703e12c5d1SDavid du Colombier 		if(t == 0){
12713e12c5d1SDavid du Colombier 			strncpy(port, name, sizeof(port));
12723e12c5d1SDavid du Colombier 			port[sizeof(port)-1] = 0;
12733e12c5d1SDavid du Colombier 		}
12743e12c5d1SDavid du Colombier 	}
12753e12c5d1SDavid du Colombier 
12763e12c5d1SDavid du Colombier 	if(t){
12773e12c5d1SDavid du Colombier 		for(nt = t; nt; nt = nt->entry)
12783e12c5d1SDavid du Colombier 			if(strcmp(nt->attr, "restricted") == 0)
12793e12c5d1SDavid du Colombier 				restr = 1;
12803e12c5d1SDavid du Colombier 		ndbfree(t);
12813e12c5d1SDavid du Colombier 	}
12823e12c5d1SDavid du Colombier 	sprint(buf, "%s%s", port, restr ? "!r" : "");
12833e12c5d1SDavid du Colombier 	return buf;
12843e12c5d1SDavid du Colombier }
12853e12c5d1SDavid du Colombier 
12863e12c5d1SDavid du Colombier /*
12877dd7cddfSDavid du Colombier  *  lookup an ip attribute
12883e12c5d1SDavid du Colombier  */
12897dd7cddfSDavid du Colombier int
12907dd7cddfSDavid du Colombier ipattrlookup(Ndb *db, char *ipa, char *attr, char *val)
12913e12c5d1SDavid du Colombier {
12923e12c5d1SDavid du Colombier 
12937dd7cddfSDavid du Colombier 	Ndbtuple *t, *nt;
12947dd7cddfSDavid du Colombier 	char *alist[2];
12953e12c5d1SDavid du Colombier 
12967dd7cddfSDavid du Colombier 	alist[0] = attr;
12977dd7cddfSDavid du Colombier 	t = ndbipinfo(db, "ip", ipa, alist, 1);
12987dd7cddfSDavid du Colombier 	if(t == nil)
12997dd7cddfSDavid du Colombier 		return 0;
13009a747e4fSDavid du Colombier 	for(nt = t; nt != nil; nt = nt->entry){
13017dd7cddfSDavid du Colombier 		if(strcmp(nt->attr, attr) == 0){
13027dd7cddfSDavid du Colombier 			strcpy(val, nt->val);
13033e12c5d1SDavid du Colombier 			ndbfree(t);
13047dd7cddfSDavid du Colombier 			return 1;
1305219b2ee8SDavid du Colombier 		}
13069a747e4fSDavid du Colombier 	}
13073e12c5d1SDavid du Colombier 
13087dd7cddfSDavid du Colombier 	/* we shouldn't get here */
13093e12c5d1SDavid du Colombier 	ndbfree(t);
13107dd7cddfSDavid du Colombier 	return 0;
13113e12c5d1SDavid du Colombier }
13123e12c5d1SDavid du Colombier 
13133e12c5d1SDavid du Colombier /*
13143e12c5d1SDavid du Colombier  *  lookup (and translate) an ip destination
13153e12c5d1SDavid du Colombier  */
1316219b2ee8SDavid du Colombier Ndbtuple*
1317219b2ee8SDavid du Colombier iplookup(Network *np, char *host, char *serv, int nolookup)
13183e12c5d1SDavid du Colombier {
13193e12c5d1SDavid du Colombier 	char *attr;
13207dd7cddfSDavid du Colombier 	Ndbtuple *t, *nt;
13213e12c5d1SDavid du Colombier 	Ndbs s;
13223e12c5d1SDavid du Colombier 	char ts[Ndbvlen+1];
13233e12c5d1SDavid du Colombier 	char th[Ndbvlen+1];
13243e12c5d1SDavid du Colombier 	char dollar[Ndbvlen+1];
13257dd7cddfSDavid du Colombier 	uchar ip[IPaddrlen];
13267dd7cddfSDavid du Colombier 	uchar net[IPaddrlen];
13277dd7cddfSDavid du Colombier 	uchar tnet[IPaddrlen];
13287dd7cddfSDavid du Colombier 	Ipifc *ifc;
13299a747e4fSDavid du Colombier 	Iplifc *lifc;
13303e12c5d1SDavid du Colombier 
1331219b2ee8SDavid du Colombier 	USED(nolookup);
1332219b2ee8SDavid du Colombier 
13333e12c5d1SDavid du Colombier 	/*
13343e12c5d1SDavid du Colombier 	 *  start with the service since it's the most likely to fail
13353e12c5d1SDavid du Colombier 	 *  and costs the least
13363e12c5d1SDavid du Colombier 	 */
13377dd7cddfSDavid du Colombier 	if(serv==0 || ipserv(np, serv, ts) == 0){
13387dd7cddfSDavid du Colombier 		werrstr("can't translate address");
1339219b2ee8SDavid du Colombier 		return 0;
13407dd7cddfSDavid du Colombier 	}
13413e12c5d1SDavid du Colombier 
13423e12c5d1SDavid du Colombier 	/* for dial strings with no host */
1343219b2ee8SDavid du Colombier 	if(strcmp(host, "*") == 0)
1344219b2ee8SDavid du Colombier 		return mktuple("ip", "*");
13453e12c5d1SDavid du Colombier 
13463e12c5d1SDavid du Colombier 	/*
13477dd7cddfSDavid du Colombier 	 *  hack till we go v6 :: = 0.0.0.0
13487dd7cddfSDavid du Colombier 	 */
13497dd7cddfSDavid du Colombier 	if(strcmp("::", host) == 0)
13507dd7cddfSDavid du Colombier 		return mktuple("ip", "*");
13517dd7cddfSDavid du Colombier 
13527dd7cddfSDavid du Colombier 	/*
13533e12c5d1SDavid du Colombier 	 *  '$' means the rest of the name is an attribute that we
13543e12c5d1SDavid du Colombier 	 *  need to search for
13553e12c5d1SDavid du Colombier 	 */
13563e12c5d1SDavid du Colombier 	if(*host == '$'){
13577dd7cddfSDavid du Colombier 		if(ipattrlookup(db, ipaddr, host+1, dollar))
13583e12c5d1SDavid du Colombier 			host = dollar;
13593e12c5d1SDavid du Colombier 	}
13603e12c5d1SDavid du Colombier 
13613e12c5d1SDavid du Colombier 	/*
13627dd7cddfSDavid du Colombier 	 *  turn '[ip address]' into just 'ip address'
13637dd7cddfSDavid du Colombier 	 */
13647dd7cddfSDavid du Colombier 	if(*host == '[' && host[strlen(host)-1] == ']'){
13657dd7cddfSDavid du Colombier 		host++;
13667dd7cddfSDavid du Colombier 		host[strlen(host)-1] = 0;
13677dd7cddfSDavid du Colombier 	}
13687dd7cddfSDavid du Colombier 
13697dd7cddfSDavid du Colombier 	/*
13703e12c5d1SDavid du Colombier 	 *  just accept addresses
13713e12c5d1SDavid du Colombier 	 */
1372219b2ee8SDavid du Colombier 	attr = ipattr(host);
1373219b2ee8SDavid du Colombier 	if(strcmp(attr, "ip") == 0)
1374219b2ee8SDavid du Colombier 		return mktuple("ip", host);
13753e12c5d1SDavid du Colombier 
13763e12c5d1SDavid du Colombier 	/*
13773e12c5d1SDavid du Colombier 	 *  give the domain name server the first opportunity to
1378bd389b36SDavid du Colombier 	 *  resolve domain names.  if that fails try the database.
13793e12c5d1SDavid du Colombier 	 */
13803e12c5d1SDavid du Colombier 	t = 0;
13813e12c5d1SDavid du Colombier 	if(strcmp(attr, "dom") == 0)
13827dd7cddfSDavid du Colombier 		t = dnsiplookup(host, &s);
13833e12c5d1SDavid du Colombier 	if(t == 0)
13843e12c5d1SDavid du Colombier 		t = ndbgetval(db, &s, attr, host, "ip", th);
13853e12c5d1SDavid du Colombier 	if(t == 0)
13867dd7cddfSDavid du Colombier 		t = dnsiplookup(host, &s);
13877dd7cddfSDavid du Colombier 	if(t == 0 && strcmp(attr, "dom") != 0)
13887dd7cddfSDavid du Colombier 		t = dnsiplookup(host, &s);
13897dd7cddfSDavid du Colombier 	if(t == 0)
1390219b2ee8SDavid du Colombier 		return 0;
1391bd389b36SDavid du Colombier 
1392bd389b36SDavid du Colombier 	/*
1393bd389b36SDavid du Colombier 	 *  reorder the tuple to have the matched line first and
1394bd389b36SDavid du Colombier 	 *  save that in the request structure.
1395bd389b36SDavid du Colombier 	 */
13967dd7cddfSDavid du Colombier 	t = reorder(t, s.t);
13977dd7cddfSDavid du Colombier 
13987dd7cddfSDavid du Colombier 	/*
13997dd7cddfSDavid du Colombier 	 * reorder according to our interfaces
14007dd7cddfSDavid du Colombier 	 */
14017dd7cddfSDavid du Colombier 	lock(&ipifclock);
14029a747e4fSDavid du Colombier 	for(ifc = ipifcs; ifc != nil; ifc = ifc->next){
14039a747e4fSDavid du Colombier 		for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
14049a747e4fSDavid du Colombier 			maskip(lifc->ip, lifc->mask, net);
14057dd7cddfSDavid du Colombier 			for(nt = t; nt; nt = nt->entry){
14067dd7cddfSDavid du Colombier 				if(strcmp(nt->attr, "ip") != 0)
14077dd7cddfSDavid du Colombier 					continue;
14087dd7cddfSDavid du Colombier 				parseip(ip, nt->val);
14099a747e4fSDavid du Colombier 				maskip(ip, lifc->mask, tnet);
14107dd7cddfSDavid du Colombier 				if(memcmp(net, tnet, IPaddrlen) == 0){
14117dd7cddfSDavid du Colombier 					t = reorder(t, nt);
14127dd7cddfSDavid du Colombier 					unlock(&ipifclock);
14137dd7cddfSDavid du Colombier 					return t;
14147dd7cddfSDavid du Colombier 				}
14157dd7cddfSDavid du Colombier 			}
14167dd7cddfSDavid du Colombier 		}
14179a747e4fSDavid du Colombier 	}
14187dd7cddfSDavid du Colombier 	unlock(&ipifclock);
14197dd7cddfSDavid du Colombier 
14207dd7cddfSDavid du Colombier 	return t;
14213e12c5d1SDavid du Colombier }
14223e12c5d1SDavid du Colombier 
14233e12c5d1SDavid du Colombier /*
14243e12c5d1SDavid du Colombier  *  translate an ip address
14253e12c5d1SDavid du Colombier  */
1426219b2ee8SDavid du Colombier char*
142780ee5cbfSDavid du Colombier iptrans(Ndbtuple *t, Network *np, char *serv, char *rem, int hack)
14283e12c5d1SDavid du Colombier {
14293e12c5d1SDavid du Colombier 	char ts[Ndbvlen+1];
1430219b2ee8SDavid du Colombier 	char reply[Maxreply];
14317dd7cddfSDavid du Colombier 	char x[Ndbvlen+1];
14323e12c5d1SDavid du Colombier 
1433219b2ee8SDavid du Colombier 	if(strcmp(t->attr, "ip") != 0)
14343e12c5d1SDavid du Colombier 		return 0;
1435219b2ee8SDavid du Colombier 
1436219b2ee8SDavid du Colombier 	if(serv == 0 || ipserv(np, serv, ts) == 0)
1437219b2ee8SDavid du Colombier 		return 0;
1438219b2ee8SDavid du Colombier 
14397dd7cddfSDavid du Colombier 	if(rem != nil)
14407dd7cddfSDavid du Colombier 		snprint(x, sizeof(x), "!%s", rem);
14417dd7cddfSDavid du Colombier 	else
14427dd7cddfSDavid du Colombier 		*x = 0;
144380ee5cbfSDavid du Colombier 
1444219b2ee8SDavid du Colombier 	if(*t->val == '*')
14457dd7cddfSDavid du Colombier 		snprint(reply, sizeof(reply), "%s/%s/clone %s%s",
14467dd7cddfSDavid du Colombier 			mntpt, np->net, ts, x);
1447219b2ee8SDavid du Colombier 	else
144880ee5cbfSDavid du Colombier 		snprint(reply, sizeof(reply), "%s/%s/clone %s!%s%s%s",
144980ee5cbfSDavid du Colombier 			mntpt, np->net, t->val, ts, x, hack?"!fasttimeout":"");
1450219b2ee8SDavid du Colombier 
1451219b2ee8SDavid du Colombier 	return strdup(reply);
14523e12c5d1SDavid du Colombier }
14533e12c5d1SDavid du Colombier 
1454219b2ee8SDavid du Colombier /*
1455219b2ee8SDavid du Colombier  *  lookup a telephone number
1456219b2ee8SDavid du Colombier  */
1457219b2ee8SDavid du Colombier Ndbtuple*
1458219b2ee8SDavid du Colombier telcolookup(Network *np, char *host, char *serv, int nolookup)
1459219b2ee8SDavid du Colombier {
1460219b2ee8SDavid du Colombier 	Ndbtuple *t;
1461219b2ee8SDavid du Colombier 	Ndbs s;
1462219b2ee8SDavid du Colombier 	char th[Ndbvlen+1];
1463219b2ee8SDavid du Colombier 
1464219b2ee8SDavid du Colombier 	USED(np, nolookup, serv);
1465219b2ee8SDavid du Colombier 
1466219b2ee8SDavid du Colombier 	t = ndbgetval(db, &s, "sys", host, "telco", th);
1467219b2ee8SDavid du Colombier 	if(t == 0)
1468219b2ee8SDavid du Colombier 		return mktuple("telco", host);
1469219b2ee8SDavid du Colombier 
1470219b2ee8SDavid du Colombier 	return reorder(t, s.t);
1471219b2ee8SDavid du Colombier }
1472219b2ee8SDavid du Colombier 
1473219b2ee8SDavid du Colombier /*
1474219b2ee8SDavid du Colombier  *  translate a telephone address
1475219b2ee8SDavid du Colombier  */
1476219b2ee8SDavid du Colombier char*
147780ee5cbfSDavid du Colombier telcotrans(Ndbtuple *t, Network *np, char *serv, char *rem, int)
1478219b2ee8SDavid du Colombier {
1479219b2ee8SDavid du Colombier 	char reply[Maxreply];
14807dd7cddfSDavid du Colombier 	char x[Ndbvlen+1];
1481219b2ee8SDavid du Colombier 
1482219b2ee8SDavid du Colombier 	if(strcmp(t->attr, "telco") != 0)
1483219b2ee8SDavid du Colombier 		return 0;
1484219b2ee8SDavid du Colombier 
14857dd7cddfSDavid du Colombier 	if(rem != nil)
14867dd7cddfSDavid du Colombier 		snprint(x, sizeof(x), "!%s", rem);
1487219b2ee8SDavid du Colombier 	else
14887dd7cddfSDavid du Colombier 		*x = 0;
14897dd7cddfSDavid du Colombier 	if(serv)
14907dd7cddfSDavid du Colombier 		snprint(reply, sizeof(reply), "%s/%s/clone %s!%s%s", mntpt, np->net,
14917dd7cddfSDavid du Colombier 			t->val, serv, x);
14927dd7cddfSDavid du Colombier 	else
14937dd7cddfSDavid du Colombier 		snprint(reply, sizeof(reply), "%s/%s/clone %s%s", mntpt, np->net,
14947dd7cddfSDavid du Colombier 			t->val, x);
1495219b2ee8SDavid du Colombier 	return strdup(reply);
1496219b2ee8SDavid du Colombier }
14973e12c5d1SDavid du Colombier 
14983e12c5d1SDavid du Colombier /*
14993e12c5d1SDavid du Colombier  *  reorder the tuple to put x's line first in the entry
15003e12c5d1SDavid du Colombier  */
15013e12c5d1SDavid du Colombier Ndbtuple*
15023e12c5d1SDavid du Colombier reorder(Ndbtuple *t, Ndbtuple *x)
15033e12c5d1SDavid du Colombier {
15043e12c5d1SDavid du Colombier 	Ndbtuple *nt;
15053e12c5d1SDavid du Colombier 	Ndbtuple *line;
15063e12c5d1SDavid du Colombier 
1507219b2ee8SDavid du Colombier 	/* find start of this entry's line */
1508219b2ee8SDavid du Colombier 	for(line = x; line->entry == line->line; line = line->line)
15093e12c5d1SDavid du Colombier 		;
1510219b2ee8SDavid du Colombier 	line = line->line;
1511219b2ee8SDavid du Colombier 	if(line == t)
1512219b2ee8SDavid du Colombier 		return t;	/* already the first line */
15133e12c5d1SDavid du Colombier 
1514219b2ee8SDavid du Colombier 	/* remove this line and everything after it from the entry */
1515219b2ee8SDavid du Colombier 	for(nt = t; nt->entry != line; nt = nt->entry)
1516219b2ee8SDavid du Colombier 		;
1517219b2ee8SDavid du Colombier 	nt->entry = 0;
15183e12c5d1SDavid du Colombier 
1519219b2ee8SDavid du Colombier 	/* make that the start of the entry */
1520219b2ee8SDavid du Colombier 	for(nt = line; nt->entry; nt = nt->entry)
1521219b2ee8SDavid du Colombier 		;
15223e12c5d1SDavid du Colombier 	nt->entry = t;
15233e12c5d1SDavid du Colombier 	return line;
15243e12c5d1SDavid du Colombier }
15253e12c5d1SDavid du Colombier 
15263e12c5d1SDavid du Colombier /*
15273e12c5d1SDavid du Colombier  *  create a slave process to handle a request to avoid one request blocking
15287dd7cddfSDavid du Colombier  *  another.  parent returns to job loop.
15293e12c5d1SDavid du Colombier  */
15303e12c5d1SDavid du Colombier void
15313e12c5d1SDavid du Colombier slave(void)
15323e12c5d1SDavid du Colombier {
15333e12c5d1SDavid du Colombier 	if(*isslave)
15343e12c5d1SDavid du Colombier 		return;		/* we're already a slave process */
15353e12c5d1SDavid du Colombier 
15363e12c5d1SDavid du Colombier 	switch(rfork(RFPROC|RFNOTEG|RFMEM|RFNOWAIT)){
15373e12c5d1SDavid du Colombier 	case -1:
15383e12c5d1SDavid du Colombier 		break;
15393e12c5d1SDavid du Colombier 	case 0:
1540219b2ee8SDavid du Colombier 		if(debug)
1541219b2ee8SDavid du Colombier 			syslog(0, logfile, "slave %d", getpid());
15423e12c5d1SDavid du Colombier 		*isslave = 1;
15433e12c5d1SDavid du Colombier 		break;
15443e12c5d1SDavid du Colombier 	default:
15453e12c5d1SDavid du Colombier 		longjmp(masterjmp, 1);
15463e12c5d1SDavid du Colombier 	}
15473e12c5d1SDavid du Colombier 
1548219b2ee8SDavid du Colombier }
1549219b2ee8SDavid du Colombier 
15503e12c5d1SDavid du Colombier /*
15513e12c5d1SDavid du Colombier  *  call the dns process and have it try to translate a name
15523e12c5d1SDavid du Colombier  */
15533e12c5d1SDavid du Colombier Ndbtuple*
15547dd7cddfSDavid du Colombier dnsiplookup(char *host, Ndbs *s)
15553e12c5d1SDavid du Colombier {
15563e12c5d1SDavid du Colombier 	char buf[Ndbvlen + 4];
15577dd7cddfSDavid du Colombier 	Ndbtuple *t;
15583e12c5d1SDavid du Colombier 
1559bd389b36SDavid du Colombier 	unlock(&dblock);
1560bd389b36SDavid du Colombier 
15613e12c5d1SDavid du Colombier 	/* save the name before starting a slave */
15627dd7cddfSDavid du Colombier 	snprint(buf, sizeof(buf), "%s", host);
15633e12c5d1SDavid du Colombier 
15643e12c5d1SDavid du Colombier 	slave();
15653e12c5d1SDavid du Colombier 
15667dd7cddfSDavid du Colombier 	if(strcmp(ipattr(buf), "ip") == 0)
15677dd7cddfSDavid du Colombier 		t = dnsquery(mntpt, buf, "ptr");
15687dd7cddfSDavid du Colombier 	else
15697dd7cddfSDavid du Colombier 		t = dnsquery(mntpt, buf, "ip");
15703e12c5d1SDavid du Colombier 	s->t = t;
15717dd7cddfSDavid du Colombier 
1572bd389b36SDavid du Colombier 	lock(&dblock);
15733e12c5d1SDavid du Colombier 	return t;
15743e12c5d1SDavid du Colombier }
1575219b2ee8SDavid du Colombier 
1576219b2ee8SDavid du Colombier int
1577219b2ee8SDavid du Colombier qmatch(Ndbtuple *t, char **attr, char **val, int n)
1578219b2ee8SDavid du Colombier {
1579219b2ee8SDavid du Colombier 	int i, found;
1580219b2ee8SDavid du Colombier 	Ndbtuple *nt;
1581219b2ee8SDavid du Colombier 
1582219b2ee8SDavid du Colombier 	for(i = 1; i < n; i++){
1583219b2ee8SDavid du Colombier 		found = 0;
1584219b2ee8SDavid du Colombier 		for(nt = t; nt; nt = nt->entry)
1585219b2ee8SDavid du Colombier 			if(strcmp(attr[i], nt->attr) == 0)
1586219b2ee8SDavid du Colombier 				if(strcmp(val[i], "*") == 0
1587219b2ee8SDavid du Colombier 				|| strcmp(val[i], nt->val) == 0){
1588219b2ee8SDavid du Colombier 					found = 1;
1589219b2ee8SDavid du Colombier 					break;
1590219b2ee8SDavid du Colombier 				}
1591219b2ee8SDavid du Colombier 		if(found == 0)
1592219b2ee8SDavid du Colombier 			break;
1593219b2ee8SDavid du Colombier 	}
1594219b2ee8SDavid du Colombier 	return i == n;
1595219b2ee8SDavid du Colombier }
1596219b2ee8SDavid du Colombier 
1597219b2ee8SDavid du Colombier void
1598219b2ee8SDavid du Colombier qreply(Mfile *mf, Ndbtuple *t)
1599219b2ee8SDavid du Colombier {
1600219b2ee8SDavid du Colombier 	int i;
1601219b2ee8SDavid du Colombier 	Ndbtuple *nt;
16027dd7cddfSDavid du Colombier 	char buf[2048];
1603219b2ee8SDavid du Colombier 
1604219b2ee8SDavid du Colombier 	buf[0] = 0;
1605219b2ee8SDavid du Colombier 	for(nt = t; mf->nreply < Nreply && nt; nt = nt->entry){
1606219b2ee8SDavid du Colombier 		strcat(buf, nt->attr);
1607219b2ee8SDavid du Colombier 		strcat(buf, "=");
1608219b2ee8SDavid du Colombier 		strcat(buf, nt->val);
1609219b2ee8SDavid du Colombier 		i = strlen(buf);
1610219b2ee8SDavid du Colombier 		if(nt->line != nt->entry || sizeof(buf) - i < 2*Ndbvlen+2){
1611219b2ee8SDavid du Colombier 			mf->replylen[mf->nreply] = strlen(buf);
1612219b2ee8SDavid du Colombier 			mf->reply[mf->nreply++] = strdup(buf);
1613219b2ee8SDavid du Colombier 			buf[0] = 0;
1614219b2ee8SDavid du Colombier 		} else
1615219b2ee8SDavid du Colombier 			strcat(buf, " ");
1616219b2ee8SDavid du Colombier 	}
1617219b2ee8SDavid du Colombier }
1618219b2ee8SDavid du Colombier 
16197dd7cddfSDavid du Colombier enum
16207dd7cddfSDavid du Colombier {
16217dd7cddfSDavid du Colombier 	Maxattr=	32,
16227dd7cddfSDavid du Colombier };
16237dd7cddfSDavid du Colombier 
1624219b2ee8SDavid du Colombier /*
16257dd7cddfSDavid du Colombier  *  generic query lookup.  The query is of one of the following
16267dd7cddfSDavid du Colombier  *  forms:
16277dd7cddfSDavid du Colombier  *
16287dd7cddfSDavid du Colombier  *  attr1=val1 attr2=val2 attr3=val3 ...
16297dd7cddfSDavid du Colombier  *
16307dd7cddfSDavid du Colombier  *  returns the matching tuple
16317dd7cddfSDavid du Colombier  *
16327dd7cddfSDavid du Colombier  *  ipinfo attr=val attr1 attr2 attr3 ...
16337dd7cddfSDavid du Colombier  *
16347dd7cddfSDavid du Colombier  *  is like ipinfo and returns the attr{1-n}
16357dd7cddfSDavid du Colombier  *  associated with the ip address.
1636219b2ee8SDavid du Colombier  */
1637219b2ee8SDavid du Colombier char*
1638219b2ee8SDavid du Colombier genquery(Mfile *mf, char *query)
1639219b2ee8SDavid du Colombier {
1640219b2ee8SDavid du Colombier 	int i, n;
1641219b2ee8SDavid du Colombier 	char *p;
16427dd7cddfSDavid du Colombier 	char *attr[Maxattr];
16437dd7cddfSDavid du Colombier 	char *val[Maxattr];
1644219b2ee8SDavid du Colombier 	Ndbtuple *t;
1645219b2ee8SDavid du Colombier 	Ndbs s;
1646219b2ee8SDavid du Colombier 
16477dd7cddfSDavid du Colombier 	n = getfields(query, attr, 32, 1, " ");
1648219b2ee8SDavid du Colombier 	if(n == 0)
1649219b2ee8SDavid du Colombier 		return "bad query";
1650219b2ee8SDavid du Colombier 
16517dd7cddfSDavid du Colombier 	if(strcmp(attr[0], "ipinfo") == 0)
16527dd7cddfSDavid du Colombier 		return ipinfoquery(mf, attr, n);
16537dd7cddfSDavid du Colombier 
1654219b2ee8SDavid du Colombier 	/* parse pairs */
1655219b2ee8SDavid du Colombier 	for(i = 0; i < n; i++){
1656219b2ee8SDavid du Colombier 		p = strchr(attr[i], '=');
1657219b2ee8SDavid du Colombier 		if(p == 0)
1658219b2ee8SDavid du Colombier 			return "bad query";
1659219b2ee8SDavid du Colombier 		*p++ = 0;
1660219b2ee8SDavid du Colombier 		val[i] = p;
1661219b2ee8SDavid du Colombier 	}
1662219b2ee8SDavid du Colombier 
1663219b2ee8SDavid du Colombier 	/* give dns a chance */
1664219b2ee8SDavid du Colombier 	if((strcmp(attr[0], "dom") == 0 || strcmp(attr[0], "ip") == 0) && val[0]){
16657dd7cddfSDavid du Colombier 		t = dnsiplookup(val[0], &s);
1666219b2ee8SDavid du Colombier 		if(t){
1667219b2ee8SDavid du Colombier 			if(qmatch(t, attr, val, n)){
1668219b2ee8SDavid du Colombier 				qreply(mf, t);
1669219b2ee8SDavid du Colombier 				ndbfree(t);
1670219b2ee8SDavid du Colombier 				return 0;
1671219b2ee8SDavid du Colombier 			}
1672219b2ee8SDavid du Colombier 			ndbfree(t);
1673219b2ee8SDavid du Colombier 		}
1674219b2ee8SDavid du Colombier 	}
1675219b2ee8SDavid du Colombier 
1676219b2ee8SDavid du Colombier 	/* first pair is always the key.  It can't be a '*' */
1677219b2ee8SDavid du Colombier 	t = ndbsearch(db, &s, attr[0], val[0]);
1678219b2ee8SDavid du Colombier 
1679219b2ee8SDavid du Colombier 	/* search is the and of all the pairs */
1680219b2ee8SDavid du Colombier 	while(t){
1681219b2ee8SDavid du Colombier 		if(qmatch(t, attr, val, n)){
1682219b2ee8SDavid du Colombier 			qreply(mf, t);
1683219b2ee8SDavid du Colombier 			ndbfree(t);
1684219b2ee8SDavid du Colombier 			return 0;
1685219b2ee8SDavid du Colombier 		}
1686219b2ee8SDavid du Colombier 
1687219b2ee8SDavid du Colombier 		ndbfree(t);
1688219b2ee8SDavid du Colombier 		t = ndbsnext(&s, attr[0], val[0]);
1689219b2ee8SDavid du Colombier 	}
1690219b2ee8SDavid du Colombier 
1691219b2ee8SDavid du Colombier 	return "no match";
1692219b2ee8SDavid du Colombier }
16937dd7cddfSDavid du Colombier 
16947dd7cddfSDavid du Colombier /*
16957dd7cddfSDavid du Colombier  *  resolve an ip address
16967dd7cddfSDavid du Colombier  */
16977dd7cddfSDavid du Colombier static Ndbtuple*
16987dd7cddfSDavid du Colombier ipresolve(char *attr, char *host)
16997dd7cddfSDavid du Colombier {
17007dd7cddfSDavid du Colombier 	Ndbtuple *t, *nt, **l;
17017dd7cddfSDavid du Colombier 
17027dd7cddfSDavid du Colombier 	t = iplookup(&network[Ntcp], host, "*", 0);
17037dd7cddfSDavid du Colombier 	for(l = &t; *l != nil; ){
17047dd7cddfSDavid du Colombier 		nt = *l;
17057dd7cddfSDavid du Colombier 		if(strcmp(nt->attr, "ip") != 0){
17067dd7cddfSDavid du Colombier 			*l = nt->entry;
17077dd7cddfSDavid du Colombier 			nt->entry = nil;
17087dd7cddfSDavid du Colombier 			ndbfree(nt);
17097dd7cddfSDavid du Colombier 			continue;
17107dd7cddfSDavid du Colombier 		}
17117dd7cddfSDavid du Colombier 		strcpy(nt->attr, attr);
17127dd7cddfSDavid du Colombier 		l = &nt->entry;
17137dd7cddfSDavid du Colombier 	}
17147dd7cddfSDavid du Colombier 	return t;
17157dd7cddfSDavid du Colombier }
17167dd7cddfSDavid du Colombier 
17177dd7cddfSDavid du Colombier char*
17187dd7cddfSDavid du Colombier ipinfoquery(Mfile *mf, char **list, int n)
17197dd7cddfSDavid du Colombier {
17207dd7cddfSDavid du Colombier 	int i, nresolve;
17217dd7cddfSDavid du Colombier 	int resolve[Maxattr];
17227dd7cddfSDavid du Colombier 	Ndbtuple *t, *nt, **l;
17237dd7cddfSDavid du Colombier 	char *attr, *val;
17247dd7cddfSDavid du Colombier 
17257dd7cddfSDavid du Colombier 	/* skip 'ipinfo' */
17267dd7cddfSDavid du Colombier 	list++; n--;
17277dd7cddfSDavid du Colombier 
17287dd7cddfSDavid du Colombier 	if(n < 2)
17297dd7cddfSDavid du Colombier 		return "bad query";
17307dd7cddfSDavid du Colombier 
17317dd7cddfSDavid du Colombier 	/* get search attribute=value */
17327dd7cddfSDavid du Colombier 	attr = *list++; n--;
17337dd7cddfSDavid du Colombier 	val = strchr(attr, '=');
17347dd7cddfSDavid du Colombier 	if(val == nil)
17357dd7cddfSDavid du Colombier 		return "bad query";
17367dd7cddfSDavid du Colombier 	*val++ = 0;
17377dd7cddfSDavid du Colombier 
17387dd7cddfSDavid du Colombier 	/*
17397dd7cddfSDavid du Colombier 	 *  don't let ndbipinfo resolve the addresses, we're
17407dd7cddfSDavid du Colombier 	 *  better at it.
17417dd7cddfSDavid du Colombier 	 */
17427dd7cddfSDavid du Colombier 	nresolve = 0;
17437dd7cddfSDavid du Colombier 	for(i = 0; i < n; i++)
17447dd7cddfSDavid du Colombier 		if(*list[i] == '@'){
17457dd7cddfSDavid du Colombier 			list[i]++;
17467dd7cddfSDavid du Colombier 			resolve[i] = 1;
17477dd7cddfSDavid du Colombier 			nresolve++;
17487dd7cddfSDavid du Colombier 		} else
17497dd7cddfSDavid du Colombier 			resolve[i] = 0;
17507dd7cddfSDavid du Colombier 
17517dd7cddfSDavid du Colombier 	t = ndbipinfo(db, attr, val, list, n);
17527dd7cddfSDavid du Colombier 	if(t == nil)
17537dd7cddfSDavid du Colombier 		return "no match";
17547dd7cddfSDavid du Colombier 
17557dd7cddfSDavid du Colombier 	if(nresolve != 0){
17567dd7cddfSDavid du Colombier 		for(l = &t; *l != nil;){
17577dd7cddfSDavid du Colombier 			nt = *l;
17587dd7cddfSDavid du Colombier 
17597dd7cddfSDavid du Colombier 			/* already an address? */
17607dd7cddfSDavid du Colombier 			if(strcmp(ipattr(nt->val), "ip") == 0){
17617dd7cddfSDavid du Colombier 				l = &(*l)->entry;
17627dd7cddfSDavid du Colombier 				continue;
17637dd7cddfSDavid du Colombier 			}
17647dd7cddfSDavid du Colombier 
17657dd7cddfSDavid du Colombier 			/* user wants it resolved? */
17667dd7cddfSDavid du Colombier 			for(i = 0; i < n; i++)
17677dd7cddfSDavid du Colombier 				if(strcmp(list[i], nt->attr) == 0)
17687dd7cddfSDavid du Colombier 					break;
17697dd7cddfSDavid du Colombier 			if(i >= n || resolve[i] == 0){
17707dd7cddfSDavid du Colombier 				l = &(*l)->entry;
17717dd7cddfSDavid du Colombier 				continue;
17727dd7cddfSDavid du Colombier 			}
17737dd7cddfSDavid du Colombier 
17747dd7cddfSDavid du Colombier 			/* resolve address and replace entry */
17757dd7cddfSDavid du Colombier 			*l = ipresolve(nt->attr, nt->val);
17767dd7cddfSDavid du Colombier 			while(*l != nil)
17777dd7cddfSDavid du Colombier 				l = &(*l)->entry;
17787dd7cddfSDavid du Colombier 			*l = nt->entry;
17797dd7cddfSDavid du Colombier 
17807dd7cddfSDavid du Colombier 			nt->entry = nil;
17817dd7cddfSDavid du Colombier 			ndbfree(nt);
17827dd7cddfSDavid du Colombier 		}
17837dd7cddfSDavid du Colombier 	}
17847dd7cddfSDavid du Colombier 
17857dd7cddfSDavid du Colombier 	/* make it all one line */
17867dd7cddfSDavid du Colombier 	for(nt = t; nt != nil; nt = nt->entry){
17877dd7cddfSDavid du Colombier 		if(nt->entry == nil)
17887dd7cddfSDavid du Colombier 			nt->line = t;
17897dd7cddfSDavid du Colombier 		else
17907dd7cddfSDavid du Colombier 			nt->line = nt->entry;
17917dd7cddfSDavid du Colombier 	}
17927dd7cddfSDavid du Colombier 
17937dd7cddfSDavid du Colombier 	qreply(mf, t);
17947dd7cddfSDavid du Colombier 
17957dd7cddfSDavid du Colombier 	return nil;
17967dd7cddfSDavid du Colombier }
17977dd7cddfSDavid du Colombier 
17987dd7cddfSDavid du Colombier void*
17997dd7cddfSDavid du Colombier emalloc(int size)
18007dd7cddfSDavid du Colombier {
18017dd7cddfSDavid du Colombier 	void *x;
18027dd7cddfSDavid du Colombier 
18037dd7cddfSDavid du Colombier 	x = malloc(size);
18047dd7cddfSDavid du Colombier 	if(x == nil)
18057dd7cddfSDavid du Colombier 		abort();
18067dd7cddfSDavid du Colombier 	memset(x, 0, size);
18077dd7cddfSDavid du Colombier 	return x;
18087dd7cddfSDavid du Colombier }
18099a747e4fSDavid du Colombier 
18109a747e4fSDavid du Colombier char*
18119a747e4fSDavid du Colombier estrdup(char *s)
18129a747e4fSDavid du Colombier {
18139a747e4fSDavid du Colombier 	int size;
18149a747e4fSDavid du Colombier 	char *p;
18159a747e4fSDavid du Colombier 
18169a747e4fSDavid du Colombier 	size = strlen(s)+1;
18179a747e4fSDavid du Colombier 	p = malloc(size);
18189a747e4fSDavid du Colombier 	if(p == nil)
18199a747e4fSDavid du Colombier 		abort();
18209a747e4fSDavid du Colombier 	memmove(p, s, size);
18219a747e4fSDavid du Colombier 	return p;
18229a747e4fSDavid du Colombier }
1823