xref: /plan9/sys/src/cmd/ndb/cs.c (revision 254fe3d33c382063ab759e3351c8169ee4bc264e)
13e12c5d1SDavid du Colombier #include <u.h>
23e12c5d1SDavid du Colombier #include <libc.h>
3219b2ee8SDavid du Colombier #include <auth.h>
43e12c5d1SDavid du Colombier #include <fcall.h>
53e12c5d1SDavid du Colombier #include <bio.h>
63e12c5d1SDavid du Colombier #include <ctype.h>
73e12c5d1SDavid du Colombier #include <ndb.h>
83e12c5d1SDavid du Colombier #include <ip.h>
995a264b3SDavid du Colombier #include <String.h>
103e12c5d1SDavid du Colombier 
113e12c5d1SDavid du Colombier enum
123e12c5d1SDavid du Colombier {
1380ee5cbfSDavid du Colombier 	Nreply=			20,
143e12c5d1SDavid du Colombier 	Maxreply=		256,
157dd7cddfSDavid du Colombier 	Maxrequest=		128,
167dd7cddfSDavid du Colombier 	Maxpath=		128,
179a747e4fSDavid du Colombier 	Maxfdata=		8192,
1895a264b3SDavid du Colombier 	Maxhost=		64,		/* maximum host name size */
1995a264b3SDavid du Colombier 	Maxservice=		64,		/* maximum service name size */
203e12c5d1SDavid du Colombier 
219a747e4fSDavid du Colombier 	Qdir=			0,
223e12c5d1SDavid du Colombier 	Qcs=			1,
233e12c5d1SDavid du Colombier };
243e12c5d1SDavid du Colombier 
253e12c5d1SDavid du Colombier typedef struct Mfile	Mfile;
26219b2ee8SDavid du Colombier typedef struct Mlist	Mlist;
273e12c5d1SDavid du Colombier typedef struct Network	Network;
287dd7cddfSDavid du Colombier typedef struct Flushreq	Flushreq;
297dd7cddfSDavid du Colombier typedef struct Job	Job;
303e12c5d1SDavid du Colombier 
313e12c5d1SDavid du Colombier int vers;		/* incremented each clone/attach */
323e12c5d1SDavid du Colombier 
333e12c5d1SDavid du Colombier struct Mfile
343e12c5d1SDavid du Colombier {
353e12c5d1SDavid du Colombier 	int		busy;
36219b2ee8SDavid du Colombier 
379a747e4fSDavid du Colombier 	char		*user;
383e12c5d1SDavid du Colombier 	Qid		qid;
393e12c5d1SDavid du Colombier 	int		fid;
403e12c5d1SDavid du Colombier 
4180ee5cbfSDavid du Colombier 	/*
4280ee5cbfSDavid du Colombier 	 *  current request
4380ee5cbfSDavid du Colombier 	 */
4480ee5cbfSDavid du Colombier 	char		*net;
4580ee5cbfSDavid du Colombier 	char		*host;
4680ee5cbfSDavid du Colombier 	char		*serv;
4780ee5cbfSDavid du Colombier 	char		*rem;
4880ee5cbfSDavid du Colombier 
4980ee5cbfSDavid du Colombier 	/*
5080ee5cbfSDavid du Colombier 	 *  result of the last lookup
5180ee5cbfSDavid du Colombier 	 */
5280ee5cbfSDavid du Colombier 	Network		*nextnet;
53219b2ee8SDavid du Colombier 	int		nreply;
54219b2ee8SDavid du Colombier 	char		*reply[Nreply];
55219b2ee8SDavid du Colombier 	int		replylen[Nreply];
56219b2ee8SDavid du Colombier };
57219b2ee8SDavid du Colombier 
58219b2ee8SDavid du Colombier struct Mlist
59219b2ee8SDavid du Colombier {
60219b2ee8SDavid du Colombier 	Mlist	*next;
61219b2ee8SDavid du Colombier 	Mfile	mf;
623e12c5d1SDavid du Colombier };
633e12c5d1SDavid du Colombier 
649a747e4fSDavid du Colombier 
65244672c5SDavid du Colombier /*
66244672c5SDavid du Colombier  *  active requests
67244672c5SDavid du Colombier  */
687dd7cddfSDavid du Colombier struct Job
697dd7cddfSDavid du Colombier {
707dd7cddfSDavid du Colombier 	Job	*next;
717dd7cddfSDavid du Colombier 	int	flushed;
727dd7cddfSDavid du Colombier 	Fcall	request;
737dd7cddfSDavid du Colombier 	Fcall	reply;
747dd7cddfSDavid du Colombier };
757dd7cddfSDavid du Colombier Lock	joblock;
767dd7cddfSDavid du Colombier Job	*joblist;
777dd7cddfSDavid du Colombier 
78219b2ee8SDavid du Colombier Mlist	*mlist;
793e12c5d1SDavid du Colombier int	mfd[2];
803e12c5d1SDavid du Colombier int	debug;
817dd7cddfSDavid du Colombier int	paranoia;
823e12c5d1SDavid du Colombier jmp_buf	masterjmp;	/* return through here after a slave process has been created */
833e12c5d1SDavid du Colombier int	*isslave;	/* *isslave non-zero means this is a slave process */
84bd389b36SDavid du Colombier char	*dbfile;
857dd7cddfSDavid du Colombier Ndb	*db, *netdb;
863e12c5d1SDavid du Colombier 
879a747e4fSDavid du Colombier void	rversion(Job*);
887dd7cddfSDavid du Colombier void	rflush(Job*);
897dd7cddfSDavid du Colombier void	rattach(Job*, Mfile*);
907dd7cddfSDavid du Colombier char*	rwalk(Job*, Mfile*);
917dd7cddfSDavid du Colombier void	ropen(Job*, Mfile*);
927dd7cddfSDavid du Colombier void	rcreate(Job*, Mfile*);
937dd7cddfSDavid du Colombier void	rread(Job*, Mfile*);
947dd7cddfSDavid du Colombier void	rwrite(Job*, Mfile*);
957dd7cddfSDavid du Colombier void	rclunk(Job*, Mfile*);
967dd7cddfSDavid du Colombier void	rremove(Job*, Mfile*);
977dd7cddfSDavid du Colombier void	rstat(Job*, Mfile*);
987dd7cddfSDavid du Colombier void	rwstat(Job*, Mfile*);
999a747e4fSDavid du Colombier void	rauth(Job*);
1007dd7cddfSDavid du Colombier void	sendmsg(Job*, char*);
1013e12c5d1SDavid du Colombier void	error(char*);
1027dd7cddfSDavid du Colombier void	mountinit(char*, char*);
1033e12c5d1SDavid du Colombier void	io(void);
1047dd7cddfSDavid du Colombier void	ndbinit(void);
1057dd7cddfSDavid du Colombier void	netinit(int);
1063e12c5d1SDavid du Colombier void	netadd(char*);
107219b2ee8SDavid du Colombier char	*genquery(Mfile*, char*);
1087dd7cddfSDavid du Colombier char*	ipinfoquery(Mfile*, char**, int);
109bd389b36SDavid du Colombier int	needproto(Network*, Ndbtuple*);
1109a747e4fSDavid du Colombier int	lookup(Mfile*);
1113e12c5d1SDavid du Colombier Ndbtuple*	reorder(Ndbtuple*, Ndbtuple*);
1127dd7cddfSDavid du Colombier void	ipid(void);
1137dd7cddfSDavid du Colombier void	readipinterfaces(void);
1147dd7cddfSDavid du Colombier void*	emalloc(int);
1159a747e4fSDavid du Colombier char*	estrdup(char*);
1167dd7cddfSDavid du Colombier Job*	newjob(void);
1177dd7cddfSDavid du Colombier void	freejob(Job*);
1187dd7cddfSDavid du Colombier void	setext(char*, int, char*);
11980ee5cbfSDavid du Colombier void	cleanmf(Mfile*);
1203e12c5d1SDavid du Colombier 
121bd389b36SDavid du Colombier extern void	paralloc(void);
122bd389b36SDavid du Colombier 
123bd389b36SDavid du Colombier Lock	dblock;		/* mutex on database operations */
1247dd7cddfSDavid du Colombier Lock	netlock;	/* mutex for netinit() */
125bd389b36SDavid du Colombier 
126219b2ee8SDavid du Colombier char	*logfile = "cs";
1277dd7cddfSDavid du Colombier char	*paranoiafile = "cs.paranoia";
128219b2ee8SDavid du Colombier 
1297dd7cddfSDavid du Colombier char	mntpt[Maxpath];
1307dd7cddfSDavid du Colombier char	netndb[Maxpath];
1317dd7cddfSDavid du Colombier 
13280ee5cbfSDavid du Colombier /*
13380ee5cbfSDavid du Colombier  *  Network specific translators
13480ee5cbfSDavid du Colombier  */
13580ee5cbfSDavid du Colombier Ndbtuple*	iplookup(Network*, char*, char*, int);
13680ee5cbfSDavid du Colombier char*		iptrans(Ndbtuple*, Network*, char*, char*, int);
13780ee5cbfSDavid du Colombier Ndbtuple*	telcolookup(Network*, char*, char*, int);
13880ee5cbfSDavid du Colombier char*		telcotrans(Ndbtuple*, Network*, char*, char*, int);
13980ee5cbfSDavid du Colombier Ndbtuple*	dnsiplookup(char*, Ndbs*);
14080ee5cbfSDavid du Colombier 
14180ee5cbfSDavid du Colombier struct Network
14280ee5cbfSDavid du Colombier {
14380ee5cbfSDavid du Colombier 	char		*net;
14480ee5cbfSDavid du Colombier 	Ndbtuple	*(*lookup)(Network*, char*, char*, int);
14580ee5cbfSDavid du Colombier 	char		*(*trans)(Ndbtuple*, Network*, char*, char*, int);
146617c0e1eSDavid du Colombier 	int		considered;		/* flag: ignored for "net!"? */
147617c0e1eSDavid du Colombier 	int		fasttimeouthack;	/* flag. was for IL */
14880ee5cbfSDavid du Colombier 	Network		*next;
14980ee5cbfSDavid du Colombier };
15080ee5cbfSDavid du Colombier 
15180ee5cbfSDavid du Colombier enum
15280ee5cbfSDavid du Colombier {
15375766116SDavid du Colombier 	Ntcp = 0,
15480ee5cbfSDavid du Colombier };
15580ee5cbfSDavid du Colombier 
15680ee5cbfSDavid du Colombier /*
157244672c5SDavid du Colombier  *  net doesn't apply to (r)udp, icmp(v6), or telco (for speed).
15880ee5cbfSDavid du Colombier  */
15980ee5cbfSDavid du Colombier Network network[] = {
160617c0e1eSDavid du Colombier [Ntcp]	{ "tcp",	iplookup,	iptrans,	0 },
161617c0e1eSDavid du Colombier 	{ "udp",	iplookup,	iptrans,	1 },
162617c0e1eSDavid du Colombier 	{ "icmp",	iplookup,	iptrans,	1 },
163617c0e1eSDavid du Colombier 	{ "icmpv6",	iplookup,	iptrans,	1 },
164617c0e1eSDavid du Colombier 	{ "rudp",	iplookup,	iptrans,	1 },
165617c0e1eSDavid du Colombier 	{ "telco",	telcolookup,	telcotrans,	1 },
16680ee5cbfSDavid du Colombier 	{ 0 },
16780ee5cbfSDavid du Colombier };
16880ee5cbfSDavid du Colombier 
16980ee5cbfSDavid du Colombier Lock ipifclock;
17080ee5cbfSDavid du Colombier Ipifc *ipifcs;
17180ee5cbfSDavid du Colombier 
17295a264b3SDavid du Colombier char	eaddr[16];		/* ascii ethernet address */
17395a264b3SDavid du Colombier char	ipaddr[64];		/* ascii internet address */
17480ee5cbfSDavid du Colombier uchar	ipa[IPaddrlen];		/* binary internet address */
17595a264b3SDavid du Colombier char	*mysysname;
17680ee5cbfSDavid du Colombier 
17780ee5cbfSDavid du Colombier Network *netlist;		/* networks ordered by preference */
17880ee5cbfSDavid du Colombier Network *last;
17980ee5cbfSDavid du Colombier 
18095a264b3SDavid du Colombier static void
18195a264b3SDavid du Colombier nstrcpy(char *to, char *from, int len)
18295a264b3SDavid du Colombier {
18395a264b3SDavid du Colombier 	strncpy(to, from, len);
18495a264b3SDavid du Colombier 	to[len-1] = 0;
18595a264b3SDavid du Colombier }
18695a264b3SDavid du Colombier 
1877dd7cddfSDavid du Colombier void
1887dd7cddfSDavid du Colombier usage(void)
1897dd7cddfSDavid du Colombier {
19075766116SDavid du Colombier 	fprint(2, "usage: %s [-dn] [-f ndb-file] [-x netmtpt]\n", argv0);
1917dd7cddfSDavid du Colombier 	exits("usage");
1927dd7cddfSDavid du Colombier }
193219b2ee8SDavid du Colombier 
194*254fe3d3SDavid du Colombier /*
195*254fe3d3SDavid du Colombier  * based on libthread's threadsetname, but drags in less library code.
196*254fe3d3SDavid du Colombier  * actually just sets the arguments displayed.
197*254fe3d3SDavid du Colombier  */
198*254fe3d3SDavid du Colombier void
199*254fe3d3SDavid du Colombier procsetname(char *fmt, ...)
200*254fe3d3SDavid du Colombier {
201*254fe3d3SDavid du Colombier 	int fd;
202*254fe3d3SDavid du Colombier 	char *cmdname;
203*254fe3d3SDavid du Colombier 	char buf[128];
204*254fe3d3SDavid du Colombier 	va_list arg;
205*254fe3d3SDavid du Colombier 
206*254fe3d3SDavid du Colombier 	va_start(arg, fmt);
207*254fe3d3SDavid du Colombier 	cmdname = vsmprint(fmt, arg);
208*254fe3d3SDavid du Colombier 	va_end(arg);
209*254fe3d3SDavid du Colombier 	if (cmdname == nil)
210*254fe3d3SDavid du Colombier 		return;
211*254fe3d3SDavid du Colombier 	snprint(buf, sizeof buf, "#p/%d/args", getpid());
212*254fe3d3SDavid du Colombier 	if((fd = open(buf, OWRITE)) >= 0){
213*254fe3d3SDavid du Colombier 		write(fd, cmdname, strlen(cmdname)+1);
214*254fe3d3SDavid du Colombier 		close(fd);
215*254fe3d3SDavid du Colombier 	}
216*254fe3d3SDavid du Colombier 	free(cmdname);
217*254fe3d3SDavid du Colombier }
218*254fe3d3SDavid du Colombier 
2193e12c5d1SDavid du Colombier void
2203e12c5d1SDavid du Colombier main(int argc, char *argv[])
2213e12c5d1SDavid du Colombier {
222219b2ee8SDavid du Colombier 	int justsetname;
22375766116SDavid du Colombier 	char ext[Maxpath], servefile[Maxpath];
2243e12c5d1SDavid du Colombier 
225219b2ee8SDavid du Colombier 	justsetname = 0;
2267dd7cddfSDavid du Colombier 	setnetmtpt(mntpt, sizeof(mntpt), nil);
2277dd7cddfSDavid du Colombier 	ext[0] = 0;
2283e12c5d1SDavid du Colombier 	ARGBEGIN{
2293e12c5d1SDavid du Colombier 	case 'd':
2303e12c5d1SDavid du Colombier 		debug = 1;
2313e12c5d1SDavid du Colombier 		break;
232bd389b36SDavid du Colombier 	case 'f':
23375766116SDavid du Colombier 		dbfile = EARGF(usage());
234bd389b36SDavid du Colombier 		break;
235219b2ee8SDavid du Colombier 	case 'n':
236219b2ee8SDavid du Colombier 		justsetname = 1;
237219b2ee8SDavid du Colombier 		break;
23875766116SDavid du Colombier 	case 'x':
23975766116SDavid du Colombier 		setnetmtpt(mntpt, sizeof(mntpt), EARGF(usage()));
24075766116SDavid du Colombier 		setext(ext, sizeof(ext), mntpt);
24175766116SDavid du Colombier 		break;
2423e12c5d1SDavid du Colombier 	}ARGEND
2433e12c5d1SDavid du Colombier 	USED(argc);
2443e12c5d1SDavid du Colombier 	USED(argv);
2453e12c5d1SDavid du Colombier 
2467dd7cddfSDavid du Colombier 	rfork(RFREND|RFNOTEG);
2477dd7cddfSDavid du Colombier 
2487dd7cddfSDavid du Colombier 	snprint(servefile, sizeof(servefile), "#s/cs%s", ext);
2497dd7cddfSDavid du Colombier 	snprint(netndb, sizeof(netndb), "%s/ndb", mntpt);
2507dd7cddfSDavid du Colombier 	unmount(servefile, mntpt);
2517dd7cddfSDavid du Colombier 	remove(servefile);
2527dd7cddfSDavid du Colombier 
2539a747e4fSDavid du Colombier 	fmtinstall('E', eipfmt);
2549a747e4fSDavid du Colombier 	fmtinstall('I', eipfmt);
2559a747e4fSDavid du Colombier 	fmtinstall('M', eipfmt);
2569a747e4fSDavid du Colombier 	fmtinstall('F', fcallfmt);
2577dd7cddfSDavid du Colombier 
2587dd7cddfSDavid du Colombier 	ndbinit();
2597dd7cddfSDavid du Colombier 	netinit(0);
2607dd7cddfSDavid du Colombier 
2617dd7cddfSDavid du Colombier 	if(!justsetname){
2627dd7cddfSDavid du Colombier 		mountinit(servefile, mntpt);
2637dd7cddfSDavid du Colombier 		io();
2647dd7cddfSDavid du Colombier 	}
265219b2ee8SDavid du Colombier 	exits(0);
266219b2ee8SDavid du Colombier }
267219b2ee8SDavid du Colombier 
2687dd7cddfSDavid du Colombier /*
2697dd7cddfSDavid du Colombier  *  if a mount point is specified, set the cs extention to be the mount point
2707dd7cddfSDavid du Colombier  *  with '_'s replacing '/'s
2717dd7cddfSDavid du Colombier  */
2727dd7cddfSDavid du Colombier void
2737dd7cddfSDavid du Colombier setext(char *ext, int n, char *p)
2747dd7cddfSDavid du Colombier {
2757dd7cddfSDavid du Colombier 	int i, c;
2763e12c5d1SDavid du Colombier 
2777dd7cddfSDavid du Colombier 	n--;
2787dd7cddfSDavid du Colombier 	for(i = 0; i < n; i++){
2797dd7cddfSDavid du Colombier 		c = p[i];
2807dd7cddfSDavid du Colombier 		if(c == 0)
2817dd7cddfSDavid du Colombier 			break;
2827dd7cddfSDavid du Colombier 		if(c == '/')
2837dd7cddfSDavid du Colombier 			c = '_';
2847dd7cddfSDavid du Colombier 		ext[i] = c;
2857dd7cddfSDavid du Colombier 	}
2867dd7cddfSDavid du Colombier 	ext[i] = 0;
2873e12c5d1SDavid du Colombier }
2883e12c5d1SDavid du Colombier 
2893e12c5d1SDavid du Colombier void
2907dd7cddfSDavid du Colombier mountinit(char *service, char *mntpt)
2913e12c5d1SDavid du Colombier {
2923e12c5d1SDavid du Colombier 	int f;
2933e12c5d1SDavid du Colombier 	int p[2];
2943e12c5d1SDavid du Colombier 	char buf[32];
2953e12c5d1SDavid du Colombier 
2963e12c5d1SDavid du Colombier 	if(pipe(p) < 0)
2973e12c5d1SDavid du Colombier 		error("pipe failed");
298a9f680aeSDavid du Colombier 
299a9f680aeSDavid du Colombier 	/*
300a9f680aeSDavid du Colombier 	 *  make a /srv/cs
301a9f680aeSDavid du Colombier 	 */
302a9f680aeSDavid du Colombier 	f = create(service, OWRITE|ORCLOSE, 0666);
303a9f680aeSDavid du Colombier 	if(f < 0)
304a9f680aeSDavid du Colombier 		error(service);
305a9f680aeSDavid du Colombier 	snprint(buf, sizeof(buf), "%d", p[1]);
306a9f680aeSDavid du Colombier 	if(write(f, buf, strlen(buf)) != strlen(buf))
307a9f680aeSDavid du Colombier 		error("write /srv/cs");
308a9f680aeSDavid du Colombier 
309219b2ee8SDavid du Colombier 	switch(rfork(RFFDG|RFPROC|RFNAMEG)){
3103e12c5d1SDavid du Colombier 	case 0:
311219b2ee8SDavid du Colombier 		close(p[1]);
312*254fe3d3SDavid du Colombier 		procsetname("%s", mntpt);
3133e12c5d1SDavid du Colombier 		break;
3143e12c5d1SDavid du Colombier 	case -1:
3153e12c5d1SDavid du Colombier 		error("fork failed\n");
3163e12c5d1SDavid du Colombier 	default:
3173e12c5d1SDavid du Colombier 		/*
3183e12c5d1SDavid du Colombier 		 *  put ourselves into the file system
3193e12c5d1SDavid du Colombier 		 */
320219b2ee8SDavid du Colombier 		close(p[0]);
3219a747e4fSDavid du Colombier 		if(mount(p[1], -1, mntpt, MAFTER, "") < 0)
3223e12c5d1SDavid du Colombier 			error("mount failed\n");
323219b2ee8SDavid du Colombier 		_exits(0);
3243e12c5d1SDavid du Colombier 	}
3253e12c5d1SDavid du Colombier 	mfd[0] = mfd[1] = p[0];
3263e12c5d1SDavid du Colombier }
3273e12c5d1SDavid du Colombier 
3287dd7cddfSDavid du Colombier void
3297dd7cddfSDavid du Colombier ndbinit(void)
3307dd7cddfSDavid du Colombier {
3317dd7cddfSDavid du Colombier 	db = ndbopen(dbfile);
3327dd7cddfSDavid du Colombier 	if(db == nil)
3337dd7cddfSDavid du Colombier 		error("can't open network database");
3347dd7cddfSDavid du Colombier 
3357dd7cddfSDavid du Colombier 	netdb = ndbopen(netndb);
3367dd7cddfSDavid du Colombier 	if(netdb != nil){
3377dd7cddfSDavid du Colombier 		netdb->nohash = 1;
3387dd7cddfSDavid du Colombier 		db = ndbcat(netdb, db);
3397dd7cddfSDavid du Colombier 	}
3407dd7cddfSDavid du Colombier }
3417dd7cddfSDavid du Colombier 
3423e12c5d1SDavid du Colombier Mfile*
3433e12c5d1SDavid du Colombier newfid(int fid)
3443e12c5d1SDavid du Colombier {
345219b2ee8SDavid du Colombier 	Mlist *f, *ff;
3463e12c5d1SDavid du Colombier 	Mfile *mf;
3473e12c5d1SDavid du Colombier 
348219b2ee8SDavid du Colombier 	ff = 0;
349219b2ee8SDavid du Colombier 	for(f = mlist; f; f = f->next)
350219b2ee8SDavid du Colombier 		if(f->mf.busy && f->mf.fid == fid)
351219b2ee8SDavid du Colombier 			return &f->mf;
352219b2ee8SDavid du Colombier 		else if(!ff && !f->mf.busy)
353219b2ee8SDavid du Colombier 			ff = f;
354219b2ee8SDavid du Colombier 	if(ff == 0){
3557dd7cddfSDavid du Colombier 		ff = emalloc(sizeof *f);
356219b2ee8SDavid du Colombier 		ff->next = mlist;
357219b2ee8SDavid du Colombier 		mlist = ff;
3583e12c5d1SDavid du Colombier 	}
359219b2ee8SDavid du Colombier 	mf = &ff->mf;
360219b2ee8SDavid du Colombier 	memset(mf, 0, sizeof *mf);
3613e12c5d1SDavid du Colombier 	mf->fid = fid;
3623e12c5d1SDavid du Colombier 	return mf;
3633e12c5d1SDavid du Colombier }
3643e12c5d1SDavid du Colombier 
3657dd7cddfSDavid du Colombier Job*
3667dd7cddfSDavid du Colombier newjob(void)
3677dd7cddfSDavid du Colombier {
3687dd7cddfSDavid du Colombier 	Job *job;
3697dd7cddfSDavid du Colombier 
3707dd7cddfSDavid du Colombier 	job = mallocz(sizeof(Job), 1);
3717dd7cddfSDavid du Colombier 	lock(&joblock);
3727dd7cddfSDavid du Colombier 	job->next = joblist;
3737dd7cddfSDavid du Colombier 	joblist = job;
3747dd7cddfSDavid du Colombier 	job->request.tag = -1;
3757dd7cddfSDavid du Colombier 	unlock(&joblock);
3767dd7cddfSDavid du Colombier 	return job;
3777dd7cddfSDavid du Colombier }
3787dd7cddfSDavid du Colombier 
3797dd7cddfSDavid du Colombier void
3807dd7cddfSDavid du Colombier freejob(Job *job)
3817dd7cddfSDavid du Colombier {
3827dd7cddfSDavid du Colombier 	Job **l;
3837dd7cddfSDavid du Colombier 
3847dd7cddfSDavid du Colombier 	lock(&joblock);
3857dd7cddfSDavid du Colombier 	for(l = &joblist; *l; l = &(*l)->next){
3867dd7cddfSDavid du Colombier 		if((*l) == job){
3877dd7cddfSDavid du Colombier 			*l = job->next;
3887dd7cddfSDavid du Colombier 			free(job);
3897dd7cddfSDavid du Colombier 			break;
3907dd7cddfSDavid du Colombier 		}
3917dd7cddfSDavid du Colombier 	}
3927dd7cddfSDavid du Colombier 	unlock(&joblock);
3937dd7cddfSDavid du Colombier }
3947dd7cddfSDavid du Colombier 
3957dd7cddfSDavid du Colombier void
3967dd7cddfSDavid du Colombier flushjob(int tag)
3977dd7cddfSDavid du Colombier {
3987dd7cddfSDavid du Colombier 	Job *job;
3997dd7cddfSDavid du Colombier 
4007dd7cddfSDavid du Colombier 	lock(&joblock);
4017dd7cddfSDavid du Colombier 	for(job = joblist; job; job = job->next){
4027dd7cddfSDavid du Colombier 		if(job->request.tag == tag && job->request.type != Tflush){
4037dd7cddfSDavid du Colombier 			job->flushed = 1;
4047dd7cddfSDavid du Colombier 			break;
4057dd7cddfSDavid du Colombier 		}
4067dd7cddfSDavid du Colombier 	}
4077dd7cddfSDavid du Colombier 	unlock(&joblock);
4087dd7cddfSDavid du Colombier }
4097dd7cddfSDavid du Colombier 
4103e12c5d1SDavid du Colombier void
4113e12c5d1SDavid du Colombier io(void)
4123e12c5d1SDavid du Colombier {
4133e12c5d1SDavid du Colombier 	long n;
4143e12c5d1SDavid du Colombier 	Mfile *mf;
4153e12c5d1SDavid du Colombier 	int slaveflag;
4169a747e4fSDavid du Colombier 	uchar mdata[IOHDRSZ + Maxfdata];
4177dd7cddfSDavid du Colombier 	Job *job;
4183e12c5d1SDavid du Colombier 
4193e12c5d1SDavid du Colombier 	/*
4203e12c5d1SDavid du Colombier 	 *  if we ask dns to fulfill requests,
4213e12c5d1SDavid du Colombier 	 *  a slave process is created to wait for replies.  The
4229a747e4fSDavid du Colombier 	 *  master process returns immediately via a longjmp
4233e12c5d1SDavid du Colombier 	 *  through 'masterjmp'.
4243e12c5d1SDavid du Colombier 	 *
4253e12c5d1SDavid du Colombier 	 *  *isslave is a pointer into the call stack to a variable
4263e12c5d1SDavid du Colombier 	 *  that tells whether or not the current process is a slave.
4273e12c5d1SDavid du Colombier 	 */
4283e12c5d1SDavid du Colombier 	slaveflag = 0;		/* init slave variable */
4293e12c5d1SDavid du Colombier 	isslave = &slaveflag;
4303e12c5d1SDavid du Colombier 	setjmp(masterjmp);
4313e12c5d1SDavid du Colombier 
4323e12c5d1SDavid du Colombier 	for(;;){
4339a747e4fSDavid du Colombier 		n = read9pmsg(mfd[0], mdata, sizeof mdata);
4343e12c5d1SDavid du Colombier 		if(n<=0)
4353e12c5d1SDavid du Colombier 			error("mount read");
4367dd7cddfSDavid du Colombier 		job = newjob();
4379a747e4fSDavid du Colombier 		if(convM2S(mdata, n, &job->request) != n){
438271b8d73SDavid du Colombier 			syslog(1, logfile, "format error %ux %ux %ux %ux %ux",
439271b8d73SDavid du Colombier 				mdata[0], mdata[1], mdata[2], mdata[3], mdata[4]);
4407dd7cddfSDavid du Colombier 			freejob(job);
4413e12c5d1SDavid du Colombier 			continue;
4423e12c5d1SDavid du Colombier 		}
443bd389b36SDavid du Colombier 		lock(&dblock);
4447dd7cddfSDavid du Colombier 		mf = newfid(job->request.fid);
445219b2ee8SDavid du Colombier 		if(debug)
4467dd7cddfSDavid du Colombier 			syslog(0, logfile, "%F", &job->request);
4473e12c5d1SDavid du Colombier 
4483e12c5d1SDavid du Colombier 
4497dd7cddfSDavid du Colombier 		switch(job->request.type){
4503e12c5d1SDavid du Colombier 		default:
4517dd7cddfSDavid du Colombier 			syslog(1, logfile, "unknown request type %d", job->request.type);
4523e12c5d1SDavid du Colombier 			break;
4539a747e4fSDavid du Colombier 		case Tversion:
4549a747e4fSDavid du Colombier 			rversion(job);
4553e12c5d1SDavid du Colombier 			break;
4569a747e4fSDavid du Colombier 		case Tauth:
4579a747e4fSDavid du Colombier 			rauth(job);
4583e12c5d1SDavid du Colombier 			break;
4593e12c5d1SDavid du Colombier 		case Tflush:
4607dd7cddfSDavid du Colombier 			rflush(job);
4613e12c5d1SDavid du Colombier 			break;
4623e12c5d1SDavid du Colombier 		case Tattach:
4637dd7cddfSDavid du Colombier 			rattach(job, mf);
4643e12c5d1SDavid du Colombier 			break;
4653e12c5d1SDavid du Colombier 		case Twalk:
4667dd7cddfSDavid du Colombier 			rwalk(job, mf);
4673e12c5d1SDavid du Colombier 			break;
4683e12c5d1SDavid du Colombier 		case Topen:
4697dd7cddfSDavid du Colombier 			ropen(job, mf);
4703e12c5d1SDavid du Colombier 			break;
4713e12c5d1SDavid du Colombier 		case Tcreate:
4727dd7cddfSDavid du Colombier 			rcreate(job, mf);
4733e12c5d1SDavid du Colombier 			break;
4743e12c5d1SDavid du Colombier 		case Tread:
4757dd7cddfSDavid du Colombier 			rread(job, mf);
4763e12c5d1SDavid du Colombier 			break;
4773e12c5d1SDavid du Colombier 		case Twrite:
4787dd7cddfSDavid du Colombier 			rwrite(job, mf);
4793e12c5d1SDavid du Colombier 			break;
4803e12c5d1SDavid du Colombier 		case Tclunk:
4817dd7cddfSDavid du Colombier 			rclunk(job, mf);
4823e12c5d1SDavid du Colombier 			break;
4833e12c5d1SDavid du Colombier 		case Tremove:
4847dd7cddfSDavid du Colombier 			rremove(job, mf);
4853e12c5d1SDavid du Colombier 			break;
4863e12c5d1SDavid du Colombier 		case Tstat:
4877dd7cddfSDavid du Colombier 			rstat(job, mf);
4883e12c5d1SDavid du Colombier 			break;
4893e12c5d1SDavid du Colombier 		case Twstat:
4907dd7cddfSDavid du Colombier 			rwstat(job, mf);
4913e12c5d1SDavid du Colombier 			break;
4923e12c5d1SDavid du Colombier 		}
493bd389b36SDavid du Colombier 		unlock(&dblock);
4947dd7cddfSDavid du Colombier 
4957dd7cddfSDavid du Colombier 		freejob(job);
4967dd7cddfSDavid du Colombier 
4973e12c5d1SDavid du Colombier 		/*
4983e12c5d1SDavid du Colombier 		 *  slave processes die after replying
4993e12c5d1SDavid du Colombier 		 */
500219b2ee8SDavid du Colombier 		if(*isslave){
501219b2ee8SDavid du Colombier 			if(debug)
502219b2ee8SDavid du Colombier 				syslog(0, logfile, "slave death %d", getpid());
5033e12c5d1SDavid du Colombier 			_exits(0);
5043e12c5d1SDavid du Colombier 		}
5053e12c5d1SDavid du Colombier 	}
506219b2ee8SDavid du Colombier }
507219b2ee8SDavid du Colombier 
508219b2ee8SDavid du Colombier void
5099a747e4fSDavid du Colombier rversion(Job *job)
510219b2ee8SDavid du Colombier {
5119a747e4fSDavid du Colombier 	if(job->request.msize > IOHDRSZ + Maxfdata)
5129a747e4fSDavid du Colombier 		job->reply.msize = IOHDRSZ + Maxfdata;
5139a747e4fSDavid du Colombier 	else
5149a747e4fSDavid du Colombier 		job->reply.msize = job->request.msize;
5159a747e4fSDavid du Colombier 	if(strncmp(job->request.version, "9P2000", 6) != 0)
5169a747e4fSDavid du Colombier 		sendmsg(job, "unknown 9P version");
5179a747e4fSDavid du Colombier 	else{
5189a747e4fSDavid du Colombier 		job->reply.version = "9P2000";
5197dd7cddfSDavid du Colombier 		sendmsg(job, 0);
520219b2ee8SDavid du Colombier 	}
5219a747e4fSDavid du Colombier }
5223e12c5d1SDavid du Colombier 
5233e12c5d1SDavid du Colombier void
5249a747e4fSDavid du Colombier rauth(Job *job)
5253e12c5d1SDavid du Colombier {
5263ff48bf5SDavid du Colombier 	sendmsg(job, "cs: authentication not required");
5277dd7cddfSDavid du Colombier }
5287dd7cddfSDavid du Colombier 
5297dd7cddfSDavid du Colombier /*
5307dd7cddfSDavid du Colombier  *  don't flush till all the slaves are done
5317dd7cddfSDavid du Colombier  */
5327dd7cddfSDavid du Colombier void
5337dd7cddfSDavid du Colombier rflush(Job *job)
5347dd7cddfSDavid du Colombier {
5357dd7cddfSDavid du Colombier 	flushjob(job->request.oldtag);
5367dd7cddfSDavid du Colombier 	sendmsg(job, 0);
5373e12c5d1SDavid du Colombier }
5383e12c5d1SDavid du Colombier 
5393e12c5d1SDavid du Colombier void
5407dd7cddfSDavid du Colombier rattach(Job *job, Mfile *mf)
5413e12c5d1SDavid du Colombier {
5423e12c5d1SDavid du Colombier 	if(mf->busy == 0){
5433e12c5d1SDavid du Colombier 		mf->busy = 1;
5449a747e4fSDavid du Colombier 		mf->user = estrdup(job->request.uname);
5453e12c5d1SDavid du Colombier 	}
5463e12c5d1SDavid du Colombier 	mf->qid.vers = vers++;
5479a747e4fSDavid du Colombier 	mf->qid.type = QTDIR;
5489a747e4fSDavid du Colombier 	mf->qid.path = 0LL;
5497dd7cddfSDavid du Colombier 	job->reply.qid = mf->qid;
5507dd7cddfSDavid du Colombier 	sendmsg(job, 0);
5513e12c5d1SDavid du Colombier }
5523e12c5d1SDavid du Colombier 
5533e12c5d1SDavid du Colombier 
5543e12c5d1SDavid du Colombier char*
5557dd7cddfSDavid du Colombier rwalk(Job *job, Mfile *mf)
5563e12c5d1SDavid du Colombier {
5573e12c5d1SDavid du Colombier 	char *err;
5589a747e4fSDavid du Colombier 	char **elems;
5599a747e4fSDavid du Colombier 	int nelems;
5609a747e4fSDavid du Colombier 	int i;
5619a747e4fSDavid du Colombier 	Mfile *nmf;
5629a747e4fSDavid du Colombier 	Qid qid;
5633e12c5d1SDavid du Colombier 
5643e12c5d1SDavid du Colombier 	err = 0;
5659a747e4fSDavid du Colombier 	nmf = nil;
5669a747e4fSDavid du Colombier 	elems = job->request.wname;
5679a747e4fSDavid du Colombier 	nelems = job->request.nwname;
5689a747e4fSDavid du Colombier 	job->reply.nwqid = 0;
5699a747e4fSDavid du Colombier 
5709a747e4fSDavid du Colombier 	if(job->request.newfid != job->request.fid){
5719a747e4fSDavid du Colombier 		/* clone fid */
5729a747e4fSDavid du Colombier 		nmf = newfid(job->request.newfid);
5739a747e4fSDavid du Colombier 		if(nmf->busy){
5749a747e4fSDavid du Colombier 			nmf = nil;
5759a747e4fSDavid du Colombier 			err = "clone to used channel";
5769a747e4fSDavid du Colombier 			goto send;
5779a747e4fSDavid du Colombier 		}
5789a747e4fSDavid du Colombier 		*nmf = *mf;
5799a747e4fSDavid du Colombier 		nmf->user = estrdup(mf->user);
5809a747e4fSDavid du Colombier 		nmf->fid = job->request.newfid;
5819a747e4fSDavid du Colombier 		nmf->qid.vers = vers++;
5829a747e4fSDavid du Colombier 		mf = nmf;
5839a747e4fSDavid du Colombier 	}
5849a747e4fSDavid du Colombier 	/* else nmf will be nil */
5859a747e4fSDavid du Colombier 
5869a747e4fSDavid du Colombier 	qid = mf->qid;
5879a747e4fSDavid du Colombier 	if(nelems > 0){
5889a747e4fSDavid du Colombier 		/* walk fid */
5899a747e4fSDavid du Colombier 		for(i=0; i<nelems && i<MAXWELEM; i++){
5909a747e4fSDavid du Colombier 			if((qid.type & QTDIR) == 0){
5913e12c5d1SDavid du Colombier 				err = "not a directory";
5929a747e4fSDavid du Colombier 				break;
5933e12c5d1SDavid du Colombier 			}
5949a747e4fSDavid du Colombier 			if(strcmp(elems[i], "..") == 0 || strcmp(elems[i], ".") == 0){
5959a747e4fSDavid du Colombier 				qid.type = QTDIR;
5969a747e4fSDavid du Colombier 				qid.path = Qdir;
5979a747e4fSDavid du Colombier     Found:
5989a747e4fSDavid du Colombier 				job->reply.wqid[i] = qid;
5999a747e4fSDavid du Colombier 				job->reply.nwqid++;
6009a747e4fSDavid du Colombier 				continue;
6013e12c5d1SDavid du Colombier 			}
6029a747e4fSDavid du Colombier 			if(strcmp(elems[i], "cs") == 0){
6039a747e4fSDavid du Colombier 				qid.type = QTFILE;
6049a747e4fSDavid du Colombier 				qid.path = Qcs;
6059a747e4fSDavid du Colombier 				goto Found;
6063e12c5d1SDavid du Colombier 			}
6079a747e4fSDavid du Colombier 			err = "file does not exist";
6089a747e4fSDavid du Colombier 			break;
6099a747e4fSDavid du Colombier 		}
6109a747e4fSDavid du Colombier 	}
6119a747e4fSDavid du Colombier 
6123e12c5d1SDavid du Colombier     send:
6139a747e4fSDavid du Colombier 	if(nmf != nil && (err!=nil || job->reply.nwqid<nelems)){
614a9f680aeSDavid du Colombier 		cleanmf(nmf);
615a9f680aeSDavid du Colombier 		free(nmf->user);
616a9f680aeSDavid du Colombier 		nmf->user = 0;
6179a747e4fSDavid du Colombier 		nmf->busy = 0;
6189a747e4fSDavid du Colombier 		nmf->fid = 0;
6199a747e4fSDavid du Colombier 	}
6209a747e4fSDavid du Colombier 	if(err == nil)
6219a747e4fSDavid du Colombier 		mf->qid = qid;
6227dd7cddfSDavid du Colombier 	sendmsg(job, err);
6233e12c5d1SDavid du Colombier 	return err;
6243e12c5d1SDavid du Colombier }
6253e12c5d1SDavid du Colombier 
6263e12c5d1SDavid du Colombier void
6277dd7cddfSDavid du Colombier ropen(Job *job, Mfile *mf)
6283e12c5d1SDavid du Colombier {
6293e12c5d1SDavid du Colombier 	int mode;
6303e12c5d1SDavid du Colombier 	char *err;
6313e12c5d1SDavid du Colombier 
6323e12c5d1SDavid du Colombier 	err = 0;
6337dd7cddfSDavid du Colombier 	mode = job->request.mode;
6349a747e4fSDavid du Colombier 	if(mf->qid.type & QTDIR){
6353e12c5d1SDavid du Colombier 		if(mode)
6363e12c5d1SDavid du Colombier 			err = "permission denied";
6379a747e4fSDavid du Colombier 	}
6387dd7cddfSDavid du Colombier 	job->reply.qid = mf->qid;
6399a747e4fSDavid du Colombier 	job->reply.iounit = 0;
6407dd7cddfSDavid du Colombier 	sendmsg(job, err);
6413e12c5d1SDavid du Colombier }
6423e12c5d1SDavid du Colombier 
6433e12c5d1SDavid du Colombier void
6447dd7cddfSDavid du Colombier rcreate(Job *job, Mfile *mf)
6453e12c5d1SDavid du Colombier {
6463e12c5d1SDavid du Colombier 	USED(mf);
6477dd7cddfSDavid du Colombier 	sendmsg(job, "creation permission denied");
6483e12c5d1SDavid du Colombier }
6493e12c5d1SDavid du Colombier 
6503e12c5d1SDavid du Colombier void
6517dd7cddfSDavid du Colombier rread(Job *job, Mfile *mf)
6523e12c5d1SDavid du Colombier {
653219b2ee8SDavid du Colombier 	int i, n, cnt;
654219b2ee8SDavid du Colombier 	long off, toff, clock;
6553e12c5d1SDavid du Colombier 	Dir dir;
656*254fe3d3SDavid du Colombier 	uchar buf[Maxfdata];
6573e12c5d1SDavid du Colombier 	char *err;
6583e12c5d1SDavid du Colombier 
6593e12c5d1SDavid du Colombier 	n = 0;
6603e12c5d1SDavid du Colombier 	err = 0;
6617dd7cddfSDavid du Colombier 	off = job->request.offset;
6627dd7cddfSDavid du Colombier 	cnt = job->request.count;
6639a747e4fSDavid du Colombier 	if(mf->qid.type & QTDIR){
6643e12c5d1SDavid du Colombier 		clock = time(0);
6653e12c5d1SDavid du Colombier 		if(off == 0){
6666aaebd7dSDavid du Colombier 			memset(&dir, 0, sizeof dir);
6679a747e4fSDavid du Colombier 			dir.name = "cs";
6689a747e4fSDavid du Colombier 			dir.qid.type = QTFILE;
6693e12c5d1SDavid du Colombier 			dir.qid.vers = vers;
6703e12c5d1SDavid du Colombier 			dir.qid.path = Qcs;
6713e12c5d1SDavid du Colombier 			dir.mode = 0666;
6723e12c5d1SDavid du Colombier 			dir.length = 0;
6739a747e4fSDavid du Colombier 			dir.uid = mf->user;
6749a747e4fSDavid du Colombier 			dir.gid = mf->user;
6759a747e4fSDavid du Colombier 			dir.muid = mf->user;
6763e12c5d1SDavid du Colombier 			dir.atime = clock;	/* wrong */
6773e12c5d1SDavid du Colombier 			dir.mtime = clock;	/* wrong */
6789a747e4fSDavid du Colombier 			n = convD2M(&dir, buf, sizeof buf);
6793e12c5d1SDavid du Colombier 		}
6809a747e4fSDavid du Colombier 		job->reply.data = (char*)buf;
6813e12c5d1SDavid du Colombier 	} else {
68280ee5cbfSDavid du Colombier 		for(;;){
68380ee5cbfSDavid du Colombier 			/* look for an answer at the right offset */
684219b2ee8SDavid du Colombier 			toff = 0;
685219b2ee8SDavid du Colombier 			for(i = 0; mf->reply[i] && i < mf->nreply; i++){
686219b2ee8SDavid du Colombier 				n = mf->replylen[i];
687219b2ee8SDavid du Colombier 				if(off < toff + n)
688219b2ee8SDavid du Colombier 					break;
689219b2ee8SDavid du Colombier 				toff += n;
6903e12c5d1SDavid du Colombier 			}
69180ee5cbfSDavid du Colombier 			if(i < mf->nreply)
69280ee5cbfSDavid du Colombier 				break;		/* got something to return */
69380ee5cbfSDavid du Colombier 
69480ee5cbfSDavid du Colombier 			/* try looking up more answers */
69580ee5cbfSDavid du Colombier 			if(lookup(mf) == 0){
69680ee5cbfSDavid du Colombier 				/* no more */
697219b2ee8SDavid du Colombier 				n = 0;
698219b2ee8SDavid du Colombier 				goto send;
699219b2ee8SDavid du Colombier 			}
70080ee5cbfSDavid du Colombier 		}
70180ee5cbfSDavid du Colombier 
70280ee5cbfSDavid du Colombier 		/* give back a single reply (or part of one) */
7037dd7cddfSDavid du Colombier 		job->reply.data = mf->reply[i] + (off - toff);
704219b2ee8SDavid du Colombier 		if(cnt > toff - off + n)
705219b2ee8SDavid du Colombier 			n = toff - off + n;
706219b2ee8SDavid du Colombier 		else
707219b2ee8SDavid du Colombier 			n = cnt;
7083e12c5d1SDavid du Colombier 	}
7093e12c5d1SDavid du Colombier send:
7107dd7cddfSDavid du Colombier 	job->reply.count = n;
7117dd7cddfSDavid du Colombier 	sendmsg(job, err);
7127dd7cddfSDavid du Colombier }
71380ee5cbfSDavid du Colombier void
71480ee5cbfSDavid du Colombier cleanmf(Mfile *mf)
7157dd7cddfSDavid du Colombier {
7167dd7cddfSDavid du Colombier 	int i;
7177dd7cddfSDavid du Colombier 
7189a747e4fSDavid du Colombier 	if(mf->net != nil){
71980ee5cbfSDavid du Colombier 		free(mf->net);
72080ee5cbfSDavid du Colombier 		mf->net = nil;
7219a747e4fSDavid du Colombier 	}
7229a747e4fSDavid du Colombier 	if(mf->host != nil){
72380ee5cbfSDavid du Colombier 		free(mf->host);
72480ee5cbfSDavid du Colombier 		mf->host = nil;
7259a747e4fSDavid du Colombier 	}
7269a747e4fSDavid du Colombier 	if(mf->serv != nil){
72780ee5cbfSDavid du Colombier 		free(mf->serv);
72880ee5cbfSDavid du Colombier 		mf->serv = nil;
7299a747e4fSDavid du Colombier 	}
7309a747e4fSDavid du Colombier 	if(mf->rem != nil){
73180ee5cbfSDavid du Colombier 		free(mf->rem);
73280ee5cbfSDavid du Colombier 		mf->rem = nil;
7339a747e4fSDavid du Colombier 	}
73480ee5cbfSDavid du Colombier 	for(i = 0; i < mf->nreply; i++){
73580ee5cbfSDavid du Colombier 		free(mf->reply[i]);
73680ee5cbfSDavid du Colombier 		mf->reply[i] = nil;
73780ee5cbfSDavid du Colombier 		mf->replylen[i] = 0;
7387dd7cddfSDavid du Colombier 	}
73980ee5cbfSDavid du Colombier 	mf->nreply = 0;
74080ee5cbfSDavid du Colombier 	mf->nextnet = netlist;
7413e12c5d1SDavid du Colombier }
7423e12c5d1SDavid du Colombier 
7433e12c5d1SDavid du Colombier void
7447dd7cddfSDavid du Colombier rwrite(Job *job, Mfile *mf)
7453e12c5d1SDavid du Colombier {
7463e12c5d1SDavid du Colombier 	int cnt, n;
74780ee5cbfSDavid du Colombier 	char *err;
7487dd7cddfSDavid du Colombier 	char *field[4];
749271b8d73SDavid du Colombier 	char curerr[64];
7503e12c5d1SDavid du Colombier 
7513e12c5d1SDavid du Colombier 	err = 0;
7527dd7cddfSDavid du Colombier 	cnt = job->request.count;
7539a747e4fSDavid du Colombier 	if(mf->qid.type & QTDIR){
7543e12c5d1SDavid du Colombier 		err = "can't write directory";
7553e12c5d1SDavid du Colombier 		goto send;
7563e12c5d1SDavid du Colombier 	}
7573e12c5d1SDavid du Colombier 	if(cnt >= Maxrequest){
7583e12c5d1SDavid du Colombier 		err = "request too long";
7593e12c5d1SDavid du Colombier 		goto send;
7603e12c5d1SDavid du Colombier 	}
7617dd7cddfSDavid du Colombier 	job->request.data[cnt] = 0;
7623e12c5d1SDavid du Colombier 
7633e12c5d1SDavid du Colombier 	/*
764219b2ee8SDavid du Colombier 	 *  toggle debugging
765219b2ee8SDavid du Colombier 	 */
7667dd7cddfSDavid du Colombier 	if(strncmp(job->request.data, "debug", 5)==0){
767219b2ee8SDavid du Colombier 		debug ^= 1;
768219b2ee8SDavid du Colombier 		syslog(1, logfile, "debug %d", debug);
769219b2ee8SDavid du Colombier 		goto send;
770219b2ee8SDavid du Colombier 	}
771219b2ee8SDavid du Colombier 
772219b2ee8SDavid du Colombier 	/*
7737dd7cddfSDavid du Colombier 	 *  toggle debugging
7747dd7cddfSDavid du Colombier 	 */
7757dd7cddfSDavid du Colombier 	if(strncmp(job->request.data, "paranoia", 8)==0){
7767dd7cddfSDavid du Colombier 		paranoia ^= 1;
7777dd7cddfSDavid du Colombier 		syslog(1, logfile, "paranoia %d", paranoia);
7787dd7cddfSDavid du Colombier 		goto send;
7797dd7cddfSDavid du Colombier 	}
7807dd7cddfSDavid du Colombier 
7817dd7cddfSDavid du Colombier 	/*
7823e12c5d1SDavid du Colombier 	 *  add networks to the default list
7833e12c5d1SDavid du Colombier 	 */
7847dd7cddfSDavid du Colombier 	if(strncmp(job->request.data, "add ", 4)==0){
7857dd7cddfSDavid du Colombier 		if(job->request.data[cnt-1] == '\n')
7867dd7cddfSDavid du Colombier 			job->request.data[cnt-1] = 0;
7877dd7cddfSDavid du Colombier 		netadd(job->request.data+4);
7887dd7cddfSDavid du Colombier 		readipinterfaces();
7897dd7cddfSDavid du Colombier 		goto send;
7907dd7cddfSDavid du Colombier 	}
7917dd7cddfSDavid du Colombier 
7927dd7cddfSDavid du Colombier 	/*
7937dd7cddfSDavid du Colombier 	 *  refresh all state
7947dd7cddfSDavid du Colombier 	 */
7957dd7cddfSDavid du Colombier 	if(strncmp(job->request.data, "refresh", 7)==0){
7967dd7cddfSDavid du Colombier 		netinit(1);
7973e12c5d1SDavid du Colombier 		goto send;
7983e12c5d1SDavid du Colombier 	}
7993e12c5d1SDavid du Colombier 
80080ee5cbfSDavid du Colombier 	/* start transaction with a clean slate */
80180ee5cbfSDavid du Colombier 	cleanmf(mf);
80280ee5cbfSDavid du Colombier 
8033e12c5d1SDavid du Colombier 	/*
804219b2ee8SDavid du Colombier 	 *  look for a general query
805219b2ee8SDavid du Colombier 	 */
8067dd7cddfSDavid du Colombier 	if(*job->request.data == '!'){
8077dd7cddfSDavid du Colombier 		err = genquery(mf, job->request.data+1);
808219b2ee8SDavid du Colombier 		goto send;
809219b2ee8SDavid du Colombier 	}
810219b2ee8SDavid du Colombier 
8117dd7cddfSDavid du Colombier 	if(debug)
8127dd7cddfSDavid du Colombier 		syslog(0, logfile, "write %s", job->request.data);
8137dd7cddfSDavid du Colombier 	if(paranoia)
8147dd7cddfSDavid du Colombier 		syslog(0, paranoiafile, "write %s by %s", job->request.data, mf->user);
8157dd7cddfSDavid du Colombier 
816219b2ee8SDavid du Colombier 	/*
8173e12c5d1SDavid du Colombier 	 *  break up name
8183e12c5d1SDavid du Colombier 	 */
8197dd7cddfSDavid du Colombier 	n = getfields(job->request.data, field, 4, 1, "!");
8203e12c5d1SDavid du Colombier 	switch(n){
8213e12c5d1SDavid du Colombier 	case 1:
82280ee5cbfSDavid du Colombier 		mf->net = strdup("net");
82380ee5cbfSDavid du Colombier 		mf->host = strdup(field[0]);
8247dd7cddfSDavid du Colombier 		break;
8257dd7cddfSDavid du Colombier 	case 4:
82680ee5cbfSDavid du Colombier 		mf->rem = strdup(field[3]);
82780ee5cbfSDavid du Colombier 		/* fall through */
82880ee5cbfSDavid du Colombier 	case 3:
82980ee5cbfSDavid du Colombier 		mf->serv = strdup(field[2]);
83080ee5cbfSDavid du Colombier 		/* fall through */
83180ee5cbfSDavid du Colombier 	case 2:
83280ee5cbfSDavid du Colombier 		mf->host = strdup(field[1]);
83380ee5cbfSDavid du Colombier 		mf->net = strdup(field[0]);
8343e12c5d1SDavid du Colombier 		break;
8353e12c5d1SDavid du Colombier 	}
8363e12c5d1SDavid du Colombier 
83780ee5cbfSDavid du Colombier 	/*
83880ee5cbfSDavid du Colombier 	 *  do the first net worth of lookup
83980ee5cbfSDavid du Colombier 	 */
840271b8d73SDavid du Colombier 	if(lookup(mf) == 0){
841271b8d73SDavid du Colombier 		rerrstr(curerr, sizeof curerr);
842271b8d73SDavid du Colombier 		err = curerr;
843271b8d73SDavid du Colombier 	}
8443e12c5d1SDavid du Colombier send:
8457dd7cddfSDavid du Colombier 	job->reply.count = cnt;
8467dd7cddfSDavid du Colombier 	sendmsg(job, err);
8473e12c5d1SDavid du Colombier }
8483e12c5d1SDavid du Colombier 
8493e12c5d1SDavid du Colombier void
8507dd7cddfSDavid du Colombier rclunk(Job *job, Mfile *mf)
8513e12c5d1SDavid du Colombier {
85280ee5cbfSDavid du Colombier 	cleanmf(mf);
853a9f680aeSDavid du Colombier 	free(mf->user);
854a9f680aeSDavid du Colombier 	mf->user = 0;
8553e12c5d1SDavid du Colombier 	mf->busy = 0;
8563e12c5d1SDavid du Colombier 	mf->fid = 0;
8577dd7cddfSDavid du Colombier 	sendmsg(job, 0);
8583e12c5d1SDavid du Colombier }
8593e12c5d1SDavid du Colombier 
8603e12c5d1SDavid du Colombier void
8617dd7cddfSDavid du Colombier rremove(Job *job, Mfile *mf)
8623e12c5d1SDavid du Colombier {
8633e12c5d1SDavid du Colombier 	USED(mf);
8647dd7cddfSDavid du Colombier 	sendmsg(job, "remove permission denied");
8653e12c5d1SDavid du Colombier }
8663e12c5d1SDavid du Colombier 
8673e12c5d1SDavid du Colombier void
8687dd7cddfSDavid du Colombier rstat(Job *job, Mfile *mf)
8693e12c5d1SDavid du Colombier {
8703e12c5d1SDavid du Colombier 	Dir dir;
8719a747e4fSDavid du Colombier 	uchar buf[IOHDRSZ+Maxfdata];
8723e12c5d1SDavid du Colombier 
8736aaebd7dSDavid du Colombier 	memset(&dir, 0, sizeof dir);
8749a747e4fSDavid du Colombier 	if(mf->qid.type & QTDIR){
8759a747e4fSDavid du Colombier 		dir.name = ".";
8769a747e4fSDavid du Colombier 		dir.mode = DMDIR|0555;
877219b2ee8SDavid du Colombier 	} else {
8789a747e4fSDavid du Colombier 		dir.name = "cs";
8793e12c5d1SDavid du Colombier 		dir.mode = 0666;
880219b2ee8SDavid du Colombier 	}
881219b2ee8SDavid du Colombier 	dir.qid = mf->qid;
8823e12c5d1SDavid du Colombier 	dir.length = 0;
8839a747e4fSDavid du Colombier 	dir.uid = mf->user;
8849a747e4fSDavid du Colombier 	dir.gid = mf->user;
8859a747e4fSDavid du Colombier 	dir.muid = mf->user;
8863e12c5d1SDavid du Colombier 	dir.atime = dir.mtime = time(0);
8879a747e4fSDavid du Colombier 	job->reply.nstat = convD2M(&dir, buf, sizeof buf);
8889a747e4fSDavid du Colombier 	job->reply.stat = buf;
8897dd7cddfSDavid du Colombier 	sendmsg(job, 0);
8903e12c5d1SDavid du Colombier }
8913e12c5d1SDavid du Colombier 
8923e12c5d1SDavid du Colombier void
8937dd7cddfSDavid du Colombier rwstat(Job *job, Mfile *mf)
8943e12c5d1SDavid du Colombier {
8953e12c5d1SDavid du Colombier 	USED(mf);
8967dd7cddfSDavid du Colombier 	sendmsg(job, "wstat permission denied");
8973e12c5d1SDavid du Colombier }
8983e12c5d1SDavid du Colombier 
8993e12c5d1SDavid du Colombier void
9007dd7cddfSDavid du Colombier sendmsg(Job *job, char *err)
9013e12c5d1SDavid du Colombier {
9023e12c5d1SDavid du Colombier 	int n;
9039a747e4fSDavid du Colombier 	uchar mdata[IOHDRSZ + Maxfdata];
9049a747e4fSDavid du Colombier 	char ename[ERRMAX];
9053e12c5d1SDavid du Colombier 
9063e12c5d1SDavid du Colombier 	if(err){
9077dd7cddfSDavid du Colombier 		job->reply.type = Rerror;
9089a747e4fSDavid du Colombier 		snprint(ename, sizeof(ename), "cs: %s", err);
9099a747e4fSDavid du Colombier 		job->reply.ename = ename;
9103e12c5d1SDavid du Colombier 	}else{
9117dd7cddfSDavid du Colombier 		job->reply.type = job->request.type+1;
9123e12c5d1SDavid du Colombier 	}
9137dd7cddfSDavid du Colombier 	job->reply.tag = job->request.tag;
9149a747e4fSDavid du Colombier 	n = convS2M(&job->reply, mdata, sizeof mdata);
915219b2ee8SDavid du Colombier 	if(n == 0){
9167dd7cddfSDavid du Colombier 		syslog(1, logfile, "sendmsg convS2M of %F returns 0", &job->reply);
917219b2ee8SDavid du Colombier 		abort();
918219b2ee8SDavid du Colombier 	}
9197dd7cddfSDavid du Colombier 	lock(&joblock);
9207dd7cddfSDavid du Colombier 	if(job->flushed == 0)
9219a747e4fSDavid du Colombier 		if(write(mfd[1], mdata, n)!=n)
9223e12c5d1SDavid du Colombier 			error("mount write");
9237dd7cddfSDavid du Colombier 	unlock(&joblock);
924219b2ee8SDavid du Colombier 	if(debug)
9257dd7cddfSDavid du Colombier 		syslog(0, logfile, "%F %d", &job->reply, n);
9263e12c5d1SDavid du Colombier }
9273e12c5d1SDavid du Colombier 
9283e12c5d1SDavid du Colombier void
9293e12c5d1SDavid du Colombier error(char *s)
9303e12c5d1SDavid du Colombier {
931bd389b36SDavid du Colombier 	syslog(1, "cs", "%s: %r", s);
932bd389b36SDavid du Colombier 	_exits(0);
9333e12c5d1SDavid du Colombier }
9343e12c5d1SDavid du Colombier 
9357dd7cddfSDavid du Colombier static int
9367dd7cddfSDavid du Colombier isvalidip(uchar *ip)
9377dd7cddfSDavid du Colombier {
9387dd7cddfSDavid du Colombier 	return ipcmp(ip, IPnoaddr) != 0 && ipcmp(ip, v4prefix) != 0;
9397dd7cddfSDavid du Colombier }
9403e12c5d1SDavid du Colombier 
9410103620dSDavid du Colombier static uchar loopbacknet[IPaddrlen] = {
9420103620dSDavid du Colombier 	0, 0, 0, 0,
9430103620dSDavid du Colombier 	0, 0, 0, 0,
9440103620dSDavid du Colombier 	0, 0, 0xff, 0xff,
9450103620dSDavid du Colombier 	127, 0, 0, 0
9460103620dSDavid du Colombier };
9470103620dSDavid du Colombier static uchar loopbackmask[IPaddrlen] = {
9480103620dSDavid du Colombier 	0xff, 0xff, 0xff, 0xff,
9490103620dSDavid du Colombier 	0xff, 0xff, 0xff, 0xff,
9500103620dSDavid du Colombier 	0xff, 0xff, 0xff, 0xff,
9510103620dSDavid du Colombier 	0xff, 0, 0, 0
9520103620dSDavid du Colombier };
9530103620dSDavid du Colombier 
9547dd7cddfSDavid du Colombier void
9557dd7cddfSDavid du Colombier readipinterfaces(void)
9567dd7cddfSDavid du Colombier {
9570103620dSDavid du Colombier 	if(myipaddr(ipa, mntpt) != 0)
9580103620dSDavid du Colombier 		ipmove(ipa, IPnoaddr);
9597dd7cddfSDavid du Colombier 	sprint(ipaddr, "%I", ipa);
9607dd7cddfSDavid du Colombier 	if (debug)
9617dd7cddfSDavid du Colombier 		syslog(0, "dns", "ipaddr is %s\n", ipaddr);
9627dd7cddfSDavid du Colombier }
9633e12c5d1SDavid du Colombier 
9643e12c5d1SDavid du Colombier /*
9657dd7cddfSDavid du Colombier  *  get the system name
9663e12c5d1SDavid du Colombier  */
9673e12c5d1SDavid du Colombier void
9683e12c5d1SDavid du Colombier ipid(void)
9693e12c5d1SDavid du Colombier {
9703e12c5d1SDavid du Colombier 	uchar addr[6];
971a9f680aeSDavid du Colombier 	Ndbtuple *t, *tt;
972219b2ee8SDavid du Colombier 	char *p, *attr;
9733e12c5d1SDavid du Colombier 	Ndbs s;
9743e12c5d1SDavid du Colombier 	int f;
9757dd7cddfSDavid du Colombier 	char buf[Maxpath];
9763e12c5d1SDavid du Colombier 
977219b2ee8SDavid du Colombier 	/* use environment, ether addr, or ipaddr to get system name */
97895a264b3SDavid du Colombier 	if(mysysname == 0){
9797dd7cddfSDavid du Colombier 		/*
9807dd7cddfSDavid du Colombier 		 *  environment has priority.
9817dd7cddfSDavid du Colombier 		 *
9827dd7cddfSDavid du Colombier 		 *  on the sgi power the default system name
9837dd7cddfSDavid du Colombier 		 *  is the ip address.  ignore that.
9847dd7cddfSDavid du Colombier 		 *
9857dd7cddfSDavid du Colombier 		 */
986219b2ee8SDavid du Colombier 		p = getenv("sysname");
987447d6a7dSDavid du Colombier 		if(p && *p){
988219b2ee8SDavid du Colombier 			attr = ipattr(p);
989219b2ee8SDavid du Colombier 			if(strcmp(attr, "ip") != 0)
99095a264b3SDavid du Colombier 				mysysname = strdup(p);
9913e12c5d1SDavid du Colombier 		}
9923e12c5d1SDavid du Colombier 
9933e12c5d1SDavid du Colombier 		/*
9947dd7cddfSDavid du Colombier 		 *  the /net/ndb contains what the network
9957dd7cddfSDavid du Colombier 		 *  figured out from DHCP.  use that name if
9967dd7cddfSDavid du Colombier 		 *  there is one.
9973e12c5d1SDavid du Colombier 		 */
99895a264b3SDavid du Colombier 		if(mysysname == 0 && netdb != nil){
9997dd7cddfSDavid du Colombier 			ndbreopen(netdb);
1000a9f680aeSDavid du Colombier 			for(tt = t = ndbparse(netdb); t != nil; t = t->entry){
10017dd7cddfSDavid du Colombier 				if(strcmp(t->attr, "sys") == 0){
100295a264b3SDavid du Colombier 					mysysname = strdup(t->val);
10033e12c5d1SDavid du Colombier 					break;
10043e12c5d1SDavid du Colombier 				}
10057dd7cddfSDavid du Colombier 			}
1006a9f680aeSDavid du Colombier 			ndbfree(tt);
10077dd7cddfSDavid du Colombier 		}
10087dd7cddfSDavid du Colombier 
10097dd7cddfSDavid du Colombier 		/* next network database, ip address, and ether address to find a name */
101095a264b3SDavid du Colombier 		if(mysysname == 0){
10117dd7cddfSDavid du Colombier 			t = nil;
10127dd7cddfSDavid du Colombier 			if(isvalidip(ipa))
101357837e0bSDavid du Colombier 				free(ndbgetvalue(db, &s, "ip", ipaddr, "sys", &t));
101495a264b3SDavid du Colombier 			if(t == nil){
10157dd7cddfSDavid du Colombier 				for(f = 0; f < 3; f++){
10167dd7cddfSDavid du Colombier 					snprint(buf, sizeof buf, "%s/ether%d", mntpt, f);
10177dd7cddfSDavid du Colombier 					if(myetheraddr(addr, buf) >= 0){
10187dd7cddfSDavid du Colombier 						snprint(eaddr, sizeof(eaddr), "%E", addr);
101957837e0bSDavid du Colombier 						free(ndbgetvalue(db, &s, "ether", eaddr, "sys", &t));
10207dd7cddfSDavid du Colombier 						if(t != nil)
10217dd7cddfSDavid du Colombier 							break;
10227dd7cddfSDavid du Colombier 					}
10237dd7cddfSDavid du Colombier 				}
10247dd7cddfSDavid du Colombier 			}
1025b7327ca2SDavid du Colombier 			for(tt = t; tt != nil; tt = tt->entry){
1026b7327ca2SDavid du Colombier 				if(strcmp(tt->attr, "sys") == 0){
1027b7327ca2SDavid du Colombier 					mysysname = strdup(tt->val);
102895a264b3SDavid du Colombier 					break;
102995a264b3SDavid du Colombier 				}
1030b7327ca2SDavid du Colombier 			}
10317dd7cddfSDavid du Colombier 			ndbfree(t);
10327dd7cddfSDavid du Colombier 		}
10337dd7cddfSDavid du Colombier 
103480ee5cbfSDavid du Colombier 		/* nothing else worked, use the ip address */
103595a264b3SDavid du Colombier 		if(mysysname == 0 && isvalidip(ipa))
103695a264b3SDavid du Colombier 			mysysname = strdup(ipaddr);
103780ee5cbfSDavid du Colombier 
103880ee5cbfSDavid du Colombier 
1039dc5a79c1SDavid du Colombier 		/* set /dev/sysname if we now know it */
104095a264b3SDavid du Colombier 		if(mysysname){
10417dd7cddfSDavid du Colombier 			f = open("/dev/sysname", OWRITE);
10427dd7cddfSDavid du Colombier 			if(f >= 0){
10437dd7cddfSDavid du Colombier 				write(f, mysysname, strlen(mysysname));
10443e12c5d1SDavid du Colombier 				close(f);
10453e12c5d1SDavid du Colombier 			}
10463e12c5d1SDavid du Colombier 		}
10473e12c5d1SDavid du Colombier 	}
10483e12c5d1SDavid du Colombier }
10493e12c5d1SDavid du Colombier 
10503e12c5d1SDavid du Colombier /*
10513e12c5d1SDavid du Colombier  *  Set up a list of default networks by looking for
1052*254fe3d3SDavid du Colombier  *  /net/^*^/clone.
10533e12c5d1SDavid du Colombier  */
10543e12c5d1SDavid du Colombier void
10557dd7cddfSDavid du Colombier netinit(int background)
10563e12c5d1SDavid du Colombier {
10577dd7cddfSDavid du Colombier 	char clone[Maxpath];
10583e12c5d1SDavid du Colombier 	Network *np;
10597dd7cddfSDavid du Colombier 	static int working;
10607dd7cddfSDavid du Colombier 
10617dd7cddfSDavid du Colombier 	if(background){
10627dd7cddfSDavid du Colombier 		switch(rfork(RFPROC|RFNOTEG|RFMEM|RFNOWAIT)){
10637dd7cddfSDavid du Colombier 		case 0:
10647dd7cddfSDavid du Colombier 			break;
10657dd7cddfSDavid du Colombier 		default:
10667dd7cddfSDavid du Colombier 			return;
10677dd7cddfSDavid du Colombier 		}
10687dd7cddfSDavid du Colombier 		lock(&netlock);
10697dd7cddfSDavid du Colombier 	}
10703e12c5d1SDavid du Colombier 
10713e12c5d1SDavid du Colombier 	/* add the mounted networks to the default list */
10723e12c5d1SDavid du Colombier 	for(np = network; np->net; np++){
10737dd7cddfSDavid du Colombier 		if(np->considered)
10747dd7cddfSDavid du Colombier 			continue;
10757dd7cddfSDavid du Colombier 		snprint(clone, sizeof(clone), "%s/%s/clone", mntpt, np->net);
10769a747e4fSDavid du Colombier 		if(access(clone, AEXIST) < 0)
10773e12c5d1SDavid du Colombier 			continue;
10783e12c5d1SDavid du Colombier 		if(netlist)
10793e12c5d1SDavid du Colombier 			last->next = np;
10803e12c5d1SDavid du Colombier 		else
10813e12c5d1SDavid du Colombier 			netlist = np;
10823e12c5d1SDavid du Colombier 		last = np;
10833e12c5d1SDavid du Colombier 		np->next = 0;
10847dd7cddfSDavid du Colombier 		np->considered = 1;
10853e12c5d1SDavid du Colombier 	}
10863e12c5d1SDavid du Colombier 
10877dd7cddfSDavid du Colombier 	/* find out what our ip address is */
10887dd7cddfSDavid du Colombier 	readipinterfaces();
10893e12c5d1SDavid du Colombier 
10907dd7cddfSDavid du Colombier 	/* set the system name if we need to, these says ip is all we have */
10913e12c5d1SDavid du Colombier 	ipid();
10923e12c5d1SDavid du Colombier 
1093219b2ee8SDavid du Colombier 	if(debug)
10947dd7cddfSDavid du Colombier 		syslog(0, logfile, "mysysname %s eaddr %s ipaddr %s ipa %I\n",
109595a264b3SDavid du Colombier 			mysysname?mysysname:"???", eaddr, ipaddr, ipa);
10967dd7cddfSDavid du Colombier 
10977dd7cddfSDavid du Colombier 	if(background){
10987dd7cddfSDavid du Colombier 		unlock(&netlock);
10997dd7cddfSDavid du Colombier 		_exits(0);
11007dd7cddfSDavid du Colombier 	}
11013e12c5d1SDavid du Colombier }
11023e12c5d1SDavid du Colombier 
11033e12c5d1SDavid du Colombier /*
11043e12c5d1SDavid du Colombier  *  add networks to the standard list
11053e12c5d1SDavid du Colombier  */
11063e12c5d1SDavid du Colombier void
11073e12c5d1SDavid du Colombier netadd(char *p)
11083e12c5d1SDavid du Colombier {
11093e12c5d1SDavid du Colombier 	Network *np;
11103e12c5d1SDavid du Colombier 	char *field[12];
11113e12c5d1SDavid du Colombier 	int i, n;
11123e12c5d1SDavid du Colombier 
11137dd7cddfSDavid du Colombier 	n = getfields(p, field, 12, 1, " ");
11143e12c5d1SDavid du Colombier 	for(i = 0; i < n; i++){
11153e12c5d1SDavid du Colombier 		for(np = network; np->net; np++){
11163e12c5d1SDavid du Colombier 			if(strcmp(field[i], np->net) != 0)
11173e12c5d1SDavid du Colombier 				continue;
11187dd7cddfSDavid du Colombier 			if(np->considered)
11193e12c5d1SDavid du Colombier 				break;
11203e12c5d1SDavid du Colombier 			if(netlist)
11213e12c5d1SDavid du Colombier 				last->next = np;
11223e12c5d1SDavid du Colombier 			else
11233e12c5d1SDavid du Colombier 				netlist = np;
11243e12c5d1SDavid du Colombier 			last = np;
11253e12c5d1SDavid du Colombier 			np->next = 0;
11267dd7cddfSDavid du Colombier 			np->considered = 1;
11273e12c5d1SDavid du Colombier 		}
11283e12c5d1SDavid du Colombier 	}
11293e12c5d1SDavid du Colombier }
11303e12c5d1SDavid du Colombier 
113180ee5cbfSDavid du Colombier int
113280ee5cbfSDavid du Colombier lookforproto(Ndbtuple *t, char *proto)
113380ee5cbfSDavid du Colombier {
113480ee5cbfSDavid du Colombier 	for(; t != nil; t = t->entry)
113580ee5cbfSDavid du Colombier 		if(strcmp(t->attr, "proto") == 0 && strcmp(t->val, proto) == 0)
113680ee5cbfSDavid du Colombier 			return 1;
113780ee5cbfSDavid du Colombier 	return 0;
113880ee5cbfSDavid du Colombier }
113980ee5cbfSDavid du Colombier 
1140219b2ee8SDavid du Colombier /*
11413e12c5d1SDavid du Colombier  *  lookup a request.  the network "net" means we should pick the
11423e12c5d1SDavid du Colombier  *  best network to get there.
11433e12c5d1SDavid du Colombier  */
11443e12c5d1SDavid du Colombier int
114580ee5cbfSDavid du Colombier lookup(Mfile *mf)
11463e12c5d1SDavid du Colombier {
114780ee5cbfSDavid du Colombier 	Network *np;
1148219b2ee8SDavid du Colombier 	char *cp;
1149219b2ee8SDavid du Colombier 	Ndbtuple *nt, *t;
1150219b2ee8SDavid du Colombier 	char reply[Maxreply];
115180ee5cbfSDavid du Colombier 	int i, rv;
115280ee5cbfSDavid du Colombier 	int hack;
11533e12c5d1SDavid du Colombier 
11543e12c5d1SDavid du Colombier 	/* open up the standard db files */
11553e12c5d1SDavid du Colombier 	if(db == 0)
11567dd7cddfSDavid du Colombier 		ndbinit();
11573e12c5d1SDavid du Colombier 	if(db == 0)
115880ee5cbfSDavid du Colombier 		error("can't open mf->network database\n");
11593e12c5d1SDavid du Colombier 
116080ee5cbfSDavid du Colombier 	rv = 0;
116180ee5cbfSDavid du Colombier 
116280ee5cbfSDavid du Colombier 	if(mf->net == nil)
116380ee5cbfSDavid du Colombier 		return 0;	/* must have been a genquery */
116480ee5cbfSDavid du Colombier 
116580ee5cbfSDavid du Colombier 	if(strcmp(mf->net, "net") == 0){
11663e12c5d1SDavid du Colombier 		/*
11673e12c5d1SDavid du Colombier 		 *  go through set of default nets
11683e12c5d1SDavid du Colombier 		 */
116980ee5cbfSDavid du Colombier 		for(np = mf->nextnet; np; np = np->next){
117080ee5cbfSDavid du Colombier 			nt = (*np->lookup)(np, mf->host, mf->serv, 1);
117180ee5cbfSDavid du Colombier 			if(nt == nil)
1172219b2ee8SDavid du Colombier 				continue;
117380ee5cbfSDavid du Colombier 			hack = np->fasttimeouthack && !lookforproto(nt, np->net);
117480ee5cbfSDavid du Colombier 			for(t = nt; mf->nreply < Nreply && t; t = t->entry){
117580ee5cbfSDavid du Colombier 				cp = (*np->trans)(t, np, mf->serv, mf->rem, hack);
1176219b2ee8SDavid du Colombier 				if(cp){
117780ee5cbfSDavid du Colombier 					/* avoid duplicates */
117880ee5cbfSDavid du Colombier 					for(i = 0; i < mf->nreply; i++)
117980ee5cbfSDavid du Colombier 						if(strcmp(mf->reply[i], cp) == 0)
118080ee5cbfSDavid du Colombier 							break;
118180ee5cbfSDavid du Colombier 					if(i == mf->nreply){
118280ee5cbfSDavid du Colombier 						/* save the reply */
1183219b2ee8SDavid du Colombier 						mf->replylen[mf->nreply] = strlen(cp);
1184219b2ee8SDavid du Colombier 						mf->reply[mf->nreply++] = cp;
118580ee5cbfSDavid du Colombier 						rv++;
1186219b2ee8SDavid du Colombier 					}
1187219b2ee8SDavid du Colombier 				}
1188219b2ee8SDavid du Colombier 			}
1189219b2ee8SDavid du Colombier 			ndbfree(nt);
119080ee5cbfSDavid du Colombier 			np = np->next;
119180ee5cbfSDavid du Colombier 			break;
119280ee5cbfSDavid du Colombier 		}
119380ee5cbfSDavid du Colombier 		mf->nextnet = np;
119480ee5cbfSDavid du Colombier 		return rv;
119580ee5cbfSDavid du Colombier 	}
119680ee5cbfSDavid du Colombier 
119780ee5cbfSDavid du Colombier 	/*
119880ee5cbfSDavid du Colombier 	 *  if not /net, we only get one lookup
119980ee5cbfSDavid du Colombier 	 */
120080ee5cbfSDavid du Colombier 	if(mf->nreply != 0)
1201219b2ee8SDavid du Colombier 		return 0;
120280ee5cbfSDavid du Colombier 	/*
120380ee5cbfSDavid du Colombier 	 *  look for a specific network
120480ee5cbfSDavid du Colombier 	 */
120595a264b3SDavid du Colombier 	for(np = netlist; np && np->net != nil; np++){
120680ee5cbfSDavid du Colombier 		if(np->fasttimeouthack)
120780ee5cbfSDavid du Colombier 			continue;
120880ee5cbfSDavid du Colombier 		if(strcmp(np->net, mf->net) == 0)
120980ee5cbfSDavid du Colombier 			break;
121080ee5cbfSDavid du Colombier 	}
121180ee5cbfSDavid du Colombier 
121295a264b3SDavid du Colombier 	if(np && np->net != nil){
121380ee5cbfSDavid du Colombier 		/*
121480ee5cbfSDavid du Colombier 		 *  known network
121580ee5cbfSDavid du Colombier 		 */
121680ee5cbfSDavid du Colombier 		nt = (*np->lookup)(np, mf->host, mf->serv, 1);
121780ee5cbfSDavid du Colombier 		for(t = nt; mf->nreply < Nreply && t; t = t->entry){
121880ee5cbfSDavid du Colombier 			cp = (*np->trans)(t, np, mf->serv, mf->rem, 0);
121980ee5cbfSDavid du Colombier 			if(cp){
122080ee5cbfSDavid du Colombier 				mf->replylen[mf->nreply] = strlen(cp);
122180ee5cbfSDavid du Colombier 				mf->reply[mf->nreply++] = cp;
122280ee5cbfSDavid du Colombier 				rv++;
122380ee5cbfSDavid du Colombier 			}
122480ee5cbfSDavid du Colombier 		}
122580ee5cbfSDavid du Colombier 		ndbfree(nt);
122680ee5cbfSDavid du Colombier 		return rv;
12273e12c5d1SDavid du Colombier 	} else {
12283e12c5d1SDavid du Colombier 		/*
1229219b2ee8SDavid du Colombier 		 *  not a known network, don't translate host or service
12303e12c5d1SDavid du Colombier 		 */
123180ee5cbfSDavid du Colombier 		if(mf->serv)
12327dd7cddfSDavid du Colombier 			snprint(reply, sizeof(reply), "%s/%s/clone %s!%s",
123380ee5cbfSDavid du Colombier 				mntpt, mf->net, mf->host, mf->serv);
1234bd389b36SDavid du Colombier 		else
12357dd7cddfSDavid du Colombier 			snprint(reply, sizeof(reply), "%s/%s/clone %s",
123680ee5cbfSDavid du Colombier 				mntpt, mf->net, mf->host);
1237219b2ee8SDavid du Colombier 		mf->reply[0] = strdup(reply);
1238219b2ee8SDavid du Colombier 		mf->replylen[0] = strlen(reply);
1239219b2ee8SDavid du Colombier 		mf->nreply = 1;
124080ee5cbfSDavid du Colombier 		return 1;
12413e12c5d1SDavid du Colombier 	}
12423e12c5d1SDavid du Colombier }
12433e12c5d1SDavid du Colombier 
12443e12c5d1SDavid du Colombier /*
12453e12c5d1SDavid du Colombier  *  translate an ip service name into a port number.  If it's a numeric port
12463e12c5d1SDavid du Colombier  *  number, look for restricted access.
12473e12c5d1SDavid du Colombier  *
12483e12c5d1SDavid du Colombier  *  the service '*' needs no translation.
12493e12c5d1SDavid du Colombier  */
12503e12c5d1SDavid du Colombier char*
125195a264b3SDavid du Colombier ipserv(Network *np, char *name, char *buf, int blen)
12523e12c5d1SDavid du Colombier {
12533e12c5d1SDavid du Colombier 	char *p;
12543e12c5d1SDavid du Colombier 	int alpha = 0;
12553e12c5d1SDavid du Colombier 	int restr = 0;
125695a264b3SDavid du Colombier 	char port[10];
12573e12c5d1SDavid du Colombier 	Ndbtuple *t, *nt;
12583e12c5d1SDavid du Colombier 	Ndbs s;
12593e12c5d1SDavid du Colombier 
12603e12c5d1SDavid du Colombier 	/* '*' means any service */
12613e12c5d1SDavid du Colombier 	if(strcmp(name, "*")==0){
12623e12c5d1SDavid du Colombier 		strcpy(buf, name);
12633e12c5d1SDavid du Colombier 		return buf;
12643e12c5d1SDavid du Colombier 	}
12653e12c5d1SDavid du Colombier 
12663e12c5d1SDavid du Colombier 	/*  see if it's numeric or symbolic */
12673e12c5d1SDavid du Colombier 	port[0] = 0;
12683e12c5d1SDavid du Colombier 	for(p = name; *p; p++){
12693e12c5d1SDavid du Colombier 		if(isdigit(*p))
12709a747e4fSDavid du Colombier 			{}
12713e12c5d1SDavid du Colombier 		else if(isalpha(*p) || *p == '-' || *p == '$')
12723e12c5d1SDavid du Colombier 			alpha = 1;
12733e12c5d1SDavid du Colombier 		else
12743e12c5d1SDavid du Colombier 			return 0;
12753e12c5d1SDavid du Colombier 	}
127657837e0bSDavid du Colombier 	t = nil;
127757837e0bSDavid du Colombier 	p = nil;
12783e12c5d1SDavid du Colombier 	if(alpha){
127957837e0bSDavid du Colombier 		p = ndbgetvalue(db, &s, np->net, name, "port", &t);
1280b7327ca2SDavid du Colombier 		if(p == nil)
1281b7327ca2SDavid du Colombier 			return 0;
12823e12c5d1SDavid du Colombier 	} else {
12833cc1eb97SDavid du Colombier 		/* look up only for tcp ports < 1024 to get the restricted
12843cc1eb97SDavid du Colombier 		 * attribute
12853cc1eb97SDavid du Colombier 		 */
12863cc1eb97SDavid du Colombier 		if(atoi(name) < 1024 && strcmp(np->net, "tcp") == 0)
128757837e0bSDavid du Colombier 			p = ndbgetvalue(db, &s, "port", name, "port", &t);
128857837e0bSDavid du Colombier 		if(p == nil)
128957837e0bSDavid du Colombier 			p = strdup(name);
12903e12c5d1SDavid du Colombier 	}
12913e12c5d1SDavid du Colombier 
12923e12c5d1SDavid du Colombier 	if(t){
12933e12c5d1SDavid du Colombier 		for(nt = t; nt; nt = nt->entry)
12943e12c5d1SDavid du Colombier 			if(strcmp(nt->attr, "restricted") == 0)
12953e12c5d1SDavid du Colombier 				restr = 1;
12963e12c5d1SDavid du Colombier 		ndbfree(t);
12973e12c5d1SDavid du Colombier 	}
129857837e0bSDavid du Colombier 	snprint(buf, blen, "%s%s", p, restr ? "!r" : "");
129957837e0bSDavid du Colombier 	free(p);
130057837e0bSDavid du Colombier 
13013e12c5d1SDavid du Colombier 	return buf;
13023e12c5d1SDavid du Colombier }
13033e12c5d1SDavid du Colombier 
13043e12c5d1SDavid du Colombier /*
13057dd7cddfSDavid du Colombier  *  lookup an ip attribute
13063e12c5d1SDavid du Colombier  */
13077dd7cddfSDavid du Colombier int
130895a264b3SDavid du Colombier ipattrlookup(Ndb *db, char *ipa, char *attr, char *val, int vlen)
13093e12c5d1SDavid du Colombier {
13103e12c5d1SDavid du Colombier 
13117dd7cddfSDavid du Colombier 	Ndbtuple *t, *nt;
13127dd7cddfSDavid du Colombier 	char *alist[2];
13133e12c5d1SDavid du Colombier 
13147dd7cddfSDavid du Colombier 	alist[0] = attr;
13157dd7cddfSDavid du Colombier 	t = ndbipinfo(db, "ip", ipa, alist, 1);
13167dd7cddfSDavid du Colombier 	if(t == nil)
13177dd7cddfSDavid du Colombier 		return 0;
13189a747e4fSDavid du Colombier 	for(nt = t; nt != nil; nt = nt->entry){
13197dd7cddfSDavid du Colombier 		if(strcmp(nt->attr, attr) == 0){
132095a264b3SDavid du Colombier 			nstrcpy(val, nt->val, vlen);
13213e12c5d1SDavid du Colombier 			ndbfree(t);
13227dd7cddfSDavid du Colombier 			return 1;
1323219b2ee8SDavid du Colombier 		}
13249a747e4fSDavid du Colombier 	}
13253e12c5d1SDavid du Colombier 
13267dd7cddfSDavid du Colombier 	/* we shouldn't get here */
13273e12c5d1SDavid du Colombier 	ndbfree(t);
13287dd7cddfSDavid du Colombier 	return 0;
13293e12c5d1SDavid du Colombier }
13303e12c5d1SDavid du Colombier 
13313e12c5d1SDavid du Colombier /*
13323e12c5d1SDavid du Colombier  *  lookup (and translate) an ip destination
13333e12c5d1SDavid du Colombier  */
1334219b2ee8SDavid du Colombier Ndbtuple*
1335219b2ee8SDavid du Colombier iplookup(Network *np, char *host, char *serv, int nolookup)
13363e12c5d1SDavid du Colombier {
13379dfc0cb2SDavid du Colombier 	char *attr, *dnsname;
13387dd7cddfSDavid du Colombier 	Ndbtuple *t, *nt;
13393e12c5d1SDavid du Colombier 	Ndbs s;
134095a264b3SDavid du Colombier 	char ts[Maxservice];
134195a264b3SDavid du Colombier 	char dollar[Maxhost];
13427dd7cddfSDavid du Colombier 	uchar ip[IPaddrlen];
13437dd7cddfSDavid du Colombier 	uchar net[IPaddrlen];
13447dd7cddfSDavid du Colombier 	uchar tnet[IPaddrlen];
13457dd7cddfSDavid du Colombier 	Ipifc *ifc;
13469a747e4fSDavid du Colombier 	Iplifc *lifc;
13473e12c5d1SDavid du Colombier 
1348219b2ee8SDavid du Colombier 	USED(nolookup);
1349219b2ee8SDavid du Colombier 
13503e12c5d1SDavid du Colombier 	/*
13513e12c5d1SDavid du Colombier 	 *  start with the service since it's the most likely to fail
13523e12c5d1SDavid du Colombier 	 *  and costs the least
13533e12c5d1SDavid du Colombier 	 */
13547dd7cddfSDavid du Colombier 	werrstr("can't translate address");
135595a264b3SDavid du Colombier 	if(serv==0 || ipserv(np, serv, ts, sizeof ts) == 0){
1356271b8d73SDavid du Colombier 		werrstr("can't translate service");
1357219b2ee8SDavid du Colombier 		return 0;
13587dd7cddfSDavid du Colombier 	}
13593e12c5d1SDavid du Colombier 
13603e12c5d1SDavid du Colombier 	/* for dial strings with no host */
1361219b2ee8SDavid du Colombier 	if(strcmp(host, "*") == 0)
136295a264b3SDavid du Colombier 		return ndbnew("ip", "*");
13633e12c5d1SDavid du Colombier 
13643e12c5d1SDavid du Colombier 	/*
13657dd7cddfSDavid du Colombier 	 *  hack till we go v6 :: = 0.0.0.0
13667dd7cddfSDavid du Colombier 	 */
13677dd7cddfSDavid du Colombier 	if(strcmp("::", host) == 0)
136895a264b3SDavid du Colombier 		return ndbnew("ip", "*");
13697dd7cddfSDavid du Colombier 
13707dd7cddfSDavid du Colombier 	/*
13713e12c5d1SDavid du Colombier 	 *  '$' means the rest of the name is an attribute that we
13723e12c5d1SDavid du Colombier 	 *  need to search for
13733e12c5d1SDavid du Colombier 	 */
13743e12c5d1SDavid du Colombier 	if(*host == '$'){
137595a264b3SDavid du Colombier 		if(ipattrlookup(db, ipaddr, host+1, dollar, sizeof dollar))
13763e12c5d1SDavid du Colombier 			host = dollar;
13773e12c5d1SDavid du Colombier 	}
13783e12c5d1SDavid du Colombier 
13793e12c5d1SDavid du Colombier 	/*
13807dd7cddfSDavid du Colombier 	 *  turn '[ip address]' into just 'ip address'
13817dd7cddfSDavid du Colombier 	 */
13827dd7cddfSDavid du Colombier 	if(*host == '[' && host[strlen(host)-1] == ']'){
13837dd7cddfSDavid du Colombier 		host++;
13847dd7cddfSDavid du Colombier 		host[strlen(host)-1] = 0;
13857dd7cddfSDavid du Colombier 	}
13867dd7cddfSDavid du Colombier 
13877dd7cddfSDavid du Colombier 	/*
13883e12c5d1SDavid du Colombier 	 *  just accept addresses
13893e12c5d1SDavid du Colombier 	 */
1390219b2ee8SDavid du Colombier 	attr = ipattr(host);
1391219b2ee8SDavid du Colombier 	if(strcmp(attr, "ip") == 0)
139295a264b3SDavid du Colombier 		return ndbnew("ip", host);
13933e12c5d1SDavid du Colombier 
13943e12c5d1SDavid du Colombier 	/*
13953e12c5d1SDavid du Colombier 	 *  give the domain name server the first opportunity to
1396bd389b36SDavid du Colombier 	 *  resolve domain names.  if that fails try the database.
13973e12c5d1SDavid du Colombier 	 */
13983e12c5d1SDavid du Colombier 	t = 0;
1399271b8d73SDavid du Colombier 	werrstr("can't translate address");
14003e12c5d1SDavid du Colombier 	if(strcmp(attr, "dom") == 0)
14017dd7cddfSDavid du Colombier 		t = dnsiplookup(host, &s);
14023e12c5d1SDavid du Colombier 	if(t == 0)
140357837e0bSDavid du Colombier 		free(ndbgetvalue(db, &s, attr, host, "ip", &t));
14049dfc0cb2SDavid du Colombier 	if(t == 0){
14059dfc0cb2SDavid du Colombier 		dnsname = ndbgetvalue(db, &s, attr, host, "dom", nil);
14069dfc0cb2SDavid du Colombier 		if(dnsname){
14079dfc0cb2SDavid du Colombier 			t = dnsiplookup(dnsname, &s);
14089dfc0cb2SDavid du Colombier 			free(dnsname);
14099dfc0cb2SDavid du Colombier 		}
14109dfc0cb2SDavid du Colombier 	}
14113e12c5d1SDavid du Colombier 	if(t == 0)
14127dd7cddfSDavid du Colombier 		t = dnsiplookup(host, &s);
14137dd7cddfSDavid du Colombier 	if(t == 0)
1414219b2ee8SDavid du Colombier 		return 0;
1415bd389b36SDavid du Colombier 
1416bd389b36SDavid du Colombier 	/*
1417bd389b36SDavid du Colombier 	 *  reorder the tuple to have the matched line first and
1418bd389b36SDavid du Colombier 	 *  save that in the request structure.
1419bd389b36SDavid du Colombier 	 */
14207dd7cddfSDavid du Colombier 	t = reorder(t, s.t);
14217dd7cddfSDavid du Colombier 
14227dd7cddfSDavid du Colombier 	/*
14237dd7cddfSDavid du Colombier 	 * reorder according to our interfaces
14247dd7cddfSDavid du Colombier 	 */
14257dd7cddfSDavid du Colombier 	lock(&ipifclock);
14269a747e4fSDavid du Colombier 	for(ifc = ipifcs; ifc != nil; ifc = ifc->next){
14279a747e4fSDavid du Colombier 		for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
14289a747e4fSDavid du Colombier 			maskip(lifc->ip, lifc->mask, net);
14297dd7cddfSDavid du Colombier 			for(nt = t; nt; nt = nt->entry){
14307dd7cddfSDavid du Colombier 				if(strcmp(nt->attr, "ip") != 0)
14317dd7cddfSDavid du Colombier 					continue;
14327dd7cddfSDavid du Colombier 				parseip(ip, nt->val);
14339a747e4fSDavid du Colombier 				maskip(ip, lifc->mask, tnet);
14347dd7cddfSDavid du Colombier 				if(memcmp(net, tnet, IPaddrlen) == 0){
14357dd7cddfSDavid du Colombier 					t = reorder(t, nt);
14367dd7cddfSDavid du Colombier 					unlock(&ipifclock);
14377dd7cddfSDavid du Colombier 					return t;
14387dd7cddfSDavid du Colombier 				}
14397dd7cddfSDavid du Colombier 			}
14407dd7cddfSDavid du Colombier 		}
14419a747e4fSDavid du Colombier 	}
14427dd7cddfSDavid du Colombier 	unlock(&ipifclock);
14437dd7cddfSDavid du Colombier 
14447dd7cddfSDavid du Colombier 	return t;
14453e12c5d1SDavid du Colombier }
14463e12c5d1SDavid du Colombier 
14473e12c5d1SDavid du Colombier /*
14483e12c5d1SDavid du Colombier  *  translate an ip address
14493e12c5d1SDavid du Colombier  */
1450219b2ee8SDavid du Colombier char*
145180ee5cbfSDavid du Colombier iptrans(Ndbtuple *t, Network *np, char *serv, char *rem, int hack)
14523e12c5d1SDavid du Colombier {
145395a264b3SDavid du Colombier 	char ts[Maxservice];
1454219b2ee8SDavid du Colombier 	char reply[Maxreply];
145595a264b3SDavid du Colombier 	char x[Maxservice];
14563e12c5d1SDavid du Colombier 
1457219b2ee8SDavid du Colombier 	if(strcmp(t->attr, "ip") != 0)
14583e12c5d1SDavid du Colombier 		return 0;
1459219b2ee8SDavid du Colombier 
146095a264b3SDavid du Colombier 	if(serv == 0 || ipserv(np, serv, ts, sizeof ts) == 0){
1461271b8d73SDavid du Colombier 		werrstr("can't translate service");
1462219b2ee8SDavid du Colombier 		return 0;
1463271b8d73SDavid du Colombier 	}
14647dd7cddfSDavid du Colombier 	if(rem != nil)
14657dd7cddfSDavid du Colombier 		snprint(x, sizeof(x), "!%s", rem);
14667dd7cddfSDavid du Colombier 	else
14677dd7cddfSDavid du Colombier 		*x = 0;
146880ee5cbfSDavid du Colombier 
1469219b2ee8SDavid du Colombier 	if(*t->val == '*')
14707dd7cddfSDavid du Colombier 		snprint(reply, sizeof(reply), "%s/%s/clone %s%s",
14717dd7cddfSDavid du Colombier 			mntpt, np->net, ts, x);
1472219b2ee8SDavid du Colombier 	else
147380ee5cbfSDavid du Colombier 		snprint(reply, sizeof(reply), "%s/%s/clone %s!%s%s%s",
147480ee5cbfSDavid du Colombier 			mntpt, np->net, t->val, ts, x, hack? "!fasttimeout": "");
1475219b2ee8SDavid du Colombier 
1476219b2ee8SDavid du Colombier 	return strdup(reply);
14773e12c5d1SDavid du Colombier }
14783e12c5d1SDavid du Colombier 
1479219b2ee8SDavid du Colombier /*
1480219b2ee8SDavid du Colombier  *  lookup a telephone number
1481219b2ee8SDavid du Colombier  */
1482219b2ee8SDavid du Colombier Ndbtuple*
1483219b2ee8SDavid du Colombier telcolookup(Network *np, char *host, char *serv, int nolookup)
1484219b2ee8SDavid du Colombier {
1485219b2ee8SDavid du Colombier 	Ndbtuple *t;
1486219b2ee8SDavid du Colombier 	Ndbs s;
1487219b2ee8SDavid du Colombier 
1488219b2ee8SDavid du Colombier 	USED(np, nolookup, serv);
1489219b2ee8SDavid du Colombier 
1490271b8d73SDavid du Colombier 	werrstr("can't translate address");
149157837e0bSDavid du Colombier 	free(ndbgetvalue(db, &s, "sys", host, "telco", &t));
1492219b2ee8SDavid du Colombier 	if(t == 0)
149395a264b3SDavid du Colombier 		return ndbnew("telco", host);
1494219b2ee8SDavid du Colombier 
1495219b2ee8SDavid du Colombier 	return reorder(t, s.t);
1496219b2ee8SDavid du Colombier }
1497219b2ee8SDavid du Colombier 
1498219b2ee8SDavid du Colombier /*
1499219b2ee8SDavid du Colombier  *  translate a telephone address
1500219b2ee8SDavid du Colombier  */
1501219b2ee8SDavid du Colombier char*
150280ee5cbfSDavid du Colombier telcotrans(Ndbtuple *t, Network *np, char *serv, char *rem, int)
1503219b2ee8SDavid du Colombier {
1504219b2ee8SDavid du Colombier 	char reply[Maxreply];
150595a264b3SDavid du Colombier 	char x[Maxservice];
1506219b2ee8SDavid du Colombier 
1507219b2ee8SDavid du Colombier 	if(strcmp(t->attr, "telco") != 0)
1508219b2ee8SDavid du Colombier 		return 0;
1509219b2ee8SDavid du Colombier 
15107dd7cddfSDavid du Colombier 	if(rem != nil)
15117dd7cddfSDavid du Colombier 		snprint(x, sizeof(x), "!%s", rem);
1512219b2ee8SDavid du Colombier 	else
15137dd7cddfSDavid du Colombier 		*x = 0;
15147dd7cddfSDavid du Colombier 	if(serv)
15157dd7cddfSDavid du Colombier 		snprint(reply, sizeof(reply), "%s/%s/clone %s!%s%s", mntpt, np->net,
15167dd7cddfSDavid du Colombier 			t->val, serv, x);
15177dd7cddfSDavid du Colombier 	else
15187dd7cddfSDavid du Colombier 		snprint(reply, sizeof(reply), "%s/%s/clone %s%s", mntpt, np->net,
15197dd7cddfSDavid du Colombier 			t->val, x);
1520219b2ee8SDavid du Colombier 	return strdup(reply);
1521219b2ee8SDavid du Colombier }
15223e12c5d1SDavid du Colombier 
15233e12c5d1SDavid du Colombier /*
15243e12c5d1SDavid du Colombier  *  reorder the tuple to put x's line first in the entry
15253e12c5d1SDavid du Colombier  */
15263e12c5d1SDavid du Colombier Ndbtuple*
15273e12c5d1SDavid du Colombier reorder(Ndbtuple *t, Ndbtuple *x)
15283e12c5d1SDavid du Colombier {
15293e12c5d1SDavid du Colombier 	Ndbtuple *nt;
15303e12c5d1SDavid du Colombier 	Ndbtuple *line;
15313e12c5d1SDavid du Colombier 
1532219b2ee8SDavid du Colombier 	/* find start of this entry's line */
1533219b2ee8SDavid du Colombier 	for(line = x; line->entry == line->line; line = line->line)
15343e12c5d1SDavid du Colombier 		;
1535219b2ee8SDavid du Colombier 	line = line->line;
1536219b2ee8SDavid du Colombier 	if(line == t)
1537219b2ee8SDavid du Colombier 		return t;	/* already the first line */
15383e12c5d1SDavid du Colombier 
1539219b2ee8SDavid du Colombier 	/* remove this line and everything after it from the entry */
1540219b2ee8SDavid du Colombier 	for(nt = t; nt->entry != line; nt = nt->entry)
1541219b2ee8SDavid du Colombier 		;
1542219b2ee8SDavid du Colombier 	nt->entry = 0;
15433e12c5d1SDavid du Colombier 
1544219b2ee8SDavid du Colombier 	/* make that the start of the entry */
1545219b2ee8SDavid du Colombier 	for(nt = line; nt->entry; nt = nt->entry)
1546219b2ee8SDavid du Colombier 		;
15473e12c5d1SDavid du Colombier 	nt->entry = t;
15483e12c5d1SDavid du Colombier 	return line;
15493e12c5d1SDavid du Colombier }
15503e12c5d1SDavid du Colombier 
15513e12c5d1SDavid du Colombier /*
15523e12c5d1SDavid du Colombier  *  create a slave process to handle a request to avoid one request blocking
15537dd7cddfSDavid du Colombier  *  another.  parent returns to job loop.
15543e12c5d1SDavid du Colombier  */
15553e12c5d1SDavid du Colombier void
1556*254fe3d3SDavid du Colombier slave(char *host)
15573e12c5d1SDavid du Colombier {
15583e12c5d1SDavid du Colombier 	if(*isslave)
15593e12c5d1SDavid du Colombier 		return;		/* we're already a slave process */
15603e12c5d1SDavid du Colombier 
15613e12c5d1SDavid du Colombier 	switch(rfork(RFPROC|RFNOTEG|RFMEM|RFNOWAIT)){
15623e12c5d1SDavid du Colombier 	case -1:
15633e12c5d1SDavid du Colombier 		break;
15643e12c5d1SDavid du Colombier 	case 0:
1565219b2ee8SDavid du Colombier 		if(debug)
1566219b2ee8SDavid du Colombier 			syslog(0, logfile, "slave %d", getpid());
1567*254fe3d3SDavid du Colombier 		procsetname("%s", host);
15683e12c5d1SDavid du Colombier 		*isslave = 1;
15693e12c5d1SDavid du Colombier 		break;
15703e12c5d1SDavid du Colombier 	default:
15713e12c5d1SDavid du Colombier 		longjmp(masterjmp, 1);
15723e12c5d1SDavid du Colombier 	}
15733e12c5d1SDavid du Colombier 
1574219b2ee8SDavid du Colombier }
1575219b2ee8SDavid du Colombier 
15763e12c5d1SDavid du Colombier /*
15773e12c5d1SDavid du Colombier  *  call the dns process and have it try to translate a name
15783e12c5d1SDavid du Colombier  */
15793e12c5d1SDavid du Colombier Ndbtuple*
15807dd7cddfSDavid du Colombier dnsiplookup(char *host, Ndbs *s)
15813e12c5d1SDavid du Colombier {
158295a264b3SDavid du Colombier 	char buf[Maxreply];
15837dd7cddfSDavid du Colombier 	Ndbtuple *t;
15843e12c5d1SDavid du Colombier 
1585bd389b36SDavid du Colombier 	unlock(&dblock);
1586bd389b36SDavid du Colombier 
15873e12c5d1SDavid du Colombier 	/* save the name before starting a slave */
15887dd7cddfSDavid du Colombier 	snprint(buf, sizeof(buf), "%s", host);
15893e12c5d1SDavid du Colombier 
1590*254fe3d3SDavid du Colombier 	slave(host);
15913e12c5d1SDavid du Colombier 
15927dd7cddfSDavid du Colombier 	if(strcmp(ipattr(buf), "ip") == 0)
15937dd7cddfSDavid du Colombier 		t = dnsquery(mntpt, buf, "ptr");
15947dd7cddfSDavid du Colombier 	else
15957dd7cddfSDavid du Colombier 		t = dnsquery(mntpt, buf, "ip");
15963e12c5d1SDavid du Colombier 	s->t = t;
15977dd7cddfSDavid du Colombier 
1598271b8d73SDavid du Colombier 	if(t == nil){
1599271b8d73SDavid du Colombier 		rerrstr(buf, sizeof buf);
1600271b8d73SDavid du Colombier 		if(strstr(buf, "exist"))
1601271b8d73SDavid du Colombier 			werrstr("can't translate address: %s", buf);
1602271b8d73SDavid du Colombier 		else if(strstr(buf, "dns failure"))
1603271b8d73SDavid du Colombier 			werrstr("temporary problem: %s", buf);
1604271b8d73SDavid du Colombier 	}
1605271b8d73SDavid du Colombier 
1606bd389b36SDavid du Colombier 	lock(&dblock);
16073e12c5d1SDavid du Colombier 	return t;
16083e12c5d1SDavid du Colombier }
1609219b2ee8SDavid du Colombier 
1610219b2ee8SDavid du Colombier int
1611219b2ee8SDavid du Colombier qmatch(Ndbtuple *t, char **attr, char **val, int n)
1612219b2ee8SDavid du Colombier {
1613219b2ee8SDavid du Colombier 	int i, found;
1614219b2ee8SDavid du Colombier 	Ndbtuple *nt;
1615219b2ee8SDavid du Colombier 
1616219b2ee8SDavid du Colombier 	for(i = 1; i < n; i++){
1617219b2ee8SDavid du Colombier 		found = 0;
1618219b2ee8SDavid du Colombier 		for(nt = t; nt; nt = nt->entry)
1619219b2ee8SDavid du Colombier 			if(strcmp(attr[i], nt->attr) == 0)
1620219b2ee8SDavid du Colombier 				if(strcmp(val[i], "*") == 0
1621219b2ee8SDavid du Colombier 				|| strcmp(val[i], nt->val) == 0){
1622219b2ee8SDavid du Colombier 					found = 1;
1623219b2ee8SDavid du Colombier 					break;
1624219b2ee8SDavid du Colombier 				}
1625219b2ee8SDavid du Colombier 		if(found == 0)
1626219b2ee8SDavid du Colombier 			break;
1627219b2ee8SDavid du Colombier 	}
1628219b2ee8SDavid du Colombier 	return i == n;
1629219b2ee8SDavid du Colombier }
1630219b2ee8SDavid du Colombier 
1631219b2ee8SDavid du Colombier void
1632219b2ee8SDavid du Colombier qreply(Mfile *mf, Ndbtuple *t)
1633219b2ee8SDavid du Colombier {
1634219b2ee8SDavid du Colombier 	Ndbtuple *nt;
163595a264b3SDavid du Colombier 	String *s;
1636219b2ee8SDavid du Colombier 
163795a264b3SDavid du Colombier 	s = s_new();
1638219b2ee8SDavid du Colombier 	for(nt = t; mf->nreply < Nreply && nt; nt = nt->entry){
163995a264b3SDavid du Colombier 		s_append(s, nt->attr);
164095a264b3SDavid du Colombier 		s_append(s, "=");
164195a264b3SDavid du Colombier 		s_append(s, nt->val);
164295a264b3SDavid du Colombier 
164395a264b3SDavid du Colombier 		if(nt->line != nt->entry){
164495a264b3SDavid du Colombier 			mf->replylen[mf->nreply] = s_len(s);
164595a264b3SDavid du Colombier 			mf->reply[mf->nreply++] = strdup(s_to_c(s));
164695a264b3SDavid du Colombier 			s_restart(s);
1647219b2ee8SDavid du Colombier 		} else
164895a264b3SDavid du Colombier 			s_append(s, " ");
1649219b2ee8SDavid du Colombier 	}
165095a264b3SDavid du Colombier 	s_free(s);
1651219b2ee8SDavid du Colombier }
1652219b2ee8SDavid du Colombier 
16537dd7cddfSDavid du Colombier enum
16547dd7cddfSDavid du Colombier {
16557dd7cddfSDavid du Colombier 	Maxattr=	32,
16567dd7cddfSDavid du Colombier };
16577dd7cddfSDavid du Colombier 
1658219b2ee8SDavid du Colombier /*
16597dd7cddfSDavid du Colombier  *  generic query lookup.  The query is of one of the following
16607dd7cddfSDavid du Colombier  *  forms:
16617dd7cddfSDavid du Colombier  *
16627dd7cddfSDavid du Colombier  *  attr1=val1 attr2=val2 attr3=val3 ...
16637dd7cddfSDavid du Colombier  *
16647dd7cddfSDavid du Colombier  *  returns the matching tuple
16657dd7cddfSDavid du Colombier  *
16667dd7cddfSDavid du Colombier  *  ipinfo attr=val attr1 attr2 attr3 ...
16677dd7cddfSDavid du Colombier  *
16687dd7cddfSDavid du Colombier  *  is like ipinfo and returns the attr{1-n}
16697dd7cddfSDavid du Colombier  *  associated with the ip address.
1670219b2ee8SDavid du Colombier  */
1671219b2ee8SDavid du Colombier char*
1672219b2ee8SDavid du Colombier genquery(Mfile *mf, char *query)
1673219b2ee8SDavid du Colombier {
1674219b2ee8SDavid du Colombier 	int i, n;
1675219b2ee8SDavid du Colombier 	char *p;
16767dd7cddfSDavid du Colombier 	char *attr[Maxattr];
16777dd7cddfSDavid du Colombier 	char *val[Maxattr];
1678219b2ee8SDavid du Colombier 	Ndbtuple *t;
1679219b2ee8SDavid du Colombier 	Ndbs s;
1680219b2ee8SDavid du Colombier 
16817dd7cddfSDavid du Colombier 	n = getfields(query, attr, 32, 1, " ");
1682219b2ee8SDavid du Colombier 	if(n == 0)
1683219b2ee8SDavid du Colombier 		return "bad query";
1684219b2ee8SDavid du Colombier 
16857dd7cddfSDavid du Colombier 	if(strcmp(attr[0], "ipinfo") == 0)
16867dd7cddfSDavid du Colombier 		return ipinfoquery(mf, attr, n);
16877dd7cddfSDavid du Colombier 
1688219b2ee8SDavid du Colombier 	/* parse pairs */
1689219b2ee8SDavid du Colombier 	for(i = 0; i < n; i++){
1690219b2ee8SDavid du Colombier 		p = strchr(attr[i], '=');
1691219b2ee8SDavid du Colombier 		if(p == 0)
1692219b2ee8SDavid du Colombier 			return "bad query";
1693219b2ee8SDavid du Colombier 		*p++ = 0;
1694219b2ee8SDavid du Colombier 		val[i] = p;
1695219b2ee8SDavid du Colombier 	}
1696219b2ee8SDavid du Colombier 
1697219b2ee8SDavid du Colombier 	/* give dns a chance */
1698219b2ee8SDavid du Colombier 	if((strcmp(attr[0], "dom") == 0 || strcmp(attr[0], "ip") == 0) && val[0]){
16997dd7cddfSDavid du Colombier 		t = dnsiplookup(val[0], &s);
1700219b2ee8SDavid du Colombier 		if(t){
1701219b2ee8SDavid du Colombier 			if(qmatch(t, attr, val, n)){
1702219b2ee8SDavid du Colombier 				qreply(mf, t);
1703219b2ee8SDavid du Colombier 				ndbfree(t);
1704219b2ee8SDavid du Colombier 				return 0;
1705219b2ee8SDavid du Colombier 			}
1706219b2ee8SDavid du Colombier 			ndbfree(t);
1707219b2ee8SDavid du Colombier 		}
1708219b2ee8SDavid du Colombier 	}
1709219b2ee8SDavid du Colombier 
1710219b2ee8SDavid du Colombier 	/* first pair is always the key.  It can't be a '*' */
1711219b2ee8SDavid du Colombier 	t = ndbsearch(db, &s, attr[0], val[0]);
1712219b2ee8SDavid du Colombier 
1713219b2ee8SDavid du Colombier 	/* search is the and of all the pairs */
1714219b2ee8SDavid du Colombier 	while(t){
1715219b2ee8SDavid du Colombier 		if(qmatch(t, attr, val, n)){
1716219b2ee8SDavid du Colombier 			qreply(mf, t);
1717219b2ee8SDavid du Colombier 			ndbfree(t);
1718219b2ee8SDavid du Colombier 			return 0;
1719219b2ee8SDavid du Colombier 		}
1720219b2ee8SDavid du Colombier 
1721219b2ee8SDavid du Colombier 		ndbfree(t);
1722219b2ee8SDavid du Colombier 		t = ndbsnext(&s, attr[0], val[0]);
1723219b2ee8SDavid du Colombier 	}
1724219b2ee8SDavid du Colombier 
1725219b2ee8SDavid du Colombier 	return "no match";
1726219b2ee8SDavid du Colombier }
17277dd7cddfSDavid du Colombier 
17287dd7cddfSDavid du Colombier /*
17297dd7cddfSDavid du Colombier  *  resolve an ip address
17307dd7cddfSDavid du Colombier  */
17317dd7cddfSDavid du Colombier static Ndbtuple*
17327dd7cddfSDavid du Colombier ipresolve(char *attr, char *host)
17337dd7cddfSDavid du Colombier {
17347dd7cddfSDavid du Colombier 	Ndbtuple *t, *nt, **l;
17357dd7cddfSDavid du Colombier 
17367dd7cddfSDavid du Colombier 	t = iplookup(&network[Ntcp], host, "*", 0);
17377dd7cddfSDavid du Colombier 	for(l = &t; *l != nil; ){
17387dd7cddfSDavid du Colombier 		nt = *l;
17397dd7cddfSDavid du Colombier 		if(strcmp(nt->attr, "ip") != 0){
17407dd7cddfSDavid du Colombier 			*l = nt->entry;
17417dd7cddfSDavid du Colombier 			nt->entry = nil;
17427dd7cddfSDavid du Colombier 			ndbfree(nt);
17437dd7cddfSDavid du Colombier 			continue;
17447dd7cddfSDavid du Colombier 		}
17457dd7cddfSDavid du Colombier 		strcpy(nt->attr, attr);
17467dd7cddfSDavid du Colombier 		l = &nt->entry;
17477dd7cddfSDavid du Colombier 	}
17487dd7cddfSDavid du Colombier 	return t;
17497dd7cddfSDavid du Colombier }
17507dd7cddfSDavid du Colombier 
17517dd7cddfSDavid du Colombier char*
17527dd7cddfSDavid du Colombier ipinfoquery(Mfile *mf, char **list, int n)
17537dd7cddfSDavid du Colombier {
17547dd7cddfSDavid du Colombier 	int i, nresolve;
17557dd7cddfSDavid du Colombier 	int resolve[Maxattr];
17567dd7cddfSDavid du Colombier 	Ndbtuple *t, *nt, **l;
17577dd7cddfSDavid du Colombier 	char *attr, *val;
17587dd7cddfSDavid du Colombier 
17597dd7cddfSDavid du Colombier 	/* skip 'ipinfo' */
17607dd7cddfSDavid du Colombier 	list++; n--;
17617dd7cddfSDavid du Colombier 
17628a2c5ad0SDavid du Colombier 	if(n < 1)
17637dd7cddfSDavid du Colombier 		return "bad query";
17647dd7cddfSDavid du Colombier 
17658a2c5ad0SDavid du Colombier 	/* get search attribute=value, or assume ip=myipaddr */
17668a2c5ad0SDavid du Colombier 	attr = *list;
17678a2c5ad0SDavid du Colombier 	if((val = strchr(attr, '=')) != nil){
17687dd7cddfSDavid du Colombier 		*val++ = 0;
17698a2c5ad0SDavid du Colombier 		list++;
17708a2c5ad0SDavid du Colombier 		n--;
17718a2c5ad0SDavid du Colombier 	}else{
17728a2c5ad0SDavid du Colombier 		attr = "ip";
17738a2c5ad0SDavid du Colombier 		val = ipaddr;
17748a2c5ad0SDavid du Colombier 	}
17758a2c5ad0SDavid du Colombier 
17768a2c5ad0SDavid du Colombier 	if(n < 1)
17778a2c5ad0SDavid du Colombier 		return "bad query";
17787dd7cddfSDavid du Colombier 
17797dd7cddfSDavid du Colombier 	/*
17807dd7cddfSDavid du Colombier 	 *  don't let ndbipinfo resolve the addresses, we're
17817dd7cddfSDavid du Colombier 	 *  better at it.
17827dd7cddfSDavid du Colombier 	 */
17837dd7cddfSDavid du Colombier 	nresolve = 0;
17847dd7cddfSDavid du Colombier 	for(i = 0; i < n; i++)
1785107aedb4SDavid du Colombier 		if(*list[i] == '@'){		/* @attr=val ? */
17867dd7cddfSDavid du Colombier 			list[i]++;
1787107aedb4SDavid du Colombier 			resolve[i] = 1;		/* we'll resolve it */
17887dd7cddfSDavid du Colombier 			nresolve++;
17897dd7cddfSDavid du Colombier 		} else
17907dd7cddfSDavid du Colombier 			resolve[i] = 0;
17917dd7cddfSDavid du Colombier 
17927dd7cddfSDavid du Colombier 	t = ndbipinfo(db, attr, val, list, n);
17937dd7cddfSDavid du Colombier 	if(t == nil)
17947dd7cddfSDavid du Colombier 		return "no match";
17957dd7cddfSDavid du Colombier 
17967dd7cddfSDavid du Colombier 	if(nresolve != 0){
17977dd7cddfSDavid du Colombier 		for(l = &t; *l != nil;){
17987dd7cddfSDavid du Colombier 			nt = *l;
17997dd7cddfSDavid du Colombier 
18007dd7cddfSDavid du Colombier 			/* already an address? */
18017dd7cddfSDavid du Colombier 			if(strcmp(ipattr(nt->val), "ip") == 0){
18027dd7cddfSDavid du Colombier 				l = &(*l)->entry;
18037dd7cddfSDavid du Colombier 				continue;
18047dd7cddfSDavid du Colombier 			}
18057dd7cddfSDavid du Colombier 
18067dd7cddfSDavid du Colombier 			/* user wants it resolved? */
18077dd7cddfSDavid du Colombier 			for(i = 0; i < n; i++)
18087dd7cddfSDavid du Colombier 				if(strcmp(list[i], nt->attr) == 0)
18097dd7cddfSDavid du Colombier 					break;
18107dd7cddfSDavid du Colombier 			if(i >= n || resolve[i] == 0){
18117dd7cddfSDavid du Colombier 				l = &(*l)->entry;
18127dd7cddfSDavid du Colombier 				continue;
18137dd7cddfSDavid du Colombier 			}
18147dd7cddfSDavid du Colombier 
18157dd7cddfSDavid du Colombier 			/* resolve address and replace entry */
18167dd7cddfSDavid du Colombier 			*l = ipresolve(nt->attr, nt->val);
18177dd7cddfSDavid du Colombier 			while(*l != nil)
18187dd7cddfSDavid du Colombier 				l = &(*l)->entry;
18197dd7cddfSDavid du Colombier 			*l = nt->entry;
18207dd7cddfSDavid du Colombier 
18217dd7cddfSDavid du Colombier 			nt->entry = nil;
18227dd7cddfSDavid du Colombier 			ndbfree(nt);
18237dd7cddfSDavid du Colombier 		}
18247dd7cddfSDavid du Colombier 	}
18257dd7cddfSDavid du Colombier 
18267dd7cddfSDavid du Colombier 	/* make it all one line */
18277dd7cddfSDavid du Colombier 	for(nt = t; nt != nil; nt = nt->entry){
18287dd7cddfSDavid du Colombier 		if(nt->entry == nil)
18297dd7cddfSDavid du Colombier 			nt->line = t;
18307dd7cddfSDavid du Colombier 		else
18317dd7cddfSDavid du Colombier 			nt->line = nt->entry;
18327dd7cddfSDavid du Colombier 	}
18337dd7cddfSDavid du Colombier 
18347dd7cddfSDavid du Colombier 	qreply(mf, t);
18357dd7cddfSDavid du Colombier 
18367dd7cddfSDavid du Colombier 	return nil;
18377dd7cddfSDavid du Colombier }
18387dd7cddfSDavid du Colombier 
18397dd7cddfSDavid du Colombier void*
18407dd7cddfSDavid du Colombier emalloc(int size)
18417dd7cddfSDavid du Colombier {
18427dd7cddfSDavid du Colombier 	void *x;
18437dd7cddfSDavid du Colombier 
18447dd7cddfSDavid du Colombier 	x = malloc(size);
18457dd7cddfSDavid du Colombier 	if(x == nil)
18467dd7cddfSDavid du Colombier 		abort();
18477dd7cddfSDavid du Colombier 	memset(x, 0, size);
18487dd7cddfSDavid du Colombier 	return x;
18497dd7cddfSDavid du Colombier }
18509a747e4fSDavid du Colombier 
18519a747e4fSDavid du Colombier char*
18529a747e4fSDavid du Colombier estrdup(char *s)
18539a747e4fSDavid du Colombier {
18549a747e4fSDavid du Colombier 	int size;
18559a747e4fSDavid du Colombier 	char *p;
18569a747e4fSDavid du Colombier 
18579a747e4fSDavid du Colombier 	size = strlen(s)+1;
18589a747e4fSDavid du Colombier 	p = malloc(size);
18599a747e4fSDavid du Colombier 	if(p == nil)
18609a747e4fSDavid du Colombier 		abort();
18619a747e4fSDavid du Colombier 	memmove(p, s, size);
18629a747e4fSDavid du Colombier 	return p;
18639a747e4fSDavid du Colombier }
1864