xref: /plan9/sys/src/cmd/ndb/cs.c (revision 3cc1eb97658fd09e8fb54db00a4791fda3aa0d0d)
13e12c5d1SDavid du Colombier #include <u.h>
23e12c5d1SDavid du Colombier #include <libc.h>
3219b2ee8SDavid du Colombier #include <auth.h>
43e12c5d1SDavid du Colombier #include <fcall.h>
53e12c5d1SDavid du Colombier #include <bio.h>
63e12c5d1SDavid du Colombier #include <ctype.h>
73e12c5d1SDavid du Colombier #include <ndb.h>
83e12c5d1SDavid du Colombier #include <ip.h>
93e12c5d1SDavid du Colombier 
103e12c5d1SDavid du Colombier enum
113e12c5d1SDavid du Colombier {
1280ee5cbfSDavid du Colombier 	Nreply=			20,
133e12c5d1SDavid du Colombier 	Maxreply=		256,
147dd7cddfSDavid du Colombier 	Maxrequest=		128,
157dd7cddfSDavid du Colombier 	Maxpath=		128,
169a747e4fSDavid du Colombier 	Maxfdata=		8192,
173e12c5d1SDavid du Colombier 
189a747e4fSDavid du Colombier 	Qdir=			0,
193e12c5d1SDavid du Colombier 	Qcs=			1,
203e12c5d1SDavid du Colombier };
213e12c5d1SDavid du Colombier 
223e12c5d1SDavid du Colombier typedef struct Mfile	Mfile;
23219b2ee8SDavid du Colombier typedef struct Mlist	Mlist;
243e12c5d1SDavid du Colombier typedef struct Network	Network;
257dd7cddfSDavid du Colombier typedef struct Flushreq	Flushreq;
267dd7cddfSDavid du Colombier typedef struct Job	Job;
273e12c5d1SDavid du Colombier 
283e12c5d1SDavid du Colombier int vers;		/* incremented each clone/attach */
293e12c5d1SDavid du Colombier 
303e12c5d1SDavid du Colombier struct Mfile
313e12c5d1SDavid du Colombier {
323e12c5d1SDavid du Colombier 	int		busy;
33219b2ee8SDavid du Colombier 
349a747e4fSDavid du Colombier 	char		*user;
353e12c5d1SDavid du Colombier 	Qid		qid;
363e12c5d1SDavid du Colombier 	int		fid;
373e12c5d1SDavid du Colombier 
3880ee5cbfSDavid du Colombier 	/*
3980ee5cbfSDavid du Colombier 	 *  current request
4080ee5cbfSDavid du Colombier 	 */
4180ee5cbfSDavid du Colombier 	char		*net;
4280ee5cbfSDavid du Colombier 	char		*host;
4380ee5cbfSDavid du Colombier 	char		*serv;
4480ee5cbfSDavid du Colombier 	char		*rem;
4580ee5cbfSDavid du Colombier 
4680ee5cbfSDavid du Colombier 	/*
4780ee5cbfSDavid du Colombier 	 *  result of the last lookup
4880ee5cbfSDavid du Colombier 	 */
4980ee5cbfSDavid du Colombier 	Network		*nextnet;
50219b2ee8SDavid du Colombier 	int		nreply;
51219b2ee8SDavid du Colombier 	char		*reply[Nreply];
52219b2ee8SDavid du Colombier 	int		replylen[Nreply];
53219b2ee8SDavid du Colombier };
54219b2ee8SDavid du Colombier 
55219b2ee8SDavid du Colombier struct Mlist
56219b2ee8SDavid du Colombier {
57219b2ee8SDavid du Colombier 	Mlist	*next;
58219b2ee8SDavid du Colombier 	Mfile	mf;
593e12c5d1SDavid du Colombier };
603e12c5d1SDavid du Colombier 
619a747e4fSDavid du Colombier 
627dd7cddfSDavid du Colombier //
637dd7cddfSDavid du Colombier //  active requests
647dd7cddfSDavid du Colombier //
657dd7cddfSDavid du Colombier struct Job
667dd7cddfSDavid du Colombier {
677dd7cddfSDavid du Colombier 	Job	*next;
687dd7cddfSDavid du Colombier 	int	flushed;
697dd7cddfSDavid du Colombier 	Fcall	request;
707dd7cddfSDavid du Colombier 	Fcall	reply;
717dd7cddfSDavid du Colombier };
727dd7cddfSDavid du Colombier Lock	joblock;
737dd7cddfSDavid du Colombier Job	*joblist;
747dd7cddfSDavid du Colombier 
75219b2ee8SDavid du Colombier Mlist	*mlist;
763e12c5d1SDavid du Colombier int	mfd[2];
773e12c5d1SDavid du Colombier int	debug;
787dd7cddfSDavid du Colombier int	paranoia;
793e12c5d1SDavid du Colombier jmp_buf	masterjmp;	/* return through here after a slave process has been created */
803e12c5d1SDavid du Colombier int	*isslave;	/* *isslave non-zero means this is a slave process */
81bd389b36SDavid du Colombier char	*dbfile;
827dd7cddfSDavid du Colombier Ndb	*db, *netdb;
833e12c5d1SDavid du Colombier 
849a747e4fSDavid du Colombier void	rversion(Job*);
857dd7cddfSDavid du Colombier void	rflush(Job*);
867dd7cddfSDavid du Colombier void	rattach(Job*, Mfile*);
877dd7cddfSDavid du Colombier char*	rwalk(Job*, Mfile*);
887dd7cddfSDavid du Colombier void	ropen(Job*, Mfile*);
897dd7cddfSDavid du Colombier void	rcreate(Job*, Mfile*);
907dd7cddfSDavid du Colombier void	rread(Job*, Mfile*);
917dd7cddfSDavid du Colombier void	rwrite(Job*, Mfile*);
927dd7cddfSDavid du Colombier void	rclunk(Job*, Mfile*);
937dd7cddfSDavid du Colombier void	rremove(Job*, Mfile*);
947dd7cddfSDavid du Colombier void	rstat(Job*, Mfile*);
957dd7cddfSDavid du Colombier void	rwstat(Job*, Mfile*);
969a747e4fSDavid du Colombier void	rauth(Job*);
977dd7cddfSDavid du Colombier void	sendmsg(Job*, char*);
983e12c5d1SDavid du Colombier void	error(char*);
997dd7cddfSDavid du Colombier void	mountinit(char*, char*);
1003e12c5d1SDavid du Colombier void	io(void);
1017dd7cddfSDavid du Colombier void	ndbinit(void);
1027dd7cddfSDavid du Colombier void	netinit(int);
1033e12c5d1SDavid du Colombier void	netadd(char*);
104219b2ee8SDavid du Colombier char	*genquery(Mfile*, char*);
1057dd7cddfSDavid du Colombier char*	ipinfoquery(Mfile*, char**, int);
106bd389b36SDavid du Colombier int	needproto(Network*, Ndbtuple*);
1079a747e4fSDavid du Colombier int	lookup(Mfile*);
1083e12c5d1SDavid du Colombier Ndbtuple*	reorder(Ndbtuple*, Ndbtuple*);
1097dd7cddfSDavid du Colombier void	ipid(void);
1107dd7cddfSDavid du Colombier void	readipinterfaces(void);
1117dd7cddfSDavid du Colombier void*	emalloc(int);
1129a747e4fSDavid du Colombier char*	estrdup(char*);
1137dd7cddfSDavid du Colombier Job*	newjob(void);
1147dd7cddfSDavid du Colombier void	freejob(Job*);
1157dd7cddfSDavid du Colombier void	setext(char*, int, char*);
11680ee5cbfSDavid du Colombier void	cleanmf(Mfile*);
1173e12c5d1SDavid du Colombier 
118bd389b36SDavid du Colombier extern void	paralloc(void);
119bd389b36SDavid du Colombier 
120bd389b36SDavid du Colombier Lock	dblock;		/* mutex on database operations */
1217dd7cddfSDavid du Colombier Lock	netlock;	/* mutex for netinit() */
122bd389b36SDavid du Colombier 
123219b2ee8SDavid du Colombier char	*logfile = "cs";
1247dd7cddfSDavid du Colombier char	*paranoiafile = "cs.paranoia";
125219b2ee8SDavid du Colombier 
1267dd7cddfSDavid du Colombier char	mntpt[Maxpath];
1277dd7cddfSDavid du Colombier char	netndb[Maxpath];
1287dd7cddfSDavid du Colombier 
12980ee5cbfSDavid du Colombier /*
13080ee5cbfSDavid du Colombier  *  Network specific translators
13180ee5cbfSDavid du Colombier  */
13280ee5cbfSDavid du Colombier Ndbtuple*	iplookup(Network*, char*, char*, int);
13380ee5cbfSDavid du Colombier char*		iptrans(Ndbtuple*, Network*, char*, char*, int);
13480ee5cbfSDavid du Colombier Ndbtuple*	telcolookup(Network*, char*, char*, int);
13580ee5cbfSDavid du Colombier char*		telcotrans(Ndbtuple*, Network*, char*, char*, int);
13680ee5cbfSDavid du Colombier Ndbtuple*	dnsiplookup(char*, Ndbs*);
13780ee5cbfSDavid du Colombier 
13880ee5cbfSDavid du Colombier struct Network
13980ee5cbfSDavid du Colombier {
14080ee5cbfSDavid du Colombier 	char		*net;
14180ee5cbfSDavid du Colombier 	Ndbtuple	*(*lookup)(Network*, char*, char*, int);
14280ee5cbfSDavid du Colombier 	char		*(*trans)(Ndbtuple*, Network*, char*, char*, int);
14380ee5cbfSDavid du Colombier 	int		considered;
14480ee5cbfSDavid du Colombier 	int		fasttimeouthack;
14580ee5cbfSDavid du Colombier 	Network		*next;
14680ee5cbfSDavid du Colombier };
14780ee5cbfSDavid du Colombier 
14880ee5cbfSDavid du Colombier enum
14980ee5cbfSDavid du Colombier {
15080ee5cbfSDavid du Colombier 	Nilfast,
15180ee5cbfSDavid du Colombier 	Ntcp,
15280ee5cbfSDavid du Colombier 	Nil,
15380ee5cbfSDavid du Colombier 	Nudp,
15480ee5cbfSDavid du Colombier 	Nicmp,
15580ee5cbfSDavid du Colombier 	Nrudp,
15680ee5cbfSDavid du Colombier 	Ntelco,
15780ee5cbfSDavid du Colombier };
15880ee5cbfSDavid du Colombier 
15980ee5cbfSDavid du Colombier /*
16080ee5cbfSDavid du Colombier  *  net doesn't apply to udp, icmp, or telco (for speed)
16180ee5cbfSDavid du Colombier  */
16280ee5cbfSDavid du Colombier Network network[] = {
16380ee5cbfSDavid du Colombier [Nilfast]	{ "il",		iplookup,	iptrans,	0, 1 },
16480ee5cbfSDavid du Colombier [Ntcp]		{ "tcp",	iplookup,	iptrans,	0, 0 },
16580ee5cbfSDavid du Colombier [Nil]		{ "il",		iplookup,	iptrans,	0, 0 },
16680ee5cbfSDavid du Colombier [Nudp]		{ "udp",	iplookup,	iptrans,	1, 0 },
16780ee5cbfSDavid du Colombier [Nicmp]		{ "icmp",	iplookup,	iptrans,	1, 0 },
16880ee5cbfSDavid du Colombier [Nrudp]		{ "rudp",	iplookup,	iptrans,	1, 0 },
16980ee5cbfSDavid du Colombier [Ntelco]	{ "telco",	telcolookup,	telcotrans,	1, 0 },
17080ee5cbfSDavid du Colombier 		{ 0 },
17180ee5cbfSDavid du Colombier };
17280ee5cbfSDavid du Colombier 
17380ee5cbfSDavid du Colombier Lock ipifclock;
17480ee5cbfSDavid du Colombier Ipifc *ipifcs;
17580ee5cbfSDavid du Colombier 
17680ee5cbfSDavid du Colombier char	eaddr[Ndbvlen];		/* ascii ethernet address */
17780ee5cbfSDavid du Colombier char	ipaddr[Ndbvlen];	/* ascii internet address */
17880ee5cbfSDavid du Colombier uchar	ipa[IPaddrlen];		/* binary internet address */
17980ee5cbfSDavid du Colombier char	mysysname[Ndbvlen];
18080ee5cbfSDavid du Colombier 
18180ee5cbfSDavid du Colombier Network *netlist;		/* networks ordered by preference */
18280ee5cbfSDavid du Colombier Network *last;
18380ee5cbfSDavid du Colombier 
1847dd7cddfSDavid du Colombier void
1857dd7cddfSDavid du Colombier usage(void)
1867dd7cddfSDavid du Colombier {
1877dd7cddfSDavid du Colombier 	fprint(2, "usage: %s [-d] [-f ndb-file] [-x netmtpt] [-n]\n", argv0);
1887dd7cddfSDavid du Colombier 	exits("usage");
1897dd7cddfSDavid du Colombier }
190219b2ee8SDavid du Colombier 
1913e12c5d1SDavid du Colombier void
1923e12c5d1SDavid du Colombier main(int argc, char *argv[])
1933e12c5d1SDavid du Colombier {
1947dd7cddfSDavid du Colombier 	char servefile[Maxpath];
195219b2ee8SDavid du Colombier 	int justsetname;
1967dd7cddfSDavid du Colombier 	char *p;
1977dd7cddfSDavid du Colombier 	char ext[Maxpath];
1983e12c5d1SDavid du Colombier 
199219b2ee8SDavid du Colombier 	justsetname = 0;
2007dd7cddfSDavid du Colombier 	setnetmtpt(mntpt, sizeof(mntpt), nil);
2017dd7cddfSDavid du Colombier 	ext[0] = 0;
2023e12c5d1SDavid du Colombier 	ARGBEGIN{
2033e12c5d1SDavid du Colombier 	case 'd':
2043e12c5d1SDavid du Colombier 		debug = 1;
2053e12c5d1SDavid du Colombier 		break;
206bd389b36SDavid du Colombier 	case 'f':
2077dd7cddfSDavid du Colombier 		p = ARGF();
2087dd7cddfSDavid du Colombier 		if(p == nil)
2097dd7cddfSDavid du Colombier 			usage();
2107dd7cddfSDavid du Colombier 		dbfile = p;
2117dd7cddfSDavid du Colombier 		break;
2127dd7cddfSDavid du Colombier 	case 'x':
2137dd7cddfSDavid du Colombier 		p = ARGF();
2147dd7cddfSDavid du Colombier 		if(p == nil)
2157dd7cddfSDavid du Colombier 			usage();
2167dd7cddfSDavid du Colombier 		setnetmtpt(mntpt, sizeof(mntpt), p);
2177dd7cddfSDavid du Colombier 		setext(ext, sizeof(ext), mntpt);
218bd389b36SDavid du Colombier 		break;
219219b2ee8SDavid du Colombier 	case 'n':
220219b2ee8SDavid du Colombier 		justsetname = 1;
221219b2ee8SDavid du Colombier 		break;
2223e12c5d1SDavid du Colombier 	}ARGEND
2233e12c5d1SDavid du Colombier 	USED(argc);
2243e12c5d1SDavid du Colombier 	USED(argv);
2253e12c5d1SDavid du Colombier 
2267dd7cddfSDavid du Colombier 	rfork(RFREND|RFNOTEG);
2277dd7cddfSDavid du Colombier 
2287dd7cddfSDavid du Colombier 	snprint(servefile, sizeof(servefile), "#s/cs%s", ext);
2297dd7cddfSDavid du Colombier 	snprint(netndb, sizeof(netndb), "%s/ndb", mntpt);
2307dd7cddfSDavid du Colombier 	unmount(servefile, mntpt);
2317dd7cddfSDavid du Colombier 	remove(servefile);
2327dd7cddfSDavid du Colombier 
2339a747e4fSDavid du Colombier 	fmtinstall('E', eipfmt);
2349a747e4fSDavid du Colombier 	fmtinstall('I', eipfmt);
2359a747e4fSDavid du Colombier 	fmtinstall('M', eipfmt);
2369a747e4fSDavid du Colombier 	fmtinstall('F', fcallfmt);
2377dd7cddfSDavid du Colombier 
2387dd7cddfSDavid du Colombier 	ndbinit();
2397dd7cddfSDavid du Colombier 	netinit(0);
2407dd7cddfSDavid du Colombier 
2417dd7cddfSDavid du Colombier 	if(!justsetname){
2427dd7cddfSDavid du Colombier 		mountinit(servefile, mntpt);
2437dd7cddfSDavid du Colombier 		io();
2447dd7cddfSDavid du Colombier 	}
245219b2ee8SDavid du Colombier 	exits(0);
246219b2ee8SDavid du Colombier }
247219b2ee8SDavid du Colombier 
2487dd7cddfSDavid du Colombier /*
2497dd7cddfSDavid du Colombier  *  if a mount point is specified, set the cs extention to be the mount point
2507dd7cddfSDavid du Colombier  *  with '_'s replacing '/'s
2517dd7cddfSDavid du Colombier  */
2527dd7cddfSDavid du Colombier void
2537dd7cddfSDavid du Colombier setext(char *ext, int n, char *p)
2547dd7cddfSDavid du Colombier {
2557dd7cddfSDavid du Colombier 	int i, c;
2563e12c5d1SDavid du Colombier 
2577dd7cddfSDavid du Colombier 	n--;
2587dd7cddfSDavid du Colombier 	for(i = 0; i < n; i++){
2597dd7cddfSDavid du Colombier 		c = p[i];
2607dd7cddfSDavid du Colombier 		if(c == 0)
2617dd7cddfSDavid du Colombier 			break;
2627dd7cddfSDavid du Colombier 		if(c == '/')
2637dd7cddfSDavid du Colombier 			c = '_';
2647dd7cddfSDavid du Colombier 		ext[i] = c;
2657dd7cddfSDavid du Colombier 	}
2667dd7cddfSDavid du Colombier 	ext[i] = 0;
2673e12c5d1SDavid du Colombier }
2683e12c5d1SDavid du Colombier 
2693e12c5d1SDavid du Colombier void
2707dd7cddfSDavid du Colombier mountinit(char *service, char *mntpt)
2713e12c5d1SDavid du Colombier {
2723e12c5d1SDavid du Colombier 	int f;
2733e12c5d1SDavid du Colombier 	int p[2];
2743e12c5d1SDavid du Colombier 	char buf[32];
2753e12c5d1SDavid du Colombier 
2763e12c5d1SDavid du Colombier 	if(pipe(p) < 0)
2773e12c5d1SDavid du Colombier 		error("pipe failed");
278219b2ee8SDavid du Colombier 	switch(rfork(RFFDG|RFPROC|RFNAMEG)){
2793e12c5d1SDavid du Colombier 	case 0:
280219b2ee8SDavid du Colombier 		close(p[1]);
2813e12c5d1SDavid du Colombier 		break;
2823e12c5d1SDavid du Colombier 	case -1:
2833e12c5d1SDavid du Colombier 		error("fork failed\n");
2843e12c5d1SDavid du Colombier 	default:
2853e12c5d1SDavid du Colombier 		/*
2863e12c5d1SDavid du Colombier 		 *  make a /srv/cs
2873e12c5d1SDavid du Colombier 		 */
2883e12c5d1SDavid du Colombier 		f = create(service, 1, 0666);
2893e12c5d1SDavid du Colombier 		if(f < 0)
2903e12c5d1SDavid du Colombier 			error(service);
291bd389b36SDavid du Colombier 		snprint(buf, sizeof(buf), "%d", p[1]);
2923e12c5d1SDavid du Colombier 		if(write(f, buf, strlen(buf)) != strlen(buf))
293219b2ee8SDavid du Colombier 			error("write /srv/cs");
2943e12c5d1SDavid du Colombier 		close(f);
2953e12c5d1SDavid du Colombier 
2963e12c5d1SDavid du Colombier 		/*
2973e12c5d1SDavid du Colombier 		 *  put ourselves into the file system
2983e12c5d1SDavid du Colombier 		 */
299219b2ee8SDavid du Colombier 		close(p[0]);
3009a747e4fSDavid du Colombier 		if(mount(p[1], -1, mntpt, MAFTER, "") < 0)
3013e12c5d1SDavid du Colombier 			error("mount failed\n");
302219b2ee8SDavid du Colombier 		_exits(0);
3033e12c5d1SDavid du Colombier 	}
3043e12c5d1SDavid du Colombier 	mfd[0] = mfd[1] = p[0];
3053e12c5d1SDavid du Colombier }
3063e12c5d1SDavid du Colombier 
3077dd7cddfSDavid du Colombier void
3087dd7cddfSDavid du Colombier ndbinit(void)
3097dd7cddfSDavid du Colombier {
3107dd7cddfSDavid du Colombier 	db = ndbopen(dbfile);
3117dd7cddfSDavid du Colombier 	if(db == nil)
3127dd7cddfSDavid du Colombier 		error("can't open network database");
3137dd7cddfSDavid du Colombier 
3147dd7cddfSDavid du Colombier 	netdb = ndbopen(netndb);
3157dd7cddfSDavid du Colombier 	if(netdb != nil){
3167dd7cddfSDavid du Colombier 		netdb->nohash = 1;
3177dd7cddfSDavid du Colombier 		db = ndbcat(netdb, db);
3187dd7cddfSDavid du Colombier 	}
3197dd7cddfSDavid du Colombier }
3207dd7cddfSDavid du Colombier 
3213e12c5d1SDavid du Colombier Mfile*
3223e12c5d1SDavid du Colombier newfid(int fid)
3233e12c5d1SDavid du Colombier {
324219b2ee8SDavid du Colombier 	Mlist *f, *ff;
3253e12c5d1SDavid du Colombier 	Mfile *mf;
3263e12c5d1SDavid du Colombier 
327219b2ee8SDavid du Colombier 	ff = 0;
328219b2ee8SDavid du Colombier 	for(f = mlist; f; f = f->next)
329219b2ee8SDavid du Colombier 		if(f->mf.busy && f->mf.fid == fid)
330219b2ee8SDavid du Colombier 			return &f->mf;
331219b2ee8SDavid du Colombier 		else if(!ff && !f->mf.busy)
332219b2ee8SDavid du Colombier 			ff = f;
333219b2ee8SDavid du Colombier 	if(ff == 0){
3347dd7cddfSDavid du Colombier 		ff = emalloc(sizeof *f);
335219b2ee8SDavid du Colombier 		ff->next = mlist;
336219b2ee8SDavid du Colombier 		mlist = ff;
3373e12c5d1SDavid du Colombier 	}
338219b2ee8SDavid du Colombier 	mf = &ff->mf;
339219b2ee8SDavid du Colombier 	memset(mf, 0, sizeof *mf);
3403e12c5d1SDavid du Colombier 	mf->fid = fid;
3413e12c5d1SDavid du Colombier 	return mf;
3423e12c5d1SDavid du Colombier }
3433e12c5d1SDavid du Colombier 
3447dd7cddfSDavid du Colombier Job*
3457dd7cddfSDavid du Colombier newjob(void)
3467dd7cddfSDavid du Colombier {
3477dd7cddfSDavid du Colombier 	Job *job;
3487dd7cddfSDavid du Colombier 
3497dd7cddfSDavid du Colombier 	job = mallocz(sizeof(Job), 1);
3507dd7cddfSDavid du Colombier 	lock(&joblock);
3517dd7cddfSDavid du Colombier 	job->next = joblist;
3527dd7cddfSDavid du Colombier 	joblist = job;
3537dd7cddfSDavid du Colombier 	job->request.tag = -1;
3547dd7cddfSDavid du Colombier 	unlock(&joblock);
3557dd7cddfSDavid du Colombier 	return job;
3567dd7cddfSDavid du Colombier }
3577dd7cddfSDavid du Colombier 
3587dd7cddfSDavid du Colombier void
3597dd7cddfSDavid du Colombier freejob(Job *job)
3607dd7cddfSDavid du Colombier {
3617dd7cddfSDavid du Colombier 	Job **l;
3627dd7cddfSDavid du Colombier 
3637dd7cddfSDavid du Colombier 	lock(&joblock);
3647dd7cddfSDavid du Colombier 	for(l = &joblist; *l; l = &(*l)->next){
3657dd7cddfSDavid du Colombier 		if((*l) == job){
3667dd7cddfSDavid du Colombier 			*l = job->next;
3677dd7cddfSDavid du Colombier 			free(job);
3687dd7cddfSDavid du Colombier 			break;
3697dd7cddfSDavid du Colombier 		}
3707dd7cddfSDavid du Colombier 	}
3717dd7cddfSDavid du Colombier 	unlock(&joblock);
3727dd7cddfSDavid du Colombier }
3737dd7cddfSDavid du Colombier 
3747dd7cddfSDavid du Colombier void
3757dd7cddfSDavid du Colombier flushjob(int tag)
3767dd7cddfSDavid du Colombier {
3777dd7cddfSDavid du Colombier 	Job *job;
3787dd7cddfSDavid du Colombier 
3797dd7cddfSDavid du Colombier 	lock(&joblock);
3807dd7cddfSDavid du Colombier 	for(job = joblist; job; job = job->next){
3817dd7cddfSDavid du Colombier 		if(job->request.tag == tag && job->request.type != Tflush){
3827dd7cddfSDavid du Colombier 			job->flushed = 1;
3837dd7cddfSDavid du Colombier 			break;
3847dd7cddfSDavid du Colombier 		}
3857dd7cddfSDavid du Colombier 	}
3867dd7cddfSDavid du Colombier 	unlock(&joblock);
3877dd7cddfSDavid du Colombier }
3887dd7cddfSDavid du Colombier 
3893e12c5d1SDavid du Colombier void
3903e12c5d1SDavid du Colombier io(void)
3913e12c5d1SDavid du Colombier {
3923e12c5d1SDavid du Colombier 	long n;
3933e12c5d1SDavid du Colombier 	Mfile *mf;
3943e12c5d1SDavid du Colombier 	int slaveflag;
3959a747e4fSDavid du Colombier 	uchar mdata[IOHDRSZ + Maxfdata];
3967dd7cddfSDavid du Colombier 	Job *job;
3973e12c5d1SDavid du Colombier 
3983e12c5d1SDavid du Colombier 	/*
3993e12c5d1SDavid du Colombier 	 *  if we ask dns to fulfill requests,
4003e12c5d1SDavid du Colombier 	 *  a slave process is created to wait for replies.  The
4019a747e4fSDavid du Colombier 	 *  master process returns immediately via a longjmp
4023e12c5d1SDavid du Colombier 	 *  through 'masterjmp'.
4033e12c5d1SDavid du Colombier 	 *
4043e12c5d1SDavid du Colombier 	 *  *isslave is a pointer into the call stack to a variable
4053e12c5d1SDavid du Colombier 	 *  that tells whether or not the current process is a slave.
4063e12c5d1SDavid du Colombier 	 */
4073e12c5d1SDavid du Colombier 	slaveflag = 0;		/* init slave variable */
4083e12c5d1SDavid du Colombier 	isslave = &slaveflag;
4093e12c5d1SDavid du Colombier 	setjmp(masterjmp);
4103e12c5d1SDavid du Colombier 
4113e12c5d1SDavid du Colombier 	for(;;){
4129a747e4fSDavid du Colombier 		n = read9pmsg(mfd[0], mdata, sizeof mdata);
4133e12c5d1SDavid du Colombier 		if(n<=0)
4143e12c5d1SDavid du Colombier 			error("mount read");
4157dd7cddfSDavid du Colombier 		job = newjob();
4169a747e4fSDavid du Colombier 		if(convM2S(mdata, n, &job->request) != n){
417271b8d73SDavid du Colombier 			syslog(1, logfile, "format error %ux %ux %ux %ux %ux",
418271b8d73SDavid du Colombier 				mdata[0], mdata[1], mdata[2], mdata[3], mdata[4]);
4197dd7cddfSDavid du Colombier 			freejob(job);
4203e12c5d1SDavid du Colombier 			continue;
4213e12c5d1SDavid du Colombier 		}
4227dd7cddfSDavid du Colombier 		if(job->request.fid<0)
4233e12c5d1SDavid du Colombier 			error("fid out of range");
424bd389b36SDavid du Colombier 		lock(&dblock);
4257dd7cddfSDavid du Colombier 		mf = newfid(job->request.fid);
426219b2ee8SDavid du Colombier 		if(debug)
4277dd7cddfSDavid du Colombier 			syslog(0, logfile, "%F", &job->request);
4283e12c5d1SDavid du Colombier 
4293e12c5d1SDavid du Colombier 
4307dd7cddfSDavid du Colombier 		switch(job->request.type){
4313e12c5d1SDavid du Colombier 		default:
4327dd7cddfSDavid du Colombier 			syslog(1, logfile, "unknown request type %d", job->request.type);
4333e12c5d1SDavid du Colombier 			break;
4349a747e4fSDavid du Colombier 		case Tversion:
4359a747e4fSDavid du Colombier 			rversion(job);
4363e12c5d1SDavid du Colombier 			break;
4379a747e4fSDavid du Colombier 		case Tauth:
4389a747e4fSDavid du Colombier 			rauth(job);
4393e12c5d1SDavid du Colombier 			break;
4403e12c5d1SDavid du Colombier 		case Tflush:
4417dd7cddfSDavid du Colombier 			rflush(job);
4423e12c5d1SDavid du Colombier 			break;
4433e12c5d1SDavid du Colombier 		case Tattach:
4447dd7cddfSDavid du Colombier 			rattach(job, mf);
4453e12c5d1SDavid du Colombier 			break;
4463e12c5d1SDavid du Colombier 		case Twalk:
4477dd7cddfSDavid du Colombier 			rwalk(job, mf);
4483e12c5d1SDavid du Colombier 			break;
4493e12c5d1SDavid du Colombier 		case Topen:
4507dd7cddfSDavid du Colombier 			ropen(job, mf);
4513e12c5d1SDavid du Colombier 			break;
4523e12c5d1SDavid du Colombier 		case Tcreate:
4537dd7cddfSDavid du Colombier 			rcreate(job, mf);
4543e12c5d1SDavid du Colombier 			break;
4553e12c5d1SDavid du Colombier 		case Tread:
4567dd7cddfSDavid du Colombier 			rread(job, mf);
4573e12c5d1SDavid du Colombier 			break;
4583e12c5d1SDavid du Colombier 		case Twrite:
4597dd7cddfSDavid du Colombier 			rwrite(job, mf);
4603e12c5d1SDavid du Colombier 			break;
4613e12c5d1SDavid du Colombier 		case Tclunk:
4627dd7cddfSDavid du Colombier 			rclunk(job, mf);
4633e12c5d1SDavid du Colombier 			break;
4643e12c5d1SDavid du Colombier 		case Tremove:
4657dd7cddfSDavid du Colombier 			rremove(job, mf);
4663e12c5d1SDavid du Colombier 			break;
4673e12c5d1SDavid du Colombier 		case Tstat:
4687dd7cddfSDavid du Colombier 			rstat(job, mf);
4693e12c5d1SDavid du Colombier 			break;
4703e12c5d1SDavid du Colombier 		case Twstat:
4717dd7cddfSDavid du Colombier 			rwstat(job, mf);
4723e12c5d1SDavid du Colombier 			break;
4733e12c5d1SDavid du Colombier 		}
474bd389b36SDavid du Colombier 		unlock(&dblock);
4757dd7cddfSDavid du Colombier 
4767dd7cddfSDavid du Colombier 		freejob(job);
4777dd7cddfSDavid du Colombier 
4783e12c5d1SDavid du Colombier 		/*
4793e12c5d1SDavid du Colombier 		 *  slave processes die after replying
4803e12c5d1SDavid du Colombier 		 */
481219b2ee8SDavid du Colombier 		if(*isslave){
482219b2ee8SDavid du Colombier 			if(debug)
483219b2ee8SDavid du Colombier 				syslog(0, logfile, "slave death %d", getpid());
4843e12c5d1SDavid du Colombier 			_exits(0);
4853e12c5d1SDavid du Colombier 		}
4863e12c5d1SDavid du Colombier 	}
487219b2ee8SDavid du Colombier }
488219b2ee8SDavid du Colombier 
489219b2ee8SDavid du Colombier void
4909a747e4fSDavid du Colombier rversion(Job *job)
491219b2ee8SDavid du Colombier {
4929a747e4fSDavid du Colombier 	if(job->request.msize > IOHDRSZ + Maxfdata)
4939a747e4fSDavid du Colombier 		job->reply.msize = IOHDRSZ + Maxfdata;
4949a747e4fSDavid du Colombier 	else
4959a747e4fSDavid du Colombier 		job->reply.msize = job->request.msize;
4969a747e4fSDavid du Colombier 	if(strncmp(job->request.version, "9P2000", 6) != 0)
4979a747e4fSDavid du Colombier 		sendmsg(job, "unknown 9P version");
4989a747e4fSDavid du Colombier 	else{
4999a747e4fSDavid du Colombier 		job->reply.version = "9P2000";
5007dd7cddfSDavid du Colombier 		sendmsg(job, 0);
501219b2ee8SDavid du Colombier 	}
5029a747e4fSDavid du Colombier }
5033e12c5d1SDavid du Colombier 
5043e12c5d1SDavid du Colombier void
5059a747e4fSDavid du Colombier rauth(Job *job)
5063e12c5d1SDavid du Colombier {
5073ff48bf5SDavid du Colombier 	sendmsg(job, "cs: authentication not required");
5087dd7cddfSDavid du Colombier }
5097dd7cddfSDavid du Colombier 
5107dd7cddfSDavid du Colombier /*
5117dd7cddfSDavid du Colombier  *  don't flush till all the slaves are done
5127dd7cddfSDavid du Colombier  */
5137dd7cddfSDavid du Colombier void
5147dd7cddfSDavid du Colombier rflush(Job *job)
5157dd7cddfSDavid du Colombier {
5167dd7cddfSDavid du Colombier 	flushjob(job->request.oldtag);
5177dd7cddfSDavid du Colombier 	sendmsg(job, 0);
5183e12c5d1SDavid du Colombier }
5193e12c5d1SDavid du Colombier 
5203e12c5d1SDavid du Colombier void
5217dd7cddfSDavid du Colombier rattach(Job *job, Mfile *mf)
5223e12c5d1SDavid du Colombier {
5233e12c5d1SDavid du Colombier 	if(mf->busy == 0){
5243e12c5d1SDavid du Colombier 		mf->busy = 1;
5259a747e4fSDavid du Colombier 		mf->user = estrdup(job->request.uname);
5263e12c5d1SDavid du Colombier 	}
5273e12c5d1SDavid du Colombier 	mf->qid.vers = vers++;
5289a747e4fSDavid du Colombier 	mf->qid.type = QTDIR;
5299a747e4fSDavid du Colombier 	mf->qid.path = 0LL;
5307dd7cddfSDavid du Colombier 	job->reply.qid = mf->qid;
5317dd7cddfSDavid du Colombier 	sendmsg(job, 0);
5323e12c5d1SDavid du Colombier }
5333e12c5d1SDavid du Colombier 
5343e12c5d1SDavid du Colombier 
5353e12c5d1SDavid du Colombier char*
5367dd7cddfSDavid du Colombier rwalk(Job *job, Mfile *mf)
5373e12c5d1SDavid du Colombier {
5383e12c5d1SDavid du Colombier 	char *err;
5399a747e4fSDavid du Colombier 	char **elems;
5409a747e4fSDavid du Colombier 	int nelems;
5419a747e4fSDavid du Colombier 	int i;
5429a747e4fSDavid du Colombier 	Mfile *nmf;
5439a747e4fSDavid du Colombier 	Qid qid;
5443e12c5d1SDavid du Colombier 
5453e12c5d1SDavid du Colombier 	err = 0;
5469a747e4fSDavid du Colombier 	nmf = nil;
5479a747e4fSDavid du Colombier 	elems = job->request.wname;
5489a747e4fSDavid du Colombier 	nelems = job->request.nwname;
5499a747e4fSDavid du Colombier 	job->reply.nwqid = 0;
5509a747e4fSDavid du Colombier 
5519a747e4fSDavid du Colombier 	if(job->request.newfid != job->request.fid){
5529a747e4fSDavid du Colombier 		/* clone fid */
5539a747e4fSDavid du Colombier 		if(job->request.newfid<0){
5549a747e4fSDavid du Colombier 			err = "clone newfid out of range";
5559a747e4fSDavid du Colombier 			goto send;
5569a747e4fSDavid du Colombier 		}
5579a747e4fSDavid du Colombier 		nmf = newfid(job->request.newfid);
5589a747e4fSDavid du Colombier 		if(nmf->busy){
5599a747e4fSDavid du Colombier 			nmf = nil;
5609a747e4fSDavid du Colombier 			err = "clone to used channel";
5619a747e4fSDavid du Colombier 			goto send;
5629a747e4fSDavid du Colombier 		}
5639a747e4fSDavid du Colombier 		*nmf = *mf;
5649a747e4fSDavid du Colombier 		nmf->user = estrdup(mf->user);
5659a747e4fSDavid du Colombier 		nmf->fid = job->request.newfid;
5669a747e4fSDavid du Colombier 		nmf->qid.vers = vers++;
5679a747e4fSDavid du Colombier 		mf = nmf;
5689a747e4fSDavid du Colombier 	}
5699a747e4fSDavid du Colombier 	/* else nmf will be nil */
5709a747e4fSDavid du Colombier 
5719a747e4fSDavid du Colombier 	qid = mf->qid;
5729a747e4fSDavid du Colombier 	if(nelems > 0){
5739a747e4fSDavid du Colombier 		/* walk fid */
5749a747e4fSDavid du Colombier 		for(i=0; i<nelems && i<MAXWELEM; i++){
5759a747e4fSDavid du Colombier 			if((qid.type & QTDIR) == 0){
5763e12c5d1SDavid du Colombier 				err = "not a directory";
5779a747e4fSDavid du Colombier 				break;
5783e12c5d1SDavid du Colombier 			}
5799a747e4fSDavid du Colombier 			if(strcmp(elems[i], "..") == 0 || strcmp(elems[i], ".") == 0){
5809a747e4fSDavid du Colombier 				qid.type = QTDIR;
5819a747e4fSDavid du Colombier 				qid.path = Qdir;
5829a747e4fSDavid du Colombier     Found:
5839a747e4fSDavid du Colombier 				job->reply.wqid[i] = qid;
5849a747e4fSDavid du Colombier 				job->reply.nwqid++;
5859a747e4fSDavid du Colombier 				continue;
5863e12c5d1SDavid du Colombier 			}
5879a747e4fSDavid du Colombier 			if(strcmp(elems[i], "cs") == 0){
5889a747e4fSDavid du Colombier 				qid.type = QTFILE;
5899a747e4fSDavid du Colombier 				qid.path = Qcs;
5909a747e4fSDavid du Colombier 				goto Found;
5913e12c5d1SDavid du Colombier 			}
5929a747e4fSDavid du Colombier 			err = "file does not exist";
5939a747e4fSDavid du Colombier 			break;
5949a747e4fSDavid du Colombier 		}
5959a747e4fSDavid du Colombier 	}
5969a747e4fSDavid du Colombier 
5973e12c5d1SDavid du Colombier     send:
5989a747e4fSDavid du Colombier 	if(nmf != nil && (err!=nil || job->reply.nwqid<nelems)){
5999a747e4fSDavid du Colombier 		nmf->busy = 0;
6009a747e4fSDavid du Colombier 		nmf->fid = 0;
6019a747e4fSDavid du Colombier 	}
6029a747e4fSDavid du Colombier 	if(err == nil)
6039a747e4fSDavid du Colombier 		mf->qid = qid;
6047dd7cddfSDavid du Colombier 	sendmsg(job, err);
6053e12c5d1SDavid du Colombier 	return err;
6063e12c5d1SDavid du Colombier }
6073e12c5d1SDavid du Colombier 
6083e12c5d1SDavid du Colombier void
6097dd7cddfSDavid du Colombier ropen(Job *job, Mfile *mf)
6103e12c5d1SDavid du Colombier {
6113e12c5d1SDavid du Colombier 	int mode;
6123e12c5d1SDavid du Colombier 	char *err;
6133e12c5d1SDavid du Colombier 
6143e12c5d1SDavid du Colombier 	err = 0;
6157dd7cddfSDavid du Colombier 	mode = job->request.mode;
6169a747e4fSDavid du Colombier 	if(mf->qid.type & QTDIR){
6173e12c5d1SDavid du Colombier 		if(mode)
6183e12c5d1SDavid du Colombier 			err = "permission denied";
6199a747e4fSDavid du Colombier 	}
6207dd7cddfSDavid du Colombier 	job->reply.qid = mf->qid;
6219a747e4fSDavid du Colombier 	job->reply.iounit = 0;
6227dd7cddfSDavid du Colombier 	sendmsg(job, err);
6233e12c5d1SDavid du Colombier }
6243e12c5d1SDavid du Colombier 
6253e12c5d1SDavid du Colombier void
6267dd7cddfSDavid du Colombier rcreate(Job *job, Mfile *mf)
6273e12c5d1SDavid du Colombier {
6283e12c5d1SDavid du Colombier 	USED(mf);
6297dd7cddfSDavid du Colombier 	sendmsg(job, "creation permission denied");
6303e12c5d1SDavid du Colombier }
6313e12c5d1SDavid du Colombier 
6323e12c5d1SDavid du Colombier void
6337dd7cddfSDavid du Colombier rread(Job *job, Mfile *mf)
6343e12c5d1SDavid du Colombier {
635219b2ee8SDavid du Colombier 	int i, n, cnt;
636219b2ee8SDavid du Colombier 	long off, toff, clock;
6373e12c5d1SDavid du Colombier 	Dir dir;
6389a747e4fSDavid du Colombier 	uchar buf[Maxfdata];
6393e12c5d1SDavid du Colombier 	char *err;
6403e12c5d1SDavid du Colombier 
6413e12c5d1SDavid du Colombier 	n = 0;
6423e12c5d1SDavid du Colombier 	err = 0;
6437dd7cddfSDavid du Colombier 	off = job->request.offset;
6447dd7cddfSDavid du Colombier 	cnt = job->request.count;
6459a747e4fSDavid du Colombier 	if(mf->qid.type & QTDIR){
6463e12c5d1SDavid du Colombier 		clock = time(0);
6473e12c5d1SDavid du Colombier 		if(off == 0){
6489a747e4fSDavid du Colombier 			dir.name = "cs";
6499a747e4fSDavid du Colombier 			dir.qid.type = QTFILE;
6503e12c5d1SDavid du Colombier 			dir.qid.vers = vers;
6513e12c5d1SDavid du Colombier 			dir.qid.path = Qcs;
6523e12c5d1SDavid du Colombier 			dir.mode = 0666;
6533e12c5d1SDavid du Colombier 			dir.length = 0;
6549a747e4fSDavid du Colombier 			dir.uid = mf->user;
6559a747e4fSDavid du Colombier 			dir.gid = mf->user;
6569a747e4fSDavid du Colombier 			dir.muid = mf->user;
6573e12c5d1SDavid du Colombier 			dir.atime = clock;	/* wrong */
6583e12c5d1SDavid du Colombier 			dir.mtime = clock;	/* wrong */
6599a747e4fSDavid du Colombier 			n = convD2M(&dir, buf, sizeof buf);
6603e12c5d1SDavid du Colombier 		}
6619a747e4fSDavid du Colombier 		job->reply.data = (char*)buf;
6623e12c5d1SDavid du Colombier 	} else {
66380ee5cbfSDavid du Colombier 		for(;;){
66480ee5cbfSDavid du Colombier 			/* look for an answer at the right offset */
665219b2ee8SDavid du Colombier 			toff = 0;
666219b2ee8SDavid du Colombier 			for(i = 0; mf->reply[i] && i < mf->nreply; i++){
667219b2ee8SDavid du Colombier 				n = mf->replylen[i];
668219b2ee8SDavid du Colombier 				if(off < toff + n)
669219b2ee8SDavid du Colombier 					break;
670219b2ee8SDavid du Colombier 				toff += n;
6713e12c5d1SDavid du Colombier 			}
67280ee5cbfSDavid du Colombier 			if(i < mf->nreply)
67380ee5cbfSDavid du Colombier 				break;		/* got something to return */
67480ee5cbfSDavid du Colombier 
67580ee5cbfSDavid du Colombier 			/* try looking up more answers */
67680ee5cbfSDavid du Colombier 			if(lookup(mf) == 0){
67780ee5cbfSDavid du Colombier 				/* no more */
678219b2ee8SDavid du Colombier 				n = 0;
679219b2ee8SDavid du Colombier 				goto send;
680219b2ee8SDavid du Colombier 			}
68180ee5cbfSDavid du Colombier 		}
68280ee5cbfSDavid du Colombier 
68380ee5cbfSDavid du Colombier 		/* give back a single reply (or part of one) */
6847dd7cddfSDavid du Colombier 		job->reply.data = mf->reply[i] + (off - toff);
685219b2ee8SDavid du Colombier 		if(cnt > toff - off + n)
686219b2ee8SDavid du Colombier 			n = toff - off + n;
687219b2ee8SDavid du Colombier 		else
688219b2ee8SDavid du Colombier 			n = cnt;
6893e12c5d1SDavid du Colombier 	}
6903e12c5d1SDavid du Colombier send:
6917dd7cddfSDavid du Colombier 	job->reply.count = n;
6927dd7cddfSDavid du Colombier 	sendmsg(job, err);
6937dd7cddfSDavid du Colombier }
69480ee5cbfSDavid du Colombier void
69580ee5cbfSDavid du Colombier cleanmf(Mfile *mf)
6967dd7cddfSDavid du Colombier {
6977dd7cddfSDavid du Colombier 	int i;
6987dd7cddfSDavid du Colombier 
6999a747e4fSDavid du Colombier 	if(mf->net != nil){
70080ee5cbfSDavid du Colombier 		free(mf->net);
70180ee5cbfSDavid du Colombier 		mf->net = nil;
7029a747e4fSDavid du Colombier 	}
7039a747e4fSDavid du Colombier 	if(mf->host != nil){
70480ee5cbfSDavid du Colombier 		free(mf->host);
70580ee5cbfSDavid du Colombier 		mf->host = nil;
7069a747e4fSDavid du Colombier 	}
7079a747e4fSDavid du Colombier 	if(mf->serv != nil){
70880ee5cbfSDavid du Colombier 		free(mf->serv);
70980ee5cbfSDavid du Colombier 		mf->serv = nil;
7109a747e4fSDavid du Colombier 	}
7119a747e4fSDavid du Colombier 	if(mf->rem != nil){
71280ee5cbfSDavid du Colombier 		free(mf->rem);
71380ee5cbfSDavid du Colombier 		mf->rem = nil;
7149a747e4fSDavid du Colombier 	}
7159a747e4fSDavid du Colombier 	if(mf->user != nil){
7169a747e4fSDavid du Colombier 		free(mf->user);
7179a747e4fSDavid du Colombier 		mf->user = nil;
7189a747e4fSDavid du Colombier 	}
71980ee5cbfSDavid du Colombier 	for(i = 0; i < mf->nreply; i++){
72080ee5cbfSDavid du Colombier 		free(mf->reply[i]);
72180ee5cbfSDavid du Colombier 		mf->reply[i] = nil;
72280ee5cbfSDavid du Colombier 		mf->replylen[i] = 0;
7237dd7cddfSDavid du Colombier 	}
72480ee5cbfSDavid du Colombier 	mf->nreply = 0;
72580ee5cbfSDavid du Colombier 	mf->nextnet = netlist;
7263e12c5d1SDavid du Colombier }
7273e12c5d1SDavid du Colombier 
7283e12c5d1SDavid du Colombier void
7297dd7cddfSDavid du Colombier rwrite(Job *job, Mfile *mf)
7303e12c5d1SDavid du Colombier {
7313e12c5d1SDavid du Colombier 	int cnt, n;
73280ee5cbfSDavid du Colombier 	char *err;
7337dd7cddfSDavid du Colombier 	char *field[4];
734271b8d73SDavid du Colombier 	char curerr[64];
7353e12c5d1SDavid du Colombier 
7363e12c5d1SDavid du Colombier 	err = 0;
7377dd7cddfSDavid du Colombier 	cnt = job->request.count;
7389a747e4fSDavid du Colombier 	if(mf->qid.type & QTDIR){
7393e12c5d1SDavid du Colombier 		err = "can't write directory";
7403e12c5d1SDavid du Colombier 		goto send;
7413e12c5d1SDavid du Colombier 	}
7423e12c5d1SDavid du Colombier 	if(cnt >= Maxrequest){
7433e12c5d1SDavid du Colombier 		err = "request too long";
7443e12c5d1SDavid du Colombier 		goto send;
7453e12c5d1SDavid du Colombier 	}
7467dd7cddfSDavid du Colombier 	job->request.data[cnt] = 0;
7473e12c5d1SDavid du Colombier 
7483e12c5d1SDavid du Colombier 	/*
749219b2ee8SDavid du Colombier 	 *  toggle debugging
750219b2ee8SDavid du Colombier 	 */
7517dd7cddfSDavid du Colombier 	if(strncmp(job->request.data, "debug", 5)==0){
752219b2ee8SDavid du Colombier 		debug ^= 1;
753219b2ee8SDavid du Colombier 		syslog(1, logfile, "debug %d", debug);
754219b2ee8SDavid du Colombier 		goto send;
755219b2ee8SDavid du Colombier 	}
756219b2ee8SDavid du Colombier 
757219b2ee8SDavid du Colombier 	/*
7587dd7cddfSDavid du Colombier 	 *  toggle debugging
7597dd7cddfSDavid du Colombier 	 */
7607dd7cddfSDavid du Colombier 	if(strncmp(job->request.data, "paranoia", 8)==0){
7617dd7cddfSDavid du Colombier 		paranoia ^= 1;
7627dd7cddfSDavid du Colombier 		syslog(1, logfile, "paranoia %d", paranoia);
7637dd7cddfSDavid du Colombier 		goto send;
7647dd7cddfSDavid du Colombier 	}
7657dd7cddfSDavid du Colombier 
7667dd7cddfSDavid du Colombier 	/*
7673e12c5d1SDavid du Colombier 	 *  add networks to the default list
7683e12c5d1SDavid du Colombier 	 */
7697dd7cddfSDavid du Colombier 	if(strncmp(job->request.data, "add ", 4)==0){
7707dd7cddfSDavid du Colombier 		if(job->request.data[cnt-1] == '\n')
7717dd7cddfSDavid du Colombier 			job->request.data[cnt-1] = 0;
7727dd7cddfSDavid du Colombier 		netadd(job->request.data+4);
7737dd7cddfSDavid du Colombier 		readipinterfaces();
7747dd7cddfSDavid du Colombier 		goto send;
7757dd7cddfSDavid du Colombier 	}
7767dd7cddfSDavid du Colombier 
7777dd7cddfSDavid du Colombier 	/*
7787dd7cddfSDavid du Colombier 	 *  refresh all state
7797dd7cddfSDavid du Colombier 	 */
7807dd7cddfSDavid du Colombier 	if(strncmp(job->request.data, "refresh", 7)==0){
7817dd7cddfSDavid du Colombier 		netinit(1);
7823e12c5d1SDavid du Colombier 		goto send;
7833e12c5d1SDavid du Colombier 	}
7843e12c5d1SDavid du Colombier 
78580ee5cbfSDavid du Colombier 	/* start transaction with a clean slate */
78680ee5cbfSDavid du Colombier 	cleanmf(mf);
78780ee5cbfSDavid du Colombier 
7883e12c5d1SDavid du Colombier 	/*
789219b2ee8SDavid du Colombier 	 *  look for a general query
790219b2ee8SDavid du Colombier 	 */
7917dd7cddfSDavid du Colombier 	if(*job->request.data == '!'){
7927dd7cddfSDavid du Colombier 		err = genquery(mf, job->request.data+1);
793219b2ee8SDavid du Colombier 		goto send;
794219b2ee8SDavid du Colombier 	}
795219b2ee8SDavid du Colombier 
7967dd7cddfSDavid du Colombier 	if(debug)
7977dd7cddfSDavid du Colombier 		syslog(0, logfile, "write %s", job->request.data);
7987dd7cddfSDavid du Colombier 	if(paranoia)
7997dd7cddfSDavid du Colombier 		syslog(0, paranoiafile, "write %s by %s", job->request.data, mf->user);
8007dd7cddfSDavid du Colombier 
801219b2ee8SDavid du Colombier 	/*
8023e12c5d1SDavid du Colombier 	 *  break up name
8033e12c5d1SDavid du Colombier 	 */
8047dd7cddfSDavid du Colombier 	n = getfields(job->request.data, field, 4, 1, "!");
8053e12c5d1SDavid du Colombier 	switch(n){
8063e12c5d1SDavid du Colombier 	case 1:
80780ee5cbfSDavid du Colombier 		mf->net = strdup("net");
80880ee5cbfSDavid du Colombier 		mf->host = strdup(field[0]);
8097dd7cddfSDavid du Colombier 		break;
8107dd7cddfSDavid du Colombier 	case 4:
81180ee5cbfSDavid du Colombier 		mf->rem = strdup(field[3]);
81280ee5cbfSDavid du Colombier 		/* fall through */
81380ee5cbfSDavid du Colombier 	case 3:
81480ee5cbfSDavid du Colombier 		mf->serv = strdup(field[2]);
81580ee5cbfSDavid du Colombier 		/* fall through */
81680ee5cbfSDavid du Colombier 	case 2:
81780ee5cbfSDavid du Colombier 		mf->host = strdup(field[1]);
81880ee5cbfSDavid du Colombier 		mf->net = strdup(field[0]);
8193e12c5d1SDavid du Colombier 		break;
8203e12c5d1SDavid du Colombier 	}
8213e12c5d1SDavid du Colombier 
82280ee5cbfSDavid du Colombier 	/*
82380ee5cbfSDavid du Colombier 	 *  do the first net worth of lookup
82480ee5cbfSDavid du Colombier 	 */
825271b8d73SDavid du Colombier 	if(lookup(mf) == 0){
826271b8d73SDavid du Colombier 		rerrstr(curerr, sizeof curerr);
827271b8d73SDavid du Colombier 		err = curerr;
828271b8d73SDavid du Colombier 	}
8293e12c5d1SDavid du Colombier send:
8307dd7cddfSDavid du Colombier 	job->reply.count = cnt;
8317dd7cddfSDavid du Colombier 	sendmsg(job, err);
8323e12c5d1SDavid du Colombier }
8333e12c5d1SDavid du Colombier 
8343e12c5d1SDavid du Colombier void
8357dd7cddfSDavid du Colombier rclunk(Job *job, Mfile *mf)
8363e12c5d1SDavid du Colombier {
83780ee5cbfSDavid du Colombier 	cleanmf(mf);
8383e12c5d1SDavid du Colombier 	mf->busy = 0;
8393e12c5d1SDavid du Colombier 	mf->fid = 0;
8407dd7cddfSDavid du Colombier 	sendmsg(job, 0);
8413e12c5d1SDavid du Colombier }
8423e12c5d1SDavid du Colombier 
8433e12c5d1SDavid du Colombier void
8447dd7cddfSDavid du Colombier rremove(Job *job, Mfile *mf)
8453e12c5d1SDavid du Colombier {
8463e12c5d1SDavid du Colombier 	USED(mf);
8477dd7cddfSDavid du Colombier 	sendmsg(job, "remove permission denied");
8483e12c5d1SDavid du Colombier }
8493e12c5d1SDavid du Colombier 
8503e12c5d1SDavid du Colombier void
8517dd7cddfSDavid du Colombier rstat(Job *job, Mfile *mf)
8523e12c5d1SDavid du Colombier {
8533e12c5d1SDavid du Colombier 	Dir dir;
8549a747e4fSDavid du Colombier 	uchar buf[IOHDRSZ+Maxfdata];
8553e12c5d1SDavid du Colombier 
8569a747e4fSDavid du Colombier 	if(mf->qid.type & QTDIR){
8579a747e4fSDavid du Colombier 		dir.name = ".";
8589a747e4fSDavid du Colombier 		dir.mode = DMDIR|0555;
859219b2ee8SDavid du Colombier 	} else {
8609a747e4fSDavid du Colombier 		dir.name = "cs";
8613e12c5d1SDavid du Colombier 		dir.mode = 0666;
862219b2ee8SDavid du Colombier 	}
863219b2ee8SDavid du Colombier 	dir.qid = mf->qid;
8643e12c5d1SDavid du Colombier 	dir.length = 0;
8659a747e4fSDavid du Colombier 	dir.uid = mf->user;
8669a747e4fSDavid du Colombier 	dir.gid = mf->user;
8679a747e4fSDavid du Colombier 	dir.muid = mf->user;
8683e12c5d1SDavid du Colombier 	dir.atime = dir.mtime = time(0);
8699a747e4fSDavid du Colombier 	job->reply.nstat = convD2M(&dir, buf, sizeof buf);
8709a747e4fSDavid du Colombier 	job->reply.stat = buf;
8717dd7cddfSDavid du Colombier 	sendmsg(job, 0);
8723e12c5d1SDavid du Colombier }
8733e12c5d1SDavid du Colombier 
8743e12c5d1SDavid du Colombier void
8757dd7cddfSDavid du Colombier rwstat(Job *job, Mfile *mf)
8763e12c5d1SDavid du Colombier {
8773e12c5d1SDavid du Colombier 	USED(mf);
8787dd7cddfSDavid du Colombier 	sendmsg(job, "wstat permission denied");
8793e12c5d1SDavid du Colombier }
8803e12c5d1SDavid du Colombier 
8813e12c5d1SDavid du Colombier void
8827dd7cddfSDavid du Colombier sendmsg(Job *job, char *err)
8833e12c5d1SDavid du Colombier {
8843e12c5d1SDavid du Colombier 	int n;
8859a747e4fSDavid du Colombier 	uchar mdata[IOHDRSZ + Maxfdata];
8869a747e4fSDavid du Colombier 	char ename[ERRMAX];
8873e12c5d1SDavid du Colombier 
8883e12c5d1SDavid du Colombier 	if(err){
8897dd7cddfSDavid du Colombier 		job->reply.type = Rerror;
8909a747e4fSDavid du Colombier 		snprint(ename, sizeof(ename), "cs: %s", err);
8919a747e4fSDavid du Colombier 		job->reply.ename = ename;
8923e12c5d1SDavid du Colombier 	}else{
8937dd7cddfSDavid du Colombier 		job->reply.type = job->request.type+1;
8943e12c5d1SDavid du Colombier 	}
8957dd7cddfSDavid du Colombier 	job->reply.tag = job->request.tag;
8969a747e4fSDavid du Colombier 	n = convS2M(&job->reply, mdata, sizeof mdata);
897219b2ee8SDavid du Colombier 	if(n == 0){
8987dd7cddfSDavid du Colombier 		syslog(1, logfile, "sendmsg convS2M of %F returns 0", &job->reply);
899219b2ee8SDavid du Colombier 		abort();
900219b2ee8SDavid du Colombier 	}
9017dd7cddfSDavid du Colombier 	lock(&joblock);
9027dd7cddfSDavid du Colombier 	if(job->flushed == 0)
9039a747e4fSDavid du Colombier 		if(write(mfd[1], mdata, n)!=n)
9043e12c5d1SDavid du Colombier 			error("mount write");
9057dd7cddfSDavid du Colombier 	unlock(&joblock);
906219b2ee8SDavid du Colombier 	if(debug)
9077dd7cddfSDavid du Colombier 		syslog(0, logfile, "%F %d", &job->reply, n);
9083e12c5d1SDavid du Colombier }
9093e12c5d1SDavid du Colombier 
9103e12c5d1SDavid du Colombier void
9113e12c5d1SDavid du Colombier error(char *s)
9123e12c5d1SDavid du Colombier {
913bd389b36SDavid du Colombier 	syslog(1, "cs", "%s: %r", s);
914bd389b36SDavid du Colombier 	_exits(0);
9153e12c5d1SDavid du Colombier }
9163e12c5d1SDavid du Colombier 
9177dd7cddfSDavid du Colombier static int
9187dd7cddfSDavid du Colombier isvalidip(uchar *ip)
9197dd7cddfSDavid du Colombier {
9207dd7cddfSDavid du Colombier 	return ipcmp(ip, IPnoaddr) != 0 && ipcmp(ip, v4prefix) != 0;
9217dd7cddfSDavid du Colombier }
9223e12c5d1SDavid du Colombier 
9230103620dSDavid du Colombier static uchar loopbacknet[IPaddrlen] = {
9240103620dSDavid du Colombier 	0, 0, 0, 0,
9250103620dSDavid du Colombier 	0, 0, 0, 0,
9260103620dSDavid du Colombier 	0, 0, 0xff, 0xff,
9270103620dSDavid du Colombier 	127, 0, 0, 0
9280103620dSDavid du Colombier };
9290103620dSDavid du Colombier static uchar loopbackmask[IPaddrlen] = {
9300103620dSDavid du Colombier 	0xff, 0xff, 0xff, 0xff,
9310103620dSDavid du Colombier 	0xff, 0xff, 0xff, 0xff,
9320103620dSDavid du Colombier 	0xff, 0xff, 0xff, 0xff,
9330103620dSDavid du Colombier 	0xff, 0, 0, 0
9340103620dSDavid du Colombier };
9350103620dSDavid du Colombier 
9367dd7cddfSDavid du Colombier void
9377dd7cddfSDavid du Colombier readipinterfaces(void)
9387dd7cddfSDavid du Colombier {
9390103620dSDavid du Colombier 	if(myipaddr(ipa, mntpt) != 0)
9400103620dSDavid du Colombier 		ipmove(ipa, IPnoaddr);
9417dd7cddfSDavid du Colombier 	sprint(ipaddr, "%I", ipa);
9427dd7cddfSDavid du Colombier 	if (debug)
9437dd7cddfSDavid du Colombier 		syslog(0, "dns", "ipaddr is %s\n", ipaddr);
9447dd7cddfSDavid du Colombier }
9453e12c5d1SDavid du Colombier 
9463e12c5d1SDavid du Colombier /*
9477dd7cddfSDavid du Colombier  *  get the system name
9483e12c5d1SDavid du Colombier  */
9493e12c5d1SDavid du Colombier void
9503e12c5d1SDavid du Colombier ipid(void)
9513e12c5d1SDavid du Colombier {
9523e12c5d1SDavid du Colombier 	uchar addr[6];
9533e12c5d1SDavid du Colombier 	Ndbtuple *t;
954219b2ee8SDavid du Colombier 	char *p, *attr;
9553e12c5d1SDavid du Colombier 	Ndbs s;
9563e12c5d1SDavid du Colombier 	int f;
9577dd7cddfSDavid du Colombier 	char buf[Maxpath];
9583e12c5d1SDavid du Colombier 
9593e12c5d1SDavid du Colombier 
960219b2ee8SDavid du Colombier 	/* use environment, ether addr, or ipaddr to get system name */
9617dd7cddfSDavid du Colombier 	if(*mysysname == 0){
9627dd7cddfSDavid du Colombier 		/*
9637dd7cddfSDavid du Colombier 		 *  environment has priority.
9647dd7cddfSDavid du Colombier 		 *
9657dd7cddfSDavid du Colombier 		 *  on the sgi power the default system name
9667dd7cddfSDavid du Colombier 		 *  is the ip address.  ignore that.
9677dd7cddfSDavid du Colombier 		 *
9687dd7cddfSDavid du Colombier 		 */
969219b2ee8SDavid du Colombier 		p = getenv("sysname");
970219b2ee8SDavid du Colombier 		if(p){
971219b2ee8SDavid du Colombier 			attr = ipattr(p);
972219b2ee8SDavid du Colombier 			if(strcmp(attr, "ip") != 0)
9737dd7cddfSDavid du Colombier 				strcpy(mysysname, p);
9743e12c5d1SDavid du Colombier 		}
9753e12c5d1SDavid du Colombier 
9763e12c5d1SDavid du Colombier 		/*
9777dd7cddfSDavid du Colombier 		 *  the /net/ndb contains what the network
9787dd7cddfSDavid du Colombier 		 *  figured out from DHCP.  use that name if
9797dd7cddfSDavid du Colombier 		 *  there is one.
9803e12c5d1SDavid du Colombier 		 */
9817dd7cddfSDavid du Colombier 		if(*mysysname == 0 && netdb != nil){
9827dd7cddfSDavid du Colombier 			ndbreopen(netdb);
9837dd7cddfSDavid du Colombier 			for(t = ndbparse(netdb); t != nil; t = t->entry){
9847dd7cddfSDavid du Colombier 				if(strcmp(t->attr, "sys") == 0){
9857dd7cddfSDavid du Colombier 					strcpy(mysysname, t->val);
9863e12c5d1SDavid du Colombier 					break;
9873e12c5d1SDavid du Colombier 				}
9887dd7cddfSDavid du Colombier 			}
9897dd7cddfSDavid du Colombier 			ndbfree(t);
9907dd7cddfSDavid du Colombier 		}
9917dd7cddfSDavid du Colombier 
9927dd7cddfSDavid du Colombier 		/* next network database, ip address, and ether address to find a name */
9937dd7cddfSDavid du Colombier 		if(*mysysname == 0){
9947dd7cddfSDavid du Colombier 			t = nil;
9957dd7cddfSDavid du Colombier 			if(isvalidip(ipa))
9967dd7cddfSDavid du Colombier 				t = ndbgetval(db, &s, "ip", ipaddr, "sys", mysysname);
9977dd7cddfSDavid du Colombier 			else {
9987dd7cddfSDavid du Colombier 				for(f = 0; f < 3; f++){
9997dd7cddfSDavid du Colombier 					snprint(buf, sizeof buf, "%s/ether%d", mntpt, f);
10007dd7cddfSDavid du Colombier 					if(myetheraddr(addr, buf) >= 0){
10017dd7cddfSDavid du Colombier 						snprint(eaddr, sizeof(eaddr), "%E", addr);
10027dd7cddfSDavid du Colombier 						t = ndbgetval(db, &s, "ether", eaddr, "sys",
10037dd7cddfSDavid du Colombier 							mysysname);
10047dd7cddfSDavid du Colombier 						if(t != nil)
10057dd7cddfSDavid du Colombier 							break;
10067dd7cddfSDavid du Colombier 					}
10077dd7cddfSDavid du Colombier 				}
10087dd7cddfSDavid du Colombier 			}
10097dd7cddfSDavid du Colombier 			ndbfree(t);
10107dd7cddfSDavid du Colombier 		}
10117dd7cddfSDavid du Colombier 
101280ee5cbfSDavid du Colombier 		/* nothing else worked, use the ip address */
101380ee5cbfSDavid du Colombier 		if(*mysysname == 0 && isvalidip(ipa))
101480ee5cbfSDavid du Colombier 			strcpy(mysysname, ipaddr);
101580ee5cbfSDavid du Colombier 
101680ee5cbfSDavid du Colombier 
1017dc5a79c1SDavid du Colombier 		/* set /dev/sysname if we now know it */
10187dd7cddfSDavid du Colombier 		if(*mysysname){
10197dd7cddfSDavid du Colombier 			f = open("/dev/sysname", OWRITE);
10207dd7cddfSDavid du Colombier 			if(f >= 0){
10217dd7cddfSDavid du Colombier 				write(f, mysysname, strlen(mysysname));
10223e12c5d1SDavid du Colombier 				close(f);
10233e12c5d1SDavid du Colombier 			}
10243e12c5d1SDavid du Colombier 		}
10253e12c5d1SDavid du Colombier 	}
10263e12c5d1SDavid du Colombier }
10273e12c5d1SDavid du Colombier 
10283e12c5d1SDavid du Colombier /*
10293e12c5d1SDavid du Colombier  *  Set up a list of default networks by looking for
10303e12c5d1SDavid du Colombier  *  /net/ * /clone.
10313e12c5d1SDavid du Colombier  */
10323e12c5d1SDavid du Colombier void
10337dd7cddfSDavid du Colombier netinit(int background)
10343e12c5d1SDavid du Colombier {
10357dd7cddfSDavid du Colombier 	char clone[Maxpath];
10363e12c5d1SDavid du Colombier 	Network *np;
10377dd7cddfSDavid du Colombier 	static int working;
10387dd7cddfSDavid du Colombier 
10397dd7cddfSDavid du Colombier 	if(background){
10407dd7cddfSDavid du Colombier 		switch(rfork(RFPROC|RFNOTEG|RFMEM|RFNOWAIT)){
10417dd7cddfSDavid du Colombier 		case 0:
10427dd7cddfSDavid du Colombier 			break;
10437dd7cddfSDavid du Colombier 		default:
10447dd7cddfSDavid du Colombier 			return;
10457dd7cddfSDavid du Colombier 		}
10467dd7cddfSDavid du Colombier 		lock(&netlock);
10477dd7cddfSDavid du Colombier 	}
10483e12c5d1SDavid du Colombier 
10493e12c5d1SDavid du Colombier 	/* add the mounted networks to the default list */
10503e12c5d1SDavid du Colombier 	for(np = network; np->net; np++){
10517dd7cddfSDavid du Colombier 		if(np->considered)
10527dd7cddfSDavid du Colombier 			continue;
10537dd7cddfSDavid du Colombier 		snprint(clone, sizeof(clone), "%s/%s/clone", mntpt, np->net);
10549a747e4fSDavid du Colombier 		if(access(clone, AEXIST) < 0)
10553e12c5d1SDavid du Colombier 			continue;
10563e12c5d1SDavid du Colombier 		if(netlist)
10573e12c5d1SDavid du Colombier 			last->next = np;
10583e12c5d1SDavid du Colombier 		else
10593e12c5d1SDavid du Colombier 			netlist = np;
10603e12c5d1SDavid du Colombier 		last = np;
10613e12c5d1SDavid du Colombier 		np->next = 0;
10627dd7cddfSDavid du Colombier 		np->considered = 1;
10633e12c5d1SDavid du Colombier 	}
10643e12c5d1SDavid du Colombier 
10657dd7cddfSDavid du Colombier 	/* find out what our ip address is */
10667dd7cddfSDavid du Colombier 	readipinterfaces();
10673e12c5d1SDavid du Colombier 
10687dd7cddfSDavid du Colombier 	/* set the system name if we need to, these says ip is all we have */
10693e12c5d1SDavid du Colombier 	ipid();
10703e12c5d1SDavid du Colombier 
1071219b2ee8SDavid du Colombier 	if(debug)
10727dd7cddfSDavid du Colombier 		syslog(0, logfile, "mysysname %s eaddr %s ipaddr %s ipa %I\n",
10737dd7cddfSDavid du Colombier 			mysysname, eaddr, ipaddr, ipa);
10747dd7cddfSDavid du Colombier 
10757dd7cddfSDavid du Colombier 	if(background){
10767dd7cddfSDavid du Colombier 		unlock(&netlock);
10777dd7cddfSDavid du Colombier 		_exits(0);
10787dd7cddfSDavid du Colombier 	}
10793e12c5d1SDavid du Colombier }
10803e12c5d1SDavid du Colombier 
10813e12c5d1SDavid du Colombier /*
10823e12c5d1SDavid du Colombier  *  add networks to the standard list
10833e12c5d1SDavid du Colombier  */
10843e12c5d1SDavid du Colombier void
10853e12c5d1SDavid du Colombier netadd(char *p)
10863e12c5d1SDavid du Colombier {
10873e12c5d1SDavid du Colombier 	Network *np;
10883e12c5d1SDavid du Colombier 	char *field[12];
10893e12c5d1SDavid du Colombier 	int i, n;
10903e12c5d1SDavid du Colombier 
10917dd7cddfSDavid du Colombier 	n = getfields(p, field, 12, 1, " ");
10923e12c5d1SDavid du Colombier 	for(i = 0; i < n; i++){
10933e12c5d1SDavid du Colombier 		for(np = network; np->net; np++){
10943e12c5d1SDavid du Colombier 			if(strcmp(field[i], np->net) != 0)
10953e12c5d1SDavid du Colombier 				continue;
10967dd7cddfSDavid du Colombier 			if(np->considered)
10973e12c5d1SDavid du Colombier 				break;
10983e12c5d1SDavid du Colombier 			if(netlist)
10993e12c5d1SDavid du Colombier 				last->next = np;
11003e12c5d1SDavid du Colombier 			else
11013e12c5d1SDavid du Colombier 				netlist = np;
11023e12c5d1SDavid du Colombier 			last = np;
11033e12c5d1SDavid du Colombier 			np->next = 0;
11047dd7cddfSDavid du Colombier 			np->considered = 1;
11053e12c5d1SDavid du Colombier 		}
11063e12c5d1SDavid du Colombier 	}
11073e12c5d1SDavid du Colombier }
11083e12c5d1SDavid du Colombier 
11093e12c5d1SDavid du Colombier /*
1110219b2ee8SDavid du Colombier  *  make a tuple
1111219b2ee8SDavid du Colombier  */
1112219b2ee8SDavid du Colombier Ndbtuple*
1113219b2ee8SDavid du Colombier mktuple(char *attr, char *val)
1114219b2ee8SDavid du Colombier {
1115219b2ee8SDavid du Colombier 	Ndbtuple *t;
1116219b2ee8SDavid du Colombier 
11177dd7cddfSDavid du Colombier 	t = emalloc(sizeof(Ndbtuple));
1118219b2ee8SDavid du Colombier 	strcpy(t->attr, attr);
1119219b2ee8SDavid du Colombier 	strncpy(t->val, val, sizeof(t->val));
1120219b2ee8SDavid du Colombier 	t->val[sizeof(t->val)-1] = 0;
1121219b2ee8SDavid du Colombier 	t->line = t;
1122219b2ee8SDavid du Colombier 	t->entry = 0;
1123219b2ee8SDavid du Colombier 	return t;
1124219b2ee8SDavid du Colombier }
1125219b2ee8SDavid du Colombier 
112680ee5cbfSDavid du Colombier int
112780ee5cbfSDavid du Colombier lookforproto(Ndbtuple *t, char *proto)
112880ee5cbfSDavid du Colombier {
112980ee5cbfSDavid du Colombier 	for(; t != nil; t = t->entry)
113080ee5cbfSDavid du Colombier 		if(strcmp(t->attr, "proto") == 0 && strcmp(t->val, proto) == 0)
113180ee5cbfSDavid du Colombier 			return 1;
113280ee5cbfSDavid du Colombier 	return 0;
113380ee5cbfSDavid du Colombier }
113480ee5cbfSDavid du Colombier 
1135219b2ee8SDavid du Colombier /*
11363e12c5d1SDavid du Colombier  *  lookup a request.  the network "net" means we should pick the
11373e12c5d1SDavid du Colombier  *  best network to get there.
11383e12c5d1SDavid du Colombier  */
11393e12c5d1SDavid du Colombier int
114080ee5cbfSDavid du Colombier lookup(Mfile *mf)
11413e12c5d1SDavid du Colombier {
114280ee5cbfSDavid du Colombier 	Network *np;
1143219b2ee8SDavid du Colombier 	char *cp;
1144219b2ee8SDavid du Colombier 	Ndbtuple *nt, *t;
1145219b2ee8SDavid du Colombier 	char reply[Maxreply];
114680ee5cbfSDavid du Colombier 	int i, rv;
114780ee5cbfSDavid du Colombier 	int hack;
11483e12c5d1SDavid du Colombier 
11493e12c5d1SDavid du Colombier 	/* open up the standard db files */
11503e12c5d1SDavid du Colombier 	if(db == 0)
11517dd7cddfSDavid du Colombier 		ndbinit();
11523e12c5d1SDavid du Colombier 	if(db == 0)
115380ee5cbfSDavid du Colombier 		error("can't open mf->network database\n");
11543e12c5d1SDavid du Colombier 
115580ee5cbfSDavid du Colombier 	rv = 0;
115680ee5cbfSDavid du Colombier 
115780ee5cbfSDavid du Colombier 	if(mf->net == nil)
115880ee5cbfSDavid du Colombier 		return 0;	/* must have been a genquery */
115980ee5cbfSDavid du Colombier 
116080ee5cbfSDavid du Colombier 	if(strcmp(mf->net, "net") == 0){
11613e12c5d1SDavid du Colombier 		/*
11623e12c5d1SDavid du Colombier 		 *  go through set of default nets
11633e12c5d1SDavid du Colombier 		 */
116480ee5cbfSDavid du Colombier 		for(np = mf->nextnet; np; np = np->next){
116580ee5cbfSDavid du Colombier 			nt = (*np->lookup)(np, mf->host, mf->serv, 1);
116680ee5cbfSDavid du Colombier 			if(nt == nil)
1167219b2ee8SDavid du Colombier 				continue;
116880ee5cbfSDavid du Colombier 			hack = np->fasttimeouthack && !lookforproto(nt, np->net);
116980ee5cbfSDavid du Colombier 			for(t = nt; mf->nreply < Nreply && t; t = t->entry){
117080ee5cbfSDavid du Colombier 				cp = (*np->trans)(t, np, mf->serv, mf->rem, hack);
1171219b2ee8SDavid du Colombier 				if(cp){
117280ee5cbfSDavid du Colombier 					/* avoid duplicates */
117380ee5cbfSDavid du Colombier 					for(i = 0; i < mf->nreply; i++)
117480ee5cbfSDavid du Colombier 						if(strcmp(mf->reply[i], cp) == 0)
117580ee5cbfSDavid du Colombier 							break;
117680ee5cbfSDavid du Colombier 					if(i == mf->nreply){
117780ee5cbfSDavid du Colombier 						/* save the reply */
1178219b2ee8SDavid du Colombier 						mf->replylen[mf->nreply] = strlen(cp);
1179219b2ee8SDavid du Colombier 						mf->reply[mf->nreply++] = cp;
118080ee5cbfSDavid du Colombier 						rv++;
1181219b2ee8SDavid du Colombier 					}
1182219b2ee8SDavid du Colombier 				}
1183219b2ee8SDavid du Colombier 			}
1184219b2ee8SDavid du Colombier 			ndbfree(nt);
118580ee5cbfSDavid du Colombier 			np = np->next;
118680ee5cbfSDavid du Colombier 			break;
118780ee5cbfSDavid du Colombier 		}
118880ee5cbfSDavid du Colombier 		mf->nextnet = np;
118980ee5cbfSDavid du Colombier 		return rv;
119080ee5cbfSDavid du Colombier 	}
119180ee5cbfSDavid du Colombier 
119280ee5cbfSDavid du Colombier 	/*
119380ee5cbfSDavid du Colombier 	 *  if not /net, we only get one lookup
119480ee5cbfSDavid du Colombier 	 */
119580ee5cbfSDavid du Colombier 	if(mf->nreply != 0)
1196219b2ee8SDavid du Colombier 		return 0;
119780ee5cbfSDavid du Colombier 
119880ee5cbfSDavid du Colombier 	/*
119980ee5cbfSDavid du Colombier 	 *  look for a specific network
120080ee5cbfSDavid du Colombier 	 */
120180ee5cbfSDavid du Colombier 	for(np = netlist; 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 
120880ee5cbfSDavid du Colombier 	if(np->net != nil){
120980ee5cbfSDavid du Colombier 		/*
121080ee5cbfSDavid du Colombier 		 *  known network
121180ee5cbfSDavid du Colombier 		 */
121280ee5cbfSDavid du Colombier 		nt = (*np->lookup)(np, mf->host, mf->serv, 1);
121380ee5cbfSDavid du Colombier 		for(t = nt; mf->nreply < Nreply && t; t = t->entry){
121480ee5cbfSDavid du Colombier 			cp = (*np->trans)(t, np, mf->serv, mf->rem, 0);
121580ee5cbfSDavid du Colombier 			if(cp){
121680ee5cbfSDavid du Colombier 				mf->replylen[mf->nreply] = strlen(cp);
121780ee5cbfSDavid du Colombier 				mf->reply[mf->nreply++] = cp;
121880ee5cbfSDavid du Colombier 				rv++;
121980ee5cbfSDavid du Colombier 			}
122080ee5cbfSDavid du Colombier 		}
122180ee5cbfSDavid du Colombier 		ndbfree(nt);
122280ee5cbfSDavid du Colombier 		return rv;
12233e12c5d1SDavid du Colombier 	} else {
12243e12c5d1SDavid du Colombier 		/*
1225219b2ee8SDavid du Colombier 		 *  not a known network, don't translate host or service
12263e12c5d1SDavid du Colombier 		 */
122780ee5cbfSDavid du Colombier 		if(mf->serv)
12287dd7cddfSDavid du Colombier 			snprint(reply, sizeof(reply), "%s/%s/clone %s!%s",
122980ee5cbfSDavid du Colombier 				mntpt, mf->net, mf->host, mf->serv);
1230bd389b36SDavid du Colombier 		else
12317dd7cddfSDavid du Colombier 			snprint(reply, sizeof(reply), "%s/%s/clone %s",
123280ee5cbfSDavid du Colombier 				mntpt, mf->net, mf->host);
1233219b2ee8SDavid du Colombier 		mf->reply[0] = strdup(reply);
1234219b2ee8SDavid du Colombier 		mf->replylen[0] = strlen(reply);
1235219b2ee8SDavid du Colombier 		mf->nreply = 1;
123680ee5cbfSDavid du Colombier 		return 1;
12373e12c5d1SDavid du Colombier 	}
12383e12c5d1SDavid du Colombier }
12393e12c5d1SDavid du Colombier 
12403e12c5d1SDavid du Colombier /*
12413e12c5d1SDavid du Colombier  *  translate an ip service name into a port number.  If it's a numeric port
12423e12c5d1SDavid du Colombier  *  number, look for restricted access.
12433e12c5d1SDavid du Colombier  *
12443e12c5d1SDavid du Colombier  *  the service '*' needs no translation.
12453e12c5d1SDavid du Colombier  */
12463e12c5d1SDavid du Colombier char*
12473e12c5d1SDavid du Colombier ipserv(Network *np, char *name, char *buf)
12483e12c5d1SDavid du Colombier {
12493e12c5d1SDavid du Colombier 	char *p;
12503e12c5d1SDavid du Colombier 	int alpha = 0;
12513e12c5d1SDavid du Colombier 	int restr = 0;
12523e12c5d1SDavid du Colombier 	char port[Ndbvlen];
12533e12c5d1SDavid du Colombier 	Ndbtuple *t, *nt;
12543e12c5d1SDavid du Colombier 	Ndbs s;
12553e12c5d1SDavid du Colombier 
12563e12c5d1SDavid du Colombier 	/* '*' means any service */
12573e12c5d1SDavid du Colombier 	if(strcmp(name, "*")==0){
12583e12c5d1SDavid du Colombier 		strcpy(buf, name);
12593e12c5d1SDavid du Colombier 		return buf;
12603e12c5d1SDavid du Colombier 	}
12613e12c5d1SDavid du Colombier 
12623e12c5d1SDavid du Colombier 	/*  see if it's numeric or symbolic */
12633e12c5d1SDavid du Colombier 	port[0] = 0;
12643e12c5d1SDavid du Colombier 	for(p = name; *p; p++){
12653e12c5d1SDavid du Colombier 		if(isdigit(*p))
12669a747e4fSDavid du Colombier 			{}
12673e12c5d1SDavid du Colombier 		else if(isalpha(*p) || *p == '-' || *p == '$')
12683e12c5d1SDavid du Colombier 			alpha = 1;
12693e12c5d1SDavid du Colombier 		else
12703e12c5d1SDavid du Colombier 			return 0;
12713e12c5d1SDavid du Colombier 	}
12723e12c5d1SDavid du Colombier 	if(alpha){
12733e12c5d1SDavid du Colombier 		t = ndbgetval(db, &s, np->net, name, "port", port);
12743e12c5d1SDavid du Colombier 		if(t == 0)
12753e12c5d1SDavid du Colombier 			return 0;
12763e12c5d1SDavid du Colombier 	} else {
1277*3cc1eb97SDavid du Colombier 		/* look up only for tcp ports < 1024 to get the restricted
1278*3cc1eb97SDavid du Colombier 		 * attribute
1279*3cc1eb97SDavid du Colombier 		 */
1280*3cc1eb97SDavid du Colombier 		t = nil;
1281*3cc1eb97SDavid du Colombier 		if(atoi(name) < 1024 && strcmp(np->net, "tcp") == 0)
12823e12c5d1SDavid du Colombier 			t = ndbgetval(db, &s, "port", name, "port", port);
1283*3cc1eb97SDavid du Colombier 		if(t == nil){
12843e12c5d1SDavid du Colombier 			strncpy(port, name, sizeof(port));
12853e12c5d1SDavid du Colombier 			port[sizeof(port)-1] = 0;
12863e12c5d1SDavid du Colombier 		}
12873e12c5d1SDavid du Colombier 	}
12883e12c5d1SDavid du Colombier 
12893e12c5d1SDavid du Colombier 	if(t){
12903e12c5d1SDavid du Colombier 		for(nt = t; nt; nt = nt->entry)
12913e12c5d1SDavid du Colombier 			if(strcmp(nt->attr, "restricted") == 0)
12923e12c5d1SDavid du Colombier 				restr = 1;
12933e12c5d1SDavid du Colombier 		ndbfree(t);
12943e12c5d1SDavid du Colombier 	}
12953e12c5d1SDavid du Colombier 	sprint(buf, "%s%s", port, restr ? "!r" : "");
12963e12c5d1SDavid du Colombier 	return buf;
12973e12c5d1SDavid du Colombier }
12983e12c5d1SDavid du Colombier 
12993e12c5d1SDavid du Colombier /*
13007dd7cddfSDavid du Colombier  *  lookup an ip attribute
13013e12c5d1SDavid du Colombier  */
13027dd7cddfSDavid du Colombier int
13037dd7cddfSDavid du Colombier ipattrlookup(Ndb *db, char *ipa, char *attr, char *val)
13043e12c5d1SDavid du Colombier {
13053e12c5d1SDavid du Colombier 
13067dd7cddfSDavid du Colombier 	Ndbtuple *t, *nt;
13077dd7cddfSDavid du Colombier 	char *alist[2];
13083e12c5d1SDavid du Colombier 
13097dd7cddfSDavid du Colombier 	alist[0] = attr;
13107dd7cddfSDavid du Colombier 	t = ndbipinfo(db, "ip", ipa, alist, 1);
13117dd7cddfSDavid du Colombier 	if(t == nil)
13127dd7cddfSDavid du Colombier 		return 0;
13139a747e4fSDavid du Colombier 	for(nt = t; nt != nil; nt = nt->entry){
13147dd7cddfSDavid du Colombier 		if(strcmp(nt->attr, attr) == 0){
13157dd7cddfSDavid du Colombier 			strcpy(val, nt->val);
13163e12c5d1SDavid du Colombier 			ndbfree(t);
13177dd7cddfSDavid du Colombier 			return 1;
1318219b2ee8SDavid du Colombier 		}
13199a747e4fSDavid du Colombier 	}
13203e12c5d1SDavid du Colombier 
13217dd7cddfSDavid du Colombier 	/* we shouldn't get here */
13223e12c5d1SDavid du Colombier 	ndbfree(t);
13237dd7cddfSDavid du Colombier 	return 0;
13243e12c5d1SDavid du Colombier }
13253e12c5d1SDavid du Colombier 
13263e12c5d1SDavid du Colombier /*
13273e12c5d1SDavid du Colombier  *  lookup (and translate) an ip destination
13283e12c5d1SDavid du Colombier  */
1329219b2ee8SDavid du Colombier Ndbtuple*
1330219b2ee8SDavid du Colombier iplookup(Network *np, char *host, char *serv, int nolookup)
13313e12c5d1SDavid du Colombier {
13323e12c5d1SDavid du Colombier 	char *attr;
13337dd7cddfSDavid du Colombier 	Ndbtuple *t, *nt;
13343e12c5d1SDavid du Colombier 	Ndbs s;
13353e12c5d1SDavid du Colombier 	char ts[Ndbvlen+1];
13363e12c5d1SDavid du Colombier 	char th[Ndbvlen+1];
13373e12c5d1SDavid du Colombier 	char dollar[Ndbvlen+1];
13387dd7cddfSDavid du Colombier 	uchar ip[IPaddrlen];
13397dd7cddfSDavid du Colombier 	uchar net[IPaddrlen];
13407dd7cddfSDavid du Colombier 	uchar tnet[IPaddrlen];
13417dd7cddfSDavid du Colombier 	Ipifc *ifc;
13429a747e4fSDavid du Colombier 	Iplifc *lifc;
13433e12c5d1SDavid du Colombier 
1344219b2ee8SDavid du Colombier 	USED(nolookup);
1345219b2ee8SDavid du Colombier 
13463e12c5d1SDavid du Colombier 	/*
13473e12c5d1SDavid du Colombier 	 *  start with the service since it's the most likely to fail
13483e12c5d1SDavid du Colombier 	 *  and costs the least
13493e12c5d1SDavid du Colombier 	 */
13507dd7cddfSDavid du Colombier 	werrstr("can't translate address");
1351271b8d73SDavid du Colombier 	if(serv==0 || ipserv(np, serv, ts) == 0){
1352271b8d73SDavid du Colombier 		werrstr("can't translate service");
1353219b2ee8SDavid du Colombier 		return 0;
13547dd7cddfSDavid du Colombier 	}
13553e12c5d1SDavid du Colombier 
13563e12c5d1SDavid du Colombier 	/* for dial strings with no host */
1357219b2ee8SDavid du Colombier 	if(strcmp(host, "*") == 0)
1358219b2ee8SDavid du Colombier 		return mktuple("ip", "*");
13593e12c5d1SDavid du Colombier 
13603e12c5d1SDavid du Colombier 	/*
13617dd7cddfSDavid du Colombier 	 *  hack till we go v6 :: = 0.0.0.0
13627dd7cddfSDavid du Colombier 	 */
13637dd7cddfSDavid du Colombier 	if(strcmp("::", host) == 0)
13647dd7cddfSDavid du Colombier 		return mktuple("ip", "*");
13657dd7cddfSDavid du Colombier 
13667dd7cddfSDavid du Colombier 	/*
13673e12c5d1SDavid du Colombier 	 *  '$' means the rest of the name is an attribute that we
13683e12c5d1SDavid du Colombier 	 *  need to search for
13693e12c5d1SDavid du Colombier 	 */
13703e12c5d1SDavid du Colombier 	if(*host == '$'){
13717dd7cddfSDavid du Colombier 		if(ipattrlookup(db, ipaddr, host+1, dollar))
13723e12c5d1SDavid du Colombier 			host = dollar;
13733e12c5d1SDavid du Colombier 	}
13743e12c5d1SDavid du Colombier 
13753e12c5d1SDavid du Colombier 	/*
13767dd7cddfSDavid du Colombier 	 *  turn '[ip address]' into just 'ip address'
13777dd7cddfSDavid du Colombier 	 */
13787dd7cddfSDavid du Colombier 	if(*host == '[' && host[strlen(host)-1] == ']'){
13797dd7cddfSDavid du Colombier 		host++;
13807dd7cddfSDavid du Colombier 		host[strlen(host)-1] = 0;
13817dd7cddfSDavid du Colombier 	}
13827dd7cddfSDavid du Colombier 
13837dd7cddfSDavid du Colombier 	/*
13843e12c5d1SDavid du Colombier 	 *  just accept addresses
13853e12c5d1SDavid du Colombier 	 */
1386219b2ee8SDavid du Colombier 	attr = ipattr(host);
1387219b2ee8SDavid du Colombier 	if(strcmp(attr, "ip") == 0)
1388219b2ee8SDavid du Colombier 		return mktuple("ip", host);
13893e12c5d1SDavid du Colombier 
13903e12c5d1SDavid du Colombier 	/*
13913e12c5d1SDavid du Colombier 	 *  give the domain name server the first opportunity to
1392bd389b36SDavid du Colombier 	 *  resolve domain names.  if that fails try the database.
13933e12c5d1SDavid du Colombier 	 */
13943e12c5d1SDavid du Colombier 	t = 0;
1395271b8d73SDavid du Colombier 	werrstr("can't translate address");
13963e12c5d1SDavid du Colombier 	if(strcmp(attr, "dom") == 0)
13977dd7cddfSDavid du Colombier 		t = dnsiplookup(host, &s);
13983e12c5d1SDavid du Colombier 	if(t == 0)
13993e12c5d1SDavid du Colombier 		t = ndbgetval(db, &s, attr, host, "ip", th);
14003e12c5d1SDavid du Colombier 	if(t == 0)
14017dd7cddfSDavid du Colombier 		t = dnsiplookup(host, &s);
14027dd7cddfSDavid du Colombier 	if(t == 0 && strcmp(attr, "dom") != 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 {
14443e12c5d1SDavid du Colombier 	char ts[Ndbvlen+1];
1445219b2ee8SDavid du Colombier 	char reply[Maxreply];
14467dd7cddfSDavid du Colombier 	char x[Ndbvlen+1];
14473e12c5d1SDavid du Colombier 
1448219b2ee8SDavid du Colombier 	if(strcmp(t->attr, "ip") != 0)
14493e12c5d1SDavid du Colombier 		return 0;
1450219b2ee8SDavid du Colombier 
1451271b8d73SDavid du Colombier 	if(serv == 0 || ipserv(np, serv, 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 	char th[Ndbvlen+1];
1479219b2ee8SDavid du Colombier 
1480219b2ee8SDavid du Colombier 	USED(np, nolookup, serv);
1481219b2ee8SDavid du Colombier 
1482271b8d73SDavid du Colombier 	werrstr("can't translate address");
1483219b2ee8SDavid du Colombier 	t = ndbgetval(db, &s, "sys", host, "telco", th);
1484219b2ee8SDavid du Colombier 	if(t == 0)
1485219b2ee8SDavid du Colombier 		return mktuple("telco", host);
1486219b2ee8SDavid du Colombier 
1487219b2ee8SDavid du Colombier 	return reorder(t, s.t);
1488219b2ee8SDavid du Colombier }
1489219b2ee8SDavid du Colombier 
1490219b2ee8SDavid du Colombier /*
1491219b2ee8SDavid du Colombier  *  translate a telephone address
1492219b2ee8SDavid du Colombier  */
1493219b2ee8SDavid du Colombier char*
149480ee5cbfSDavid du Colombier telcotrans(Ndbtuple *t, Network *np, char *serv, char *rem, int)
1495219b2ee8SDavid du Colombier {
1496219b2ee8SDavid du Colombier 	char reply[Maxreply];
14977dd7cddfSDavid du Colombier 	char x[Ndbvlen+1];
1498219b2ee8SDavid du Colombier 
1499219b2ee8SDavid du Colombier 	if(strcmp(t->attr, "telco") != 0)
1500219b2ee8SDavid du Colombier 		return 0;
1501219b2ee8SDavid du Colombier 
15027dd7cddfSDavid du Colombier 	if(rem != nil)
15037dd7cddfSDavid du Colombier 		snprint(x, sizeof(x), "!%s", rem);
1504219b2ee8SDavid du Colombier 	else
15057dd7cddfSDavid du Colombier 		*x = 0;
15067dd7cddfSDavid du Colombier 	if(serv)
15077dd7cddfSDavid du Colombier 		snprint(reply, sizeof(reply), "%s/%s/clone %s!%s%s", mntpt, np->net,
15087dd7cddfSDavid du Colombier 			t->val, serv, x);
15097dd7cddfSDavid du Colombier 	else
15107dd7cddfSDavid du Colombier 		snprint(reply, sizeof(reply), "%s/%s/clone %s%s", mntpt, np->net,
15117dd7cddfSDavid du Colombier 			t->val, x);
1512219b2ee8SDavid du Colombier 	return strdup(reply);
1513219b2ee8SDavid du Colombier }
15143e12c5d1SDavid du Colombier 
15153e12c5d1SDavid du Colombier /*
15163e12c5d1SDavid du Colombier  *  reorder the tuple to put x's line first in the entry
15173e12c5d1SDavid du Colombier  */
15183e12c5d1SDavid du Colombier Ndbtuple*
15193e12c5d1SDavid du Colombier reorder(Ndbtuple *t, Ndbtuple *x)
15203e12c5d1SDavid du Colombier {
15213e12c5d1SDavid du Colombier 	Ndbtuple *nt;
15223e12c5d1SDavid du Colombier 	Ndbtuple *line;
15233e12c5d1SDavid du Colombier 
1524219b2ee8SDavid du Colombier 	/* find start of this entry's line */
1525219b2ee8SDavid du Colombier 	for(line = x; line->entry == line->line; line = line->line)
15263e12c5d1SDavid du Colombier 		;
1527219b2ee8SDavid du Colombier 	line = line->line;
1528219b2ee8SDavid du Colombier 	if(line == t)
1529219b2ee8SDavid du Colombier 		return t;	/* already the first line */
15303e12c5d1SDavid du Colombier 
1531219b2ee8SDavid du Colombier 	/* remove this line and everything after it from the entry */
1532219b2ee8SDavid du Colombier 	for(nt = t; nt->entry != line; nt = nt->entry)
1533219b2ee8SDavid du Colombier 		;
1534219b2ee8SDavid du Colombier 	nt->entry = 0;
15353e12c5d1SDavid du Colombier 
1536219b2ee8SDavid du Colombier 	/* make that the start of the entry */
1537219b2ee8SDavid du Colombier 	for(nt = line; nt->entry; nt = nt->entry)
1538219b2ee8SDavid du Colombier 		;
15393e12c5d1SDavid du Colombier 	nt->entry = t;
15403e12c5d1SDavid du Colombier 	return line;
15413e12c5d1SDavid du Colombier }
15423e12c5d1SDavid du Colombier 
15433e12c5d1SDavid du Colombier /*
15443e12c5d1SDavid du Colombier  *  create a slave process to handle a request to avoid one request blocking
15457dd7cddfSDavid du Colombier  *  another.  parent returns to job loop.
15463e12c5d1SDavid du Colombier  */
15473e12c5d1SDavid du Colombier void
15483e12c5d1SDavid du Colombier slave(void)
15493e12c5d1SDavid du Colombier {
15503e12c5d1SDavid du Colombier 	if(*isslave)
15513e12c5d1SDavid du Colombier 		return;		/* we're already a slave process */
15523e12c5d1SDavid du Colombier 
15533e12c5d1SDavid du Colombier 	switch(rfork(RFPROC|RFNOTEG|RFMEM|RFNOWAIT)){
15543e12c5d1SDavid du Colombier 	case -1:
15553e12c5d1SDavid du Colombier 		break;
15563e12c5d1SDavid du Colombier 	case 0:
1557219b2ee8SDavid du Colombier 		if(debug)
1558219b2ee8SDavid du Colombier 			syslog(0, logfile, "slave %d", getpid());
15593e12c5d1SDavid du Colombier 		*isslave = 1;
15603e12c5d1SDavid du Colombier 		break;
15613e12c5d1SDavid du Colombier 	default:
15623e12c5d1SDavid du Colombier 		longjmp(masterjmp, 1);
15633e12c5d1SDavid du Colombier 	}
15643e12c5d1SDavid du Colombier 
1565219b2ee8SDavid du Colombier }
1566219b2ee8SDavid du Colombier 
15673e12c5d1SDavid du Colombier /*
15683e12c5d1SDavid du Colombier  *  call the dns process and have it try to translate a name
15693e12c5d1SDavid du Colombier  */
15703e12c5d1SDavid du Colombier Ndbtuple*
15717dd7cddfSDavid du Colombier dnsiplookup(char *host, Ndbs *s)
15723e12c5d1SDavid du Colombier {
15733e12c5d1SDavid du Colombier 	char buf[Ndbvlen + 4];
15747dd7cddfSDavid du Colombier 	Ndbtuple *t;
15753e12c5d1SDavid du Colombier 
1576bd389b36SDavid du Colombier 	unlock(&dblock);
1577bd389b36SDavid du Colombier 
15783e12c5d1SDavid du Colombier 	/* save the name before starting a slave */
15797dd7cddfSDavid du Colombier 	snprint(buf, sizeof(buf), "%s", host);
15803e12c5d1SDavid du Colombier 
15813e12c5d1SDavid du Colombier 	slave();
15823e12c5d1SDavid du Colombier 
15837dd7cddfSDavid du Colombier 	if(strcmp(ipattr(buf), "ip") == 0)
15847dd7cddfSDavid du Colombier 		t = dnsquery(mntpt, buf, "ptr");
15857dd7cddfSDavid du Colombier 	else
15867dd7cddfSDavid du Colombier 		t = dnsquery(mntpt, buf, "ip");
15873e12c5d1SDavid du Colombier 	s->t = t;
15887dd7cddfSDavid du Colombier 
1589271b8d73SDavid du Colombier 	if(t == nil){
1590271b8d73SDavid du Colombier 		rerrstr(buf, sizeof buf);
1591271b8d73SDavid du Colombier 		if(strstr(buf, "exist"))
1592271b8d73SDavid du Colombier 			werrstr("can't translate address: %s", buf);
1593271b8d73SDavid du Colombier 		else if(strstr(buf, "dns failure"))
1594271b8d73SDavid du Colombier 			werrstr("temporary problem: %s", buf);
1595271b8d73SDavid du Colombier 	}
1596271b8d73SDavid du Colombier 
1597bd389b36SDavid du Colombier 	lock(&dblock);
15983e12c5d1SDavid du Colombier 	return t;
15993e12c5d1SDavid du Colombier }
1600219b2ee8SDavid du Colombier 
1601219b2ee8SDavid du Colombier int
1602219b2ee8SDavid du Colombier qmatch(Ndbtuple *t, char **attr, char **val, int n)
1603219b2ee8SDavid du Colombier {
1604219b2ee8SDavid du Colombier 	int i, found;
1605219b2ee8SDavid du Colombier 	Ndbtuple *nt;
1606219b2ee8SDavid du Colombier 
1607219b2ee8SDavid du Colombier 	for(i = 1; i < n; i++){
1608219b2ee8SDavid du Colombier 		found = 0;
1609219b2ee8SDavid du Colombier 		for(nt = t; nt; nt = nt->entry)
1610219b2ee8SDavid du Colombier 			if(strcmp(attr[i], nt->attr) == 0)
1611219b2ee8SDavid du Colombier 				if(strcmp(val[i], "*") == 0
1612219b2ee8SDavid du Colombier 				|| strcmp(val[i], nt->val) == 0){
1613219b2ee8SDavid du Colombier 					found = 1;
1614219b2ee8SDavid du Colombier 					break;
1615219b2ee8SDavid du Colombier 				}
1616219b2ee8SDavid du Colombier 		if(found == 0)
1617219b2ee8SDavid du Colombier 			break;
1618219b2ee8SDavid du Colombier 	}
1619219b2ee8SDavid du Colombier 	return i == n;
1620219b2ee8SDavid du Colombier }
1621219b2ee8SDavid du Colombier 
1622219b2ee8SDavid du Colombier void
1623219b2ee8SDavid du Colombier qreply(Mfile *mf, Ndbtuple *t)
1624219b2ee8SDavid du Colombier {
1625219b2ee8SDavid du Colombier 	int i;
1626219b2ee8SDavid du Colombier 	Ndbtuple *nt;
16277dd7cddfSDavid du Colombier 	char buf[2048];
1628219b2ee8SDavid du Colombier 
1629219b2ee8SDavid du Colombier 	buf[0] = 0;
1630219b2ee8SDavid du Colombier 	for(nt = t; mf->nreply < Nreply && nt; nt = nt->entry){
1631219b2ee8SDavid du Colombier 		strcat(buf, nt->attr);
1632219b2ee8SDavid du Colombier 		strcat(buf, "=");
1633219b2ee8SDavid du Colombier 		strcat(buf, nt->val);
1634219b2ee8SDavid du Colombier 		i = strlen(buf);
1635219b2ee8SDavid du Colombier 		if(nt->line != nt->entry || sizeof(buf) - i < 2*Ndbvlen+2){
1636219b2ee8SDavid du Colombier 			mf->replylen[mf->nreply] = strlen(buf);
1637219b2ee8SDavid du Colombier 			mf->reply[mf->nreply++] = strdup(buf);
1638219b2ee8SDavid du Colombier 			buf[0] = 0;
1639219b2ee8SDavid du Colombier 		} else
1640219b2ee8SDavid du Colombier 			strcat(buf, " ");
1641219b2ee8SDavid du Colombier 	}
1642219b2ee8SDavid du Colombier }
1643219b2ee8SDavid du Colombier 
16447dd7cddfSDavid du Colombier enum
16457dd7cddfSDavid du Colombier {
16467dd7cddfSDavid du Colombier 	Maxattr=	32,
16477dd7cddfSDavid du Colombier };
16487dd7cddfSDavid du Colombier 
1649219b2ee8SDavid du Colombier /*
16507dd7cddfSDavid du Colombier  *  generic query lookup.  The query is of one of the following
16517dd7cddfSDavid du Colombier  *  forms:
16527dd7cddfSDavid du Colombier  *
16537dd7cddfSDavid du Colombier  *  attr1=val1 attr2=val2 attr3=val3 ...
16547dd7cddfSDavid du Colombier  *
16557dd7cddfSDavid du Colombier  *  returns the matching tuple
16567dd7cddfSDavid du Colombier  *
16577dd7cddfSDavid du Colombier  *  ipinfo attr=val attr1 attr2 attr3 ...
16587dd7cddfSDavid du Colombier  *
16597dd7cddfSDavid du Colombier  *  is like ipinfo and returns the attr{1-n}
16607dd7cddfSDavid du Colombier  *  associated with the ip address.
1661219b2ee8SDavid du Colombier  */
1662219b2ee8SDavid du Colombier char*
1663219b2ee8SDavid du Colombier genquery(Mfile *mf, char *query)
1664219b2ee8SDavid du Colombier {
1665219b2ee8SDavid du Colombier 	int i, n;
1666219b2ee8SDavid du Colombier 	char *p;
16677dd7cddfSDavid du Colombier 	char *attr[Maxattr];
16687dd7cddfSDavid du Colombier 	char *val[Maxattr];
1669219b2ee8SDavid du Colombier 	Ndbtuple *t;
1670219b2ee8SDavid du Colombier 	Ndbs s;
1671219b2ee8SDavid du Colombier 
16727dd7cddfSDavid du Colombier 	n = getfields(query, attr, 32, 1, " ");
1673219b2ee8SDavid du Colombier 	if(n == 0)
1674219b2ee8SDavid du Colombier 		return "bad query";
1675219b2ee8SDavid du Colombier 
16767dd7cddfSDavid du Colombier 	if(strcmp(attr[0], "ipinfo") == 0)
16777dd7cddfSDavid du Colombier 		return ipinfoquery(mf, attr, n);
16787dd7cddfSDavid du Colombier 
1679219b2ee8SDavid du Colombier 	/* parse pairs */
1680219b2ee8SDavid du Colombier 	for(i = 0; i < n; i++){
1681219b2ee8SDavid du Colombier 		p = strchr(attr[i], '=');
1682219b2ee8SDavid du Colombier 		if(p == 0)
1683219b2ee8SDavid du Colombier 			return "bad query";
1684219b2ee8SDavid du Colombier 		*p++ = 0;
1685219b2ee8SDavid du Colombier 		val[i] = p;
1686219b2ee8SDavid du Colombier 	}
1687219b2ee8SDavid du Colombier 
1688219b2ee8SDavid du Colombier 	/* give dns a chance */
1689219b2ee8SDavid du Colombier 	if((strcmp(attr[0], "dom") == 0 || strcmp(attr[0], "ip") == 0) && val[0]){
16907dd7cddfSDavid du Colombier 		t = dnsiplookup(val[0], &s);
1691219b2ee8SDavid du Colombier 		if(t){
1692219b2ee8SDavid du Colombier 			if(qmatch(t, attr, val, n)){
1693219b2ee8SDavid du Colombier 				qreply(mf, t);
1694219b2ee8SDavid du Colombier 				ndbfree(t);
1695219b2ee8SDavid du Colombier 				return 0;
1696219b2ee8SDavid du Colombier 			}
1697219b2ee8SDavid du Colombier 			ndbfree(t);
1698219b2ee8SDavid du Colombier 		}
1699219b2ee8SDavid du Colombier 	}
1700219b2ee8SDavid du Colombier 
1701219b2ee8SDavid du Colombier 	/* first pair is always the key.  It can't be a '*' */
1702219b2ee8SDavid du Colombier 	t = ndbsearch(db, &s, attr[0], val[0]);
1703219b2ee8SDavid du Colombier 
1704219b2ee8SDavid du Colombier 	/* search is the and of all the pairs */
1705219b2ee8SDavid du Colombier 	while(t){
1706219b2ee8SDavid du Colombier 		if(qmatch(t, attr, val, n)){
1707219b2ee8SDavid du Colombier 			qreply(mf, t);
1708219b2ee8SDavid du Colombier 			ndbfree(t);
1709219b2ee8SDavid du Colombier 			return 0;
1710219b2ee8SDavid du Colombier 		}
1711219b2ee8SDavid du Colombier 
1712219b2ee8SDavid du Colombier 		ndbfree(t);
1713219b2ee8SDavid du Colombier 		t = ndbsnext(&s, attr[0], val[0]);
1714219b2ee8SDavid du Colombier 	}
1715219b2ee8SDavid du Colombier 
1716219b2ee8SDavid du Colombier 	return "no match";
1717219b2ee8SDavid du Colombier }
17187dd7cddfSDavid du Colombier 
17197dd7cddfSDavid du Colombier /*
17207dd7cddfSDavid du Colombier  *  resolve an ip address
17217dd7cddfSDavid du Colombier  */
17227dd7cddfSDavid du Colombier static Ndbtuple*
17237dd7cddfSDavid du Colombier ipresolve(char *attr, char *host)
17247dd7cddfSDavid du Colombier {
17257dd7cddfSDavid du Colombier 	Ndbtuple *t, *nt, **l;
17267dd7cddfSDavid du Colombier 
17277dd7cddfSDavid du Colombier 	t = iplookup(&network[Ntcp], host, "*", 0);
17287dd7cddfSDavid du Colombier 	for(l = &t; *l != nil; ){
17297dd7cddfSDavid du Colombier 		nt = *l;
17307dd7cddfSDavid du Colombier 		if(strcmp(nt->attr, "ip") != 0){
17317dd7cddfSDavid du Colombier 			*l = nt->entry;
17327dd7cddfSDavid du Colombier 			nt->entry = nil;
17337dd7cddfSDavid du Colombier 			ndbfree(nt);
17347dd7cddfSDavid du Colombier 			continue;
17357dd7cddfSDavid du Colombier 		}
17367dd7cddfSDavid du Colombier 		strcpy(nt->attr, attr);
17377dd7cddfSDavid du Colombier 		l = &nt->entry;
17387dd7cddfSDavid du Colombier 	}
17397dd7cddfSDavid du Colombier 	return t;
17407dd7cddfSDavid du Colombier }
17417dd7cddfSDavid du Colombier 
17427dd7cddfSDavid du Colombier char*
17437dd7cddfSDavid du Colombier ipinfoquery(Mfile *mf, char **list, int n)
17447dd7cddfSDavid du Colombier {
17457dd7cddfSDavid du Colombier 	int i, nresolve;
17467dd7cddfSDavid du Colombier 	int resolve[Maxattr];
17477dd7cddfSDavid du Colombier 	Ndbtuple *t, *nt, **l;
17487dd7cddfSDavid du Colombier 	char *attr, *val;
17497dd7cddfSDavid du Colombier 
17507dd7cddfSDavid du Colombier 	/* skip 'ipinfo' */
17517dd7cddfSDavid du Colombier 	list++; n--;
17527dd7cddfSDavid du Colombier 
17537dd7cddfSDavid du Colombier 	if(n < 2)
17547dd7cddfSDavid du Colombier 		return "bad query";
17557dd7cddfSDavid du Colombier 
17567dd7cddfSDavid du Colombier 	/* get search attribute=value */
17577dd7cddfSDavid du Colombier 	attr = *list++; n--;
17587dd7cddfSDavid du Colombier 	val = strchr(attr, '=');
17597dd7cddfSDavid du Colombier 	if(val == nil)
17607dd7cddfSDavid du Colombier 		return "bad query";
17617dd7cddfSDavid du Colombier 	*val++ = 0;
17627dd7cddfSDavid du Colombier 
17637dd7cddfSDavid du Colombier 	/*
17647dd7cddfSDavid du Colombier 	 *  don't let ndbipinfo resolve the addresses, we're
17657dd7cddfSDavid du Colombier 	 *  better at it.
17667dd7cddfSDavid du Colombier 	 */
17677dd7cddfSDavid du Colombier 	nresolve = 0;
17687dd7cddfSDavid du Colombier 	for(i = 0; i < n; i++)
17697dd7cddfSDavid du Colombier 		if(*list[i] == '@'){
17707dd7cddfSDavid du Colombier 			list[i]++;
17717dd7cddfSDavid du Colombier 			resolve[i] = 1;
17727dd7cddfSDavid du Colombier 			nresolve++;
17737dd7cddfSDavid du Colombier 		} else
17747dd7cddfSDavid du Colombier 			resolve[i] = 0;
17757dd7cddfSDavid du Colombier 
17767dd7cddfSDavid du Colombier 	t = ndbipinfo(db, attr, val, list, n);
17777dd7cddfSDavid du Colombier 	if(t == nil)
17787dd7cddfSDavid du Colombier 		return "no match";
17797dd7cddfSDavid du Colombier 
17807dd7cddfSDavid du Colombier 	if(nresolve != 0){
17817dd7cddfSDavid du Colombier 		for(l = &t; *l != nil;){
17827dd7cddfSDavid du Colombier 			nt = *l;
17837dd7cddfSDavid du Colombier 
17847dd7cddfSDavid du Colombier 			/* already an address? */
17857dd7cddfSDavid du Colombier 			if(strcmp(ipattr(nt->val), "ip") == 0){
17867dd7cddfSDavid du Colombier 				l = &(*l)->entry;
17877dd7cddfSDavid du Colombier 				continue;
17887dd7cddfSDavid du Colombier 			}
17897dd7cddfSDavid du Colombier 
17907dd7cddfSDavid du Colombier 			/* user wants it resolved? */
17917dd7cddfSDavid du Colombier 			for(i = 0; i < n; i++)
17927dd7cddfSDavid du Colombier 				if(strcmp(list[i], nt->attr) == 0)
17937dd7cddfSDavid du Colombier 					break;
17947dd7cddfSDavid du Colombier 			if(i >= n || resolve[i] == 0){
17957dd7cddfSDavid du Colombier 				l = &(*l)->entry;
17967dd7cddfSDavid du Colombier 				continue;
17977dd7cddfSDavid du Colombier 			}
17987dd7cddfSDavid du Colombier 
17997dd7cddfSDavid du Colombier 			/* resolve address and replace entry */
18007dd7cddfSDavid du Colombier 			*l = ipresolve(nt->attr, nt->val);
18017dd7cddfSDavid du Colombier 			while(*l != nil)
18027dd7cddfSDavid du Colombier 				l = &(*l)->entry;
18037dd7cddfSDavid du Colombier 			*l = nt->entry;
18047dd7cddfSDavid du Colombier 
18057dd7cddfSDavid du Colombier 			nt->entry = nil;
18067dd7cddfSDavid du Colombier 			ndbfree(nt);
18077dd7cddfSDavid du Colombier 		}
18087dd7cddfSDavid du Colombier 	}
18097dd7cddfSDavid du Colombier 
18107dd7cddfSDavid du Colombier 	/* make it all one line */
18117dd7cddfSDavid du Colombier 	for(nt = t; nt != nil; nt = nt->entry){
18127dd7cddfSDavid du Colombier 		if(nt->entry == nil)
18137dd7cddfSDavid du Colombier 			nt->line = t;
18147dd7cddfSDavid du Colombier 		else
18157dd7cddfSDavid du Colombier 			nt->line = nt->entry;
18167dd7cddfSDavid du Colombier 	}
18177dd7cddfSDavid du Colombier 
18187dd7cddfSDavid du Colombier 	qreply(mf, t);
18197dd7cddfSDavid du Colombier 
18207dd7cddfSDavid du Colombier 	return nil;
18217dd7cddfSDavid du Colombier }
18227dd7cddfSDavid du Colombier 
18237dd7cddfSDavid du Colombier void*
18247dd7cddfSDavid du Colombier emalloc(int size)
18257dd7cddfSDavid du Colombier {
18267dd7cddfSDavid du Colombier 	void *x;
18277dd7cddfSDavid du Colombier 
18287dd7cddfSDavid du Colombier 	x = malloc(size);
18297dd7cddfSDavid du Colombier 	if(x == nil)
18307dd7cddfSDavid du Colombier 		abort();
18317dd7cddfSDavid du Colombier 	memset(x, 0, size);
18327dd7cddfSDavid du Colombier 	return x;
18337dd7cddfSDavid du Colombier }
18349a747e4fSDavid du Colombier 
18359a747e4fSDavid du Colombier char*
18369a747e4fSDavid du Colombier estrdup(char *s)
18379a747e4fSDavid du Colombier {
18389a747e4fSDavid du Colombier 	int size;
18399a747e4fSDavid du Colombier 	char *p;
18409a747e4fSDavid du Colombier 
18419a747e4fSDavid du Colombier 	size = strlen(s)+1;
18429a747e4fSDavid du Colombier 	p = malloc(size);
18439a747e4fSDavid du Colombier 	if(p == nil)
18449a747e4fSDavid du Colombier 		abort();
18459a747e4fSDavid du Colombier 	memmove(p, s, size);
18469a747e4fSDavid du Colombier 	return p;
18479a747e4fSDavid du Colombier }
1848