xref: /plan9/sys/src/cmd/ndb/cs.c (revision 9dfc0cb2ef9edafc5a26f7e8dbe4ef1ca2b37021)
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 
657dd7cddfSDavid du Colombier //
667dd7cddfSDavid du Colombier //  active requests
677dd7cddfSDavid 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 {
15380ee5cbfSDavid du Colombier 	Nilfast,
15480ee5cbfSDavid du Colombier 	Ntcp,
15580ee5cbfSDavid du Colombier 	Nil,
15680ee5cbfSDavid du Colombier 	Nudp,
15780ee5cbfSDavid du Colombier 	Nicmp,
15895a264b3SDavid du Colombier 	Nicmpv6,
15980ee5cbfSDavid du Colombier 	Nrudp,
16080ee5cbfSDavid du Colombier 	Ntelco,
16180ee5cbfSDavid du Colombier };
16280ee5cbfSDavid du Colombier 
16380ee5cbfSDavid du Colombier /*
16495a264b3SDavid du Colombier >  *  net doesn't apply to (r)udp, icmp(v6), or telco (for speed)
16580ee5cbfSDavid du Colombier  */
16680ee5cbfSDavid du Colombier Network network[] = {
16780ee5cbfSDavid du Colombier [Nilfast]	{ "il",		iplookup,	iptrans,	0, 1 },
16880ee5cbfSDavid du Colombier [Ntcp]		{ "tcp",	iplookup,	iptrans,	0, 0 },
16980ee5cbfSDavid du Colombier [Nil]		{ "il",		iplookup,	iptrans,	0, 0 },
17080ee5cbfSDavid du Colombier [Nudp]		{ "udp",	iplookup,	iptrans,	1, 0 },
17180ee5cbfSDavid du Colombier [Nicmp]		{ "icmp",	iplookup,	iptrans,	1, 0 },
17295a264b3SDavid du Colombier [Nicmpv6]	{ "icmpv6",	iplookup,	iptrans,	1, 0 },
17380ee5cbfSDavid du Colombier [Nrudp]		{ "rudp",	iplookup,	iptrans,	1, 0 },
17480ee5cbfSDavid du Colombier [Ntelco]	{ "telco",	telcolookup,	telcotrans,	1, 0 },
17580ee5cbfSDavid du Colombier 		{ 0 },
17680ee5cbfSDavid du Colombier };
17780ee5cbfSDavid du Colombier 
17880ee5cbfSDavid du Colombier Lock ipifclock;
17980ee5cbfSDavid du Colombier Ipifc *ipifcs;
18080ee5cbfSDavid du Colombier 
18195a264b3SDavid du Colombier char	eaddr[16];		/* ascii ethernet address */
18295a264b3SDavid du Colombier char	ipaddr[64];		/* ascii internet address */
18380ee5cbfSDavid du Colombier uchar	ipa[IPaddrlen];		/* binary internet address */
18495a264b3SDavid du Colombier char	*mysysname;
18580ee5cbfSDavid du Colombier 
18680ee5cbfSDavid du Colombier Network *netlist;		/* networks ordered by preference */
18780ee5cbfSDavid du Colombier Network *last;
18880ee5cbfSDavid du Colombier 
18995a264b3SDavid du Colombier static void
19095a264b3SDavid du Colombier nstrcpy(char *to, char *from, int len)
19195a264b3SDavid du Colombier {
19295a264b3SDavid du Colombier 	strncpy(to, from, len);
19395a264b3SDavid du Colombier 	to[len-1] = 0;
19495a264b3SDavid du Colombier }
19595a264b3SDavid du Colombier 
19695a264b3SDavid du Colombier 
1977dd7cddfSDavid du Colombier void
1987dd7cddfSDavid du Colombier usage(void)
1997dd7cddfSDavid du Colombier {
2007dd7cddfSDavid du Colombier 	fprint(2, "usage: %s [-d] [-f ndb-file] [-x netmtpt] [-n]\n", argv0);
2017dd7cddfSDavid du Colombier 	exits("usage");
2027dd7cddfSDavid du Colombier }
203219b2ee8SDavid du Colombier 
2043e12c5d1SDavid du Colombier void
2053e12c5d1SDavid du Colombier main(int argc, char *argv[])
2063e12c5d1SDavid du Colombier {
2077dd7cddfSDavid du Colombier 	char servefile[Maxpath];
208219b2ee8SDavid du Colombier 	int justsetname;
2097dd7cddfSDavid du Colombier 	char *p;
2107dd7cddfSDavid du Colombier 	char ext[Maxpath];
2113e12c5d1SDavid du Colombier 
212219b2ee8SDavid du Colombier 	justsetname = 0;
2137dd7cddfSDavid du Colombier 	setnetmtpt(mntpt, sizeof(mntpt), nil);
2147dd7cddfSDavid du Colombier 	ext[0] = 0;
2153e12c5d1SDavid du Colombier 	ARGBEGIN{
2163e12c5d1SDavid du Colombier 	case 'd':
2173e12c5d1SDavid du Colombier 		debug = 1;
2183e12c5d1SDavid du Colombier 		break;
219bd389b36SDavid du Colombier 	case 'f':
2207dd7cddfSDavid du Colombier 		p = ARGF();
2217dd7cddfSDavid du Colombier 		if(p == nil)
2227dd7cddfSDavid du Colombier 			usage();
2237dd7cddfSDavid du Colombier 		dbfile = p;
2247dd7cddfSDavid du Colombier 		break;
2257dd7cddfSDavid du Colombier 	case 'x':
2267dd7cddfSDavid du Colombier 		p = ARGF();
2277dd7cddfSDavid du Colombier 		if(p == nil)
2287dd7cddfSDavid du Colombier 			usage();
2297dd7cddfSDavid du Colombier 		setnetmtpt(mntpt, sizeof(mntpt), p);
2307dd7cddfSDavid du Colombier 		setext(ext, sizeof(ext), mntpt);
231bd389b36SDavid du Colombier 		break;
232219b2ee8SDavid du Colombier 	case 'n':
233219b2ee8SDavid du Colombier 		justsetname = 1;
234219b2ee8SDavid du Colombier 		break;
2353e12c5d1SDavid du Colombier 	}ARGEND
2363e12c5d1SDavid du Colombier 	USED(argc);
2373e12c5d1SDavid du Colombier 	USED(argv);
2383e12c5d1SDavid du Colombier 
2397dd7cddfSDavid du Colombier 	rfork(RFREND|RFNOTEG);
2407dd7cddfSDavid du Colombier 
2417dd7cddfSDavid du Colombier 	snprint(servefile, sizeof(servefile), "#s/cs%s", ext);
2427dd7cddfSDavid du Colombier 	snprint(netndb, sizeof(netndb), "%s/ndb", mntpt);
2437dd7cddfSDavid du Colombier 	unmount(servefile, mntpt);
2447dd7cddfSDavid du Colombier 	remove(servefile);
2457dd7cddfSDavid du Colombier 
2469a747e4fSDavid du Colombier 	fmtinstall('E', eipfmt);
2479a747e4fSDavid du Colombier 	fmtinstall('I', eipfmt);
2489a747e4fSDavid du Colombier 	fmtinstall('M', eipfmt);
2499a747e4fSDavid du Colombier 	fmtinstall('F', fcallfmt);
2507dd7cddfSDavid du Colombier 
2517dd7cddfSDavid du Colombier 	ndbinit();
2527dd7cddfSDavid du Colombier 	netinit(0);
2537dd7cddfSDavid du Colombier 
2547dd7cddfSDavid du Colombier 	if(!justsetname){
2557dd7cddfSDavid du Colombier 		mountinit(servefile, mntpt);
2567dd7cddfSDavid du Colombier 		io();
2577dd7cddfSDavid du Colombier 	}
258219b2ee8SDavid du Colombier 	exits(0);
259219b2ee8SDavid du Colombier }
260219b2ee8SDavid du Colombier 
2617dd7cddfSDavid du Colombier /*
2627dd7cddfSDavid du Colombier  *  if a mount point is specified, set the cs extention to be the mount point
2637dd7cddfSDavid du Colombier  *  with '_'s replacing '/'s
2647dd7cddfSDavid du Colombier  */
2657dd7cddfSDavid du Colombier void
2667dd7cddfSDavid du Colombier setext(char *ext, int n, char *p)
2677dd7cddfSDavid du Colombier {
2687dd7cddfSDavid du Colombier 	int i, c;
2693e12c5d1SDavid du Colombier 
2707dd7cddfSDavid du Colombier 	n--;
2717dd7cddfSDavid du Colombier 	for(i = 0; i < n; i++){
2727dd7cddfSDavid du Colombier 		c = p[i];
2737dd7cddfSDavid du Colombier 		if(c == 0)
2747dd7cddfSDavid du Colombier 			break;
2757dd7cddfSDavid du Colombier 		if(c == '/')
2767dd7cddfSDavid du Colombier 			c = '_';
2777dd7cddfSDavid du Colombier 		ext[i] = c;
2787dd7cddfSDavid du Colombier 	}
2797dd7cddfSDavid du Colombier 	ext[i] = 0;
2803e12c5d1SDavid du Colombier }
2813e12c5d1SDavid du Colombier 
2823e12c5d1SDavid du Colombier void
2837dd7cddfSDavid du Colombier mountinit(char *service, char *mntpt)
2843e12c5d1SDavid du Colombier {
2853e12c5d1SDavid du Colombier 	int f;
2863e12c5d1SDavid du Colombier 	int p[2];
2873e12c5d1SDavid du Colombier 	char buf[32];
2883e12c5d1SDavid du Colombier 
2893e12c5d1SDavid du Colombier 	if(pipe(p) < 0)
2903e12c5d1SDavid du Colombier 		error("pipe failed");
291a9f680aeSDavid du Colombier 
292a9f680aeSDavid du Colombier 	/*
293a9f680aeSDavid du Colombier 	 *  make a /srv/cs
294a9f680aeSDavid du Colombier 	 */
295a9f680aeSDavid du Colombier 	f = create(service, OWRITE|ORCLOSE, 0666);
296a9f680aeSDavid du Colombier 	if(f < 0)
297a9f680aeSDavid du Colombier 		error(service);
298a9f680aeSDavid du Colombier 	snprint(buf, sizeof(buf), "%d", p[1]);
299a9f680aeSDavid du Colombier 	if(write(f, buf, strlen(buf)) != strlen(buf))
300a9f680aeSDavid du Colombier 		error("write /srv/cs");
301a9f680aeSDavid du Colombier 
302219b2ee8SDavid du Colombier 	switch(rfork(RFFDG|RFPROC|RFNAMEG)){
3033e12c5d1SDavid du Colombier 	case 0:
304219b2ee8SDavid du Colombier 		close(p[1]);
3053e12c5d1SDavid du Colombier 		break;
3063e12c5d1SDavid du Colombier 	case -1:
3073e12c5d1SDavid du Colombier 		error("fork failed\n");
3083e12c5d1SDavid du Colombier 	default:
3093e12c5d1SDavid du Colombier 		/*
3103e12c5d1SDavid du Colombier 		 *  put ourselves into the file system
3113e12c5d1SDavid du Colombier 		 */
312219b2ee8SDavid du Colombier 		close(p[0]);
3139a747e4fSDavid du Colombier 		if(mount(p[1], -1, mntpt, MAFTER, "") < 0)
3143e12c5d1SDavid du Colombier 			error("mount failed\n");
315219b2ee8SDavid du Colombier 		_exits(0);
3163e12c5d1SDavid du Colombier 	}
3173e12c5d1SDavid du Colombier 	mfd[0] = mfd[1] = p[0];
3183e12c5d1SDavid du Colombier }
3193e12c5d1SDavid du Colombier 
3207dd7cddfSDavid du Colombier void
3217dd7cddfSDavid du Colombier ndbinit(void)
3227dd7cddfSDavid du Colombier {
3237dd7cddfSDavid du Colombier 	db = ndbopen(dbfile);
3247dd7cddfSDavid du Colombier 	if(db == nil)
3257dd7cddfSDavid du Colombier 		error("can't open network database");
3267dd7cddfSDavid du Colombier 
3277dd7cddfSDavid du Colombier 	netdb = ndbopen(netndb);
3287dd7cddfSDavid du Colombier 	if(netdb != nil){
3297dd7cddfSDavid du Colombier 		netdb->nohash = 1;
3307dd7cddfSDavid du Colombier 		db = ndbcat(netdb, db);
3317dd7cddfSDavid du Colombier 	}
3327dd7cddfSDavid du Colombier }
3337dd7cddfSDavid du Colombier 
3343e12c5d1SDavid du Colombier Mfile*
3353e12c5d1SDavid du Colombier newfid(int fid)
3363e12c5d1SDavid du Colombier {
337219b2ee8SDavid du Colombier 	Mlist *f, *ff;
3383e12c5d1SDavid du Colombier 	Mfile *mf;
3393e12c5d1SDavid du Colombier 
340219b2ee8SDavid du Colombier 	ff = 0;
341219b2ee8SDavid du Colombier 	for(f = mlist; f; f = f->next)
342219b2ee8SDavid du Colombier 		if(f->mf.busy && f->mf.fid == fid)
343219b2ee8SDavid du Colombier 			return &f->mf;
344219b2ee8SDavid du Colombier 		else if(!ff && !f->mf.busy)
345219b2ee8SDavid du Colombier 			ff = f;
346219b2ee8SDavid du Colombier 	if(ff == 0){
3477dd7cddfSDavid du Colombier 		ff = emalloc(sizeof *f);
348219b2ee8SDavid du Colombier 		ff->next = mlist;
349219b2ee8SDavid du Colombier 		mlist = ff;
3503e12c5d1SDavid du Colombier 	}
351219b2ee8SDavid du Colombier 	mf = &ff->mf;
352219b2ee8SDavid du Colombier 	memset(mf, 0, sizeof *mf);
3533e12c5d1SDavid du Colombier 	mf->fid = fid;
3543e12c5d1SDavid du Colombier 	return mf;
3553e12c5d1SDavid du Colombier }
3563e12c5d1SDavid du Colombier 
3577dd7cddfSDavid du Colombier Job*
3587dd7cddfSDavid du Colombier newjob(void)
3597dd7cddfSDavid du Colombier {
3607dd7cddfSDavid du Colombier 	Job *job;
3617dd7cddfSDavid du Colombier 
3627dd7cddfSDavid du Colombier 	job = mallocz(sizeof(Job), 1);
3637dd7cddfSDavid du Colombier 	lock(&joblock);
3647dd7cddfSDavid du Colombier 	job->next = joblist;
3657dd7cddfSDavid du Colombier 	joblist = job;
3667dd7cddfSDavid du Colombier 	job->request.tag = -1;
3677dd7cddfSDavid du Colombier 	unlock(&joblock);
3687dd7cddfSDavid du Colombier 	return job;
3697dd7cddfSDavid du Colombier }
3707dd7cddfSDavid du Colombier 
3717dd7cddfSDavid du Colombier void
3727dd7cddfSDavid du Colombier freejob(Job *job)
3737dd7cddfSDavid du Colombier {
3747dd7cddfSDavid du Colombier 	Job **l;
3757dd7cddfSDavid du Colombier 
3767dd7cddfSDavid du Colombier 	lock(&joblock);
3777dd7cddfSDavid du Colombier 	for(l = &joblist; *l; l = &(*l)->next){
3787dd7cddfSDavid du Colombier 		if((*l) == job){
3797dd7cddfSDavid du Colombier 			*l = job->next;
3807dd7cddfSDavid du Colombier 			free(job);
3817dd7cddfSDavid du Colombier 			break;
3827dd7cddfSDavid du Colombier 		}
3837dd7cddfSDavid du Colombier 	}
3847dd7cddfSDavid du Colombier 	unlock(&joblock);
3857dd7cddfSDavid du Colombier }
3867dd7cddfSDavid du Colombier 
3877dd7cddfSDavid du Colombier void
3887dd7cddfSDavid du Colombier flushjob(int tag)
3897dd7cddfSDavid du Colombier {
3907dd7cddfSDavid du Colombier 	Job *job;
3917dd7cddfSDavid du Colombier 
3927dd7cddfSDavid du Colombier 	lock(&joblock);
3937dd7cddfSDavid du Colombier 	for(job = joblist; job; job = job->next){
3947dd7cddfSDavid du Colombier 		if(job->request.tag == tag && job->request.type != Tflush){
3957dd7cddfSDavid du Colombier 			job->flushed = 1;
3967dd7cddfSDavid du Colombier 			break;
3977dd7cddfSDavid du Colombier 		}
3987dd7cddfSDavid du Colombier 	}
3997dd7cddfSDavid du Colombier 	unlock(&joblock);
4007dd7cddfSDavid du Colombier }
4017dd7cddfSDavid du Colombier 
4023e12c5d1SDavid du Colombier void
4033e12c5d1SDavid du Colombier io(void)
4043e12c5d1SDavid du Colombier {
4053e12c5d1SDavid du Colombier 	long n;
4063e12c5d1SDavid du Colombier 	Mfile *mf;
4073e12c5d1SDavid du Colombier 	int slaveflag;
4089a747e4fSDavid du Colombier 	uchar mdata[IOHDRSZ + Maxfdata];
4097dd7cddfSDavid du Colombier 	Job *job;
4103e12c5d1SDavid du Colombier 
4113e12c5d1SDavid du Colombier 	/*
4123e12c5d1SDavid du Colombier 	 *  if we ask dns to fulfill requests,
4133e12c5d1SDavid du Colombier 	 *  a slave process is created to wait for replies.  The
4149a747e4fSDavid du Colombier 	 *  master process returns immediately via a longjmp
4153e12c5d1SDavid du Colombier 	 *  through 'masterjmp'.
4163e12c5d1SDavid du Colombier 	 *
4173e12c5d1SDavid du Colombier 	 *  *isslave is a pointer into the call stack to a variable
4183e12c5d1SDavid du Colombier 	 *  that tells whether or not the current process is a slave.
4193e12c5d1SDavid du Colombier 	 */
4203e12c5d1SDavid du Colombier 	slaveflag = 0;		/* init slave variable */
4213e12c5d1SDavid du Colombier 	isslave = &slaveflag;
4223e12c5d1SDavid du Colombier 	setjmp(masterjmp);
4233e12c5d1SDavid du Colombier 
4243e12c5d1SDavid du Colombier 	for(;;){
4259a747e4fSDavid du Colombier 		n = read9pmsg(mfd[0], mdata, sizeof mdata);
4263e12c5d1SDavid du Colombier 		if(n<=0)
4273e12c5d1SDavid du Colombier 			error("mount read");
4287dd7cddfSDavid du Colombier 		job = newjob();
4299a747e4fSDavid du Colombier 		if(convM2S(mdata, n, &job->request) != n){
430271b8d73SDavid du Colombier 			syslog(1, logfile, "format error %ux %ux %ux %ux %ux",
431271b8d73SDavid du Colombier 				mdata[0], mdata[1], mdata[2], mdata[3], mdata[4]);
4327dd7cddfSDavid du Colombier 			freejob(job);
4333e12c5d1SDavid du Colombier 			continue;
4343e12c5d1SDavid du Colombier 		}
4357dd7cddfSDavid du Colombier 		if(job->request.fid<0)
4363e12c5d1SDavid du Colombier 			error("fid out of range");
437bd389b36SDavid du Colombier 		lock(&dblock);
4387dd7cddfSDavid du Colombier 		mf = newfid(job->request.fid);
439219b2ee8SDavid du Colombier 		if(debug)
4407dd7cddfSDavid du Colombier 			syslog(0, logfile, "%F", &job->request);
4413e12c5d1SDavid du Colombier 
4423e12c5d1SDavid du Colombier 
4437dd7cddfSDavid du Colombier 		switch(job->request.type){
4443e12c5d1SDavid du Colombier 		default:
4457dd7cddfSDavid du Colombier 			syslog(1, logfile, "unknown request type %d", job->request.type);
4463e12c5d1SDavid du Colombier 			break;
4479a747e4fSDavid du Colombier 		case Tversion:
4489a747e4fSDavid du Colombier 			rversion(job);
4493e12c5d1SDavid du Colombier 			break;
4509a747e4fSDavid du Colombier 		case Tauth:
4519a747e4fSDavid du Colombier 			rauth(job);
4523e12c5d1SDavid du Colombier 			break;
4533e12c5d1SDavid du Colombier 		case Tflush:
4547dd7cddfSDavid du Colombier 			rflush(job);
4553e12c5d1SDavid du Colombier 			break;
4563e12c5d1SDavid du Colombier 		case Tattach:
4577dd7cddfSDavid du Colombier 			rattach(job, mf);
4583e12c5d1SDavid du Colombier 			break;
4593e12c5d1SDavid du Colombier 		case Twalk:
4607dd7cddfSDavid du Colombier 			rwalk(job, mf);
4613e12c5d1SDavid du Colombier 			break;
4623e12c5d1SDavid du Colombier 		case Topen:
4637dd7cddfSDavid du Colombier 			ropen(job, mf);
4643e12c5d1SDavid du Colombier 			break;
4653e12c5d1SDavid du Colombier 		case Tcreate:
4667dd7cddfSDavid du Colombier 			rcreate(job, mf);
4673e12c5d1SDavid du Colombier 			break;
4683e12c5d1SDavid du Colombier 		case Tread:
4697dd7cddfSDavid du Colombier 			rread(job, mf);
4703e12c5d1SDavid du Colombier 			break;
4713e12c5d1SDavid du Colombier 		case Twrite:
4727dd7cddfSDavid du Colombier 			rwrite(job, mf);
4733e12c5d1SDavid du Colombier 			break;
4743e12c5d1SDavid du Colombier 		case Tclunk:
4757dd7cddfSDavid du Colombier 			rclunk(job, mf);
4763e12c5d1SDavid du Colombier 			break;
4773e12c5d1SDavid du Colombier 		case Tremove:
4787dd7cddfSDavid du Colombier 			rremove(job, mf);
4793e12c5d1SDavid du Colombier 			break;
4803e12c5d1SDavid du Colombier 		case Tstat:
4817dd7cddfSDavid du Colombier 			rstat(job, mf);
4823e12c5d1SDavid du Colombier 			break;
4833e12c5d1SDavid du Colombier 		case Twstat:
4847dd7cddfSDavid du Colombier 			rwstat(job, mf);
4853e12c5d1SDavid du Colombier 			break;
4863e12c5d1SDavid du Colombier 		}
487bd389b36SDavid du Colombier 		unlock(&dblock);
4887dd7cddfSDavid du Colombier 
4897dd7cddfSDavid du Colombier 		freejob(job);
4907dd7cddfSDavid du Colombier 
4913e12c5d1SDavid du Colombier 		/*
4923e12c5d1SDavid du Colombier 		 *  slave processes die after replying
4933e12c5d1SDavid du Colombier 		 */
494219b2ee8SDavid du Colombier 		if(*isslave){
495219b2ee8SDavid du Colombier 			if(debug)
496219b2ee8SDavid du Colombier 				syslog(0, logfile, "slave death %d", getpid());
4973e12c5d1SDavid du Colombier 			_exits(0);
4983e12c5d1SDavid du Colombier 		}
4993e12c5d1SDavid du Colombier 	}
500219b2ee8SDavid du Colombier }
501219b2ee8SDavid du Colombier 
502219b2ee8SDavid du Colombier void
5039a747e4fSDavid du Colombier rversion(Job *job)
504219b2ee8SDavid du Colombier {
5059a747e4fSDavid du Colombier 	if(job->request.msize > IOHDRSZ + Maxfdata)
5069a747e4fSDavid du Colombier 		job->reply.msize = IOHDRSZ + Maxfdata;
5079a747e4fSDavid du Colombier 	else
5089a747e4fSDavid du Colombier 		job->reply.msize = job->request.msize;
5099a747e4fSDavid du Colombier 	if(strncmp(job->request.version, "9P2000", 6) != 0)
5109a747e4fSDavid du Colombier 		sendmsg(job, "unknown 9P version");
5119a747e4fSDavid du Colombier 	else{
5129a747e4fSDavid du Colombier 		job->reply.version = "9P2000";
5137dd7cddfSDavid du Colombier 		sendmsg(job, 0);
514219b2ee8SDavid du Colombier 	}
5159a747e4fSDavid du Colombier }
5163e12c5d1SDavid du Colombier 
5173e12c5d1SDavid du Colombier void
5189a747e4fSDavid du Colombier rauth(Job *job)
5193e12c5d1SDavid du Colombier {
5203ff48bf5SDavid du Colombier 	sendmsg(job, "cs: authentication not required");
5217dd7cddfSDavid du Colombier }
5227dd7cddfSDavid du Colombier 
5237dd7cddfSDavid du Colombier /*
5247dd7cddfSDavid du Colombier  *  don't flush till all the slaves are done
5257dd7cddfSDavid du Colombier  */
5267dd7cddfSDavid du Colombier void
5277dd7cddfSDavid du Colombier rflush(Job *job)
5287dd7cddfSDavid du Colombier {
5297dd7cddfSDavid du Colombier 	flushjob(job->request.oldtag);
5307dd7cddfSDavid du Colombier 	sendmsg(job, 0);
5313e12c5d1SDavid du Colombier }
5323e12c5d1SDavid du Colombier 
5333e12c5d1SDavid du Colombier void
5347dd7cddfSDavid du Colombier rattach(Job *job, Mfile *mf)
5353e12c5d1SDavid du Colombier {
5363e12c5d1SDavid du Colombier 	if(mf->busy == 0){
5373e12c5d1SDavid du Colombier 		mf->busy = 1;
5389a747e4fSDavid du Colombier 		mf->user = estrdup(job->request.uname);
5393e12c5d1SDavid du Colombier 	}
5403e12c5d1SDavid du Colombier 	mf->qid.vers = vers++;
5419a747e4fSDavid du Colombier 	mf->qid.type = QTDIR;
5429a747e4fSDavid du Colombier 	mf->qid.path = 0LL;
5437dd7cddfSDavid du Colombier 	job->reply.qid = mf->qid;
5447dd7cddfSDavid du Colombier 	sendmsg(job, 0);
5453e12c5d1SDavid du Colombier }
5463e12c5d1SDavid du Colombier 
5473e12c5d1SDavid du Colombier 
5483e12c5d1SDavid du Colombier char*
5497dd7cddfSDavid du Colombier rwalk(Job *job, Mfile *mf)
5503e12c5d1SDavid du Colombier {
5513e12c5d1SDavid du Colombier 	char *err;
5529a747e4fSDavid du Colombier 	char **elems;
5539a747e4fSDavid du Colombier 	int nelems;
5549a747e4fSDavid du Colombier 	int i;
5559a747e4fSDavid du Colombier 	Mfile *nmf;
5569a747e4fSDavid du Colombier 	Qid qid;
5573e12c5d1SDavid du Colombier 
5583e12c5d1SDavid du Colombier 	err = 0;
5599a747e4fSDavid du Colombier 	nmf = nil;
5609a747e4fSDavid du Colombier 	elems = job->request.wname;
5619a747e4fSDavid du Colombier 	nelems = job->request.nwname;
5629a747e4fSDavid du Colombier 	job->reply.nwqid = 0;
5639a747e4fSDavid du Colombier 
5649a747e4fSDavid du Colombier 	if(job->request.newfid != job->request.fid){
5659a747e4fSDavid du Colombier 		/* clone fid */
5669a747e4fSDavid du Colombier 		if(job->request.newfid<0){
5679a747e4fSDavid du Colombier 			err = "clone newfid out of range";
5689a747e4fSDavid du Colombier 			goto send;
5699a747e4fSDavid du Colombier 		}
5709a747e4fSDavid du Colombier 		nmf = newfid(job->request.newfid);
5719a747e4fSDavid du Colombier 		if(nmf->busy){
5729a747e4fSDavid du Colombier 			nmf = nil;
5739a747e4fSDavid du Colombier 			err = "clone to used channel";
5749a747e4fSDavid du Colombier 			goto send;
5759a747e4fSDavid du Colombier 		}
5769a747e4fSDavid du Colombier 		*nmf = *mf;
5779a747e4fSDavid du Colombier 		nmf->user = estrdup(mf->user);
5789a747e4fSDavid du Colombier 		nmf->fid = job->request.newfid;
5799a747e4fSDavid du Colombier 		nmf->qid.vers = vers++;
5809a747e4fSDavid du Colombier 		mf = nmf;
5819a747e4fSDavid du Colombier 	}
5829a747e4fSDavid du Colombier 	/* else nmf will be nil */
5839a747e4fSDavid du Colombier 
5849a747e4fSDavid du Colombier 	qid = mf->qid;
5859a747e4fSDavid du Colombier 	if(nelems > 0){
5869a747e4fSDavid du Colombier 		/* walk fid */
5879a747e4fSDavid du Colombier 		for(i=0; i<nelems && i<MAXWELEM; i++){
5889a747e4fSDavid du Colombier 			if((qid.type & QTDIR) == 0){
5893e12c5d1SDavid du Colombier 				err = "not a directory";
5909a747e4fSDavid du Colombier 				break;
5913e12c5d1SDavid du Colombier 			}
5929a747e4fSDavid du Colombier 			if(strcmp(elems[i], "..") == 0 || strcmp(elems[i], ".") == 0){
5939a747e4fSDavid du Colombier 				qid.type = QTDIR;
5949a747e4fSDavid du Colombier 				qid.path = Qdir;
5959a747e4fSDavid du Colombier     Found:
5969a747e4fSDavid du Colombier 				job->reply.wqid[i] = qid;
5979a747e4fSDavid du Colombier 				job->reply.nwqid++;
5989a747e4fSDavid du Colombier 				continue;
5993e12c5d1SDavid du Colombier 			}
6009a747e4fSDavid du Colombier 			if(strcmp(elems[i], "cs") == 0){
6019a747e4fSDavid du Colombier 				qid.type = QTFILE;
6029a747e4fSDavid du Colombier 				qid.path = Qcs;
6039a747e4fSDavid du Colombier 				goto Found;
6043e12c5d1SDavid du Colombier 			}
6059a747e4fSDavid du Colombier 			err = "file does not exist";
6069a747e4fSDavid du Colombier 			break;
6079a747e4fSDavid du Colombier 		}
6089a747e4fSDavid du Colombier 	}
6099a747e4fSDavid du Colombier 
6103e12c5d1SDavid du Colombier     send:
6119a747e4fSDavid du Colombier 	if(nmf != nil && (err!=nil || job->reply.nwqid<nelems)){
612a9f680aeSDavid du Colombier 		cleanmf(nmf);
613a9f680aeSDavid du Colombier 		free(nmf->user);
614a9f680aeSDavid du Colombier 		nmf->user = 0;
6159a747e4fSDavid du Colombier 		nmf->busy = 0;
6169a747e4fSDavid du Colombier 		nmf->fid = 0;
6179a747e4fSDavid du Colombier 	}
6189a747e4fSDavid du Colombier 	if(err == nil)
6199a747e4fSDavid du Colombier 		mf->qid = qid;
6207dd7cddfSDavid du Colombier 	sendmsg(job, err);
6213e12c5d1SDavid du Colombier 	return err;
6223e12c5d1SDavid du Colombier }
6233e12c5d1SDavid du Colombier 
6243e12c5d1SDavid du Colombier void
6257dd7cddfSDavid du Colombier ropen(Job *job, Mfile *mf)
6263e12c5d1SDavid du Colombier {
6273e12c5d1SDavid du Colombier 	int mode;
6283e12c5d1SDavid du Colombier 	char *err;
6293e12c5d1SDavid du Colombier 
6303e12c5d1SDavid du Colombier 	err = 0;
6317dd7cddfSDavid du Colombier 	mode = job->request.mode;
6329a747e4fSDavid du Colombier 	if(mf->qid.type & QTDIR){
6333e12c5d1SDavid du Colombier 		if(mode)
6343e12c5d1SDavid du Colombier 			err = "permission denied";
6359a747e4fSDavid du Colombier 	}
6367dd7cddfSDavid du Colombier 	job->reply.qid = mf->qid;
6379a747e4fSDavid du Colombier 	job->reply.iounit = 0;
6387dd7cddfSDavid du Colombier 	sendmsg(job, err);
6393e12c5d1SDavid du Colombier }
6403e12c5d1SDavid du Colombier 
6413e12c5d1SDavid du Colombier void
6427dd7cddfSDavid du Colombier rcreate(Job *job, Mfile *mf)
6433e12c5d1SDavid du Colombier {
6443e12c5d1SDavid du Colombier 	USED(mf);
6457dd7cddfSDavid du Colombier 	sendmsg(job, "creation permission denied");
6463e12c5d1SDavid du Colombier }
6473e12c5d1SDavid du Colombier 
6483e12c5d1SDavid du Colombier void
6497dd7cddfSDavid du Colombier rread(Job *job, Mfile *mf)
6503e12c5d1SDavid du Colombier {
651219b2ee8SDavid du Colombier 	int i, n, cnt;
652219b2ee8SDavid du Colombier 	long off, toff, clock;
6533e12c5d1SDavid du Colombier 	Dir dir;
6549a747e4fSDavid du Colombier 	uchar buf[Maxfdata];
6553e12c5d1SDavid du Colombier 	char *err;
6563e12c5d1SDavid du Colombier 
6573e12c5d1SDavid du Colombier 	n = 0;
6583e12c5d1SDavid du Colombier 	err = 0;
6597dd7cddfSDavid du Colombier 	off = job->request.offset;
6607dd7cddfSDavid du Colombier 	cnt = job->request.count;
6619a747e4fSDavid du Colombier 	if(mf->qid.type & QTDIR){
6623e12c5d1SDavid du Colombier 		clock = time(0);
6633e12c5d1SDavid du Colombier 		if(off == 0){
6649a747e4fSDavid du Colombier 			dir.name = "cs";
6659a747e4fSDavid du Colombier 			dir.qid.type = QTFILE;
6663e12c5d1SDavid du Colombier 			dir.qid.vers = vers;
6673e12c5d1SDavid du Colombier 			dir.qid.path = Qcs;
6683e12c5d1SDavid du Colombier 			dir.mode = 0666;
6693e12c5d1SDavid du Colombier 			dir.length = 0;
6709a747e4fSDavid du Colombier 			dir.uid = mf->user;
6719a747e4fSDavid du Colombier 			dir.gid = mf->user;
6729a747e4fSDavid du Colombier 			dir.muid = mf->user;
6733e12c5d1SDavid du Colombier 			dir.atime = clock;	/* wrong */
6743e12c5d1SDavid du Colombier 			dir.mtime = clock;	/* wrong */
6759a747e4fSDavid du Colombier 			n = convD2M(&dir, buf, sizeof buf);
6763e12c5d1SDavid du Colombier 		}
6779a747e4fSDavid du Colombier 		job->reply.data = (char*)buf;
6783e12c5d1SDavid du Colombier 	} else {
67980ee5cbfSDavid du Colombier 		for(;;){
68080ee5cbfSDavid du Colombier 			/* look for an answer at the right offset */
681219b2ee8SDavid du Colombier 			toff = 0;
682219b2ee8SDavid du Colombier 			for(i = 0; mf->reply[i] && i < mf->nreply; i++){
683219b2ee8SDavid du Colombier 				n = mf->replylen[i];
684219b2ee8SDavid du Colombier 				if(off < toff + n)
685219b2ee8SDavid du Colombier 					break;
686219b2ee8SDavid du Colombier 				toff += n;
6873e12c5d1SDavid du Colombier 			}
68880ee5cbfSDavid du Colombier 			if(i < mf->nreply)
68980ee5cbfSDavid du Colombier 				break;		/* got something to return */
69080ee5cbfSDavid du Colombier 
69180ee5cbfSDavid du Colombier 			/* try looking up more answers */
69280ee5cbfSDavid du Colombier 			if(lookup(mf) == 0){
69380ee5cbfSDavid du Colombier 				/* no more */
694219b2ee8SDavid du Colombier 				n = 0;
695219b2ee8SDavid du Colombier 				goto send;
696219b2ee8SDavid du Colombier 			}
69780ee5cbfSDavid du Colombier 		}
69880ee5cbfSDavid du Colombier 
69980ee5cbfSDavid du Colombier 		/* give back a single reply (or part of one) */
7007dd7cddfSDavid du Colombier 		job->reply.data = mf->reply[i] + (off - toff);
701219b2ee8SDavid du Colombier 		if(cnt > toff - off + n)
702219b2ee8SDavid du Colombier 			n = toff - off + n;
703219b2ee8SDavid du Colombier 		else
704219b2ee8SDavid du Colombier 			n = cnt;
7053e12c5d1SDavid du Colombier 	}
7063e12c5d1SDavid du Colombier send:
7077dd7cddfSDavid du Colombier 	job->reply.count = n;
7087dd7cddfSDavid du Colombier 	sendmsg(job, err);
7097dd7cddfSDavid du Colombier }
71080ee5cbfSDavid du Colombier void
71180ee5cbfSDavid du Colombier cleanmf(Mfile *mf)
7127dd7cddfSDavid du Colombier {
7137dd7cddfSDavid du Colombier 	int i;
7147dd7cddfSDavid du Colombier 
7159a747e4fSDavid du Colombier 	if(mf->net != nil){
71680ee5cbfSDavid du Colombier 		free(mf->net);
71780ee5cbfSDavid du Colombier 		mf->net = nil;
7189a747e4fSDavid du Colombier 	}
7199a747e4fSDavid du Colombier 	if(mf->host != nil){
72080ee5cbfSDavid du Colombier 		free(mf->host);
72180ee5cbfSDavid du Colombier 		mf->host = nil;
7229a747e4fSDavid du Colombier 	}
7239a747e4fSDavid du Colombier 	if(mf->serv != nil){
72480ee5cbfSDavid du Colombier 		free(mf->serv);
72580ee5cbfSDavid du Colombier 		mf->serv = nil;
7269a747e4fSDavid du Colombier 	}
7279a747e4fSDavid du Colombier 	if(mf->rem != nil){
72880ee5cbfSDavid du Colombier 		free(mf->rem);
72980ee5cbfSDavid du Colombier 		mf->rem = nil;
7309a747e4fSDavid du Colombier 	}
73180ee5cbfSDavid du Colombier 	for(i = 0; i < mf->nreply; i++){
73280ee5cbfSDavid du Colombier 		free(mf->reply[i]);
73380ee5cbfSDavid du Colombier 		mf->reply[i] = nil;
73480ee5cbfSDavid du Colombier 		mf->replylen[i] = 0;
7357dd7cddfSDavid du Colombier 	}
73680ee5cbfSDavid du Colombier 	mf->nreply = 0;
73780ee5cbfSDavid du Colombier 	mf->nextnet = netlist;
7383e12c5d1SDavid du Colombier }
7393e12c5d1SDavid du Colombier 
7403e12c5d1SDavid du Colombier void
7417dd7cddfSDavid du Colombier rwrite(Job *job, Mfile *mf)
7423e12c5d1SDavid du Colombier {
7433e12c5d1SDavid du Colombier 	int cnt, n;
74480ee5cbfSDavid du Colombier 	char *err;
7457dd7cddfSDavid du Colombier 	char *field[4];
746271b8d73SDavid du Colombier 	char curerr[64];
7473e12c5d1SDavid du Colombier 
7483e12c5d1SDavid du Colombier 	err = 0;
7497dd7cddfSDavid du Colombier 	cnt = job->request.count;
7509a747e4fSDavid du Colombier 	if(mf->qid.type & QTDIR){
7513e12c5d1SDavid du Colombier 		err = "can't write directory";
7523e12c5d1SDavid du Colombier 		goto send;
7533e12c5d1SDavid du Colombier 	}
7543e12c5d1SDavid du Colombier 	if(cnt >= Maxrequest){
7553e12c5d1SDavid du Colombier 		err = "request too long";
7563e12c5d1SDavid du Colombier 		goto send;
7573e12c5d1SDavid du Colombier 	}
7587dd7cddfSDavid du Colombier 	job->request.data[cnt] = 0;
7593e12c5d1SDavid du Colombier 
7603e12c5d1SDavid du Colombier 	/*
761219b2ee8SDavid du Colombier 	 *  toggle debugging
762219b2ee8SDavid du Colombier 	 */
7637dd7cddfSDavid du Colombier 	if(strncmp(job->request.data, "debug", 5)==0){
764219b2ee8SDavid du Colombier 		debug ^= 1;
765219b2ee8SDavid du Colombier 		syslog(1, logfile, "debug %d", debug);
766219b2ee8SDavid du Colombier 		goto send;
767219b2ee8SDavid du Colombier 	}
768219b2ee8SDavid du Colombier 
769219b2ee8SDavid du Colombier 	/*
7707dd7cddfSDavid du Colombier 	 *  toggle debugging
7717dd7cddfSDavid du Colombier 	 */
7727dd7cddfSDavid du Colombier 	if(strncmp(job->request.data, "paranoia", 8)==0){
7737dd7cddfSDavid du Colombier 		paranoia ^= 1;
7747dd7cddfSDavid du Colombier 		syslog(1, logfile, "paranoia %d", paranoia);
7757dd7cddfSDavid du Colombier 		goto send;
7767dd7cddfSDavid du Colombier 	}
7777dd7cddfSDavid du Colombier 
7787dd7cddfSDavid du Colombier 	/*
7793e12c5d1SDavid du Colombier 	 *  add networks to the default list
7803e12c5d1SDavid du Colombier 	 */
7817dd7cddfSDavid du Colombier 	if(strncmp(job->request.data, "add ", 4)==0){
7827dd7cddfSDavid du Colombier 		if(job->request.data[cnt-1] == '\n')
7837dd7cddfSDavid du Colombier 			job->request.data[cnt-1] = 0;
7847dd7cddfSDavid du Colombier 		netadd(job->request.data+4);
7857dd7cddfSDavid du Colombier 		readipinterfaces();
7867dd7cddfSDavid du Colombier 		goto send;
7877dd7cddfSDavid du Colombier 	}
7887dd7cddfSDavid du Colombier 
7897dd7cddfSDavid du Colombier 	/*
7907dd7cddfSDavid du Colombier 	 *  refresh all state
7917dd7cddfSDavid du Colombier 	 */
7927dd7cddfSDavid du Colombier 	if(strncmp(job->request.data, "refresh", 7)==0){
7937dd7cddfSDavid du Colombier 		netinit(1);
7943e12c5d1SDavid du Colombier 		goto send;
7953e12c5d1SDavid du Colombier 	}
7963e12c5d1SDavid du Colombier 
79780ee5cbfSDavid du Colombier 	/* start transaction with a clean slate */
79880ee5cbfSDavid du Colombier 	cleanmf(mf);
79980ee5cbfSDavid du Colombier 
8003e12c5d1SDavid du Colombier 	/*
801219b2ee8SDavid du Colombier 	 *  look for a general query
802219b2ee8SDavid du Colombier 	 */
8037dd7cddfSDavid du Colombier 	if(*job->request.data == '!'){
8047dd7cddfSDavid du Colombier 		err = genquery(mf, job->request.data+1);
805219b2ee8SDavid du Colombier 		goto send;
806219b2ee8SDavid du Colombier 	}
807219b2ee8SDavid du Colombier 
8087dd7cddfSDavid du Colombier 	if(debug)
8097dd7cddfSDavid du Colombier 		syslog(0, logfile, "write %s", job->request.data);
8107dd7cddfSDavid du Colombier 	if(paranoia)
8117dd7cddfSDavid du Colombier 		syslog(0, paranoiafile, "write %s by %s", job->request.data, mf->user);
8127dd7cddfSDavid du Colombier 
813219b2ee8SDavid du Colombier 	/*
8143e12c5d1SDavid du Colombier 	 *  break up name
8153e12c5d1SDavid du Colombier 	 */
8167dd7cddfSDavid du Colombier 	n = getfields(job->request.data, field, 4, 1, "!");
8173e12c5d1SDavid du Colombier 	switch(n){
8183e12c5d1SDavid du Colombier 	case 1:
81980ee5cbfSDavid du Colombier 		mf->net = strdup("net");
82080ee5cbfSDavid du Colombier 		mf->host = strdup(field[0]);
8217dd7cddfSDavid du Colombier 		break;
8227dd7cddfSDavid du Colombier 	case 4:
82380ee5cbfSDavid du Colombier 		mf->rem = strdup(field[3]);
82480ee5cbfSDavid du Colombier 		/* fall through */
82580ee5cbfSDavid du Colombier 	case 3:
82680ee5cbfSDavid du Colombier 		mf->serv = strdup(field[2]);
82780ee5cbfSDavid du Colombier 		/* fall through */
82880ee5cbfSDavid du Colombier 	case 2:
82980ee5cbfSDavid du Colombier 		mf->host = strdup(field[1]);
83080ee5cbfSDavid du Colombier 		mf->net = strdup(field[0]);
8313e12c5d1SDavid du Colombier 		break;
8323e12c5d1SDavid du Colombier 	}
8333e12c5d1SDavid du Colombier 
83480ee5cbfSDavid du Colombier 	/*
83580ee5cbfSDavid du Colombier 	 *  do the first net worth of lookup
83680ee5cbfSDavid du Colombier 	 */
837271b8d73SDavid du Colombier 	if(lookup(mf) == 0){
838271b8d73SDavid du Colombier 		rerrstr(curerr, sizeof curerr);
839271b8d73SDavid du Colombier 		err = curerr;
840271b8d73SDavid du Colombier 	}
8413e12c5d1SDavid du Colombier send:
8427dd7cddfSDavid du Colombier 	job->reply.count = cnt;
8437dd7cddfSDavid du Colombier 	sendmsg(job, err);
8443e12c5d1SDavid du Colombier }
8453e12c5d1SDavid du Colombier 
8463e12c5d1SDavid du Colombier void
8477dd7cddfSDavid du Colombier rclunk(Job *job, Mfile *mf)
8483e12c5d1SDavid du Colombier {
84980ee5cbfSDavid du Colombier 	cleanmf(mf);
850a9f680aeSDavid du Colombier 	free(mf->user);
851a9f680aeSDavid du Colombier 	mf->user = 0;
8523e12c5d1SDavid du Colombier 	mf->busy = 0;
8533e12c5d1SDavid du Colombier 	mf->fid = 0;
8547dd7cddfSDavid du Colombier 	sendmsg(job, 0);
8553e12c5d1SDavid du Colombier }
8563e12c5d1SDavid du Colombier 
8573e12c5d1SDavid du Colombier void
8587dd7cddfSDavid du Colombier rremove(Job *job, Mfile *mf)
8593e12c5d1SDavid du Colombier {
8603e12c5d1SDavid du Colombier 	USED(mf);
8617dd7cddfSDavid du Colombier 	sendmsg(job, "remove permission denied");
8623e12c5d1SDavid du Colombier }
8633e12c5d1SDavid du Colombier 
8643e12c5d1SDavid du Colombier void
8657dd7cddfSDavid du Colombier rstat(Job *job, Mfile *mf)
8663e12c5d1SDavid du Colombier {
8673e12c5d1SDavid du Colombier 	Dir dir;
8689a747e4fSDavid du Colombier 	uchar buf[IOHDRSZ+Maxfdata];
8693e12c5d1SDavid du Colombier 
8709a747e4fSDavid du Colombier 	if(mf->qid.type & QTDIR){
8719a747e4fSDavid du Colombier 		dir.name = ".";
8729a747e4fSDavid du Colombier 		dir.mode = DMDIR|0555;
873219b2ee8SDavid du Colombier 	} else {
8749a747e4fSDavid du Colombier 		dir.name = "cs";
8753e12c5d1SDavid du Colombier 		dir.mode = 0666;
876219b2ee8SDavid du Colombier 	}
877219b2ee8SDavid du Colombier 	dir.qid = mf->qid;
8783e12c5d1SDavid du Colombier 	dir.length = 0;
8799a747e4fSDavid du Colombier 	dir.uid = mf->user;
8809a747e4fSDavid du Colombier 	dir.gid = mf->user;
8819a747e4fSDavid du Colombier 	dir.muid = mf->user;
8823e12c5d1SDavid du Colombier 	dir.atime = dir.mtime = time(0);
8839a747e4fSDavid du Colombier 	job->reply.nstat = convD2M(&dir, buf, sizeof buf);
8849a747e4fSDavid du Colombier 	job->reply.stat = buf;
8857dd7cddfSDavid du Colombier 	sendmsg(job, 0);
8863e12c5d1SDavid du Colombier }
8873e12c5d1SDavid du Colombier 
8883e12c5d1SDavid du Colombier void
8897dd7cddfSDavid du Colombier rwstat(Job *job, Mfile *mf)
8903e12c5d1SDavid du Colombier {
8913e12c5d1SDavid du Colombier 	USED(mf);
8927dd7cddfSDavid du Colombier 	sendmsg(job, "wstat permission denied");
8933e12c5d1SDavid du Colombier }
8943e12c5d1SDavid du Colombier 
8953e12c5d1SDavid du Colombier void
8967dd7cddfSDavid du Colombier sendmsg(Job *job, char *err)
8973e12c5d1SDavid du Colombier {
8983e12c5d1SDavid du Colombier 	int n;
8999a747e4fSDavid du Colombier 	uchar mdata[IOHDRSZ + Maxfdata];
9009a747e4fSDavid du Colombier 	char ename[ERRMAX];
9013e12c5d1SDavid du Colombier 
9023e12c5d1SDavid du Colombier 	if(err){
9037dd7cddfSDavid du Colombier 		job->reply.type = Rerror;
9049a747e4fSDavid du Colombier 		snprint(ename, sizeof(ename), "cs: %s", err);
9059a747e4fSDavid du Colombier 		job->reply.ename = ename;
9063e12c5d1SDavid du Colombier 	}else{
9077dd7cddfSDavid du Colombier 		job->reply.type = job->request.type+1;
9083e12c5d1SDavid du Colombier 	}
9097dd7cddfSDavid du Colombier 	job->reply.tag = job->request.tag;
9109a747e4fSDavid du Colombier 	n = convS2M(&job->reply, mdata, sizeof mdata);
911219b2ee8SDavid du Colombier 	if(n == 0){
9127dd7cddfSDavid du Colombier 		syslog(1, logfile, "sendmsg convS2M of %F returns 0", &job->reply);
913219b2ee8SDavid du Colombier 		abort();
914219b2ee8SDavid du Colombier 	}
9157dd7cddfSDavid du Colombier 	lock(&joblock);
9167dd7cddfSDavid du Colombier 	if(job->flushed == 0)
9179a747e4fSDavid du Colombier 		if(write(mfd[1], mdata, n)!=n)
9183e12c5d1SDavid du Colombier 			error("mount write");
9197dd7cddfSDavid du Colombier 	unlock(&joblock);
920219b2ee8SDavid du Colombier 	if(debug)
9217dd7cddfSDavid du Colombier 		syslog(0, logfile, "%F %d", &job->reply, n);
9223e12c5d1SDavid du Colombier }
9233e12c5d1SDavid du Colombier 
9243e12c5d1SDavid du Colombier void
9253e12c5d1SDavid du Colombier error(char *s)
9263e12c5d1SDavid du Colombier {
927bd389b36SDavid du Colombier 	syslog(1, "cs", "%s: %r", s);
928bd389b36SDavid du Colombier 	_exits(0);
9293e12c5d1SDavid du Colombier }
9303e12c5d1SDavid du Colombier 
9317dd7cddfSDavid du Colombier static int
9327dd7cddfSDavid du Colombier isvalidip(uchar *ip)
9337dd7cddfSDavid du Colombier {
9347dd7cddfSDavid du Colombier 	return ipcmp(ip, IPnoaddr) != 0 && ipcmp(ip, v4prefix) != 0;
9357dd7cddfSDavid du Colombier }
9363e12c5d1SDavid du Colombier 
9370103620dSDavid du Colombier static uchar loopbacknet[IPaddrlen] = {
9380103620dSDavid du Colombier 	0, 0, 0, 0,
9390103620dSDavid du Colombier 	0, 0, 0, 0,
9400103620dSDavid du Colombier 	0, 0, 0xff, 0xff,
9410103620dSDavid du Colombier 	127, 0, 0, 0
9420103620dSDavid du Colombier };
9430103620dSDavid du Colombier static uchar loopbackmask[IPaddrlen] = {
9440103620dSDavid du Colombier 	0xff, 0xff, 0xff, 0xff,
9450103620dSDavid du Colombier 	0xff, 0xff, 0xff, 0xff,
9460103620dSDavid du Colombier 	0xff, 0xff, 0xff, 0xff,
9470103620dSDavid du Colombier 	0xff, 0, 0, 0
9480103620dSDavid du Colombier };
9490103620dSDavid du Colombier 
9507dd7cddfSDavid du Colombier void
9517dd7cddfSDavid du Colombier readipinterfaces(void)
9527dd7cddfSDavid du Colombier {
9530103620dSDavid du Colombier 	if(myipaddr(ipa, mntpt) != 0)
9540103620dSDavid du Colombier 		ipmove(ipa, IPnoaddr);
9557dd7cddfSDavid du Colombier 	sprint(ipaddr, "%I", ipa);
9567dd7cddfSDavid du Colombier 	if (debug)
9577dd7cddfSDavid du Colombier 		syslog(0, "dns", "ipaddr is %s\n", ipaddr);
9587dd7cddfSDavid du Colombier }
9593e12c5d1SDavid du Colombier 
9603e12c5d1SDavid du Colombier /*
9617dd7cddfSDavid du Colombier  *  get the system name
9623e12c5d1SDavid du Colombier  */
9633e12c5d1SDavid du Colombier void
9643e12c5d1SDavid du Colombier ipid(void)
9653e12c5d1SDavid du Colombier {
9663e12c5d1SDavid du Colombier 	uchar addr[6];
967a9f680aeSDavid du Colombier 	Ndbtuple *t, *tt;
968219b2ee8SDavid du Colombier 	char *p, *attr;
9693e12c5d1SDavid du Colombier 	Ndbs s;
9703e12c5d1SDavid du Colombier 	int f;
9717dd7cddfSDavid du Colombier 	char buf[Maxpath];
9723e12c5d1SDavid du Colombier 
973219b2ee8SDavid du Colombier 	/* use environment, ether addr, or ipaddr to get system name */
97495a264b3SDavid du Colombier 	if(mysysname == 0){
9757dd7cddfSDavid du Colombier 		/*
9767dd7cddfSDavid du Colombier 		 *  environment has priority.
9777dd7cddfSDavid du Colombier 		 *
9787dd7cddfSDavid du Colombier 		 *  on the sgi power the default system name
9797dd7cddfSDavid du Colombier 		 *  is the ip address.  ignore that.
9807dd7cddfSDavid du Colombier 		 *
9817dd7cddfSDavid du Colombier 		 */
982219b2ee8SDavid du Colombier 		p = getenv("sysname");
983447d6a7dSDavid du Colombier 		if(p && *p){
984219b2ee8SDavid du Colombier 			attr = ipattr(p);
985219b2ee8SDavid du Colombier 			if(strcmp(attr, "ip") != 0)
98695a264b3SDavid du Colombier 				mysysname = strdup(p);
9873e12c5d1SDavid du Colombier 		}
9883e12c5d1SDavid du Colombier 
9893e12c5d1SDavid du Colombier 		/*
9907dd7cddfSDavid du Colombier 		 *  the /net/ndb contains what the network
9917dd7cddfSDavid du Colombier 		 *  figured out from DHCP.  use that name if
9927dd7cddfSDavid du Colombier 		 *  there is one.
9933e12c5d1SDavid du Colombier 		 */
99495a264b3SDavid du Colombier 		if(mysysname == 0 && netdb != nil){
9957dd7cddfSDavid du Colombier 			ndbreopen(netdb);
996a9f680aeSDavid du Colombier 			for(tt = t = ndbparse(netdb); t != nil; t = t->entry){
9977dd7cddfSDavid du Colombier 				if(strcmp(t->attr, "sys") == 0){
99895a264b3SDavid du Colombier 					mysysname = strdup(t->val);
9993e12c5d1SDavid du Colombier 					break;
10003e12c5d1SDavid du Colombier 				}
10017dd7cddfSDavid du Colombier 			}
1002a9f680aeSDavid du Colombier 			ndbfree(tt);
10037dd7cddfSDavid du Colombier 		}
10047dd7cddfSDavid du Colombier 
10057dd7cddfSDavid du Colombier 		/* next network database, ip address, and ether address to find a name */
100695a264b3SDavid du Colombier 		if(mysysname == 0){
10077dd7cddfSDavid du Colombier 			t = nil;
10087dd7cddfSDavid du Colombier 			if(isvalidip(ipa))
100957837e0bSDavid du Colombier 				free(ndbgetvalue(db, &s, "ip", ipaddr, "sys", &t));
101095a264b3SDavid du Colombier 			if(t == nil){
10117dd7cddfSDavid du Colombier 				for(f = 0; f < 3; f++){
10127dd7cddfSDavid du Colombier 					snprint(buf, sizeof buf, "%s/ether%d", mntpt, f);
10137dd7cddfSDavid du Colombier 					if(myetheraddr(addr, buf) >= 0){
10147dd7cddfSDavid du Colombier 						snprint(eaddr, sizeof(eaddr), "%E", addr);
101557837e0bSDavid du Colombier 						free(ndbgetvalue(db, &s, "ether", eaddr, "sys", &t));
10167dd7cddfSDavid du Colombier 						if(t != nil)
10177dd7cddfSDavid du Colombier 							break;
10187dd7cddfSDavid du Colombier 					}
10197dd7cddfSDavid du Colombier 				}
10207dd7cddfSDavid du Colombier 			}
1021b7327ca2SDavid du Colombier 			for(tt = t; tt != nil; tt = tt->entry){
1022b7327ca2SDavid du Colombier 				if(strcmp(tt->attr, "sys") == 0){
1023b7327ca2SDavid du Colombier 					mysysname = strdup(tt->val);
102495a264b3SDavid du Colombier 					break;
102595a264b3SDavid du Colombier 				}
1026b7327ca2SDavid du Colombier 			}
10277dd7cddfSDavid du Colombier 			ndbfree(t);
10287dd7cddfSDavid du Colombier 		}
10297dd7cddfSDavid du Colombier 
103080ee5cbfSDavid du Colombier 		/* nothing else worked, use the ip address */
103195a264b3SDavid du Colombier 		if(mysysname == 0 && isvalidip(ipa))
103295a264b3SDavid du Colombier 			mysysname = strdup(ipaddr);
103380ee5cbfSDavid du Colombier 
103480ee5cbfSDavid du Colombier 
1035dc5a79c1SDavid du Colombier 		/* set /dev/sysname if we now know it */
103695a264b3SDavid du Colombier 		if(mysysname){
10377dd7cddfSDavid du Colombier 			f = open("/dev/sysname", OWRITE);
10387dd7cddfSDavid du Colombier 			if(f >= 0){
10397dd7cddfSDavid du Colombier 				write(f, mysysname, strlen(mysysname));
10403e12c5d1SDavid du Colombier 				close(f);
10413e12c5d1SDavid du Colombier 			}
10423e12c5d1SDavid du Colombier 		}
10433e12c5d1SDavid du Colombier 	}
10443e12c5d1SDavid du Colombier }
10453e12c5d1SDavid du Colombier 
10463e12c5d1SDavid du Colombier /*
10473e12c5d1SDavid du Colombier  *  Set up a list of default networks by looking for
10483e12c5d1SDavid du Colombier  *  /net/ * /clone.
10493e12c5d1SDavid du Colombier  */
10503e12c5d1SDavid du Colombier void
10517dd7cddfSDavid du Colombier netinit(int background)
10523e12c5d1SDavid du Colombier {
10537dd7cddfSDavid du Colombier 	char clone[Maxpath];
10543e12c5d1SDavid du Colombier 	Network *np;
10557dd7cddfSDavid du Colombier 	static int working;
10567dd7cddfSDavid du Colombier 
10577dd7cddfSDavid du Colombier 	if(background){
10587dd7cddfSDavid du Colombier 		switch(rfork(RFPROC|RFNOTEG|RFMEM|RFNOWAIT)){
10597dd7cddfSDavid du Colombier 		case 0:
10607dd7cddfSDavid du Colombier 			break;
10617dd7cddfSDavid du Colombier 		default:
10627dd7cddfSDavid du Colombier 			return;
10637dd7cddfSDavid du Colombier 		}
10647dd7cddfSDavid du Colombier 		lock(&netlock);
10657dd7cddfSDavid du Colombier 	}
10663e12c5d1SDavid du Colombier 
10673e12c5d1SDavid du Colombier 	/* add the mounted networks to the default list */
10683e12c5d1SDavid du Colombier 	for(np = network; np->net; np++){
10697dd7cddfSDavid du Colombier 		if(np->considered)
10707dd7cddfSDavid du Colombier 			continue;
10717dd7cddfSDavid du Colombier 		snprint(clone, sizeof(clone), "%s/%s/clone", mntpt, np->net);
10729a747e4fSDavid du Colombier 		if(access(clone, AEXIST) < 0)
10733e12c5d1SDavid du Colombier 			continue;
10743e12c5d1SDavid du Colombier 		if(netlist)
10753e12c5d1SDavid du Colombier 			last->next = np;
10763e12c5d1SDavid du Colombier 		else
10773e12c5d1SDavid du Colombier 			netlist = np;
10783e12c5d1SDavid du Colombier 		last = np;
10793e12c5d1SDavid du Colombier 		np->next = 0;
10807dd7cddfSDavid du Colombier 		np->considered = 1;
10813e12c5d1SDavid du Colombier 	}
10823e12c5d1SDavid du Colombier 
10837dd7cddfSDavid du Colombier 	/* find out what our ip address is */
10847dd7cddfSDavid du Colombier 	readipinterfaces();
10853e12c5d1SDavid du Colombier 
10867dd7cddfSDavid du Colombier 	/* set the system name if we need to, these says ip is all we have */
10873e12c5d1SDavid du Colombier 	ipid();
10883e12c5d1SDavid du Colombier 
1089219b2ee8SDavid du Colombier 	if(debug)
10907dd7cddfSDavid du Colombier 		syslog(0, logfile, "mysysname %s eaddr %s ipaddr %s ipa %I\n",
109195a264b3SDavid du Colombier 			mysysname?mysysname:"???", eaddr, ipaddr, ipa);
10927dd7cddfSDavid du Colombier 
10937dd7cddfSDavid du Colombier 	if(background){
10947dd7cddfSDavid du Colombier 		unlock(&netlock);
10957dd7cddfSDavid du Colombier 		_exits(0);
10967dd7cddfSDavid du Colombier 	}
10973e12c5d1SDavid du Colombier }
10983e12c5d1SDavid du Colombier 
10993e12c5d1SDavid du Colombier /*
11003e12c5d1SDavid du Colombier  *  add networks to the standard list
11013e12c5d1SDavid du Colombier  */
11023e12c5d1SDavid du Colombier void
11033e12c5d1SDavid du Colombier netadd(char *p)
11043e12c5d1SDavid du Colombier {
11053e12c5d1SDavid du Colombier 	Network *np;
11063e12c5d1SDavid du Colombier 	char *field[12];
11073e12c5d1SDavid du Colombier 	int i, n;
11083e12c5d1SDavid du Colombier 
11097dd7cddfSDavid du Colombier 	n = getfields(p, field, 12, 1, " ");
11103e12c5d1SDavid du Colombier 	for(i = 0; i < n; i++){
11113e12c5d1SDavid du Colombier 		for(np = network; np->net; np++){
11123e12c5d1SDavid du Colombier 			if(strcmp(field[i], np->net) != 0)
11133e12c5d1SDavid du Colombier 				continue;
11147dd7cddfSDavid du Colombier 			if(np->considered)
11153e12c5d1SDavid du Colombier 				break;
11163e12c5d1SDavid du Colombier 			if(netlist)
11173e12c5d1SDavid du Colombier 				last->next = np;
11183e12c5d1SDavid du Colombier 			else
11193e12c5d1SDavid du Colombier 				netlist = np;
11203e12c5d1SDavid du Colombier 			last = np;
11213e12c5d1SDavid du Colombier 			np->next = 0;
11227dd7cddfSDavid du Colombier 			np->considered = 1;
11233e12c5d1SDavid du Colombier 		}
11243e12c5d1SDavid du Colombier 	}
11253e12c5d1SDavid du Colombier }
11263e12c5d1SDavid du Colombier 
112780ee5cbfSDavid du Colombier int
112880ee5cbfSDavid du Colombier lookforproto(Ndbtuple *t, char *proto)
112980ee5cbfSDavid du Colombier {
113080ee5cbfSDavid du Colombier 	for(; t != nil; t = t->entry)
113180ee5cbfSDavid du Colombier 		if(strcmp(t->attr, "proto") == 0 && strcmp(t->val, proto) == 0)
113280ee5cbfSDavid du Colombier 			return 1;
113380ee5cbfSDavid du Colombier 	return 0;
113480ee5cbfSDavid du Colombier }
113580ee5cbfSDavid du Colombier 
1136219b2ee8SDavid du Colombier /*
11373e12c5d1SDavid du Colombier  *  lookup a request.  the network "net" means we should pick the
11383e12c5d1SDavid du Colombier  *  best network to get there.
11393e12c5d1SDavid du Colombier  */
11403e12c5d1SDavid du Colombier int
114180ee5cbfSDavid du Colombier lookup(Mfile *mf)
11423e12c5d1SDavid du Colombier {
114380ee5cbfSDavid du Colombier 	Network *np;
1144219b2ee8SDavid du Colombier 	char *cp;
1145219b2ee8SDavid du Colombier 	Ndbtuple *nt, *t;
1146219b2ee8SDavid du Colombier 	char reply[Maxreply];
114780ee5cbfSDavid du Colombier 	int i, rv;
114880ee5cbfSDavid du Colombier 	int hack;
11493e12c5d1SDavid du Colombier 
11503e12c5d1SDavid du Colombier 	/* open up the standard db files */
11513e12c5d1SDavid du Colombier 	if(db == 0)
11527dd7cddfSDavid du Colombier 		ndbinit();
11533e12c5d1SDavid du Colombier 	if(db == 0)
115480ee5cbfSDavid du Colombier 		error("can't open mf->network database\n");
11553e12c5d1SDavid du Colombier 
115680ee5cbfSDavid du Colombier 	rv = 0;
115780ee5cbfSDavid du Colombier 
115880ee5cbfSDavid du Colombier 	if(mf->net == nil)
115980ee5cbfSDavid du Colombier 		return 0;	/* must have been a genquery */
116080ee5cbfSDavid du Colombier 
116180ee5cbfSDavid du Colombier 	if(strcmp(mf->net, "net") == 0){
11623e12c5d1SDavid du Colombier 		/*
11633e12c5d1SDavid du Colombier 		 *  go through set of default nets
11643e12c5d1SDavid du Colombier 		 */
116580ee5cbfSDavid du Colombier 		for(np = mf->nextnet; np; np = np->next){
116680ee5cbfSDavid du Colombier 			nt = (*np->lookup)(np, mf->host, mf->serv, 1);
116780ee5cbfSDavid du Colombier 			if(nt == nil)
1168219b2ee8SDavid du Colombier 				continue;
116980ee5cbfSDavid du Colombier 			hack = np->fasttimeouthack && !lookforproto(nt, np->net);
117080ee5cbfSDavid du Colombier 			for(t = nt; mf->nreply < Nreply && t; t = t->entry){
117180ee5cbfSDavid du Colombier 				cp = (*np->trans)(t, np, mf->serv, mf->rem, hack);
1172219b2ee8SDavid du Colombier 				if(cp){
117380ee5cbfSDavid du Colombier 					/* avoid duplicates */
117480ee5cbfSDavid du Colombier 					for(i = 0; i < mf->nreply; i++)
117580ee5cbfSDavid du Colombier 						if(strcmp(mf->reply[i], cp) == 0)
117680ee5cbfSDavid du Colombier 							break;
117780ee5cbfSDavid du Colombier 					if(i == mf->nreply){
117880ee5cbfSDavid du Colombier 						/* save the reply */
1179219b2ee8SDavid du Colombier 						mf->replylen[mf->nreply] = strlen(cp);
1180219b2ee8SDavid du Colombier 						mf->reply[mf->nreply++] = cp;
118180ee5cbfSDavid du Colombier 						rv++;
1182219b2ee8SDavid du Colombier 					}
1183219b2ee8SDavid du Colombier 				}
1184219b2ee8SDavid du Colombier 			}
1185219b2ee8SDavid du Colombier 			ndbfree(nt);
118680ee5cbfSDavid du Colombier 			np = np->next;
118780ee5cbfSDavid du Colombier 			break;
118880ee5cbfSDavid du Colombier 		}
118980ee5cbfSDavid du Colombier 		mf->nextnet = np;
119080ee5cbfSDavid du Colombier 		return rv;
119180ee5cbfSDavid du Colombier 	}
119280ee5cbfSDavid du Colombier 
119380ee5cbfSDavid du Colombier 	/*
119480ee5cbfSDavid du Colombier 	 *  if not /net, we only get one lookup
119580ee5cbfSDavid du Colombier 	 */
119680ee5cbfSDavid du Colombier 	if(mf->nreply != 0)
1197219b2ee8SDavid du Colombier 		return 0;
119880ee5cbfSDavid du Colombier 	/*
119980ee5cbfSDavid du Colombier 	 *  look for a specific network
120080ee5cbfSDavid du Colombier 	 */
120195a264b3SDavid du Colombier 	for(np = netlist; np && np->net != nil; np++){
120280ee5cbfSDavid du Colombier 		if(np->fasttimeouthack)
120380ee5cbfSDavid du Colombier 			continue;
120480ee5cbfSDavid du Colombier 		if(strcmp(np->net, mf->net) == 0)
120580ee5cbfSDavid du Colombier 			break;
120680ee5cbfSDavid du Colombier 	}
120780ee5cbfSDavid du Colombier 
120895a264b3SDavid du Colombier 	if(np && np->net != nil){
120980ee5cbfSDavid du Colombier 		/*
121080ee5cbfSDavid du Colombier 		 *  known network
121180ee5cbfSDavid du Colombier 		 */
121280ee5cbfSDavid du Colombier 		nt = (*np->lookup)(np, mf->host, mf->serv, 1);
121380ee5cbfSDavid du Colombier 		for(t = nt; mf->nreply < Nreply && t; t = t->entry){
121480ee5cbfSDavid du Colombier 			cp = (*np->trans)(t, np, mf->serv, mf->rem, 0);
121580ee5cbfSDavid du Colombier 			if(cp){
121680ee5cbfSDavid du Colombier 				mf->replylen[mf->nreply] = strlen(cp);
121780ee5cbfSDavid du Colombier 				mf->reply[mf->nreply++] = cp;
121880ee5cbfSDavid du Colombier 				rv++;
121980ee5cbfSDavid du Colombier 			}
122080ee5cbfSDavid du Colombier 		}
122180ee5cbfSDavid du Colombier 		ndbfree(nt);
122280ee5cbfSDavid du Colombier 		return rv;
12233e12c5d1SDavid du Colombier 	} else {
12243e12c5d1SDavid du Colombier 		/*
1225219b2ee8SDavid du Colombier 		 *  not a known network, don't translate host or service
12263e12c5d1SDavid du Colombier 		 */
122780ee5cbfSDavid du Colombier 		if(mf->serv)
12287dd7cddfSDavid du Colombier 			snprint(reply, sizeof(reply), "%s/%s/clone %s!%s",
122980ee5cbfSDavid du Colombier 				mntpt, mf->net, mf->host, mf->serv);
1230bd389b36SDavid du Colombier 		else
12317dd7cddfSDavid du Colombier 			snprint(reply, sizeof(reply), "%s/%s/clone %s",
123280ee5cbfSDavid du Colombier 				mntpt, mf->net, mf->host);
1233219b2ee8SDavid du Colombier 		mf->reply[0] = strdup(reply);
1234219b2ee8SDavid du Colombier 		mf->replylen[0] = strlen(reply);
1235219b2ee8SDavid du Colombier 		mf->nreply = 1;
123680ee5cbfSDavid du Colombier 		return 1;
12373e12c5d1SDavid du Colombier 	}
12383e12c5d1SDavid du Colombier }
12393e12c5d1SDavid du Colombier 
12403e12c5d1SDavid du Colombier /*
12413e12c5d1SDavid du Colombier  *  translate an ip service name into a port number.  If it's a numeric port
12423e12c5d1SDavid du Colombier  *  number, look for restricted access.
12433e12c5d1SDavid du Colombier  *
12443e12c5d1SDavid du Colombier  *  the service '*' needs no translation.
12453e12c5d1SDavid du Colombier  */
12463e12c5d1SDavid du Colombier char*
124795a264b3SDavid du Colombier ipserv(Network *np, char *name, char *buf, int blen)
12483e12c5d1SDavid du Colombier {
12493e12c5d1SDavid du Colombier 	char *p;
12503e12c5d1SDavid du Colombier 	int alpha = 0;
12513e12c5d1SDavid du Colombier 	int restr = 0;
125295a264b3SDavid du Colombier 	char port[10];
12533e12c5d1SDavid du Colombier 	Ndbtuple *t, *nt;
12543e12c5d1SDavid du Colombier 	Ndbs s;
12553e12c5d1SDavid du Colombier 
12563e12c5d1SDavid du Colombier 	/* '*' means any service */
12573e12c5d1SDavid du Colombier 	if(strcmp(name, "*")==0){
12583e12c5d1SDavid du Colombier 		strcpy(buf, name);
12593e12c5d1SDavid du Colombier 		return buf;
12603e12c5d1SDavid du Colombier 	}
12613e12c5d1SDavid du Colombier 
12623e12c5d1SDavid du Colombier 	/*  see if it's numeric or symbolic */
12633e12c5d1SDavid du Colombier 	port[0] = 0;
12643e12c5d1SDavid du Colombier 	for(p = name; *p; p++){
12653e12c5d1SDavid du Colombier 		if(isdigit(*p))
12669a747e4fSDavid du Colombier 			{}
12673e12c5d1SDavid du Colombier 		else if(isalpha(*p) || *p == '-' || *p == '$')
12683e12c5d1SDavid du Colombier 			alpha = 1;
12693e12c5d1SDavid du Colombier 		else
12703e12c5d1SDavid du Colombier 			return 0;
12713e12c5d1SDavid du Colombier 	}
127257837e0bSDavid du Colombier 	t = nil;
127357837e0bSDavid du Colombier 	p = nil;
12743e12c5d1SDavid du Colombier 	if(alpha){
127557837e0bSDavid du Colombier 		p = ndbgetvalue(db, &s, np->net, name, "port", &t);
1276b7327ca2SDavid du Colombier 		if(p == nil)
1277b7327ca2SDavid du Colombier 			return 0;
12783e12c5d1SDavid du Colombier 	} else {
12793cc1eb97SDavid du Colombier 		/* look up only for tcp ports < 1024 to get the restricted
12803cc1eb97SDavid du Colombier 		 * attribute
12813cc1eb97SDavid du Colombier 		 */
12823cc1eb97SDavid du Colombier 		if(atoi(name) < 1024 && strcmp(np->net, "tcp") == 0)
128357837e0bSDavid du Colombier 			p = ndbgetvalue(db, &s, "port", name, "port", &t);
128457837e0bSDavid du Colombier 		if(p == nil)
128557837e0bSDavid du Colombier 			p = strdup(name);
12863e12c5d1SDavid du Colombier 	}
12873e12c5d1SDavid du Colombier 
12883e12c5d1SDavid du Colombier 	if(t){
12893e12c5d1SDavid du Colombier 		for(nt = t; nt; nt = nt->entry)
12903e12c5d1SDavid du Colombier 			if(strcmp(nt->attr, "restricted") == 0)
12913e12c5d1SDavid du Colombier 				restr = 1;
12923e12c5d1SDavid du Colombier 		ndbfree(t);
12933e12c5d1SDavid du Colombier 	}
129457837e0bSDavid du Colombier 	snprint(buf, blen, "%s%s", p, restr ? "!r" : "");
129557837e0bSDavid du Colombier 	free(p);
129657837e0bSDavid du Colombier 
12973e12c5d1SDavid du Colombier 	return buf;
12983e12c5d1SDavid du Colombier }
12993e12c5d1SDavid du Colombier 
13003e12c5d1SDavid du Colombier /*
13017dd7cddfSDavid du Colombier  *  lookup an ip attribute
13023e12c5d1SDavid du Colombier  */
13037dd7cddfSDavid du Colombier int
130495a264b3SDavid du Colombier ipattrlookup(Ndb *db, char *ipa, char *attr, char *val, int vlen)
13053e12c5d1SDavid du Colombier {
13063e12c5d1SDavid du Colombier 
13077dd7cddfSDavid du Colombier 	Ndbtuple *t, *nt;
13087dd7cddfSDavid du Colombier 	char *alist[2];
13093e12c5d1SDavid du Colombier 
13107dd7cddfSDavid du Colombier 	alist[0] = attr;
13117dd7cddfSDavid du Colombier 	t = ndbipinfo(db, "ip", ipa, alist, 1);
13127dd7cddfSDavid du Colombier 	if(t == nil)
13137dd7cddfSDavid du Colombier 		return 0;
13149a747e4fSDavid du Colombier 	for(nt = t; nt != nil; nt = nt->entry){
13157dd7cddfSDavid du Colombier 		if(strcmp(nt->attr, attr) == 0){
131695a264b3SDavid du Colombier 			nstrcpy(val, nt->val, vlen);
13173e12c5d1SDavid du Colombier 			ndbfree(t);
13187dd7cddfSDavid du Colombier 			return 1;
1319219b2ee8SDavid du Colombier 		}
13209a747e4fSDavid du Colombier 	}
13213e12c5d1SDavid du Colombier 
13227dd7cddfSDavid du Colombier 	/* we shouldn't get here */
13233e12c5d1SDavid du Colombier 	ndbfree(t);
13247dd7cddfSDavid du Colombier 	return 0;
13253e12c5d1SDavid du Colombier }
13263e12c5d1SDavid du Colombier 
13273e12c5d1SDavid du Colombier /*
13283e12c5d1SDavid du Colombier  *  lookup (and translate) an ip destination
13293e12c5d1SDavid du Colombier  */
1330219b2ee8SDavid du Colombier Ndbtuple*
1331219b2ee8SDavid du Colombier iplookup(Network *np, char *host, char *serv, int nolookup)
13323e12c5d1SDavid du Colombier {
1333*9dfc0cb2SDavid du Colombier 	char *attr, *dnsname;
13347dd7cddfSDavid du Colombier 	Ndbtuple *t, *nt;
13353e12c5d1SDavid du Colombier 	Ndbs s;
133695a264b3SDavid du Colombier 	char ts[Maxservice];
133795a264b3SDavid du Colombier 	char dollar[Maxhost];
13387dd7cddfSDavid du Colombier 	uchar ip[IPaddrlen];
13397dd7cddfSDavid du Colombier 	uchar net[IPaddrlen];
13407dd7cddfSDavid du Colombier 	uchar tnet[IPaddrlen];
13417dd7cddfSDavid du Colombier 	Ipifc *ifc;
13429a747e4fSDavid du Colombier 	Iplifc *lifc;
13433e12c5d1SDavid du Colombier 
1344219b2ee8SDavid du Colombier 	USED(nolookup);
1345219b2ee8SDavid du Colombier 
13463e12c5d1SDavid du Colombier 	/*
13473e12c5d1SDavid du Colombier 	 *  start with the service since it's the most likely to fail
13483e12c5d1SDavid du Colombier 	 *  and costs the least
13493e12c5d1SDavid du Colombier 	 */
13507dd7cddfSDavid du Colombier 	werrstr("can't translate address");
135195a264b3SDavid du Colombier 	if(serv==0 || ipserv(np, serv, ts, sizeof ts) == 0){
1352271b8d73SDavid du Colombier 		werrstr("can't translate service");
1353219b2ee8SDavid du Colombier 		return 0;
13547dd7cddfSDavid du Colombier 	}
13553e12c5d1SDavid du Colombier 
13563e12c5d1SDavid du Colombier 	/* for dial strings with no host */
1357219b2ee8SDavid du Colombier 	if(strcmp(host, "*") == 0)
135895a264b3SDavid du Colombier 		return ndbnew("ip", "*");
13593e12c5d1SDavid du Colombier 
13603e12c5d1SDavid du Colombier 	/*
13617dd7cddfSDavid du Colombier 	 *  hack till we go v6 :: = 0.0.0.0
13627dd7cddfSDavid du Colombier 	 */
13637dd7cddfSDavid du Colombier 	if(strcmp("::", host) == 0)
136495a264b3SDavid du Colombier 		return ndbnew("ip", "*");
13657dd7cddfSDavid du Colombier 
13667dd7cddfSDavid du Colombier 	/*
13673e12c5d1SDavid du Colombier 	 *  '$' means the rest of the name is an attribute that we
13683e12c5d1SDavid du Colombier 	 *  need to search for
13693e12c5d1SDavid du Colombier 	 */
13703e12c5d1SDavid du Colombier 	if(*host == '$'){
137195a264b3SDavid du Colombier 		if(ipattrlookup(db, ipaddr, host+1, dollar, sizeof dollar))
13723e12c5d1SDavid du Colombier 			host = dollar;
13733e12c5d1SDavid du Colombier 	}
13743e12c5d1SDavid du Colombier 
13753e12c5d1SDavid du Colombier 	/*
13767dd7cddfSDavid du Colombier 	 *  turn '[ip address]' into just 'ip address'
13777dd7cddfSDavid du Colombier 	 */
13787dd7cddfSDavid du Colombier 	if(*host == '[' && host[strlen(host)-1] == ']'){
13797dd7cddfSDavid du Colombier 		host++;
13807dd7cddfSDavid du Colombier 		host[strlen(host)-1] = 0;
13817dd7cddfSDavid du Colombier 	}
13827dd7cddfSDavid du Colombier 
13837dd7cddfSDavid du Colombier 	/*
13843e12c5d1SDavid du Colombier 	 *  just accept addresses
13853e12c5d1SDavid du Colombier 	 */
1386219b2ee8SDavid du Colombier 	attr = ipattr(host);
1387219b2ee8SDavid du Colombier 	if(strcmp(attr, "ip") == 0)
138895a264b3SDavid du Colombier 		return ndbnew("ip", host);
13893e12c5d1SDavid du Colombier 
13903e12c5d1SDavid du Colombier 	/*
13913e12c5d1SDavid du Colombier 	 *  give the domain name server the first opportunity to
1392bd389b36SDavid du Colombier 	 *  resolve domain names.  if that fails try the database.
13933e12c5d1SDavid du Colombier 	 */
13943e12c5d1SDavid du Colombier 	t = 0;
1395271b8d73SDavid du Colombier 	werrstr("can't translate address");
13963e12c5d1SDavid du Colombier 	if(strcmp(attr, "dom") == 0)
13977dd7cddfSDavid du Colombier 		t = dnsiplookup(host, &s);
13983e12c5d1SDavid du Colombier 	if(t == 0)
139957837e0bSDavid du Colombier 		free(ndbgetvalue(db, &s, attr, host, "ip", &t));
1400*9dfc0cb2SDavid du Colombier 	if(t == 0){
1401*9dfc0cb2SDavid du Colombier 		dnsname = ndbgetvalue(db, &s, attr, host, "dom", nil);
1402*9dfc0cb2SDavid du Colombier 		if(dnsname){
1403*9dfc0cb2SDavid du Colombier 			t = dnsiplookup(dnsname, &s);
1404*9dfc0cb2SDavid du Colombier 			free(dnsname);
1405*9dfc0cb2SDavid du Colombier 		}
1406*9dfc0cb2SDavid du Colombier 	}
14073e12c5d1SDavid du Colombier 	if(t == 0)
14087dd7cddfSDavid du Colombier 		t = dnsiplookup(host, &s);
14097dd7cddfSDavid du Colombier 	if(t == 0)
1410219b2ee8SDavid du Colombier 		return 0;
1411bd389b36SDavid du Colombier 
1412bd389b36SDavid du Colombier 	/*
1413bd389b36SDavid du Colombier 	 *  reorder the tuple to have the matched line first and
1414bd389b36SDavid du Colombier 	 *  save that in the request structure.
1415bd389b36SDavid du Colombier 	 */
14167dd7cddfSDavid du Colombier 	t = reorder(t, s.t);
14177dd7cddfSDavid du Colombier 
14187dd7cddfSDavid du Colombier 	/*
14197dd7cddfSDavid du Colombier 	 * reorder according to our interfaces
14207dd7cddfSDavid du Colombier 	 */
14217dd7cddfSDavid du Colombier 	lock(&ipifclock);
14229a747e4fSDavid du Colombier 	for(ifc = ipifcs; ifc != nil; ifc = ifc->next){
14239a747e4fSDavid du Colombier 		for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
14249a747e4fSDavid du Colombier 			maskip(lifc->ip, lifc->mask, net);
14257dd7cddfSDavid du Colombier 			for(nt = t; nt; nt = nt->entry){
14267dd7cddfSDavid du Colombier 				if(strcmp(nt->attr, "ip") != 0)
14277dd7cddfSDavid du Colombier 					continue;
14287dd7cddfSDavid du Colombier 				parseip(ip, nt->val);
14299a747e4fSDavid du Colombier 				maskip(ip, lifc->mask, tnet);
14307dd7cddfSDavid du Colombier 				if(memcmp(net, tnet, IPaddrlen) == 0){
14317dd7cddfSDavid du Colombier 					t = reorder(t, nt);
14327dd7cddfSDavid du Colombier 					unlock(&ipifclock);
14337dd7cddfSDavid du Colombier 					return t;
14347dd7cddfSDavid du Colombier 				}
14357dd7cddfSDavid du Colombier 			}
14367dd7cddfSDavid du Colombier 		}
14379a747e4fSDavid du Colombier 	}
14387dd7cddfSDavid du Colombier 	unlock(&ipifclock);
14397dd7cddfSDavid du Colombier 
14407dd7cddfSDavid du Colombier 	return t;
14413e12c5d1SDavid du Colombier }
14423e12c5d1SDavid du Colombier 
14433e12c5d1SDavid du Colombier /*
14443e12c5d1SDavid du Colombier  *  translate an ip address
14453e12c5d1SDavid du Colombier  */
1446219b2ee8SDavid du Colombier char*
144780ee5cbfSDavid du Colombier iptrans(Ndbtuple *t, Network *np, char *serv, char *rem, int hack)
14483e12c5d1SDavid du Colombier {
144995a264b3SDavid du Colombier 	char ts[Maxservice];
1450219b2ee8SDavid du Colombier 	char reply[Maxreply];
145195a264b3SDavid du Colombier 	char x[Maxservice];
14523e12c5d1SDavid du Colombier 
1453219b2ee8SDavid du Colombier 	if(strcmp(t->attr, "ip") != 0)
14543e12c5d1SDavid du Colombier 		return 0;
1455219b2ee8SDavid du Colombier 
145695a264b3SDavid du Colombier 	if(serv == 0 || ipserv(np, serv, ts, sizeof ts) == 0){
1457271b8d73SDavid du Colombier 		werrstr("can't translate service");
1458219b2ee8SDavid du Colombier 		return 0;
1459271b8d73SDavid du Colombier 	}
14607dd7cddfSDavid du Colombier 	if(rem != nil)
14617dd7cddfSDavid du Colombier 		snprint(x, sizeof(x), "!%s", rem);
14627dd7cddfSDavid du Colombier 	else
14637dd7cddfSDavid du Colombier 		*x = 0;
146480ee5cbfSDavid du Colombier 
1465219b2ee8SDavid du Colombier 	if(*t->val == '*')
14667dd7cddfSDavid du Colombier 		snprint(reply, sizeof(reply), "%s/%s/clone %s%s",
14677dd7cddfSDavid du Colombier 			mntpt, np->net, ts, x);
1468219b2ee8SDavid du Colombier 	else
146980ee5cbfSDavid du Colombier 		snprint(reply, sizeof(reply), "%s/%s/clone %s!%s%s%s",
147080ee5cbfSDavid du Colombier 			mntpt, np->net, t->val, ts, x, hack?"!fasttimeout":"");
1471219b2ee8SDavid du Colombier 
1472219b2ee8SDavid du Colombier 	return strdup(reply);
14733e12c5d1SDavid du Colombier }
14743e12c5d1SDavid du Colombier 
1475219b2ee8SDavid du Colombier /*
1476219b2ee8SDavid du Colombier  *  lookup a telephone number
1477219b2ee8SDavid du Colombier  */
1478219b2ee8SDavid du Colombier Ndbtuple*
1479219b2ee8SDavid du Colombier telcolookup(Network *np, char *host, char *serv, int nolookup)
1480219b2ee8SDavid du Colombier {
1481219b2ee8SDavid du Colombier 	Ndbtuple *t;
1482219b2ee8SDavid du Colombier 	Ndbs s;
1483219b2ee8SDavid du Colombier 
1484219b2ee8SDavid du Colombier 	USED(np, nolookup, serv);
1485219b2ee8SDavid du Colombier 
1486271b8d73SDavid du Colombier 	werrstr("can't translate address");
148757837e0bSDavid du Colombier 	free(ndbgetvalue(db, &s, "sys", host, "telco", &t));
1488219b2ee8SDavid du Colombier 	if(t == 0)
148995a264b3SDavid du Colombier 		return ndbnew("telco", host);
1490219b2ee8SDavid du Colombier 
1491219b2ee8SDavid du Colombier 	return reorder(t, s.t);
1492219b2ee8SDavid du Colombier }
1493219b2ee8SDavid du Colombier 
1494219b2ee8SDavid du Colombier /*
1495219b2ee8SDavid du Colombier  *  translate a telephone address
1496219b2ee8SDavid du Colombier  */
1497219b2ee8SDavid du Colombier char*
149880ee5cbfSDavid du Colombier telcotrans(Ndbtuple *t, Network *np, char *serv, char *rem, int)
1499219b2ee8SDavid du Colombier {
1500219b2ee8SDavid du Colombier 	char reply[Maxreply];
150195a264b3SDavid du Colombier 	char x[Maxservice];
1502219b2ee8SDavid du Colombier 
1503219b2ee8SDavid du Colombier 	if(strcmp(t->attr, "telco") != 0)
1504219b2ee8SDavid du Colombier 		return 0;
1505219b2ee8SDavid du Colombier 
15067dd7cddfSDavid du Colombier 	if(rem != nil)
15077dd7cddfSDavid du Colombier 		snprint(x, sizeof(x), "!%s", rem);
1508219b2ee8SDavid du Colombier 	else
15097dd7cddfSDavid du Colombier 		*x = 0;
15107dd7cddfSDavid du Colombier 	if(serv)
15117dd7cddfSDavid du Colombier 		snprint(reply, sizeof(reply), "%s/%s/clone %s!%s%s", mntpt, np->net,
15127dd7cddfSDavid du Colombier 			t->val, serv, x);
15137dd7cddfSDavid du Colombier 	else
15147dd7cddfSDavid du Colombier 		snprint(reply, sizeof(reply), "%s/%s/clone %s%s", mntpt, np->net,
15157dd7cddfSDavid du Colombier 			t->val, x);
1516219b2ee8SDavid du Colombier 	return strdup(reply);
1517219b2ee8SDavid du Colombier }
15183e12c5d1SDavid du Colombier 
15193e12c5d1SDavid du Colombier /*
15203e12c5d1SDavid du Colombier  *  reorder the tuple to put x's line first in the entry
15213e12c5d1SDavid du Colombier  */
15223e12c5d1SDavid du Colombier Ndbtuple*
15233e12c5d1SDavid du Colombier reorder(Ndbtuple *t, Ndbtuple *x)
15243e12c5d1SDavid du Colombier {
15253e12c5d1SDavid du Colombier 	Ndbtuple *nt;
15263e12c5d1SDavid du Colombier 	Ndbtuple *line;
15273e12c5d1SDavid du Colombier 
1528219b2ee8SDavid du Colombier 	/* find start of this entry's line */
1529219b2ee8SDavid du Colombier 	for(line = x; line->entry == line->line; line = line->line)
15303e12c5d1SDavid du Colombier 		;
1531219b2ee8SDavid du Colombier 	line = line->line;
1532219b2ee8SDavid du Colombier 	if(line == t)
1533219b2ee8SDavid du Colombier 		return t;	/* already the first line */
15343e12c5d1SDavid du Colombier 
1535219b2ee8SDavid du Colombier 	/* remove this line and everything after it from the entry */
1536219b2ee8SDavid du Colombier 	for(nt = t; nt->entry != line; nt = nt->entry)
1537219b2ee8SDavid du Colombier 		;
1538219b2ee8SDavid du Colombier 	nt->entry = 0;
15393e12c5d1SDavid du Colombier 
1540219b2ee8SDavid du Colombier 	/* make that the start of the entry */
1541219b2ee8SDavid du Colombier 	for(nt = line; nt->entry; nt = nt->entry)
1542219b2ee8SDavid du Colombier 		;
15433e12c5d1SDavid du Colombier 	nt->entry = t;
15443e12c5d1SDavid du Colombier 	return line;
15453e12c5d1SDavid du Colombier }
15463e12c5d1SDavid du Colombier 
15473e12c5d1SDavid du Colombier /*
15483e12c5d1SDavid du Colombier  *  create a slave process to handle a request to avoid one request blocking
15497dd7cddfSDavid du Colombier  *  another.  parent returns to job loop.
15503e12c5d1SDavid du Colombier  */
15513e12c5d1SDavid du Colombier void
15523e12c5d1SDavid du Colombier slave(void)
15533e12c5d1SDavid du Colombier {
15543e12c5d1SDavid du Colombier 	if(*isslave)
15553e12c5d1SDavid du Colombier 		return;		/* we're already a slave process */
15563e12c5d1SDavid du Colombier 
15573e12c5d1SDavid du Colombier 	switch(rfork(RFPROC|RFNOTEG|RFMEM|RFNOWAIT)){
15583e12c5d1SDavid du Colombier 	case -1:
15593e12c5d1SDavid du Colombier 		break;
15603e12c5d1SDavid du Colombier 	case 0:
1561219b2ee8SDavid du Colombier 		if(debug)
1562219b2ee8SDavid du Colombier 			syslog(0, logfile, "slave %d", getpid());
15633e12c5d1SDavid du Colombier 		*isslave = 1;
15643e12c5d1SDavid du Colombier 		break;
15653e12c5d1SDavid du Colombier 	default:
15663e12c5d1SDavid du Colombier 		longjmp(masterjmp, 1);
15673e12c5d1SDavid du Colombier 	}
15683e12c5d1SDavid du Colombier 
1569219b2ee8SDavid du Colombier }
1570219b2ee8SDavid du Colombier 
15713e12c5d1SDavid du Colombier /*
15723e12c5d1SDavid du Colombier  *  call the dns process and have it try to translate a name
15733e12c5d1SDavid du Colombier  */
15743e12c5d1SDavid du Colombier Ndbtuple*
15757dd7cddfSDavid du Colombier dnsiplookup(char *host, Ndbs *s)
15763e12c5d1SDavid du Colombier {
157795a264b3SDavid du Colombier 	char buf[Maxreply];
15787dd7cddfSDavid du Colombier 	Ndbtuple *t;
15793e12c5d1SDavid du Colombier 
1580bd389b36SDavid du Colombier 	unlock(&dblock);
1581bd389b36SDavid du Colombier 
15823e12c5d1SDavid du Colombier 	/* save the name before starting a slave */
15837dd7cddfSDavid du Colombier 	snprint(buf, sizeof(buf), "%s", host);
15843e12c5d1SDavid du Colombier 
15853e12c5d1SDavid du Colombier 	slave();
15863e12c5d1SDavid du Colombier 
15877dd7cddfSDavid du Colombier 	if(strcmp(ipattr(buf), "ip") == 0)
15887dd7cddfSDavid du Colombier 		t = dnsquery(mntpt, buf, "ptr");
15897dd7cddfSDavid du Colombier 	else
15907dd7cddfSDavid du Colombier 		t = dnsquery(mntpt, buf, "ip");
15913e12c5d1SDavid du Colombier 	s->t = t;
15927dd7cddfSDavid du Colombier 
1593271b8d73SDavid du Colombier 	if(t == nil){
1594271b8d73SDavid du Colombier 		rerrstr(buf, sizeof buf);
1595271b8d73SDavid du Colombier 		if(strstr(buf, "exist"))
1596271b8d73SDavid du Colombier 			werrstr("can't translate address: %s", buf);
1597271b8d73SDavid du Colombier 		else if(strstr(buf, "dns failure"))
1598271b8d73SDavid du Colombier 			werrstr("temporary problem: %s", buf);
1599271b8d73SDavid du Colombier 	}
1600271b8d73SDavid du Colombier 
1601bd389b36SDavid du Colombier 	lock(&dblock);
16023e12c5d1SDavid du Colombier 	return t;
16033e12c5d1SDavid du Colombier }
1604219b2ee8SDavid du Colombier 
1605219b2ee8SDavid du Colombier int
1606219b2ee8SDavid du Colombier qmatch(Ndbtuple *t, char **attr, char **val, int n)
1607219b2ee8SDavid du Colombier {
1608219b2ee8SDavid du Colombier 	int i, found;
1609219b2ee8SDavid du Colombier 	Ndbtuple *nt;
1610219b2ee8SDavid du Colombier 
1611219b2ee8SDavid du Colombier 	for(i = 1; i < n; i++){
1612219b2ee8SDavid du Colombier 		found = 0;
1613219b2ee8SDavid du Colombier 		for(nt = t; nt; nt = nt->entry)
1614219b2ee8SDavid du Colombier 			if(strcmp(attr[i], nt->attr) == 0)
1615219b2ee8SDavid du Colombier 				if(strcmp(val[i], "*") == 0
1616219b2ee8SDavid du Colombier 				|| strcmp(val[i], nt->val) == 0){
1617219b2ee8SDavid du Colombier 					found = 1;
1618219b2ee8SDavid du Colombier 					break;
1619219b2ee8SDavid du Colombier 				}
1620219b2ee8SDavid du Colombier 		if(found == 0)
1621219b2ee8SDavid du Colombier 			break;
1622219b2ee8SDavid du Colombier 	}
1623219b2ee8SDavid du Colombier 	return i == n;
1624219b2ee8SDavid du Colombier }
1625219b2ee8SDavid du Colombier 
1626219b2ee8SDavid du Colombier void
1627219b2ee8SDavid du Colombier qreply(Mfile *mf, Ndbtuple *t)
1628219b2ee8SDavid du Colombier {
1629219b2ee8SDavid du Colombier 	Ndbtuple *nt;
163095a264b3SDavid du Colombier 	String *s;
1631219b2ee8SDavid du Colombier 
163295a264b3SDavid du Colombier 	s = s_new();
1633219b2ee8SDavid du Colombier 	for(nt = t; mf->nreply < Nreply && nt; nt = nt->entry){
163495a264b3SDavid du Colombier 		s_append(s, nt->attr);
163595a264b3SDavid du Colombier 		s_append(s, "=");
163695a264b3SDavid du Colombier 		s_append(s, nt->val);
163795a264b3SDavid du Colombier 
163895a264b3SDavid du Colombier 		if(nt->line != nt->entry){
163995a264b3SDavid du Colombier 			mf->replylen[mf->nreply] = s_len(s);
164095a264b3SDavid du Colombier 			mf->reply[mf->nreply++] = strdup(s_to_c(s));
164195a264b3SDavid du Colombier 			s_restart(s);
1642219b2ee8SDavid du Colombier 		} else
164395a264b3SDavid du Colombier 			s_append(s, " ");
1644219b2ee8SDavid du Colombier 	}
164595a264b3SDavid du Colombier 	s_free(s);
1646219b2ee8SDavid du Colombier }
1647219b2ee8SDavid du Colombier 
16487dd7cddfSDavid du Colombier enum
16497dd7cddfSDavid du Colombier {
16507dd7cddfSDavid du Colombier 	Maxattr=	32,
16517dd7cddfSDavid du Colombier };
16527dd7cddfSDavid du Colombier 
1653219b2ee8SDavid du Colombier /*
16547dd7cddfSDavid du Colombier  *  generic query lookup.  The query is of one of the following
16557dd7cddfSDavid du Colombier  *  forms:
16567dd7cddfSDavid du Colombier  *
16577dd7cddfSDavid du Colombier  *  attr1=val1 attr2=val2 attr3=val3 ...
16587dd7cddfSDavid du Colombier  *
16597dd7cddfSDavid du Colombier  *  returns the matching tuple
16607dd7cddfSDavid du Colombier  *
16617dd7cddfSDavid du Colombier  *  ipinfo attr=val attr1 attr2 attr3 ...
16627dd7cddfSDavid du Colombier  *
16637dd7cddfSDavid du Colombier  *  is like ipinfo and returns the attr{1-n}
16647dd7cddfSDavid du Colombier  *  associated with the ip address.
1665219b2ee8SDavid du Colombier  */
1666219b2ee8SDavid du Colombier char*
1667219b2ee8SDavid du Colombier genquery(Mfile *mf, char *query)
1668219b2ee8SDavid du Colombier {
1669219b2ee8SDavid du Colombier 	int i, n;
1670219b2ee8SDavid du Colombier 	char *p;
16717dd7cddfSDavid du Colombier 	char *attr[Maxattr];
16727dd7cddfSDavid du Colombier 	char *val[Maxattr];
1673219b2ee8SDavid du Colombier 	Ndbtuple *t;
1674219b2ee8SDavid du Colombier 	Ndbs s;
1675219b2ee8SDavid du Colombier 
16767dd7cddfSDavid du Colombier 	n = getfields(query, attr, 32, 1, " ");
1677219b2ee8SDavid du Colombier 	if(n == 0)
1678219b2ee8SDavid du Colombier 		return "bad query";
1679219b2ee8SDavid du Colombier 
16807dd7cddfSDavid du Colombier 	if(strcmp(attr[0], "ipinfo") == 0)
16817dd7cddfSDavid du Colombier 		return ipinfoquery(mf, attr, n);
16827dd7cddfSDavid du Colombier 
1683219b2ee8SDavid du Colombier 	/* parse pairs */
1684219b2ee8SDavid du Colombier 	for(i = 0; i < n; i++){
1685219b2ee8SDavid du Colombier 		p = strchr(attr[i], '=');
1686219b2ee8SDavid du Colombier 		if(p == 0)
1687219b2ee8SDavid du Colombier 			return "bad query";
1688219b2ee8SDavid du Colombier 		*p++ = 0;
1689219b2ee8SDavid du Colombier 		val[i] = p;
1690219b2ee8SDavid du Colombier 	}
1691219b2ee8SDavid du Colombier 
1692219b2ee8SDavid du Colombier 	/* give dns a chance */
1693219b2ee8SDavid du Colombier 	if((strcmp(attr[0], "dom") == 0 || strcmp(attr[0], "ip") == 0) && val[0]){
16947dd7cddfSDavid du Colombier 		t = dnsiplookup(val[0], &s);
1695219b2ee8SDavid du Colombier 		if(t){
1696219b2ee8SDavid du Colombier 			if(qmatch(t, attr, val, n)){
1697219b2ee8SDavid du Colombier 				qreply(mf, t);
1698219b2ee8SDavid du Colombier 				ndbfree(t);
1699219b2ee8SDavid du Colombier 				return 0;
1700219b2ee8SDavid du Colombier 			}
1701219b2ee8SDavid du Colombier 			ndbfree(t);
1702219b2ee8SDavid du Colombier 		}
1703219b2ee8SDavid du Colombier 	}
1704219b2ee8SDavid du Colombier 
1705219b2ee8SDavid du Colombier 	/* first pair is always the key.  It can't be a '*' */
1706219b2ee8SDavid du Colombier 	t = ndbsearch(db, &s, attr[0], val[0]);
1707219b2ee8SDavid du Colombier 
1708219b2ee8SDavid du Colombier 	/* search is the and of all the pairs */
1709219b2ee8SDavid du Colombier 	while(t){
1710219b2ee8SDavid du Colombier 		if(qmatch(t, attr, val, n)){
1711219b2ee8SDavid du Colombier 			qreply(mf, t);
1712219b2ee8SDavid du Colombier 			ndbfree(t);
1713219b2ee8SDavid du Colombier 			return 0;
1714219b2ee8SDavid du Colombier 		}
1715219b2ee8SDavid du Colombier 
1716219b2ee8SDavid du Colombier 		ndbfree(t);
1717219b2ee8SDavid du Colombier 		t = ndbsnext(&s, attr[0], val[0]);
1718219b2ee8SDavid du Colombier 	}
1719219b2ee8SDavid du Colombier 
1720219b2ee8SDavid du Colombier 	return "no match";
1721219b2ee8SDavid du Colombier }
17227dd7cddfSDavid du Colombier 
17237dd7cddfSDavid du Colombier /*
17247dd7cddfSDavid du Colombier  *  resolve an ip address
17257dd7cddfSDavid du Colombier  */
17267dd7cddfSDavid du Colombier static Ndbtuple*
17277dd7cddfSDavid du Colombier ipresolve(char *attr, char *host)
17287dd7cddfSDavid du Colombier {
17297dd7cddfSDavid du Colombier 	Ndbtuple *t, *nt, **l;
17307dd7cddfSDavid du Colombier 
17317dd7cddfSDavid du Colombier 	t = iplookup(&network[Ntcp], host, "*", 0);
17327dd7cddfSDavid du Colombier 	for(l = &t; *l != nil; ){
17337dd7cddfSDavid du Colombier 		nt = *l;
17347dd7cddfSDavid du Colombier 		if(strcmp(nt->attr, "ip") != 0){
17357dd7cddfSDavid du Colombier 			*l = nt->entry;
17367dd7cddfSDavid du Colombier 			nt->entry = nil;
17377dd7cddfSDavid du Colombier 			ndbfree(nt);
17387dd7cddfSDavid du Colombier 			continue;
17397dd7cddfSDavid du Colombier 		}
17407dd7cddfSDavid du Colombier 		strcpy(nt->attr, attr);
17417dd7cddfSDavid du Colombier 		l = &nt->entry;
17427dd7cddfSDavid du Colombier 	}
17437dd7cddfSDavid du Colombier 	return t;
17447dd7cddfSDavid du Colombier }
17457dd7cddfSDavid du Colombier 
17467dd7cddfSDavid du Colombier char*
17477dd7cddfSDavid du Colombier ipinfoquery(Mfile *mf, char **list, int n)
17487dd7cddfSDavid du Colombier {
17497dd7cddfSDavid du Colombier 	int i, nresolve;
17507dd7cddfSDavid du Colombier 	int resolve[Maxattr];
17517dd7cddfSDavid du Colombier 	Ndbtuple *t, *nt, **l;
17527dd7cddfSDavid du Colombier 	char *attr, *val;
17537dd7cddfSDavid du Colombier 
17547dd7cddfSDavid du Colombier 	/* skip 'ipinfo' */
17557dd7cddfSDavid du Colombier 	list++; n--;
17567dd7cddfSDavid du Colombier 
17578a2c5ad0SDavid du Colombier 	if(n < 1)
17587dd7cddfSDavid du Colombier 		return "bad query";
17597dd7cddfSDavid du Colombier 
17608a2c5ad0SDavid du Colombier 	/* get search attribute=value, or assume ip=myipaddr */
17618a2c5ad0SDavid du Colombier 	attr = *list;
17628a2c5ad0SDavid du Colombier 	if((val = strchr(attr, '=')) != nil){
17637dd7cddfSDavid du Colombier 		*val++ = 0;
17648a2c5ad0SDavid du Colombier 		list++;
17658a2c5ad0SDavid du Colombier 		n--;
17668a2c5ad0SDavid du Colombier 	}else{
17678a2c5ad0SDavid du Colombier 		attr = "ip";
17688a2c5ad0SDavid du Colombier 		val = ipaddr;
17698a2c5ad0SDavid du Colombier 	}
17708a2c5ad0SDavid du Colombier 
17718a2c5ad0SDavid du Colombier 	if(n < 1)
17728a2c5ad0SDavid du Colombier 		return "bad query";
17737dd7cddfSDavid du Colombier 
17747dd7cddfSDavid du Colombier 	/*
17757dd7cddfSDavid du Colombier 	 *  don't let ndbipinfo resolve the addresses, we're
17767dd7cddfSDavid du Colombier 	 *  better at it.
17777dd7cddfSDavid du Colombier 	 */
17787dd7cddfSDavid du Colombier 	nresolve = 0;
17797dd7cddfSDavid du Colombier 	for(i = 0; i < n; i++)
17807dd7cddfSDavid du Colombier 		if(*list[i] == '@'){
17817dd7cddfSDavid du Colombier 			list[i]++;
17827dd7cddfSDavid du Colombier 			resolve[i] = 1;
17837dd7cddfSDavid du Colombier 			nresolve++;
17847dd7cddfSDavid du Colombier 		} else
17857dd7cddfSDavid du Colombier 			resolve[i] = 0;
17867dd7cddfSDavid du Colombier 
17877dd7cddfSDavid du Colombier 	t = ndbipinfo(db, attr, val, list, n);
17887dd7cddfSDavid du Colombier 	if(t == nil)
17897dd7cddfSDavid du Colombier 		return "no match";
17907dd7cddfSDavid du Colombier 
17917dd7cddfSDavid du Colombier 	if(nresolve != 0){
17927dd7cddfSDavid du Colombier 		for(l = &t; *l != nil;){
17937dd7cddfSDavid du Colombier 			nt = *l;
17947dd7cddfSDavid du Colombier 
17957dd7cddfSDavid du Colombier 			/* already an address? */
17967dd7cddfSDavid du Colombier 			if(strcmp(ipattr(nt->val), "ip") == 0){
17977dd7cddfSDavid du Colombier 				l = &(*l)->entry;
17987dd7cddfSDavid du Colombier 				continue;
17997dd7cddfSDavid du Colombier 			}
18007dd7cddfSDavid du Colombier 
18017dd7cddfSDavid du Colombier 			/* user wants it resolved? */
18027dd7cddfSDavid du Colombier 			for(i = 0; i < n; i++)
18037dd7cddfSDavid du Colombier 				if(strcmp(list[i], nt->attr) == 0)
18047dd7cddfSDavid du Colombier 					break;
18057dd7cddfSDavid du Colombier 			if(i >= n || resolve[i] == 0){
18067dd7cddfSDavid du Colombier 				l = &(*l)->entry;
18077dd7cddfSDavid du Colombier 				continue;
18087dd7cddfSDavid du Colombier 			}
18097dd7cddfSDavid du Colombier 
18107dd7cddfSDavid du Colombier 			/* resolve address and replace entry */
18117dd7cddfSDavid du Colombier 			*l = ipresolve(nt->attr, nt->val);
18127dd7cddfSDavid du Colombier 			while(*l != nil)
18137dd7cddfSDavid du Colombier 				l = &(*l)->entry;
18147dd7cddfSDavid du Colombier 			*l = nt->entry;
18157dd7cddfSDavid du Colombier 
18167dd7cddfSDavid du Colombier 			nt->entry = nil;
18177dd7cddfSDavid du Colombier 			ndbfree(nt);
18187dd7cddfSDavid du Colombier 		}
18197dd7cddfSDavid du Colombier 	}
18207dd7cddfSDavid du Colombier 
18217dd7cddfSDavid du Colombier 	/* make it all one line */
18227dd7cddfSDavid du Colombier 	for(nt = t; nt != nil; nt = nt->entry){
18237dd7cddfSDavid du Colombier 		if(nt->entry == nil)
18247dd7cddfSDavid du Colombier 			nt->line = t;
18257dd7cddfSDavid du Colombier 		else
18267dd7cddfSDavid du Colombier 			nt->line = nt->entry;
18277dd7cddfSDavid du Colombier 	}
18287dd7cddfSDavid du Colombier 
18297dd7cddfSDavid du Colombier 	qreply(mf, t);
18307dd7cddfSDavid du Colombier 
18317dd7cddfSDavid du Colombier 	return nil;
18327dd7cddfSDavid du Colombier }
18337dd7cddfSDavid du Colombier 
18347dd7cddfSDavid du Colombier void*
18357dd7cddfSDavid du Colombier emalloc(int size)
18367dd7cddfSDavid du Colombier {
18377dd7cddfSDavid du Colombier 	void *x;
18387dd7cddfSDavid du Colombier 
18397dd7cddfSDavid du Colombier 	x = malloc(size);
18407dd7cddfSDavid du Colombier 	if(x == nil)
18417dd7cddfSDavid du Colombier 		abort();
18427dd7cddfSDavid du Colombier 	memset(x, 0, size);
18437dd7cddfSDavid du Colombier 	return x;
18447dd7cddfSDavid du Colombier }
18459a747e4fSDavid du Colombier 
18469a747e4fSDavid du Colombier char*
18479a747e4fSDavid du Colombier estrdup(char *s)
18489a747e4fSDavid du Colombier {
18499a747e4fSDavid du Colombier 	int size;
18509a747e4fSDavid du Colombier 	char *p;
18519a747e4fSDavid du Colombier 
18529a747e4fSDavid du Colombier 	size = strlen(s)+1;
18539a747e4fSDavid du Colombier 	p = malloc(size);
18549a747e4fSDavid du Colombier 	if(p == nil)
18559a747e4fSDavid du Colombier 		abort();
18569a747e4fSDavid du Colombier 	memmove(p, s, size);
18579a747e4fSDavid du Colombier 	return p;
18589a747e4fSDavid du Colombier }
1859