xref: /plan9/sys/src/cmd/ip/tftpd.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
13e12c5d1SDavid du Colombier #include <u.h>
23e12c5d1SDavid du Colombier #include <libc.h>
33e12c5d1SDavid du Colombier #include <bio.h>
43e12c5d1SDavid du Colombier #include <ip.h>
53e12c5d1SDavid du Colombier #include <ndb.h>
63e12c5d1SDavid du Colombier 
73e12c5d1SDavid du Colombier void	fatal(int syserr, char *fmt, ...);
83e12c5d1SDavid du Colombier void	openlisten(void);
93e12c5d1SDavid du Colombier 
103e12c5d1SDavid du Colombier int 	dbg;
11*219b2ee8SDavid du Colombier int	restricted;
123e12c5d1SDavid du Colombier int	tftpreq;
133e12c5d1SDavid du Colombier int	tftpaddr;
143e12c5d1SDavid du Colombier int	tftpctl;
153e12c5d1SDavid du Colombier void	openlisten(void);
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*);
233e12c5d1SDavid du Colombier 
243e12c5d1SDavid du Colombier char	mbuf[32768];
253e12c5d1SDavid du Colombier char	raddr[32];
263e12c5d1SDavid du Colombier 
273e12c5d1SDavid du Colombier char	*dir = "/lib/tftpd";
28*219b2ee8SDavid du Colombier char	*dirsl;
29*219b2ee8SDavid du Colombier int	dirsllen;
303e12c5d1SDavid du Colombier char	flog[] = "ipboot";
313e12c5d1SDavid du Colombier 
323e12c5d1SDavid du Colombier enum
333e12c5d1SDavid du Colombier {
343e12c5d1SDavid du Colombier 	Tftp_READ	= 1,
353e12c5d1SDavid du Colombier 	Tftp_WRITE	= 2,
363e12c5d1SDavid du Colombier 	Tftp_DATA	= 3,
373e12c5d1SDavid du Colombier 	Tftp_ACK	= 4,
383e12c5d1SDavid du Colombier 	Tftp_ERROR	= 5,
393e12c5d1SDavid du Colombier 	Segsize		= 512,
403e12c5d1SDavid du Colombier };
413e12c5d1SDavid du Colombier 
423e12c5d1SDavid du Colombier void
433e12c5d1SDavid du Colombier main(int argc, char **argv)
443e12c5d1SDavid du Colombier {
453e12c5d1SDavid du Colombier 	int n, dlen, clen;
463e12c5d1SDavid du Colombier 	char connect[64], buf[64], datadir[64];
473e12c5d1SDavid du Colombier 	char *mode, *p;
483e12c5d1SDavid du Colombier 	short op;
493e12c5d1SDavid du Colombier 	int ctl, data;
503e12c5d1SDavid du Colombier 
513e12c5d1SDavid du Colombier 	ARGBEGIN{
523e12c5d1SDavid du Colombier 	case 'd':
533e12c5d1SDavid du Colombier 		dbg++;
543e12c5d1SDavid du Colombier 		break;
553e12c5d1SDavid du Colombier 	case 'h':
563e12c5d1SDavid du Colombier 		dir = ARGF();
573e12c5d1SDavid du Colombier 		break;
58*219b2ee8SDavid du Colombier 	case 'r':
59*219b2ee8SDavid du Colombier 		restricted = 1;
60*219b2ee8SDavid du Colombier 		break;
613e12c5d1SDavid du Colombier 	default:
62*219b2ee8SDavid du Colombier 		fprint(2, "usage: tftpd [-dr] [-h homedir]\n");
633e12c5d1SDavid du Colombier 		exits("usage");
643e12c5d1SDavid du Colombier 	}ARGEND
653e12c5d1SDavid du Colombier 	USED(argc); USED(argv);
663e12c5d1SDavid du Colombier 
67*219b2ee8SDavid du Colombier 	snprint(buf, sizeof buf, "%s/", dir);
68*219b2ee8SDavid du Colombier 	dirsl = strdup(buf);
69*219b2ee8SDavid du Colombier 	dirsllen = strlen(dirsl);
70*219b2ee8SDavid du Colombier 
713e12c5d1SDavid du Colombier 	fmtinstall('E', eipconv);
723e12c5d1SDavid du Colombier 	fmtinstall('I', eipconv);
733e12c5d1SDavid du Colombier 
743e12c5d1SDavid du Colombier 	if(chdir(dir) < 0)
753e12c5d1SDavid du Colombier 		fatal(1, "cant get to directory %s", dir);
763e12c5d1SDavid du Colombier 
773e12c5d1SDavid du Colombier 	switch(rfork(RFNOTEG|RFPROC|RFFDG)) {
783e12c5d1SDavid du Colombier 	case -1:
793e12c5d1SDavid du Colombier 		fatal(1, "fork");
803e12c5d1SDavid du Colombier 	case 0:
813e12c5d1SDavid du Colombier 		break;
823e12c5d1SDavid du Colombier 	default:
833e12c5d1SDavid du Colombier 		exits(0);
843e12c5d1SDavid du Colombier 	}
853e12c5d1SDavid du Colombier 
863e12c5d1SDavid du Colombier 	syslog(dbg, flog, "started");
873e12c5d1SDavid du Colombier 
883e12c5d1SDavid du Colombier 	openlisten();
893e12c5d1SDavid du Colombier 	setuser();
903e12c5d1SDavid du Colombier 	for(;;) {
913e12c5d1SDavid du Colombier 		dlen = read(tftpreq, mbuf, sizeof(mbuf));
923e12c5d1SDavid du Colombier 		if(dlen < 0)
933e12c5d1SDavid du Colombier 			fatal(1, "listen read");
943e12c5d1SDavid du Colombier 		seek(tftpaddr, 0, 0);
953e12c5d1SDavid du Colombier 		clen = read(tftpaddr, raddr, sizeof(raddr));
963e12c5d1SDavid du Colombier 		if(clen < 0)
973e12c5d1SDavid du Colombier 			fatal(1, "request address read");
983e12c5d1SDavid du Colombier 		raddr[clen-1] = '\0';
993e12c5d1SDavid du Colombier 		clrcon();
1003e12c5d1SDavid du Colombier 
1013e12c5d1SDavid du Colombier 		ctl = open("/net/udp/clone", ORDWR);
1023e12c5d1SDavid du Colombier 		if(ctl < 0)
1033e12c5d1SDavid du Colombier 			fatal(1, "open udp clone");
1043e12c5d1SDavid du Colombier 		n = read(ctl, buf, sizeof(buf));
1053e12c5d1SDavid du Colombier 		if(n < 0)
1063e12c5d1SDavid du Colombier 			fatal(1, "read udp ctl");
1073e12c5d1SDavid du Colombier 		buf[n] = 0;
1083e12c5d1SDavid du Colombier 
1093e12c5d1SDavid du Colombier 		clen = sprint(connect, "connect %s", raddr);
1103e12c5d1SDavid du Colombier 		n = write(ctl, connect, clen);
1113e12c5d1SDavid du Colombier 		if(n < 0)
1123e12c5d1SDavid du Colombier 			fatal(1, "udp %s", raddr);
1133e12c5d1SDavid du Colombier 
1143e12c5d1SDavid du Colombier 		sprint(datadir, "/net/udp/%s/data", buf);
1153e12c5d1SDavid du Colombier 		data = open(datadir, ORDWR);
1163e12c5d1SDavid du Colombier 		if(data < 0)
1173e12c5d1SDavid du Colombier 			fatal(1, "open udp data");
1183e12c5d1SDavid du Colombier 
1193e12c5d1SDavid du Colombier 		close(ctl);
1203e12c5d1SDavid du Colombier 
1213e12c5d1SDavid du Colombier 		dlen -= 2;
1223e12c5d1SDavid du Colombier 		mode = mbuf+2;
1233e12c5d1SDavid du Colombier 		while(*mode != '\0' && dlen--)
1243e12c5d1SDavid du Colombier 			mode++;
1253e12c5d1SDavid du Colombier 		mode++;
1263e12c5d1SDavid du Colombier 		p = mode;
1273e12c5d1SDavid du Colombier 		while(*p && dlen--)
1283e12c5d1SDavid du Colombier 			p++;
1293e12c5d1SDavid du Colombier 		if(dlen == 0) {
1303e12c5d1SDavid du Colombier 			nak(data, 0, "bad tftpmode");
1313e12c5d1SDavid du Colombier 			close(data);
1323e12c5d1SDavid du Colombier 			syslog(dbg, flog, "bad mode %s", raddr);
1333e12c5d1SDavid du Colombier 			continue;
1343e12c5d1SDavid du Colombier 		}
1353e12c5d1SDavid du Colombier 
1363e12c5d1SDavid du Colombier 		op = mbuf[0]<<8 | mbuf[1];
1373e12c5d1SDavid du Colombier 		if(op != Tftp_READ && op != Tftp_WRITE) {
1383e12c5d1SDavid du Colombier 			nak(data, 4, "Illegal TFTP operation");
1393e12c5d1SDavid du Colombier 			close(data);
1403e12c5d1SDavid du Colombier 			syslog(dbg, flog, "bad request %d %s", op, raddr);
1413e12c5d1SDavid du Colombier 			continue;
1423e12c5d1SDavid du Colombier 		}
143*219b2ee8SDavid du Colombier 		if(restricted){
144*219b2ee8SDavid du Colombier 			if(strncmp(mbuf+2, "../", 3) || strstr(mbuf+2, "/../") ||
145*219b2ee8SDavid du Colombier 			  (mbuf[2] == '/' && strncmp(mbuf+2, dirsl, dirsllen)!=0)){
146*219b2ee8SDavid du Colombier 				nak(data, 4, "Permission denied");
147*219b2ee8SDavid du Colombier 				close(data);
148*219b2ee8SDavid du Colombier 				syslog(dbg, flog, "bad request %d %s", op, raddr);
149*219b2ee8SDavid du Colombier 				continue;
150*219b2ee8SDavid du Colombier 			}
151*219b2ee8SDavid du Colombier 		}
1523e12c5d1SDavid du Colombier 		switch(fork()) {
1533e12c5d1SDavid du Colombier 		case -1:
1543e12c5d1SDavid du Colombier 			fatal(1, "fork");
1553e12c5d1SDavid du Colombier 		case 0:
1563e12c5d1SDavid du Colombier 			if(op == Tftp_READ)
1573e12c5d1SDavid du Colombier 				sendfile(data, mbuf+2, mode);
1583e12c5d1SDavid du Colombier 			else
1593e12c5d1SDavid du Colombier 				recvfile(data, mbuf+2, mode);
1603e12c5d1SDavid du Colombier 			exits("done");
1613e12c5d1SDavid du Colombier 		default:
1623e12c5d1SDavid du Colombier 			close(data);
1633e12c5d1SDavid du Colombier 		}
1643e12c5d1SDavid du Colombier 	}
1653e12c5d1SDavid du Colombier }
1663e12c5d1SDavid du Colombier 
1673e12c5d1SDavid du Colombier void
1683e12c5d1SDavid du Colombier catcher(void *junk, char *msg)
1693e12c5d1SDavid du Colombier {
1703e12c5d1SDavid du Colombier 	USED(junk);
1713e12c5d1SDavid du Colombier 
1723e12c5d1SDavid du Colombier 	if(strncmp(msg, "exit", 4) == 0)
1733e12c5d1SDavid du Colombier 		noted(NDFLT);
1743e12c5d1SDavid du Colombier 	noted(NCONT);
1753e12c5d1SDavid du Colombier }
1763e12c5d1SDavid du Colombier 
1773e12c5d1SDavid du Colombier void
1783e12c5d1SDavid du Colombier sendfile(int fd, char *name, char *mode)
1793e12c5d1SDavid du Colombier {
1803e12c5d1SDavid du Colombier 	int file;
1813e12c5d1SDavid du Colombier 	uchar buf[Segsize+4];
1823e12c5d1SDavid du Colombier 	uchar ack[1024];
1833e12c5d1SDavid du Colombier 	char errbuf[ERRLEN];
1843e12c5d1SDavid du Colombier 	int ackblock, block, ret;
1853e12c5d1SDavid du Colombier 	int rexmit, n, al, txtry, rxl;
1863e12c5d1SDavid du Colombier 	short op;
1873e12c5d1SDavid du Colombier 
1883e12c5d1SDavid du Colombier 	syslog(dbg, flog, "send file '%s' %s to %s", name, mode, raddr);
1893e12c5d1SDavid du Colombier 	name = sunkernel(name);
1903e12c5d1SDavid du Colombier 	if(name == 0){
1913e12c5d1SDavid du Colombier 		nak(fd, 0, "not in our database");
1923e12c5d1SDavid du Colombier 		return;
1933e12c5d1SDavid du Colombier 	}
1943e12c5d1SDavid du Colombier 
1953e12c5d1SDavid du Colombier 	notify(catcher);
1963e12c5d1SDavid du Colombier 
1973e12c5d1SDavid du Colombier 	file = open(name, OREAD);
1983e12c5d1SDavid du Colombier 	if(file < 0) {
1993e12c5d1SDavid du Colombier 		errstr(errbuf);
2003e12c5d1SDavid du Colombier 		nak(fd, 0, errbuf);
2013e12c5d1SDavid du Colombier 		return;
2023e12c5d1SDavid du Colombier 	}
2033e12c5d1SDavid du Colombier 	block = 0;
2043e12c5d1SDavid du Colombier 	rexmit = 0;
2053e12c5d1SDavid du Colombier 	n = 0;
206*219b2ee8SDavid du Colombier 	for(txtry = 0; txtry < 5;) {
2073e12c5d1SDavid du Colombier 		if(rexmit == 0) {
2083e12c5d1SDavid du Colombier 			block++;
2093e12c5d1SDavid du Colombier 			buf[0] = 0;
2103e12c5d1SDavid du Colombier 			buf[1] = Tftp_DATA;
2113e12c5d1SDavid du Colombier 			buf[2] = block>>8;
2123e12c5d1SDavid du Colombier 			buf[3] = block;
2133e12c5d1SDavid du Colombier 			n = read(file, buf+4, Segsize);
2143e12c5d1SDavid du Colombier 			if(n < 0) {
2153e12c5d1SDavid du Colombier 				errstr(errbuf);
2163e12c5d1SDavid du Colombier 				nak(fd, 0, errbuf);
2173e12c5d1SDavid du Colombier 				return;
2183e12c5d1SDavid du Colombier 			}
219*219b2ee8SDavid du Colombier 			txtry = 0;
2203e12c5d1SDavid du Colombier 		}
2213e12c5d1SDavid du Colombier 		else
2223e12c5d1SDavid du Colombier 			txtry++;
2233e12c5d1SDavid du Colombier 		ret = write(fd, buf, 4+n);
2243e12c5d1SDavid du Colombier 		if(ret < 0)
2253e12c5d1SDavid du Colombier 			fatal(1, "tftp: network write error");
2263e12c5d1SDavid du Colombier 
2273e12c5d1SDavid du Colombier 		for(rxl = 0; rxl < 10; rxl++) {
2283e12c5d1SDavid du Colombier 			rexmit = 0;
229*219b2ee8SDavid du Colombier 			alarm(500);
2303e12c5d1SDavid du Colombier 			al = read(fd, ack, sizeof(ack));
2313e12c5d1SDavid du Colombier 			alarm(0);
2323e12c5d1SDavid du Colombier 			if(al < 0) {
2333e12c5d1SDavid du Colombier 				rexmit = 1;
2343e12c5d1SDavid du Colombier 				break;
2353e12c5d1SDavid du Colombier 			}
2363e12c5d1SDavid du Colombier 			op = ack[0]<<8|ack[1];
2373e12c5d1SDavid du Colombier 			if(op == Tftp_ERROR)
2383e12c5d1SDavid du Colombier 				goto error;
2393e12c5d1SDavid du Colombier 			ackblock = ack[2]<<8|ack[3];
2403e12c5d1SDavid du Colombier 			if(ackblock == block)
2413e12c5d1SDavid du Colombier 				break;
2423e12c5d1SDavid du Colombier 			if(ackblock == 0xffff) {
2433e12c5d1SDavid du Colombier 				rexmit = 1;
2443e12c5d1SDavid du Colombier 				break;
2453e12c5d1SDavid du Colombier 			}
2463e12c5d1SDavid du Colombier 		}
2473e12c5d1SDavid du Colombier 		if(ret != Segsize+4 && rexmit == 0)
2483e12c5d1SDavid du Colombier 			break;
2493e12c5d1SDavid du Colombier 	}
2503e12c5d1SDavid du Colombier error:
2513e12c5d1SDavid du Colombier 	close(fd);
2523e12c5d1SDavid du Colombier 	close(file);
2533e12c5d1SDavid du Colombier }
2543e12c5d1SDavid du Colombier 
2553e12c5d1SDavid du Colombier void
2563e12c5d1SDavid du Colombier recvfile(int fd, char *name, char *mode)
2573e12c5d1SDavid du Colombier {
2583e12c5d1SDavid du Colombier 	ushort op, block, inblock;
2593e12c5d1SDavid du Colombier 	uchar buf[Segsize+8];
2603e12c5d1SDavid du Colombier 	char errbuf[ERRLEN];
2613e12c5d1SDavid du Colombier 	int n, ret, file;
2623e12c5d1SDavid du Colombier 
2633e12c5d1SDavid du Colombier 	syslog(dbg, flog, "receive file '%s' %s from %s", name, mode, raddr);
2643e12c5d1SDavid du Colombier 
2653e12c5d1SDavid du Colombier 	file = create(name, OWRITE, 0666);
2663e12c5d1SDavid du Colombier 	if(file < 0) {
2673e12c5d1SDavid du Colombier 		errstr(errbuf);
2683e12c5d1SDavid du Colombier 		nak(fd, 0, errbuf);
2693e12c5d1SDavid du Colombier 		return;
2703e12c5d1SDavid du Colombier 	}
2713e12c5d1SDavid du Colombier 
2723e12c5d1SDavid du Colombier 	block = 0;
2733e12c5d1SDavid du Colombier 	ack(fd, block);
2743e12c5d1SDavid du Colombier 	block++;
2753e12c5d1SDavid du Colombier 
2763e12c5d1SDavid du Colombier 	for(;;) {
2773e12c5d1SDavid du Colombier 		alarm(15000);
2783e12c5d1SDavid du Colombier 		n = read(fd, buf, sizeof(buf));
2793e12c5d1SDavid du Colombier 		alarm(0);
2803e12c5d1SDavid du Colombier 		if(n < 0)
2813e12c5d1SDavid du Colombier 			goto error;
2823e12c5d1SDavid du Colombier 		op = buf[0]<<8|buf[1];
2833e12c5d1SDavid du Colombier 		if(op == Tftp_ERROR)
2843e12c5d1SDavid du Colombier 			goto error;
2853e12c5d1SDavid du Colombier 
2863e12c5d1SDavid du Colombier 		n -= 4;
2873e12c5d1SDavid du Colombier 		inblock = buf[2]<<8|buf[3];
2883e12c5d1SDavid du Colombier 		if(op == Tftp_DATA) {
2893e12c5d1SDavid du Colombier 			if(inblock == block) {
2903e12c5d1SDavid du Colombier 				ret = write(file, buf, n);
2913e12c5d1SDavid du Colombier 				if(ret < 0) {
2923e12c5d1SDavid du Colombier 					errstr(errbuf);
2933e12c5d1SDavid du Colombier 					nak(fd, 0, errbuf);
2943e12c5d1SDavid du Colombier 					goto error;
2953e12c5d1SDavid du Colombier 				}
2963e12c5d1SDavid du Colombier 				ack(fd, block);
2973e12c5d1SDavid du Colombier 				block++;
2983e12c5d1SDavid du Colombier 			}
2993e12c5d1SDavid du Colombier 			ack(fd, 0xffff);
3003e12c5d1SDavid du Colombier 		}
3013e12c5d1SDavid du Colombier 	}
3023e12c5d1SDavid du Colombier error:
3033e12c5d1SDavid du Colombier 	close(file);
3043e12c5d1SDavid du Colombier }
3053e12c5d1SDavid du Colombier 
3063e12c5d1SDavid du Colombier void
3073e12c5d1SDavid du Colombier ack(int fd, ushort block)
3083e12c5d1SDavid du Colombier {
3093e12c5d1SDavid du Colombier 	uchar ack[4];
3103e12c5d1SDavid du Colombier 	int n;
3113e12c5d1SDavid du Colombier 
3123e12c5d1SDavid du Colombier 	ack[0] = 0;
3133e12c5d1SDavid du Colombier 	ack[1] = Tftp_ACK;
3143e12c5d1SDavid du Colombier 	ack[2] = block>>8;
3153e12c5d1SDavid du Colombier 	ack[3] = block;
3163e12c5d1SDavid du Colombier 
3173e12c5d1SDavid du Colombier 	n = write(fd, ack, 4);
3183e12c5d1SDavid du Colombier 	if(n < 0)
3193e12c5d1SDavid du Colombier 		fatal(1, "network write");
3203e12c5d1SDavid du Colombier }
3213e12c5d1SDavid du Colombier 
3223e12c5d1SDavid du Colombier void
3233e12c5d1SDavid du Colombier nak(int fd, int code, char *msg)
3243e12c5d1SDavid du Colombier {
3253e12c5d1SDavid du Colombier 	char buf[128];
3263e12c5d1SDavid du Colombier 	int n;
3273e12c5d1SDavid du Colombier 
3283e12c5d1SDavid du Colombier 	buf[0] = 0;
3293e12c5d1SDavid du Colombier 	buf[1] = Tftp_ERROR;
3303e12c5d1SDavid du Colombier 	buf[2] = 0;
3313e12c5d1SDavid du Colombier 	buf[3] = code;
3323e12c5d1SDavid du Colombier 	strcpy(buf+4, msg);
3333e12c5d1SDavid du Colombier 	n = strlen(msg) + 4 + 1;
3343e12c5d1SDavid du Colombier 	n = write(fd, buf, n);
3353e12c5d1SDavid du Colombier 	if(n < 0)
3363e12c5d1SDavid du Colombier 		fatal(1, "write nak");
3373e12c5d1SDavid du Colombier }
3383e12c5d1SDavid du Colombier 
3393e12c5d1SDavid du Colombier void
3403e12c5d1SDavid du Colombier fatal(int syserr, char *fmt, ...)
3413e12c5d1SDavid du Colombier {
3423e12c5d1SDavid du Colombier 	char buf[ERRLEN], sysbuf[ERRLEN];
3433e12c5d1SDavid du Colombier 
3443e12c5d1SDavid du Colombier 	doprint(buf, buf+sizeof(buf), fmt, (&fmt+1));
3453e12c5d1SDavid du Colombier 	if(syserr) {
3463e12c5d1SDavid du Colombier 		errstr(sysbuf);
3473e12c5d1SDavid du Colombier 		fprint(2, "tftpd: %s: %s\n", buf, sysbuf);
3483e12c5d1SDavid du Colombier 	}
3493e12c5d1SDavid du Colombier 	else
3503e12c5d1SDavid du Colombier 		fprint(2, "tftpd: %s\n", buf);
3513e12c5d1SDavid du Colombier 	exits(buf);
3523e12c5d1SDavid du Colombier }
3533e12c5d1SDavid du Colombier 
3543e12c5d1SDavid du Colombier void
3553e12c5d1SDavid du Colombier openlisten(void)
3563e12c5d1SDavid du Colombier {
3573e12c5d1SDavid du Colombier 	char buf[128], data[128];
3583e12c5d1SDavid du Colombier 	int n;
3593e12c5d1SDavid du Colombier 
3603e12c5d1SDavid du Colombier 	tftpctl = open("/net/udp/clone", ORDWR);
3613e12c5d1SDavid du Colombier 	if(tftpctl < 0)
3623e12c5d1SDavid du Colombier 		fatal(1, "open udp clone");
3633e12c5d1SDavid du Colombier 
3643e12c5d1SDavid du Colombier 	n = read(tftpctl, buf, sizeof(buf));
3653e12c5d1SDavid du Colombier 	if(n < 0)
3663e12c5d1SDavid du Colombier 		fatal(1, "read clone");
3673e12c5d1SDavid du Colombier 	buf[n] = 0;
3683e12c5d1SDavid du Colombier 
3693e12c5d1SDavid du Colombier 	n = write(tftpctl, "announce 69", sizeof("announce 69"));
3703e12c5d1SDavid du Colombier 	if(n < 0)
3713e12c5d1SDavid du Colombier 		fatal(1, "can't announce");
3723e12c5d1SDavid du Colombier 
3733e12c5d1SDavid du Colombier 	sprint(data, "/net/udp/%s/data", buf);
3743e12c5d1SDavid du Colombier 
3753e12c5d1SDavid du Colombier 	tftpreq = open(data, ORDWR);
3763e12c5d1SDavid du Colombier 	if(tftpreq < 0)
3773e12c5d1SDavid du Colombier 		fatal(1, "open udp/data");
3783e12c5d1SDavid du Colombier 
3793e12c5d1SDavid du Colombier 	sprint(data, "/net/udp/%s/remote", buf);
3803e12c5d1SDavid du Colombier 	tftpaddr = open(data, OREAD);
3813e12c5d1SDavid du Colombier 	if(tftpaddr < 0)
3823e12c5d1SDavid du Colombier 		fatal(1, "open udp/remote");
3833e12c5d1SDavid du Colombier 
3843e12c5d1SDavid du Colombier }
3853e12c5d1SDavid du Colombier 
3863e12c5d1SDavid du Colombier void
3873e12c5d1SDavid du Colombier clrcon(void)
3883e12c5d1SDavid du Colombier {
3893e12c5d1SDavid du Colombier 	int n;
3903e12c5d1SDavid du Colombier 
3913e12c5d1SDavid du Colombier 	n = write(tftpctl, "connect 0.0.0.0!0!r", sizeof("connect 0.0.0.0!0!r"));
3923e12c5d1SDavid du Colombier 	if(n < 0)
3933e12c5d1SDavid du Colombier 		fatal(1, "clear connect");
3943e12c5d1SDavid du Colombier }
3953e12c5d1SDavid du Colombier 
3963e12c5d1SDavid du Colombier void
3973e12c5d1SDavid du Colombier setuser(void)
3983e12c5d1SDavid du Colombier {
3993e12c5d1SDavid du Colombier 	int f;
4003e12c5d1SDavid du Colombier 
4013e12c5d1SDavid du Colombier 	f = open("/dev/user", OWRITE);
4023e12c5d1SDavid du Colombier 	if(f < 0)
4033e12c5d1SDavid du Colombier 		return;
4043e12c5d1SDavid du Colombier 	write(f, "none", sizeof("none"));
4053e12c5d1SDavid du Colombier 	close(f);
4063e12c5d1SDavid du Colombier }
4073e12c5d1SDavid du Colombier 
4083e12c5d1SDavid du Colombier /*
4093e12c5d1SDavid du Colombier  *  for sun kernel boots, replace the requested file name with
4103e12c5d1SDavid du Colombier  *  a one from our database.  If the database doesn't specify a file,
4113e12c5d1SDavid du Colombier  *  don't answer.
4123e12c5d1SDavid du Colombier  */
4133e12c5d1SDavid du Colombier char*
4143e12c5d1SDavid du Colombier sunkernel(char *name)
4153e12c5d1SDavid du Colombier {
4163e12c5d1SDavid du Colombier 	ulong addr;
4173e12c5d1SDavid du Colombier 	uchar ipaddr[4];
4183e12c5d1SDavid du Colombier 	char buf[32];
4193e12c5d1SDavid du Colombier 	static Ipinfo info;
4203e12c5d1SDavid du Colombier 	static Ndb *db;
4213e12c5d1SDavid du Colombier 
422*219b2ee8SDavid du Colombier 	if(strlen(name) != 14 || strncmp(name + 8, ".SUN", 4) != 0)
4233e12c5d1SDavid du Colombier 		return name;
4243e12c5d1SDavid du Colombier 
4253e12c5d1SDavid du Colombier 	addr = strtoul(name, 0, 16);
4263e12c5d1SDavid du Colombier 	ipaddr[0] = addr>>24;
4273e12c5d1SDavid du Colombier 	ipaddr[1] = addr>>16;
4283e12c5d1SDavid du Colombier 	ipaddr[2] = addr>>8;
4293e12c5d1SDavid du Colombier 	ipaddr[3] = addr;
4303e12c5d1SDavid du Colombier 	sprint(buf, "%I", ipaddr);
4313e12c5d1SDavid du Colombier 	if(db == 0)
4323e12c5d1SDavid du Colombier 		db = ndbopen(0);
4333e12c5d1SDavid du Colombier 	if(db == 0)
4343e12c5d1SDavid du Colombier 		return 0;
4353e12c5d1SDavid du Colombier 	if(ipinfo(db, 0, buf, 0, &info) < 0)
4363e12c5d1SDavid du Colombier 		return 0;
4373e12c5d1SDavid du Colombier 	if(info.bootf[0])
4383e12c5d1SDavid du Colombier 		return info.bootf;
4393e12c5d1SDavid du Colombier 	return 0;
4403e12c5d1SDavid du Colombier }
441