xref: /plan9/sys/src/cmd/ndb/cs.c (revision 757661169def8a2aa1c5a7b9b0326740581d86d8)
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>
995a264b3SDavid du Colombier #include <String.h>
103e12c5d1SDavid du Colombier 
113e12c5d1SDavid du Colombier enum
123e12c5d1SDavid du Colombier {
1380ee5cbfSDavid du Colombier 	Nreply=			20,
143e12c5d1SDavid du Colombier 	Maxreply=		256,
157dd7cddfSDavid du Colombier 	Maxrequest=		128,
167dd7cddfSDavid du Colombier 	Maxpath=		128,
179a747e4fSDavid du Colombier 	Maxfdata=		8192,
1895a264b3SDavid du Colombier 	Maxhost=		64,		/* maximum host name size */
1995a264b3SDavid du Colombier 	Maxservice=		64,		/* maximum service name size */
203e12c5d1SDavid du Colombier 
219a747e4fSDavid du Colombier 	Qdir=			0,
223e12c5d1SDavid du Colombier 	Qcs=			1,
233e12c5d1SDavid du Colombier };
243e12c5d1SDavid du Colombier 
253e12c5d1SDavid du Colombier typedef struct Mfile	Mfile;
26219b2ee8SDavid du Colombier typedef struct Mlist	Mlist;
273e12c5d1SDavid du Colombier typedef struct Network	Network;
287dd7cddfSDavid du Colombier typedef struct Flushreq	Flushreq;
297dd7cddfSDavid du Colombier typedef struct Job	Job;
303e12c5d1SDavid du Colombier 
313e12c5d1SDavid du Colombier int vers;		/* incremented each clone/attach */
323e12c5d1SDavid du Colombier 
333e12c5d1SDavid du Colombier struct Mfile
343e12c5d1SDavid du Colombier {
353e12c5d1SDavid du Colombier 	int		busy;
36219b2ee8SDavid du Colombier 
379a747e4fSDavid du Colombier 	char		*user;
383e12c5d1SDavid du Colombier 	Qid		qid;
393e12c5d1SDavid du Colombier 	int		fid;
403e12c5d1SDavid du Colombier 
4180ee5cbfSDavid du Colombier 	/*
4280ee5cbfSDavid du Colombier 	 *  current request
4380ee5cbfSDavid du Colombier 	 */
4480ee5cbfSDavid du Colombier 	char		*net;
4580ee5cbfSDavid du Colombier 	char		*host;
4680ee5cbfSDavid du Colombier 	char		*serv;
4780ee5cbfSDavid du Colombier 	char		*rem;
4880ee5cbfSDavid du Colombier 
4980ee5cbfSDavid du Colombier 	/*
5080ee5cbfSDavid du Colombier 	 *  result of the last lookup
5180ee5cbfSDavid du Colombier 	 */
5280ee5cbfSDavid du Colombier 	Network		*nextnet;
53219b2ee8SDavid du Colombier 	int		nreply;
54219b2ee8SDavid du Colombier 	char		*reply[Nreply];
55219b2ee8SDavid du Colombier 	int		replylen[Nreply];
56219b2ee8SDavid du Colombier };
57219b2ee8SDavid du Colombier 
58219b2ee8SDavid du Colombier struct Mlist
59219b2ee8SDavid du Colombier {
60219b2ee8SDavid du Colombier 	Mlist	*next;
61219b2ee8SDavid du Colombier 	Mfile	mf;
623e12c5d1SDavid du Colombier };
633e12c5d1SDavid du Colombier 
649a747e4fSDavid du Colombier 
65244672c5SDavid du Colombier /*
66244672c5SDavid du Colombier  *  active requests
67244672c5SDavid du Colombier  */
687dd7cddfSDavid du Colombier struct Job
697dd7cddfSDavid du Colombier {
707dd7cddfSDavid du Colombier 	Job	*next;
717dd7cddfSDavid du Colombier 	int	flushed;
727dd7cddfSDavid du Colombier 	Fcall	request;
737dd7cddfSDavid du Colombier 	Fcall	reply;
747dd7cddfSDavid du Colombier };
757dd7cddfSDavid du Colombier Lock	joblock;
767dd7cddfSDavid du Colombier Job	*joblist;
777dd7cddfSDavid du Colombier 
78219b2ee8SDavid du Colombier Mlist	*mlist;
793e12c5d1SDavid du Colombier int	mfd[2];
803e12c5d1SDavid du Colombier int	debug;
817dd7cddfSDavid du Colombier int	paranoia;
823e12c5d1SDavid du Colombier jmp_buf	masterjmp;	/* return through here after a slave process has been created */
833e12c5d1SDavid du Colombier int	*isslave;	/* *isslave non-zero means this is a slave process */
84bd389b36SDavid du Colombier char	*dbfile;
857dd7cddfSDavid du Colombier Ndb	*db, *netdb;
863e12c5d1SDavid du Colombier 
879a747e4fSDavid du Colombier void	rversion(Job*);
887dd7cddfSDavid du Colombier void	rflush(Job*);
897dd7cddfSDavid du Colombier void	rattach(Job*, Mfile*);
907dd7cddfSDavid du Colombier char*	rwalk(Job*, Mfile*);
917dd7cddfSDavid du Colombier void	ropen(Job*, Mfile*);
927dd7cddfSDavid du Colombier void	rcreate(Job*, Mfile*);
937dd7cddfSDavid du Colombier void	rread(Job*, Mfile*);
947dd7cddfSDavid du Colombier void	rwrite(Job*, Mfile*);
957dd7cddfSDavid du Colombier void	rclunk(Job*, Mfile*);
967dd7cddfSDavid du Colombier void	rremove(Job*, Mfile*);
977dd7cddfSDavid du Colombier void	rstat(Job*, Mfile*);
987dd7cddfSDavid du Colombier void	rwstat(Job*, Mfile*);
999a747e4fSDavid du Colombier void	rauth(Job*);
1007dd7cddfSDavid du Colombier void	sendmsg(Job*, char*);
1013e12c5d1SDavid du Colombier void	error(char*);
1027dd7cddfSDavid du Colombier void	mountinit(char*, char*);
1033e12c5d1SDavid du Colombier void	io(void);
1047dd7cddfSDavid du Colombier void	ndbinit(void);
1057dd7cddfSDavid du Colombier void	netinit(int);
1063e12c5d1SDavid du Colombier void	netadd(char*);
107219b2ee8SDavid du Colombier char	*genquery(Mfile*, char*);
1087dd7cddfSDavid du Colombier char*	ipinfoquery(Mfile*, char**, int);
109bd389b36SDavid du Colombier int	needproto(Network*, Ndbtuple*);
1109a747e4fSDavid du Colombier int	lookup(Mfile*);
1113e12c5d1SDavid du Colombier Ndbtuple*	reorder(Ndbtuple*, Ndbtuple*);
1127dd7cddfSDavid du Colombier void	ipid(void);
1137dd7cddfSDavid du Colombier void	readipinterfaces(void);
1147dd7cddfSDavid du Colombier void*	emalloc(int);
1159a747e4fSDavid du Colombier char*	estrdup(char*);
1167dd7cddfSDavid du Colombier Job*	newjob(void);
1177dd7cddfSDavid du Colombier void	freejob(Job*);
1187dd7cddfSDavid du Colombier void	setext(char*, int, char*);
11980ee5cbfSDavid du Colombier void	cleanmf(Mfile*);
1203e12c5d1SDavid du Colombier 
121bd389b36SDavid du Colombier extern void	paralloc(void);
122bd389b36SDavid du Colombier 
123bd389b36SDavid du Colombier Lock	dblock;		/* mutex on database operations */
1247dd7cddfSDavid du Colombier Lock	netlock;	/* mutex for netinit() */
125bd389b36SDavid du Colombier 
126219b2ee8SDavid du Colombier char	*logfile = "cs";
1277dd7cddfSDavid du Colombier char	*paranoiafile = "cs.paranoia";
128219b2ee8SDavid du Colombier 
1297dd7cddfSDavid du Colombier char	mntpt[Maxpath];
1307dd7cddfSDavid du Colombier char	netndb[Maxpath];
1317dd7cddfSDavid du Colombier 
13280ee5cbfSDavid du Colombier /*
13380ee5cbfSDavid du Colombier  *  Network specific translators
13480ee5cbfSDavid du Colombier  */
13580ee5cbfSDavid du Colombier Ndbtuple*	iplookup(Network*, char*, char*, int);
13680ee5cbfSDavid du Colombier char*		iptrans(Ndbtuple*, Network*, char*, char*, int);
13780ee5cbfSDavid du Colombier Ndbtuple*	telcolookup(Network*, char*, char*, int);
13880ee5cbfSDavid du Colombier char*		telcotrans(Ndbtuple*, Network*, char*, char*, int);
13980ee5cbfSDavid du Colombier Ndbtuple*	dnsiplookup(char*, Ndbs*);
14080ee5cbfSDavid du Colombier 
14180ee5cbfSDavid du Colombier struct Network
14280ee5cbfSDavid du Colombier {
14380ee5cbfSDavid du Colombier 	char		*net;
14480ee5cbfSDavid du Colombier 	Ndbtuple	*(*lookup)(Network*, char*, char*, int);
14580ee5cbfSDavid du Colombier 	char		*(*trans)(Ndbtuple*, Network*, char*, char*, int);
14680ee5cbfSDavid du Colombier 	int		considered;
14780ee5cbfSDavid du Colombier 	int		fasttimeouthack;
14880ee5cbfSDavid du Colombier 	Network		*next;
14980ee5cbfSDavid du Colombier };
15080ee5cbfSDavid du Colombier 
15180ee5cbfSDavid du Colombier enum
15280ee5cbfSDavid du Colombier {
153*75766116SDavid du Colombier 	Ntcp = 0,
154244672c5SDavid du Colombier //	Nilfast,
155*75766116SDavid du Colombier 
156*75766116SDavid du Colombier //	Fasttimeout = 1,
15780ee5cbfSDavid du Colombier };
15880ee5cbfSDavid du Colombier 
15980ee5cbfSDavid du Colombier /*
160244672c5SDavid du Colombier  *  net doesn't apply to (r)udp, icmp(v6), or telco (for speed).
16180ee5cbfSDavid du Colombier  */
16280ee5cbfSDavid du Colombier Network network[] = {
16380ee5cbfSDavid du Colombier [Ntcp]	{ "tcp",	iplookup,	iptrans,	0, 0 },
164*75766116SDavid du Colombier // [Nilfast]{ "il",	iplookup,	iptrans,	0, Fasttimeout },
165*75766116SDavid du Colombier 	{ "il",		iplookup,	iptrans,	0, 0 },
166*75766116SDavid du Colombier 	{ "udp",	iplookup,	iptrans,	1, 0 },
167*75766116SDavid du Colombier 	{ "icmp",	iplookup,	iptrans,	1, 0 },
168*75766116SDavid du Colombier 	{ "icmpv6",	iplookup,	iptrans,	1, 0 },
169*75766116SDavid du Colombier 	{ "rudp",	iplookup,	iptrans,	1, 0 },
170*75766116SDavid du Colombier 	{ "telco",	telcolookup,	telcotrans,	1, 0 },
17180ee5cbfSDavid du Colombier 	{ 0 },
17280ee5cbfSDavid du Colombier };
17380ee5cbfSDavid du Colombier 
17480ee5cbfSDavid du Colombier Lock ipifclock;
17580ee5cbfSDavid du Colombier Ipifc *ipifcs;
17680ee5cbfSDavid du Colombier 
17795a264b3SDavid du Colombier char	eaddr[16];		/* ascii ethernet address */
17895a264b3SDavid du Colombier char	ipaddr[64];		/* ascii internet address */
17980ee5cbfSDavid du Colombier uchar	ipa[IPaddrlen];		/* binary internet address */
18095a264b3SDavid du Colombier char	*mysysname;
18180ee5cbfSDavid du Colombier 
18280ee5cbfSDavid du Colombier Network *netlist;		/* networks ordered by preference */
18380ee5cbfSDavid du Colombier Network *last;
18480ee5cbfSDavid du Colombier 
18595a264b3SDavid du Colombier static void
18695a264b3SDavid du Colombier nstrcpy(char *to, char *from, int len)
18795a264b3SDavid du Colombier {
18895a264b3SDavid du Colombier 	strncpy(to, from, len);
18995a264b3SDavid du Colombier 	to[len-1] = 0;
19095a264b3SDavid du Colombier }
19195a264b3SDavid du Colombier 
1927dd7cddfSDavid du Colombier void
1937dd7cddfSDavid du Colombier usage(void)
1947dd7cddfSDavid du Colombier {
195*75766116SDavid du Colombier 	fprint(2, "usage: %s [-dn] [-f ndb-file] [-x netmtpt]\n", argv0);
1967dd7cddfSDavid du Colombier 	exits("usage");
1977dd7cddfSDavid du Colombier }
198219b2ee8SDavid du Colombier 
1993e12c5d1SDavid du Colombier void
2003e12c5d1SDavid du Colombier main(int argc, char *argv[])
2013e12c5d1SDavid du Colombier {
202219b2ee8SDavid du Colombier 	int justsetname;
203*75766116SDavid du Colombier 	char ext[Maxpath], servefile[Maxpath];
2043e12c5d1SDavid du Colombier 
205219b2ee8SDavid du Colombier 	justsetname = 0;
2067dd7cddfSDavid du Colombier 	setnetmtpt(mntpt, sizeof(mntpt), nil);
2077dd7cddfSDavid du Colombier 	ext[0] = 0;
2083e12c5d1SDavid du Colombier 	ARGBEGIN{
2093e12c5d1SDavid du Colombier 	case 'd':
2103e12c5d1SDavid du Colombier 		debug = 1;
2113e12c5d1SDavid du Colombier 		break;
212bd389b36SDavid du Colombier 	case 'f':
213*75766116SDavid du Colombier 		dbfile = EARGF(usage());
214bd389b36SDavid du Colombier 		break;
215219b2ee8SDavid du Colombier 	case 'n':
216219b2ee8SDavid du Colombier 		justsetname = 1;
217219b2ee8SDavid du Colombier 		break;
218*75766116SDavid du Colombier 	case 'x':
219*75766116SDavid du Colombier 		setnetmtpt(mntpt, sizeof(mntpt), EARGF(usage()));
220*75766116SDavid du Colombier 		setext(ext, sizeof(ext), mntpt);
221*75766116SDavid 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");
278a9f680aeSDavid du Colombier 
279a9f680aeSDavid du Colombier 	/*
280a9f680aeSDavid du Colombier 	 *  make a /srv/cs
281a9f680aeSDavid du Colombier 	 */
282a9f680aeSDavid du Colombier 	f = create(service, OWRITE|ORCLOSE, 0666);
283a9f680aeSDavid du Colombier 	if(f < 0)
284a9f680aeSDavid du Colombier 		error(service);
285a9f680aeSDavid du Colombier 	snprint(buf, sizeof(buf), "%d", p[1]);
286a9f680aeSDavid du Colombier 	if(write(f, buf, strlen(buf)) != strlen(buf))
287a9f680aeSDavid du Colombier 		error("write /srv/cs");
288a9f680aeSDavid du Colombier 
289219b2ee8SDavid du Colombier 	switch(rfork(RFFDG|RFPROC|RFNAMEG)){
2903e12c5d1SDavid du Colombier 	case 0:
291219b2ee8SDavid du Colombier 		close(p[1]);
2923e12c5d1SDavid du Colombier 		break;
2933e12c5d1SDavid du Colombier 	case -1:
2943e12c5d1SDavid du Colombier 		error("fork failed\n");
2953e12c5d1SDavid du Colombier 	default:
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){
417271b8d73SDavid du Colombier 			syslog(1, logfile, "format error %ux %ux %ux %ux %ux",
418271b8d73SDavid du Colombier 				mdata[0], mdata[1], mdata[2], mdata[3], mdata[4]);
4197dd7cddfSDavid du Colombier 			freejob(job);
4203e12c5d1SDavid du Colombier 			continue;
4213e12c5d1SDavid du Colombier 		}
422bd389b36SDavid du Colombier 		lock(&dblock);
4237dd7cddfSDavid du Colombier 		mf = newfid(job->request.fid);
424219b2ee8SDavid du Colombier 		if(debug)
4257dd7cddfSDavid du Colombier 			syslog(0, logfile, "%F", &job->request);
4263e12c5d1SDavid du Colombier 
4273e12c5d1SDavid du Colombier 
4287dd7cddfSDavid du Colombier 		switch(job->request.type){
4293e12c5d1SDavid du Colombier 		default:
4307dd7cddfSDavid du Colombier 			syslog(1, logfile, "unknown request type %d", job->request.type);
4313e12c5d1SDavid du Colombier 			break;
4329a747e4fSDavid du Colombier 		case Tversion:
4339a747e4fSDavid du Colombier 			rversion(job);
4343e12c5d1SDavid du Colombier 			break;
4359a747e4fSDavid du Colombier 		case Tauth:
4369a747e4fSDavid du Colombier 			rauth(job);
4373e12c5d1SDavid du Colombier 			break;
4383e12c5d1SDavid du Colombier 		case Tflush:
4397dd7cddfSDavid du Colombier 			rflush(job);
4403e12c5d1SDavid du Colombier 			break;
4413e12c5d1SDavid du Colombier 		case Tattach:
4427dd7cddfSDavid du Colombier 			rattach(job, mf);
4433e12c5d1SDavid du Colombier 			break;
4443e12c5d1SDavid du Colombier 		case Twalk:
4457dd7cddfSDavid du Colombier 			rwalk(job, mf);
4463e12c5d1SDavid du Colombier 			break;
4473e12c5d1SDavid du Colombier 		case Topen:
4487dd7cddfSDavid du Colombier 			ropen(job, mf);
4493e12c5d1SDavid du Colombier 			break;
4503e12c5d1SDavid du Colombier 		case Tcreate:
4517dd7cddfSDavid du Colombier 			rcreate(job, mf);
4523e12c5d1SDavid du Colombier 			break;
4533e12c5d1SDavid du Colombier 		case Tread:
4547dd7cddfSDavid du Colombier 			rread(job, mf);
4553e12c5d1SDavid du Colombier 			break;
4563e12c5d1SDavid du Colombier 		case Twrite:
4577dd7cddfSDavid du Colombier 			rwrite(job, mf);
4583e12c5d1SDavid du Colombier 			break;
4593e12c5d1SDavid du Colombier 		case Tclunk:
4607dd7cddfSDavid du Colombier 			rclunk(job, mf);
4613e12c5d1SDavid du Colombier 			break;
4623e12c5d1SDavid du Colombier 		case Tremove:
4637dd7cddfSDavid du Colombier 			rremove(job, mf);
4643e12c5d1SDavid du Colombier 			break;
4653e12c5d1SDavid du Colombier 		case Tstat:
4667dd7cddfSDavid du Colombier 			rstat(job, mf);
4673e12c5d1SDavid du Colombier 			break;
4683e12c5d1SDavid du Colombier 		case Twstat:
4697dd7cddfSDavid du Colombier 			rwstat(job, mf);
4703e12c5d1SDavid du Colombier 			break;
4713e12c5d1SDavid du Colombier 		}
472bd389b36SDavid du Colombier 		unlock(&dblock);
4737dd7cddfSDavid du Colombier 
4747dd7cddfSDavid du Colombier 		freejob(job);
4757dd7cddfSDavid du Colombier 
4763e12c5d1SDavid du Colombier 		/*
4773e12c5d1SDavid du Colombier 		 *  slave processes die after replying
4783e12c5d1SDavid du Colombier 		 */
479219b2ee8SDavid du Colombier 		if(*isslave){
480219b2ee8SDavid du Colombier 			if(debug)
481219b2ee8SDavid du Colombier 				syslog(0, logfile, "slave death %d", getpid());
4823e12c5d1SDavid du Colombier 			_exits(0);
4833e12c5d1SDavid du Colombier 		}
4843e12c5d1SDavid du Colombier 	}
485219b2ee8SDavid du Colombier }
486219b2ee8SDavid du Colombier 
487219b2ee8SDavid du Colombier void
4889a747e4fSDavid du Colombier rversion(Job *job)
489219b2ee8SDavid du Colombier {
4909a747e4fSDavid du Colombier 	if(job->request.msize > IOHDRSZ + Maxfdata)
4919a747e4fSDavid du Colombier 		job->reply.msize = IOHDRSZ + Maxfdata;
4929a747e4fSDavid du Colombier 	else
4939a747e4fSDavid du Colombier 		job->reply.msize = job->request.msize;
4949a747e4fSDavid du Colombier 	if(strncmp(job->request.version, "9P2000", 6) != 0)
4959a747e4fSDavid du Colombier 		sendmsg(job, "unknown 9P version");
4969a747e4fSDavid du Colombier 	else{
4979a747e4fSDavid du Colombier 		job->reply.version = "9P2000";
4987dd7cddfSDavid du Colombier 		sendmsg(job, 0);
499219b2ee8SDavid du Colombier 	}
5009a747e4fSDavid du Colombier }
5013e12c5d1SDavid du Colombier 
5023e12c5d1SDavid du Colombier void
5039a747e4fSDavid du Colombier rauth(Job *job)
5043e12c5d1SDavid du Colombier {
5053ff48bf5SDavid du Colombier 	sendmsg(job, "cs: authentication not required");
5067dd7cddfSDavid du Colombier }
5077dd7cddfSDavid du Colombier 
5087dd7cddfSDavid du Colombier /*
5097dd7cddfSDavid du Colombier  *  don't flush till all the slaves are done
5107dd7cddfSDavid du Colombier  */
5117dd7cddfSDavid du Colombier void
5127dd7cddfSDavid du Colombier rflush(Job *job)
5137dd7cddfSDavid du Colombier {
5147dd7cddfSDavid du Colombier 	flushjob(job->request.oldtag);
5157dd7cddfSDavid du Colombier 	sendmsg(job, 0);
5163e12c5d1SDavid du Colombier }
5173e12c5d1SDavid du Colombier 
5183e12c5d1SDavid du Colombier void
5197dd7cddfSDavid du Colombier rattach(Job *job, Mfile *mf)
5203e12c5d1SDavid du Colombier {
5213e12c5d1SDavid du Colombier 	if(mf->busy == 0){
5223e12c5d1SDavid du Colombier 		mf->busy = 1;
5239a747e4fSDavid du Colombier 		mf->user = estrdup(job->request.uname);
5243e12c5d1SDavid du Colombier 	}
5253e12c5d1SDavid du Colombier 	mf->qid.vers = vers++;
5269a747e4fSDavid du Colombier 	mf->qid.type = QTDIR;
5279a747e4fSDavid du Colombier 	mf->qid.path = 0LL;
5287dd7cddfSDavid du Colombier 	job->reply.qid = mf->qid;
5297dd7cddfSDavid du Colombier 	sendmsg(job, 0);
5303e12c5d1SDavid du Colombier }
5313e12c5d1SDavid du Colombier 
5323e12c5d1SDavid du Colombier 
5333e12c5d1SDavid du Colombier char*
5347dd7cddfSDavid du Colombier rwalk(Job *job, Mfile *mf)
5353e12c5d1SDavid du Colombier {
5363e12c5d1SDavid du Colombier 	char *err;
5379a747e4fSDavid du Colombier 	char **elems;
5389a747e4fSDavid du Colombier 	int nelems;
5399a747e4fSDavid du Colombier 	int i;
5409a747e4fSDavid du Colombier 	Mfile *nmf;
5419a747e4fSDavid du Colombier 	Qid qid;
5423e12c5d1SDavid du Colombier 
5433e12c5d1SDavid du Colombier 	err = 0;
5449a747e4fSDavid du Colombier 	nmf = nil;
5459a747e4fSDavid du Colombier 	elems = job->request.wname;
5469a747e4fSDavid du Colombier 	nelems = job->request.nwname;
5479a747e4fSDavid du Colombier 	job->reply.nwqid = 0;
5489a747e4fSDavid du Colombier 
5499a747e4fSDavid du Colombier 	if(job->request.newfid != job->request.fid){
5509a747e4fSDavid du Colombier 		/* clone fid */
5519a747e4fSDavid du Colombier 		nmf = newfid(job->request.newfid);
5529a747e4fSDavid du Colombier 		if(nmf->busy){
5539a747e4fSDavid du Colombier 			nmf = nil;
5549a747e4fSDavid du Colombier 			err = "clone to used channel";
5559a747e4fSDavid du Colombier 			goto send;
5569a747e4fSDavid du Colombier 		}
5579a747e4fSDavid du Colombier 		*nmf = *mf;
5589a747e4fSDavid du Colombier 		nmf->user = estrdup(mf->user);
5599a747e4fSDavid du Colombier 		nmf->fid = job->request.newfid;
5609a747e4fSDavid du Colombier 		nmf->qid.vers = vers++;
5619a747e4fSDavid du Colombier 		mf = nmf;
5629a747e4fSDavid du Colombier 	}
5639a747e4fSDavid du Colombier 	/* else nmf will be nil */
5649a747e4fSDavid du Colombier 
5659a747e4fSDavid du Colombier 	qid = mf->qid;
5669a747e4fSDavid du Colombier 	if(nelems > 0){
5679a747e4fSDavid du Colombier 		/* walk fid */
5689a747e4fSDavid du Colombier 		for(i=0; i<nelems && i<MAXWELEM; i++){
5699a747e4fSDavid du Colombier 			if((qid.type & QTDIR) == 0){
5703e12c5d1SDavid du Colombier 				err = "not a directory";
5719a747e4fSDavid du Colombier 				break;
5723e12c5d1SDavid du Colombier 			}
5739a747e4fSDavid du Colombier 			if(strcmp(elems[i], "..") == 0 || strcmp(elems[i], ".") == 0){
5749a747e4fSDavid du Colombier 				qid.type = QTDIR;
5759a747e4fSDavid du Colombier 				qid.path = Qdir;
5769a747e4fSDavid du Colombier     Found:
5779a747e4fSDavid du Colombier 				job->reply.wqid[i] = qid;
5789a747e4fSDavid du Colombier 				job->reply.nwqid++;
5799a747e4fSDavid du Colombier 				continue;
5803e12c5d1SDavid du Colombier 			}
5819a747e4fSDavid du Colombier 			if(strcmp(elems[i], "cs") == 0){
5829a747e4fSDavid du Colombier 				qid.type = QTFILE;
5839a747e4fSDavid du Colombier 				qid.path = Qcs;
5849a747e4fSDavid du Colombier 				goto Found;
5853e12c5d1SDavid du Colombier 			}
5869a747e4fSDavid du Colombier 			err = "file does not exist";
5879a747e4fSDavid du Colombier 			break;
5889a747e4fSDavid du Colombier 		}
5899a747e4fSDavid du Colombier 	}
5909a747e4fSDavid du Colombier 
5913e12c5d1SDavid du Colombier     send:
5929a747e4fSDavid du Colombier 	if(nmf != nil && (err!=nil || job->reply.nwqid<nelems)){
593a9f680aeSDavid du Colombier 		cleanmf(nmf);
594a9f680aeSDavid du Colombier 		free(nmf->user);
595a9f680aeSDavid du Colombier 		nmf->user = 0;
5969a747e4fSDavid du Colombier 		nmf->busy = 0;
5979a747e4fSDavid du Colombier 		nmf->fid = 0;
5989a747e4fSDavid du Colombier 	}
5999a747e4fSDavid du Colombier 	if(err == nil)
6009a747e4fSDavid du Colombier 		mf->qid = qid;
6017dd7cddfSDavid du Colombier 	sendmsg(job, err);
6023e12c5d1SDavid du Colombier 	return err;
6033e12c5d1SDavid du Colombier }
6043e12c5d1SDavid du Colombier 
6053e12c5d1SDavid du Colombier void
6067dd7cddfSDavid du Colombier ropen(Job *job, Mfile *mf)
6073e12c5d1SDavid du Colombier {
6083e12c5d1SDavid du Colombier 	int mode;
6093e12c5d1SDavid du Colombier 	char *err;
6103e12c5d1SDavid du Colombier 
6113e12c5d1SDavid du Colombier 	err = 0;
6127dd7cddfSDavid du Colombier 	mode = job->request.mode;
6139a747e4fSDavid du Colombier 	if(mf->qid.type & QTDIR){
6143e12c5d1SDavid du Colombier 		if(mode)
6153e12c5d1SDavid du Colombier 			err = "permission denied";
6169a747e4fSDavid du Colombier 	}
6177dd7cddfSDavid du Colombier 	job->reply.qid = mf->qid;
6189a747e4fSDavid du Colombier 	job->reply.iounit = 0;
6197dd7cddfSDavid du Colombier 	sendmsg(job, err);
6203e12c5d1SDavid du Colombier }
6213e12c5d1SDavid du Colombier 
6223e12c5d1SDavid du Colombier void
6237dd7cddfSDavid du Colombier rcreate(Job *job, Mfile *mf)
6243e12c5d1SDavid du Colombier {
6253e12c5d1SDavid du Colombier 	USED(mf);
6267dd7cddfSDavid du Colombier 	sendmsg(job, "creation permission denied");
6273e12c5d1SDavid du Colombier }
6283e12c5d1SDavid du Colombier 
6293e12c5d1SDavid du Colombier void
6307dd7cddfSDavid du Colombier rread(Job *job, Mfile *mf)
6313e12c5d1SDavid du Colombier {
632219b2ee8SDavid du Colombier 	int i, n, cnt;
633219b2ee8SDavid du Colombier 	long off, toff, clock;
6343e12c5d1SDavid du Colombier 	Dir dir;
6359a747e4fSDavid du Colombier 	uchar buf[Maxfdata];
6363e12c5d1SDavid du Colombier 	char *err;
6373e12c5d1SDavid du Colombier 
6383e12c5d1SDavid du Colombier 	n = 0;
6393e12c5d1SDavid du Colombier 	err = 0;
6407dd7cddfSDavid du Colombier 	off = job->request.offset;
6417dd7cddfSDavid du Colombier 	cnt = job->request.count;
6429a747e4fSDavid du Colombier 	if(mf->qid.type & QTDIR){
6433e12c5d1SDavid du Colombier 		clock = time(0);
6443e12c5d1SDavid du Colombier 		if(off == 0){
6459a747e4fSDavid du Colombier 			dir.name = "cs";
6469a747e4fSDavid du Colombier 			dir.qid.type = QTFILE;
6473e12c5d1SDavid du Colombier 			dir.qid.vers = vers;
6483e12c5d1SDavid du Colombier 			dir.qid.path = Qcs;
6493e12c5d1SDavid du Colombier 			dir.mode = 0666;
6503e12c5d1SDavid du Colombier 			dir.length = 0;
6519a747e4fSDavid du Colombier 			dir.uid = mf->user;
6529a747e4fSDavid du Colombier 			dir.gid = mf->user;
6539a747e4fSDavid du Colombier 			dir.muid = mf->user;
6543e12c5d1SDavid du Colombier 			dir.atime = clock;	/* wrong */
6553e12c5d1SDavid du Colombier 			dir.mtime = clock;	/* wrong */
6569a747e4fSDavid du Colombier 			n = convD2M(&dir, buf, sizeof buf);
6573e12c5d1SDavid du Colombier 		}
6589a747e4fSDavid du Colombier 		job->reply.data = (char*)buf;
6593e12c5d1SDavid du Colombier 	} else {
66080ee5cbfSDavid du Colombier 		for(;;){
66180ee5cbfSDavid du Colombier 			/* look for an answer at the right offset */
662219b2ee8SDavid du Colombier 			toff = 0;
663219b2ee8SDavid du Colombier 			for(i = 0; mf->reply[i] && i < mf->nreply; i++){
664219b2ee8SDavid du Colombier 				n = mf->replylen[i];
665219b2ee8SDavid du Colombier 				if(off < toff + n)
666219b2ee8SDavid du Colombier 					break;
667219b2ee8SDavid du Colombier 				toff += n;
6683e12c5d1SDavid du Colombier 			}
66980ee5cbfSDavid du Colombier 			if(i < mf->nreply)
67080ee5cbfSDavid du Colombier 				break;		/* got something to return */
67180ee5cbfSDavid du Colombier 
67280ee5cbfSDavid du Colombier 			/* try looking up more answers */
67380ee5cbfSDavid du Colombier 			if(lookup(mf) == 0){
67480ee5cbfSDavid du Colombier 				/* no more */
675219b2ee8SDavid du Colombier 				n = 0;
676219b2ee8SDavid du Colombier 				goto send;
677219b2ee8SDavid du Colombier 			}
67880ee5cbfSDavid du Colombier 		}
67980ee5cbfSDavid du Colombier 
68080ee5cbfSDavid du Colombier 		/* give back a single reply (or part of one) */
6817dd7cddfSDavid du Colombier 		job->reply.data = mf->reply[i] + (off - toff);
682219b2ee8SDavid du Colombier 		if(cnt > toff - off + n)
683219b2ee8SDavid du Colombier 			n = toff - off + n;
684219b2ee8SDavid du Colombier 		else
685219b2ee8SDavid du Colombier 			n = cnt;
6863e12c5d1SDavid du Colombier 	}
6873e12c5d1SDavid du Colombier send:
6887dd7cddfSDavid du Colombier 	job->reply.count = n;
6897dd7cddfSDavid du Colombier 	sendmsg(job, err);
6907dd7cddfSDavid du Colombier }
69180ee5cbfSDavid du Colombier void
69280ee5cbfSDavid du Colombier cleanmf(Mfile *mf)
6937dd7cddfSDavid du Colombier {
6947dd7cddfSDavid du Colombier 	int i;
6957dd7cddfSDavid du Colombier 
6969a747e4fSDavid du Colombier 	if(mf->net != nil){
69780ee5cbfSDavid du Colombier 		free(mf->net);
69880ee5cbfSDavid du Colombier 		mf->net = nil;
6999a747e4fSDavid du Colombier 	}
7009a747e4fSDavid du Colombier 	if(mf->host != nil){
70180ee5cbfSDavid du Colombier 		free(mf->host);
70280ee5cbfSDavid du Colombier 		mf->host = nil;
7039a747e4fSDavid du Colombier 	}
7049a747e4fSDavid du Colombier 	if(mf->serv != nil){
70580ee5cbfSDavid du Colombier 		free(mf->serv);
70680ee5cbfSDavid du Colombier 		mf->serv = nil;
7079a747e4fSDavid du Colombier 	}
7089a747e4fSDavid du Colombier 	if(mf->rem != nil){
70980ee5cbfSDavid du Colombier 		free(mf->rem);
71080ee5cbfSDavid du Colombier 		mf->rem = nil;
7119a747e4fSDavid du Colombier 	}
71280ee5cbfSDavid du Colombier 	for(i = 0; i < mf->nreply; i++){
71380ee5cbfSDavid du Colombier 		free(mf->reply[i]);
71480ee5cbfSDavid du Colombier 		mf->reply[i] = nil;
71580ee5cbfSDavid du Colombier 		mf->replylen[i] = 0;
7167dd7cddfSDavid du Colombier 	}
71780ee5cbfSDavid du Colombier 	mf->nreply = 0;
71880ee5cbfSDavid du Colombier 	mf->nextnet = netlist;
7193e12c5d1SDavid du Colombier }
7203e12c5d1SDavid du Colombier 
7213e12c5d1SDavid du Colombier void
7227dd7cddfSDavid du Colombier rwrite(Job *job, Mfile *mf)
7233e12c5d1SDavid du Colombier {
7243e12c5d1SDavid du Colombier 	int cnt, n;
72580ee5cbfSDavid du Colombier 	char *err;
7267dd7cddfSDavid du Colombier 	char *field[4];
727271b8d73SDavid du Colombier 	char curerr[64];
7283e12c5d1SDavid du Colombier 
7293e12c5d1SDavid du Colombier 	err = 0;
7307dd7cddfSDavid du Colombier 	cnt = job->request.count;
7319a747e4fSDavid du Colombier 	if(mf->qid.type & QTDIR){
7323e12c5d1SDavid du Colombier 		err = "can't write directory";
7333e12c5d1SDavid du Colombier 		goto send;
7343e12c5d1SDavid du Colombier 	}
7353e12c5d1SDavid du Colombier 	if(cnt >= Maxrequest){
7363e12c5d1SDavid du Colombier 		err = "request too long";
7373e12c5d1SDavid du Colombier 		goto send;
7383e12c5d1SDavid du Colombier 	}
7397dd7cddfSDavid du Colombier 	job->request.data[cnt] = 0;
7403e12c5d1SDavid du Colombier 
7413e12c5d1SDavid du Colombier 	/*
742219b2ee8SDavid du Colombier 	 *  toggle debugging
743219b2ee8SDavid du Colombier 	 */
7447dd7cddfSDavid du Colombier 	if(strncmp(job->request.data, "debug", 5)==0){
745219b2ee8SDavid du Colombier 		debug ^= 1;
746219b2ee8SDavid du Colombier 		syslog(1, logfile, "debug %d", debug);
747219b2ee8SDavid du Colombier 		goto send;
748219b2ee8SDavid du Colombier 	}
749219b2ee8SDavid du Colombier 
750219b2ee8SDavid du Colombier 	/*
7517dd7cddfSDavid du Colombier 	 *  toggle debugging
7527dd7cddfSDavid du Colombier 	 */
7537dd7cddfSDavid du Colombier 	if(strncmp(job->request.data, "paranoia", 8)==0){
7547dd7cddfSDavid du Colombier 		paranoia ^= 1;
7557dd7cddfSDavid du Colombier 		syslog(1, logfile, "paranoia %d", paranoia);
7567dd7cddfSDavid du Colombier 		goto send;
7577dd7cddfSDavid du Colombier 	}
7587dd7cddfSDavid du Colombier 
7597dd7cddfSDavid du Colombier 	/*
7603e12c5d1SDavid du Colombier 	 *  add networks to the default list
7613e12c5d1SDavid du Colombier 	 */
7627dd7cddfSDavid du Colombier 	if(strncmp(job->request.data, "add ", 4)==0){
7637dd7cddfSDavid du Colombier 		if(job->request.data[cnt-1] == '\n')
7647dd7cddfSDavid du Colombier 			job->request.data[cnt-1] = 0;
7657dd7cddfSDavid du Colombier 		netadd(job->request.data+4);
7667dd7cddfSDavid du Colombier 		readipinterfaces();
7677dd7cddfSDavid du Colombier 		goto send;
7687dd7cddfSDavid du Colombier 	}
7697dd7cddfSDavid du Colombier 
7707dd7cddfSDavid du Colombier 	/*
7717dd7cddfSDavid du Colombier 	 *  refresh all state
7727dd7cddfSDavid du Colombier 	 */
7737dd7cddfSDavid du Colombier 	if(strncmp(job->request.data, "refresh", 7)==0){
7747dd7cddfSDavid du Colombier 		netinit(1);
7753e12c5d1SDavid du Colombier 		goto send;
7763e12c5d1SDavid du Colombier 	}
7773e12c5d1SDavid du Colombier 
77880ee5cbfSDavid du Colombier 	/* start transaction with a clean slate */
77980ee5cbfSDavid du Colombier 	cleanmf(mf);
78080ee5cbfSDavid du Colombier 
7813e12c5d1SDavid du Colombier 	/*
782219b2ee8SDavid du Colombier 	 *  look for a general query
783219b2ee8SDavid du Colombier 	 */
7847dd7cddfSDavid du Colombier 	if(*job->request.data == '!'){
7857dd7cddfSDavid du Colombier 		err = genquery(mf, job->request.data+1);
786219b2ee8SDavid du Colombier 		goto send;
787219b2ee8SDavid du Colombier 	}
788219b2ee8SDavid du Colombier 
7897dd7cddfSDavid du Colombier 	if(debug)
7907dd7cddfSDavid du Colombier 		syslog(0, logfile, "write %s", job->request.data);
7917dd7cddfSDavid du Colombier 	if(paranoia)
7927dd7cddfSDavid du Colombier 		syslog(0, paranoiafile, "write %s by %s", job->request.data, mf->user);
7937dd7cddfSDavid du Colombier 
794219b2ee8SDavid du Colombier 	/*
7953e12c5d1SDavid du Colombier 	 *  break up name
7963e12c5d1SDavid du Colombier 	 */
7977dd7cddfSDavid du Colombier 	n = getfields(job->request.data, field, 4, 1, "!");
7983e12c5d1SDavid du Colombier 	switch(n){
7993e12c5d1SDavid du Colombier 	case 1:
80080ee5cbfSDavid du Colombier 		mf->net = strdup("net");
80180ee5cbfSDavid du Colombier 		mf->host = strdup(field[0]);
8027dd7cddfSDavid du Colombier 		break;
8037dd7cddfSDavid du Colombier 	case 4:
80480ee5cbfSDavid du Colombier 		mf->rem = strdup(field[3]);
80580ee5cbfSDavid du Colombier 		/* fall through */
80680ee5cbfSDavid du Colombier 	case 3:
80780ee5cbfSDavid du Colombier 		mf->serv = strdup(field[2]);
80880ee5cbfSDavid du Colombier 		/* fall through */
80980ee5cbfSDavid du Colombier 	case 2:
81080ee5cbfSDavid du Colombier 		mf->host = strdup(field[1]);
81180ee5cbfSDavid du Colombier 		mf->net = strdup(field[0]);
8123e12c5d1SDavid du Colombier 		break;
8133e12c5d1SDavid du Colombier 	}
8143e12c5d1SDavid du Colombier 
81580ee5cbfSDavid du Colombier 	/*
81680ee5cbfSDavid du Colombier 	 *  do the first net worth of lookup
81780ee5cbfSDavid du Colombier 	 */
818271b8d73SDavid du Colombier 	if(lookup(mf) == 0){
819271b8d73SDavid du Colombier 		rerrstr(curerr, sizeof curerr);
820271b8d73SDavid du Colombier 		err = curerr;
821271b8d73SDavid du Colombier 	}
8223e12c5d1SDavid du Colombier send:
8237dd7cddfSDavid du Colombier 	job->reply.count = cnt;
8247dd7cddfSDavid du Colombier 	sendmsg(job, err);
8253e12c5d1SDavid du Colombier }
8263e12c5d1SDavid du Colombier 
8273e12c5d1SDavid du Colombier void
8287dd7cddfSDavid du Colombier rclunk(Job *job, Mfile *mf)
8293e12c5d1SDavid du Colombier {
83080ee5cbfSDavid du Colombier 	cleanmf(mf);
831a9f680aeSDavid du Colombier 	free(mf->user);
832a9f680aeSDavid du Colombier 	mf->user = 0;
8333e12c5d1SDavid du Colombier 	mf->busy = 0;
8343e12c5d1SDavid du Colombier 	mf->fid = 0;
8357dd7cddfSDavid du Colombier 	sendmsg(job, 0);
8363e12c5d1SDavid du Colombier }
8373e12c5d1SDavid du Colombier 
8383e12c5d1SDavid du Colombier void
8397dd7cddfSDavid du Colombier rremove(Job *job, Mfile *mf)
8403e12c5d1SDavid du Colombier {
8413e12c5d1SDavid du Colombier 	USED(mf);
8427dd7cddfSDavid du Colombier 	sendmsg(job, "remove permission denied");
8433e12c5d1SDavid du Colombier }
8443e12c5d1SDavid du Colombier 
8453e12c5d1SDavid du Colombier void
8467dd7cddfSDavid du Colombier rstat(Job *job, Mfile *mf)
8473e12c5d1SDavid du Colombier {
8483e12c5d1SDavid du Colombier 	Dir dir;
8499a747e4fSDavid du Colombier 	uchar buf[IOHDRSZ+Maxfdata];
8503e12c5d1SDavid du Colombier 
8519a747e4fSDavid du Colombier 	if(mf->qid.type & QTDIR){
8529a747e4fSDavid du Colombier 		dir.name = ".";
8539a747e4fSDavid du Colombier 		dir.mode = DMDIR|0555;
854219b2ee8SDavid du Colombier 	} else {
8559a747e4fSDavid du Colombier 		dir.name = "cs";
8563e12c5d1SDavid du Colombier 		dir.mode = 0666;
857219b2ee8SDavid du Colombier 	}
858219b2ee8SDavid du Colombier 	dir.qid = mf->qid;
8593e12c5d1SDavid du Colombier 	dir.length = 0;
8609a747e4fSDavid du Colombier 	dir.uid = mf->user;
8619a747e4fSDavid du Colombier 	dir.gid = mf->user;
8629a747e4fSDavid du Colombier 	dir.muid = mf->user;
8633e12c5d1SDavid du Colombier 	dir.atime = dir.mtime = time(0);
8649a747e4fSDavid du Colombier 	job->reply.nstat = convD2M(&dir, buf, sizeof buf);
8659a747e4fSDavid du Colombier 	job->reply.stat = buf;
8667dd7cddfSDavid du Colombier 	sendmsg(job, 0);
8673e12c5d1SDavid du Colombier }
8683e12c5d1SDavid du Colombier 
8693e12c5d1SDavid du Colombier void
8707dd7cddfSDavid du Colombier rwstat(Job *job, Mfile *mf)
8713e12c5d1SDavid du Colombier {
8723e12c5d1SDavid du Colombier 	USED(mf);
8737dd7cddfSDavid du Colombier 	sendmsg(job, "wstat permission denied");
8743e12c5d1SDavid du Colombier }
8753e12c5d1SDavid du Colombier 
8763e12c5d1SDavid du Colombier void
8777dd7cddfSDavid du Colombier sendmsg(Job *job, char *err)
8783e12c5d1SDavid du Colombier {
8793e12c5d1SDavid du Colombier 	int n;
8809a747e4fSDavid du Colombier 	uchar mdata[IOHDRSZ + Maxfdata];
8819a747e4fSDavid du Colombier 	char ename[ERRMAX];
8823e12c5d1SDavid du Colombier 
8833e12c5d1SDavid du Colombier 	if(err){
8847dd7cddfSDavid du Colombier 		job->reply.type = Rerror;
8859a747e4fSDavid du Colombier 		snprint(ename, sizeof(ename), "cs: %s", err);
8869a747e4fSDavid du Colombier 		job->reply.ename = ename;
8873e12c5d1SDavid du Colombier 	}else{
8887dd7cddfSDavid du Colombier 		job->reply.type = job->request.type+1;
8893e12c5d1SDavid du Colombier 	}
8907dd7cddfSDavid du Colombier 	job->reply.tag = job->request.tag;
8919a747e4fSDavid du Colombier 	n = convS2M(&job->reply, mdata, sizeof mdata);
892219b2ee8SDavid du Colombier 	if(n == 0){
8937dd7cddfSDavid du Colombier 		syslog(1, logfile, "sendmsg convS2M of %F returns 0", &job->reply);
894219b2ee8SDavid du Colombier 		abort();
895219b2ee8SDavid du Colombier 	}
8967dd7cddfSDavid du Colombier 	lock(&joblock);
8977dd7cddfSDavid du Colombier 	if(job->flushed == 0)
8989a747e4fSDavid du Colombier 		if(write(mfd[1], mdata, n)!=n)
8993e12c5d1SDavid du Colombier 			error("mount write");
9007dd7cddfSDavid du Colombier 	unlock(&joblock);
901219b2ee8SDavid du Colombier 	if(debug)
9027dd7cddfSDavid du Colombier 		syslog(0, logfile, "%F %d", &job->reply, n);
9033e12c5d1SDavid du Colombier }
9043e12c5d1SDavid du Colombier 
9053e12c5d1SDavid du Colombier void
9063e12c5d1SDavid du Colombier error(char *s)
9073e12c5d1SDavid du Colombier {
908bd389b36SDavid du Colombier 	syslog(1, "cs", "%s: %r", s);
909bd389b36SDavid du Colombier 	_exits(0);
9103e12c5d1SDavid du Colombier }
9113e12c5d1SDavid du Colombier 
9127dd7cddfSDavid du Colombier static int
9137dd7cddfSDavid du Colombier isvalidip(uchar *ip)
9147dd7cddfSDavid du Colombier {
9157dd7cddfSDavid du Colombier 	return ipcmp(ip, IPnoaddr) != 0 && ipcmp(ip, v4prefix) != 0;
9167dd7cddfSDavid du Colombier }
9173e12c5d1SDavid du Colombier 
9180103620dSDavid du Colombier static uchar loopbacknet[IPaddrlen] = {
9190103620dSDavid du Colombier 	0, 0, 0, 0,
9200103620dSDavid du Colombier 	0, 0, 0, 0,
9210103620dSDavid du Colombier 	0, 0, 0xff, 0xff,
9220103620dSDavid du Colombier 	127, 0, 0, 0
9230103620dSDavid du Colombier };
9240103620dSDavid du Colombier static uchar loopbackmask[IPaddrlen] = {
9250103620dSDavid du Colombier 	0xff, 0xff, 0xff, 0xff,
9260103620dSDavid du Colombier 	0xff, 0xff, 0xff, 0xff,
9270103620dSDavid du Colombier 	0xff, 0xff, 0xff, 0xff,
9280103620dSDavid du Colombier 	0xff, 0, 0, 0
9290103620dSDavid du Colombier };
9300103620dSDavid du Colombier 
9317dd7cddfSDavid du Colombier void
9327dd7cddfSDavid du Colombier readipinterfaces(void)
9337dd7cddfSDavid du Colombier {
9340103620dSDavid du Colombier 	if(myipaddr(ipa, mntpt) != 0)
9350103620dSDavid du Colombier 		ipmove(ipa, IPnoaddr);
9367dd7cddfSDavid du Colombier 	sprint(ipaddr, "%I", ipa);
9377dd7cddfSDavid du Colombier 	if (debug)
9387dd7cddfSDavid du Colombier 		syslog(0, "dns", "ipaddr is %s\n", ipaddr);
9397dd7cddfSDavid du Colombier }
9403e12c5d1SDavid du Colombier 
9413e12c5d1SDavid du Colombier /*
9427dd7cddfSDavid du Colombier  *  get the system name
9433e12c5d1SDavid du Colombier  */
9443e12c5d1SDavid du Colombier void
9453e12c5d1SDavid du Colombier ipid(void)
9463e12c5d1SDavid du Colombier {
9473e12c5d1SDavid du Colombier 	uchar addr[6];
948a9f680aeSDavid du Colombier 	Ndbtuple *t, *tt;
949219b2ee8SDavid du Colombier 	char *p, *attr;
9503e12c5d1SDavid du Colombier 	Ndbs s;
9513e12c5d1SDavid du Colombier 	int f;
9527dd7cddfSDavid du Colombier 	char buf[Maxpath];
9533e12c5d1SDavid du Colombier 
954219b2ee8SDavid du Colombier 	/* use environment, ether addr, or ipaddr to get system name */
95595a264b3SDavid du Colombier 	if(mysysname == 0){
9567dd7cddfSDavid du Colombier 		/*
9577dd7cddfSDavid du Colombier 		 *  environment has priority.
9587dd7cddfSDavid du Colombier 		 *
9597dd7cddfSDavid du Colombier 		 *  on the sgi power the default system name
9607dd7cddfSDavid du Colombier 		 *  is the ip address.  ignore that.
9617dd7cddfSDavid du Colombier 		 *
9627dd7cddfSDavid du Colombier 		 */
963219b2ee8SDavid du Colombier 		p = getenv("sysname");
964447d6a7dSDavid du Colombier 		if(p && *p){
965219b2ee8SDavid du Colombier 			attr = ipattr(p);
966219b2ee8SDavid du Colombier 			if(strcmp(attr, "ip") != 0)
96795a264b3SDavid du Colombier 				mysysname = strdup(p);
9683e12c5d1SDavid du Colombier 		}
9693e12c5d1SDavid du Colombier 
9703e12c5d1SDavid du Colombier 		/*
9717dd7cddfSDavid du Colombier 		 *  the /net/ndb contains what the network
9727dd7cddfSDavid du Colombier 		 *  figured out from DHCP.  use that name if
9737dd7cddfSDavid du Colombier 		 *  there is one.
9743e12c5d1SDavid du Colombier 		 */
97595a264b3SDavid du Colombier 		if(mysysname == 0 && netdb != nil){
9767dd7cddfSDavid du Colombier 			ndbreopen(netdb);
977a9f680aeSDavid du Colombier 			for(tt = t = ndbparse(netdb); t != nil; t = t->entry){
9787dd7cddfSDavid du Colombier 				if(strcmp(t->attr, "sys") == 0){
97995a264b3SDavid du Colombier 					mysysname = strdup(t->val);
9803e12c5d1SDavid du Colombier 					break;
9813e12c5d1SDavid du Colombier 				}
9827dd7cddfSDavid du Colombier 			}
983a9f680aeSDavid du Colombier 			ndbfree(tt);
9847dd7cddfSDavid du Colombier 		}
9857dd7cddfSDavid du Colombier 
9867dd7cddfSDavid du Colombier 		/* next network database, ip address, and ether address to find a name */
98795a264b3SDavid du Colombier 		if(mysysname == 0){
9887dd7cddfSDavid du Colombier 			t = nil;
9897dd7cddfSDavid du Colombier 			if(isvalidip(ipa))
99057837e0bSDavid du Colombier 				free(ndbgetvalue(db, &s, "ip", ipaddr, "sys", &t));
99195a264b3SDavid du Colombier 			if(t == nil){
9927dd7cddfSDavid du Colombier 				for(f = 0; f < 3; f++){
9937dd7cddfSDavid du Colombier 					snprint(buf, sizeof buf, "%s/ether%d", mntpt, f);
9947dd7cddfSDavid du Colombier 					if(myetheraddr(addr, buf) >= 0){
9957dd7cddfSDavid du Colombier 						snprint(eaddr, sizeof(eaddr), "%E", addr);
99657837e0bSDavid du Colombier 						free(ndbgetvalue(db, &s, "ether", eaddr, "sys", &t));
9977dd7cddfSDavid du Colombier 						if(t != nil)
9987dd7cddfSDavid du Colombier 							break;
9997dd7cddfSDavid du Colombier 					}
10007dd7cddfSDavid du Colombier 				}
10017dd7cddfSDavid du Colombier 			}
1002b7327ca2SDavid du Colombier 			for(tt = t; tt != nil; tt = tt->entry){
1003b7327ca2SDavid du Colombier 				if(strcmp(tt->attr, "sys") == 0){
1004b7327ca2SDavid du Colombier 					mysysname = strdup(tt->val);
100595a264b3SDavid du Colombier 					break;
100695a264b3SDavid du Colombier 				}
1007b7327ca2SDavid du Colombier 			}
10087dd7cddfSDavid du Colombier 			ndbfree(t);
10097dd7cddfSDavid du Colombier 		}
10107dd7cddfSDavid du Colombier 
101180ee5cbfSDavid du Colombier 		/* nothing else worked, use the ip address */
101295a264b3SDavid du Colombier 		if(mysysname == 0 && isvalidip(ipa))
101395a264b3SDavid du Colombier 			mysysname = strdup(ipaddr);
101480ee5cbfSDavid du Colombier 
101580ee5cbfSDavid du Colombier 
1016dc5a79c1SDavid du Colombier 		/* set /dev/sysname if we now know it */
101795a264b3SDavid du Colombier 		if(mysysname){
10187dd7cddfSDavid du Colombier 			f = open("/dev/sysname", OWRITE);
10197dd7cddfSDavid du Colombier 			if(f >= 0){
10207dd7cddfSDavid du Colombier 				write(f, mysysname, strlen(mysysname));
10213e12c5d1SDavid du Colombier 				close(f);
10223e12c5d1SDavid du Colombier 			}
10233e12c5d1SDavid du Colombier 		}
10243e12c5d1SDavid du Colombier 	}
10253e12c5d1SDavid du Colombier }
10263e12c5d1SDavid du Colombier 
10273e12c5d1SDavid du Colombier /*
10283e12c5d1SDavid du Colombier  *  Set up a list of default networks by looking for
10293e12c5d1SDavid du Colombier  *  /net/ * /clone.
10303e12c5d1SDavid du Colombier  */
10313e12c5d1SDavid du Colombier void
10327dd7cddfSDavid du Colombier netinit(int background)
10333e12c5d1SDavid du Colombier {
10347dd7cddfSDavid du Colombier 	char clone[Maxpath];
10353e12c5d1SDavid du Colombier 	Network *np;
10367dd7cddfSDavid du Colombier 	static int working;
10377dd7cddfSDavid du Colombier 
10387dd7cddfSDavid du Colombier 	if(background){
10397dd7cddfSDavid du Colombier 		switch(rfork(RFPROC|RFNOTEG|RFMEM|RFNOWAIT)){
10407dd7cddfSDavid du Colombier 		case 0:
10417dd7cddfSDavid du Colombier 			break;
10427dd7cddfSDavid du Colombier 		default:
10437dd7cddfSDavid du Colombier 			return;
10447dd7cddfSDavid du Colombier 		}
10457dd7cddfSDavid du Colombier 		lock(&netlock);
10467dd7cddfSDavid du Colombier 	}
10473e12c5d1SDavid du Colombier 
10483e12c5d1SDavid du Colombier 	/* add the mounted networks to the default list */
10493e12c5d1SDavid du Colombier 	for(np = network; np->net; np++){
10507dd7cddfSDavid du Colombier 		if(np->considered)
10517dd7cddfSDavid du Colombier 			continue;
10527dd7cddfSDavid du Colombier 		snprint(clone, sizeof(clone), "%s/%s/clone", mntpt, np->net);
10539a747e4fSDavid du Colombier 		if(access(clone, AEXIST) < 0)
10543e12c5d1SDavid du Colombier 			continue;
10553e12c5d1SDavid du Colombier 		if(netlist)
10563e12c5d1SDavid du Colombier 			last->next = np;
10573e12c5d1SDavid du Colombier 		else
10583e12c5d1SDavid du Colombier 			netlist = np;
10593e12c5d1SDavid du Colombier 		last = np;
10603e12c5d1SDavid du Colombier 		np->next = 0;
10617dd7cddfSDavid du Colombier 		np->considered = 1;
10623e12c5d1SDavid du Colombier 	}
10633e12c5d1SDavid du Colombier 
10647dd7cddfSDavid du Colombier 	/* find out what our ip address is */
10657dd7cddfSDavid du Colombier 	readipinterfaces();
10663e12c5d1SDavid du Colombier 
10677dd7cddfSDavid du Colombier 	/* set the system name if we need to, these says ip is all we have */
10683e12c5d1SDavid du Colombier 	ipid();
10693e12c5d1SDavid du Colombier 
1070219b2ee8SDavid du Colombier 	if(debug)
10717dd7cddfSDavid du Colombier 		syslog(0, logfile, "mysysname %s eaddr %s ipaddr %s ipa %I\n",
107295a264b3SDavid du Colombier 			mysysname?mysysname:"???", eaddr, ipaddr, ipa);
10737dd7cddfSDavid du Colombier 
10747dd7cddfSDavid du Colombier 	if(background){
10757dd7cddfSDavid du Colombier 		unlock(&netlock);
10767dd7cddfSDavid du Colombier 		_exits(0);
10777dd7cddfSDavid du Colombier 	}
10783e12c5d1SDavid du Colombier }
10793e12c5d1SDavid du Colombier 
10803e12c5d1SDavid du Colombier /*
10813e12c5d1SDavid du Colombier  *  add networks to the standard list
10823e12c5d1SDavid du Colombier  */
10833e12c5d1SDavid du Colombier void
10843e12c5d1SDavid du Colombier netadd(char *p)
10853e12c5d1SDavid du Colombier {
10863e12c5d1SDavid du Colombier 	Network *np;
10873e12c5d1SDavid du Colombier 	char *field[12];
10883e12c5d1SDavid du Colombier 	int i, n;
10893e12c5d1SDavid du Colombier 
10907dd7cddfSDavid du Colombier 	n = getfields(p, field, 12, 1, " ");
10913e12c5d1SDavid du Colombier 	for(i = 0; i < n; i++){
10923e12c5d1SDavid du Colombier 		for(np = network; np->net; np++){
10933e12c5d1SDavid du Colombier 			if(strcmp(field[i], np->net) != 0)
10943e12c5d1SDavid du Colombier 				continue;
10957dd7cddfSDavid du Colombier 			if(np->considered)
10963e12c5d1SDavid du Colombier 				break;
10973e12c5d1SDavid du Colombier 			if(netlist)
10983e12c5d1SDavid du Colombier 				last->next = np;
10993e12c5d1SDavid du Colombier 			else
11003e12c5d1SDavid du Colombier 				netlist = np;
11013e12c5d1SDavid du Colombier 			last = np;
11023e12c5d1SDavid du Colombier 			np->next = 0;
11037dd7cddfSDavid du Colombier 			np->considered = 1;
11043e12c5d1SDavid du Colombier 		}
11053e12c5d1SDavid du Colombier 	}
11063e12c5d1SDavid du Colombier }
11073e12c5d1SDavid du Colombier 
110880ee5cbfSDavid du Colombier int
110980ee5cbfSDavid du Colombier lookforproto(Ndbtuple *t, char *proto)
111080ee5cbfSDavid du Colombier {
111180ee5cbfSDavid du Colombier 	for(; t != nil; t = t->entry)
111280ee5cbfSDavid du Colombier 		if(strcmp(t->attr, "proto") == 0 && strcmp(t->val, proto) == 0)
111380ee5cbfSDavid du Colombier 			return 1;
111480ee5cbfSDavid du Colombier 	return 0;
111580ee5cbfSDavid du Colombier }
111680ee5cbfSDavid du Colombier 
1117219b2ee8SDavid du Colombier /*
11183e12c5d1SDavid du Colombier  *  lookup a request.  the network "net" means we should pick the
11193e12c5d1SDavid du Colombier  *  best network to get there.
11203e12c5d1SDavid du Colombier  */
11213e12c5d1SDavid du Colombier int
112280ee5cbfSDavid du Colombier lookup(Mfile *mf)
11233e12c5d1SDavid du Colombier {
112480ee5cbfSDavid du Colombier 	Network *np;
1125219b2ee8SDavid du Colombier 	char *cp;
1126219b2ee8SDavid du Colombier 	Ndbtuple *nt, *t;
1127219b2ee8SDavid du Colombier 	char reply[Maxreply];
112880ee5cbfSDavid du Colombier 	int i, rv;
112980ee5cbfSDavid du Colombier 	int hack;
11303e12c5d1SDavid du Colombier 
11313e12c5d1SDavid du Colombier 	/* open up the standard db files */
11323e12c5d1SDavid du Colombier 	if(db == 0)
11337dd7cddfSDavid du Colombier 		ndbinit();
11343e12c5d1SDavid du Colombier 	if(db == 0)
113580ee5cbfSDavid du Colombier 		error("can't open mf->network database\n");
11363e12c5d1SDavid du Colombier 
113780ee5cbfSDavid du Colombier 	rv = 0;
113880ee5cbfSDavid du Colombier 
113980ee5cbfSDavid du Colombier 	if(mf->net == nil)
114080ee5cbfSDavid du Colombier 		return 0;	/* must have been a genquery */
114180ee5cbfSDavid du Colombier 
114280ee5cbfSDavid du Colombier 	if(strcmp(mf->net, "net") == 0){
11433e12c5d1SDavid du Colombier 		/*
11443e12c5d1SDavid du Colombier 		 *  go through set of default nets
11453e12c5d1SDavid du Colombier 		 */
114680ee5cbfSDavid du Colombier 		for(np = mf->nextnet; np; np = np->next){
114780ee5cbfSDavid du Colombier 			nt = (*np->lookup)(np, mf->host, mf->serv, 1);
114880ee5cbfSDavid du Colombier 			if(nt == nil)
1149219b2ee8SDavid du Colombier 				continue;
115080ee5cbfSDavid du Colombier 			hack = np->fasttimeouthack && !lookforproto(nt, np->net);
115180ee5cbfSDavid du Colombier 			for(t = nt; mf->nreply < Nreply && t; t = t->entry){
115280ee5cbfSDavid du Colombier 				cp = (*np->trans)(t, np, mf->serv, mf->rem, hack);
1153219b2ee8SDavid du Colombier 				if(cp){
115480ee5cbfSDavid du Colombier 					/* avoid duplicates */
115580ee5cbfSDavid du Colombier 					for(i = 0; i < mf->nreply; i++)
115680ee5cbfSDavid du Colombier 						if(strcmp(mf->reply[i], cp) == 0)
115780ee5cbfSDavid du Colombier 							break;
115880ee5cbfSDavid du Colombier 					if(i == mf->nreply){
115980ee5cbfSDavid du Colombier 						/* save the reply */
1160219b2ee8SDavid du Colombier 						mf->replylen[mf->nreply] = strlen(cp);
1161219b2ee8SDavid du Colombier 						mf->reply[mf->nreply++] = cp;
116280ee5cbfSDavid du Colombier 						rv++;
1163219b2ee8SDavid du Colombier 					}
1164219b2ee8SDavid du Colombier 				}
1165219b2ee8SDavid du Colombier 			}
1166219b2ee8SDavid du Colombier 			ndbfree(nt);
116780ee5cbfSDavid du Colombier 			np = np->next;
116880ee5cbfSDavid du Colombier 			break;
116980ee5cbfSDavid du Colombier 		}
117080ee5cbfSDavid du Colombier 		mf->nextnet = np;
117180ee5cbfSDavid du Colombier 		return rv;
117280ee5cbfSDavid du Colombier 	}
117380ee5cbfSDavid du Colombier 
117480ee5cbfSDavid du Colombier 	/*
117580ee5cbfSDavid du Colombier 	 *  if not /net, we only get one lookup
117680ee5cbfSDavid du Colombier 	 */
117780ee5cbfSDavid du Colombier 	if(mf->nreply != 0)
1178219b2ee8SDavid du Colombier 		return 0;
117980ee5cbfSDavid du Colombier 	/*
118080ee5cbfSDavid du Colombier 	 *  look for a specific network
118180ee5cbfSDavid du Colombier 	 */
118295a264b3SDavid du Colombier 	for(np = netlist; np && np->net != nil; np++){
118380ee5cbfSDavid du Colombier 		if(np->fasttimeouthack)
118480ee5cbfSDavid du Colombier 			continue;
118580ee5cbfSDavid du Colombier 		if(strcmp(np->net, mf->net) == 0)
118680ee5cbfSDavid du Colombier 			break;
118780ee5cbfSDavid du Colombier 	}
118880ee5cbfSDavid du Colombier 
118995a264b3SDavid du Colombier 	if(np && np->net != nil){
119080ee5cbfSDavid du Colombier 		/*
119180ee5cbfSDavid du Colombier 		 *  known network
119280ee5cbfSDavid du Colombier 		 */
119380ee5cbfSDavid du Colombier 		nt = (*np->lookup)(np, mf->host, mf->serv, 1);
119480ee5cbfSDavid du Colombier 		for(t = nt; mf->nreply < Nreply && t; t = t->entry){
119580ee5cbfSDavid du Colombier 			cp = (*np->trans)(t, np, mf->serv, mf->rem, 0);
119680ee5cbfSDavid du Colombier 			if(cp){
119780ee5cbfSDavid du Colombier 				mf->replylen[mf->nreply] = strlen(cp);
119880ee5cbfSDavid du Colombier 				mf->reply[mf->nreply++] = cp;
119980ee5cbfSDavid du Colombier 				rv++;
120080ee5cbfSDavid du Colombier 			}
120180ee5cbfSDavid du Colombier 		}
120280ee5cbfSDavid du Colombier 		ndbfree(nt);
120380ee5cbfSDavid du Colombier 		return rv;
12043e12c5d1SDavid du Colombier 	} else {
12053e12c5d1SDavid du Colombier 		/*
1206219b2ee8SDavid du Colombier 		 *  not a known network, don't translate host or service
12073e12c5d1SDavid du Colombier 		 */
120880ee5cbfSDavid du Colombier 		if(mf->serv)
12097dd7cddfSDavid du Colombier 			snprint(reply, sizeof(reply), "%s/%s/clone %s!%s",
121080ee5cbfSDavid du Colombier 				mntpt, mf->net, mf->host, mf->serv);
1211bd389b36SDavid du Colombier 		else
12127dd7cddfSDavid du Colombier 			snprint(reply, sizeof(reply), "%s/%s/clone %s",
121380ee5cbfSDavid du Colombier 				mntpt, mf->net, mf->host);
1214219b2ee8SDavid du Colombier 		mf->reply[0] = strdup(reply);
1215219b2ee8SDavid du Colombier 		mf->replylen[0] = strlen(reply);
1216219b2ee8SDavid du Colombier 		mf->nreply = 1;
121780ee5cbfSDavid du Colombier 		return 1;
12183e12c5d1SDavid du Colombier 	}
12193e12c5d1SDavid du Colombier }
12203e12c5d1SDavid du Colombier 
12213e12c5d1SDavid du Colombier /*
12223e12c5d1SDavid du Colombier  *  translate an ip service name into a port number.  If it's a numeric port
12233e12c5d1SDavid du Colombier  *  number, look for restricted access.
12243e12c5d1SDavid du Colombier  *
12253e12c5d1SDavid du Colombier  *  the service '*' needs no translation.
12263e12c5d1SDavid du Colombier  */
12273e12c5d1SDavid du Colombier char*
122895a264b3SDavid du Colombier ipserv(Network *np, char *name, char *buf, int blen)
12293e12c5d1SDavid du Colombier {
12303e12c5d1SDavid du Colombier 	char *p;
12313e12c5d1SDavid du Colombier 	int alpha = 0;
12323e12c5d1SDavid du Colombier 	int restr = 0;
123395a264b3SDavid du Colombier 	char port[10];
12343e12c5d1SDavid du Colombier 	Ndbtuple *t, *nt;
12353e12c5d1SDavid du Colombier 	Ndbs s;
12363e12c5d1SDavid du Colombier 
12373e12c5d1SDavid du Colombier 	/* '*' means any service */
12383e12c5d1SDavid du Colombier 	if(strcmp(name, "*")==0){
12393e12c5d1SDavid du Colombier 		strcpy(buf, name);
12403e12c5d1SDavid du Colombier 		return buf;
12413e12c5d1SDavid du Colombier 	}
12423e12c5d1SDavid du Colombier 
12433e12c5d1SDavid du Colombier 	/*  see if it's numeric or symbolic */
12443e12c5d1SDavid du Colombier 	port[0] = 0;
12453e12c5d1SDavid du Colombier 	for(p = name; *p; p++){
12463e12c5d1SDavid du Colombier 		if(isdigit(*p))
12479a747e4fSDavid du Colombier 			{}
12483e12c5d1SDavid du Colombier 		else if(isalpha(*p) || *p == '-' || *p == '$')
12493e12c5d1SDavid du Colombier 			alpha = 1;
12503e12c5d1SDavid du Colombier 		else
12513e12c5d1SDavid du Colombier 			return 0;
12523e12c5d1SDavid du Colombier 	}
125357837e0bSDavid du Colombier 	t = nil;
125457837e0bSDavid du Colombier 	p = nil;
12553e12c5d1SDavid du Colombier 	if(alpha){
125657837e0bSDavid du Colombier 		p = ndbgetvalue(db, &s, np->net, name, "port", &t);
1257b7327ca2SDavid du Colombier 		if(p == nil)
1258b7327ca2SDavid du Colombier 			return 0;
12593e12c5d1SDavid du Colombier 	} else {
12603cc1eb97SDavid du Colombier 		/* look up only for tcp ports < 1024 to get the restricted
12613cc1eb97SDavid du Colombier 		 * attribute
12623cc1eb97SDavid du Colombier 		 */
12633cc1eb97SDavid du Colombier 		if(atoi(name) < 1024 && strcmp(np->net, "tcp") == 0)
126457837e0bSDavid du Colombier 			p = ndbgetvalue(db, &s, "port", name, "port", &t);
126557837e0bSDavid du Colombier 		if(p == nil)
126657837e0bSDavid du Colombier 			p = strdup(name);
12673e12c5d1SDavid du Colombier 	}
12683e12c5d1SDavid du Colombier 
12693e12c5d1SDavid du Colombier 	if(t){
12703e12c5d1SDavid du Colombier 		for(nt = t; nt; nt = nt->entry)
12713e12c5d1SDavid du Colombier 			if(strcmp(nt->attr, "restricted") == 0)
12723e12c5d1SDavid du Colombier 				restr = 1;
12733e12c5d1SDavid du Colombier 		ndbfree(t);
12743e12c5d1SDavid du Colombier 	}
127557837e0bSDavid du Colombier 	snprint(buf, blen, "%s%s", p, restr ? "!r" : "");
127657837e0bSDavid du Colombier 	free(p);
127757837e0bSDavid du Colombier 
12783e12c5d1SDavid du Colombier 	return buf;
12793e12c5d1SDavid du Colombier }
12803e12c5d1SDavid du Colombier 
12813e12c5d1SDavid du Colombier /*
12827dd7cddfSDavid du Colombier  *  lookup an ip attribute
12833e12c5d1SDavid du Colombier  */
12847dd7cddfSDavid du Colombier int
128595a264b3SDavid du Colombier ipattrlookup(Ndb *db, char *ipa, char *attr, char *val, int vlen)
12863e12c5d1SDavid du Colombier {
12873e12c5d1SDavid du Colombier 
12887dd7cddfSDavid du Colombier 	Ndbtuple *t, *nt;
12897dd7cddfSDavid du Colombier 	char *alist[2];
12903e12c5d1SDavid du Colombier 
12917dd7cddfSDavid du Colombier 	alist[0] = attr;
12927dd7cddfSDavid du Colombier 	t = ndbipinfo(db, "ip", ipa, alist, 1);
12937dd7cddfSDavid du Colombier 	if(t == nil)
12947dd7cddfSDavid du Colombier 		return 0;
12959a747e4fSDavid du Colombier 	for(nt = t; nt != nil; nt = nt->entry){
12967dd7cddfSDavid du Colombier 		if(strcmp(nt->attr, attr) == 0){
129795a264b3SDavid du Colombier 			nstrcpy(val, nt->val, vlen);
12983e12c5d1SDavid du Colombier 			ndbfree(t);
12997dd7cddfSDavid du Colombier 			return 1;
1300219b2ee8SDavid du Colombier 		}
13019a747e4fSDavid du Colombier 	}
13023e12c5d1SDavid du Colombier 
13037dd7cddfSDavid du Colombier 	/* we shouldn't get here */
13043e12c5d1SDavid du Colombier 	ndbfree(t);
13057dd7cddfSDavid du Colombier 	return 0;
13063e12c5d1SDavid du Colombier }
13073e12c5d1SDavid du Colombier 
13083e12c5d1SDavid du Colombier /*
13093e12c5d1SDavid du Colombier  *  lookup (and translate) an ip destination
13103e12c5d1SDavid du Colombier  */
1311219b2ee8SDavid du Colombier Ndbtuple*
1312219b2ee8SDavid du Colombier iplookup(Network *np, char *host, char *serv, int nolookup)
13133e12c5d1SDavid du Colombier {
13149dfc0cb2SDavid du Colombier 	char *attr, *dnsname;
13157dd7cddfSDavid du Colombier 	Ndbtuple *t, *nt;
13163e12c5d1SDavid du Colombier 	Ndbs s;
131795a264b3SDavid du Colombier 	char ts[Maxservice];
131895a264b3SDavid du Colombier 	char dollar[Maxhost];
13197dd7cddfSDavid du Colombier 	uchar ip[IPaddrlen];
13207dd7cddfSDavid du Colombier 	uchar net[IPaddrlen];
13217dd7cddfSDavid du Colombier 	uchar tnet[IPaddrlen];
13227dd7cddfSDavid du Colombier 	Ipifc *ifc;
13239a747e4fSDavid du Colombier 	Iplifc *lifc;
13243e12c5d1SDavid du Colombier 
1325219b2ee8SDavid du Colombier 	USED(nolookup);
1326219b2ee8SDavid du Colombier 
13273e12c5d1SDavid du Colombier 	/*
13283e12c5d1SDavid du Colombier 	 *  start with the service since it's the most likely to fail
13293e12c5d1SDavid du Colombier 	 *  and costs the least
13303e12c5d1SDavid du Colombier 	 */
13317dd7cddfSDavid du Colombier 	werrstr("can't translate address");
133295a264b3SDavid du Colombier 	if(serv==0 || ipserv(np, serv, ts, sizeof ts) == 0){
1333271b8d73SDavid du Colombier 		werrstr("can't translate service");
1334219b2ee8SDavid du Colombier 		return 0;
13357dd7cddfSDavid du Colombier 	}
13363e12c5d1SDavid du Colombier 
13373e12c5d1SDavid du Colombier 	/* for dial strings with no host */
1338219b2ee8SDavid du Colombier 	if(strcmp(host, "*") == 0)
133995a264b3SDavid du Colombier 		return ndbnew("ip", "*");
13403e12c5d1SDavid du Colombier 
13413e12c5d1SDavid du Colombier 	/*
13427dd7cddfSDavid du Colombier 	 *  hack till we go v6 :: = 0.0.0.0
13437dd7cddfSDavid du Colombier 	 */
13447dd7cddfSDavid du Colombier 	if(strcmp("::", host) == 0)
134595a264b3SDavid du Colombier 		return ndbnew("ip", "*");
13467dd7cddfSDavid du Colombier 
13477dd7cddfSDavid du Colombier 	/*
13483e12c5d1SDavid du Colombier 	 *  '$' means the rest of the name is an attribute that we
13493e12c5d1SDavid du Colombier 	 *  need to search for
13503e12c5d1SDavid du Colombier 	 */
13513e12c5d1SDavid du Colombier 	if(*host == '$'){
135295a264b3SDavid du Colombier 		if(ipattrlookup(db, ipaddr, host+1, dollar, sizeof dollar))
13533e12c5d1SDavid du Colombier 			host = dollar;
13543e12c5d1SDavid du Colombier 	}
13553e12c5d1SDavid du Colombier 
13563e12c5d1SDavid du Colombier 	/*
13577dd7cddfSDavid du Colombier 	 *  turn '[ip address]' into just 'ip address'
13587dd7cddfSDavid du Colombier 	 */
13597dd7cddfSDavid du Colombier 	if(*host == '[' && host[strlen(host)-1] == ']'){
13607dd7cddfSDavid du Colombier 		host++;
13617dd7cddfSDavid du Colombier 		host[strlen(host)-1] = 0;
13627dd7cddfSDavid du Colombier 	}
13637dd7cddfSDavid du Colombier 
13647dd7cddfSDavid du Colombier 	/*
13653e12c5d1SDavid du Colombier 	 *  just accept addresses
13663e12c5d1SDavid du Colombier 	 */
1367219b2ee8SDavid du Colombier 	attr = ipattr(host);
1368219b2ee8SDavid du Colombier 	if(strcmp(attr, "ip") == 0)
136995a264b3SDavid du Colombier 		return ndbnew("ip", host);
13703e12c5d1SDavid du Colombier 
13713e12c5d1SDavid du Colombier 	/*
13723e12c5d1SDavid du Colombier 	 *  give the domain name server the first opportunity to
1373bd389b36SDavid du Colombier 	 *  resolve domain names.  if that fails try the database.
13743e12c5d1SDavid du Colombier 	 */
13753e12c5d1SDavid du Colombier 	t = 0;
1376271b8d73SDavid du Colombier 	werrstr("can't translate address");
13773e12c5d1SDavid du Colombier 	if(strcmp(attr, "dom") == 0)
13787dd7cddfSDavid du Colombier 		t = dnsiplookup(host, &s);
13793e12c5d1SDavid du Colombier 	if(t == 0)
138057837e0bSDavid du Colombier 		free(ndbgetvalue(db, &s, attr, host, "ip", &t));
13819dfc0cb2SDavid du Colombier 	if(t == 0){
13829dfc0cb2SDavid du Colombier 		dnsname = ndbgetvalue(db, &s, attr, host, "dom", nil);
13839dfc0cb2SDavid du Colombier 		if(dnsname){
13849dfc0cb2SDavid du Colombier 			t = dnsiplookup(dnsname, &s);
13859dfc0cb2SDavid du Colombier 			free(dnsname);
13869dfc0cb2SDavid du Colombier 		}
13879dfc0cb2SDavid du Colombier 	}
13883e12c5d1SDavid du Colombier 	if(t == 0)
13897dd7cddfSDavid du Colombier 		t = dnsiplookup(host, &s);
13907dd7cddfSDavid du Colombier 	if(t == 0)
1391219b2ee8SDavid du Colombier 		return 0;
1392bd389b36SDavid du Colombier 
1393bd389b36SDavid du Colombier 	/*
1394bd389b36SDavid du Colombier 	 *  reorder the tuple to have the matched line first and
1395bd389b36SDavid du Colombier 	 *  save that in the request structure.
1396bd389b36SDavid du Colombier 	 */
13977dd7cddfSDavid du Colombier 	t = reorder(t, s.t);
13987dd7cddfSDavid du Colombier 
13997dd7cddfSDavid du Colombier 	/*
14007dd7cddfSDavid du Colombier 	 * reorder according to our interfaces
14017dd7cddfSDavid du Colombier 	 */
14027dd7cddfSDavid du Colombier 	lock(&ipifclock);
14039a747e4fSDavid du Colombier 	for(ifc = ipifcs; ifc != nil; ifc = ifc->next){
14049a747e4fSDavid du Colombier 		for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
14059a747e4fSDavid du Colombier 			maskip(lifc->ip, lifc->mask, net);
14067dd7cddfSDavid du Colombier 			for(nt = t; nt; nt = nt->entry){
14077dd7cddfSDavid du Colombier 				if(strcmp(nt->attr, "ip") != 0)
14087dd7cddfSDavid du Colombier 					continue;
14097dd7cddfSDavid du Colombier 				parseip(ip, nt->val);
14109a747e4fSDavid du Colombier 				maskip(ip, lifc->mask, tnet);
14117dd7cddfSDavid du Colombier 				if(memcmp(net, tnet, IPaddrlen) == 0){
14127dd7cddfSDavid du Colombier 					t = reorder(t, nt);
14137dd7cddfSDavid du Colombier 					unlock(&ipifclock);
14147dd7cddfSDavid du Colombier 					return t;
14157dd7cddfSDavid du Colombier 				}
14167dd7cddfSDavid du Colombier 			}
14177dd7cddfSDavid du Colombier 		}
14189a747e4fSDavid du Colombier 	}
14197dd7cddfSDavid du Colombier 	unlock(&ipifclock);
14207dd7cddfSDavid du Colombier 
14217dd7cddfSDavid du Colombier 	return t;
14223e12c5d1SDavid du Colombier }
14233e12c5d1SDavid du Colombier 
14243e12c5d1SDavid du Colombier /*
14253e12c5d1SDavid du Colombier  *  translate an ip address
14263e12c5d1SDavid du Colombier  */
1427219b2ee8SDavid du Colombier char*
142880ee5cbfSDavid du Colombier iptrans(Ndbtuple *t, Network *np, char *serv, char *rem, int hack)
14293e12c5d1SDavid du Colombier {
143095a264b3SDavid du Colombier 	char ts[Maxservice];
1431219b2ee8SDavid du Colombier 	char reply[Maxreply];
143295a264b3SDavid du Colombier 	char x[Maxservice];
14333e12c5d1SDavid du Colombier 
1434219b2ee8SDavid du Colombier 	if(strcmp(t->attr, "ip") != 0)
14353e12c5d1SDavid du Colombier 		return 0;
1436219b2ee8SDavid du Colombier 
143795a264b3SDavid du Colombier 	if(serv == 0 || ipserv(np, serv, ts, sizeof ts) == 0){
1438271b8d73SDavid du Colombier 		werrstr("can't translate service");
1439219b2ee8SDavid du Colombier 		return 0;
1440271b8d73SDavid du Colombier 	}
14417dd7cddfSDavid du Colombier 	if(rem != nil)
14427dd7cddfSDavid du Colombier 		snprint(x, sizeof(x), "!%s", rem);
14437dd7cddfSDavid du Colombier 	else
14447dd7cddfSDavid du Colombier 		*x = 0;
144580ee5cbfSDavid du Colombier 
1446219b2ee8SDavid du Colombier 	if(*t->val == '*')
14477dd7cddfSDavid du Colombier 		snprint(reply, sizeof(reply), "%s/%s/clone %s%s",
14487dd7cddfSDavid du Colombier 			mntpt, np->net, ts, x);
1449219b2ee8SDavid du Colombier 	else
145080ee5cbfSDavid du Colombier 		snprint(reply, sizeof(reply), "%s/%s/clone %s!%s%s%s",
145180ee5cbfSDavid du Colombier 			mntpt, np->net, t->val, ts, x, hack? "!fasttimeout": "");
1452219b2ee8SDavid du Colombier 
1453219b2ee8SDavid du Colombier 	return strdup(reply);
14543e12c5d1SDavid du Colombier }
14553e12c5d1SDavid du Colombier 
1456219b2ee8SDavid du Colombier /*
1457219b2ee8SDavid du Colombier  *  lookup a telephone number
1458219b2ee8SDavid du Colombier  */
1459219b2ee8SDavid du Colombier Ndbtuple*
1460219b2ee8SDavid du Colombier telcolookup(Network *np, char *host, char *serv, int nolookup)
1461219b2ee8SDavid du Colombier {
1462219b2ee8SDavid du Colombier 	Ndbtuple *t;
1463219b2ee8SDavid du Colombier 	Ndbs s;
1464219b2ee8SDavid du Colombier 
1465219b2ee8SDavid du Colombier 	USED(np, nolookup, serv);
1466219b2ee8SDavid du Colombier 
1467271b8d73SDavid du Colombier 	werrstr("can't translate address");
146857837e0bSDavid du Colombier 	free(ndbgetvalue(db, &s, "sys", host, "telco", &t));
1469219b2ee8SDavid du Colombier 	if(t == 0)
147095a264b3SDavid du Colombier 		return ndbnew("telco", host);
1471219b2ee8SDavid du Colombier 
1472219b2ee8SDavid du Colombier 	return reorder(t, s.t);
1473219b2ee8SDavid du Colombier }
1474219b2ee8SDavid du Colombier 
1475219b2ee8SDavid du Colombier /*
1476219b2ee8SDavid du Colombier  *  translate a telephone address
1477219b2ee8SDavid du Colombier  */
1478219b2ee8SDavid du Colombier char*
147980ee5cbfSDavid du Colombier telcotrans(Ndbtuple *t, Network *np, char *serv, char *rem, int)
1480219b2ee8SDavid du Colombier {
1481219b2ee8SDavid du Colombier 	char reply[Maxreply];
148295a264b3SDavid du Colombier 	char x[Maxservice];
1483219b2ee8SDavid du Colombier 
1484219b2ee8SDavid du Colombier 	if(strcmp(t->attr, "telco") != 0)
1485219b2ee8SDavid du Colombier 		return 0;
1486219b2ee8SDavid du Colombier 
14877dd7cddfSDavid du Colombier 	if(rem != nil)
14887dd7cddfSDavid du Colombier 		snprint(x, sizeof(x), "!%s", rem);
1489219b2ee8SDavid du Colombier 	else
14907dd7cddfSDavid du Colombier 		*x = 0;
14917dd7cddfSDavid du Colombier 	if(serv)
14927dd7cddfSDavid du Colombier 		snprint(reply, sizeof(reply), "%s/%s/clone %s!%s%s", mntpt, np->net,
14937dd7cddfSDavid du Colombier 			t->val, serv, x);
14947dd7cddfSDavid du Colombier 	else
14957dd7cddfSDavid du Colombier 		snprint(reply, sizeof(reply), "%s/%s/clone %s%s", mntpt, np->net,
14967dd7cddfSDavid du Colombier 			t->val, x);
1497219b2ee8SDavid du Colombier 	return strdup(reply);
1498219b2ee8SDavid du Colombier }
14993e12c5d1SDavid du Colombier 
15003e12c5d1SDavid du Colombier /*
15013e12c5d1SDavid du Colombier  *  reorder the tuple to put x's line first in the entry
15023e12c5d1SDavid du Colombier  */
15033e12c5d1SDavid du Colombier Ndbtuple*
15043e12c5d1SDavid du Colombier reorder(Ndbtuple *t, Ndbtuple *x)
15053e12c5d1SDavid du Colombier {
15063e12c5d1SDavid du Colombier 	Ndbtuple *nt;
15073e12c5d1SDavid du Colombier 	Ndbtuple *line;
15083e12c5d1SDavid du Colombier 
1509219b2ee8SDavid du Colombier 	/* find start of this entry's line */
1510219b2ee8SDavid du Colombier 	for(line = x; line->entry == line->line; line = line->line)
15113e12c5d1SDavid du Colombier 		;
1512219b2ee8SDavid du Colombier 	line = line->line;
1513219b2ee8SDavid du Colombier 	if(line == t)
1514219b2ee8SDavid du Colombier 		return t;	/* already the first line */
15153e12c5d1SDavid du Colombier 
1516219b2ee8SDavid du Colombier 	/* remove this line and everything after it from the entry */
1517219b2ee8SDavid du Colombier 	for(nt = t; nt->entry != line; nt = nt->entry)
1518219b2ee8SDavid du Colombier 		;
1519219b2ee8SDavid du Colombier 	nt->entry = 0;
15203e12c5d1SDavid du Colombier 
1521219b2ee8SDavid du Colombier 	/* make that the start of the entry */
1522219b2ee8SDavid du Colombier 	for(nt = line; nt->entry; nt = nt->entry)
1523219b2ee8SDavid du Colombier 		;
15243e12c5d1SDavid du Colombier 	nt->entry = t;
15253e12c5d1SDavid du Colombier 	return line;
15263e12c5d1SDavid du Colombier }
15273e12c5d1SDavid du Colombier 
15283e12c5d1SDavid du Colombier /*
15293e12c5d1SDavid du Colombier  *  create a slave process to handle a request to avoid one request blocking
15307dd7cddfSDavid du Colombier  *  another.  parent returns to job loop.
15313e12c5d1SDavid du Colombier  */
15323e12c5d1SDavid du Colombier void
15333e12c5d1SDavid du Colombier slave(void)
15343e12c5d1SDavid du Colombier {
15353e12c5d1SDavid du Colombier 	if(*isslave)
15363e12c5d1SDavid du Colombier 		return;		/* we're already a slave process */
15373e12c5d1SDavid du Colombier 
15383e12c5d1SDavid du Colombier 	switch(rfork(RFPROC|RFNOTEG|RFMEM|RFNOWAIT)){
15393e12c5d1SDavid du Colombier 	case -1:
15403e12c5d1SDavid du Colombier 		break;
15413e12c5d1SDavid du Colombier 	case 0:
1542219b2ee8SDavid du Colombier 		if(debug)
1543219b2ee8SDavid du Colombier 			syslog(0, logfile, "slave %d", getpid());
15443e12c5d1SDavid du Colombier 		*isslave = 1;
15453e12c5d1SDavid du Colombier 		break;
15463e12c5d1SDavid du Colombier 	default:
15473e12c5d1SDavid du Colombier 		longjmp(masterjmp, 1);
15483e12c5d1SDavid du Colombier 	}
15493e12c5d1SDavid du Colombier 
1550219b2ee8SDavid du Colombier }
1551219b2ee8SDavid du Colombier 
15523e12c5d1SDavid du Colombier /*
15533e12c5d1SDavid du Colombier  *  call the dns process and have it try to translate a name
15543e12c5d1SDavid du Colombier  */
15553e12c5d1SDavid du Colombier Ndbtuple*
15567dd7cddfSDavid du Colombier dnsiplookup(char *host, Ndbs *s)
15573e12c5d1SDavid du Colombier {
155895a264b3SDavid du Colombier 	char buf[Maxreply];
15597dd7cddfSDavid du Colombier 	Ndbtuple *t;
15603e12c5d1SDavid du Colombier 
1561bd389b36SDavid du Colombier 	unlock(&dblock);
1562bd389b36SDavid du Colombier 
15633e12c5d1SDavid du Colombier 	/* save the name before starting a slave */
15647dd7cddfSDavid du Colombier 	snprint(buf, sizeof(buf), "%s", host);
15653e12c5d1SDavid du Colombier 
15663e12c5d1SDavid du Colombier 	slave();
15673e12c5d1SDavid du Colombier 
15687dd7cddfSDavid du Colombier 	if(strcmp(ipattr(buf), "ip") == 0)
15697dd7cddfSDavid du Colombier 		t = dnsquery(mntpt, buf, "ptr");
15707dd7cddfSDavid du Colombier 	else
15717dd7cddfSDavid du Colombier 		t = dnsquery(mntpt, buf, "ip");
15723e12c5d1SDavid du Colombier 	s->t = t;
15737dd7cddfSDavid du Colombier 
1574271b8d73SDavid du Colombier 	if(t == nil){
1575271b8d73SDavid du Colombier 		rerrstr(buf, sizeof buf);
1576271b8d73SDavid du Colombier 		if(strstr(buf, "exist"))
1577271b8d73SDavid du Colombier 			werrstr("can't translate address: %s", buf);
1578271b8d73SDavid du Colombier 		else if(strstr(buf, "dns failure"))
1579271b8d73SDavid du Colombier 			werrstr("temporary problem: %s", buf);
1580271b8d73SDavid du Colombier 	}
1581271b8d73SDavid du Colombier 
1582bd389b36SDavid du Colombier 	lock(&dblock);
15833e12c5d1SDavid du Colombier 	return t;
15843e12c5d1SDavid du Colombier }
1585219b2ee8SDavid du Colombier 
1586219b2ee8SDavid du Colombier int
1587219b2ee8SDavid du Colombier qmatch(Ndbtuple *t, char **attr, char **val, int n)
1588219b2ee8SDavid du Colombier {
1589219b2ee8SDavid du Colombier 	int i, found;
1590219b2ee8SDavid du Colombier 	Ndbtuple *nt;
1591219b2ee8SDavid du Colombier 
1592219b2ee8SDavid du Colombier 	for(i = 1; i < n; i++){
1593219b2ee8SDavid du Colombier 		found = 0;
1594219b2ee8SDavid du Colombier 		for(nt = t; nt; nt = nt->entry)
1595219b2ee8SDavid du Colombier 			if(strcmp(attr[i], nt->attr) == 0)
1596219b2ee8SDavid du Colombier 				if(strcmp(val[i], "*") == 0
1597219b2ee8SDavid du Colombier 				|| strcmp(val[i], nt->val) == 0){
1598219b2ee8SDavid du Colombier 					found = 1;
1599219b2ee8SDavid du Colombier 					break;
1600219b2ee8SDavid du Colombier 				}
1601219b2ee8SDavid du Colombier 		if(found == 0)
1602219b2ee8SDavid du Colombier 			break;
1603219b2ee8SDavid du Colombier 	}
1604219b2ee8SDavid du Colombier 	return i == n;
1605219b2ee8SDavid du Colombier }
1606219b2ee8SDavid du Colombier 
1607219b2ee8SDavid du Colombier void
1608219b2ee8SDavid du Colombier qreply(Mfile *mf, Ndbtuple *t)
1609219b2ee8SDavid du Colombier {
1610219b2ee8SDavid du Colombier 	Ndbtuple *nt;
161195a264b3SDavid du Colombier 	String *s;
1612219b2ee8SDavid du Colombier 
161395a264b3SDavid du Colombier 	s = s_new();
1614219b2ee8SDavid du Colombier 	for(nt = t; mf->nreply < Nreply && nt; nt = nt->entry){
161595a264b3SDavid du Colombier 		s_append(s, nt->attr);
161695a264b3SDavid du Colombier 		s_append(s, "=");
161795a264b3SDavid du Colombier 		s_append(s, nt->val);
161895a264b3SDavid du Colombier 
161995a264b3SDavid du Colombier 		if(nt->line != nt->entry){
162095a264b3SDavid du Colombier 			mf->replylen[mf->nreply] = s_len(s);
162195a264b3SDavid du Colombier 			mf->reply[mf->nreply++] = strdup(s_to_c(s));
162295a264b3SDavid du Colombier 			s_restart(s);
1623219b2ee8SDavid du Colombier 		} else
162495a264b3SDavid du Colombier 			s_append(s, " ");
1625219b2ee8SDavid du Colombier 	}
162695a264b3SDavid du Colombier 	s_free(s);
1627219b2ee8SDavid du Colombier }
1628219b2ee8SDavid du Colombier 
16297dd7cddfSDavid du Colombier enum
16307dd7cddfSDavid du Colombier {
16317dd7cddfSDavid du Colombier 	Maxattr=	32,
16327dd7cddfSDavid du Colombier };
16337dd7cddfSDavid du Colombier 
1634219b2ee8SDavid du Colombier /*
16357dd7cddfSDavid du Colombier  *  generic query lookup.  The query is of one of the following
16367dd7cddfSDavid du Colombier  *  forms:
16377dd7cddfSDavid du Colombier  *
16387dd7cddfSDavid du Colombier  *  attr1=val1 attr2=val2 attr3=val3 ...
16397dd7cddfSDavid du Colombier  *
16407dd7cddfSDavid du Colombier  *  returns the matching tuple
16417dd7cddfSDavid du Colombier  *
16427dd7cddfSDavid du Colombier  *  ipinfo attr=val attr1 attr2 attr3 ...
16437dd7cddfSDavid du Colombier  *
16447dd7cddfSDavid du Colombier  *  is like ipinfo and returns the attr{1-n}
16457dd7cddfSDavid du Colombier  *  associated with the ip address.
1646219b2ee8SDavid du Colombier  */
1647219b2ee8SDavid du Colombier char*
1648219b2ee8SDavid du Colombier genquery(Mfile *mf, char *query)
1649219b2ee8SDavid du Colombier {
1650219b2ee8SDavid du Colombier 	int i, n;
1651219b2ee8SDavid du Colombier 	char *p;
16527dd7cddfSDavid du Colombier 	char *attr[Maxattr];
16537dd7cddfSDavid du Colombier 	char *val[Maxattr];
1654219b2ee8SDavid du Colombier 	Ndbtuple *t;
1655219b2ee8SDavid du Colombier 	Ndbs s;
1656219b2ee8SDavid du Colombier 
16577dd7cddfSDavid du Colombier 	n = getfields(query, attr, 32, 1, " ");
1658219b2ee8SDavid du Colombier 	if(n == 0)
1659219b2ee8SDavid du Colombier 		return "bad query";
1660219b2ee8SDavid du Colombier 
16617dd7cddfSDavid du Colombier 	if(strcmp(attr[0], "ipinfo") == 0)
16627dd7cddfSDavid du Colombier 		return ipinfoquery(mf, attr, n);
16637dd7cddfSDavid du Colombier 
1664219b2ee8SDavid du Colombier 	/* parse pairs */
1665219b2ee8SDavid du Colombier 	for(i = 0; i < n; i++){
1666219b2ee8SDavid du Colombier 		p = strchr(attr[i], '=');
1667219b2ee8SDavid du Colombier 		if(p == 0)
1668219b2ee8SDavid du Colombier 			return "bad query";
1669219b2ee8SDavid du Colombier 		*p++ = 0;
1670219b2ee8SDavid du Colombier 		val[i] = p;
1671219b2ee8SDavid du Colombier 	}
1672219b2ee8SDavid du Colombier 
1673219b2ee8SDavid du Colombier 	/* give dns a chance */
1674219b2ee8SDavid du Colombier 	if((strcmp(attr[0], "dom") == 0 || strcmp(attr[0], "ip") == 0) && val[0]){
16757dd7cddfSDavid du Colombier 		t = dnsiplookup(val[0], &s);
1676219b2ee8SDavid du Colombier 		if(t){
1677219b2ee8SDavid du Colombier 			if(qmatch(t, attr, val, n)){
1678219b2ee8SDavid du Colombier 				qreply(mf, t);
1679219b2ee8SDavid du Colombier 				ndbfree(t);
1680219b2ee8SDavid du Colombier 				return 0;
1681219b2ee8SDavid du Colombier 			}
1682219b2ee8SDavid du Colombier 			ndbfree(t);
1683219b2ee8SDavid du Colombier 		}
1684219b2ee8SDavid du Colombier 	}
1685219b2ee8SDavid du Colombier 
1686219b2ee8SDavid du Colombier 	/* first pair is always the key.  It can't be a '*' */
1687219b2ee8SDavid du Colombier 	t = ndbsearch(db, &s, attr[0], val[0]);
1688219b2ee8SDavid du Colombier 
1689219b2ee8SDavid du Colombier 	/* search is the and of all the pairs */
1690219b2ee8SDavid du Colombier 	while(t){
1691219b2ee8SDavid du Colombier 		if(qmatch(t, attr, val, n)){
1692219b2ee8SDavid du Colombier 			qreply(mf, t);
1693219b2ee8SDavid du Colombier 			ndbfree(t);
1694219b2ee8SDavid du Colombier 			return 0;
1695219b2ee8SDavid du Colombier 		}
1696219b2ee8SDavid du Colombier 
1697219b2ee8SDavid du Colombier 		ndbfree(t);
1698219b2ee8SDavid du Colombier 		t = ndbsnext(&s, attr[0], val[0]);
1699219b2ee8SDavid du Colombier 	}
1700219b2ee8SDavid du Colombier 
1701219b2ee8SDavid du Colombier 	return "no match";
1702219b2ee8SDavid du Colombier }
17037dd7cddfSDavid du Colombier 
17047dd7cddfSDavid du Colombier /*
17057dd7cddfSDavid du Colombier  *  resolve an ip address
17067dd7cddfSDavid du Colombier  */
17077dd7cddfSDavid du Colombier static Ndbtuple*
17087dd7cddfSDavid du Colombier ipresolve(char *attr, char *host)
17097dd7cddfSDavid du Colombier {
17107dd7cddfSDavid du Colombier 	Ndbtuple *t, *nt, **l;
17117dd7cddfSDavid du Colombier 
17127dd7cddfSDavid du Colombier 	t = iplookup(&network[Ntcp], host, "*", 0);
17137dd7cddfSDavid du Colombier 	for(l = &t; *l != nil; ){
17147dd7cddfSDavid du Colombier 		nt = *l;
17157dd7cddfSDavid du Colombier 		if(strcmp(nt->attr, "ip") != 0){
17167dd7cddfSDavid du Colombier 			*l = nt->entry;
17177dd7cddfSDavid du Colombier 			nt->entry = nil;
17187dd7cddfSDavid du Colombier 			ndbfree(nt);
17197dd7cddfSDavid du Colombier 			continue;
17207dd7cddfSDavid du Colombier 		}
17217dd7cddfSDavid du Colombier 		strcpy(nt->attr, attr);
17227dd7cddfSDavid du Colombier 		l = &nt->entry;
17237dd7cddfSDavid du Colombier 	}
17247dd7cddfSDavid du Colombier 	return t;
17257dd7cddfSDavid du Colombier }
17267dd7cddfSDavid du Colombier 
17277dd7cddfSDavid du Colombier char*
17287dd7cddfSDavid du Colombier ipinfoquery(Mfile *mf, char **list, int n)
17297dd7cddfSDavid du Colombier {
17307dd7cddfSDavid du Colombier 	int i, nresolve;
17317dd7cddfSDavid du Colombier 	int resolve[Maxattr];
17327dd7cddfSDavid du Colombier 	Ndbtuple *t, *nt, **l;
17337dd7cddfSDavid du Colombier 	char *attr, *val;
17347dd7cddfSDavid du Colombier 
17357dd7cddfSDavid du Colombier 	/* skip 'ipinfo' */
17367dd7cddfSDavid du Colombier 	list++; n--;
17377dd7cddfSDavid du Colombier 
17388a2c5ad0SDavid du Colombier 	if(n < 1)
17397dd7cddfSDavid du Colombier 		return "bad query";
17407dd7cddfSDavid du Colombier 
17418a2c5ad0SDavid du Colombier 	/* get search attribute=value, or assume ip=myipaddr */
17428a2c5ad0SDavid du Colombier 	attr = *list;
17438a2c5ad0SDavid du Colombier 	if((val = strchr(attr, '=')) != nil){
17447dd7cddfSDavid du Colombier 		*val++ = 0;
17458a2c5ad0SDavid du Colombier 		list++;
17468a2c5ad0SDavid du Colombier 		n--;
17478a2c5ad0SDavid du Colombier 	}else{
17488a2c5ad0SDavid du Colombier 		attr = "ip";
17498a2c5ad0SDavid du Colombier 		val = ipaddr;
17508a2c5ad0SDavid du Colombier 	}
17518a2c5ad0SDavid du Colombier 
17528a2c5ad0SDavid du Colombier 	if(n < 1)
17538a2c5ad0SDavid du Colombier 		return "bad query";
17547dd7cddfSDavid du Colombier 
17557dd7cddfSDavid du Colombier 	/*
17567dd7cddfSDavid du Colombier 	 *  don't let ndbipinfo resolve the addresses, we're
17577dd7cddfSDavid du Colombier 	 *  better at it.
17587dd7cddfSDavid du Colombier 	 */
17597dd7cddfSDavid du Colombier 	nresolve = 0;
17607dd7cddfSDavid du Colombier 	for(i = 0; i < n; i++)
1761107aedb4SDavid du Colombier 		if(*list[i] == '@'){		/* @attr=val ? */
17627dd7cddfSDavid du Colombier 			list[i]++;
1763107aedb4SDavid du Colombier 			resolve[i] = 1;		/* we'll resolve it */
17647dd7cddfSDavid du Colombier 			nresolve++;
17657dd7cddfSDavid du Colombier 		} else
17667dd7cddfSDavid du Colombier 			resolve[i] = 0;
17677dd7cddfSDavid du Colombier 
17687dd7cddfSDavid du Colombier 	t = ndbipinfo(db, attr, val, list, n);
17697dd7cddfSDavid du Colombier 	if(t == nil)
17707dd7cddfSDavid du Colombier 		return "no match";
17717dd7cddfSDavid du Colombier 
17727dd7cddfSDavid du Colombier 	if(nresolve != 0){
17737dd7cddfSDavid du Colombier 		for(l = &t; *l != nil;){
17747dd7cddfSDavid du Colombier 			nt = *l;
17757dd7cddfSDavid du Colombier 
17767dd7cddfSDavid du Colombier 			/* already an address? */
17777dd7cddfSDavid du Colombier 			if(strcmp(ipattr(nt->val), "ip") == 0){
17787dd7cddfSDavid du Colombier 				l = &(*l)->entry;
17797dd7cddfSDavid du Colombier 				continue;
17807dd7cddfSDavid du Colombier 			}
17817dd7cddfSDavid du Colombier 
17827dd7cddfSDavid du Colombier 			/* user wants it resolved? */
17837dd7cddfSDavid du Colombier 			for(i = 0; i < n; i++)
17847dd7cddfSDavid du Colombier 				if(strcmp(list[i], nt->attr) == 0)
17857dd7cddfSDavid du Colombier 					break;
17867dd7cddfSDavid du Colombier 			if(i >= n || resolve[i] == 0){
17877dd7cddfSDavid du Colombier 				l = &(*l)->entry;
17887dd7cddfSDavid du Colombier 				continue;
17897dd7cddfSDavid du Colombier 			}
17907dd7cddfSDavid du Colombier 
17917dd7cddfSDavid du Colombier 			/* resolve address and replace entry */
17927dd7cddfSDavid du Colombier 			*l = ipresolve(nt->attr, nt->val);
17937dd7cddfSDavid du Colombier 			while(*l != nil)
17947dd7cddfSDavid du Colombier 				l = &(*l)->entry;
17957dd7cddfSDavid du Colombier 			*l = nt->entry;
17967dd7cddfSDavid du Colombier 
17977dd7cddfSDavid du Colombier 			nt->entry = nil;
17987dd7cddfSDavid du Colombier 			ndbfree(nt);
17997dd7cddfSDavid du Colombier 		}
18007dd7cddfSDavid du Colombier 	}
18017dd7cddfSDavid du Colombier 
18027dd7cddfSDavid du Colombier 	/* make it all one line */
18037dd7cddfSDavid du Colombier 	for(nt = t; nt != nil; nt = nt->entry){
18047dd7cddfSDavid du Colombier 		if(nt->entry == nil)
18057dd7cddfSDavid du Colombier 			nt->line = t;
18067dd7cddfSDavid du Colombier 		else
18077dd7cddfSDavid du Colombier 			nt->line = nt->entry;
18087dd7cddfSDavid du Colombier 	}
18097dd7cddfSDavid du Colombier 
18107dd7cddfSDavid du Colombier 	qreply(mf, t);
18117dd7cddfSDavid du Colombier 
18127dd7cddfSDavid du Colombier 	return nil;
18137dd7cddfSDavid du Colombier }
18147dd7cddfSDavid du Colombier 
18157dd7cddfSDavid du Colombier void*
18167dd7cddfSDavid du Colombier emalloc(int size)
18177dd7cddfSDavid du Colombier {
18187dd7cddfSDavid du Colombier 	void *x;
18197dd7cddfSDavid du Colombier 
18207dd7cddfSDavid du Colombier 	x = malloc(size);
18217dd7cddfSDavid du Colombier 	if(x == nil)
18227dd7cddfSDavid du Colombier 		abort();
18237dd7cddfSDavid du Colombier 	memset(x, 0, size);
18247dd7cddfSDavid du Colombier 	return x;
18257dd7cddfSDavid du Colombier }
18269a747e4fSDavid du Colombier 
18279a747e4fSDavid du Colombier char*
18289a747e4fSDavid du Colombier estrdup(char *s)
18299a747e4fSDavid du Colombier {
18309a747e4fSDavid du Colombier 	int size;
18319a747e4fSDavid du Colombier 	char *p;
18329a747e4fSDavid du Colombier 
18339a747e4fSDavid du Colombier 	size = strlen(s)+1;
18349a747e4fSDavid du Colombier 	p = malloc(size);
18359a747e4fSDavid du Colombier 	if(p == nil)
18369a747e4fSDavid du Colombier 		abort();
18379a747e4fSDavid du Colombier 	memmove(p, s, size);
18389a747e4fSDavid du Colombier 	return p;
18399a747e4fSDavid du Colombier }
1840