xref: /plan9/sys/src/cmd/ip/tftpd.c (revision 27e109191c331e847f7fbc482db3475eda35f6b4)
13e12c5d1SDavid du Colombier #include <u.h>
23e12c5d1SDavid du Colombier #include <libc.h>
3c0eadb1cSDavid du Colombier #include <auth.h>
43e12c5d1SDavid du Colombier #include <bio.h>
53e12c5d1SDavid du Colombier #include <ip.h>
63e12c5d1SDavid du Colombier #include <ndb.h>
73e12c5d1SDavid du Colombier 
89a747e4fSDavid du Colombier enum
99a747e4fSDavid du Colombier {
109a747e4fSDavid du Colombier 	Maxpath=	128,
119a747e4fSDavid du Colombier 	Maxerr=		256,
129a747e4fSDavid du Colombier };
139a747e4fSDavid du Colombier 
143e12c5d1SDavid du Colombier int 	dbg;
15219b2ee8SDavid du Colombier int	restricted;
163e12c5d1SDavid du Colombier void	sendfile(int, char*, char*);
173e12c5d1SDavid du Colombier void	recvfile(int, char*, char*);
183e12c5d1SDavid du Colombier void	nak(int, int, char*);
193e12c5d1SDavid du Colombier void	ack(int, ushort);
203e12c5d1SDavid du Colombier void	clrcon(void);
213e12c5d1SDavid du Colombier void	setuser(void);
223e12c5d1SDavid du Colombier char*	sunkernel(char*);
237dd7cddfSDavid du Colombier void	remoteaddr(char*, char*, int);
247dd7cddfSDavid du Colombier void	doserve(int);
253e12c5d1SDavid du Colombier 
267dd7cddfSDavid du Colombier char	bigbuf[32768];
277dd7cddfSDavid du Colombier char	raddr[64];
283e12c5d1SDavid du Colombier 
293e12c5d1SDavid du Colombier char	*dir = "/lib/tftpd";
30219b2ee8SDavid du Colombier char	*dirsl;
31219b2ee8SDavid du Colombier int	dirsllen;
323e12c5d1SDavid du Colombier char	flog[] = "ipboot";
339a747e4fSDavid du Colombier char	net[Maxpath];
343e12c5d1SDavid du Colombier 
353e12c5d1SDavid du Colombier enum
363e12c5d1SDavid du Colombier {
373e12c5d1SDavid du Colombier 	Tftp_READ	= 1,
383e12c5d1SDavid du Colombier 	Tftp_WRITE	= 2,
393e12c5d1SDavid du Colombier 	Tftp_DATA	= 3,
403e12c5d1SDavid du Colombier 	Tftp_ACK	= 4,
413e12c5d1SDavid du Colombier 	Tftp_ERROR	= 5,
423e12c5d1SDavid du Colombier 	Segsize		= 512,
433e12c5d1SDavid du Colombier };
443e12c5d1SDavid du Colombier 
453e12c5d1SDavid du Colombier void
467dd7cddfSDavid du Colombier usage(void)
477dd7cddfSDavid du Colombier {
48c0eadb1cSDavid du Colombier 	fprint(2, "usage: %s [-dr] [-h homedir] [-s svc] [-x netmtpt]\n",
49c0eadb1cSDavid du Colombier 		argv0);
507dd7cddfSDavid du Colombier 	exits("usage");
517dd7cddfSDavid du Colombier }
527dd7cddfSDavid du Colombier 
537dd7cddfSDavid du Colombier void
543e12c5d1SDavid du Colombier main(int argc, char **argv)
553e12c5d1SDavid du Colombier {
567dd7cddfSDavid du Colombier 	char buf[64];
577dd7cddfSDavid du Colombier 	char adir[64], ldir[64];
587dd7cddfSDavid du Colombier 	int cfd, lcfd, dfd;
59c0eadb1cSDavid du Colombier 	char *p, *svc = "69";
603e12c5d1SDavid du Colombier 
617dd7cddfSDavid du Colombier 	setnetmtpt(net, sizeof(net), nil);
623e12c5d1SDavid du Colombier 	ARGBEGIN{
633e12c5d1SDavid du Colombier 	case 'd':
643e12c5d1SDavid du Colombier 		dbg++;
653e12c5d1SDavid du Colombier 		break;
663e12c5d1SDavid du Colombier 	case 'h':
673e12c5d1SDavid du Colombier 		dir = ARGF();
683e12c5d1SDavid du Colombier 		break;
69219b2ee8SDavid du Colombier 	case 'r':
70219b2ee8SDavid du Colombier 		restricted = 1;
71219b2ee8SDavid du Colombier 		break;
72c0eadb1cSDavid du Colombier 	case 's':
73c0eadb1cSDavid du Colombier 		svc = EARGF(usage());
74c0eadb1cSDavid du Colombier 		break;
757dd7cddfSDavid du Colombier 	case 'x':
767dd7cddfSDavid du Colombier 		p = ARGF();
777dd7cddfSDavid du Colombier 		if(p == nil)
787dd7cddfSDavid du Colombier 			usage();
797dd7cddfSDavid du Colombier 		setnetmtpt(net, sizeof(net), p);
807dd7cddfSDavid du Colombier 		break;
813e12c5d1SDavid du Colombier 	default:
827dd7cddfSDavid du Colombier 		usage();
833e12c5d1SDavid du Colombier 	}ARGEND
843e12c5d1SDavid du Colombier 
85219b2ee8SDavid du Colombier 	snprint(buf, sizeof buf, "%s/", dir);
86219b2ee8SDavid du Colombier 	dirsl = strdup(buf);
87219b2ee8SDavid du Colombier 	dirsllen = strlen(dirsl);
88219b2ee8SDavid du Colombier 
899a747e4fSDavid du Colombier 	fmtinstall('E', eipfmt);
909a747e4fSDavid du Colombier 	fmtinstall('I', eipfmt);
913e12c5d1SDavid du Colombier 
923e12c5d1SDavid du Colombier 	if(chdir(dir) < 0)
937dd7cddfSDavid du Colombier 		sysfatal("can't get to directory %s: %r", dir);
943e12c5d1SDavid du Colombier 
957dd7cddfSDavid du Colombier 	if(!dbg)
963e12c5d1SDavid du Colombier 		switch(rfork(RFNOTEG|RFPROC|RFFDG)) {
973e12c5d1SDavid du Colombier 		case -1:
987dd7cddfSDavid du Colombier 			sysfatal("fork: %r");
993e12c5d1SDavid du Colombier 		case 0:
1003e12c5d1SDavid du Colombier 			break;
1013e12c5d1SDavid du Colombier 		default:
1023e12c5d1SDavid du Colombier 			exits(0);
1033e12c5d1SDavid du Colombier 		}
1043e12c5d1SDavid du Colombier 
105c0eadb1cSDavid du Colombier 	snprint(buf, sizeof buf, "%s/udp!*!%s", net, svc);
1067dd7cddfSDavid du Colombier 	cfd = announce(buf, adir);
107c0eadb1cSDavid du Colombier 	if (cfd < 0)
108c0eadb1cSDavid du Colombier 		sysfatal("announcing on %s: %r", buf);
109c0eadb1cSDavid du Colombier 	syslog(dbg, flog, "tftpd started on %s dir %s", buf, adir);
110*27e10919SDavid du Colombier 	setuser();
1113e12c5d1SDavid du Colombier 	for(;;) {
1127dd7cddfSDavid du Colombier 		lcfd = listen(adir, ldir);
1137dd7cddfSDavid du Colombier 		if(lcfd < 0)
114c0eadb1cSDavid du Colombier 			sysfatal("listening on %s: %r", adir);
1157dd7cddfSDavid du Colombier 
1167dd7cddfSDavid du Colombier 		switch(fork()) {
1177dd7cddfSDavid du Colombier 		case -1:
1187dd7cddfSDavid du Colombier 			sysfatal("fork: %r");
1197dd7cddfSDavid du Colombier 		case 0:
120c0eadb1cSDavid du Colombier 			dfd = accept(lcfd, ldir);
1217dd7cddfSDavid du Colombier 			if(dfd < 0)
1227dd7cddfSDavid du Colombier  				exits(0);
1237dd7cddfSDavid du Colombier 			remoteaddr(ldir, raddr, sizeof(raddr));
124c0eadb1cSDavid du Colombier 			syslog(0, flog, "tftp connection from %s dir %s",
125c0eadb1cSDavid du Colombier 				raddr, ldir);
1267dd7cddfSDavid du Colombier 			doserve(dfd);
1277dd7cddfSDavid du Colombier 			exits("done");
1287dd7cddfSDavid du Colombier 			break;
1297dd7cddfSDavid du Colombier 		default:
1307dd7cddfSDavid du Colombier 			close(lcfd);
1317dd7cddfSDavid du Colombier 			continue;
1327dd7cddfSDavid du Colombier 		}
1337dd7cddfSDavid du Colombier 	}
1347dd7cddfSDavid du Colombier }
1357dd7cddfSDavid du Colombier 
1367dd7cddfSDavid du Colombier void
1377dd7cddfSDavid du Colombier doserve(int fd)
1387dd7cddfSDavid du Colombier {
1397dd7cddfSDavid du Colombier 	int dlen;
1407dd7cddfSDavid du Colombier 	char *mode, *p;
1417dd7cddfSDavid du Colombier 	short op;
1427dd7cddfSDavid du Colombier 
1437dd7cddfSDavid du Colombier 	dlen = read(fd, bigbuf, sizeof(bigbuf));
1443e12c5d1SDavid du Colombier 	if(dlen < 0)
1457dd7cddfSDavid du Colombier 		sysfatal("listen read: %r");
1463e12c5d1SDavid du Colombier 
1477dd7cddfSDavid du Colombier 	op = (bigbuf[0]<<8) | bigbuf[1];
1483e12c5d1SDavid du Colombier 	dlen -= 2;
1497dd7cddfSDavid du Colombier 	mode = bigbuf+2;
1503e12c5d1SDavid du Colombier 	while(*mode != '\0' && dlen--)
1513e12c5d1SDavid du Colombier 		mode++;
1523e12c5d1SDavid du Colombier 	mode++;
1533e12c5d1SDavid du Colombier 	p = mode;
1543e12c5d1SDavid du Colombier 	while(*p && dlen--)
1553e12c5d1SDavid du Colombier 		p++;
1563e12c5d1SDavid du Colombier 	if(dlen == 0) {
1577dd7cddfSDavid du Colombier 		nak(fd, 0, "bad tftpmode");
1587dd7cddfSDavid du Colombier 		close(fd);
159c0eadb1cSDavid du Colombier 		syslog(dbg, flog, "bad mode from %s", raddr);
1607dd7cddfSDavid du Colombier 		return;
1613e12c5d1SDavid du Colombier 	}
1623e12c5d1SDavid du Colombier 
1633e12c5d1SDavid du Colombier 	if(op != Tftp_READ && op != Tftp_WRITE) {
1647dd7cddfSDavid du Colombier 		nak(fd, 4, "Illegal TFTP operation");
1657dd7cddfSDavid du Colombier 		close(fd);
1663e12c5d1SDavid du Colombier 		syslog(dbg, flog, "bad request %d %s", op, raddr);
1677dd7cddfSDavid du Colombier 		return;
1683e12c5d1SDavid du Colombier 	}
1697dd7cddfSDavid du Colombier 
170219b2ee8SDavid du Colombier 	if(restricted){
17167031067SDavid du Colombier 		if(bigbuf[2] == '#' ||
17267031067SDavid du Colombier 		  strncmp(bigbuf+2, "../", 3)==0 || strstr(bigbuf+2, "/../") ||
1737dd7cddfSDavid du Colombier 		  (bigbuf[2] == '/' && strncmp(bigbuf+2, dirsl, dirsllen)!=0)){
1747dd7cddfSDavid du Colombier 			nak(fd, 4, "Permission denied");
1757dd7cddfSDavid du Colombier 			close(fd);
17639734e7eSDavid du Colombier 			syslog(dbg, flog, "bad request %d from %s file %s", op, raddr, bigbuf+2);
1777dd7cddfSDavid du Colombier 			return;
178219b2ee8SDavid du Colombier 		}
179219b2ee8SDavid du Colombier 	}
1807dd7cddfSDavid du Colombier 
1813e12c5d1SDavid du Colombier 	if(op == Tftp_READ)
1827dd7cddfSDavid du Colombier 		sendfile(fd, bigbuf+2, mode);
1833e12c5d1SDavid du Colombier 	else
1847dd7cddfSDavid du Colombier 		recvfile(fd, bigbuf+2, mode);
1853e12c5d1SDavid du Colombier }
1863e12c5d1SDavid du Colombier 
1873e12c5d1SDavid du Colombier void
1883e12c5d1SDavid du Colombier catcher(void *junk, char *msg)
1893e12c5d1SDavid du Colombier {
1903e12c5d1SDavid du Colombier 	USED(junk);
1913e12c5d1SDavid du Colombier 
1923e12c5d1SDavid du Colombier 	if(strncmp(msg, "exit", 4) == 0)
1933e12c5d1SDavid du Colombier 		noted(NDFLT);
1943e12c5d1SDavid du Colombier 	noted(NCONT);
1953e12c5d1SDavid du Colombier }
1963e12c5d1SDavid du Colombier 
1973e12c5d1SDavid du Colombier void
1983e12c5d1SDavid du Colombier sendfile(int fd, char *name, char *mode)
1993e12c5d1SDavid du Colombier {
2003e12c5d1SDavid du Colombier 	int file;
2013e12c5d1SDavid du Colombier 	uchar buf[Segsize+4];
2023e12c5d1SDavid du Colombier 	uchar ack[1024];
2039a747e4fSDavid du Colombier 	char errbuf[Maxerr];
2043e12c5d1SDavid du Colombier 	int ackblock, block, ret;
2053e12c5d1SDavid du Colombier 	int rexmit, n, al, txtry, rxl;
2063e12c5d1SDavid du Colombier 	short op;
2073e12c5d1SDavid du Colombier 
2083e12c5d1SDavid du Colombier 	syslog(dbg, flog, "send file '%s' %s to %s", name, mode, raddr);
2093e12c5d1SDavid du Colombier 	name = sunkernel(name);
2103e12c5d1SDavid du Colombier 	if(name == 0){
2113e12c5d1SDavid du Colombier 		nak(fd, 0, "not in our database");
2123e12c5d1SDavid du Colombier 		return;
2133e12c5d1SDavid du Colombier 	}
2143e12c5d1SDavid du Colombier 
2153e12c5d1SDavid du Colombier 	notify(catcher);
2163e12c5d1SDavid du Colombier 
2173e12c5d1SDavid du Colombier 	file = open(name, OREAD);
2183e12c5d1SDavid du Colombier 	if(file < 0) {
2199a747e4fSDavid du Colombier 		errstr(errbuf, sizeof errbuf);
2203e12c5d1SDavid du Colombier 		nak(fd, 0, errbuf);
2213e12c5d1SDavid du Colombier 		return;
2223e12c5d1SDavid du Colombier 	}
2233e12c5d1SDavid du Colombier 	block = 0;
2243e12c5d1SDavid du Colombier 	rexmit = 0;
2253e12c5d1SDavid du Colombier 	n = 0;
226219b2ee8SDavid du Colombier 	for(txtry = 0; txtry < 5;) {
2273e12c5d1SDavid du Colombier 		if(rexmit == 0) {
2283e12c5d1SDavid du Colombier 			block++;
2293e12c5d1SDavid du Colombier 			buf[0] = 0;
2303e12c5d1SDavid du Colombier 			buf[1] = Tftp_DATA;
2313e12c5d1SDavid du Colombier 			buf[2] = block>>8;
2323e12c5d1SDavid du Colombier 			buf[3] = block;
2333e12c5d1SDavid du Colombier 			n = read(file, buf+4, Segsize);
2343e12c5d1SDavid du Colombier 			if(n < 0) {
2359a747e4fSDavid du Colombier 				errstr(errbuf, sizeof errbuf);
2363e12c5d1SDavid du Colombier 				nak(fd, 0, errbuf);
2373e12c5d1SDavid du Colombier 				return;
2383e12c5d1SDavid du Colombier 			}
239219b2ee8SDavid du Colombier 			txtry = 0;
2403e12c5d1SDavid du Colombier 		}
2417dd7cddfSDavid du Colombier 		else {
2427dd7cddfSDavid du Colombier 			syslog(dbg, flog, "rexmit %d %s:%d to %s", 4+n, name, block, raddr);
2433e12c5d1SDavid du Colombier 			txtry++;
2447dd7cddfSDavid du Colombier 		}
2457dd7cddfSDavid du Colombier 
2463e12c5d1SDavid du Colombier 		ret = write(fd, buf, 4+n);
2473e12c5d1SDavid du Colombier 		if(ret < 0)
2487dd7cddfSDavid du Colombier 			sysfatal("tftpd: network write error: %r");
2493e12c5d1SDavid du Colombier 
2503e12c5d1SDavid du Colombier 		for(rxl = 0; rxl < 10; rxl++) {
2513e12c5d1SDavid du Colombier 			rexmit = 0;
252219b2ee8SDavid du Colombier 			alarm(500);
2533e12c5d1SDavid du Colombier 			al = read(fd, ack, sizeof(ack));
2543e12c5d1SDavid du Colombier 			alarm(0);
2553e12c5d1SDavid du Colombier 			if(al < 0) {
2563e12c5d1SDavid du Colombier 				rexmit = 1;
2573e12c5d1SDavid du Colombier 				break;
2583e12c5d1SDavid du Colombier 			}
2593e12c5d1SDavid du Colombier 			op = ack[0]<<8|ack[1];
2603e12c5d1SDavid du Colombier 			if(op == Tftp_ERROR)
2613e12c5d1SDavid du Colombier 				goto error;
2623e12c5d1SDavid du Colombier 			ackblock = ack[2]<<8|ack[3];
2633e12c5d1SDavid du Colombier 			if(ackblock == block)
2643e12c5d1SDavid du Colombier 				break;
2653e12c5d1SDavid du Colombier 			if(ackblock == 0xffff) {
2663e12c5d1SDavid du Colombier 				rexmit = 1;
2673e12c5d1SDavid du Colombier 				break;
2683e12c5d1SDavid du Colombier 			}
2693e12c5d1SDavid du Colombier 		}
2703e12c5d1SDavid du Colombier 		if(ret != Segsize+4 && rexmit == 0)
2713e12c5d1SDavid du Colombier 			break;
2723e12c5d1SDavid du Colombier 	}
2733e12c5d1SDavid du Colombier error:
2743e12c5d1SDavid du Colombier 	close(fd);
2753e12c5d1SDavid du Colombier 	close(file);
2763e12c5d1SDavid du Colombier }
2773e12c5d1SDavid du Colombier 
2783e12c5d1SDavid du Colombier void
2793e12c5d1SDavid du Colombier recvfile(int fd, char *name, char *mode)
2803e12c5d1SDavid du Colombier {
2813e12c5d1SDavid du Colombier 	ushort op, block, inblock;
2823e12c5d1SDavid du Colombier 	uchar buf[Segsize+8];
2839a747e4fSDavid du Colombier 	char errbuf[Maxerr];
2843e12c5d1SDavid du Colombier 	int n, ret, file;
2853e12c5d1SDavid du Colombier 
2863e12c5d1SDavid du Colombier 	syslog(dbg, flog, "receive file '%s' %s from %s", name, mode, raddr);
2873e12c5d1SDavid du Colombier 
2883e12c5d1SDavid du Colombier 	file = create(name, OWRITE, 0666);
2893e12c5d1SDavid du Colombier 	if(file < 0) {
2909a747e4fSDavid du Colombier 		errstr(errbuf, sizeof errbuf);
2913e12c5d1SDavid du Colombier 		nak(fd, 0, errbuf);
2923e12c5d1SDavid du Colombier 		return;
2933e12c5d1SDavid du Colombier 	}
2943e12c5d1SDavid du Colombier 
2953e12c5d1SDavid du Colombier 	block = 0;
2963e12c5d1SDavid du Colombier 	ack(fd, block);
2973e12c5d1SDavid du Colombier 	block++;
2983e12c5d1SDavid du Colombier 
2993e12c5d1SDavid du Colombier 	for(;;) {
3003e12c5d1SDavid du Colombier 		alarm(15000);
3013e12c5d1SDavid du Colombier 		n = read(fd, buf, sizeof(buf));
3023e12c5d1SDavid du Colombier 		alarm(0);
3033e12c5d1SDavid du Colombier 		if(n < 0)
3043e12c5d1SDavid du Colombier 			goto error;
3053e12c5d1SDavid du Colombier 		op = buf[0]<<8|buf[1];
3063e12c5d1SDavid du Colombier 		if(op == Tftp_ERROR)
3073e12c5d1SDavid du Colombier 			goto error;
3083e12c5d1SDavid du Colombier 
3093e12c5d1SDavid du Colombier 		n -= 4;
3103e12c5d1SDavid du Colombier 		inblock = buf[2]<<8|buf[3];
3113e12c5d1SDavid du Colombier 		if(op == Tftp_DATA) {
3123e12c5d1SDavid du Colombier 			if(inblock == block) {
3133e12c5d1SDavid du Colombier 				ret = write(file, buf, n);
3143e12c5d1SDavid du Colombier 				if(ret < 0) {
3159a747e4fSDavid du Colombier 					errstr(errbuf, sizeof errbuf);
3163e12c5d1SDavid du Colombier 					nak(fd, 0, errbuf);
3173e12c5d1SDavid du Colombier 					goto error;
3183e12c5d1SDavid du Colombier 				}
3193e12c5d1SDavid du Colombier 				ack(fd, block);
3203e12c5d1SDavid du Colombier 				block++;
3213e12c5d1SDavid du Colombier 			}
3223e12c5d1SDavid du Colombier 			ack(fd, 0xffff);
3233e12c5d1SDavid du Colombier 		}
3243e12c5d1SDavid du Colombier 	}
3253e12c5d1SDavid du Colombier error:
3263e12c5d1SDavid du Colombier 	close(file);
3273e12c5d1SDavid du Colombier }
3283e12c5d1SDavid du Colombier 
3293e12c5d1SDavid du Colombier void
3303e12c5d1SDavid du Colombier ack(int fd, ushort block)
3313e12c5d1SDavid du Colombier {
3323e12c5d1SDavid du Colombier 	uchar ack[4];
3333e12c5d1SDavid du Colombier 	int n;
3343e12c5d1SDavid du Colombier 
3353e12c5d1SDavid du Colombier 	ack[0] = 0;
3363e12c5d1SDavid du Colombier 	ack[1] = Tftp_ACK;
3373e12c5d1SDavid du Colombier 	ack[2] = block>>8;
3383e12c5d1SDavid du Colombier 	ack[3] = block;
3393e12c5d1SDavid du Colombier 
3403e12c5d1SDavid du Colombier 	n = write(fd, ack, 4);
3413e12c5d1SDavid du Colombier 	if(n < 0)
3427dd7cddfSDavid du Colombier 		sysfatal("network write: %r");
3433e12c5d1SDavid du Colombier }
3443e12c5d1SDavid du Colombier 
3453e12c5d1SDavid du Colombier void
3463e12c5d1SDavid du Colombier nak(int fd, int code, char *msg)
3473e12c5d1SDavid du Colombier {
3483e12c5d1SDavid du Colombier 	char buf[128];
3493e12c5d1SDavid du Colombier 	int n;
3503e12c5d1SDavid du Colombier 
3513e12c5d1SDavid du Colombier 	buf[0] = 0;
3523e12c5d1SDavid du Colombier 	buf[1] = Tftp_ERROR;
3533e12c5d1SDavid du Colombier 	buf[2] = 0;
3543e12c5d1SDavid du Colombier 	buf[3] = code;
3553e12c5d1SDavid du Colombier 	strcpy(buf+4, msg);
3563e12c5d1SDavid du Colombier 	n = strlen(msg) + 4 + 1;
3573e12c5d1SDavid du Colombier 	n = write(fd, buf, n);
3583e12c5d1SDavid du Colombier 	if(n < 0)
3597dd7cddfSDavid du Colombier 		sysfatal("write nak: %r");
3603e12c5d1SDavid du Colombier }
3613e12c5d1SDavid du Colombier 
3623e12c5d1SDavid du Colombier void
3633e12c5d1SDavid du Colombier setuser(void)
3643e12c5d1SDavid du Colombier {
365c0eadb1cSDavid du Colombier 	int fd;
3663e12c5d1SDavid du Colombier 
367c0eadb1cSDavid du Colombier 	fd = open("#c/user", OWRITE);
368c0eadb1cSDavid du Colombier 	if(fd < 0 || write(fd, "none", strlen("none")) < 0)
369c0eadb1cSDavid du Colombier 		sysfatal("can't become none: %r");
370c0eadb1cSDavid du Colombier 	close(fd);
371c0eadb1cSDavid du Colombier 	if(newns("none", nil) < 0)
372c0eadb1cSDavid du Colombier 		sysfatal("can't build namespace: %r");
3733e12c5d1SDavid du Colombier }
3743e12c5d1SDavid du Colombier 
3757dd7cddfSDavid du Colombier char*
376da51d93aSDavid du Colombier lookup(char *sattr, char *sval, char *tattr, char *tval, int len)
3777dd7cddfSDavid du Colombier {
3787dd7cddfSDavid du Colombier 	static Ndb *db;
3797dd7cddfSDavid du Colombier 	char *attrs[1];
3807dd7cddfSDavid du Colombier 	Ndbtuple *t;
3817dd7cddfSDavid du Colombier 
3827dd7cddfSDavid du Colombier 	if(db == nil)
3837dd7cddfSDavid du Colombier 		db = ndbopen(0);
3847dd7cddfSDavid du Colombier 	if(db == nil)
3857dd7cddfSDavid du Colombier 		return nil;
3867dd7cddfSDavid du Colombier 
3877dd7cddfSDavid du Colombier 	if(sattr == nil)
3887dd7cddfSDavid du Colombier 		sattr = ipattr(sval);
3897dd7cddfSDavid du Colombier 
3907dd7cddfSDavid du Colombier 	attrs[0] = tattr;
3917dd7cddfSDavid du Colombier 	t = ndbipinfo(db, sattr, sval, attrs, 1);
3927dd7cddfSDavid du Colombier 	if(t == nil)
3937dd7cddfSDavid du Colombier 		return nil;
394da51d93aSDavid du Colombier 	strncpy(tval, t->val, len);
395da51d93aSDavid du Colombier 	tval[len-1] = 0;
3967dd7cddfSDavid du Colombier 	ndbfree(t);
3977dd7cddfSDavid du Colombier 	return tval;
3987dd7cddfSDavid du Colombier }
3997dd7cddfSDavid du Colombier 
4003e12c5d1SDavid du Colombier /*
4013e12c5d1SDavid du Colombier  *  for sun kernel boots, replace the requested file name with
4023e12c5d1SDavid du Colombier  *  a one from our database.  If the database doesn't specify a file,
4033e12c5d1SDavid du Colombier  *  don't answer.
4043e12c5d1SDavid du Colombier  */
4053e12c5d1SDavid du Colombier char*
4063e12c5d1SDavid du Colombier sunkernel(char *name)
4073e12c5d1SDavid du Colombier {
4083e12c5d1SDavid du Colombier 	ulong addr;
4097dd7cddfSDavid du Colombier 	uchar v4[IPv4addrlen];
4107dd7cddfSDavid du Colombier 	uchar v6[IPaddrlen];
411da51d93aSDavid du Colombier 	char buf[256];
412da51d93aSDavid du Colombier 	char ipbuf[128];
413*27e10919SDavid du Colombier 	char *suffix;
4143e12c5d1SDavid du Colombier 
415*27e10919SDavid du Colombier 	addr = strtoul(name, &suffix, 16);
416*27e10919SDavid du Colombier 	if(suffix-name != 8 || (strcmp(suffix, "") != 0 && strcmp(suffix, ".SUN") != 0))
4173e12c5d1SDavid du Colombier 		return name;
4183e12c5d1SDavid du Colombier 
4197dd7cddfSDavid du Colombier 	v4[0] = addr>>24;
4207dd7cddfSDavid du Colombier 	v4[1] = addr>>16;
4217dd7cddfSDavid du Colombier 	v4[2] = addr>>8;
4227dd7cddfSDavid du Colombier 	v4[3] = addr;
4237dd7cddfSDavid du Colombier 	v4tov6(v6, v4);
4247dd7cddfSDavid du Colombier 	sprint(ipbuf, "%I", v6);
425da51d93aSDavid du Colombier 	return lookup("ip", ipbuf, "bootf", buf, sizeof buf);
4267dd7cddfSDavid du Colombier }
4277dd7cddfSDavid du Colombier 
4287dd7cddfSDavid du Colombier void
4297dd7cddfSDavid du Colombier remoteaddr(char *dir, char *raddr, int len)
4307dd7cddfSDavid du Colombier {
4317dd7cddfSDavid du Colombier 	char buf[64];
4327dd7cddfSDavid du Colombier 	int fd, n;
4337dd7cddfSDavid du Colombier 
4347dd7cddfSDavid du Colombier 	snprint(buf, sizeof(buf), "%s/remote", dir);
4357dd7cddfSDavid du Colombier 	fd = open(buf, OREAD);
4367dd7cddfSDavid du Colombier 	if(fd < 0){
4377dd7cddfSDavid du Colombier 		snprint(raddr, sizeof(raddr), "unknown");
4387dd7cddfSDavid du Colombier 		return;
4397dd7cddfSDavid du Colombier 	}
4407dd7cddfSDavid du Colombier 	n = read(fd, raddr, len-1);
4417dd7cddfSDavid du Colombier 	close(fd);
4427dd7cddfSDavid du Colombier 	if(n <= 0){
4437dd7cddfSDavid du Colombier 		snprint(raddr, sizeof(raddr), "unknown");
4447dd7cddfSDavid du Colombier 		return;
4457dd7cddfSDavid du Colombier 	}
4467dd7cddfSDavid du Colombier 	if(n > 0)
4477dd7cddfSDavid du Colombier 		n--;
4487dd7cddfSDavid du Colombier 	raddr[n] = 0;
4493e12c5d1SDavid du Colombier }
450