xref: /plan9-contrib/sys/src/cmd/ndb/cs.c (revision 244672c51f7f79a5fb2ba7d2d6432ecba76aaa8a)
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 
65*244672c5SDavid du Colombier /*
66*244672c5SDavid du Colombier  *  active requests
67*244672c5SDavid 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 	Ntcp,
154*244672c5SDavid du Colombier //	Nilfast,
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 /*
164*244672c5SDavid du Colombier  *  net doesn't apply to (r)udp, icmp(v6), or telco (for speed).
165*244672c5SDavid du Colombier  *  there should be no gaps in this table, as a zero entry terminates
166*244672c5SDavid du Colombier  *  the "net!" search.
16780ee5cbfSDavid du Colombier  */
16880ee5cbfSDavid du Colombier Network network[] = {
16980ee5cbfSDavid du Colombier [Ntcp]		{ "tcp",	iplookup,	iptrans,	0, 0 },
170*244672c5SDavid du Colombier // [Nilfast]	{ "il",		iplookup,	iptrans,	0, 1 },
17180ee5cbfSDavid du Colombier [Nil]		{ "il",		iplookup,	iptrans,	0, 0 },
17280ee5cbfSDavid du Colombier [Nudp]		{ "udp",	iplookup,	iptrans,	1, 0 },
17380ee5cbfSDavid du Colombier [Nicmp]		{ "icmp",	iplookup,	iptrans,	1, 0 },
17495a264b3SDavid du Colombier [Nicmpv6]	{ "icmpv6",	iplookup,	iptrans,	1, 0 },
17580ee5cbfSDavid du Colombier [Nrudp]		{ "rudp",	iplookup,	iptrans,	1, 0 },
17680ee5cbfSDavid du Colombier [Ntelco]	{ "telco",	telcolookup,	telcotrans,	1, 0 },
17780ee5cbfSDavid du Colombier 		{ 0 },
17880ee5cbfSDavid du Colombier };
17980ee5cbfSDavid du Colombier 
18080ee5cbfSDavid du Colombier Lock ipifclock;
18180ee5cbfSDavid du Colombier Ipifc *ipifcs;
18280ee5cbfSDavid du Colombier 
18395a264b3SDavid du Colombier char	eaddr[16];		/* ascii ethernet address */
18495a264b3SDavid du Colombier char	ipaddr[64];		/* ascii internet address */
18580ee5cbfSDavid du Colombier uchar	ipa[IPaddrlen];		/* binary internet address */
18695a264b3SDavid du Colombier char	*mysysname;
18780ee5cbfSDavid du Colombier 
18880ee5cbfSDavid du Colombier Network *netlist;		/* networks ordered by preference */
18980ee5cbfSDavid du Colombier Network *last;
19080ee5cbfSDavid du Colombier 
19195a264b3SDavid du Colombier static void
19295a264b3SDavid du Colombier nstrcpy(char *to, char *from, int len)
19395a264b3SDavid du Colombier {
19495a264b3SDavid du Colombier 	strncpy(to, from, len);
19595a264b3SDavid du Colombier 	to[len-1] = 0;
19695a264b3SDavid du Colombier }
19795a264b3SDavid du Colombier 
1987dd7cddfSDavid du Colombier void
1997dd7cddfSDavid du Colombier usage(void)
2007dd7cddfSDavid du Colombier {
2017dd7cddfSDavid du Colombier 	fprint(2, "usage: %s [-d] [-f ndb-file] [-x netmtpt] [-n]\n", argv0);
2027dd7cddfSDavid du Colombier 	exits("usage");
2037dd7cddfSDavid du Colombier }
204219b2ee8SDavid du Colombier 
2053e12c5d1SDavid du Colombier void
2063e12c5d1SDavid du Colombier main(int argc, char *argv[])
2073e12c5d1SDavid du Colombier {
2087dd7cddfSDavid du Colombier 	char servefile[Maxpath];
209219b2ee8SDavid du Colombier 	int justsetname;
2107dd7cddfSDavid du Colombier 	char *p;
2117dd7cddfSDavid du Colombier 	char ext[Maxpath];
2123e12c5d1SDavid du Colombier 
213219b2ee8SDavid du Colombier 	justsetname = 0;
2147dd7cddfSDavid du Colombier 	setnetmtpt(mntpt, sizeof(mntpt), nil);
2157dd7cddfSDavid du Colombier 	ext[0] = 0;
2163e12c5d1SDavid du Colombier 	ARGBEGIN{
2173e12c5d1SDavid du Colombier 	case 'd':
2183e12c5d1SDavid du Colombier 		debug = 1;
2193e12c5d1SDavid du Colombier 		break;
220bd389b36SDavid du Colombier 	case 'f':
2217dd7cddfSDavid du Colombier 		p = ARGF();
2227dd7cddfSDavid du Colombier 		if(p == nil)
2237dd7cddfSDavid du Colombier 			usage();
2247dd7cddfSDavid du Colombier 		dbfile = p;
2257dd7cddfSDavid du Colombier 		break;
2267dd7cddfSDavid du Colombier 	case 'x':
2277dd7cddfSDavid du Colombier 		p = ARGF();
2287dd7cddfSDavid du Colombier 		if(p == nil)
2297dd7cddfSDavid du Colombier 			usage();
2307dd7cddfSDavid du Colombier 		setnetmtpt(mntpt, sizeof(mntpt), p);
2317dd7cddfSDavid du Colombier 		setext(ext, sizeof(ext), mntpt);
232bd389b36SDavid du Colombier 		break;
233219b2ee8SDavid du Colombier 	case 'n':
234219b2ee8SDavid du Colombier 		justsetname = 1;
235219b2ee8SDavid du Colombier 		break;
2363e12c5d1SDavid du Colombier 	}ARGEND
2373e12c5d1SDavid du Colombier 	USED(argc);
2383e12c5d1SDavid du Colombier 	USED(argv);
2393e12c5d1SDavid du Colombier 
2407dd7cddfSDavid du Colombier 	rfork(RFREND|RFNOTEG);
2417dd7cddfSDavid du Colombier 
2427dd7cddfSDavid du Colombier 	snprint(servefile, sizeof(servefile), "#s/cs%s", ext);
2437dd7cddfSDavid du Colombier 	snprint(netndb, sizeof(netndb), "%s/ndb", mntpt);
2447dd7cddfSDavid du Colombier 	unmount(servefile, mntpt);
2457dd7cddfSDavid du Colombier 	remove(servefile);
2467dd7cddfSDavid du Colombier 
2479a747e4fSDavid du Colombier 	fmtinstall('E', eipfmt);
2489a747e4fSDavid du Colombier 	fmtinstall('I', eipfmt);
2499a747e4fSDavid du Colombier 	fmtinstall('M', eipfmt);
2509a747e4fSDavid du Colombier 	fmtinstall('F', fcallfmt);
2517dd7cddfSDavid du Colombier 
2527dd7cddfSDavid du Colombier 	ndbinit();
2537dd7cddfSDavid du Colombier 	netinit(0);
2547dd7cddfSDavid du Colombier 
2557dd7cddfSDavid du Colombier 	if(!justsetname){
2567dd7cddfSDavid du Colombier 		mountinit(servefile, mntpt);
2577dd7cddfSDavid du Colombier 		io();
2587dd7cddfSDavid du Colombier 	}
259219b2ee8SDavid du Colombier 	exits(0);
260219b2ee8SDavid du Colombier }
261219b2ee8SDavid du Colombier 
2627dd7cddfSDavid du Colombier /*
2637dd7cddfSDavid du Colombier  *  if a mount point is specified, set the cs extention to be the mount point
2647dd7cddfSDavid du Colombier  *  with '_'s replacing '/'s
2657dd7cddfSDavid du Colombier  */
2667dd7cddfSDavid du Colombier void
2677dd7cddfSDavid du Colombier setext(char *ext, int n, char *p)
2687dd7cddfSDavid du Colombier {
2697dd7cddfSDavid du Colombier 	int i, c;
2703e12c5d1SDavid du Colombier 
2717dd7cddfSDavid du Colombier 	n--;
2727dd7cddfSDavid du Colombier 	for(i = 0; i < n; i++){
2737dd7cddfSDavid du Colombier 		c = p[i];
2747dd7cddfSDavid du Colombier 		if(c == 0)
2757dd7cddfSDavid du Colombier 			break;
2767dd7cddfSDavid du Colombier 		if(c == '/')
2777dd7cddfSDavid du Colombier 			c = '_';
2787dd7cddfSDavid du Colombier 		ext[i] = c;
2797dd7cddfSDavid du Colombier 	}
2807dd7cddfSDavid du Colombier 	ext[i] = 0;
2813e12c5d1SDavid du Colombier }
2823e12c5d1SDavid du Colombier 
2833e12c5d1SDavid du Colombier void
2847dd7cddfSDavid du Colombier mountinit(char *service, char *mntpt)
2853e12c5d1SDavid du Colombier {
2863e12c5d1SDavid du Colombier 	int f;
2873e12c5d1SDavid du Colombier 	int p[2];
2883e12c5d1SDavid du Colombier 	char buf[32];
2893e12c5d1SDavid du Colombier 
2903e12c5d1SDavid du Colombier 	if(pipe(p) < 0)
2913e12c5d1SDavid du Colombier 		error("pipe failed");
292a9f680aeSDavid du Colombier 
293a9f680aeSDavid du Colombier 	/*
294a9f680aeSDavid du Colombier 	 *  make a /srv/cs
295a9f680aeSDavid du Colombier 	 */
296a9f680aeSDavid du Colombier 	f = create(service, OWRITE|ORCLOSE, 0666);
297a9f680aeSDavid du Colombier 	if(f < 0)
298a9f680aeSDavid du Colombier 		error(service);
299a9f680aeSDavid du Colombier 	snprint(buf, sizeof(buf), "%d", p[1]);
300a9f680aeSDavid du Colombier 	if(write(f, buf, strlen(buf)) != strlen(buf))
301a9f680aeSDavid du Colombier 		error("write /srv/cs");
302a9f680aeSDavid du Colombier 
303219b2ee8SDavid du Colombier 	switch(rfork(RFFDG|RFPROC|RFNAMEG)){
3043e12c5d1SDavid du Colombier 	case 0:
305219b2ee8SDavid du Colombier 		close(p[1]);
3063e12c5d1SDavid du Colombier 		break;
3073e12c5d1SDavid du Colombier 	case -1:
3083e12c5d1SDavid du Colombier 		error("fork failed\n");
3093e12c5d1SDavid du Colombier 	default:
3103e12c5d1SDavid du Colombier 		/*
3113e12c5d1SDavid du Colombier 		 *  put ourselves into the file system
3123e12c5d1SDavid du Colombier 		 */
313219b2ee8SDavid du Colombier 		close(p[0]);
3149a747e4fSDavid du Colombier 		if(mount(p[1], -1, mntpt, MAFTER, "") < 0)
3153e12c5d1SDavid du Colombier 			error("mount failed\n");
316219b2ee8SDavid du Colombier 		_exits(0);
3173e12c5d1SDavid du Colombier 	}
3183e12c5d1SDavid du Colombier 	mfd[0] = mfd[1] = p[0];
3193e12c5d1SDavid du Colombier }
3203e12c5d1SDavid du Colombier 
3217dd7cddfSDavid du Colombier void
3227dd7cddfSDavid du Colombier ndbinit(void)
3237dd7cddfSDavid du Colombier {
3247dd7cddfSDavid du Colombier 	db = ndbopen(dbfile);
3257dd7cddfSDavid du Colombier 	if(db == nil)
3267dd7cddfSDavid du Colombier 		error("can't open network database");
3277dd7cddfSDavid du Colombier 
3287dd7cddfSDavid du Colombier 	netdb = ndbopen(netndb);
3297dd7cddfSDavid du Colombier 	if(netdb != nil){
3307dd7cddfSDavid du Colombier 		netdb->nohash = 1;
3317dd7cddfSDavid du Colombier 		db = ndbcat(netdb, db);
3327dd7cddfSDavid du Colombier 	}
3337dd7cddfSDavid du Colombier }
3347dd7cddfSDavid du Colombier 
3353e12c5d1SDavid du Colombier Mfile*
3363e12c5d1SDavid du Colombier newfid(int fid)
3373e12c5d1SDavid du Colombier {
338219b2ee8SDavid du Colombier 	Mlist *f, *ff;
3393e12c5d1SDavid du Colombier 	Mfile *mf;
3403e12c5d1SDavid du Colombier 
341219b2ee8SDavid du Colombier 	ff = 0;
342219b2ee8SDavid du Colombier 	for(f = mlist; f; f = f->next)
343219b2ee8SDavid du Colombier 		if(f->mf.busy && f->mf.fid == fid)
344219b2ee8SDavid du Colombier 			return &f->mf;
345219b2ee8SDavid du Colombier 		else if(!ff && !f->mf.busy)
346219b2ee8SDavid du Colombier 			ff = f;
347219b2ee8SDavid du Colombier 	if(ff == 0){
3487dd7cddfSDavid du Colombier 		ff = emalloc(sizeof *f);
349219b2ee8SDavid du Colombier 		ff->next = mlist;
350219b2ee8SDavid du Colombier 		mlist = ff;
3513e12c5d1SDavid du Colombier 	}
352219b2ee8SDavid du Colombier 	mf = &ff->mf;
353219b2ee8SDavid du Colombier 	memset(mf, 0, sizeof *mf);
3543e12c5d1SDavid du Colombier 	mf->fid = fid;
3553e12c5d1SDavid du Colombier 	return mf;
3563e12c5d1SDavid du Colombier }
3573e12c5d1SDavid du Colombier 
3587dd7cddfSDavid du Colombier Job*
3597dd7cddfSDavid du Colombier newjob(void)
3607dd7cddfSDavid du Colombier {
3617dd7cddfSDavid du Colombier 	Job *job;
3627dd7cddfSDavid du Colombier 
3637dd7cddfSDavid du Colombier 	job = mallocz(sizeof(Job), 1);
3647dd7cddfSDavid du Colombier 	lock(&joblock);
3657dd7cddfSDavid du Colombier 	job->next = joblist;
3667dd7cddfSDavid du Colombier 	joblist = job;
3677dd7cddfSDavid du Colombier 	job->request.tag = -1;
3687dd7cddfSDavid du Colombier 	unlock(&joblock);
3697dd7cddfSDavid du Colombier 	return job;
3707dd7cddfSDavid du Colombier }
3717dd7cddfSDavid du Colombier 
3727dd7cddfSDavid du Colombier void
3737dd7cddfSDavid du Colombier freejob(Job *job)
3747dd7cddfSDavid du Colombier {
3757dd7cddfSDavid du Colombier 	Job **l;
3767dd7cddfSDavid du Colombier 
3777dd7cddfSDavid du Colombier 	lock(&joblock);
3787dd7cddfSDavid du Colombier 	for(l = &joblist; *l; l = &(*l)->next){
3797dd7cddfSDavid du Colombier 		if((*l) == job){
3807dd7cddfSDavid du Colombier 			*l = job->next;
3817dd7cddfSDavid du Colombier 			free(job);
3827dd7cddfSDavid du Colombier 			break;
3837dd7cddfSDavid du Colombier 		}
3847dd7cddfSDavid du Colombier 	}
3857dd7cddfSDavid du Colombier 	unlock(&joblock);
3867dd7cddfSDavid du Colombier }
3877dd7cddfSDavid du Colombier 
3887dd7cddfSDavid du Colombier void
3897dd7cddfSDavid du Colombier flushjob(int tag)
3907dd7cddfSDavid du Colombier {
3917dd7cddfSDavid du Colombier 	Job *job;
3927dd7cddfSDavid du Colombier 
3937dd7cddfSDavid du Colombier 	lock(&joblock);
3947dd7cddfSDavid du Colombier 	for(job = joblist; job; job = job->next){
3957dd7cddfSDavid du Colombier 		if(job->request.tag == tag && job->request.type != Tflush){
3967dd7cddfSDavid du Colombier 			job->flushed = 1;
3977dd7cddfSDavid du Colombier 			break;
3987dd7cddfSDavid du Colombier 		}
3997dd7cddfSDavid du Colombier 	}
4007dd7cddfSDavid du Colombier 	unlock(&joblock);
4017dd7cddfSDavid du Colombier }
4027dd7cddfSDavid du Colombier 
4033e12c5d1SDavid du Colombier void
4043e12c5d1SDavid du Colombier io(void)
4053e12c5d1SDavid du Colombier {
4063e12c5d1SDavid du Colombier 	long n;
4073e12c5d1SDavid du Colombier 	Mfile *mf;
4083e12c5d1SDavid du Colombier 	int slaveflag;
4099a747e4fSDavid du Colombier 	uchar mdata[IOHDRSZ + Maxfdata];
4107dd7cddfSDavid du Colombier 	Job *job;
4113e12c5d1SDavid du Colombier 
4123e12c5d1SDavid du Colombier 	/*
4133e12c5d1SDavid du Colombier 	 *  if we ask dns to fulfill requests,
4143e12c5d1SDavid du Colombier 	 *  a slave process is created to wait for replies.  The
4159a747e4fSDavid du Colombier 	 *  master process returns immediately via a longjmp
4163e12c5d1SDavid du Colombier 	 *  through 'masterjmp'.
4173e12c5d1SDavid du Colombier 	 *
4183e12c5d1SDavid du Colombier 	 *  *isslave is a pointer into the call stack to a variable
4193e12c5d1SDavid du Colombier 	 *  that tells whether or not the current process is a slave.
4203e12c5d1SDavid du Colombier 	 */
4213e12c5d1SDavid du Colombier 	slaveflag = 0;		/* init slave variable */
4223e12c5d1SDavid du Colombier 	isslave = &slaveflag;
4233e12c5d1SDavid du Colombier 	setjmp(masterjmp);
4243e12c5d1SDavid du Colombier 
4253e12c5d1SDavid du Colombier 	for(;;){
4269a747e4fSDavid du Colombier 		n = read9pmsg(mfd[0], mdata, sizeof mdata);
4273e12c5d1SDavid du Colombier 		if(n<=0)
4283e12c5d1SDavid du Colombier 			error("mount read");
4297dd7cddfSDavid du Colombier 		job = newjob();
4309a747e4fSDavid du Colombier 		if(convM2S(mdata, n, &job->request) != n){
431271b8d73SDavid du Colombier 			syslog(1, logfile, "format error %ux %ux %ux %ux %ux",
432271b8d73SDavid du Colombier 				mdata[0], mdata[1], mdata[2], mdata[3], mdata[4]);
4337dd7cddfSDavid du Colombier 			freejob(job);
4343e12c5d1SDavid du Colombier 			continue;
4353e12c5d1SDavid du Colombier 		}
436bd389b36SDavid du Colombier 		lock(&dblock);
4377dd7cddfSDavid du Colombier 		mf = newfid(job->request.fid);
438219b2ee8SDavid du Colombier 		if(debug)
4397dd7cddfSDavid du Colombier 			syslog(0, logfile, "%F", &job->request);
4403e12c5d1SDavid du Colombier 
4413e12c5d1SDavid du Colombier 
4427dd7cddfSDavid du Colombier 		switch(job->request.type){
4433e12c5d1SDavid du Colombier 		default:
4447dd7cddfSDavid du Colombier 			syslog(1, logfile, "unknown request type %d", job->request.type);
4453e12c5d1SDavid du Colombier 			break;
4469a747e4fSDavid du Colombier 		case Tversion:
4479a747e4fSDavid du Colombier 			rversion(job);
4483e12c5d1SDavid du Colombier 			break;
4499a747e4fSDavid du Colombier 		case Tauth:
4509a747e4fSDavid du Colombier 			rauth(job);
4513e12c5d1SDavid du Colombier 			break;
4523e12c5d1SDavid du Colombier 		case Tflush:
4537dd7cddfSDavid du Colombier 			rflush(job);
4543e12c5d1SDavid du Colombier 			break;
4553e12c5d1SDavid du Colombier 		case Tattach:
4567dd7cddfSDavid du Colombier 			rattach(job, mf);
4573e12c5d1SDavid du Colombier 			break;
4583e12c5d1SDavid du Colombier 		case Twalk:
4597dd7cddfSDavid du Colombier 			rwalk(job, mf);
4603e12c5d1SDavid du Colombier 			break;
4613e12c5d1SDavid du Colombier 		case Topen:
4627dd7cddfSDavid du Colombier 			ropen(job, mf);
4633e12c5d1SDavid du Colombier 			break;
4643e12c5d1SDavid du Colombier 		case Tcreate:
4657dd7cddfSDavid du Colombier 			rcreate(job, mf);
4663e12c5d1SDavid du Colombier 			break;
4673e12c5d1SDavid du Colombier 		case Tread:
4687dd7cddfSDavid du Colombier 			rread(job, mf);
4693e12c5d1SDavid du Colombier 			break;
4703e12c5d1SDavid du Colombier 		case Twrite:
4717dd7cddfSDavid du Colombier 			rwrite(job, mf);
4723e12c5d1SDavid du Colombier 			break;
4733e12c5d1SDavid du Colombier 		case Tclunk:
4747dd7cddfSDavid du Colombier 			rclunk(job, mf);
4753e12c5d1SDavid du Colombier 			break;
4763e12c5d1SDavid du Colombier 		case Tremove:
4777dd7cddfSDavid du Colombier 			rremove(job, mf);
4783e12c5d1SDavid du Colombier 			break;
4793e12c5d1SDavid du Colombier 		case Tstat:
4807dd7cddfSDavid du Colombier 			rstat(job, mf);
4813e12c5d1SDavid du Colombier 			break;
4823e12c5d1SDavid du Colombier 		case Twstat:
4837dd7cddfSDavid du Colombier 			rwstat(job, mf);
4843e12c5d1SDavid du Colombier 			break;
4853e12c5d1SDavid du Colombier 		}
486bd389b36SDavid du Colombier 		unlock(&dblock);
4877dd7cddfSDavid du Colombier 
4887dd7cddfSDavid du Colombier 		freejob(job);
4897dd7cddfSDavid du Colombier 
4903e12c5d1SDavid du Colombier 		/*
4913e12c5d1SDavid du Colombier 		 *  slave processes die after replying
4923e12c5d1SDavid du Colombier 		 */
493219b2ee8SDavid du Colombier 		if(*isslave){
494219b2ee8SDavid du Colombier 			if(debug)
495219b2ee8SDavid du Colombier 				syslog(0, logfile, "slave death %d", getpid());
4963e12c5d1SDavid du Colombier 			_exits(0);
4973e12c5d1SDavid du Colombier 		}
4983e12c5d1SDavid du Colombier 	}
499219b2ee8SDavid du Colombier }
500219b2ee8SDavid du Colombier 
501219b2ee8SDavid du Colombier void
5029a747e4fSDavid du Colombier rversion(Job *job)
503219b2ee8SDavid du Colombier {
5049a747e4fSDavid du Colombier 	if(job->request.msize > IOHDRSZ + Maxfdata)
5059a747e4fSDavid du Colombier 		job->reply.msize = IOHDRSZ + Maxfdata;
5069a747e4fSDavid du Colombier 	else
5079a747e4fSDavid du Colombier 		job->reply.msize = job->request.msize;
5089a747e4fSDavid du Colombier 	if(strncmp(job->request.version, "9P2000", 6) != 0)
5099a747e4fSDavid du Colombier 		sendmsg(job, "unknown 9P version");
5109a747e4fSDavid du Colombier 	else{
5119a747e4fSDavid du Colombier 		job->reply.version = "9P2000";
5127dd7cddfSDavid du Colombier 		sendmsg(job, 0);
513219b2ee8SDavid du Colombier 	}
5149a747e4fSDavid du Colombier }
5153e12c5d1SDavid du Colombier 
5163e12c5d1SDavid du Colombier void
5179a747e4fSDavid du Colombier rauth(Job *job)
5183e12c5d1SDavid du Colombier {
5193ff48bf5SDavid du Colombier 	sendmsg(job, "cs: authentication not required");
5207dd7cddfSDavid du Colombier }
5217dd7cddfSDavid du Colombier 
5227dd7cddfSDavid du Colombier /*
5237dd7cddfSDavid du Colombier  *  don't flush till all the slaves are done
5247dd7cddfSDavid du Colombier  */
5257dd7cddfSDavid du Colombier void
5267dd7cddfSDavid du Colombier rflush(Job *job)
5277dd7cddfSDavid du Colombier {
5287dd7cddfSDavid du Colombier 	flushjob(job->request.oldtag);
5297dd7cddfSDavid du Colombier 	sendmsg(job, 0);
5303e12c5d1SDavid du Colombier }
5313e12c5d1SDavid du Colombier 
5323e12c5d1SDavid du Colombier void
5337dd7cddfSDavid du Colombier rattach(Job *job, Mfile *mf)
5343e12c5d1SDavid du Colombier {
5353e12c5d1SDavid du Colombier 	if(mf->busy == 0){
5363e12c5d1SDavid du Colombier 		mf->busy = 1;
5379a747e4fSDavid du Colombier 		mf->user = estrdup(job->request.uname);
5383e12c5d1SDavid du Colombier 	}
5393e12c5d1SDavid du Colombier 	mf->qid.vers = vers++;
5409a747e4fSDavid du Colombier 	mf->qid.type = QTDIR;
5419a747e4fSDavid du Colombier 	mf->qid.path = 0LL;
5427dd7cddfSDavid du Colombier 	job->reply.qid = mf->qid;
5437dd7cddfSDavid du Colombier 	sendmsg(job, 0);
5443e12c5d1SDavid du Colombier }
5453e12c5d1SDavid du Colombier 
5463e12c5d1SDavid du Colombier 
5473e12c5d1SDavid du Colombier char*
5487dd7cddfSDavid du Colombier rwalk(Job *job, Mfile *mf)
5493e12c5d1SDavid du Colombier {
5503e12c5d1SDavid du Colombier 	char *err;
5519a747e4fSDavid du Colombier 	char **elems;
5529a747e4fSDavid du Colombier 	int nelems;
5539a747e4fSDavid du Colombier 	int i;
5549a747e4fSDavid du Colombier 	Mfile *nmf;
5559a747e4fSDavid du Colombier 	Qid qid;
5563e12c5d1SDavid du Colombier 
5573e12c5d1SDavid du Colombier 	err = 0;
5589a747e4fSDavid du Colombier 	nmf = nil;
5599a747e4fSDavid du Colombier 	elems = job->request.wname;
5609a747e4fSDavid du Colombier 	nelems = job->request.nwname;
5619a747e4fSDavid du Colombier 	job->reply.nwqid = 0;
5629a747e4fSDavid du Colombier 
5639a747e4fSDavid du Colombier 	if(job->request.newfid != job->request.fid){
5649a747e4fSDavid du Colombier 		/* clone fid */
5659a747e4fSDavid du Colombier 		nmf = newfid(job->request.newfid);
5669a747e4fSDavid du Colombier 		if(nmf->busy){
5679a747e4fSDavid du Colombier 			nmf = nil;
5689a747e4fSDavid du Colombier 			err = "clone to used channel";
5699a747e4fSDavid du Colombier 			goto send;
5709a747e4fSDavid du Colombier 		}
5719a747e4fSDavid du Colombier 		*nmf = *mf;
5729a747e4fSDavid du Colombier 		nmf->user = estrdup(mf->user);
5739a747e4fSDavid du Colombier 		nmf->fid = job->request.newfid;
5749a747e4fSDavid du Colombier 		nmf->qid.vers = vers++;
5759a747e4fSDavid du Colombier 		mf = nmf;
5769a747e4fSDavid du Colombier 	}
5779a747e4fSDavid du Colombier 	/* else nmf will be nil */
5789a747e4fSDavid du Colombier 
5799a747e4fSDavid du Colombier 	qid = mf->qid;
5809a747e4fSDavid du Colombier 	if(nelems > 0){
5819a747e4fSDavid du Colombier 		/* walk fid */
5829a747e4fSDavid du Colombier 		for(i=0; i<nelems && i<MAXWELEM; i++){
5839a747e4fSDavid du Colombier 			if((qid.type & QTDIR) == 0){
5843e12c5d1SDavid du Colombier 				err = "not a directory";
5859a747e4fSDavid du Colombier 				break;
5863e12c5d1SDavid du Colombier 			}
5879a747e4fSDavid du Colombier 			if(strcmp(elems[i], "..") == 0 || strcmp(elems[i], ".") == 0){
5889a747e4fSDavid du Colombier 				qid.type = QTDIR;
5899a747e4fSDavid du Colombier 				qid.path = Qdir;
5909a747e4fSDavid du Colombier     Found:
5919a747e4fSDavid du Colombier 				job->reply.wqid[i] = qid;
5929a747e4fSDavid du Colombier 				job->reply.nwqid++;
5939a747e4fSDavid du Colombier 				continue;
5943e12c5d1SDavid du Colombier 			}
5959a747e4fSDavid du Colombier 			if(strcmp(elems[i], "cs") == 0){
5969a747e4fSDavid du Colombier 				qid.type = QTFILE;
5979a747e4fSDavid du Colombier 				qid.path = Qcs;
5989a747e4fSDavid du Colombier 				goto Found;
5993e12c5d1SDavid du Colombier 			}
6009a747e4fSDavid du Colombier 			err = "file does not exist";
6019a747e4fSDavid du Colombier 			break;
6029a747e4fSDavid du Colombier 		}
6039a747e4fSDavid du Colombier 	}
6049a747e4fSDavid du Colombier 
6053e12c5d1SDavid du Colombier     send:
6069a747e4fSDavid du Colombier 	if(nmf != nil && (err!=nil || job->reply.nwqid<nelems)){
607a9f680aeSDavid du Colombier 		cleanmf(nmf);
608a9f680aeSDavid du Colombier 		free(nmf->user);
609a9f680aeSDavid du Colombier 		nmf->user = 0;
6109a747e4fSDavid du Colombier 		nmf->busy = 0;
6119a747e4fSDavid du Colombier 		nmf->fid = 0;
6129a747e4fSDavid du Colombier 	}
6139a747e4fSDavid du Colombier 	if(err == nil)
6149a747e4fSDavid du Colombier 		mf->qid = qid;
6157dd7cddfSDavid du Colombier 	sendmsg(job, err);
6163e12c5d1SDavid du Colombier 	return err;
6173e12c5d1SDavid du Colombier }
6183e12c5d1SDavid du Colombier 
6193e12c5d1SDavid du Colombier void
6207dd7cddfSDavid du Colombier ropen(Job *job, Mfile *mf)
6213e12c5d1SDavid du Colombier {
6223e12c5d1SDavid du Colombier 	int mode;
6233e12c5d1SDavid du Colombier 	char *err;
6243e12c5d1SDavid du Colombier 
6253e12c5d1SDavid du Colombier 	err = 0;
6267dd7cddfSDavid du Colombier 	mode = job->request.mode;
6279a747e4fSDavid du Colombier 	if(mf->qid.type & QTDIR){
6283e12c5d1SDavid du Colombier 		if(mode)
6293e12c5d1SDavid du Colombier 			err = "permission denied";
6309a747e4fSDavid du Colombier 	}
6317dd7cddfSDavid du Colombier 	job->reply.qid = mf->qid;
6329a747e4fSDavid du Colombier 	job->reply.iounit = 0;
6337dd7cddfSDavid du Colombier 	sendmsg(job, err);
6343e12c5d1SDavid du Colombier }
6353e12c5d1SDavid du Colombier 
6363e12c5d1SDavid du Colombier void
6377dd7cddfSDavid du Colombier rcreate(Job *job, Mfile *mf)
6383e12c5d1SDavid du Colombier {
6393e12c5d1SDavid du Colombier 	USED(mf);
6407dd7cddfSDavid du Colombier 	sendmsg(job, "creation permission denied");
6413e12c5d1SDavid du Colombier }
6423e12c5d1SDavid du Colombier 
6433e12c5d1SDavid du Colombier void
6447dd7cddfSDavid du Colombier rread(Job *job, Mfile *mf)
6453e12c5d1SDavid du Colombier {
646219b2ee8SDavid du Colombier 	int i, n, cnt;
647219b2ee8SDavid du Colombier 	long off, toff, clock;
6483e12c5d1SDavid du Colombier 	Dir dir;
6499a747e4fSDavid du Colombier 	uchar buf[Maxfdata];
6503e12c5d1SDavid du Colombier 	char *err;
6513e12c5d1SDavid du Colombier 
6523e12c5d1SDavid du Colombier 	n = 0;
6533e12c5d1SDavid du Colombier 	err = 0;
6547dd7cddfSDavid du Colombier 	off = job->request.offset;
6557dd7cddfSDavid du Colombier 	cnt = job->request.count;
6569a747e4fSDavid du Colombier 	if(mf->qid.type & QTDIR){
6573e12c5d1SDavid du Colombier 		clock = time(0);
6583e12c5d1SDavid du Colombier 		if(off == 0){
6599a747e4fSDavid du Colombier 			dir.name = "cs";
6609a747e4fSDavid du Colombier 			dir.qid.type = QTFILE;
6613e12c5d1SDavid du Colombier 			dir.qid.vers = vers;
6623e12c5d1SDavid du Colombier 			dir.qid.path = Qcs;
6633e12c5d1SDavid du Colombier 			dir.mode = 0666;
6643e12c5d1SDavid du Colombier 			dir.length = 0;
6659a747e4fSDavid du Colombier 			dir.uid = mf->user;
6669a747e4fSDavid du Colombier 			dir.gid = mf->user;
6679a747e4fSDavid du Colombier 			dir.muid = mf->user;
6683e12c5d1SDavid du Colombier 			dir.atime = clock;	/* wrong */
6693e12c5d1SDavid du Colombier 			dir.mtime = clock;	/* wrong */
6709a747e4fSDavid du Colombier 			n = convD2M(&dir, buf, sizeof buf);
6713e12c5d1SDavid du Colombier 		}
6729a747e4fSDavid du Colombier 		job->reply.data = (char*)buf;
6733e12c5d1SDavid du Colombier 	} else {
67480ee5cbfSDavid du Colombier 		for(;;){
67580ee5cbfSDavid du Colombier 			/* look for an answer at the right offset */
676219b2ee8SDavid du Colombier 			toff = 0;
677219b2ee8SDavid du Colombier 			for(i = 0; mf->reply[i] && i < mf->nreply; i++){
678219b2ee8SDavid du Colombier 				n = mf->replylen[i];
679219b2ee8SDavid du Colombier 				if(off < toff + n)
680219b2ee8SDavid du Colombier 					break;
681219b2ee8SDavid du Colombier 				toff += n;
6823e12c5d1SDavid du Colombier 			}
68380ee5cbfSDavid du Colombier 			if(i < mf->nreply)
68480ee5cbfSDavid du Colombier 				break;		/* got something to return */
68580ee5cbfSDavid du Colombier 
68680ee5cbfSDavid du Colombier 			/* try looking up more answers */
68780ee5cbfSDavid du Colombier 			if(lookup(mf) == 0){
68880ee5cbfSDavid du Colombier 				/* no more */
689219b2ee8SDavid du Colombier 				n = 0;
690219b2ee8SDavid du Colombier 				goto send;
691219b2ee8SDavid du Colombier 			}
69280ee5cbfSDavid du Colombier 		}
69380ee5cbfSDavid du Colombier 
69480ee5cbfSDavid du Colombier 		/* give back a single reply (or part of one) */
6957dd7cddfSDavid du Colombier 		job->reply.data = mf->reply[i] + (off - toff);
696219b2ee8SDavid du Colombier 		if(cnt > toff - off + n)
697219b2ee8SDavid du Colombier 			n = toff - off + n;
698219b2ee8SDavid du Colombier 		else
699219b2ee8SDavid du Colombier 			n = cnt;
7003e12c5d1SDavid du Colombier 	}
7013e12c5d1SDavid du Colombier send:
7027dd7cddfSDavid du Colombier 	job->reply.count = n;
7037dd7cddfSDavid du Colombier 	sendmsg(job, err);
7047dd7cddfSDavid du Colombier }
70580ee5cbfSDavid du Colombier void
70680ee5cbfSDavid du Colombier cleanmf(Mfile *mf)
7077dd7cddfSDavid du Colombier {
7087dd7cddfSDavid du Colombier 	int i;
7097dd7cddfSDavid du Colombier 
7109a747e4fSDavid du Colombier 	if(mf->net != nil){
71180ee5cbfSDavid du Colombier 		free(mf->net);
71280ee5cbfSDavid du Colombier 		mf->net = nil;
7139a747e4fSDavid du Colombier 	}
7149a747e4fSDavid du Colombier 	if(mf->host != nil){
71580ee5cbfSDavid du Colombier 		free(mf->host);
71680ee5cbfSDavid du Colombier 		mf->host = nil;
7179a747e4fSDavid du Colombier 	}
7189a747e4fSDavid du Colombier 	if(mf->serv != nil){
71980ee5cbfSDavid du Colombier 		free(mf->serv);
72080ee5cbfSDavid du Colombier 		mf->serv = nil;
7219a747e4fSDavid du Colombier 	}
7229a747e4fSDavid du Colombier 	if(mf->rem != nil){
72380ee5cbfSDavid du Colombier 		free(mf->rem);
72480ee5cbfSDavid du Colombier 		mf->rem = nil;
7259a747e4fSDavid du Colombier 	}
72680ee5cbfSDavid du Colombier 	for(i = 0; i < mf->nreply; i++){
72780ee5cbfSDavid du Colombier 		free(mf->reply[i]);
72880ee5cbfSDavid du Colombier 		mf->reply[i] = nil;
72980ee5cbfSDavid du Colombier 		mf->replylen[i] = 0;
7307dd7cddfSDavid du Colombier 	}
73180ee5cbfSDavid du Colombier 	mf->nreply = 0;
73280ee5cbfSDavid du Colombier 	mf->nextnet = netlist;
7333e12c5d1SDavid du Colombier }
7343e12c5d1SDavid du Colombier 
7353e12c5d1SDavid du Colombier void
7367dd7cddfSDavid du Colombier rwrite(Job *job, Mfile *mf)
7373e12c5d1SDavid du Colombier {
7383e12c5d1SDavid du Colombier 	int cnt, n;
73980ee5cbfSDavid du Colombier 	char *err;
7407dd7cddfSDavid du Colombier 	char *field[4];
741271b8d73SDavid du Colombier 	char curerr[64];
7423e12c5d1SDavid du Colombier 
7433e12c5d1SDavid du Colombier 	err = 0;
7447dd7cddfSDavid du Colombier 	cnt = job->request.count;
7459a747e4fSDavid du Colombier 	if(mf->qid.type & QTDIR){
7463e12c5d1SDavid du Colombier 		err = "can't write directory";
7473e12c5d1SDavid du Colombier 		goto send;
7483e12c5d1SDavid du Colombier 	}
7493e12c5d1SDavid du Colombier 	if(cnt >= Maxrequest){
7503e12c5d1SDavid du Colombier 		err = "request too long";
7513e12c5d1SDavid du Colombier 		goto send;
7523e12c5d1SDavid du Colombier 	}
7537dd7cddfSDavid du Colombier 	job->request.data[cnt] = 0;
7543e12c5d1SDavid du Colombier 
7553e12c5d1SDavid du Colombier 	/*
756219b2ee8SDavid du Colombier 	 *  toggle debugging
757219b2ee8SDavid du Colombier 	 */
7587dd7cddfSDavid du Colombier 	if(strncmp(job->request.data, "debug", 5)==0){
759219b2ee8SDavid du Colombier 		debug ^= 1;
760219b2ee8SDavid du Colombier 		syslog(1, logfile, "debug %d", debug);
761219b2ee8SDavid du Colombier 		goto send;
762219b2ee8SDavid du Colombier 	}
763219b2ee8SDavid du Colombier 
764219b2ee8SDavid du Colombier 	/*
7657dd7cddfSDavid du Colombier 	 *  toggle debugging
7667dd7cddfSDavid du Colombier 	 */
7677dd7cddfSDavid du Colombier 	if(strncmp(job->request.data, "paranoia", 8)==0){
7687dd7cddfSDavid du Colombier 		paranoia ^= 1;
7697dd7cddfSDavid du Colombier 		syslog(1, logfile, "paranoia %d", paranoia);
7707dd7cddfSDavid du Colombier 		goto send;
7717dd7cddfSDavid du Colombier 	}
7727dd7cddfSDavid du Colombier 
7737dd7cddfSDavid du Colombier 	/*
7743e12c5d1SDavid du Colombier 	 *  add networks to the default list
7753e12c5d1SDavid du Colombier 	 */
7767dd7cddfSDavid du Colombier 	if(strncmp(job->request.data, "add ", 4)==0){
7777dd7cddfSDavid du Colombier 		if(job->request.data[cnt-1] == '\n')
7787dd7cddfSDavid du Colombier 			job->request.data[cnt-1] = 0;
7797dd7cddfSDavid du Colombier 		netadd(job->request.data+4);
7807dd7cddfSDavid du Colombier 		readipinterfaces();
7817dd7cddfSDavid du Colombier 		goto send;
7827dd7cddfSDavid du Colombier 	}
7837dd7cddfSDavid du Colombier 
7847dd7cddfSDavid du Colombier 	/*
7857dd7cddfSDavid du Colombier 	 *  refresh all state
7867dd7cddfSDavid du Colombier 	 */
7877dd7cddfSDavid du Colombier 	if(strncmp(job->request.data, "refresh", 7)==0){
7887dd7cddfSDavid du Colombier 		netinit(1);
7893e12c5d1SDavid du Colombier 		goto send;
7903e12c5d1SDavid du Colombier 	}
7913e12c5d1SDavid du Colombier 
79280ee5cbfSDavid du Colombier 	/* start transaction with a clean slate */
79380ee5cbfSDavid du Colombier 	cleanmf(mf);
79480ee5cbfSDavid du Colombier 
7953e12c5d1SDavid du Colombier 	/*
796219b2ee8SDavid du Colombier 	 *  look for a general query
797219b2ee8SDavid du Colombier 	 */
7987dd7cddfSDavid du Colombier 	if(*job->request.data == '!'){
7997dd7cddfSDavid du Colombier 		err = genquery(mf, job->request.data+1);
800219b2ee8SDavid du Colombier 		goto send;
801219b2ee8SDavid du Colombier 	}
802219b2ee8SDavid du Colombier 
8037dd7cddfSDavid du Colombier 	if(debug)
8047dd7cddfSDavid du Colombier 		syslog(0, logfile, "write %s", job->request.data);
8057dd7cddfSDavid du Colombier 	if(paranoia)
8067dd7cddfSDavid du Colombier 		syslog(0, paranoiafile, "write %s by %s", job->request.data, mf->user);
8077dd7cddfSDavid du Colombier 
808219b2ee8SDavid du Colombier 	/*
8093e12c5d1SDavid du Colombier 	 *  break up name
8103e12c5d1SDavid du Colombier 	 */
8117dd7cddfSDavid du Colombier 	n = getfields(job->request.data, field, 4, 1, "!");
8123e12c5d1SDavid du Colombier 	switch(n){
8133e12c5d1SDavid du Colombier 	case 1:
81480ee5cbfSDavid du Colombier 		mf->net = strdup("net");
81580ee5cbfSDavid du Colombier 		mf->host = strdup(field[0]);
8167dd7cddfSDavid du Colombier 		break;
8177dd7cddfSDavid du Colombier 	case 4:
81880ee5cbfSDavid du Colombier 		mf->rem = strdup(field[3]);
81980ee5cbfSDavid du Colombier 		/* fall through */
82080ee5cbfSDavid du Colombier 	case 3:
82180ee5cbfSDavid du Colombier 		mf->serv = strdup(field[2]);
82280ee5cbfSDavid du Colombier 		/* fall through */
82380ee5cbfSDavid du Colombier 	case 2:
82480ee5cbfSDavid du Colombier 		mf->host = strdup(field[1]);
82580ee5cbfSDavid du Colombier 		mf->net = strdup(field[0]);
8263e12c5d1SDavid du Colombier 		break;
8273e12c5d1SDavid du Colombier 	}
8283e12c5d1SDavid du Colombier 
82980ee5cbfSDavid du Colombier 	/*
83080ee5cbfSDavid du Colombier 	 *  do the first net worth of lookup
83180ee5cbfSDavid du Colombier 	 */
832271b8d73SDavid du Colombier 	if(lookup(mf) == 0){
833271b8d73SDavid du Colombier 		rerrstr(curerr, sizeof curerr);
834271b8d73SDavid du Colombier 		err = curerr;
835271b8d73SDavid du Colombier 	}
8363e12c5d1SDavid du Colombier send:
8377dd7cddfSDavid du Colombier 	job->reply.count = cnt;
8387dd7cddfSDavid du Colombier 	sendmsg(job, err);
8393e12c5d1SDavid du Colombier }
8403e12c5d1SDavid du Colombier 
8413e12c5d1SDavid du Colombier void
8427dd7cddfSDavid du Colombier rclunk(Job *job, Mfile *mf)
8433e12c5d1SDavid du Colombier {
84480ee5cbfSDavid du Colombier 	cleanmf(mf);
845a9f680aeSDavid du Colombier 	free(mf->user);
846a9f680aeSDavid du Colombier 	mf->user = 0;
8473e12c5d1SDavid du Colombier 	mf->busy = 0;
8483e12c5d1SDavid du Colombier 	mf->fid = 0;
8497dd7cddfSDavid du Colombier 	sendmsg(job, 0);
8503e12c5d1SDavid du Colombier }
8513e12c5d1SDavid du Colombier 
8523e12c5d1SDavid du Colombier void
8537dd7cddfSDavid du Colombier rremove(Job *job, Mfile *mf)
8543e12c5d1SDavid du Colombier {
8553e12c5d1SDavid du Colombier 	USED(mf);
8567dd7cddfSDavid du Colombier 	sendmsg(job, "remove permission denied");
8573e12c5d1SDavid du Colombier }
8583e12c5d1SDavid du Colombier 
8593e12c5d1SDavid du Colombier void
8607dd7cddfSDavid du Colombier rstat(Job *job, Mfile *mf)
8613e12c5d1SDavid du Colombier {
8623e12c5d1SDavid du Colombier 	Dir dir;
8639a747e4fSDavid du Colombier 	uchar buf[IOHDRSZ+Maxfdata];
8643e12c5d1SDavid du Colombier 
8659a747e4fSDavid du Colombier 	if(mf->qid.type & QTDIR){
8669a747e4fSDavid du Colombier 		dir.name = ".";
8679a747e4fSDavid du Colombier 		dir.mode = DMDIR|0555;
868219b2ee8SDavid du Colombier 	} else {
8699a747e4fSDavid du Colombier 		dir.name = "cs";
8703e12c5d1SDavid du Colombier 		dir.mode = 0666;
871219b2ee8SDavid du Colombier 	}
872219b2ee8SDavid du Colombier 	dir.qid = mf->qid;
8733e12c5d1SDavid du Colombier 	dir.length = 0;
8749a747e4fSDavid du Colombier 	dir.uid = mf->user;
8759a747e4fSDavid du Colombier 	dir.gid = mf->user;
8769a747e4fSDavid du Colombier 	dir.muid = mf->user;
8773e12c5d1SDavid du Colombier 	dir.atime = dir.mtime = time(0);
8789a747e4fSDavid du Colombier 	job->reply.nstat = convD2M(&dir, buf, sizeof buf);
8799a747e4fSDavid du Colombier 	job->reply.stat = buf;
8807dd7cddfSDavid du Colombier 	sendmsg(job, 0);
8813e12c5d1SDavid du Colombier }
8823e12c5d1SDavid du Colombier 
8833e12c5d1SDavid du Colombier void
8847dd7cddfSDavid du Colombier rwstat(Job *job, Mfile *mf)
8853e12c5d1SDavid du Colombier {
8863e12c5d1SDavid du Colombier 	USED(mf);
8877dd7cddfSDavid du Colombier 	sendmsg(job, "wstat permission denied");
8883e12c5d1SDavid du Colombier }
8893e12c5d1SDavid du Colombier 
8903e12c5d1SDavid du Colombier void
8917dd7cddfSDavid du Colombier sendmsg(Job *job, char *err)
8923e12c5d1SDavid du Colombier {
8933e12c5d1SDavid du Colombier 	int n;
8949a747e4fSDavid du Colombier 	uchar mdata[IOHDRSZ + Maxfdata];
8959a747e4fSDavid du Colombier 	char ename[ERRMAX];
8963e12c5d1SDavid du Colombier 
8973e12c5d1SDavid du Colombier 	if(err){
8987dd7cddfSDavid du Colombier 		job->reply.type = Rerror;
8999a747e4fSDavid du Colombier 		snprint(ename, sizeof(ename), "cs: %s", err);
9009a747e4fSDavid du Colombier 		job->reply.ename = ename;
9013e12c5d1SDavid du Colombier 	}else{
9027dd7cddfSDavid du Colombier 		job->reply.type = job->request.type+1;
9033e12c5d1SDavid du Colombier 	}
9047dd7cddfSDavid du Colombier 	job->reply.tag = job->request.tag;
9059a747e4fSDavid du Colombier 	n = convS2M(&job->reply, mdata, sizeof mdata);
906219b2ee8SDavid du Colombier 	if(n == 0){
9077dd7cddfSDavid du Colombier 		syslog(1, logfile, "sendmsg convS2M of %F returns 0", &job->reply);
908219b2ee8SDavid du Colombier 		abort();
909219b2ee8SDavid du Colombier 	}
9107dd7cddfSDavid du Colombier 	lock(&joblock);
9117dd7cddfSDavid du Colombier 	if(job->flushed == 0)
9129a747e4fSDavid du Colombier 		if(write(mfd[1], mdata, n)!=n)
9133e12c5d1SDavid du Colombier 			error("mount write");
9147dd7cddfSDavid du Colombier 	unlock(&joblock);
915219b2ee8SDavid du Colombier 	if(debug)
9167dd7cddfSDavid du Colombier 		syslog(0, logfile, "%F %d", &job->reply, n);
9173e12c5d1SDavid du Colombier }
9183e12c5d1SDavid du Colombier 
9193e12c5d1SDavid du Colombier void
9203e12c5d1SDavid du Colombier error(char *s)
9213e12c5d1SDavid du Colombier {
922bd389b36SDavid du Colombier 	syslog(1, "cs", "%s: %r", s);
923bd389b36SDavid du Colombier 	_exits(0);
9243e12c5d1SDavid du Colombier }
9253e12c5d1SDavid du Colombier 
9267dd7cddfSDavid du Colombier static int
9277dd7cddfSDavid du Colombier isvalidip(uchar *ip)
9287dd7cddfSDavid du Colombier {
9297dd7cddfSDavid du Colombier 	return ipcmp(ip, IPnoaddr) != 0 && ipcmp(ip, v4prefix) != 0;
9307dd7cddfSDavid du Colombier }
9313e12c5d1SDavid du Colombier 
9320103620dSDavid du Colombier static uchar loopbacknet[IPaddrlen] = {
9330103620dSDavid du Colombier 	0, 0, 0, 0,
9340103620dSDavid du Colombier 	0, 0, 0, 0,
9350103620dSDavid du Colombier 	0, 0, 0xff, 0xff,
9360103620dSDavid du Colombier 	127, 0, 0, 0
9370103620dSDavid du Colombier };
9380103620dSDavid du Colombier static uchar loopbackmask[IPaddrlen] = {
9390103620dSDavid du Colombier 	0xff, 0xff, 0xff, 0xff,
9400103620dSDavid du Colombier 	0xff, 0xff, 0xff, 0xff,
9410103620dSDavid du Colombier 	0xff, 0xff, 0xff, 0xff,
9420103620dSDavid du Colombier 	0xff, 0, 0, 0
9430103620dSDavid du Colombier };
9440103620dSDavid du Colombier 
9457dd7cddfSDavid du Colombier void
9467dd7cddfSDavid du Colombier readipinterfaces(void)
9477dd7cddfSDavid du Colombier {
9480103620dSDavid du Colombier 	if(myipaddr(ipa, mntpt) != 0)
9490103620dSDavid du Colombier 		ipmove(ipa, IPnoaddr);
9507dd7cddfSDavid du Colombier 	sprint(ipaddr, "%I", ipa);
9517dd7cddfSDavid du Colombier 	if (debug)
9527dd7cddfSDavid du Colombier 		syslog(0, "dns", "ipaddr is %s\n", ipaddr);
9537dd7cddfSDavid du Colombier }
9543e12c5d1SDavid du Colombier 
9553e12c5d1SDavid du Colombier /*
9567dd7cddfSDavid du Colombier  *  get the system name
9573e12c5d1SDavid du Colombier  */
9583e12c5d1SDavid du Colombier void
9593e12c5d1SDavid du Colombier ipid(void)
9603e12c5d1SDavid du Colombier {
9613e12c5d1SDavid du Colombier 	uchar addr[6];
962a9f680aeSDavid du Colombier 	Ndbtuple *t, *tt;
963219b2ee8SDavid du Colombier 	char *p, *attr;
9643e12c5d1SDavid du Colombier 	Ndbs s;
9653e12c5d1SDavid du Colombier 	int f;
9667dd7cddfSDavid du Colombier 	char buf[Maxpath];
9673e12c5d1SDavid du Colombier 
968219b2ee8SDavid du Colombier 	/* use environment, ether addr, or ipaddr to get system name */
96995a264b3SDavid du Colombier 	if(mysysname == 0){
9707dd7cddfSDavid du Colombier 		/*
9717dd7cddfSDavid du Colombier 		 *  environment has priority.
9727dd7cddfSDavid du Colombier 		 *
9737dd7cddfSDavid du Colombier 		 *  on the sgi power the default system name
9747dd7cddfSDavid du Colombier 		 *  is the ip address.  ignore that.
9757dd7cddfSDavid du Colombier 		 *
9767dd7cddfSDavid du Colombier 		 */
977219b2ee8SDavid du Colombier 		p = getenv("sysname");
978447d6a7dSDavid du Colombier 		if(p && *p){
979219b2ee8SDavid du Colombier 			attr = ipattr(p);
980219b2ee8SDavid du Colombier 			if(strcmp(attr, "ip") != 0)
98195a264b3SDavid du Colombier 				mysysname = strdup(p);
9823e12c5d1SDavid du Colombier 		}
9833e12c5d1SDavid du Colombier 
9843e12c5d1SDavid du Colombier 		/*
9857dd7cddfSDavid du Colombier 		 *  the /net/ndb contains what the network
9867dd7cddfSDavid du Colombier 		 *  figured out from DHCP.  use that name if
9877dd7cddfSDavid du Colombier 		 *  there is one.
9883e12c5d1SDavid du Colombier 		 */
98995a264b3SDavid du Colombier 		if(mysysname == 0 && netdb != nil){
9907dd7cddfSDavid du Colombier 			ndbreopen(netdb);
991a9f680aeSDavid du Colombier 			for(tt = t = ndbparse(netdb); t != nil; t = t->entry){
9927dd7cddfSDavid du Colombier 				if(strcmp(t->attr, "sys") == 0){
99395a264b3SDavid du Colombier 					mysysname = strdup(t->val);
9943e12c5d1SDavid du Colombier 					break;
9953e12c5d1SDavid du Colombier 				}
9967dd7cddfSDavid du Colombier 			}
997a9f680aeSDavid du Colombier 			ndbfree(tt);
9987dd7cddfSDavid du Colombier 		}
9997dd7cddfSDavid du Colombier 
10007dd7cddfSDavid du Colombier 		/* next network database, ip address, and ether address to find a name */
100195a264b3SDavid du Colombier 		if(mysysname == 0){
10027dd7cddfSDavid du Colombier 			t = nil;
10037dd7cddfSDavid du Colombier 			if(isvalidip(ipa))
100457837e0bSDavid du Colombier 				free(ndbgetvalue(db, &s, "ip", ipaddr, "sys", &t));
100595a264b3SDavid du Colombier 			if(t == nil){
10067dd7cddfSDavid du Colombier 				for(f = 0; f < 3; f++){
10077dd7cddfSDavid du Colombier 					snprint(buf, sizeof buf, "%s/ether%d", mntpt, f);
10087dd7cddfSDavid du Colombier 					if(myetheraddr(addr, buf) >= 0){
10097dd7cddfSDavid du Colombier 						snprint(eaddr, sizeof(eaddr), "%E", addr);
101057837e0bSDavid du Colombier 						free(ndbgetvalue(db, &s, "ether", eaddr, "sys", &t));
10117dd7cddfSDavid du Colombier 						if(t != nil)
10127dd7cddfSDavid du Colombier 							break;
10137dd7cddfSDavid du Colombier 					}
10147dd7cddfSDavid du Colombier 				}
10157dd7cddfSDavid du Colombier 			}
1016b7327ca2SDavid du Colombier 			for(tt = t; tt != nil; tt = tt->entry){
1017b7327ca2SDavid du Colombier 				if(strcmp(tt->attr, "sys") == 0){
1018b7327ca2SDavid du Colombier 					mysysname = strdup(tt->val);
101995a264b3SDavid du Colombier 					break;
102095a264b3SDavid du Colombier 				}
1021b7327ca2SDavid du Colombier 			}
10227dd7cddfSDavid du Colombier 			ndbfree(t);
10237dd7cddfSDavid du Colombier 		}
10247dd7cddfSDavid du Colombier 
102580ee5cbfSDavid du Colombier 		/* nothing else worked, use the ip address */
102695a264b3SDavid du Colombier 		if(mysysname == 0 && isvalidip(ipa))
102795a264b3SDavid du Colombier 			mysysname = strdup(ipaddr);
102880ee5cbfSDavid du Colombier 
102980ee5cbfSDavid du Colombier 
1030dc5a79c1SDavid du Colombier 		/* set /dev/sysname if we now know it */
103195a264b3SDavid du Colombier 		if(mysysname){
10327dd7cddfSDavid du Colombier 			f = open("/dev/sysname", OWRITE);
10337dd7cddfSDavid du Colombier 			if(f >= 0){
10347dd7cddfSDavid du Colombier 				write(f, mysysname, strlen(mysysname));
10353e12c5d1SDavid du Colombier 				close(f);
10363e12c5d1SDavid du Colombier 			}
10373e12c5d1SDavid du Colombier 		}
10383e12c5d1SDavid du Colombier 	}
10393e12c5d1SDavid du Colombier }
10403e12c5d1SDavid du Colombier 
10413e12c5d1SDavid du Colombier /*
10423e12c5d1SDavid du Colombier  *  Set up a list of default networks by looking for
10433e12c5d1SDavid du Colombier  *  /net/ * /clone.
10443e12c5d1SDavid du Colombier  */
10453e12c5d1SDavid du Colombier void
10467dd7cddfSDavid du Colombier netinit(int background)
10473e12c5d1SDavid du Colombier {
10487dd7cddfSDavid du Colombier 	char clone[Maxpath];
10493e12c5d1SDavid du Colombier 	Network *np;
10507dd7cddfSDavid du Colombier 	static int working;
10517dd7cddfSDavid du Colombier 
10527dd7cddfSDavid du Colombier 	if(background){
10537dd7cddfSDavid du Colombier 		switch(rfork(RFPROC|RFNOTEG|RFMEM|RFNOWAIT)){
10547dd7cddfSDavid du Colombier 		case 0:
10557dd7cddfSDavid du Colombier 			break;
10567dd7cddfSDavid du Colombier 		default:
10577dd7cddfSDavid du Colombier 			return;
10587dd7cddfSDavid du Colombier 		}
10597dd7cddfSDavid du Colombier 		lock(&netlock);
10607dd7cddfSDavid du Colombier 	}
10613e12c5d1SDavid du Colombier 
10623e12c5d1SDavid du Colombier 	/* add the mounted networks to the default list */
10633e12c5d1SDavid du Colombier 	for(np = network; np->net; np++){
10647dd7cddfSDavid du Colombier 		if(np->considered)
10657dd7cddfSDavid du Colombier 			continue;
10667dd7cddfSDavid du Colombier 		snprint(clone, sizeof(clone), "%s/%s/clone", mntpt, np->net);
10679a747e4fSDavid du Colombier 		if(access(clone, AEXIST) < 0)
10683e12c5d1SDavid du Colombier 			continue;
10693e12c5d1SDavid du Colombier 		if(netlist)
10703e12c5d1SDavid du Colombier 			last->next = np;
10713e12c5d1SDavid du Colombier 		else
10723e12c5d1SDavid du Colombier 			netlist = np;
10733e12c5d1SDavid du Colombier 		last = np;
10743e12c5d1SDavid du Colombier 		np->next = 0;
10757dd7cddfSDavid du Colombier 		np->considered = 1;
10763e12c5d1SDavid du Colombier 	}
10773e12c5d1SDavid du Colombier 
10787dd7cddfSDavid du Colombier 	/* find out what our ip address is */
10797dd7cddfSDavid du Colombier 	readipinterfaces();
10803e12c5d1SDavid du Colombier 
10817dd7cddfSDavid du Colombier 	/* set the system name if we need to, these says ip is all we have */
10823e12c5d1SDavid du Colombier 	ipid();
10833e12c5d1SDavid du Colombier 
1084219b2ee8SDavid du Colombier 	if(debug)
10857dd7cddfSDavid du Colombier 		syslog(0, logfile, "mysysname %s eaddr %s ipaddr %s ipa %I\n",
108695a264b3SDavid du Colombier 			mysysname?mysysname:"???", eaddr, ipaddr, ipa);
10877dd7cddfSDavid du Colombier 
10887dd7cddfSDavid du Colombier 	if(background){
10897dd7cddfSDavid du Colombier 		unlock(&netlock);
10907dd7cddfSDavid du Colombier 		_exits(0);
10917dd7cddfSDavid du Colombier 	}
10923e12c5d1SDavid du Colombier }
10933e12c5d1SDavid du Colombier 
10943e12c5d1SDavid du Colombier /*
10953e12c5d1SDavid du Colombier  *  add networks to the standard list
10963e12c5d1SDavid du Colombier  */
10973e12c5d1SDavid du Colombier void
10983e12c5d1SDavid du Colombier netadd(char *p)
10993e12c5d1SDavid du Colombier {
11003e12c5d1SDavid du Colombier 	Network *np;
11013e12c5d1SDavid du Colombier 	char *field[12];
11023e12c5d1SDavid du Colombier 	int i, n;
11033e12c5d1SDavid du Colombier 
11047dd7cddfSDavid du Colombier 	n = getfields(p, field, 12, 1, " ");
11053e12c5d1SDavid du Colombier 	for(i = 0; i < n; i++){
11063e12c5d1SDavid du Colombier 		for(np = network; np->net; np++){
11073e12c5d1SDavid du Colombier 			if(strcmp(field[i], np->net) != 0)
11083e12c5d1SDavid du Colombier 				continue;
11097dd7cddfSDavid du Colombier 			if(np->considered)
11103e12c5d1SDavid du Colombier 				break;
11113e12c5d1SDavid du Colombier 			if(netlist)
11123e12c5d1SDavid du Colombier 				last->next = np;
11133e12c5d1SDavid du Colombier 			else
11143e12c5d1SDavid du Colombier 				netlist = np;
11153e12c5d1SDavid du Colombier 			last = np;
11163e12c5d1SDavid du Colombier 			np->next = 0;
11177dd7cddfSDavid du Colombier 			np->considered = 1;
11183e12c5d1SDavid du Colombier 		}
11193e12c5d1SDavid du Colombier 	}
11203e12c5d1SDavid du Colombier }
11213e12c5d1SDavid du Colombier 
112280ee5cbfSDavid du Colombier int
112380ee5cbfSDavid du Colombier lookforproto(Ndbtuple *t, char *proto)
112480ee5cbfSDavid du Colombier {
112580ee5cbfSDavid du Colombier 	for(; t != nil; t = t->entry)
112680ee5cbfSDavid du Colombier 		if(strcmp(t->attr, "proto") == 0 && strcmp(t->val, proto) == 0)
112780ee5cbfSDavid du Colombier 			return 1;
112880ee5cbfSDavid du Colombier 	return 0;
112980ee5cbfSDavid du Colombier }
113080ee5cbfSDavid du Colombier 
1131219b2ee8SDavid du Colombier /*
11323e12c5d1SDavid du Colombier  *  lookup a request.  the network "net" means we should pick the
11333e12c5d1SDavid du Colombier  *  best network to get there.
11343e12c5d1SDavid du Colombier  */
11353e12c5d1SDavid du Colombier int
113680ee5cbfSDavid du Colombier lookup(Mfile *mf)
11373e12c5d1SDavid du Colombier {
113880ee5cbfSDavid du Colombier 	Network *np;
1139219b2ee8SDavid du Colombier 	char *cp;
1140219b2ee8SDavid du Colombier 	Ndbtuple *nt, *t;
1141219b2ee8SDavid du Colombier 	char reply[Maxreply];
114280ee5cbfSDavid du Colombier 	int i, rv;
114380ee5cbfSDavid du Colombier 	int hack;
11443e12c5d1SDavid du Colombier 
11453e12c5d1SDavid du Colombier 	/* open up the standard db files */
11463e12c5d1SDavid du Colombier 	if(db == 0)
11477dd7cddfSDavid du Colombier 		ndbinit();
11483e12c5d1SDavid du Colombier 	if(db == 0)
114980ee5cbfSDavid du Colombier 		error("can't open mf->network database\n");
11503e12c5d1SDavid du Colombier 
115180ee5cbfSDavid du Colombier 	rv = 0;
115280ee5cbfSDavid du Colombier 
115380ee5cbfSDavid du Colombier 	if(mf->net == nil)
115480ee5cbfSDavid du Colombier 		return 0;	/* must have been a genquery */
115580ee5cbfSDavid du Colombier 
115680ee5cbfSDavid du Colombier 	if(strcmp(mf->net, "net") == 0){
11573e12c5d1SDavid du Colombier 		/*
11583e12c5d1SDavid du Colombier 		 *  go through set of default nets
11593e12c5d1SDavid du Colombier 		 */
116080ee5cbfSDavid du Colombier 		for(np = mf->nextnet; np; np = np->next){
116180ee5cbfSDavid du Colombier 			nt = (*np->lookup)(np, mf->host, mf->serv, 1);
116280ee5cbfSDavid du Colombier 			if(nt == nil)
1163219b2ee8SDavid du Colombier 				continue;
116480ee5cbfSDavid du Colombier 			hack = np->fasttimeouthack && !lookforproto(nt, np->net);
116580ee5cbfSDavid du Colombier 			for(t = nt; mf->nreply < Nreply && t; t = t->entry){
116680ee5cbfSDavid du Colombier 				cp = (*np->trans)(t, np, mf->serv, mf->rem, hack);
1167219b2ee8SDavid du Colombier 				if(cp){
116880ee5cbfSDavid du Colombier 					/* avoid duplicates */
116980ee5cbfSDavid du Colombier 					for(i = 0; i < mf->nreply; i++)
117080ee5cbfSDavid du Colombier 						if(strcmp(mf->reply[i], cp) == 0)
117180ee5cbfSDavid du Colombier 							break;
117280ee5cbfSDavid du Colombier 					if(i == mf->nreply){
117380ee5cbfSDavid du Colombier 						/* save the reply */
1174219b2ee8SDavid du Colombier 						mf->replylen[mf->nreply] = strlen(cp);
1175219b2ee8SDavid du Colombier 						mf->reply[mf->nreply++] = cp;
117680ee5cbfSDavid du Colombier 						rv++;
1177219b2ee8SDavid du Colombier 					}
1178219b2ee8SDavid du Colombier 				}
1179219b2ee8SDavid du Colombier 			}
1180219b2ee8SDavid du Colombier 			ndbfree(nt);
118180ee5cbfSDavid du Colombier 			np = np->next;
118280ee5cbfSDavid du Colombier 			break;
118380ee5cbfSDavid du Colombier 		}
118480ee5cbfSDavid du Colombier 		mf->nextnet = np;
118580ee5cbfSDavid du Colombier 		return rv;
118680ee5cbfSDavid du Colombier 	}
118780ee5cbfSDavid du Colombier 
118880ee5cbfSDavid du Colombier 	/*
118980ee5cbfSDavid du Colombier 	 *  if not /net, we only get one lookup
119080ee5cbfSDavid du Colombier 	 */
119180ee5cbfSDavid du Colombier 	if(mf->nreply != 0)
1192219b2ee8SDavid du Colombier 		return 0;
119380ee5cbfSDavid du Colombier 	/*
119480ee5cbfSDavid du Colombier 	 *  look for a specific network
119580ee5cbfSDavid du Colombier 	 */
119695a264b3SDavid du Colombier 	for(np = netlist; np && np->net != nil; np++){
119780ee5cbfSDavid du Colombier 		if(np->fasttimeouthack)
119880ee5cbfSDavid du Colombier 			continue;
119980ee5cbfSDavid du Colombier 		if(strcmp(np->net, mf->net) == 0)
120080ee5cbfSDavid du Colombier 			break;
120180ee5cbfSDavid du Colombier 	}
120280ee5cbfSDavid du Colombier 
120395a264b3SDavid du Colombier 	if(np && np->net != nil){
120480ee5cbfSDavid du Colombier 		/*
120580ee5cbfSDavid du Colombier 		 *  known network
120680ee5cbfSDavid du Colombier 		 */
120780ee5cbfSDavid du Colombier 		nt = (*np->lookup)(np, mf->host, mf->serv, 1);
120880ee5cbfSDavid du Colombier 		for(t = nt; mf->nreply < Nreply && t; t = t->entry){
120980ee5cbfSDavid du Colombier 			cp = (*np->trans)(t, np, mf->serv, mf->rem, 0);
121080ee5cbfSDavid du Colombier 			if(cp){
121180ee5cbfSDavid du Colombier 				mf->replylen[mf->nreply] = strlen(cp);
121280ee5cbfSDavid du Colombier 				mf->reply[mf->nreply++] = cp;
121380ee5cbfSDavid du Colombier 				rv++;
121480ee5cbfSDavid du Colombier 			}
121580ee5cbfSDavid du Colombier 		}
121680ee5cbfSDavid du Colombier 		ndbfree(nt);
121780ee5cbfSDavid du Colombier 		return rv;
12183e12c5d1SDavid du Colombier 	} else {
12193e12c5d1SDavid du Colombier 		/*
1220219b2ee8SDavid du Colombier 		 *  not a known network, don't translate host or service
12213e12c5d1SDavid du Colombier 		 */
122280ee5cbfSDavid du Colombier 		if(mf->serv)
12237dd7cddfSDavid du Colombier 			snprint(reply, sizeof(reply), "%s/%s/clone %s!%s",
122480ee5cbfSDavid du Colombier 				mntpt, mf->net, mf->host, mf->serv);
1225bd389b36SDavid du Colombier 		else
12267dd7cddfSDavid du Colombier 			snprint(reply, sizeof(reply), "%s/%s/clone %s",
122780ee5cbfSDavid du Colombier 				mntpt, mf->net, mf->host);
1228219b2ee8SDavid du Colombier 		mf->reply[0] = strdup(reply);
1229219b2ee8SDavid du Colombier 		mf->replylen[0] = strlen(reply);
1230219b2ee8SDavid du Colombier 		mf->nreply = 1;
123180ee5cbfSDavid du Colombier 		return 1;
12323e12c5d1SDavid du Colombier 	}
12333e12c5d1SDavid du Colombier }
12343e12c5d1SDavid du Colombier 
12353e12c5d1SDavid du Colombier /*
12363e12c5d1SDavid du Colombier  *  translate an ip service name into a port number.  If it's a numeric port
12373e12c5d1SDavid du Colombier  *  number, look for restricted access.
12383e12c5d1SDavid du Colombier  *
12393e12c5d1SDavid du Colombier  *  the service '*' needs no translation.
12403e12c5d1SDavid du Colombier  */
12413e12c5d1SDavid du Colombier char*
124295a264b3SDavid du Colombier ipserv(Network *np, char *name, char *buf, int blen)
12433e12c5d1SDavid du Colombier {
12443e12c5d1SDavid du Colombier 	char *p;
12453e12c5d1SDavid du Colombier 	int alpha = 0;
12463e12c5d1SDavid du Colombier 	int restr = 0;
124795a264b3SDavid du Colombier 	char port[10];
12483e12c5d1SDavid du Colombier 	Ndbtuple *t, *nt;
12493e12c5d1SDavid du Colombier 	Ndbs s;
12503e12c5d1SDavid du Colombier 
12513e12c5d1SDavid du Colombier 	/* '*' means any service */
12523e12c5d1SDavid du Colombier 	if(strcmp(name, "*")==0){
12533e12c5d1SDavid du Colombier 		strcpy(buf, name);
12543e12c5d1SDavid du Colombier 		return buf;
12553e12c5d1SDavid du Colombier 	}
12563e12c5d1SDavid du Colombier 
12573e12c5d1SDavid du Colombier 	/*  see if it's numeric or symbolic */
12583e12c5d1SDavid du Colombier 	port[0] = 0;
12593e12c5d1SDavid du Colombier 	for(p = name; *p; p++){
12603e12c5d1SDavid du Colombier 		if(isdigit(*p))
12619a747e4fSDavid du Colombier 			{}
12623e12c5d1SDavid du Colombier 		else if(isalpha(*p) || *p == '-' || *p == '$')
12633e12c5d1SDavid du Colombier 			alpha = 1;
12643e12c5d1SDavid du Colombier 		else
12653e12c5d1SDavid du Colombier 			return 0;
12663e12c5d1SDavid du Colombier 	}
126757837e0bSDavid du Colombier 	t = nil;
126857837e0bSDavid du Colombier 	p = nil;
12693e12c5d1SDavid du Colombier 	if(alpha){
127057837e0bSDavid du Colombier 		p = ndbgetvalue(db, &s, np->net, name, "port", &t);
1271b7327ca2SDavid du Colombier 		if(p == nil)
1272b7327ca2SDavid du Colombier 			return 0;
12733e12c5d1SDavid du Colombier 	} else {
12743cc1eb97SDavid du Colombier 		/* look up only for tcp ports < 1024 to get the restricted
12753cc1eb97SDavid du Colombier 		 * attribute
12763cc1eb97SDavid du Colombier 		 */
12773cc1eb97SDavid du Colombier 		if(atoi(name) < 1024 && strcmp(np->net, "tcp") == 0)
127857837e0bSDavid du Colombier 			p = ndbgetvalue(db, &s, "port", name, "port", &t);
127957837e0bSDavid du Colombier 		if(p == nil)
128057837e0bSDavid du Colombier 			p = strdup(name);
12813e12c5d1SDavid du Colombier 	}
12823e12c5d1SDavid du Colombier 
12833e12c5d1SDavid du Colombier 	if(t){
12843e12c5d1SDavid du Colombier 		for(nt = t; nt; nt = nt->entry)
12853e12c5d1SDavid du Colombier 			if(strcmp(nt->attr, "restricted") == 0)
12863e12c5d1SDavid du Colombier 				restr = 1;
12873e12c5d1SDavid du Colombier 		ndbfree(t);
12883e12c5d1SDavid du Colombier 	}
128957837e0bSDavid du Colombier 	snprint(buf, blen, "%s%s", p, restr ? "!r" : "");
129057837e0bSDavid du Colombier 	free(p);
129157837e0bSDavid du Colombier 
12923e12c5d1SDavid du Colombier 	return buf;
12933e12c5d1SDavid du Colombier }
12943e12c5d1SDavid du Colombier 
12953e12c5d1SDavid du Colombier /*
12967dd7cddfSDavid du Colombier  *  lookup an ip attribute
12973e12c5d1SDavid du Colombier  */
12987dd7cddfSDavid du Colombier int
129995a264b3SDavid du Colombier ipattrlookup(Ndb *db, char *ipa, char *attr, char *val, int vlen)
13003e12c5d1SDavid du Colombier {
13013e12c5d1SDavid du Colombier 
13027dd7cddfSDavid du Colombier 	Ndbtuple *t, *nt;
13037dd7cddfSDavid du Colombier 	char *alist[2];
13043e12c5d1SDavid du Colombier 
13057dd7cddfSDavid du Colombier 	alist[0] = attr;
13067dd7cddfSDavid du Colombier 	t = ndbipinfo(db, "ip", ipa, alist, 1);
13077dd7cddfSDavid du Colombier 	if(t == nil)
13087dd7cddfSDavid du Colombier 		return 0;
13099a747e4fSDavid du Colombier 	for(nt = t; nt != nil; nt = nt->entry){
13107dd7cddfSDavid du Colombier 		if(strcmp(nt->attr, attr) == 0){
131195a264b3SDavid du Colombier 			nstrcpy(val, nt->val, vlen);
13123e12c5d1SDavid du Colombier 			ndbfree(t);
13137dd7cddfSDavid du Colombier 			return 1;
1314219b2ee8SDavid du Colombier 		}
13159a747e4fSDavid du Colombier 	}
13163e12c5d1SDavid du Colombier 
13177dd7cddfSDavid du Colombier 	/* we shouldn't get here */
13183e12c5d1SDavid du Colombier 	ndbfree(t);
13197dd7cddfSDavid du Colombier 	return 0;
13203e12c5d1SDavid du Colombier }
13213e12c5d1SDavid du Colombier 
13223e12c5d1SDavid du Colombier /*
13233e12c5d1SDavid du Colombier  *  lookup (and translate) an ip destination
13243e12c5d1SDavid du Colombier  */
1325219b2ee8SDavid du Colombier Ndbtuple*
1326219b2ee8SDavid du Colombier iplookup(Network *np, char *host, char *serv, int nolookup)
13273e12c5d1SDavid du Colombier {
13289dfc0cb2SDavid du Colombier 	char *attr, *dnsname;
13297dd7cddfSDavid du Colombier 	Ndbtuple *t, *nt;
13303e12c5d1SDavid du Colombier 	Ndbs s;
133195a264b3SDavid du Colombier 	char ts[Maxservice];
133295a264b3SDavid du Colombier 	char dollar[Maxhost];
13337dd7cddfSDavid du Colombier 	uchar ip[IPaddrlen];
13347dd7cddfSDavid du Colombier 	uchar net[IPaddrlen];
13357dd7cddfSDavid du Colombier 	uchar tnet[IPaddrlen];
13367dd7cddfSDavid du Colombier 	Ipifc *ifc;
13379a747e4fSDavid du Colombier 	Iplifc *lifc;
13383e12c5d1SDavid du Colombier 
1339219b2ee8SDavid du Colombier 	USED(nolookup);
1340219b2ee8SDavid du Colombier 
13413e12c5d1SDavid du Colombier 	/*
13423e12c5d1SDavid du Colombier 	 *  start with the service since it's the most likely to fail
13433e12c5d1SDavid du Colombier 	 *  and costs the least
13443e12c5d1SDavid du Colombier 	 */
13457dd7cddfSDavid du Colombier 	werrstr("can't translate address");
134695a264b3SDavid du Colombier 	if(serv==0 || ipserv(np, serv, ts, sizeof ts) == 0){
1347271b8d73SDavid du Colombier 		werrstr("can't translate service");
1348219b2ee8SDavid du Colombier 		return 0;
13497dd7cddfSDavid du Colombier 	}
13503e12c5d1SDavid du Colombier 
13513e12c5d1SDavid du Colombier 	/* for dial strings with no host */
1352219b2ee8SDavid du Colombier 	if(strcmp(host, "*") == 0)
135395a264b3SDavid du Colombier 		return ndbnew("ip", "*");
13543e12c5d1SDavid du Colombier 
13553e12c5d1SDavid du Colombier 	/*
13567dd7cddfSDavid du Colombier 	 *  hack till we go v6 :: = 0.0.0.0
13577dd7cddfSDavid du Colombier 	 */
13587dd7cddfSDavid du Colombier 	if(strcmp("::", host) == 0)
135995a264b3SDavid du Colombier 		return ndbnew("ip", "*");
13607dd7cddfSDavid du Colombier 
13617dd7cddfSDavid du Colombier 	/*
13623e12c5d1SDavid du Colombier 	 *  '$' means the rest of the name is an attribute that we
13633e12c5d1SDavid du Colombier 	 *  need to search for
13643e12c5d1SDavid du Colombier 	 */
13653e12c5d1SDavid du Colombier 	if(*host == '$'){
136695a264b3SDavid du Colombier 		if(ipattrlookup(db, ipaddr, host+1, dollar, sizeof dollar))
13673e12c5d1SDavid du Colombier 			host = dollar;
13683e12c5d1SDavid du Colombier 	}
13693e12c5d1SDavid du Colombier 
13703e12c5d1SDavid du Colombier 	/*
13717dd7cddfSDavid du Colombier 	 *  turn '[ip address]' into just 'ip address'
13727dd7cddfSDavid du Colombier 	 */
13737dd7cddfSDavid du Colombier 	if(*host == '[' && host[strlen(host)-1] == ']'){
13747dd7cddfSDavid du Colombier 		host++;
13757dd7cddfSDavid du Colombier 		host[strlen(host)-1] = 0;
13767dd7cddfSDavid du Colombier 	}
13777dd7cddfSDavid du Colombier 
13787dd7cddfSDavid du Colombier 	/*
13793e12c5d1SDavid du Colombier 	 *  just accept addresses
13803e12c5d1SDavid du Colombier 	 */
1381219b2ee8SDavid du Colombier 	attr = ipattr(host);
1382219b2ee8SDavid du Colombier 	if(strcmp(attr, "ip") == 0)
138395a264b3SDavid du Colombier 		return ndbnew("ip", host);
13843e12c5d1SDavid du Colombier 
13853e12c5d1SDavid du Colombier 	/*
13863e12c5d1SDavid du Colombier 	 *  give the domain name server the first opportunity to
1387bd389b36SDavid du Colombier 	 *  resolve domain names.  if that fails try the database.
13883e12c5d1SDavid du Colombier 	 */
13893e12c5d1SDavid du Colombier 	t = 0;
1390271b8d73SDavid du Colombier 	werrstr("can't translate address");
13913e12c5d1SDavid du Colombier 	if(strcmp(attr, "dom") == 0)
13927dd7cddfSDavid du Colombier 		t = dnsiplookup(host, &s);
13933e12c5d1SDavid du Colombier 	if(t == 0)
139457837e0bSDavid du Colombier 		free(ndbgetvalue(db, &s, attr, host, "ip", &t));
13959dfc0cb2SDavid du Colombier 	if(t == 0){
13969dfc0cb2SDavid du Colombier 		dnsname = ndbgetvalue(db, &s, attr, host, "dom", nil);
13979dfc0cb2SDavid du Colombier 		if(dnsname){
13989dfc0cb2SDavid du Colombier 			t = dnsiplookup(dnsname, &s);
13999dfc0cb2SDavid du Colombier 			free(dnsname);
14009dfc0cb2SDavid du Colombier 		}
14019dfc0cb2SDavid du Colombier 	}
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 
17528a2c5ad0SDavid du Colombier 	if(n < 1)
17537dd7cddfSDavid du Colombier 		return "bad query";
17547dd7cddfSDavid du Colombier 
17558a2c5ad0SDavid du Colombier 	/* get search attribute=value, or assume ip=myipaddr */
17568a2c5ad0SDavid du Colombier 	attr = *list;
17578a2c5ad0SDavid du Colombier 	if((val = strchr(attr, '=')) != nil){
17587dd7cddfSDavid du Colombier 		*val++ = 0;
17598a2c5ad0SDavid du Colombier 		list++;
17608a2c5ad0SDavid du Colombier 		n--;
17618a2c5ad0SDavid du Colombier 	}else{
17628a2c5ad0SDavid du Colombier 		attr = "ip";
17638a2c5ad0SDavid du Colombier 		val = ipaddr;
17648a2c5ad0SDavid du Colombier 	}
17658a2c5ad0SDavid du Colombier 
17668a2c5ad0SDavid du Colombier 	if(n < 1)
17678a2c5ad0SDavid du Colombier 		return "bad query";
17687dd7cddfSDavid du Colombier 
17697dd7cddfSDavid du Colombier 	/*
17707dd7cddfSDavid du Colombier 	 *  don't let ndbipinfo resolve the addresses, we're
17717dd7cddfSDavid du Colombier 	 *  better at it.
17727dd7cddfSDavid du Colombier 	 */
17737dd7cddfSDavid du Colombier 	nresolve = 0;
17747dd7cddfSDavid du Colombier 	for(i = 0; i < n; i++)
1775107aedb4SDavid du Colombier 		if(*list[i] == '@'){		/* @attr=val ? */
17767dd7cddfSDavid du Colombier 			list[i]++;
1777107aedb4SDavid du Colombier 			resolve[i] = 1;		/* we'll resolve it */
17787dd7cddfSDavid du Colombier 			nresolve++;
17797dd7cddfSDavid du Colombier 		} else
17807dd7cddfSDavid du Colombier 			resolve[i] = 0;
17817dd7cddfSDavid du Colombier 
17827dd7cddfSDavid du Colombier 	t = ndbipinfo(db, attr, val, list, n);
17837dd7cddfSDavid du Colombier 	if(t == nil)
17847dd7cddfSDavid du Colombier 		return "no match";
17857dd7cddfSDavid du Colombier 
17867dd7cddfSDavid du Colombier 	if(nresolve != 0){
17877dd7cddfSDavid du Colombier 		for(l = &t; *l != nil;){
17887dd7cddfSDavid du Colombier 			nt = *l;
17897dd7cddfSDavid du Colombier 
17907dd7cddfSDavid du Colombier 			/* already an address? */
17917dd7cddfSDavid du Colombier 			if(strcmp(ipattr(nt->val), "ip") == 0){
17927dd7cddfSDavid du Colombier 				l = &(*l)->entry;
17937dd7cddfSDavid du Colombier 				continue;
17947dd7cddfSDavid du Colombier 			}
17957dd7cddfSDavid du Colombier 
17967dd7cddfSDavid du Colombier 			/* user wants it resolved? */
17977dd7cddfSDavid du Colombier 			for(i = 0; i < n; i++)
17987dd7cddfSDavid du Colombier 				if(strcmp(list[i], nt->attr) == 0)
17997dd7cddfSDavid du Colombier 					break;
18007dd7cddfSDavid du Colombier 			if(i >= n || resolve[i] == 0){
18017dd7cddfSDavid du Colombier 				l = &(*l)->entry;
18027dd7cddfSDavid du Colombier 				continue;
18037dd7cddfSDavid du Colombier 			}
18047dd7cddfSDavid du Colombier 
18057dd7cddfSDavid du Colombier 			/* resolve address and replace entry */
18067dd7cddfSDavid du Colombier 			*l = ipresolve(nt->attr, nt->val);
18077dd7cddfSDavid du Colombier 			while(*l != nil)
18087dd7cddfSDavid du Colombier 				l = &(*l)->entry;
18097dd7cddfSDavid du Colombier 			*l = nt->entry;
18107dd7cddfSDavid du Colombier 
18117dd7cddfSDavid du Colombier 			nt->entry = nil;
18127dd7cddfSDavid du Colombier 			ndbfree(nt);
18137dd7cddfSDavid du Colombier 		}
18147dd7cddfSDavid du Colombier 	}
18157dd7cddfSDavid du Colombier 
18167dd7cddfSDavid du Colombier 	/* make it all one line */
18177dd7cddfSDavid du Colombier 	for(nt = t; nt != nil; nt = nt->entry){
18187dd7cddfSDavid du Colombier 		if(nt->entry == nil)
18197dd7cddfSDavid du Colombier 			nt->line = t;
18207dd7cddfSDavid du Colombier 		else
18217dd7cddfSDavid du Colombier 			nt->line = nt->entry;
18227dd7cddfSDavid du Colombier 	}
18237dd7cddfSDavid du Colombier 
18247dd7cddfSDavid du Colombier 	qreply(mf, t);
18257dd7cddfSDavid du Colombier 
18267dd7cddfSDavid du Colombier 	return nil;
18277dd7cddfSDavid du Colombier }
18287dd7cddfSDavid du Colombier 
18297dd7cddfSDavid du Colombier void*
18307dd7cddfSDavid du Colombier emalloc(int size)
18317dd7cddfSDavid du Colombier {
18327dd7cddfSDavid du Colombier 	void *x;
18337dd7cddfSDavid du Colombier 
18347dd7cddfSDavid du Colombier 	x = malloc(size);
18357dd7cddfSDavid du Colombier 	if(x == nil)
18367dd7cddfSDavid du Colombier 		abort();
18377dd7cddfSDavid du Colombier 	memset(x, 0, size);
18387dd7cddfSDavid du Colombier 	return x;
18397dd7cddfSDavid du Colombier }
18409a747e4fSDavid du Colombier 
18419a747e4fSDavid du Colombier char*
18429a747e4fSDavid du Colombier estrdup(char *s)
18439a747e4fSDavid du Colombier {
18449a747e4fSDavid du Colombier 	int size;
18459a747e4fSDavid du Colombier 	char *p;
18469a747e4fSDavid du Colombier 
18479a747e4fSDavid du Colombier 	size = strlen(s)+1;
18489a747e4fSDavid du Colombier 	p = malloc(size);
18499a747e4fSDavid du Colombier 	if(p == nil)
18509a747e4fSDavid du Colombier 		abort();
18519a747e4fSDavid du Colombier 	memmove(p, s, size);
18529a747e4fSDavid du Colombier 	return p;
18539a747e4fSDavid du Colombier }
1854