xref: /plan9/sys/src/cmd/ndb/cs.c (revision b7327ca21ed3e4a9e0de5a7574d158a22b9e1024)
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");
983219b2ee8SDavid du Colombier 		if(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 			}
1021*b7327ca2SDavid du Colombier 			for(tt = t; tt != nil; tt = tt->entry){
1022*b7327ca2SDavid du Colombier 				if(strcmp(tt->attr, "sys") == 0){
1023*b7327ca2SDavid du Colombier 					mysysname = strdup(tt->val);
102495a264b3SDavid du Colombier 					break;
102595a264b3SDavid du Colombier 				}
1026*b7327ca2SDavid 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 		 */
121295a264b3SDavid du Colombier syslog(0, logfile, "specific lookup %s", np->net);
121380ee5cbfSDavid du Colombier 		nt = (*np->lookup)(np, mf->host, mf->serv, 1);
121495a264b3SDavid du Colombier syslog(0, logfile, "returned %p", nt);
121580ee5cbfSDavid du Colombier 		for(t = nt; mf->nreply < Nreply && t; t = t->entry){
121680ee5cbfSDavid du Colombier 			cp = (*np->trans)(t, np, mf->serv, mf->rem, 0);
121780ee5cbfSDavid du Colombier 			if(cp){
121880ee5cbfSDavid du Colombier 				mf->replylen[mf->nreply] = strlen(cp);
121980ee5cbfSDavid du Colombier 				mf->reply[mf->nreply++] = cp;
122080ee5cbfSDavid du Colombier 				rv++;
122180ee5cbfSDavid du Colombier 			}
122280ee5cbfSDavid du Colombier 		}
122380ee5cbfSDavid du Colombier 		ndbfree(nt);
122480ee5cbfSDavid du Colombier 		return rv;
12253e12c5d1SDavid du Colombier 	} else {
12263e12c5d1SDavid du Colombier 		/*
1227219b2ee8SDavid du Colombier 		 *  not a known network, don't translate host or service
12283e12c5d1SDavid du Colombier 		 */
122980ee5cbfSDavid du Colombier 		if(mf->serv)
12307dd7cddfSDavid du Colombier 			snprint(reply, sizeof(reply), "%s/%s/clone %s!%s",
123180ee5cbfSDavid du Colombier 				mntpt, mf->net, mf->host, mf->serv);
1232bd389b36SDavid du Colombier 		else
12337dd7cddfSDavid du Colombier 			snprint(reply, sizeof(reply), "%s/%s/clone %s",
123480ee5cbfSDavid du Colombier 				mntpt, mf->net, mf->host);
1235219b2ee8SDavid du Colombier 		mf->reply[0] = strdup(reply);
1236219b2ee8SDavid du Colombier 		mf->replylen[0] = strlen(reply);
1237219b2ee8SDavid du Colombier 		mf->nreply = 1;
123880ee5cbfSDavid du Colombier 		return 1;
12393e12c5d1SDavid du Colombier 	}
12403e12c5d1SDavid du Colombier }
12413e12c5d1SDavid du Colombier 
12423e12c5d1SDavid du Colombier /*
12433e12c5d1SDavid du Colombier  *  translate an ip service name into a port number.  If it's a numeric port
12443e12c5d1SDavid du Colombier  *  number, look for restricted access.
12453e12c5d1SDavid du Colombier  *
12463e12c5d1SDavid du Colombier  *  the service '*' needs no translation.
12473e12c5d1SDavid du Colombier  */
12483e12c5d1SDavid du Colombier char*
124995a264b3SDavid du Colombier ipserv(Network *np, char *name, char *buf, int blen)
12503e12c5d1SDavid du Colombier {
12513e12c5d1SDavid du Colombier 	char *p;
12523e12c5d1SDavid du Colombier 	int alpha = 0;
12533e12c5d1SDavid du Colombier 	int restr = 0;
125495a264b3SDavid du Colombier 	char port[10];
12553e12c5d1SDavid du Colombier 	Ndbtuple *t, *nt;
12563e12c5d1SDavid du Colombier 	Ndbs s;
12573e12c5d1SDavid du Colombier 
12583e12c5d1SDavid du Colombier 	/* '*' means any service */
12593e12c5d1SDavid du Colombier 	if(strcmp(name, "*")==0){
12603e12c5d1SDavid du Colombier 		strcpy(buf, name);
12613e12c5d1SDavid du Colombier 		return buf;
12623e12c5d1SDavid du Colombier 	}
12633e12c5d1SDavid du Colombier 
12643e12c5d1SDavid du Colombier 	/*  see if it's numeric or symbolic */
12653e12c5d1SDavid du Colombier 	port[0] = 0;
12663e12c5d1SDavid du Colombier 	for(p = name; *p; p++){
12673e12c5d1SDavid du Colombier 		if(isdigit(*p))
12689a747e4fSDavid du Colombier 			{}
12693e12c5d1SDavid du Colombier 		else if(isalpha(*p) || *p == '-' || *p == '$')
12703e12c5d1SDavid du Colombier 			alpha = 1;
12713e12c5d1SDavid du Colombier 		else
12723e12c5d1SDavid du Colombier 			return 0;
12733e12c5d1SDavid du Colombier 	}
127457837e0bSDavid du Colombier 	t = nil;
127557837e0bSDavid du Colombier 	p = nil;
12763e12c5d1SDavid du Colombier 	if(alpha){
127757837e0bSDavid du Colombier 		p = ndbgetvalue(db, &s, np->net, name, "port", &t);
1278*b7327ca2SDavid du Colombier 		if(p == nil)
1279*b7327ca2SDavid du Colombier 			return 0;
12803e12c5d1SDavid du Colombier 	} else {
12813cc1eb97SDavid du Colombier 		/* look up only for tcp ports < 1024 to get the restricted
12823cc1eb97SDavid du Colombier 		 * attribute
12833cc1eb97SDavid du Colombier 		 */
12843cc1eb97SDavid du Colombier 		if(atoi(name) < 1024 && strcmp(np->net, "tcp") == 0)
128557837e0bSDavid du Colombier 			p = ndbgetvalue(db, &s, "port", name, "port", &t);
128657837e0bSDavid du Colombier 		if(p == nil)
128757837e0bSDavid du Colombier 			p = strdup(name);
12883e12c5d1SDavid du Colombier 	}
12893e12c5d1SDavid du Colombier 
12903e12c5d1SDavid du Colombier 	if(t){
12913e12c5d1SDavid du Colombier 		for(nt = t; nt; nt = nt->entry)
12923e12c5d1SDavid du Colombier 			if(strcmp(nt->attr, "restricted") == 0)
12933e12c5d1SDavid du Colombier 				restr = 1;
12943e12c5d1SDavid du Colombier 		ndbfree(t);
12953e12c5d1SDavid du Colombier 	}
129657837e0bSDavid du Colombier 	snprint(buf, blen, "%s%s", p, restr ? "!r" : "");
129757837e0bSDavid du Colombier 	free(p);
129857837e0bSDavid du Colombier 
12993e12c5d1SDavid du Colombier 	return buf;
13003e12c5d1SDavid du Colombier }
13013e12c5d1SDavid du Colombier 
13023e12c5d1SDavid du Colombier /*
13037dd7cddfSDavid du Colombier  *  lookup an ip attribute
13043e12c5d1SDavid du Colombier  */
13057dd7cddfSDavid du Colombier int
130695a264b3SDavid du Colombier ipattrlookup(Ndb *db, char *ipa, char *attr, char *val, int vlen)
13073e12c5d1SDavid du Colombier {
13083e12c5d1SDavid du Colombier 
13097dd7cddfSDavid du Colombier 	Ndbtuple *t, *nt;
13107dd7cddfSDavid du Colombier 	char *alist[2];
13113e12c5d1SDavid du Colombier 
13127dd7cddfSDavid du Colombier 	alist[0] = attr;
13137dd7cddfSDavid du Colombier 	t = ndbipinfo(db, "ip", ipa, alist, 1);
13147dd7cddfSDavid du Colombier 	if(t == nil)
13157dd7cddfSDavid du Colombier 		return 0;
13169a747e4fSDavid du Colombier 	for(nt = t; nt != nil; nt = nt->entry){
13177dd7cddfSDavid du Colombier 		if(strcmp(nt->attr, attr) == 0){
131895a264b3SDavid du Colombier 			nstrcpy(val, nt->val, vlen);
13193e12c5d1SDavid du Colombier 			ndbfree(t);
13207dd7cddfSDavid du Colombier 			return 1;
1321219b2ee8SDavid du Colombier 		}
13229a747e4fSDavid du Colombier 	}
13233e12c5d1SDavid du Colombier 
13247dd7cddfSDavid du Colombier 	/* we shouldn't get here */
13253e12c5d1SDavid du Colombier 	ndbfree(t);
13267dd7cddfSDavid du Colombier 	return 0;
13273e12c5d1SDavid du Colombier }
13283e12c5d1SDavid du Colombier 
13293e12c5d1SDavid du Colombier /*
13303e12c5d1SDavid du Colombier  *  lookup (and translate) an ip destination
13313e12c5d1SDavid du Colombier  */
1332219b2ee8SDavid du Colombier Ndbtuple*
1333219b2ee8SDavid du Colombier iplookup(Network *np, char *host, char *serv, int nolookup)
13343e12c5d1SDavid du Colombier {
13353e12c5d1SDavid du Colombier 	char *attr;
13367dd7cddfSDavid du Colombier 	Ndbtuple *t, *nt;
13373e12c5d1SDavid du Colombier 	Ndbs s;
133895a264b3SDavid du Colombier 	char ts[Maxservice];
133995a264b3SDavid du Colombier 	char dollar[Maxhost];
13407dd7cddfSDavid du Colombier 	uchar ip[IPaddrlen];
13417dd7cddfSDavid du Colombier 	uchar net[IPaddrlen];
13427dd7cddfSDavid du Colombier 	uchar tnet[IPaddrlen];
13437dd7cddfSDavid du Colombier 	Ipifc *ifc;
13449a747e4fSDavid du Colombier 	Iplifc *lifc;
13453e12c5d1SDavid du Colombier 
1346219b2ee8SDavid du Colombier 	USED(nolookup);
1347219b2ee8SDavid du Colombier 
13483e12c5d1SDavid du Colombier 	/*
13493e12c5d1SDavid du Colombier 	 *  start with the service since it's the most likely to fail
13503e12c5d1SDavid du Colombier 	 *  and costs the least
13513e12c5d1SDavid du Colombier 	 */
13527dd7cddfSDavid du Colombier 	werrstr("can't translate address");
135395a264b3SDavid du Colombier 	if(serv==0 || ipserv(np, serv, ts, sizeof ts) == 0){
1354271b8d73SDavid du Colombier 		werrstr("can't translate service");
1355219b2ee8SDavid du Colombier 		return 0;
13567dd7cddfSDavid du Colombier 	}
13573e12c5d1SDavid du Colombier 
13583e12c5d1SDavid du Colombier 	/* for dial strings with no host */
1359219b2ee8SDavid du Colombier 	if(strcmp(host, "*") == 0)
136095a264b3SDavid du Colombier 		return ndbnew("ip", "*");
13613e12c5d1SDavid du Colombier 
13623e12c5d1SDavid du Colombier 	/*
13637dd7cddfSDavid du Colombier 	 *  hack till we go v6 :: = 0.0.0.0
13647dd7cddfSDavid du Colombier 	 */
13657dd7cddfSDavid du Colombier 	if(strcmp("::", host) == 0)
136695a264b3SDavid du Colombier 		return ndbnew("ip", "*");
13677dd7cddfSDavid du Colombier 
13687dd7cddfSDavid du Colombier 	/*
13693e12c5d1SDavid du Colombier 	 *  '$' means the rest of the name is an attribute that we
13703e12c5d1SDavid du Colombier 	 *  need to search for
13713e12c5d1SDavid du Colombier 	 */
13723e12c5d1SDavid du Colombier 	if(*host == '$'){
137395a264b3SDavid du Colombier 		if(ipattrlookup(db, ipaddr, host+1, dollar, sizeof dollar))
13743e12c5d1SDavid du Colombier 			host = dollar;
13753e12c5d1SDavid du Colombier 	}
13763e12c5d1SDavid du Colombier 
13773e12c5d1SDavid du Colombier 	/*
13787dd7cddfSDavid du Colombier 	 *  turn '[ip address]' into just 'ip address'
13797dd7cddfSDavid du Colombier 	 */
13807dd7cddfSDavid du Colombier 	if(*host == '[' && host[strlen(host)-1] == ']'){
13817dd7cddfSDavid du Colombier 		host++;
13827dd7cddfSDavid du Colombier 		host[strlen(host)-1] = 0;
13837dd7cddfSDavid du Colombier 	}
13847dd7cddfSDavid du Colombier 
13857dd7cddfSDavid du Colombier 	/*
13863e12c5d1SDavid du Colombier 	 *  just accept addresses
13873e12c5d1SDavid du Colombier 	 */
1388219b2ee8SDavid du Colombier 	attr = ipattr(host);
1389219b2ee8SDavid du Colombier 	if(strcmp(attr, "ip") == 0)
139095a264b3SDavid du Colombier 		return ndbnew("ip", host);
13913e12c5d1SDavid du Colombier 
13923e12c5d1SDavid du Colombier 	/*
13933e12c5d1SDavid du Colombier 	 *  give the domain name server the first opportunity to
1394bd389b36SDavid du Colombier 	 *  resolve domain names.  if that fails try the database.
13953e12c5d1SDavid du Colombier 	 */
13963e12c5d1SDavid du Colombier 	t = 0;
1397271b8d73SDavid du Colombier 	werrstr("can't translate address");
13983e12c5d1SDavid du Colombier 	if(strcmp(attr, "dom") == 0)
13997dd7cddfSDavid du Colombier 		t = dnsiplookup(host, &s);
14003e12c5d1SDavid du Colombier 	if(t == 0)
140157837e0bSDavid du Colombier 		free(ndbgetvalue(db, &s, attr, host, "ip", &t));
14023e12c5d1SDavid du Colombier 	if(t == 0)
14037dd7cddfSDavid du Colombier 		t = dnsiplookup(host, &s);
14047dd7cddfSDavid du Colombier 	if(t == 0)
1405219b2ee8SDavid du Colombier 		return 0;
1406bd389b36SDavid du Colombier 
1407bd389b36SDavid du Colombier 	/*
1408bd389b36SDavid du Colombier 	 *  reorder the tuple to have the matched line first and
1409bd389b36SDavid du Colombier 	 *  save that in the request structure.
1410bd389b36SDavid du Colombier 	 */
14117dd7cddfSDavid du Colombier 	t = reorder(t, s.t);
14127dd7cddfSDavid du Colombier 
14137dd7cddfSDavid du Colombier 	/*
14147dd7cddfSDavid du Colombier 	 * reorder according to our interfaces
14157dd7cddfSDavid du Colombier 	 */
14167dd7cddfSDavid du Colombier 	lock(&ipifclock);
14179a747e4fSDavid du Colombier 	for(ifc = ipifcs; ifc != nil; ifc = ifc->next){
14189a747e4fSDavid du Colombier 		for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
14199a747e4fSDavid du Colombier 			maskip(lifc->ip, lifc->mask, net);
14207dd7cddfSDavid du Colombier 			for(nt = t; nt; nt = nt->entry){
14217dd7cddfSDavid du Colombier 				if(strcmp(nt->attr, "ip") != 0)
14227dd7cddfSDavid du Colombier 					continue;
14237dd7cddfSDavid du Colombier 				parseip(ip, nt->val);
14249a747e4fSDavid du Colombier 				maskip(ip, lifc->mask, tnet);
14257dd7cddfSDavid du Colombier 				if(memcmp(net, tnet, IPaddrlen) == 0){
14267dd7cddfSDavid du Colombier 					t = reorder(t, nt);
14277dd7cddfSDavid du Colombier 					unlock(&ipifclock);
14287dd7cddfSDavid du Colombier 					return t;
14297dd7cddfSDavid du Colombier 				}
14307dd7cddfSDavid du Colombier 			}
14317dd7cddfSDavid du Colombier 		}
14329a747e4fSDavid du Colombier 	}
14337dd7cddfSDavid du Colombier 	unlock(&ipifclock);
14347dd7cddfSDavid du Colombier 
14357dd7cddfSDavid du Colombier 	return t;
14363e12c5d1SDavid du Colombier }
14373e12c5d1SDavid du Colombier 
14383e12c5d1SDavid du Colombier /*
14393e12c5d1SDavid du Colombier  *  translate an ip address
14403e12c5d1SDavid du Colombier  */
1441219b2ee8SDavid du Colombier char*
144280ee5cbfSDavid du Colombier iptrans(Ndbtuple *t, Network *np, char *serv, char *rem, int hack)
14433e12c5d1SDavid du Colombier {
144495a264b3SDavid du Colombier 	char ts[Maxservice];
1445219b2ee8SDavid du Colombier 	char reply[Maxreply];
144695a264b3SDavid du Colombier 	char x[Maxservice];
14473e12c5d1SDavid du Colombier 
1448219b2ee8SDavid du Colombier 	if(strcmp(t->attr, "ip") != 0)
14493e12c5d1SDavid du Colombier 		return 0;
1450219b2ee8SDavid du Colombier 
145195a264b3SDavid du Colombier 	if(serv == 0 || ipserv(np, serv, ts, sizeof ts) == 0){
1452271b8d73SDavid du Colombier 		werrstr("can't translate service");
1453219b2ee8SDavid du Colombier 		return 0;
1454271b8d73SDavid du Colombier 	}
14557dd7cddfSDavid du Colombier 	if(rem != nil)
14567dd7cddfSDavid du Colombier 		snprint(x, sizeof(x), "!%s", rem);
14577dd7cddfSDavid du Colombier 	else
14587dd7cddfSDavid du Colombier 		*x = 0;
145980ee5cbfSDavid du Colombier 
1460219b2ee8SDavid du Colombier 	if(*t->val == '*')
14617dd7cddfSDavid du Colombier 		snprint(reply, sizeof(reply), "%s/%s/clone %s%s",
14627dd7cddfSDavid du Colombier 			mntpt, np->net, ts, x);
1463219b2ee8SDavid du Colombier 	else
146480ee5cbfSDavid du Colombier 		snprint(reply, sizeof(reply), "%s/%s/clone %s!%s%s%s",
146580ee5cbfSDavid du Colombier 			mntpt, np->net, t->val, ts, x, hack?"!fasttimeout":"");
1466219b2ee8SDavid du Colombier 
1467219b2ee8SDavid du Colombier 	return strdup(reply);
14683e12c5d1SDavid du Colombier }
14693e12c5d1SDavid du Colombier 
1470219b2ee8SDavid du Colombier /*
1471219b2ee8SDavid du Colombier  *  lookup a telephone number
1472219b2ee8SDavid du Colombier  */
1473219b2ee8SDavid du Colombier Ndbtuple*
1474219b2ee8SDavid du Colombier telcolookup(Network *np, char *host, char *serv, int nolookup)
1475219b2ee8SDavid du Colombier {
1476219b2ee8SDavid du Colombier 	Ndbtuple *t;
1477219b2ee8SDavid du Colombier 	Ndbs s;
1478219b2ee8SDavid du Colombier 
1479219b2ee8SDavid du Colombier 	USED(np, nolookup, serv);
1480219b2ee8SDavid du Colombier 
1481271b8d73SDavid du Colombier 	werrstr("can't translate address");
148257837e0bSDavid du Colombier 	free(ndbgetvalue(db, &s, "sys", host, "telco", &t));
1483219b2ee8SDavid du Colombier 	if(t == 0)
148495a264b3SDavid du Colombier 		return ndbnew("telco", host);
1485219b2ee8SDavid du Colombier 
1486219b2ee8SDavid du Colombier 	return reorder(t, s.t);
1487219b2ee8SDavid du Colombier }
1488219b2ee8SDavid du Colombier 
1489219b2ee8SDavid du Colombier /*
1490219b2ee8SDavid du Colombier  *  translate a telephone address
1491219b2ee8SDavid du Colombier  */
1492219b2ee8SDavid du Colombier char*
149380ee5cbfSDavid du Colombier telcotrans(Ndbtuple *t, Network *np, char *serv, char *rem, int)
1494219b2ee8SDavid du Colombier {
1495219b2ee8SDavid du Colombier 	char reply[Maxreply];
149695a264b3SDavid du Colombier 	char x[Maxservice];
1497219b2ee8SDavid du Colombier 
1498219b2ee8SDavid du Colombier 	if(strcmp(t->attr, "telco") != 0)
1499219b2ee8SDavid du Colombier 		return 0;
1500219b2ee8SDavid du Colombier 
15017dd7cddfSDavid du Colombier 	if(rem != nil)
15027dd7cddfSDavid du Colombier 		snprint(x, sizeof(x), "!%s", rem);
1503219b2ee8SDavid du Colombier 	else
15047dd7cddfSDavid du Colombier 		*x = 0;
15057dd7cddfSDavid du Colombier 	if(serv)
15067dd7cddfSDavid du Colombier 		snprint(reply, sizeof(reply), "%s/%s/clone %s!%s%s", mntpt, np->net,
15077dd7cddfSDavid du Colombier 			t->val, serv, x);
15087dd7cddfSDavid du Colombier 	else
15097dd7cddfSDavid du Colombier 		snprint(reply, sizeof(reply), "%s/%s/clone %s%s", mntpt, np->net,
15107dd7cddfSDavid du Colombier 			t->val, x);
1511219b2ee8SDavid du Colombier 	return strdup(reply);
1512219b2ee8SDavid du Colombier }
15133e12c5d1SDavid du Colombier 
15143e12c5d1SDavid du Colombier /*
15153e12c5d1SDavid du Colombier  *  reorder the tuple to put x's line first in the entry
15163e12c5d1SDavid du Colombier  */
15173e12c5d1SDavid du Colombier Ndbtuple*
15183e12c5d1SDavid du Colombier reorder(Ndbtuple *t, Ndbtuple *x)
15193e12c5d1SDavid du Colombier {
15203e12c5d1SDavid du Colombier 	Ndbtuple *nt;
15213e12c5d1SDavid du Colombier 	Ndbtuple *line;
15223e12c5d1SDavid du Colombier 
1523219b2ee8SDavid du Colombier 	/* find start of this entry's line */
1524219b2ee8SDavid du Colombier 	for(line = x; line->entry == line->line; line = line->line)
15253e12c5d1SDavid du Colombier 		;
1526219b2ee8SDavid du Colombier 	line = line->line;
1527219b2ee8SDavid du Colombier 	if(line == t)
1528219b2ee8SDavid du Colombier 		return t;	/* already the first line */
15293e12c5d1SDavid du Colombier 
1530219b2ee8SDavid du Colombier 	/* remove this line and everything after it from the entry */
1531219b2ee8SDavid du Colombier 	for(nt = t; nt->entry != line; nt = nt->entry)
1532219b2ee8SDavid du Colombier 		;
1533219b2ee8SDavid du Colombier 	nt->entry = 0;
15343e12c5d1SDavid du Colombier 
1535219b2ee8SDavid du Colombier 	/* make that the start of the entry */
1536219b2ee8SDavid du Colombier 	for(nt = line; nt->entry; nt = nt->entry)
1537219b2ee8SDavid du Colombier 		;
15383e12c5d1SDavid du Colombier 	nt->entry = t;
15393e12c5d1SDavid du Colombier 	return line;
15403e12c5d1SDavid du Colombier }
15413e12c5d1SDavid du Colombier 
15423e12c5d1SDavid du Colombier /*
15433e12c5d1SDavid du Colombier  *  create a slave process to handle a request to avoid one request blocking
15447dd7cddfSDavid du Colombier  *  another.  parent returns to job loop.
15453e12c5d1SDavid du Colombier  */
15463e12c5d1SDavid du Colombier void
15473e12c5d1SDavid du Colombier slave(void)
15483e12c5d1SDavid du Colombier {
15493e12c5d1SDavid du Colombier 	if(*isslave)
15503e12c5d1SDavid du Colombier 		return;		/* we're already a slave process */
15513e12c5d1SDavid du Colombier 
15523e12c5d1SDavid du Colombier 	switch(rfork(RFPROC|RFNOTEG|RFMEM|RFNOWAIT)){
15533e12c5d1SDavid du Colombier 	case -1:
15543e12c5d1SDavid du Colombier 		break;
15553e12c5d1SDavid du Colombier 	case 0:
1556219b2ee8SDavid du Colombier 		if(debug)
1557219b2ee8SDavid du Colombier 			syslog(0, logfile, "slave %d", getpid());
15583e12c5d1SDavid du Colombier 		*isslave = 1;
15593e12c5d1SDavid du Colombier 		break;
15603e12c5d1SDavid du Colombier 	default:
15613e12c5d1SDavid du Colombier 		longjmp(masterjmp, 1);
15623e12c5d1SDavid du Colombier 	}
15633e12c5d1SDavid du Colombier 
1564219b2ee8SDavid du Colombier }
1565219b2ee8SDavid du Colombier 
15663e12c5d1SDavid du Colombier /*
15673e12c5d1SDavid du Colombier  *  call the dns process and have it try to translate a name
15683e12c5d1SDavid du Colombier  */
15693e12c5d1SDavid du Colombier Ndbtuple*
15707dd7cddfSDavid du Colombier dnsiplookup(char *host, Ndbs *s)
15713e12c5d1SDavid du Colombier {
157295a264b3SDavid du Colombier 	char buf[Maxreply];
15737dd7cddfSDavid du Colombier 	Ndbtuple *t;
15743e12c5d1SDavid du Colombier 
1575bd389b36SDavid du Colombier 	unlock(&dblock);
1576bd389b36SDavid du Colombier 
15773e12c5d1SDavid du Colombier 	/* save the name before starting a slave */
15787dd7cddfSDavid du Colombier 	snprint(buf, sizeof(buf), "%s", host);
15793e12c5d1SDavid du Colombier 
15803e12c5d1SDavid du Colombier 	slave();
15813e12c5d1SDavid du Colombier 
15827dd7cddfSDavid du Colombier 	if(strcmp(ipattr(buf), "ip") == 0)
15837dd7cddfSDavid du Colombier 		t = dnsquery(mntpt, buf, "ptr");
15847dd7cddfSDavid du Colombier 	else
15857dd7cddfSDavid du Colombier 		t = dnsquery(mntpt, buf, "ip");
15863e12c5d1SDavid du Colombier 	s->t = t;
15877dd7cddfSDavid du Colombier 
1588271b8d73SDavid du Colombier 	if(t == nil){
1589271b8d73SDavid du Colombier 		rerrstr(buf, sizeof buf);
1590271b8d73SDavid du Colombier 		if(strstr(buf, "exist"))
1591271b8d73SDavid du Colombier 			werrstr("can't translate address: %s", buf);
1592271b8d73SDavid du Colombier 		else if(strstr(buf, "dns failure"))
1593271b8d73SDavid du Colombier 			werrstr("temporary problem: %s", buf);
1594271b8d73SDavid du Colombier 	}
1595271b8d73SDavid du Colombier 
1596bd389b36SDavid du Colombier 	lock(&dblock);
15973e12c5d1SDavid du Colombier 	return t;
15983e12c5d1SDavid du Colombier }
1599219b2ee8SDavid du Colombier 
1600219b2ee8SDavid du Colombier int
1601219b2ee8SDavid du Colombier qmatch(Ndbtuple *t, char **attr, char **val, int n)
1602219b2ee8SDavid du Colombier {
1603219b2ee8SDavid du Colombier 	int i, found;
1604219b2ee8SDavid du Colombier 	Ndbtuple *nt;
1605219b2ee8SDavid du Colombier 
1606219b2ee8SDavid du Colombier 	for(i = 1; i < n; i++){
1607219b2ee8SDavid du Colombier 		found = 0;
1608219b2ee8SDavid du Colombier 		for(nt = t; nt; nt = nt->entry)
1609219b2ee8SDavid du Colombier 			if(strcmp(attr[i], nt->attr) == 0)
1610219b2ee8SDavid du Colombier 				if(strcmp(val[i], "*") == 0
1611219b2ee8SDavid du Colombier 				|| strcmp(val[i], nt->val) == 0){
1612219b2ee8SDavid du Colombier 					found = 1;
1613219b2ee8SDavid du Colombier 					break;
1614219b2ee8SDavid du Colombier 				}
1615219b2ee8SDavid du Colombier 		if(found == 0)
1616219b2ee8SDavid du Colombier 			break;
1617219b2ee8SDavid du Colombier 	}
1618219b2ee8SDavid du Colombier 	return i == n;
1619219b2ee8SDavid du Colombier }
1620219b2ee8SDavid du Colombier 
1621219b2ee8SDavid du Colombier void
1622219b2ee8SDavid du Colombier qreply(Mfile *mf, Ndbtuple *t)
1623219b2ee8SDavid du Colombier {
1624219b2ee8SDavid du Colombier 	Ndbtuple *nt;
162595a264b3SDavid du Colombier 	String *s;
1626219b2ee8SDavid du Colombier 
162795a264b3SDavid du Colombier 	s = s_new();
1628219b2ee8SDavid du Colombier 	for(nt = t; mf->nreply < Nreply && nt; nt = nt->entry){
162995a264b3SDavid du Colombier 		s_append(s, nt->attr);
163095a264b3SDavid du Colombier 		s_append(s, "=");
163195a264b3SDavid du Colombier 		s_append(s, nt->val);
163295a264b3SDavid du Colombier 
163395a264b3SDavid du Colombier 		if(nt->line != nt->entry){
163495a264b3SDavid du Colombier 			mf->replylen[mf->nreply] = s_len(s);
163595a264b3SDavid du Colombier 			mf->reply[mf->nreply++] = strdup(s_to_c(s));
163695a264b3SDavid du Colombier 			s_restart(s);
1637219b2ee8SDavid du Colombier 		} else
163895a264b3SDavid du Colombier 			s_append(s, " ");
1639219b2ee8SDavid du Colombier 	}
164095a264b3SDavid du Colombier 	s_free(s);
1641219b2ee8SDavid du Colombier }
1642219b2ee8SDavid du Colombier 
16437dd7cddfSDavid du Colombier enum
16447dd7cddfSDavid du Colombier {
16457dd7cddfSDavid du Colombier 	Maxattr=	32,
16467dd7cddfSDavid du Colombier };
16477dd7cddfSDavid du Colombier 
1648219b2ee8SDavid du Colombier /*
16497dd7cddfSDavid du Colombier  *  generic query lookup.  The query is of one of the following
16507dd7cddfSDavid du Colombier  *  forms:
16517dd7cddfSDavid du Colombier  *
16527dd7cddfSDavid du Colombier  *  attr1=val1 attr2=val2 attr3=val3 ...
16537dd7cddfSDavid du Colombier  *
16547dd7cddfSDavid du Colombier  *  returns the matching tuple
16557dd7cddfSDavid du Colombier  *
16567dd7cddfSDavid du Colombier  *  ipinfo attr=val attr1 attr2 attr3 ...
16577dd7cddfSDavid du Colombier  *
16587dd7cddfSDavid du Colombier  *  is like ipinfo and returns the attr{1-n}
16597dd7cddfSDavid du Colombier  *  associated with the ip address.
1660219b2ee8SDavid du Colombier  */
1661219b2ee8SDavid du Colombier char*
1662219b2ee8SDavid du Colombier genquery(Mfile *mf, char *query)
1663219b2ee8SDavid du Colombier {
1664219b2ee8SDavid du Colombier 	int i, n;
1665219b2ee8SDavid du Colombier 	char *p;
16667dd7cddfSDavid du Colombier 	char *attr[Maxattr];
16677dd7cddfSDavid du Colombier 	char *val[Maxattr];
1668219b2ee8SDavid du Colombier 	Ndbtuple *t;
1669219b2ee8SDavid du Colombier 	Ndbs s;
1670219b2ee8SDavid du Colombier 
16717dd7cddfSDavid du Colombier 	n = getfields(query, attr, 32, 1, " ");
1672219b2ee8SDavid du Colombier 	if(n == 0)
1673219b2ee8SDavid du Colombier 		return "bad query";
1674219b2ee8SDavid du Colombier 
16757dd7cddfSDavid du Colombier 	if(strcmp(attr[0], "ipinfo") == 0)
16767dd7cddfSDavid du Colombier 		return ipinfoquery(mf, attr, n);
16777dd7cddfSDavid du Colombier 
1678219b2ee8SDavid du Colombier 	/* parse pairs */
1679219b2ee8SDavid du Colombier 	for(i = 0; i < n; i++){
1680219b2ee8SDavid du Colombier 		p = strchr(attr[i], '=');
1681219b2ee8SDavid du Colombier 		if(p == 0)
1682219b2ee8SDavid du Colombier 			return "bad query";
1683219b2ee8SDavid du Colombier 		*p++ = 0;
1684219b2ee8SDavid du Colombier 		val[i] = p;
1685219b2ee8SDavid du Colombier 	}
1686219b2ee8SDavid du Colombier 
1687219b2ee8SDavid du Colombier 	/* give dns a chance */
1688219b2ee8SDavid du Colombier 	if((strcmp(attr[0], "dom") == 0 || strcmp(attr[0], "ip") == 0) && val[0]){
16897dd7cddfSDavid du Colombier 		t = dnsiplookup(val[0], &s);
1690219b2ee8SDavid du Colombier 		if(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 			ndbfree(t);
1697219b2ee8SDavid du Colombier 		}
1698219b2ee8SDavid du Colombier 	}
1699219b2ee8SDavid du Colombier 
1700219b2ee8SDavid du Colombier 	/* first pair is always the key.  It can't be a '*' */
1701219b2ee8SDavid du Colombier 	t = ndbsearch(db, &s, attr[0], val[0]);
1702219b2ee8SDavid du Colombier 
1703219b2ee8SDavid du Colombier 	/* search is the and of all the pairs */
1704219b2ee8SDavid du Colombier 	while(t){
1705219b2ee8SDavid du Colombier 		if(qmatch(t, attr, val, n)){
1706219b2ee8SDavid du Colombier 			qreply(mf, t);
1707219b2ee8SDavid du Colombier 			ndbfree(t);
1708219b2ee8SDavid du Colombier 			return 0;
1709219b2ee8SDavid du Colombier 		}
1710219b2ee8SDavid du Colombier 
1711219b2ee8SDavid du Colombier 		ndbfree(t);
1712219b2ee8SDavid du Colombier 		t = ndbsnext(&s, attr[0], val[0]);
1713219b2ee8SDavid du Colombier 	}
1714219b2ee8SDavid du Colombier 
1715219b2ee8SDavid du Colombier 	return "no match";
1716219b2ee8SDavid du Colombier }
17177dd7cddfSDavid du Colombier 
17187dd7cddfSDavid du Colombier /*
17197dd7cddfSDavid du Colombier  *  resolve an ip address
17207dd7cddfSDavid du Colombier  */
17217dd7cddfSDavid du Colombier static Ndbtuple*
17227dd7cddfSDavid du Colombier ipresolve(char *attr, char *host)
17237dd7cddfSDavid du Colombier {
17247dd7cddfSDavid du Colombier 	Ndbtuple *t, *nt, **l;
17257dd7cddfSDavid du Colombier 
17267dd7cddfSDavid du Colombier 	t = iplookup(&network[Ntcp], host, "*", 0);
17277dd7cddfSDavid du Colombier 	for(l = &t; *l != nil; ){
17287dd7cddfSDavid du Colombier 		nt = *l;
17297dd7cddfSDavid du Colombier 		if(strcmp(nt->attr, "ip") != 0){
17307dd7cddfSDavid du Colombier 			*l = nt->entry;
17317dd7cddfSDavid du Colombier 			nt->entry = nil;
17327dd7cddfSDavid du Colombier 			ndbfree(nt);
17337dd7cddfSDavid du Colombier 			continue;
17347dd7cddfSDavid du Colombier 		}
17357dd7cddfSDavid du Colombier 		strcpy(nt->attr, attr);
17367dd7cddfSDavid du Colombier 		l = &nt->entry;
17377dd7cddfSDavid du Colombier 	}
17387dd7cddfSDavid du Colombier 	return t;
17397dd7cddfSDavid du Colombier }
17407dd7cddfSDavid du Colombier 
17417dd7cddfSDavid du Colombier char*
17427dd7cddfSDavid du Colombier ipinfoquery(Mfile *mf, char **list, int n)
17437dd7cddfSDavid du Colombier {
17447dd7cddfSDavid du Colombier 	int i, nresolve;
17457dd7cddfSDavid du Colombier 	int resolve[Maxattr];
17467dd7cddfSDavid du Colombier 	Ndbtuple *t, *nt, **l;
17477dd7cddfSDavid du Colombier 	char *attr, *val;
17487dd7cddfSDavid du Colombier 
17497dd7cddfSDavid du Colombier 	/* skip 'ipinfo' */
17507dd7cddfSDavid du Colombier 	list++; n--;
17517dd7cddfSDavid du Colombier 
17527dd7cddfSDavid du Colombier 	if(n < 2)
17537dd7cddfSDavid du Colombier 		return "bad query";
17547dd7cddfSDavid du Colombier 
17557dd7cddfSDavid du Colombier 	/* get search attribute=value */
17567dd7cddfSDavid du Colombier 	attr = *list++; n--;
17577dd7cddfSDavid du Colombier 	val = strchr(attr, '=');
17587dd7cddfSDavid du Colombier 	if(val == nil)
17597dd7cddfSDavid du Colombier 		return "bad query";
17607dd7cddfSDavid du Colombier 	*val++ = 0;
17617dd7cddfSDavid du Colombier 
17627dd7cddfSDavid du Colombier 	/*
17637dd7cddfSDavid du Colombier 	 *  don't let ndbipinfo resolve the addresses, we're
17647dd7cddfSDavid du Colombier 	 *  better at it.
17657dd7cddfSDavid du Colombier 	 */
17667dd7cddfSDavid du Colombier 	nresolve = 0;
17677dd7cddfSDavid du Colombier 	for(i = 0; i < n; i++)
17687dd7cddfSDavid du Colombier 		if(*list[i] == '@'){
17697dd7cddfSDavid du Colombier 			list[i]++;
17707dd7cddfSDavid du Colombier 			resolve[i] = 1;
17717dd7cddfSDavid du Colombier 			nresolve++;
17727dd7cddfSDavid du Colombier 		} else
17737dd7cddfSDavid du Colombier 			resolve[i] = 0;
17747dd7cddfSDavid du Colombier 
17757dd7cddfSDavid du Colombier 	t = ndbipinfo(db, attr, val, list, n);
17767dd7cddfSDavid du Colombier 	if(t == nil)
17777dd7cddfSDavid du Colombier 		return "no match";
17787dd7cddfSDavid du Colombier 
17797dd7cddfSDavid du Colombier 	if(nresolve != 0){
17807dd7cddfSDavid du Colombier 		for(l = &t; *l != nil;){
17817dd7cddfSDavid du Colombier 			nt = *l;
17827dd7cddfSDavid du Colombier 
17837dd7cddfSDavid du Colombier 			/* already an address? */
17847dd7cddfSDavid du Colombier 			if(strcmp(ipattr(nt->val), "ip") == 0){
17857dd7cddfSDavid du Colombier 				l = &(*l)->entry;
17867dd7cddfSDavid du Colombier 				continue;
17877dd7cddfSDavid du Colombier 			}
17887dd7cddfSDavid du Colombier 
17897dd7cddfSDavid du Colombier 			/* user wants it resolved? */
17907dd7cddfSDavid du Colombier 			for(i = 0; i < n; i++)
17917dd7cddfSDavid du Colombier 				if(strcmp(list[i], nt->attr) == 0)
17927dd7cddfSDavid du Colombier 					break;
17937dd7cddfSDavid du Colombier 			if(i >= n || resolve[i] == 0){
17947dd7cddfSDavid du Colombier 				l = &(*l)->entry;
17957dd7cddfSDavid du Colombier 				continue;
17967dd7cddfSDavid du Colombier 			}
17977dd7cddfSDavid du Colombier 
17987dd7cddfSDavid du Colombier 			/* resolve address and replace entry */
17997dd7cddfSDavid du Colombier 			*l = ipresolve(nt->attr, nt->val);
18007dd7cddfSDavid du Colombier 			while(*l != nil)
18017dd7cddfSDavid du Colombier 				l = &(*l)->entry;
18027dd7cddfSDavid du Colombier 			*l = nt->entry;
18037dd7cddfSDavid du Colombier 
18047dd7cddfSDavid du Colombier 			nt->entry = nil;
18057dd7cddfSDavid du Colombier 			ndbfree(nt);
18067dd7cddfSDavid du Colombier 		}
18077dd7cddfSDavid du Colombier 	}
18087dd7cddfSDavid du Colombier 
18097dd7cddfSDavid du Colombier 	/* make it all one line */
18107dd7cddfSDavid du Colombier 	for(nt = t; nt != nil; nt = nt->entry){
18117dd7cddfSDavid du Colombier 		if(nt->entry == nil)
18127dd7cddfSDavid du Colombier 			nt->line = t;
18137dd7cddfSDavid du Colombier 		else
18147dd7cddfSDavid du Colombier 			nt->line = nt->entry;
18157dd7cddfSDavid du Colombier 	}
18167dd7cddfSDavid du Colombier 
18177dd7cddfSDavid du Colombier 	qreply(mf, t);
18187dd7cddfSDavid du Colombier 
18197dd7cddfSDavid du Colombier 	return nil;
18207dd7cddfSDavid du Colombier }
18217dd7cddfSDavid du Colombier 
18227dd7cddfSDavid du Colombier void*
18237dd7cddfSDavid du Colombier emalloc(int size)
18247dd7cddfSDavid du Colombier {
18257dd7cddfSDavid du Colombier 	void *x;
18267dd7cddfSDavid du Colombier 
18277dd7cddfSDavid du Colombier 	x = malloc(size);
18287dd7cddfSDavid du Colombier 	if(x == nil)
18297dd7cddfSDavid du Colombier 		abort();
18307dd7cddfSDavid du Colombier 	memset(x, 0, size);
18317dd7cddfSDavid du Colombier 	return x;
18327dd7cddfSDavid du Colombier }
18339a747e4fSDavid du Colombier 
18349a747e4fSDavid du Colombier char*
18359a747e4fSDavid du Colombier estrdup(char *s)
18369a747e4fSDavid du Colombier {
18379a747e4fSDavid du Colombier 	int size;
18389a747e4fSDavid du Colombier 	char *p;
18399a747e4fSDavid du Colombier 
18409a747e4fSDavid du Colombier 	size = strlen(s)+1;
18419a747e4fSDavid du Colombier 	p = malloc(size);
18429a747e4fSDavid du Colombier 	if(p == nil)
18439a747e4fSDavid du Colombier 		abort();
18449a747e4fSDavid du Colombier 	memmove(p, s, size);
18459a747e4fSDavid du Colombier 	return p;
18469a747e4fSDavid du Colombier }
1847