xref: /plan9/sys/src/cmd/ndb/cs.c (revision 9d244d11485ac0621f4267fcec7912b5f16de532)
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;
82b8b25780SDavid du Colombier int	ipv6lookups = 1;
833e12c5d1SDavid du Colombier jmp_buf	masterjmp;	/* return through here after a slave process has been created */
843e12c5d1SDavid du Colombier int	*isslave;	/* *isslave non-zero means this is a slave process */
85bd389b36SDavid du Colombier char	*dbfile;
867dd7cddfSDavid du Colombier Ndb	*db, *netdb;
873e12c5d1SDavid du Colombier 
889a747e4fSDavid du Colombier void	rversion(Job*);
897dd7cddfSDavid du Colombier void	rflush(Job*);
907dd7cddfSDavid du Colombier void	rattach(Job*, Mfile*);
917dd7cddfSDavid du Colombier char*	rwalk(Job*, Mfile*);
927dd7cddfSDavid du Colombier void	ropen(Job*, Mfile*);
937dd7cddfSDavid du Colombier void	rcreate(Job*, Mfile*);
947dd7cddfSDavid du Colombier void	rread(Job*, Mfile*);
957dd7cddfSDavid du Colombier void	rwrite(Job*, Mfile*);
967dd7cddfSDavid du Colombier void	rclunk(Job*, Mfile*);
977dd7cddfSDavid du Colombier void	rremove(Job*, Mfile*);
987dd7cddfSDavid du Colombier void	rstat(Job*, Mfile*);
997dd7cddfSDavid du Colombier void	rwstat(Job*, Mfile*);
1009a747e4fSDavid du Colombier void	rauth(Job*);
1017dd7cddfSDavid du Colombier void	sendmsg(Job*, char*);
1023e12c5d1SDavid du Colombier void	error(char*);
1037dd7cddfSDavid du Colombier void	mountinit(char*, char*);
1043e12c5d1SDavid du Colombier void	io(void);
1057dd7cddfSDavid du Colombier void	ndbinit(void);
1067dd7cddfSDavid du Colombier void	netinit(int);
1073e12c5d1SDavid du Colombier void	netadd(char*);
108219b2ee8SDavid du Colombier char	*genquery(Mfile*, char*);
1097dd7cddfSDavid du Colombier char*	ipinfoquery(Mfile*, char**, int);
110bd389b36SDavid du Colombier int	needproto(Network*, Ndbtuple*);
1119a747e4fSDavid du Colombier int	lookup(Mfile*);
1123e12c5d1SDavid du Colombier Ndbtuple*	reorder(Ndbtuple*, Ndbtuple*);
1137dd7cddfSDavid du Colombier void	ipid(void);
1147dd7cddfSDavid du Colombier void	readipinterfaces(void);
1157dd7cddfSDavid du Colombier void*	emalloc(int);
1169a747e4fSDavid du Colombier char*	estrdup(char*);
1177dd7cddfSDavid du Colombier Job*	newjob(void);
1187dd7cddfSDavid du Colombier void	freejob(Job*);
1197dd7cddfSDavid du Colombier void	setext(char*, int, char*);
12080ee5cbfSDavid du Colombier void	cleanmf(Mfile*);
1213e12c5d1SDavid du Colombier 
122bd389b36SDavid du Colombier extern void	paralloc(void);
123bd389b36SDavid du Colombier 
124bd389b36SDavid du Colombier Lock	dblock;		/* mutex on database operations */
1257dd7cddfSDavid du Colombier Lock	netlock;	/* mutex for netinit() */
126bd389b36SDavid du Colombier 
127219b2ee8SDavid du Colombier char	*logfile = "cs";
1287dd7cddfSDavid du Colombier char	*paranoiafile = "cs.paranoia";
129219b2ee8SDavid du Colombier 
1307dd7cddfSDavid du Colombier char	mntpt[Maxpath];
1317dd7cddfSDavid du Colombier char	netndb[Maxpath];
1327dd7cddfSDavid du Colombier 
13380ee5cbfSDavid du Colombier /*
13480ee5cbfSDavid du Colombier  *  Network specific translators
13580ee5cbfSDavid du Colombier  */
13680ee5cbfSDavid du Colombier Ndbtuple*	iplookup(Network*, char*, char*, int);
13780ee5cbfSDavid du Colombier char*		iptrans(Ndbtuple*, Network*, char*, char*, int);
13880ee5cbfSDavid du Colombier Ndbtuple*	telcolookup(Network*, char*, char*, int);
13980ee5cbfSDavid du Colombier char*		telcotrans(Ndbtuple*, Network*, char*, char*, int);
14080ee5cbfSDavid du Colombier Ndbtuple*	dnsiplookup(char*, Ndbs*);
14180ee5cbfSDavid du Colombier 
14280ee5cbfSDavid du Colombier struct Network
14380ee5cbfSDavid du Colombier {
14480ee5cbfSDavid du Colombier 	char		*net;
14580ee5cbfSDavid du Colombier 	Ndbtuple	*(*lookup)(Network*, char*, char*, int);
14680ee5cbfSDavid du Colombier 	char		*(*trans)(Ndbtuple*, Network*, char*, char*, int);
147617c0e1eSDavid du Colombier 	int		considered;		/* flag: ignored for "net!"? */
148617c0e1eSDavid du Colombier 	int		fasttimeouthack;	/* flag. was for IL */
14980ee5cbfSDavid du Colombier 	Network		*next;
15080ee5cbfSDavid du Colombier };
15180ee5cbfSDavid du Colombier 
15280ee5cbfSDavid du Colombier enum
15380ee5cbfSDavid du Colombier {
15475766116SDavid du Colombier 	Ntcp = 0,
15580ee5cbfSDavid du Colombier };
15680ee5cbfSDavid du Colombier 
15780ee5cbfSDavid du Colombier /*
158244672c5SDavid du Colombier  *  net doesn't apply to (r)udp, icmp(v6), or telco (for speed).
15980ee5cbfSDavid du Colombier  */
16080ee5cbfSDavid du Colombier Network network[] = {
161617c0e1eSDavid du Colombier [Ntcp]	{ "tcp",	iplookup,	iptrans,	0 },
162617c0e1eSDavid du Colombier 	{ "udp",	iplookup,	iptrans,	1 },
163617c0e1eSDavid du Colombier 	{ "icmp",	iplookup,	iptrans,	1 },
164617c0e1eSDavid du Colombier 	{ "icmpv6",	iplookup,	iptrans,	1 },
165617c0e1eSDavid du Colombier 	{ "rudp",	iplookup,	iptrans,	1 },
166*9d244d11SDavid du Colombier 	{ "ssh",	iplookup,	iptrans,	1 },
167617c0e1eSDavid du Colombier 	{ "telco",	telcolookup,	telcotrans,	1 },
16880ee5cbfSDavid du Colombier 	{ 0 },
16980ee5cbfSDavid du Colombier };
17080ee5cbfSDavid du Colombier 
17180ee5cbfSDavid du Colombier Lock ipifclock;
17280ee5cbfSDavid du Colombier Ipifc *ipifcs;
17380ee5cbfSDavid du Colombier 
17495a264b3SDavid du Colombier char	eaddr[16];		/* ascii ethernet address */
17595a264b3SDavid du Colombier char	ipaddr[64];		/* ascii internet address */
17680ee5cbfSDavid du Colombier uchar	ipa[IPaddrlen];		/* binary internet address */
17795a264b3SDavid du Colombier char	*mysysname;
17880ee5cbfSDavid du Colombier 
17980ee5cbfSDavid du Colombier Network *netlist;		/* networks ordered by preference */
18080ee5cbfSDavid du Colombier Network *last;
18180ee5cbfSDavid du Colombier 
18295a264b3SDavid du Colombier static void
nstrcpy(char * to,char * from,int len)18395a264b3SDavid du Colombier nstrcpy(char *to, char *from, int len)
18495a264b3SDavid du Colombier {
18595a264b3SDavid du Colombier 	strncpy(to, from, len);
18695a264b3SDavid du Colombier 	to[len-1] = 0;
18795a264b3SDavid du Colombier }
18895a264b3SDavid du Colombier 
1897dd7cddfSDavid du Colombier void
usage(void)1907dd7cddfSDavid du Colombier usage(void)
1917dd7cddfSDavid du Colombier {
19275766116SDavid du Colombier 	fprint(2, "usage: %s [-dn] [-f ndb-file] [-x netmtpt]\n", argv0);
1937dd7cddfSDavid du Colombier 	exits("usage");
1947dd7cddfSDavid du Colombier }
195219b2ee8SDavid du Colombier 
196254fe3d3SDavid du Colombier /*
197254fe3d3SDavid du Colombier  * based on libthread's threadsetname, but drags in less library code.
198254fe3d3SDavid du Colombier  * actually just sets the arguments displayed.
199254fe3d3SDavid du Colombier  */
200254fe3d3SDavid du Colombier void
procsetname(char * fmt,...)201254fe3d3SDavid du Colombier procsetname(char *fmt, ...)
202254fe3d3SDavid du Colombier {
203254fe3d3SDavid du Colombier 	int fd;
204254fe3d3SDavid du Colombier 	char *cmdname;
205254fe3d3SDavid du Colombier 	char buf[128];
206254fe3d3SDavid du Colombier 	va_list arg;
207254fe3d3SDavid du Colombier 
208254fe3d3SDavid du Colombier 	va_start(arg, fmt);
209254fe3d3SDavid du Colombier 	cmdname = vsmprint(fmt, arg);
210254fe3d3SDavid du Colombier 	va_end(arg);
211254fe3d3SDavid du Colombier 	if (cmdname == nil)
212254fe3d3SDavid du Colombier 		return;
213254fe3d3SDavid du Colombier 	snprint(buf, sizeof buf, "#p/%d/args", getpid());
214254fe3d3SDavid du Colombier 	if((fd = open(buf, OWRITE)) >= 0){
215254fe3d3SDavid du Colombier 		write(fd, cmdname, strlen(cmdname)+1);
216254fe3d3SDavid du Colombier 		close(fd);
217254fe3d3SDavid du Colombier 	}
218254fe3d3SDavid du Colombier 	free(cmdname);
219254fe3d3SDavid du Colombier }
220254fe3d3SDavid du Colombier 
2213e12c5d1SDavid du Colombier void
main(int argc,char * argv[])2223e12c5d1SDavid du Colombier main(int argc, char *argv[])
2233e12c5d1SDavid du Colombier {
224219b2ee8SDavid du Colombier 	int justsetname;
22575766116SDavid du Colombier 	char ext[Maxpath], servefile[Maxpath];
2263e12c5d1SDavid du Colombier 
227219b2ee8SDavid du Colombier 	justsetname = 0;
2287dd7cddfSDavid du Colombier 	setnetmtpt(mntpt, sizeof(mntpt), nil);
2297dd7cddfSDavid du Colombier 	ext[0] = 0;
2303e12c5d1SDavid du Colombier 	ARGBEGIN{
231b8b25780SDavid du Colombier 	case '4':
232b8b25780SDavid du Colombier 		ipv6lookups = 0;
233b8b25780SDavid du Colombier 		break;
2343e12c5d1SDavid du Colombier 	case 'd':
2353e12c5d1SDavid du Colombier 		debug = 1;
2363e12c5d1SDavid du Colombier 		break;
237bd389b36SDavid du Colombier 	case 'f':
23875766116SDavid du Colombier 		dbfile = EARGF(usage());
239bd389b36SDavid du Colombier 		break;
240219b2ee8SDavid du Colombier 	case 'n':
241219b2ee8SDavid du Colombier 		justsetname = 1;
242219b2ee8SDavid du Colombier 		break;
24375766116SDavid du Colombier 	case 'x':
24475766116SDavid du Colombier 		setnetmtpt(mntpt, sizeof(mntpt), EARGF(usage()));
24575766116SDavid du Colombier 		setext(ext, sizeof(ext), mntpt);
24675766116SDavid du Colombier 		break;
2473e12c5d1SDavid du Colombier 	}ARGEND
2483e12c5d1SDavid du Colombier 	USED(argc);
2493e12c5d1SDavid du Colombier 	USED(argv);
2503e12c5d1SDavid du Colombier 
2517dd7cddfSDavid du Colombier 	rfork(RFREND|RFNOTEG);
2527dd7cddfSDavid du Colombier 
2537dd7cddfSDavid du Colombier 	snprint(servefile, sizeof(servefile), "#s/cs%s", ext);
2547dd7cddfSDavid du Colombier 	snprint(netndb, sizeof(netndb), "%s/ndb", mntpt);
2557dd7cddfSDavid du Colombier 	unmount(servefile, mntpt);
2567dd7cddfSDavid du Colombier 	remove(servefile);
2577dd7cddfSDavid du Colombier 
2589a747e4fSDavid du Colombier 	fmtinstall('E', eipfmt);
2599a747e4fSDavid du Colombier 	fmtinstall('I', eipfmt);
2609a747e4fSDavid du Colombier 	fmtinstall('M', eipfmt);
2619a747e4fSDavid du Colombier 	fmtinstall('F', fcallfmt);
2627dd7cddfSDavid du Colombier 
2637dd7cddfSDavid du Colombier 	ndbinit();
2647dd7cddfSDavid du Colombier 	netinit(0);
2657dd7cddfSDavid du Colombier 
2667dd7cddfSDavid du Colombier 	if(!justsetname){
2677dd7cddfSDavid du Colombier 		mountinit(servefile, mntpt);
2687dd7cddfSDavid du Colombier 		io();
2697dd7cddfSDavid du Colombier 	}
270219b2ee8SDavid du Colombier 	exits(0);
271219b2ee8SDavid du Colombier }
272219b2ee8SDavid du Colombier 
2737dd7cddfSDavid du Colombier /*
2747dd7cddfSDavid du Colombier  *  if a mount point is specified, set the cs extention to be the mount point
2757dd7cddfSDavid du Colombier  *  with '_'s replacing '/'s
2767dd7cddfSDavid du Colombier  */
2777dd7cddfSDavid du Colombier void
setext(char * ext,int n,char * p)2787dd7cddfSDavid du Colombier setext(char *ext, int n, char *p)
2797dd7cddfSDavid du Colombier {
2807dd7cddfSDavid du Colombier 	int i, c;
2813e12c5d1SDavid du Colombier 
2827dd7cddfSDavid du Colombier 	n--;
2837dd7cddfSDavid du Colombier 	for(i = 0; i < n; i++){
2847dd7cddfSDavid du Colombier 		c = p[i];
2857dd7cddfSDavid du Colombier 		if(c == 0)
2867dd7cddfSDavid du Colombier 			break;
2877dd7cddfSDavid du Colombier 		if(c == '/')
2887dd7cddfSDavid du Colombier 			c = '_';
2897dd7cddfSDavid du Colombier 		ext[i] = c;
2907dd7cddfSDavid du Colombier 	}
2917dd7cddfSDavid du Colombier 	ext[i] = 0;
2923e12c5d1SDavid du Colombier }
2933e12c5d1SDavid du Colombier 
2943e12c5d1SDavid du Colombier void
mountinit(char * service,char * mntpt)2957dd7cddfSDavid du Colombier mountinit(char *service, char *mntpt)
2963e12c5d1SDavid du Colombier {
2973e12c5d1SDavid du Colombier 	int f;
2983e12c5d1SDavid du Colombier 	int p[2];
2993e12c5d1SDavid du Colombier 	char buf[32];
3003e12c5d1SDavid du Colombier 
3013e12c5d1SDavid du Colombier 	if(pipe(p) < 0)
3023e12c5d1SDavid du Colombier 		error("pipe failed");
303a9f680aeSDavid du Colombier 
304a9f680aeSDavid du Colombier 	/*
305a9f680aeSDavid du Colombier 	 *  make a /srv/cs
306a9f680aeSDavid du Colombier 	 */
307a9f680aeSDavid du Colombier 	f = create(service, OWRITE|ORCLOSE, 0666);
308a9f680aeSDavid du Colombier 	if(f < 0)
309a9f680aeSDavid du Colombier 		error(service);
310a9f680aeSDavid du Colombier 	snprint(buf, sizeof(buf), "%d", p[1]);
311a9f680aeSDavid du Colombier 	if(write(f, buf, strlen(buf)) != strlen(buf))
312a9f680aeSDavid du Colombier 		error("write /srv/cs");
313a9f680aeSDavid du Colombier 
314219b2ee8SDavid du Colombier 	switch(rfork(RFFDG|RFPROC|RFNAMEG)){
3153e12c5d1SDavid du Colombier 	case 0:
316219b2ee8SDavid du Colombier 		close(p[1]);
317254fe3d3SDavid du Colombier 		procsetname("%s", mntpt);
3183e12c5d1SDavid du Colombier 		break;
3193e12c5d1SDavid du Colombier 	case -1:
3203e12c5d1SDavid du Colombier 		error("fork failed\n");
3213e12c5d1SDavid du Colombier 	default:
3223e12c5d1SDavid du Colombier 		/*
3233e12c5d1SDavid du Colombier 		 *  put ourselves into the file system
3243e12c5d1SDavid du Colombier 		 */
325219b2ee8SDavid du Colombier 		close(p[0]);
3269a747e4fSDavid du Colombier 		if(mount(p[1], -1, mntpt, MAFTER, "") < 0)
3273e12c5d1SDavid du Colombier 			error("mount failed\n");
328219b2ee8SDavid du Colombier 		_exits(0);
3293e12c5d1SDavid du Colombier 	}
3303e12c5d1SDavid du Colombier 	mfd[0] = mfd[1] = p[0];
3313e12c5d1SDavid du Colombier }
3323e12c5d1SDavid du Colombier 
3337dd7cddfSDavid du Colombier void
ndbinit(void)3347dd7cddfSDavid du Colombier ndbinit(void)
3357dd7cddfSDavid du Colombier {
3367dd7cddfSDavid du Colombier 	db = ndbopen(dbfile);
3377dd7cddfSDavid du Colombier 	if(db == nil)
3387dd7cddfSDavid du Colombier 		error("can't open network database");
3397dd7cddfSDavid du Colombier 
3407dd7cddfSDavid du Colombier 	netdb = ndbopen(netndb);
3417dd7cddfSDavid du Colombier 	if(netdb != nil){
3427dd7cddfSDavid du Colombier 		netdb->nohash = 1;
3437dd7cddfSDavid du Colombier 		db = ndbcat(netdb, db);
3447dd7cddfSDavid du Colombier 	}
3457dd7cddfSDavid du Colombier }
3467dd7cddfSDavid du Colombier 
3473e12c5d1SDavid du Colombier Mfile*
newfid(int fid)3483e12c5d1SDavid du Colombier newfid(int fid)
3493e12c5d1SDavid du Colombier {
350219b2ee8SDavid du Colombier 	Mlist *f, *ff;
3513e12c5d1SDavid du Colombier 	Mfile *mf;
3523e12c5d1SDavid du Colombier 
353219b2ee8SDavid du Colombier 	ff = 0;
354219b2ee8SDavid du Colombier 	for(f = mlist; f; f = f->next)
355219b2ee8SDavid du Colombier 		if(f->mf.busy && f->mf.fid == fid)
356219b2ee8SDavid du Colombier 			return &f->mf;
357219b2ee8SDavid du Colombier 		else if(!ff && !f->mf.busy)
358219b2ee8SDavid du Colombier 			ff = f;
359219b2ee8SDavid du Colombier 	if(ff == 0){
3607dd7cddfSDavid du Colombier 		ff = emalloc(sizeof *f);
361219b2ee8SDavid du Colombier 		ff->next = mlist;
362219b2ee8SDavid du Colombier 		mlist = ff;
3633e12c5d1SDavid du Colombier 	}
364219b2ee8SDavid du Colombier 	mf = &ff->mf;
365219b2ee8SDavid du Colombier 	memset(mf, 0, sizeof *mf);
3663e12c5d1SDavid du Colombier 	mf->fid = fid;
3673e12c5d1SDavid du Colombier 	return mf;
3683e12c5d1SDavid du Colombier }
3693e12c5d1SDavid du Colombier 
3707dd7cddfSDavid du Colombier Job*
newjob(void)3717dd7cddfSDavid du Colombier newjob(void)
3727dd7cddfSDavid du Colombier {
3737dd7cddfSDavid du Colombier 	Job *job;
3747dd7cddfSDavid du Colombier 
3757dd7cddfSDavid du Colombier 	job = mallocz(sizeof(Job), 1);
3767dd7cddfSDavid du Colombier 	lock(&joblock);
3777dd7cddfSDavid du Colombier 	job->next = joblist;
3787dd7cddfSDavid du Colombier 	joblist = job;
3797dd7cddfSDavid du Colombier 	job->request.tag = -1;
3807dd7cddfSDavid du Colombier 	unlock(&joblock);
3817dd7cddfSDavid du Colombier 	return job;
3827dd7cddfSDavid du Colombier }
3837dd7cddfSDavid du Colombier 
3847dd7cddfSDavid du Colombier void
freejob(Job * job)3857dd7cddfSDavid du Colombier freejob(Job *job)
3867dd7cddfSDavid du Colombier {
3877dd7cddfSDavid du Colombier 	Job **l;
3887dd7cddfSDavid du Colombier 
3897dd7cddfSDavid du Colombier 	lock(&joblock);
3907dd7cddfSDavid du Colombier 	for(l = &joblist; *l; l = &(*l)->next){
3917dd7cddfSDavid du Colombier 		if((*l) == job){
3927dd7cddfSDavid du Colombier 			*l = job->next;
3937dd7cddfSDavid du Colombier 			free(job);
3947dd7cddfSDavid du Colombier 			break;
3957dd7cddfSDavid du Colombier 		}
3967dd7cddfSDavid du Colombier 	}
3977dd7cddfSDavid du Colombier 	unlock(&joblock);
3987dd7cddfSDavid du Colombier }
3997dd7cddfSDavid du Colombier 
4007dd7cddfSDavid du Colombier void
flushjob(int tag)4017dd7cddfSDavid du Colombier flushjob(int tag)
4027dd7cddfSDavid du Colombier {
4037dd7cddfSDavid du Colombier 	Job *job;
4047dd7cddfSDavid du Colombier 
4057dd7cddfSDavid du Colombier 	lock(&joblock);
4067dd7cddfSDavid du Colombier 	for(job = joblist; job; job = job->next){
4077dd7cddfSDavid du Colombier 		if(job->request.tag == tag && job->request.type != Tflush){
4087dd7cddfSDavid du Colombier 			job->flushed = 1;
4097dd7cddfSDavid du Colombier 			break;
4107dd7cddfSDavid du Colombier 		}
4117dd7cddfSDavid du Colombier 	}
4127dd7cddfSDavid du Colombier 	unlock(&joblock);
4137dd7cddfSDavid du Colombier }
4147dd7cddfSDavid du Colombier 
4153e12c5d1SDavid du Colombier void
io(void)4163e12c5d1SDavid du Colombier io(void)
4173e12c5d1SDavid du Colombier {
4183e12c5d1SDavid du Colombier 	long n;
4193e12c5d1SDavid du Colombier 	Mfile *mf;
4203e12c5d1SDavid du Colombier 	int slaveflag;
4219a747e4fSDavid du Colombier 	uchar mdata[IOHDRSZ + Maxfdata];
4227dd7cddfSDavid du Colombier 	Job *job;
4233e12c5d1SDavid du Colombier 
4243e12c5d1SDavid du Colombier 	/*
4253e12c5d1SDavid du Colombier 	 *  if we ask dns to fulfill requests,
4263e12c5d1SDavid du Colombier 	 *  a slave process is created to wait for replies.  The
4279a747e4fSDavid du Colombier 	 *  master process returns immediately via a longjmp
4283e12c5d1SDavid du Colombier 	 *  through 'masterjmp'.
4293e12c5d1SDavid du Colombier 	 *
4303e12c5d1SDavid du Colombier 	 *  *isslave is a pointer into the call stack to a variable
4313e12c5d1SDavid du Colombier 	 *  that tells whether or not the current process is a slave.
4323e12c5d1SDavid du Colombier 	 */
4333e12c5d1SDavid du Colombier 	slaveflag = 0;		/* init slave variable */
4343e12c5d1SDavid du Colombier 	isslave = &slaveflag;
4353e12c5d1SDavid du Colombier 	setjmp(masterjmp);
4363e12c5d1SDavid du Colombier 
4373e12c5d1SDavid du Colombier 	for(;;){
4389a747e4fSDavid du Colombier 		n = read9pmsg(mfd[0], mdata, sizeof mdata);
4393e12c5d1SDavid du Colombier 		if(n<=0)
4403e12c5d1SDavid du Colombier 			error("mount read");
4417dd7cddfSDavid du Colombier 		job = newjob();
4429a747e4fSDavid du Colombier 		if(convM2S(mdata, n, &job->request) != n){
443271b8d73SDavid du Colombier 			syslog(1, logfile, "format error %ux %ux %ux %ux %ux",
444271b8d73SDavid du Colombier 				mdata[0], mdata[1], mdata[2], mdata[3], mdata[4]);
4457dd7cddfSDavid du Colombier 			freejob(job);
4463e12c5d1SDavid du Colombier 			continue;
4473e12c5d1SDavid du Colombier 		}
448bd389b36SDavid du Colombier 		lock(&dblock);
4497dd7cddfSDavid du Colombier 		mf = newfid(job->request.fid);
450219b2ee8SDavid du Colombier 		if(debug)
4517dd7cddfSDavid du Colombier 			syslog(0, logfile, "%F", &job->request);
4523e12c5d1SDavid du Colombier 
4533e12c5d1SDavid du Colombier 
4547dd7cddfSDavid du Colombier 		switch(job->request.type){
4553e12c5d1SDavid du Colombier 		default:
4567dd7cddfSDavid du Colombier 			syslog(1, logfile, "unknown request type %d", job->request.type);
4573e12c5d1SDavid du Colombier 			break;
4589a747e4fSDavid du Colombier 		case Tversion:
4599a747e4fSDavid du Colombier 			rversion(job);
4603e12c5d1SDavid du Colombier 			break;
4619a747e4fSDavid du Colombier 		case Tauth:
4629a747e4fSDavid du Colombier 			rauth(job);
4633e12c5d1SDavid du Colombier 			break;
4643e12c5d1SDavid du Colombier 		case Tflush:
4657dd7cddfSDavid du Colombier 			rflush(job);
4663e12c5d1SDavid du Colombier 			break;
4673e12c5d1SDavid du Colombier 		case Tattach:
4687dd7cddfSDavid du Colombier 			rattach(job, mf);
4693e12c5d1SDavid du Colombier 			break;
4703e12c5d1SDavid du Colombier 		case Twalk:
4717dd7cddfSDavid du Colombier 			rwalk(job, mf);
4723e12c5d1SDavid du Colombier 			break;
4733e12c5d1SDavid du Colombier 		case Topen:
4747dd7cddfSDavid du Colombier 			ropen(job, mf);
4753e12c5d1SDavid du Colombier 			break;
4763e12c5d1SDavid du Colombier 		case Tcreate:
4777dd7cddfSDavid du Colombier 			rcreate(job, mf);
4783e12c5d1SDavid du Colombier 			break;
4793e12c5d1SDavid du Colombier 		case Tread:
4807dd7cddfSDavid du Colombier 			rread(job, mf);
4813e12c5d1SDavid du Colombier 			break;
4823e12c5d1SDavid du Colombier 		case Twrite:
4837dd7cddfSDavid du Colombier 			rwrite(job, mf);
4843e12c5d1SDavid du Colombier 			break;
4853e12c5d1SDavid du Colombier 		case Tclunk:
4867dd7cddfSDavid du Colombier 			rclunk(job, mf);
4873e12c5d1SDavid du Colombier 			break;
4883e12c5d1SDavid du Colombier 		case Tremove:
4897dd7cddfSDavid du Colombier 			rremove(job, mf);
4903e12c5d1SDavid du Colombier 			break;
4913e12c5d1SDavid du Colombier 		case Tstat:
4927dd7cddfSDavid du Colombier 			rstat(job, mf);
4933e12c5d1SDavid du Colombier 			break;
4943e12c5d1SDavid du Colombier 		case Twstat:
4957dd7cddfSDavid du Colombier 			rwstat(job, mf);
4963e12c5d1SDavid du Colombier 			break;
4973e12c5d1SDavid du Colombier 		}
498bd389b36SDavid du Colombier 		unlock(&dblock);
4997dd7cddfSDavid du Colombier 
5007dd7cddfSDavid du Colombier 		freejob(job);
5017dd7cddfSDavid du Colombier 
5023e12c5d1SDavid du Colombier 		/*
5033e12c5d1SDavid du Colombier 		 *  slave processes die after replying
5043e12c5d1SDavid du Colombier 		 */
505219b2ee8SDavid du Colombier 		if(*isslave){
506219b2ee8SDavid du Colombier 			if(debug)
507219b2ee8SDavid du Colombier 				syslog(0, logfile, "slave death %d", getpid());
5083e12c5d1SDavid du Colombier 			_exits(0);
5093e12c5d1SDavid du Colombier 		}
5103e12c5d1SDavid du Colombier 	}
511219b2ee8SDavid du Colombier }
512219b2ee8SDavid du Colombier 
513219b2ee8SDavid du Colombier void
rversion(Job * job)5149a747e4fSDavid du Colombier rversion(Job *job)
515219b2ee8SDavid du Colombier {
5169a747e4fSDavid du Colombier 	if(job->request.msize > IOHDRSZ + Maxfdata)
5179a747e4fSDavid du Colombier 		job->reply.msize = IOHDRSZ + Maxfdata;
5189a747e4fSDavid du Colombier 	else
5199a747e4fSDavid du Colombier 		job->reply.msize = job->request.msize;
5209a747e4fSDavid du Colombier 	if(strncmp(job->request.version, "9P2000", 6) != 0)
5219a747e4fSDavid du Colombier 		sendmsg(job, "unknown 9P version");
5229a747e4fSDavid du Colombier 	else{
5239a747e4fSDavid du Colombier 		job->reply.version = "9P2000";
5247dd7cddfSDavid du Colombier 		sendmsg(job, 0);
525219b2ee8SDavid du Colombier 	}
5269a747e4fSDavid du Colombier }
5273e12c5d1SDavid du Colombier 
5283e12c5d1SDavid du Colombier void
rauth(Job * job)5299a747e4fSDavid du Colombier rauth(Job *job)
5303e12c5d1SDavid du Colombier {
5313ff48bf5SDavid du Colombier 	sendmsg(job, "cs: authentication not required");
5327dd7cddfSDavid du Colombier }
5337dd7cddfSDavid du Colombier 
5347dd7cddfSDavid du Colombier /*
5357dd7cddfSDavid du Colombier  *  don't flush till all the slaves are done
5367dd7cddfSDavid du Colombier  */
5377dd7cddfSDavid du Colombier void
rflush(Job * job)5387dd7cddfSDavid du Colombier rflush(Job *job)
5397dd7cddfSDavid du Colombier {
5407dd7cddfSDavid du Colombier 	flushjob(job->request.oldtag);
5417dd7cddfSDavid du Colombier 	sendmsg(job, 0);
5423e12c5d1SDavid du Colombier }
5433e12c5d1SDavid du Colombier 
5443e12c5d1SDavid du Colombier void
rattach(Job * job,Mfile * mf)5457dd7cddfSDavid du Colombier rattach(Job *job, Mfile *mf)
5463e12c5d1SDavid du Colombier {
5473e12c5d1SDavid du Colombier 	if(mf->busy == 0){
5483e12c5d1SDavid du Colombier 		mf->busy = 1;
5499a747e4fSDavid du Colombier 		mf->user = estrdup(job->request.uname);
5503e12c5d1SDavid du Colombier 	}
5513e12c5d1SDavid du Colombier 	mf->qid.vers = vers++;
5529a747e4fSDavid du Colombier 	mf->qid.type = QTDIR;
5539a747e4fSDavid du Colombier 	mf->qid.path = 0LL;
5547dd7cddfSDavid du Colombier 	job->reply.qid = mf->qid;
5557dd7cddfSDavid du Colombier 	sendmsg(job, 0);
5563e12c5d1SDavid du Colombier }
5573e12c5d1SDavid du Colombier 
5583e12c5d1SDavid du Colombier 
5593e12c5d1SDavid du Colombier char*
rwalk(Job * job,Mfile * mf)5607dd7cddfSDavid du Colombier rwalk(Job *job, Mfile *mf)
5613e12c5d1SDavid du Colombier {
5623e12c5d1SDavid du Colombier 	char *err;
5639a747e4fSDavid du Colombier 	char **elems;
5649a747e4fSDavid du Colombier 	int nelems;
5659a747e4fSDavid du Colombier 	int i;
5669a747e4fSDavid du Colombier 	Mfile *nmf;
5679a747e4fSDavid du Colombier 	Qid qid;
5683e12c5d1SDavid du Colombier 
5693e12c5d1SDavid du Colombier 	err = 0;
5709a747e4fSDavid du Colombier 	nmf = nil;
5719a747e4fSDavid du Colombier 	elems = job->request.wname;
5729a747e4fSDavid du Colombier 	nelems = job->request.nwname;
5739a747e4fSDavid du Colombier 	job->reply.nwqid = 0;
5749a747e4fSDavid du Colombier 
5759a747e4fSDavid du Colombier 	if(job->request.newfid != job->request.fid){
5769a747e4fSDavid du Colombier 		/* clone fid */
5779a747e4fSDavid du Colombier 		nmf = newfid(job->request.newfid);
5789a747e4fSDavid du Colombier 		if(nmf->busy){
5799a747e4fSDavid du Colombier 			nmf = nil;
5809a747e4fSDavid du Colombier 			err = "clone to used channel";
5819a747e4fSDavid du Colombier 			goto send;
5829a747e4fSDavid du Colombier 		}
5839a747e4fSDavid du Colombier 		*nmf = *mf;
5849a747e4fSDavid du Colombier 		nmf->user = estrdup(mf->user);
5859a747e4fSDavid du Colombier 		nmf->fid = job->request.newfid;
5869a747e4fSDavid du Colombier 		nmf->qid.vers = vers++;
5879a747e4fSDavid du Colombier 		mf = nmf;
5889a747e4fSDavid du Colombier 	}
5899a747e4fSDavid du Colombier 	/* else nmf will be nil */
5909a747e4fSDavid du Colombier 
5919a747e4fSDavid du Colombier 	qid = mf->qid;
5929a747e4fSDavid du Colombier 	if(nelems > 0){
5939a747e4fSDavid du Colombier 		/* walk fid */
5949a747e4fSDavid du Colombier 		for(i=0; i<nelems && i<MAXWELEM; i++){
5959a747e4fSDavid du Colombier 			if((qid.type & QTDIR) == 0){
5963e12c5d1SDavid du Colombier 				err = "not a directory";
5979a747e4fSDavid du Colombier 				break;
5983e12c5d1SDavid du Colombier 			}
5999a747e4fSDavid du Colombier 			if(strcmp(elems[i], "..") == 0 || strcmp(elems[i], ".") == 0){
6009a747e4fSDavid du Colombier 				qid.type = QTDIR;
6019a747e4fSDavid du Colombier 				qid.path = Qdir;
6029a747e4fSDavid du Colombier     Found:
6039a747e4fSDavid du Colombier 				job->reply.wqid[i] = qid;
6049a747e4fSDavid du Colombier 				job->reply.nwqid++;
6059a747e4fSDavid du Colombier 				continue;
6063e12c5d1SDavid du Colombier 			}
6079a747e4fSDavid du Colombier 			if(strcmp(elems[i], "cs") == 0){
6089a747e4fSDavid du Colombier 				qid.type = QTFILE;
6099a747e4fSDavid du Colombier 				qid.path = Qcs;
6109a747e4fSDavid du Colombier 				goto Found;
6113e12c5d1SDavid du Colombier 			}
6129a747e4fSDavid du Colombier 			err = "file does not exist";
6139a747e4fSDavid du Colombier 			break;
6149a747e4fSDavid du Colombier 		}
6159a747e4fSDavid du Colombier 	}
6169a747e4fSDavid du Colombier 
6173e12c5d1SDavid du Colombier     send:
6189a747e4fSDavid du Colombier 	if(nmf != nil && (err!=nil || job->reply.nwqid<nelems)){
619a9f680aeSDavid du Colombier 		cleanmf(nmf);
620a9f680aeSDavid du Colombier 		free(nmf->user);
621a9f680aeSDavid du Colombier 		nmf->user = 0;
6229a747e4fSDavid du Colombier 		nmf->busy = 0;
6239a747e4fSDavid du Colombier 		nmf->fid = 0;
6249a747e4fSDavid du Colombier 	}
6259a747e4fSDavid du Colombier 	if(err == nil)
6269a747e4fSDavid du Colombier 		mf->qid = qid;
6277dd7cddfSDavid du Colombier 	sendmsg(job, err);
6283e12c5d1SDavid du Colombier 	return err;
6293e12c5d1SDavid du Colombier }
6303e12c5d1SDavid du Colombier 
6313e12c5d1SDavid du Colombier void
ropen(Job * job,Mfile * mf)6327dd7cddfSDavid du Colombier ropen(Job *job, Mfile *mf)
6333e12c5d1SDavid du Colombier {
6343e12c5d1SDavid du Colombier 	int mode;
6353e12c5d1SDavid du Colombier 	char *err;
6363e12c5d1SDavid du Colombier 
6373e12c5d1SDavid du Colombier 	err = 0;
6387dd7cddfSDavid du Colombier 	mode = job->request.mode;
6399a747e4fSDavid du Colombier 	if(mf->qid.type & QTDIR){
6403e12c5d1SDavid du Colombier 		if(mode)
6413e12c5d1SDavid du Colombier 			err = "permission denied";
6429a747e4fSDavid du Colombier 	}
6437dd7cddfSDavid du Colombier 	job->reply.qid = mf->qid;
6449a747e4fSDavid du Colombier 	job->reply.iounit = 0;
6457dd7cddfSDavid du Colombier 	sendmsg(job, err);
6463e12c5d1SDavid du Colombier }
6473e12c5d1SDavid du Colombier 
6483e12c5d1SDavid du Colombier void
rcreate(Job * job,Mfile * mf)6497dd7cddfSDavid du Colombier rcreate(Job *job, Mfile *mf)
6503e12c5d1SDavid du Colombier {
6513e12c5d1SDavid du Colombier 	USED(mf);
6527dd7cddfSDavid du Colombier 	sendmsg(job, "creation permission denied");
6533e12c5d1SDavid du Colombier }
6543e12c5d1SDavid du Colombier 
6553e12c5d1SDavid du Colombier void
rread(Job * job,Mfile * mf)6567dd7cddfSDavid du Colombier rread(Job *job, Mfile *mf)
6573e12c5d1SDavid du Colombier {
658219b2ee8SDavid du Colombier 	int i, n, cnt;
659219b2ee8SDavid du Colombier 	long off, toff, clock;
6603e12c5d1SDavid du Colombier 	Dir dir;
661254fe3d3SDavid du Colombier 	uchar buf[Maxfdata];
6623e12c5d1SDavid du Colombier 	char *err;
6633e12c5d1SDavid du Colombier 
6643e12c5d1SDavid du Colombier 	n = 0;
6653e12c5d1SDavid du Colombier 	err = 0;
6667dd7cddfSDavid du Colombier 	off = job->request.offset;
6677dd7cddfSDavid du Colombier 	cnt = job->request.count;
6689a747e4fSDavid du Colombier 	if(mf->qid.type & QTDIR){
6693e12c5d1SDavid du Colombier 		clock = time(0);
6703e12c5d1SDavid du Colombier 		if(off == 0){
6716aaebd7dSDavid du Colombier 			memset(&dir, 0, sizeof dir);
6729a747e4fSDavid du Colombier 			dir.name = "cs";
6739a747e4fSDavid du Colombier 			dir.qid.type = QTFILE;
6743e12c5d1SDavid du Colombier 			dir.qid.vers = vers;
6753e12c5d1SDavid du Colombier 			dir.qid.path = Qcs;
6763e12c5d1SDavid du Colombier 			dir.mode = 0666;
6773e12c5d1SDavid du Colombier 			dir.length = 0;
6789a747e4fSDavid du Colombier 			dir.uid = mf->user;
6799a747e4fSDavid du Colombier 			dir.gid = mf->user;
6809a747e4fSDavid du Colombier 			dir.muid = mf->user;
6813e12c5d1SDavid du Colombier 			dir.atime = clock;	/* wrong */
6823e12c5d1SDavid du Colombier 			dir.mtime = clock;	/* wrong */
6839a747e4fSDavid du Colombier 			n = convD2M(&dir, buf, sizeof buf);
6843e12c5d1SDavid du Colombier 		}
6859a747e4fSDavid du Colombier 		job->reply.data = (char*)buf;
6863e12c5d1SDavid du Colombier 	} else {
68780ee5cbfSDavid du Colombier 		for(;;){
68880ee5cbfSDavid du Colombier 			/* look for an answer at the right offset */
689219b2ee8SDavid du Colombier 			toff = 0;
690219b2ee8SDavid du Colombier 			for(i = 0; mf->reply[i] && i < mf->nreply; i++){
691219b2ee8SDavid du Colombier 				n = mf->replylen[i];
692219b2ee8SDavid du Colombier 				if(off < toff + n)
693219b2ee8SDavid du Colombier 					break;
694219b2ee8SDavid du Colombier 				toff += n;
6953e12c5d1SDavid du Colombier 			}
69680ee5cbfSDavid du Colombier 			if(i < mf->nreply)
69780ee5cbfSDavid du Colombier 				break;		/* got something to return */
69880ee5cbfSDavid du Colombier 
69980ee5cbfSDavid du Colombier 			/* try looking up more answers */
70080ee5cbfSDavid du Colombier 			if(lookup(mf) == 0){
70180ee5cbfSDavid du Colombier 				/* no more */
702219b2ee8SDavid du Colombier 				n = 0;
703219b2ee8SDavid du Colombier 				goto send;
704219b2ee8SDavid du Colombier 			}
70580ee5cbfSDavid du Colombier 		}
70680ee5cbfSDavid du Colombier 
70780ee5cbfSDavid du Colombier 		/* give back a single reply (or part of one) */
7087dd7cddfSDavid du Colombier 		job->reply.data = mf->reply[i] + (off - toff);
709219b2ee8SDavid du Colombier 		if(cnt > toff - off + n)
710219b2ee8SDavid du Colombier 			n = toff - off + n;
711219b2ee8SDavid du Colombier 		else
712219b2ee8SDavid du Colombier 			n = cnt;
7133e12c5d1SDavid du Colombier 	}
7143e12c5d1SDavid du Colombier send:
7157dd7cddfSDavid du Colombier 	job->reply.count = n;
7167dd7cddfSDavid du Colombier 	sendmsg(job, err);
7177dd7cddfSDavid du Colombier }
71880ee5cbfSDavid du Colombier void
cleanmf(Mfile * mf)71980ee5cbfSDavid du Colombier cleanmf(Mfile *mf)
7207dd7cddfSDavid du Colombier {
7217dd7cddfSDavid du Colombier 	int i;
7227dd7cddfSDavid du Colombier 
7239a747e4fSDavid du Colombier 	if(mf->net != nil){
72480ee5cbfSDavid du Colombier 		free(mf->net);
72580ee5cbfSDavid du Colombier 		mf->net = nil;
7269a747e4fSDavid du Colombier 	}
7279a747e4fSDavid du Colombier 	if(mf->host != nil){
72880ee5cbfSDavid du Colombier 		free(mf->host);
72980ee5cbfSDavid du Colombier 		mf->host = nil;
7309a747e4fSDavid du Colombier 	}
7319a747e4fSDavid du Colombier 	if(mf->serv != nil){
73280ee5cbfSDavid du Colombier 		free(mf->serv);
73380ee5cbfSDavid du Colombier 		mf->serv = nil;
7349a747e4fSDavid du Colombier 	}
7359a747e4fSDavid du Colombier 	if(mf->rem != nil){
73680ee5cbfSDavid du Colombier 		free(mf->rem);
73780ee5cbfSDavid du Colombier 		mf->rem = nil;
7389a747e4fSDavid du Colombier 	}
73980ee5cbfSDavid du Colombier 	for(i = 0; i < mf->nreply; i++){
74080ee5cbfSDavid du Colombier 		free(mf->reply[i]);
74180ee5cbfSDavid du Colombier 		mf->reply[i] = nil;
74280ee5cbfSDavid du Colombier 		mf->replylen[i] = 0;
7437dd7cddfSDavid du Colombier 	}
74480ee5cbfSDavid du Colombier 	mf->nreply = 0;
74580ee5cbfSDavid du Colombier 	mf->nextnet = netlist;
7463e12c5d1SDavid du Colombier }
7473e12c5d1SDavid du Colombier 
7483e12c5d1SDavid du Colombier void
rwrite(Job * job,Mfile * mf)7497dd7cddfSDavid du Colombier rwrite(Job *job, Mfile *mf)
7503e12c5d1SDavid du Colombier {
7513e12c5d1SDavid du Colombier 	int cnt, n;
75280ee5cbfSDavid du Colombier 	char *err;
7537dd7cddfSDavid du Colombier 	char *field[4];
754271b8d73SDavid du Colombier 	char curerr[64];
7553e12c5d1SDavid du Colombier 
7563e12c5d1SDavid du Colombier 	err = 0;
7577dd7cddfSDavid du Colombier 	cnt = job->request.count;
7589a747e4fSDavid du Colombier 	if(mf->qid.type & QTDIR){
7593e12c5d1SDavid du Colombier 		err = "can't write directory";
7603e12c5d1SDavid du Colombier 		goto send;
7613e12c5d1SDavid du Colombier 	}
7623e12c5d1SDavid du Colombier 	if(cnt >= Maxrequest){
7633e12c5d1SDavid du Colombier 		err = "request too long";
7643e12c5d1SDavid du Colombier 		goto send;
7653e12c5d1SDavid du Colombier 	}
7667dd7cddfSDavid du Colombier 	job->request.data[cnt] = 0;
7673e12c5d1SDavid du Colombier 
7683e12c5d1SDavid du Colombier 	/*
769219b2ee8SDavid du Colombier 	 *  toggle debugging
770219b2ee8SDavid du Colombier 	 */
7717dd7cddfSDavid du Colombier 	if(strncmp(job->request.data, "debug", 5)==0){
772219b2ee8SDavid du Colombier 		debug ^= 1;
773219b2ee8SDavid du Colombier 		syslog(1, logfile, "debug %d", debug);
774219b2ee8SDavid du Colombier 		goto send;
775219b2ee8SDavid du Colombier 	}
776219b2ee8SDavid du Colombier 
777219b2ee8SDavid du Colombier 	/*
778b8b25780SDavid du Colombier 	 *  toggle ipv6 lookups
779b8b25780SDavid du Colombier 	 */
780b8b25780SDavid du Colombier 	if(strncmp(job->request.data, "ipv6", 4)==0){
781b8b25780SDavid du Colombier 		ipv6lookups ^= 1;
782b8b25780SDavid du Colombier 		syslog(1, logfile, "ipv6lookups %d", ipv6lookups);
783b8b25780SDavid du Colombier 		goto send;
784b8b25780SDavid du Colombier 	}
785b8b25780SDavid du Colombier 
786b8b25780SDavid du Colombier 	/*
7877dd7cddfSDavid du Colombier 	 *  toggle debugging
7887dd7cddfSDavid du Colombier 	 */
7897dd7cddfSDavid du Colombier 	if(strncmp(job->request.data, "paranoia", 8)==0){
7907dd7cddfSDavid du Colombier 		paranoia ^= 1;
7917dd7cddfSDavid du Colombier 		syslog(1, logfile, "paranoia %d", paranoia);
7927dd7cddfSDavid du Colombier 		goto send;
7937dd7cddfSDavid du Colombier 	}
7947dd7cddfSDavid du Colombier 
7957dd7cddfSDavid du Colombier 	/*
7963e12c5d1SDavid du Colombier 	 *  add networks to the default list
7973e12c5d1SDavid du Colombier 	 */
7987dd7cddfSDavid du Colombier 	if(strncmp(job->request.data, "add ", 4)==0){
7997dd7cddfSDavid du Colombier 		if(job->request.data[cnt-1] == '\n')
8007dd7cddfSDavid du Colombier 			job->request.data[cnt-1] = 0;
8017dd7cddfSDavid du Colombier 		netadd(job->request.data+4);
8027dd7cddfSDavid du Colombier 		readipinterfaces();
8037dd7cddfSDavid du Colombier 		goto send;
8047dd7cddfSDavid du Colombier 	}
8057dd7cddfSDavid du Colombier 
8067dd7cddfSDavid du Colombier 	/*
8077dd7cddfSDavid du Colombier 	 *  refresh all state
8087dd7cddfSDavid du Colombier 	 */
8097dd7cddfSDavid du Colombier 	if(strncmp(job->request.data, "refresh", 7)==0){
8107dd7cddfSDavid du Colombier 		netinit(1);
8113e12c5d1SDavid du Colombier 		goto send;
8123e12c5d1SDavid du Colombier 	}
8133e12c5d1SDavid du Colombier 
81480ee5cbfSDavid du Colombier 	/* start transaction with a clean slate */
81580ee5cbfSDavid du Colombier 	cleanmf(mf);
81680ee5cbfSDavid du Colombier 
8173e12c5d1SDavid du Colombier 	/*
818219b2ee8SDavid du Colombier 	 *  look for a general query
819219b2ee8SDavid du Colombier 	 */
8207dd7cddfSDavid du Colombier 	if(*job->request.data == '!'){
8217dd7cddfSDavid du Colombier 		err = genquery(mf, job->request.data+1);
822219b2ee8SDavid du Colombier 		goto send;
823219b2ee8SDavid du Colombier 	}
824219b2ee8SDavid du Colombier 
8257dd7cddfSDavid du Colombier 	if(debug)
8267dd7cddfSDavid du Colombier 		syslog(0, logfile, "write %s", job->request.data);
8277dd7cddfSDavid du Colombier 	if(paranoia)
8287dd7cddfSDavid du Colombier 		syslog(0, paranoiafile, "write %s by %s", job->request.data, mf->user);
8297dd7cddfSDavid du Colombier 
830219b2ee8SDavid du Colombier 	/*
8313e12c5d1SDavid du Colombier 	 *  break up name
8323e12c5d1SDavid du Colombier 	 */
8337dd7cddfSDavid du Colombier 	n = getfields(job->request.data, field, 4, 1, "!");
8343e12c5d1SDavid du Colombier 	switch(n){
8353e12c5d1SDavid du Colombier 	case 1:
83680ee5cbfSDavid du Colombier 		mf->net = strdup("net");
83780ee5cbfSDavid du Colombier 		mf->host = strdup(field[0]);
8387dd7cddfSDavid du Colombier 		break;
8397dd7cddfSDavid du Colombier 	case 4:
84080ee5cbfSDavid du Colombier 		mf->rem = strdup(field[3]);
84180ee5cbfSDavid du Colombier 		/* fall through */
84280ee5cbfSDavid du Colombier 	case 3:
84380ee5cbfSDavid du Colombier 		mf->serv = strdup(field[2]);
84480ee5cbfSDavid du Colombier 		/* fall through */
84580ee5cbfSDavid du Colombier 	case 2:
84680ee5cbfSDavid du Colombier 		mf->host = strdup(field[1]);
84780ee5cbfSDavid du Colombier 		mf->net = strdup(field[0]);
8483e12c5d1SDavid du Colombier 		break;
8493e12c5d1SDavid du Colombier 	}
8503e12c5d1SDavid du Colombier 
85180ee5cbfSDavid du Colombier 	/*
85280ee5cbfSDavid du Colombier 	 *  do the first net worth of lookup
85380ee5cbfSDavid du Colombier 	 */
854271b8d73SDavid du Colombier 	if(lookup(mf) == 0){
855271b8d73SDavid du Colombier 		rerrstr(curerr, sizeof curerr);
856271b8d73SDavid du Colombier 		err = curerr;
857271b8d73SDavid du Colombier 	}
8583e12c5d1SDavid du Colombier send:
8597dd7cddfSDavid du Colombier 	job->reply.count = cnt;
8607dd7cddfSDavid du Colombier 	sendmsg(job, err);
8613e12c5d1SDavid du Colombier }
8623e12c5d1SDavid du Colombier 
8633e12c5d1SDavid du Colombier void
rclunk(Job * job,Mfile * mf)8647dd7cddfSDavid du Colombier rclunk(Job *job, Mfile *mf)
8653e12c5d1SDavid du Colombier {
86680ee5cbfSDavid du Colombier 	cleanmf(mf);
867a9f680aeSDavid du Colombier 	free(mf->user);
868a9f680aeSDavid du Colombier 	mf->user = 0;
8693e12c5d1SDavid du Colombier 	mf->busy = 0;
8703e12c5d1SDavid du Colombier 	mf->fid = 0;
8717dd7cddfSDavid du Colombier 	sendmsg(job, 0);
8723e12c5d1SDavid du Colombier }
8733e12c5d1SDavid du Colombier 
8743e12c5d1SDavid du Colombier void
rremove(Job * job,Mfile * mf)8757dd7cddfSDavid du Colombier rremove(Job *job, Mfile *mf)
8763e12c5d1SDavid du Colombier {
8773e12c5d1SDavid du Colombier 	USED(mf);
8787dd7cddfSDavid du Colombier 	sendmsg(job, "remove permission denied");
8793e12c5d1SDavid du Colombier }
8803e12c5d1SDavid du Colombier 
8813e12c5d1SDavid du Colombier void
rstat(Job * job,Mfile * mf)8827dd7cddfSDavid du Colombier rstat(Job *job, Mfile *mf)
8833e12c5d1SDavid du Colombier {
8843e12c5d1SDavid du Colombier 	Dir dir;
8859a747e4fSDavid du Colombier 	uchar buf[IOHDRSZ+Maxfdata];
8863e12c5d1SDavid du Colombier 
8876aaebd7dSDavid du Colombier 	memset(&dir, 0, sizeof dir);
8889a747e4fSDavid du Colombier 	if(mf->qid.type & QTDIR){
8899a747e4fSDavid du Colombier 		dir.name = ".";
8909a747e4fSDavid du Colombier 		dir.mode = DMDIR|0555;
891219b2ee8SDavid du Colombier 	} else {
8929a747e4fSDavid du Colombier 		dir.name = "cs";
8933e12c5d1SDavid du Colombier 		dir.mode = 0666;
894219b2ee8SDavid du Colombier 	}
895219b2ee8SDavid du Colombier 	dir.qid = mf->qid;
8963e12c5d1SDavid du Colombier 	dir.length = 0;
8979a747e4fSDavid du Colombier 	dir.uid = mf->user;
8989a747e4fSDavid du Colombier 	dir.gid = mf->user;
8999a747e4fSDavid du Colombier 	dir.muid = mf->user;
9003e12c5d1SDavid du Colombier 	dir.atime = dir.mtime = time(0);
9019a747e4fSDavid du Colombier 	job->reply.nstat = convD2M(&dir, buf, sizeof buf);
9029a747e4fSDavid du Colombier 	job->reply.stat = buf;
9037dd7cddfSDavid du Colombier 	sendmsg(job, 0);
9043e12c5d1SDavid du Colombier }
9053e12c5d1SDavid du Colombier 
9063e12c5d1SDavid du Colombier void
rwstat(Job * job,Mfile * mf)9077dd7cddfSDavid du Colombier rwstat(Job *job, Mfile *mf)
9083e12c5d1SDavid du Colombier {
9093e12c5d1SDavid du Colombier 	USED(mf);
9107dd7cddfSDavid du Colombier 	sendmsg(job, "wstat permission denied");
9113e12c5d1SDavid du Colombier }
9123e12c5d1SDavid du Colombier 
9133e12c5d1SDavid du Colombier void
sendmsg(Job * job,char * err)9147dd7cddfSDavid du Colombier sendmsg(Job *job, char *err)
9153e12c5d1SDavid du Colombier {
9163e12c5d1SDavid du Colombier 	int n;
9179a747e4fSDavid du Colombier 	uchar mdata[IOHDRSZ + Maxfdata];
9189a747e4fSDavid du Colombier 	char ename[ERRMAX];
9193e12c5d1SDavid du Colombier 
9203e12c5d1SDavid du Colombier 	if(err){
9217dd7cddfSDavid du Colombier 		job->reply.type = Rerror;
9229a747e4fSDavid du Colombier 		snprint(ename, sizeof(ename), "cs: %s", err);
9239a747e4fSDavid du Colombier 		job->reply.ename = ename;
9243e12c5d1SDavid du Colombier 	}else{
9257dd7cddfSDavid du Colombier 		job->reply.type = job->request.type+1;
9263e12c5d1SDavid du Colombier 	}
9277dd7cddfSDavid du Colombier 	job->reply.tag = job->request.tag;
9289a747e4fSDavid du Colombier 	n = convS2M(&job->reply, mdata, sizeof mdata);
929219b2ee8SDavid du Colombier 	if(n == 0){
9307dd7cddfSDavid du Colombier 		syslog(1, logfile, "sendmsg convS2M of %F returns 0", &job->reply);
931219b2ee8SDavid du Colombier 		abort();
932219b2ee8SDavid du Colombier 	}
9337dd7cddfSDavid du Colombier 	lock(&joblock);
9347dd7cddfSDavid du Colombier 	if(job->flushed == 0)
9359a747e4fSDavid du Colombier 		if(write(mfd[1], mdata, n)!=n)
9363e12c5d1SDavid du Colombier 			error("mount write");
9377dd7cddfSDavid du Colombier 	unlock(&joblock);
938219b2ee8SDavid du Colombier 	if(debug)
9397dd7cddfSDavid du Colombier 		syslog(0, logfile, "%F %d", &job->reply, n);
9403e12c5d1SDavid du Colombier }
9413e12c5d1SDavid du Colombier 
9423e12c5d1SDavid du Colombier void
error(char * s)9433e12c5d1SDavid du Colombier error(char *s)
9443e12c5d1SDavid du Colombier {
945bd389b36SDavid du Colombier 	syslog(1, "cs", "%s: %r", s);
946bd389b36SDavid du Colombier 	_exits(0);
9473e12c5d1SDavid du Colombier }
9483e12c5d1SDavid du Colombier 
9497dd7cddfSDavid du Colombier static int
isvalidip(uchar * ip)9507dd7cddfSDavid du Colombier isvalidip(uchar *ip)
9517dd7cddfSDavid du Colombier {
9527dd7cddfSDavid du Colombier 	return ipcmp(ip, IPnoaddr) != 0 && ipcmp(ip, v4prefix) != 0;
9537dd7cddfSDavid du Colombier }
9543e12c5d1SDavid du Colombier 
9550103620dSDavid du Colombier static uchar loopbacknet[IPaddrlen] = {
9560103620dSDavid du Colombier 	0, 0, 0, 0,
9570103620dSDavid du Colombier 	0, 0, 0, 0,
9580103620dSDavid du Colombier 	0, 0, 0xff, 0xff,
9590103620dSDavid du Colombier 	127, 0, 0, 0
9600103620dSDavid du Colombier };
9610103620dSDavid du Colombier static uchar loopbackmask[IPaddrlen] = {
9620103620dSDavid du Colombier 	0xff, 0xff, 0xff, 0xff,
9630103620dSDavid du Colombier 	0xff, 0xff, 0xff, 0xff,
9640103620dSDavid du Colombier 	0xff, 0xff, 0xff, 0xff,
9650103620dSDavid du Colombier 	0xff, 0, 0, 0
9660103620dSDavid du Colombier };
9670103620dSDavid du Colombier 
9687dd7cddfSDavid du Colombier void
readipinterfaces(void)9697dd7cddfSDavid du Colombier readipinterfaces(void)
9707dd7cddfSDavid du Colombier {
9710103620dSDavid du Colombier 	if(myipaddr(ipa, mntpt) != 0)
9720103620dSDavid du Colombier 		ipmove(ipa, IPnoaddr);
9737dd7cddfSDavid du Colombier 	sprint(ipaddr, "%I", ipa);
9747dd7cddfSDavid du Colombier 	if (debug)
9757dd7cddfSDavid du Colombier 		syslog(0, "dns", "ipaddr is %s\n", ipaddr);
9767dd7cddfSDavid du Colombier }
9773e12c5d1SDavid du Colombier 
9783e12c5d1SDavid du Colombier /*
9797dd7cddfSDavid du Colombier  *  get the system name
9803e12c5d1SDavid du Colombier  */
9813e12c5d1SDavid du Colombier void
ipid(void)9823e12c5d1SDavid du Colombier ipid(void)
9833e12c5d1SDavid du Colombier {
9843e12c5d1SDavid du Colombier 	uchar addr[6];
985a9f680aeSDavid du Colombier 	Ndbtuple *t, *tt;
986219b2ee8SDavid du Colombier 	char *p, *attr;
9873e12c5d1SDavid du Colombier 	Ndbs s;
9883e12c5d1SDavid du Colombier 	int f;
9897dd7cddfSDavid du Colombier 	char buf[Maxpath];
9903e12c5d1SDavid du Colombier 
991219b2ee8SDavid du Colombier 	/* use environment, ether addr, or ipaddr to get system name */
99295a264b3SDavid du Colombier 	if(mysysname == 0){
9937dd7cddfSDavid du Colombier 		/*
9947dd7cddfSDavid du Colombier 		 *  environment has priority.
9957dd7cddfSDavid du Colombier 		 *
9967dd7cddfSDavid du Colombier 		 *  on the sgi power the default system name
9977dd7cddfSDavid du Colombier 		 *  is the ip address.  ignore that.
9987dd7cddfSDavid du Colombier 		 *
9997dd7cddfSDavid du Colombier 		 */
1000219b2ee8SDavid du Colombier 		p = getenv("sysname");
1001447d6a7dSDavid du Colombier 		if(p && *p){
1002219b2ee8SDavid du Colombier 			attr = ipattr(p);
1003219b2ee8SDavid du Colombier 			if(strcmp(attr, "ip") != 0)
100495a264b3SDavid du Colombier 				mysysname = strdup(p);
10053e12c5d1SDavid du Colombier 		}
10063e12c5d1SDavid du Colombier 
10073e12c5d1SDavid du Colombier 		/*
10087dd7cddfSDavid du Colombier 		 *  the /net/ndb contains what the network
10097dd7cddfSDavid du Colombier 		 *  figured out from DHCP.  use that name if
10107dd7cddfSDavid du Colombier 		 *  there is one.
10113e12c5d1SDavid du Colombier 		 */
101295a264b3SDavid du Colombier 		if(mysysname == 0 && netdb != nil){
10137dd7cddfSDavid du Colombier 			ndbreopen(netdb);
1014a9f680aeSDavid du Colombier 			for(tt = t = ndbparse(netdb); t != nil; t = t->entry){
10157dd7cddfSDavid du Colombier 				if(strcmp(t->attr, "sys") == 0){
101695a264b3SDavid du Colombier 					mysysname = strdup(t->val);
10173e12c5d1SDavid du Colombier 					break;
10183e12c5d1SDavid du Colombier 				}
10197dd7cddfSDavid du Colombier 			}
1020a9f680aeSDavid du Colombier 			ndbfree(tt);
10217dd7cddfSDavid du Colombier 		}
10227dd7cddfSDavid du Colombier 
10237dd7cddfSDavid du Colombier 		/* next network database, ip address, and ether address to find a name */
102495a264b3SDavid du Colombier 		if(mysysname == 0){
10257dd7cddfSDavid du Colombier 			t = nil;
10267dd7cddfSDavid du Colombier 			if(isvalidip(ipa))
102757837e0bSDavid du Colombier 				free(ndbgetvalue(db, &s, "ip", ipaddr, "sys", &t));
102895a264b3SDavid du Colombier 			if(t == nil){
10297dd7cddfSDavid du Colombier 				for(f = 0; f < 3; f++){
10307dd7cddfSDavid du Colombier 					snprint(buf, sizeof buf, "%s/ether%d", mntpt, f);
10317dd7cddfSDavid du Colombier 					if(myetheraddr(addr, buf) >= 0){
10327dd7cddfSDavid du Colombier 						snprint(eaddr, sizeof(eaddr), "%E", addr);
103357837e0bSDavid du Colombier 						free(ndbgetvalue(db, &s, "ether", eaddr, "sys", &t));
10347dd7cddfSDavid du Colombier 						if(t != nil)
10357dd7cddfSDavid du Colombier 							break;
10367dd7cddfSDavid du Colombier 					}
10377dd7cddfSDavid du Colombier 				}
10387dd7cddfSDavid du Colombier 			}
1039b7327ca2SDavid du Colombier 			for(tt = t; tt != nil; tt = tt->entry){
1040b7327ca2SDavid du Colombier 				if(strcmp(tt->attr, "sys") == 0){
1041b7327ca2SDavid du Colombier 					mysysname = strdup(tt->val);
104295a264b3SDavid du Colombier 					break;
104395a264b3SDavid du Colombier 				}
1044b7327ca2SDavid du Colombier 			}
10457dd7cddfSDavid du Colombier 			ndbfree(t);
10467dd7cddfSDavid du Colombier 		}
10477dd7cddfSDavid du Colombier 
104880ee5cbfSDavid du Colombier 		/* nothing else worked, use the ip address */
104995a264b3SDavid du Colombier 		if(mysysname == 0 && isvalidip(ipa))
105095a264b3SDavid du Colombier 			mysysname = strdup(ipaddr);
105180ee5cbfSDavid du Colombier 
105280ee5cbfSDavid du Colombier 
1053dc5a79c1SDavid du Colombier 		/* set /dev/sysname if we now know it */
105495a264b3SDavid du Colombier 		if(mysysname){
10557dd7cddfSDavid du Colombier 			f = open("/dev/sysname", OWRITE);
10567dd7cddfSDavid du Colombier 			if(f >= 0){
10577dd7cddfSDavid du Colombier 				write(f, mysysname, strlen(mysysname));
10583e12c5d1SDavid du Colombier 				close(f);
10593e12c5d1SDavid du Colombier 			}
10603e12c5d1SDavid du Colombier 		}
10613e12c5d1SDavid du Colombier 	}
10623e12c5d1SDavid du Colombier }
10633e12c5d1SDavid du Colombier 
10643e12c5d1SDavid du Colombier /*
10653e12c5d1SDavid du Colombier  *  Set up a list of default networks by looking for
1066254fe3d3SDavid du Colombier  *  /net/^*^/clone.
10673e12c5d1SDavid du Colombier  */
10683e12c5d1SDavid du Colombier void
netinit(int background)10697dd7cddfSDavid du Colombier netinit(int background)
10703e12c5d1SDavid du Colombier {
10717dd7cddfSDavid du Colombier 	char clone[Maxpath];
10723e12c5d1SDavid du Colombier 	Network *np;
10737dd7cddfSDavid du Colombier 	static int working;
10747dd7cddfSDavid du Colombier 
10757dd7cddfSDavid du Colombier 	if(background){
10767dd7cddfSDavid du Colombier 		switch(rfork(RFPROC|RFNOTEG|RFMEM|RFNOWAIT)){
10777dd7cddfSDavid du Colombier 		case 0:
10787dd7cddfSDavid du Colombier 			break;
10797dd7cddfSDavid du Colombier 		default:
10807dd7cddfSDavid du Colombier 			return;
10817dd7cddfSDavid du Colombier 		}
10827dd7cddfSDavid du Colombier 		lock(&netlock);
10837dd7cddfSDavid du Colombier 	}
10843e12c5d1SDavid du Colombier 
10853e12c5d1SDavid du Colombier 	/* add the mounted networks to the default list */
10863e12c5d1SDavid du Colombier 	for(np = network; np->net; np++){
10877dd7cddfSDavid du Colombier 		if(np->considered)
10887dd7cddfSDavid du Colombier 			continue;
10897dd7cddfSDavid du Colombier 		snprint(clone, sizeof(clone), "%s/%s/clone", mntpt, np->net);
10909a747e4fSDavid du Colombier 		if(access(clone, AEXIST) < 0)
10913e12c5d1SDavid du Colombier 			continue;
10923e12c5d1SDavid du Colombier 		if(netlist)
10933e12c5d1SDavid du Colombier 			last->next = np;
10943e12c5d1SDavid du Colombier 		else
10953e12c5d1SDavid du Colombier 			netlist = np;
10963e12c5d1SDavid du Colombier 		last = np;
10973e12c5d1SDavid du Colombier 		np->next = 0;
10987dd7cddfSDavid du Colombier 		np->considered = 1;
10993e12c5d1SDavid du Colombier 	}
11003e12c5d1SDavid du Colombier 
11017dd7cddfSDavid du Colombier 	/* find out what our ip address is */
11027dd7cddfSDavid du Colombier 	readipinterfaces();
11033e12c5d1SDavid du Colombier 
110432411399SDavid du Colombier 	/* set the system name if we need to, these days ip is all we have */
11053e12c5d1SDavid du Colombier 	ipid();
11063e12c5d1SDavid du Colombier 
1107219b2ee8SDavid du Colombier 	if(debug)
11087dd7cddfSDavid du Colombier 		syslog(0, logfile, "mysysname %s eaddr %s ipaddr %s ipa %I\n",
110995a264b3SDavid du Colombier 			mysysname?mysysname:"???", eaddr, ipaddr, ipa);
11107dd7cddfSDavid du Colombier 
11117dd7cddfSDavid du Colombier 	if(background){
11127dd7cddfSDavid du Colombier 		unlock(&netlock);
11137dd7cddfSDavid du Colombier 		_exits(0);
11147dd7cddfSDavid du Colombier 	}
11153e12c5d1SDavid du Colombier }
11163e12c5d1SDavid du Colombier 
11173e12c5d1SDavid du Colombier /*
11183e12c5d1SDavid du Colombier  *  add networks to the standard list
11193e12c5d1SDavid du Colombier  */
11203e12c5d1SDavid du Colombier void
netadd(char * p)11213e12c5d1SDavid du Colombier netadd(char *p)
11223e12c5d1SDavid du Colombier {
11233e12c5d1SDavid du Colombier 	Network *np;
11243e12c5d1SDavid du Colombier 	char *field[12];
11253e12c5d1SDavid du Colombier 	int i, n;
11263e12c5d1SDavid du Colombier 
11277dd7cddfSDavid du Colombier 	n = getfields(p, field, 12, 1, " ");
11283e12c5d1SDavid du Colombier 	for(i = 0; i < n; i++){
11293e12c5d1SDavid du Colombier 		for(np = network; np->net; np++){
11303e12c5d1SDavid du Colombier 			if(strcmp(field[i], np->net) != 0)
11313e12c5d1SDavid du Colombier 				continue;
11327dd7cddfSDavid du Colombier 			if(np->considered)
11333e12c5d1SDavid du Colombier 				break;
11343e12c5d1SDavid du Colombier 			if(netlist)
11353e12c5d1SDavid du Colombier 				last->next = np;
11363e12c5d1SDavid du Colombier 			else
11373e12c5d1SDavid du Colombier 				netlist = np;
11383e12c5d1SDavid du Colombier 			last = np;
11393e12c5d1SDavid du Colombier 			np->next = 0;
11407dd7cddfSDavid du Colombier 			np->considered = 1;
11413e12c5d1SDavid du Colombier 		}
11423e12c5d1SDavid du Colombier 	}
11433e12c5d1SDavid du Colombier }
11443e12c5d1SDavid du Colombier 
114580ee5cbfSDavid du Colombier int
lookforproto(Ndbtuple * t,char * proto)114680ee5cbfSDavid du Colombier lookforproto(Ndbtuple *t, char *proto)
114780ee5cbfSDavid du Colombier {
114880ee5cbfSDavid du Colombier 	for(; t != nil; t = t->entry)
114980ee5cbfSDavid du Colombier 		if(strcmp(t->attr, "proto") == 0 && strcmp(t->val, proto) == 0)
115080ee5cbfSDavid du Colombier 			return 1;
115180ee5cbfSDavid du Colombier 	return 0;
115280ee5cbfSDavid du Colombier }
115380ee5cbfSDavid du Colombier 
1154219b2ee8SDavid du Colombier /*
11553e12c5d1SDavid du Colombier  *  lookup a request.  the network "net" means we should pick the
11563e12c5d1SDavid du Colombier  *  best network to get there.
11573e12c5d1SDavid du Colombier  */
11583e12c5d1SDavid du Colombier int
lookup(Mfile * mf)115980ee5cbfSDavid du Colombier lookup(Mfile *mf)
11603e12c5d1SDavid du Colombier {
116180ee5cbfSDavid du Colombier 	Network *np;
1162219b2ee8SDavid du Colombier 	char *cp;
1163219b2ee8SDavid du Colombier 	Ndbtuple *nt, *t;
1164219b2ee8SDavid du Colombier 	char reply[Maxreply];
116580ee5cbfSDavid du Colombier 	int i, rv;
116680ee5cbfSDavid du Colombier 	int hack;
11673e12c5d1SDavid du Colombier 
11683e12c5d1SDavid du Colombier 	/* open up the standard db files */
11693e12c5d1SDavid du Colombier 	if(db == 0)
11707dd7cddfSDavid du Colombier 		ndbinit();
11713e12c5d1SDavid du Colombier 	if(db == 0)
117280ee5cbfSDavid du Colombier 		error("can't open mf->network database\n");
11733e12c5d1SDavid du Colombier 
117480ee5cbfSDavid du Colombier 	rv = 0;
117580ee5cbfSDavid du Colombier 
117680ee5cbfSDavid du Colombier 	if(mf->net == nil)
117780ee5cbfSDavid du Colombier 		return 0;	/* must have been a genquery */
117880ee5cbfSDavid du Colombier 
117980ee5cbfSDavid du Colombier 	if(strcmp(mf->net, "net") == 0){
11803e12c5d1SDavid du Colombier 		/*
11813e12c5d1SDavid du Colombier 		 *  go through set of default nets
11823e12c5d1SDavid du Colombier 		 */
118380ee5cbfSDavid du Colombier 		for(np = mf->nextnet; np; np = np->next){
118480ee5cbfSDavid du Colombier 			nt = (*np->lookup)(np, mf->host, mf->serv, 1);
118580ee5cbfSDavid du Colombier 			if(nt == nil)
1186219b2ee8SDavid du Colombier 				continue;
118780ee5cbfSDavid du Colombier 			hack = np->fasttimeouthack && !lookforproto(nt, np->net);
118880ee5cbfSDavid du Colombier 			for(t = nt; mf->nreply < Nreply && t; t = t->entry){
118980ee5cbfSDavid du Colombier 				cp = (*np->trans)(t, np, mf->serv, mf->rem, hack);
1190219b2ee8SDavid du Colombier 				if(cp){
119180ee5cbfSDavid du Colombier 					/* avoid duplicates */
119280ee5cbfSDavid du Colombier 					for(i = 0; i < mf->nreply; i++)
119380ee5cbfSDavid du Colombier 						if(strcmp(mf->reply[i], cp) == 0)
119480ee5cbfSDavid du Colombier 							break;
119580ee5cbfSDavid du Colombier 					if(i == mf->nreply){
119680ee5cbfSDavid du Colombier 						/* save the reply */
1197219b2ee8SDavid du Colombier 						mf->replylen[mf->nreply] = strlen(cp);
1198219b2ee8SDavid du Colombier 						mf->reply[mf->nreply++] = cp;
119980ee5cbfSDavid du Colombier 						rv++;
1200219b2ee8SDavid du Colombier 					}
1201219b2ee8SDavid du Colombier 				}
1202219b2ee8SDavid du Colombier 			}
1203219b2ee8SDavid du Colombier 			ndbfree(nt);
120480ee5cbfSDavid du Colombier 			np = np->next;
120580ee5cbfSDavid du Colombier 			break;
120680ee5cbfSDavid du Colombier 		}
120780ee5cbfSDavid du Colombier 		mf->nextnet = np;
120880ee5cbfSDavid du Colombier 		return rv;
120980ee5cbfSDavid du Colombier 	}
121080ee5cbfSDavid du Colombier 
121180ee5cbfSDavid du Colombier 	/*
121280ee5cbfSDavid du Colombier 	 *  if not /net, we only get one lookup
121380ee5cbfSDavid du Colombier 	 */
121480ee5cbfSDavid du Colombier 	if(mf->nreply != 0)
1215219b2ee8SDavid du Colombier 		return 0;
121680ee5cbfSDavid du Colombier 	/*
121780ee5cbfSDavid du Colombier 	 *  look for a specific network
121880ee5cbfSDavid du Colombier 	 */
121995a264b3SDavid du Colombier 	for(np = netlist; np && np->net != nil; np++){
122080ee5cbfSDavid du Colombier 		if(np->fasttimeouthack)
122180ee5cbfSDavid du Colombier 			continue;
122280ee5cbfSDavid du Colombier 		if(strcmp(np->net, mf->net) == 0)
122380ee5cbfSDavid du Colombier 			break;
122480ee5cbfSDavid du Colombier 	}
122580ee5cbfSDavid du Colombier 
122695a264b3SDavid du Colombier 	if(np && np->net != nil){
122780ee5cbfSDavid du Colombier 		/*
122880ee5cbfSDavid du Colombier 		 *  known network
122980ee5cbfSDavid du Colombier 		 */
123080ee5cbfSDavid du Colombier 		nt = (*np->lookup)(np, mf->host, mf->serv, 1);
123180ee5cbfSDavid du Colombier 		for(t = nt; mf->nreply < Nreply && t; t = t->entry){
123280ee5cbfSDavid du Colombier 			cp = (*np->trans)(t, np, mf->serv, mf->rem, 0);
123380ee5cbfSDavid du Colombier 			if(cp){
123480ee5cbfSDavid du Colombier 				mf->replylen[mf->nreply] = strlen(cp);
123580ee5cbfSDavid du Colombier 				mf->reply[mf->nreply++] = cp;
123680ee5cbfSDavid du Colombier 				rv++;
123780ee5cbfSDavid du Colombier 			}
123880ee5cbfSDavid du Colombier 		}
123980ee5cbfSDavid du Colombier 		ndbfree(nt);
124080ee5cbfSDavid du Colombier 		return rv;
12413e12c5d1SDavid du Colombier 	} else {
12423e12c5d1SDavid du Colombier 		/*
1243219b2ee8SDavid du Colombier 		 *  not a known network, don't translate host or service
12443e12c5d1SDavid du Colombier 		 */
124580ee5cbfSDavid du Colombier 		if(mf->serv)
12467dd7cddfSDavid du Colombier 			snprint(reply, sizeof(reply), "%s/%s/clone %s!%s",
124780ee5cbfSDavid du Colombier 				mntpt, mf->net, mf->host, mf->serv);
1248bd389b36SDavid du Colombier 		else
12497dd7cddfSDavid du Colombier 			snprint(reply, sizeof(reply), "%s/%s/clone %s",
125080ee5cbfSDavid du Colombier 				mntpt, mf->net, mf->host);
1251219b2ee8SDavid du Colombier 		mf->reply[0] = strdup(reply);
1252219b2ee8SDavid du Colombier 		mf->replylen[0] = strlen(reply);
1253219b2ee8SDavid du Colombier 		mf->nreply = 1;
125480ee5cbfSDavid du Colombier 		return 1;
12553e12c5d1SDavid du Colombier 	}
12563e12c5d1SDavid du Colombier }
12573e12c5d1SDavid du Colombier 
12583e12c5d1SDavid du Colombier /*
12593e12c5d1SDavid du Colombier  *  translate an ip service name into a port number.  If it's a numeric port
12603e12c5d1SDavid du Colombier  *  number, look for restricted access.
12613e12c5d1SDavid du Colombier  *
12623e12c5d1SDavid du Colombier  *  the service '*' needs no translation.
12633e12c5d1SDavid du Colombier  */
12643e12c5d1SDavid du Colombier char*
ipserv(Network * np,char * name,char * buf,int blen)126595a264b3SDavid du Colombier ipserv(Network *np, char *name, char *buf, int blen)
12663e12c5d1SDavid du Colombier {
12673e12c5d1SDavid du Colombier 	char *p;
12683e12c5d1SDavid du Colombier 	int alpha = 0;
12693e12c5d1SDavid du Colombier 	int restr = 0;
127095a264b3SDavid du Colombier 	char port[10];
12713e12c5d1SDavid du Colombier 	Ndbtuple *t, *nt;
12723e12c5d1SDavid du Colombier 	Ndbs s;
12733e12c5d1SDavid du Colombier 
12743e12c5d1SDavid du Colombier 	/* '*' means any service */
12753e12c5d1SDavid du Colombier 	if(strcmp(name, "*")==0){
12763e12c5d1SDavid du Colombier 		strcpy(buf, name);
12773e12c5d1SDavid du Colombier 		return buf;
12783e12c5d1SDavid du Colombier 	}
12793e12c5d1SDavid du Colombier 
12803e12c5d1SDavid du Colombier 	/*  see if it's numeric or symbolic */
12813e12c5d1SDavid du Colombier 	port[0] = 0;
12823e12c5d1SDavid du Colombier 	for(p = name; *p; p++){
12833e12c5d1SDavid du Colombier 		if(isdigit(*p))
12849a747e4fSDavid du Colombier 			{}
12853e12c5d1SDavid du Colombier 		else if(isalpha(*p) || *p == '-' || *p == '$')
12863e12c5d1SDavid du Colombier 			alpha = 1;
12873e12c5d1SDavid du Colombier 		else
12883e12c5d1SDavid du Colombier 			return 0;
12893e12c5d1SDavid du Colombier 	}
129057837e0bSDavid du Colombier 	t = nil;
129157837e0bSDavid du Colombier 	p = nil;
12923e12c5d1SDavid du Colombier 	if(alpha){
129357837e0bSDavid du Colombier 		p = ndbgetvalue(db, &s, np->net, name, "port", &t);
1294b7327ca2SDavid du Colombier 		if(p == nil)
1295b7327ca2SDavid du Colombier 			return 0;
12963e12c5d1SDavid du Colombier 	} else {
12973cc1eb97SDavid du Colombier 		/* look up only for tcp ports < 1024 to get the restricted
12983cc1eb97SDavid du Colombier 		 * attribute
12993cc1eb97SDavid du Colombier 		 */
13003cc1eb97SDavid du Colombier 		if(atoi(name) < 1024 && strcmp(np->net, "tcp") == 0)
130157837e0bSDavid du Colombier 			p = ndbgetvalue(db, &s, "port", name, "port", &t);
130257837e0bSDavid du Colombier 		if(p == nil)
130357837e0bSDavid du Colombier 			p = strdup(name);
13043e12c5d1SDavid du Colombier 	}
13053e12c5d1SDavid du Colombier 
13063e12c5d1SDavid du Colombier 	if(t){
13073e12c5d1SDavid du Colombier 		for(nt = t; nt; nt = nt->entry)
13083e12c5d1SDavid du Colombier 			if(strcmp(nt->attr, "restricted") == 0)
13093e12c5d1SDavid du Colombier 				restr = 1;
13103e12c5d1SDavid du Colombier 		ndbfree(t);
13113e12c5d1SDavid du Colombier 	}
131257837e0bSDavid du Colombier 	snprint(buf, blen, "%s%s", p, restr ? "!r" : "");
131357837e0bSDavid du Colombier 	free(p);
131457837e0bSDavid du Colombier 
13153e12c5d1SDavid du Colombier 	return buf;
13163e12c5d1SDavid du Colombier }
13173e12c5d1SDavid du Colombier 
13183e12c5d1SDavid du Colombier /*
13197dd7cddfSDavid du Colombier  *  lookup an ip attribute
13203e12c5d1SDavid du Colombier  */
13217dd7cddfSDavid du Colombier int
ipattrlookup(Ndb * db,char * ipa,char * attr,char * val,int vlen)132295a264b3SDavid du Colombier ipattrlookup(Ndb *db, char *ipa, char *attr, char *val, int vlen)
13233e12c5d1SDavid du Colombier {
13243e12c5d1SDavid du Colombier 
13257dd7cddfSDavid du Colombier 	Ndbtuple *t, *nt;
13267dd7cddfSDavid du Colombier 	char *alist[2];
13273e12c5d1SDavid du Colombier 
13287dd7cddfSDavid du Colombier 	alist[0] = attr;
13297dd7cddfSDavid du Colombier 	t = ndbipinfo(db, "ip", ipa, alist, 1);
13307dd7cddfSDavid du Colombier 	if(t == nil)
13317dd7cddfSDavid du Colombier 		return 0;
13329a747e4fSDavid du Colombier 	for(nt = t; nt != nil; nt = nt->entry){
13337dd7cddfSDavid du Colombier 		if(strcmp(nt->attr, attr) == 0){
133495a264b3SDavid du Colombier 			nstrcpy(val, nt->val, vlen);
13353e12c5d1SDavid du Colombier 			ndbfree(t);
13367dd7cddfSDavid du Colombier 			return 1;
1337219b2ee8SDavid du Colombier 		}
13389a747e4fSDavid du Colombier 	}
13393e12c5d1SDavid du Colombier 
13407dd7cddfSDavid du Colombier 	/* we shouldn't get here */
13413e12c5d1SDavid du Colombier 	ndbfree(t);
13427dd7cddfSDavid du Colombier 	return 0;
13433e12c5d1SDavid du Colombier }
13443e12c5d1SDavid du Colombier 
13453e12c5d1SDavid du Colombier /*
13463e12c5d1SDavid du Colombier  *  lookup (and translate) an ip destination
13473e12c5d1SDavid du Colombier  */
1348219b2ee8SDavid du Colombier Ndbtuple*
iplookup(Network * np,char * host,char * serv,int nolookup)1349219b2ee8SDavid du Colombier iplookup(Network *np, char *host, char *serv, int nolookup)
13503e12c5d1SDavid du Colombier {
13519dfc0cb2SDavid du Colombier 	char *attr, *dnsname;
13527dd7cddfSDavid du Colombier 	Ndbtuple *t, *nt;
13533e12c5d1SDavid du Colombier 	Ndbs s;
135495a264b3SDavid du Colombier 	char ts[Maxservice];
135595a264b3SDavid du Colombier 	char dollar[Maxhost];
13567dd7cddfSDavid du Colombier 	uchar ip[IPaddrlen];
13577dd7cddfSDavid du Colombier 	uchar net[IPaddrlen];
13587dd7cddfSDavid du Colombier 	uchar tnet[IPaddrlen];
13597dd7cddfSDavid du Colombier 	Ipifc *ifc;
13609a747e4fSDavid du Colombier 	Iplifc *lifc;
13613e12c5d1SDavid du Colombier 
1362219b2ee8SDavid du Colombier 	USED(nolookup);
1363219b2ee8SDavid du Colombier 
13643e12c5d1SDavid du Colombier 	/*
13653e12c5d1SDavid du Colombier 	 *  start with the service since it's the most likely to fail
13663e12c5d1SDavid du Colombier 	 *  and costs the least
13673e12c5d1SDavid du Colombier 	 */
13687dd7cddfSDavid du Colombier 	werrstr("can't translate address");
136995a264b3SDavid du Colombier 	if(serv==0 || ipserv(np, serv, ts, sizeof ts) == 0){
1370271b8d73SDavid du Colombier 		werrstr("can't translate service");
1371219b2ee8SDavid du Colombier 		return 0;
13727dd7cddfSDavid du Colombier 	}
13733e12c5d1SDavid du Colombier 
13743e12c5d1SDavid du Colombier 	/* for dial strings with no host */
1375219b2ee8SDavid du Colombier 	if(strcmp(host, "*") == 0)
137695a264b3SDavid du Colombier 		return ndbnew("ip", "*");
13773e12c5d1SDavid du Colombier 
13783e12c5d1SDavid du Colombier 	/*
13797dd7cddfSDavid du Colombier 	 *  hack till we go v6 :: = 0.0.0.0
13807dd7cddfSDavid du Colombier 	 */
13817dd7cddfSDavid du Colombier 	if(strcmp("::", host) == 0)
138295a264b3SDavid du Colombier 		return ndbnew("ip", "*");
13837dd7cddfSDavid du Colombier 
13847dd7cddfSDavid du Colombier 	/*
13853e12c5d1SDavid du Colombier 	 *  '$' means the rest of the name is an attribute that we
13863e12c5d1SDavid du Colombier 	 *  need to search for
13873e12c5d1SDavid du Colombier 	 */
13883e12c5d1SDavid du Colombier 	if(*host == '$'){
138995a264b3SDavid du Colombier 		if(ipattrlookup(db, ipaddr, host+1, dollar, sizeof dollar))
13903e12c5d1SDavid du Colombier 			host = dollar;
13913e12c5d1SDavid du Colombier 	}
13923e12c5d1SDavid du Colombier 
13933e12c5d1SDavid du Colombier 	/*
13947dd7cddfSDavid du Colombier 	 *  turn '[ip address]' into just 'ip address'
13957dd7cddfSDavid du Colombier 	 */
13967dd7cddfSDavid du Colombier 	if(*host == '[' && host[strlen(host)-1] == ']'){
13977dd7cddfSDavid du Colombier 		host++;
13987dd7cddfSDavid du Colombier 		host[strlen(host)-1] = 0;
13997dd7cddfSDavid du Colombier 	}
14007dd7cddfSDavid du Colombier 
14017dd7cddfSDavid du Colombier 	/*
14023e12c5d1SDavid du Colombier 	 *  just accept addresses
14033e12c5d1SDavid du Colombier 	 */
1404219b2ee8SDavid du Colombier 	attr = ipattr(host);
1405219b2ee8SDavid du Colombier 	if(strcmp(attr, "ip") == 0)
140695a264b3SDavid du Colombier 		return ndbnew("ip", host);
14073e12c5d1SDavid du Colombier 
14083e12c5d1SDavid du Colombier 	/*
14093e12c5d1SDavid du Colombier 	 *  give the domain name server the first opportunity to
1410bd389b36SDavid du Colombier 	 *  resolve domain names.  if that fails try the database.
14113e12c5d1SDavid du Colombier 	 */
14123e12c5d1SDavid du Colombier 	t = 0;
1413271b8d73SDavid du Colombier 	werrstr("can't translate address");
14143e12c5d1SDavid du Colombier 	if(strcmp(attr, "dom") == 0)
14157dd7cddfSDavid du Colombier 		t = dnsiplookup(host, &s);
14163e12c5d1SDavid du Colombier 	if(t == 0)
141757837e0bSDavid du Colombier 		free(ndbgetvalue(db, &s, attr, host, "ip", &t));
14189dfc0cb2SDavid du Colombier 	if(t == 0){
14199dfc0cb2SDavid du Colombier 		dnsname = ndbgetvalue(db, &s, attr, host, "dom", nil);
14209dfc0cb2SDavid du Colombier 		if(dnsname){
14219dfc0cb2SDavid du Colombier 			t = dnsiplookup(dnsname, &s);
14229dfc0cb2SDavid du Colombier 			free(dnsname);
14239dfc0cb2SDavid du Colombier 		}
14249dfc0cb2SDavid du Colombier 	}
14253e12c5d1SDavid du Colombier 	if(t == 0)
14267dd7cddfSDavid du Colombier 		t = dnsiplookup(host, &s);
14277dd7cddfSDavid du Colombier 	if(t == 0)
1428219b2ee8SDavid du Colombier 		return 0;
1429bd389b36SDavid du Colombier 
1430bd389b36SDavid du Colombier 	/*
1431bd389b36SDavid du Colombier 	 *  reorder the tuple to have the matched line first and
1432bd389b36SDavid du Colombier 	 *  save that in the request structure.
1433bd389b36SDavid du Colombier 	 */
14347dd7cddfSDavid du Colombier 	t = reorder(t, s.t);
14357dd7cddfSDavid du Colombier 
14367dd7cddfSDavid du Colombier 	/*
14377dd7cddfSDavid du Colombier 	 * reorder according to our interfaces
14387dd7cddfSDavid du Colombier 	 */
14397dd7cddfSDavid du Colombier 	lock(&ipifclock);
14409a747e4fSDavid du Colombier 	for(ifc = ipifcs; ifc != nil; ifc = ifc->next){
14419a747e4fSDavid du Colombier 		for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
14429a747e4fSDavid du Colombier 			maskip(lifc->ip, lifc->mask, net);
14437dd7cddfSDavid du Colombier 			for(nt = t; nt; nt = nt->entry){
14447dd7cddfSDavid du Colombier 				if(strcmp(nt->attr, "ip") != 0)
14457dd7cddfSDavid du Colombier 					continue;
14467dd7cddfSDavid du Colombier 				parseip(ip, nt->val);
14479a747e4fSDavid du Colombier 				maskip(ip, lifc->mask, tnet);
14487dd7cddfSDavid du Colombier 				if(memcmp(net, tnet, IPaddrlen) == 0){
14497dd7cddfSDavid du Colombier 					t = reorder(t, nt);
14507dd7cddfSDavid du Colombier 					unlock(&ipifclock);
14517dd7cddfSDavid du Colombier 					return t;
14527dd7cddfSDavid du Colombier 				}
14537dd7cddfSDavid du Colombier 			}
14547dd7cddfSDavid du Colombier 		}
14559a747e4fSDavid du Colombier 	}
14567dd7cddfSDavid du Colombier 	unlock(&ipifclock);
14577dd7cddfSDavid du Colombier 
14587dd7cddfSDavid du Colombier 	return t;
14593e12c5d1SDavid du Colombier }
14603e12c5d1SDavid du Colombier 
14613e12c5d1SDavid du Colombier /*
14623e12c5d1SDavid du Colombier  *  translate an ip address
14633e12c5d1SDavid du Colombier  */
1464219b2ee8SDavid du Colombier char*
iptrans(Ndbtuple * t,Network * np,char * serv,char * rem,int hack)146580ee5cbfSDavid du Colombier iptrans(Ndbtuple *t, Network *np, char *serv, char *rem, int hack)
14663e12c5d1SDavid du Colombier {
146795a264b3SDavid du Colombier 	char ts[Maxservice];
1468219b2ee8SDavid du Colombier 	char reply[Maxreply];
146995a264b3SDavid du Colombier 	char x[Maxservice];
14703e12c5d1SDavid du Colombier 
1471219b2ee8SDavid du Colombier 	if(strcmp(t->attr, "ip") != 0)
14723e12c5d1SDavid du Colombier 		return 0;
1473219b2ee8SDavid du Colombier 
147495a264b3SDavid du Colombier 	if(serv == 0 || ipserv(np, serv, ts, sizeof ts) == 0){
1475271b8d73SDavid du Colombier 		werrstr("can't translate service");
1476219b2ee8SDavid du Colombier 		return 0;
1477271b8d73SDavid du Colombier 	}
14787dd7cddfSDavid du Colombier 	if(rem != nil)
14797dd7cddfSDavid du Colombier 		snprint(x, sizeof(x), "!%s", rem);
14807dd7cddfSDavid du Colombier 	else
14817dd7cddfSDavid du Colombier 		*x = 0;
148280ee5cbfSDavid du Colombier 
1483219b2ee8SDavid du Colombier 	if(*t->val == '*')
14847dd7cddfSDavid du Colombier 		snprint(reply, sizeof(reply), "%s/%s/clone %s%s",
14857dd7cddfSDavid du Colombier 			mntpt, np->net, ts, x);
1486219b2ee8SDavid du Colombier 	else
148780ee5cbfSDavid du Colombier 		snprint(reply, sizeof(reply), "%s/%s/clone %s!%s%s%s",
148880ee5cbfSDavid du Colombier 			mntpt, np->net, t->val, ts, x, hack? "!fasttimeout": "");
1489219b2ee8SDavid du Colombier 
1490219b2ee8SDavid du Colombier 	return strdup(reply);
14913e12c5d1SDavid du Colombier }
14923e12c5d1SDavid du Colombier 
1493219b2ee8SDavid du Colombier /*
1494219b2ee8SDavid du Colombier  *  lookup a telephone number
1495219b2ee8SDavid du Colombier  */
1496219b2ee8SDavid du Colombier Ndbtuple*
telcolookup(Network * np,char * host,char * serv,int nolookup)1497219b2ee8SDavid du Colombier telcolookup(Network *np, char *host, char *serv, int nolookup)
1498219b2ee8SDavid du Colombier {
1499219b2ee8SDavid du Colombier 	Ndbtuple *t;
1500219b2ee8SDavid du Colombier 	Ndbs s;
1501219b2ee8SDavid du Colombier 
1502219b2ee8SDavid du Colombier 	USED(np, nolookup, serv);
1503219b2ee8SDavid du Colombier 
1504271b8d73SDavid du Colombier 	werrstr("can't translate address");
150557837e0bSDavid du Colombier 	free(ndbgetvalue(db, &s, "sys", host, "telco", &t));
1506219b2ee8SDavid du Colombier 	if(t == 0)
150795a264b3SDavid du Colombier 		return ndbnew("telco", host);
1508219b2ee8SDavid du Colombier 
1509219b2ee8SDavid du Colombier 	return reorder(t, s.t);
1510219b2ee8SDavid du Colombier }
1511219b2ee8SDavid du Colombier 
1512219b2ee8SDavid du Colombier /*
1513219b2ee8SDavid du Colombier  *  translate a telephone address
1514219b2ee8SDavid du Colombier  */
1515219b2ee8SDavid du Colombier char*
telcotrans(Ndbtuple * t,Network * np,char * serv,char * rem,int)151680ee5cbfSDavid du Colombier telcotrans(Ndbtuple *t, Network *np, char *serv, char *rem, int)
1517219b2ee8SDavid du Colombier {
1518219b2ee8SDavid du Colombier 	char reply[Maxreply];
151995a264b3SDavid du Colombier 	char x[Maxservice];
1520219b2ee8SDavid du Colombier 
1521219b2ee8SDavid du Colombier 	if(strcmp(t->attr, "telco") != 0)
1522219b2ee8SDavid du Colombier 		return 0;
1523219b2ee8SDavid du Colombier 
15247dd7cddfSDavid du Colombier 	if(rem != nil)
15257dd7cddfSDavid du Colombier 		snprint(x, sizeof(x), "!%s", rem);
1526219b2ee8SDavid du Colombier 	else
15277dd7cddfSDavid du Colombier 		*x = 0;
15287dd7cddfSDavid du Colombier 	if(serv)
15297dd7cddfSDavid du Colombier 		snprint(reply, sizeof(reply), "%s/%s/clone %s!%s%s", mntpt, np->net,
15307dd7cddfSDavid du Colombier 			t->val, serv, x);
15317dd7cddfSDavid du Colombier 	else
15327dd7cddfSDavid du Colombier 		snprint(reply, sizeof(reply), "%s/%s/clone %s%s", mntpt, np->net,
15337dd7cddfSDavid du Colombier 			t->val, x);
1534219b2ee8SDavid du Colombier 	return strdup(reply);
1535219b2ee8SDavid du Colombier }
15363e12c5d1SDavid du Colombier 
15373e12c5d1SDavid du Colombier /*
15383e12c5d1SDavid du Colombier  *  reorder the tuple to put x's line first in the entry
15393e12c5d1SDavid du Colombier  */
15403e12c5d1SDavid du Colombier Ndbtuple*
reorder(Ndbtuple * t,Ndbtuple * x)15413e12c5d1SDavid du Colombier reorder(Ndbtuple *t, Ndbtuple *x)
15423e12c5d1SDavid du Colombier {
15433e12c5d1SDavid du Colombier 	Ndbtuple *nt;
15443e12c5d1SDavid du Colombier 	Ndbtuple *line;
15453e12c5d1SDavid du Colombier 
1546219b2ee8SDavid du Colombier 	/* find start of this entry's line */
1547219b2ee8SDavid du Colombier 	for(line = x; line->entry == line->line; line = line->line)
15483e12c5d1SDavid du Colombier 		;
1549219b2ee8SDavid du Colombier 	line = line->line;
1550219b2ee8SDavid du Colombier 	if(line == t)
1551219b2ee8SDavid du Colombier 		return t;	/* already the first line */
15523e12c5d1SDavid du Colombier 
1553219b2ee8SDavid du Colombier 	/* remove this line and everything after it from the entry */
1554219b2ee8SDavid du Colombier 	for(nt = t; nt->entry != line; nt = nt->entry)
1555219b2ee8SDavid du Colombier 		;
1556219b2ee8SDavid du Colombier 	nt->entry = 0;
15573e12c5d1SDavid du Colombier 
1558219b2ee8SDavid du Colombier 	/* make that the start of the entry */
1559219b2ee8SDavid du Colombier 	for(nt = line; nt->entry; nt = nt->entry)
1560219b2ee8SDavid du Colombier 		;
15613e12c5d1SDavid du Colombier 	nt->entry = t;
15623e12c5d1SDavid du Colombier 	return line;
15633e12c5d1SDavid du Colombier }
15643e12c5d1SDavid du Colombier 
15653e12c5d1SDavid du Colombier /*
15663e12c5d1SDavid du Colombier  *  create a slave process to handle a request to avoid one request blocking
15677dd7cddfSDavid du Colombier  *  another.  parent returns to job loop.
15683e12c5d1SDavid du Colombier  */
15693e12c5d1SDavid du Colombier void
slave(char * host)1570254fe3d3SDavid du Colombier slave(char *host)
15713e12c5d1SDavid du Colombier {
15723e12c5d1SDavid du Colombier 	if(*isslave)
15733e12c5d1SDavid du Colombier 		return;		/* we're already a slave process */
15743e12c5d1SDavid du Colombier 
15753e12c5d1SDavid du Colombier 	switch(rfork(RFPROC|RFNOTEG|RFMEM|RFNOWAIT)){
15763e12c5d1SDavid du Colombier 	case -1:
15773e12c5d1SDavid du Colombier 		break;
15783e12c5d1SDavid du Colombier 	case 0:
1579219b2ee8SDavid du Colombier 		if(debug)
1580219b2ee8SDavid du Colombier 			syslog(0, logfile, "slave %d", getpid());
1581254fe3d3SDavid du Colombier 		procsetname("%s", host);
15823e12c5d1SDavid du Colombier 		*isslave = 1;
15833e12c5d1SDavid du Colombier 		break;
15843e12c5d1SDavid du Colombier 	default:
15853e12c5d1SDavid du Colombier 		longjmp(masterjmp, 1);
15863e12c5d1SDavid du Colombier 	}
15873e12c5d1SDavid du Colombier 
1588219b2ee8SDavid du Colombier }
1589219b2ee8SDavid du Colombier 
1590b8b25780SDavid du Colombier static Ndbtuple*
dnsip6lookup(char * mntpt,char * buf,Ndbtuple * t)1591b8b25780SDavid du Colombier dnsip6lookup(char *mntpt, char *buf, Ndbtuple *t)
1592b8b25780SDavid du Colombier {
1593b8b25780SDavid du Colombier 	Ndbtuple *t6, *tt;
1594b8b25780SDavid du Colombier 
1595b8b25780SDavid du Colombier 	t6 = dnsquery(mntpt, buf, "ipv6");	/* lookup AAAA dns RRs */
1596b8b25780SDavid du Colombier 	if (t6 == nil)
1597b8b25780SDavid du Colombier 		return t;
1598b8b25780SDavid du Colombier 
1599b8b25780SDavid du Colombier 	/* convert ipv6 attr to ip */
1600b8b25780SDavid du Colombier 	for (tt = t6; tt != nil; tt = tt->entry)
1601b8b25780SDavid du Colombier 		if (strcmp(tt->attr, "ipv6") == 0)
1602b8b25780SDavid du Colombier 			strncpy(tt->attr, "ip", sizeof tt->attr - 1);
1603b8b25780SDavid du Colombier 
1604b8b25780SDavid du Colombier 	if (t == nil)
1605b8b25780SDavid du Colombier 		return t6;
1606b8b25780SDavid du Colombier 
1607b8b25780SDavid du Colombier 	/* append t6 list to t list */
1608b8b25780SDavid du Colombier 	for (tt = t; tt->entry != nil; tt = tt->entry)
1609b8b25780SDavid du Colombier 		;
1610b8b25780SDavid du Colombier 	tt->entry = t6;
1611b8b25780SDavid du Colombier 	return t;
1612b8b25780SDavid du Colombier }
1613b8b25780SDavid du Colombier 
16143e12c5d1SDavid du Colombier /*
16153e12c5d1SDavid du Colombier  *  call the dns process and have it try to translate a name
16163e12c5d1SDavid du Colombier  */
16173e12c5d1SDavid du Colombier Ndbtuple*
dnsiplookup(char * host,Ndbs * s)16187dd7cddfSDavid du Colombier dnsiplookup(char *host, Ndbs *s)
16193e12c5d1SDavid du Colombier {
162095a264b3SDavid du Colombier 	char buf[Maxreply];
16217dd7cddfSDavid du Colombier 	Ndbtuple *t;
16223e12c5d1SDavid du Colombier 
1623bd389b36SDavid du Colombier 	unlock(&dblock);
1624bd389b36SDavid du Colombier 
16253e12c5d1SDavid du Colombier 	/* save the name before starting a slave */
16267dd7cddfSDavid du Colombier 	snprint(buf, sizeof(buf), "%s", host);
16273e12c5d1SDavid du Colombier 
1628254fe3d3SDavid du Colombier 	slave(host);
16293e12c5d1SDavid du Colombier 
16307dd7cddfSDavid du Colombier 	if(strcmp(ipattr(buf), "ip") == 0)
16317dd7cddfSDavid du Colombier 		t = dnsquery(mntpt, buf, "ptr");
1632b8b25780SDavid du Colombier 	else {
16337dd7cddfSDavid du Colombier 		t = dnsquery(mntpt, buf, "ip");
1634b8b25780SDavid du Colombier 		/* special case: query ipv6 (AAAA dns RR) too */
1635b8b25780SDavid du Colombier 		if (ipv6lookups)
1636b8b25780SDavid du Colombier 			t = dnsip6lookup(mntpt, buf, t);
1637b8b25780SDavid du Colombier 	}
16383e12c5d1SDavid du Colombier 	s->t = t;
16397dd7cddfSDavid du Colombier 
1640271b8d73SDavid du Colombier 	if(t == nil){
1641271b8d73SDavid du Colombier 		rerrstr(buf, sizeof buf);
1642271b8d73SDavid du Colombier 		if(strstr(buf, "exist"))
1643271b8d73SDavid du Colombier 			werrstr("can't translate address: %s", buf);
1644271b8d73SDavid du Colombier 		else if(strstr(buf, "dns failure"))
1645271b8d73SDavid du Colombier 			werrstr("temporary problem: %s", buf);
1646271b8d73SDavid du Colombier 	}
1647271b8d73SDavid du Colombier 
1648bd389b36SDavid du Colombier 	lock(&dblock);
16493e12c5d1SDavid du Colombier 	return t;
16503e12c5d1SDavid du Colombier }
1651219b2ee8SDavid du Colombier 
1652219b2ee8SDavid du Colombier int
qmatch(Ndbtuple * t,char ** attr,char ** val,int n)1653219b2ee8SDavid du Colombier qmatch(Ndbtuple *t, char **attr, char **val, int n)
1654219b2ee8SDavid du Colombier {
1655219b2ee8SDavid du Colombier 	int i, found;
1656219b2ee8SDavid du Colombier 	Ndbtuple *nt;
1657219b2ee8SDavid du Colombier 
1658219b2ee8SDavid du Colombier 	for(i = 1; i < n; i++){
1659219b2ee8SDavid du Colombier 		found = 0;
1660219b2ee8SDavid du Colombier 		for(nt = t; nt; nt = nt->entry)
1661219b2ee8SDavid du Colombier 			if(strcmp(attr[i], nt->attr) == 0)
1662219b2ee8SDavid du Colombier 				if(strcmp(val[i], "*") == 0
1663219b2ee8SDavid du Colombier 				|| strcmp(val[i], nt->val) == 0){
1664219b2ee8SDavid du Colombier 					found = 1;
1665219b2ee8SDavid du Colombier 					break;
1666219b2ee8SDavid du Colombier 				}
1667219b2ee8SDavid du Colombier 		if(found == 0)
1668219b2ee8SDavid du Colombier 			break;
1669219b2ee8SDavid du Colombier 	}
1670219b2ee8SDavid du Colombier 	return i == n;
1671219b2ee8SDavid du Colombier }
1672219b2ee8SDavid du Colombier 
1673219b2ee8SDavid du Colombier void
qreply(Mfile * mf,Ndbtuple * t)1674219b2ee8SDavid du Colombier qreply(Mfile *mf, Ndbtuple *t)
1675219b2ee8SDavid du Colombier {
1676219b2ee8SDavid du Colombier 	Ndbtuple *nt;
167795a264b3SDavid du Colombier 	String *s;
1678219b2ee8SDavid du Colombier 
167995a264b3SDavid du Colombier 	s = s_new();
1680219b2ee8SDavid du Colombier 	for(nt = t; mf->nreply < Nreply && nt; nt = nt->entry){
168195a264b3SDavid du Colombier 		s_append(s, nt->attr);
168295a264b3SDavid du Colombier 		s_append(s, "=");
168395a264b3SDavid du Colombier 		s_append(s, nt->val);
168495a264b3SDavid du Colombier 
168595a264b3SDavid du Colombier 		if(nt->line != nt->entry){
168695a264b3SDavid du Colombier 			mf->replylen[mf->nreply] = s_len(s);
168795a264b3SDavid du Colombier 			mf->reply[mf->nreply++] = strdup(s_to_c(s));
168895a264b3SDavid du Colombier 			s_restart(s);
1689219b2ee8SDavid du Colombier 		} else
169095a264b3SDavid du Colombier 			s_append(s, " ");
1691219b2ee8SDavid du Colombier 	}
169295a264b3SDavid du Colombier 	s_free(s);
1693219b2ee8SDavid du Colombier }
1694219b2ee8SDavid du Colombier 
16957dd7cddfSDavid du Colombier enum
16967dd7cddfSDavid du Colombier {
16977dd7cddfSDavid du Colombier 	Maxattr=	32,
16987dd7cddfSDavid du Colombier };
16997dd7cddfSDavid du Colombier 
1700219b2ee8SDavid du Colombier /*
17017dd7cddfSDavid du Colombier  *  generic query lookup.  The query is of one of the following
17027dd7cddfSDavid du Colombier  *  forms:
17037dd7cddfSDavid du Colombier  *
17047dd7cddfSDavid du Colombier  *  attr1=val1 attr2=val2 attr3=val3 ...
17057dd7cddfSDavid du Colombier  *
17067dd7cddfSDavid du Colombier  *  returns the matching tuple
17077dd7cddfSDavid du Colombier  *
17087dd7cddfSDavid du Colombier  *  ipinfo attr=val attr1 attr2 attr3 ...
17097dd7cddfSDavid du Colombier  *
17107dd7cddfSDavid du Colombier  *  is like ipinfo and returns the attr{1-n}
17117dd7cddfSDavid du Colombier  *  associated with the ip address.
1712219b2ee8SDavid du Colombier  */
1713219b2ee8SDavid du Colombier char*
genquery(Mfile * mf,char * query)1714219b2ee8SDavid du Colombier genquery(Mfile *mf, char *query)
1715219b2ee8SDavid du Colombier {
1716219b2ee8SDavid du Colombier 	int i, n;
1717219b2ee8SDavid du Colombier 	char *p;
17187dd7cddfSDavid du Colombier 	char *attr[Maxattr];
17197dd7cddfSDavid du Colombier 	char *val[Maxattr];
1720219b2ee8SDavid du Colombier 	Ndbtuple *t;
1721219b2ee8SDavid du Colombier 	Ndbs s;
1722219b2ee8SDavid du Colombier 
1723b8b25780SDavid du Colombier 	n = getfields(query, attr, nelem(attr), 1, " ");
1724219b2ee8SDavid du Colombier 	if(n == 0)
1725219b2ee8SDavid du Colombier 		return "bad query";
1726219b2ee8SDavid du Colombier 
17277dd7cddfSDavid du Colombier 	if(strcmp(attr[0], "ipinfo") == 0)
17287dd7cddfSDavid du Colombier 		return ipinfoquery(mf, attr, n);
17297dd7cddfSDavid du Colombier 
1730219b2ee8SDavid du Colombier 	/* parse pairs */
1731219b2ee8SDavid du Colombier 	for(i = 0; i < n; i++){
1732219b2ee8SDavid du Colombier 		p = strchr(attr[i], '=');
1733219b2ee8SDavid du Colombier 		if(p == 0)
1734219b2ee8SDavid du Colombier 			return "bad query";
1735219b2ee8SDavid du Colombier 		*p++ = 0;
1736219b2ee8SDavid du Colombier 		val[i] = p;
1737219b2ee8SDavid du Colombier 	}
1738219b2ee8SDavid du Colombier 
1739219b2ee8SDavid du Colombier 	/* give dns a chance */
1740219b2ee8SDavid du Colombier 	if((strcmp(attr[0], "dom") == 0 || strcmp(attr[0], "ip") == 0) && val[0]){
17417dd7cddfSDavid du Colombier 		t = dnsiplookup(val[0], &s);
1742219b2ee8SDavid du Colombier 		if(t){
1743219b2ee8SDavid du Colombier 			if(qmatch(t, attr, val, n)){
1744219b2ee8SDavid du Colombier 				qreply(mf, t);
1745219b2ee8SDavid du Colombier 				ndbfree(t);
1746219b2ee8SDavid du Colombier 				return 0;
1747219b2ee8SDavid du Colombier 			}
1748219b2ee8SDavid du Colombier 			ndbfree(t);
1749219b2ee8SDavid du Colombier 		}
1750219b2ee8SDavid du Colombier 	}
1751219b2ee8SDavid du Colombier 
1752219b2ee8SDavid du Colombier 	/* first pair is always the key.  It can't be a '*' */
1753219b2ee8SDavid du Colombier 	t = ndbsearch(db, &s, attr[0], val[0]);
1754219b2ee8SDavid du Colombier 
1755219b2ee8SDavid du Colombier 	/* search is the and of all the pairs */
1756219b2ee8SDavid du Colombier 	while(t){
1757219b2ee8SDavid du Colombier 		if(qmatch(t, attr, val, n)){
1758219b2ee8SDavid du Colombier 			qreply(mf, t);
1759219b2ee8SDavid du Colombier 			ndbfree(t);
1760219b2ee8SDavid du Colombier 			return 0;
1761219b2ee8SDavid du Colombier 		}
1762219b2ee8SDavid du Colombier 
1763219b2ee8SDavid du Colombier 		ndbfree(t);
1764219b2ee8SDavid du Colombier 		t = ndbsnext(&s, attr[0], val[0]);
1765219b2ee8SDavid du Colombier 	}
1766219b2ee8SDavid du Colombier 
1767219b2ee8SDavid du Colombier 	return "no match";
1768219b2ee8SDavid du Colombier }
17697dd7cddfSDavid du Colombier 
17707dd7cddfSDavid du Colombier /*
17717dd7cddfSDavid du Colombier  *  resolve an ip address
17727dd7cddfSDavid du Colombier  */
17737dd7cddfSDavid du Colombier static Ndbtuple*
ipresolve(char * attr,char * host)17747dd7cddfSDavid du Colombier ipresolve(char *attr, char *host)
17757dd7cddfSDavid du Colombier {
17767dd7cddfSDavid du Colombier 	Ndbtuple *t, *nt, **l;
17777dd7cddfSDavid du Colombier 
17787dd7cddfSDavid du Colombier 	t = iplookup(&network[Ntcp], host, "*", 0);
17797dd7cddfSDavid du Colombier 	for(l = &t; *l != nil; ){
17807dd7cddfSDavid du Colombier 		nt = *l;
17817dd7cddfSDavid du Colombier 		if(strcmp(nt->attr, "ip") != 0){
17827dd7cddfSDavid du Colombier 			*l = nt->entry;
17837dd7cddfSDavid du Colombier 			nt->entry = nil;
17847dd7cddfSDavid du Colombier 			ndbfree(nt);
17857dd7cddfSDavid du Colombier 			continue;
17867dd7cddfSDavid du Colombier 		}
17877dd7cddfSDavid du Colombier 		strcpy(nt->attr, attr);
17887dd7cddfSDavid du Colombier 		l = &nt->entry;
17897dd7cddfSDavid du Colombier 	}
17907dd7cddfSDavid du Colombier 	return t;
17917dd7cddfSDavid du Colombier }
17927dd7cddfSDavid du Colombier 
17937dd7cddfSDavid du Colombier char*
ipinfoquery(Mfile * mf,char ** list,int n)17947dd7cddfSDavid du Colombier ipinfoquery(Mfile *mf, char **list, int n)
17957dd7cddfSDavid du Colombier {
17967dd7cddfSDavid du Colombier 	int i, nresolve;
17977dd7cddfSDavid du Colombier 	int resolve[Maxattr];
17987dd7cddfSDavid du Colombier 	Ndbtuple *t, *nt, **l;
17997dd7cddfSDavid du Colombier 	char *attr, *val;
18007dd7cddfSDavid du Colombier 
18017dd7cddfSDavid du Colombier 	/* skip 'ipinfo' */
18027dd7cddfSDavid du Colombier 	list++; n--;
18037dd7cddfSDavid du Colombier 
18048a2c5ad0SDavid du Colombier 	if(n < 1)
18057dd7cddfSDavid du Colombier 		return "bad query";
18067dd7cddfSDavid du Colombier 
18078a2c5ad0SDavid du Colombier 	/* get search attribute=value, or assume ip=myipaddr */
18088a2c5ad0SDavid du Colombier 	attr = *list;
18098a2c5ad0SDavid du Colombier 	if((val = strchr(attr, '=')) != nil){
18107dd7cddfSDavid du Colombier 		*val++ = 0;
18118a2c5ad0SDavid du Colombier 		list++;
18128a2c5ad0SDavid du Colombier 		n--;
18138a2c5ad0SDavid du Colombier 	}else{
18148a2c5ad0SDavid du Colombier 		attr = "ip";
18158a2c5ad0SDavid du Colombier 		val = ipaddr;
18168a2c5ad0SDavid du Colombier 	}
18178a2c5ad0SDavid du Colombier 
18188a2c5ad0SDavid du Colombier 	if(n < 1)
18198a2c5ad0SDavid du Colombier 		return "bad query";
18207dd7cddfSDavid du Colombier 
18217dd7cddfSDavid du Colombier 	/*
18227dd7cddfSDavid du Colombier 	 *  don't let ndbipinfo resolve the addresses, we're
18237dd7cddfSDavid du Colombier 	 *  better at it.
18247dd7cddfSDavid du Colombier 	 */
18257dd7cddfSDavid du Colombier 	nresolve = 0;
18267dd7cddfSDavid du Colombier 	for(i = 0; i < n; i++)
1827107aedb4SDavid du Colombier 		if(*list[i] == '@'){		/* @attr=val ? */
18287dd7cddfSDavid du Colombier 			list[i]++;
1829107aedb4SDavid du Colombier 			resolve[i] = 1;		/* we'll resolve it */
18307dd7cddfSDavid du Colombier 			nresolve++;
18317dd7cddfSDavid du Colombier 		} else
18327dd7cddfSDavid du Colombier 			resolve[i] = 0;
18337dd7cddfSDavid du Colombier 
18347dd7cddfSDavid du Colombier 	t = ndbipinfo(db, attr, val, list, n);
18357dd7cddfSDavid du Colombier 	if(t == nil)
18367dd7cddfSDavid du Colombier 		return "no match";
18377dd7cddfSDavid du Colombier 
18387dd7cddfSDavid du Colombier 	if(nresolve != 0){
18397dd7cddfSDavid du Colombier 		for(l = &t; *l != nil;){
18407dd7cddfSDavid du Colombier 			nt = *l;
18417dd7cddfSDavid du Colombier 
18427dd7cddfSDavid du Colombier 			/* already an address? */
18437dd7cddfSDavid du Colombier 			if(strcmp(ipattr(nt->val), "ip") == 0){
18447dd7cddfSDavid du Colombier 				l = &(*l)->entry;
18457dd7cddfSDavid du Colombier 				continue;
18467dd7cddfSDavid du Colombier 			}
18477dd7cddfSDavid du Colombier 
18487dd7cddfSDavid du Colombier 			/* user wants it resolved? */
18497dd7cddfSDavid du Colombier 			for(i = 0; i < n; i++)
18507dd7cddfSDavid du Colombier 				if(strcmp(list[i], nt->attr) == 0)
18517dd7cddfSDavid du Colombier 					break;
18527dd7cddfSDavid du Colombier 			if(i >= n || resolve[i] == 0){
18537dd7cddfSDavid du Colombier 				l = &(*l)->entry;
18547dd7cddfSDavid du Colombier 				continue;
18557dd7cddfSDavid du Colombier 			}
18567dd7cddfSDavid du Colombier 
18577dd7cddfSDavid du Colombier 			/* resolve address and replace entry */
18587dd7cddfSDavid du Colombier 			*l = ipresolve(nt->attr, nt->val);
18597dd7cddfSDavid du Colombier 			while(*l != nil)
18607dd7cddfSDavid du Colombier 				l = &(*l)->entry;
18617dd7cddfSDavid du Colombier 			*l = nt->entry;
18627dd7cddfSDavid du Colombier 
18637dd7cddfSDavid du Colombier 			nt->entry = nil;
18647dd7cddfSDavid du Colombier 			ndbfree(nt);
18657dd7cddfSDavid du Colombier 		}
18667dd7cddfSDavid du Colombier 	}
18677dd7cddfSDavid du Colombier 
18687dd7cddfSDavid du Colombier 	/* make it all one line */
18697dd7cddfSDavid du Colombier 	for(nt = t; nt != nil; nt = nt->entry){
18707dd7cddfSDavid du Colombier 		if(nt->entry == nil)
18717dd7cddfSDavid du Colombier 			nt->line = t;
18727dd7cddfSDavid du Colombier 		else
18737dd7cddfSDavid du Colombier 			nt->line = nt->entry;
18747dd7cddfSDavid du Colombier 	}
18757dd7cddfSDavid du Colombier 
18767dd7cddfSDavid du Colombier 	qreply(mf, t);
18777dd7cddfSDavid du Colombier 
18787dd7cddfSDavid du Colombier 	return nil;
18797dd7cddfSDavid du Colombier }
18807dd7cddfSDavid du Colombier 
18817dd7cddfSDavid du Colombier void*
emalloc(int size)18827dd7cddfSDavid du Colombier emalloc(int size)
18837dd7cddfSDavid du Colombier {
18847dd7cddfSDavid du Colombier 	void *x;
18857dd7cddfSDavid du Colombier 
18867dd7cddfSDavid du Colombier 	x = malloc(size);
18877dd7cddfSDavid du Colombier 	if(x == nil)
18887dd7cddfSDavid du Colombier 		abort();
18897dd7cddfSDavid du Colombier 	memset(x, 0, size);
18907dd7cddfSDavid du Colombier 	return x;
18917dd7cddfSDavid du Colombier }
18929a747e4fSDavid du Colombier 
18939a747e4fSDavid du Colombier char*
estrdup(char * s)18949a747e4fSDavid du Colombier estrdup(char *s)
18959a747e4fSDavid du Colombier {
18969a747e4fSDavid du Colombier 	int size;
18979a747e4fSDavid du Colombier 	char *p;
18989a747e4fSDavid du Colombier 
18999a747e4fSDavid du Colombier 	size = strlen(s)+1;
19009a747e4fSDavid du Colombier 	p = malloc(size);
19019a747e4fSDavid du Colombier 	if(p == nil)
19029a747e4fSDavid du Colombier 		abort();
19039a747e4fSDavid du Colombier 	memmove(p, s, size);
19049a747e4fSDavid du Colombier 	return p;
19059a747e4fSDavid du Colombier }
1906