xref: /plan9/sys/src/cmd/con/con.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
13e12c5d1SDavid du Colombier #include <u.h>
23e12c5d1SDavid du Colombier #include <libc.h>
33e12c5d1SDavid du Colombier 
43e12c5d1SDavid du Colombier #include "rustream.h"
53e12c5d1SDavid du Colombier #include "ruttyio.h"
63e12c5d1SDavid du Colombier #include "rusignal.h"
73e12c5d1SDavid du Colombier #include "rufilio.h"
83e12c5d1SDavid du Colombier 
93e12c5d1SDavid du Colombier int debug;		/* true if debugging */
103e12c5d1SDavid du Colombier int ctl = -1;		/* control fd (for break's) */
113e12c5d1SDavid du Colombier int raw;		/* true if raw is on */
123e12c5d1SDavid du Colombier int consctl = -1;	/* control fd for cons */
133e12c5d1SDavid du Colombier int ttypid;		/* pid's if the 2 processes (used to kill them) */
143e12c5d1SDavid du Colombier int msgfd = -1;		/* mesgld file descriptor (for signals to be written to) */
153e12c5d1SDavid du Colombier int outfd = 1;		/* local output file descriptor */
163e12c5d1SDavid du Colombier int cooked;		/* non-zero forces cooked mode */
173e12c5d1SDavid du Colombier int returns;		/* non-zero forces carriage returns not to be filtered out */
18*219b2ee8SDavid du Colombier int	strip;		/* strip off parity bits */
193e12c5d1SDavid du Colombier char firsterr[2*ERRLEN];
203e12c5d1SDavid du Colombier char transerr[2*ERRLEN];
213e12c5d1SDavid du Colombier int limited;
223e12c5d1SDavid du Colombier char *remuser;
233e12c5d1SDavid du Colombier int verbose;
24*219b2ee8SDavid du Colombier int baud;
253e12c5d1SDavid du Colombier 
263e12c5d1SDavid du Colombier typedef struct Msg Msg;
27*219b2ee8SDavid du Colombier #define MAXMSG (2*8192)
283e12c5d1SDavid du Colombier 
293e12c5d1SDavid du Colombier int	dkauth(int);
303e12c5d1SDavid du Colombier int	dodial(char*, char*, char*);
313e12c5d1SDavid du Colombier void	fromkbd(int);
323e12c5d1SDavid du Colombier void	fromnet(int);
333e12c5d1SDavid du Colombier long	iread(int, void*, int);
343e12c5d1SDavid du Colombier long	iwrite(int, void*, int);
353e12c5d1SDavid du Colombier int	menu(int);
363e12c5d1SDavid du Colombier void	msgfromkbd(int);
373e12c5d1SDavid du Colombier void	msgfromnet(int);
383e12c5d1SDavid du Colombier void	msgnotifyf(void*, char*);
393e12c5d1SDavid du Colombier int	msgwrite(int, void*, int);
403e12c5d1SDavid du Colombier void	notifyf(void*, char*);
413e12c5d1SDavid du Colombier void	pass(int, int, int);
423e12c5d1SDavid du Colombier void	rawoff(void);
433e12c5d1SDavid du Colombier void	rawon(void);
443e12c5d1SDavid du Colombier int	readupto(int, char*, int);
453e12c5d1SDavid du Colombier int	sendctl(int, int);
463e12c5d1SDavid du Colombier int	sendctl1(int, int, int);
473e12c5d1SDavid du Colombier void	stdcon(int);
483e12c5d1SDavid du Colombier char*	system(int, char*);
493e12c5d1SDavid du Colombier void	dosystem(int, char*);
503e12c5d1SDavid du Colombier int	wasintr(void);
513e12c5d1SDavid du Colombier void	punt(char*);
523e12c5d1SDavid du Colombier char*	syserr(void);
53*219b2ee8SDavid du Colombier void	seterr(char*);
543e12c5d1SDavid du Colombier 
553e12c5d1SDavid du Colombier /* protocols */
563e12c5d1SDavid du Colombier void	dcon(char*, char*);
573e12c5d1SDavid du Colombier void	device(char*, char*);
583e12c5d1SDavid du Colombier void	mesgdcon(char*, char*);
593e12c5d1SDavid du Colombier void	rlogin(char*, char*);
603e12c5d1SDavid du Colombier void	simple(char*, char*);
613e12c5d1SDavid du Colombier 
623e12c5d1SDavid du Colombier void
633e12c5d1SDavid du Colombier usage(void)
643e12c5d1SDavid du Colombier {
65*219b2ee8SDavid du Colombier 	punt("usage: con [-drCvs] [-l [user]] [-c cmd] net!host[!service]");
663e12c5d1SDavid du Colombier }
673e12c5d1SDavid du Colombier 
683e12c5d1SDavid du Colombier void
693e12c5d1SDavid du Colombier main(int argc, char *argv[])
703e12c5d1SDavid du Colombier {
713e12c5d1SDavid du Colombier 	char *dest;
723e12c5d1SDavid du Colombier 	char *cmd = 0;
733e12c5d1SDavid du Colombier 
743e12c5d1SDavid du Colombier 	returns = 1;
753e12c5d1SDavid du Colombier 	ARGBEGIN{
76*219b2ee8SDavid du Colombier 	case 'b':
77*219b2ee8SDavid du Colombier 		baud = atoi(ARGF());
78*219b2ee8SDavid du Colombier 		break;
793e12c5d1SDavid du Colombier 	case 'd':
803e12c5d1SDavid du Colombier 		debug = 1;
813e12c5d1SDavid du Colombier 		break;
823e12c5d1SDavid du Colombier 	case 'l':
833e12c5d1SDavid du Colombier 		limited = 1;
843e12c5d1SDavid du Colombier 		if(argv[1][0] != '-')
853e12c5d1SDavid du Colombier 			remuser = ARGF();
863e12c5d1SDavid du Colombier 		break;
873e12c5d1SDavid du Colombier 	case 'r':
883e12c5d1SDavid du Colombier 		returns = 0;
893e12c5d1SDavid du Colombier 		break;
903e12c5d1SDavid du Colombier 	case 'C':
913e12c5d1SDavid du Colombier 		cooked = 1;
923e12c5d1SDavid du Colombier 		break;
933e12c5d1SDavid du Colombier 	case 'c':
943e12c5d1SDavid du Colombier 		cmd = ARGF();
953e12c5d1SDavid du Colombier 		break;
963e12c5d1SDavid du Colombier 	case 'v':
973e12c5d1SDavid du Colombier 		verbose = 1;
983e12c5d1SDavid du Colombier 		break;
99*219b2ee8SDavid du Colombier 	case 's':
100*219b2ee8SDavid du Colombier 		strip = 1;
101*219b2ee8SDavid du Colombier 		break;
1023e12c5d1SDavid du Colombier 	default:
1033e12c5d1SDavid du Colombier 		usage();
1043e12c5d1SDavid du Colombier 	}ARGEND
1053e12c5d1SDavid du Colombier 
1063e12c5d1SDavid du Colombier 	if(argc != 1){
1073e12c5d1SDavid du Colombier 		if(remuser == 0)
1083e12c5d1SDavid du Colombier 			usage();
1093e12c5d1SDavid du Colombier 		dest = remuser;
1103e12c5d1SDavid du Colombier 		remuser = 0;
1113e12c5d1SDavid du Colombier 	} else
1123e12c5d1SDavid du Colombier 		dest = argv[0];
1133e12c5d1SDavid du Colombier 	if(*dest == '/')
1143e12c5d1SDavid du Colombier 		device(dest, cmd);
1153e12c5d1SDavid du Colombier 	else if(limited){
1163e12c5d1SDavid du Colombier 		simple(dest, cmd);	/* doesn't return if dialout succeeds */
1173e12c5d1SDavid du Colombier 		rlogin(dest, cmd);	/* doesn't return if dialout succeeds */
1183e12c5d1SDavid du Colombier 	} else {
119*219b2ee8SDavid du Colombier 		rlogin(dest, cmd);	/* doesn't return if dialout succeeds */
1203e12c5d1SDavid du Colombier 		mesgdcon(dest, cmd);	/* doesn't return if dialout succeeds */
1213e12c5d1SDavid du Colombier 		dcon(dest, cmd);	/* doesn't return if dialout succeeds */
1223e12c5d1SDavid du Colombier 		simple(dest, cmd);	/* doesn't return if dialout succeeds */
1233e12c5d1SDavid du Colombier 	}
1243e12c5d1SDavid du Colombier 	punt(firsterr);
1253e12c5d1SDavid du Colombier }
1263e12c5d1SDavid du Colombier 
1273e12c5d1SDavid du Colombier /*
1283e12c5d1SDavid du Colombier  *  just dial and use as a byte stream with remote echo
1293e12c5d1SDavid du Colombier  */
1303e12c5d1SDavid du Colombier void
1313e12c5d1SDavid du Colombier simple(char *dest, char *cmd)
1323e12c5d1SDavid du Colombier {
1333e12c5d1SDavid du Colombier 	int net;
1343e12c5d1SDavid du Colombier 
1353e12c5d1SDavid du Colombier 	net = dodial(dest, 0, 0);
1363e12c5d1SDavid du Colombier 	if(net < 0)
1373e12c5d1SDavid du Colombier 		return;
1383e12c5d1SDavid du Colombier 
1393e12c5d1SDavid du Colombier 	if(cmd)
1403e12c5d1SDavid du Colombier 		dosystem(net, cmd);
1413e12c5d1SDavid du Colombier 
1423e12c5d1SDavid du Colombier 	if(!cooked)
1433e12c5d1SDavid du Colombier 		rawon();
1443e12c5d1SDavid du Colombier 	stdcon(net);
1453e12c5d1SDavid du Colombier 	exits(0);
1463e12c5d1SDavid du Colombier }
1473e12c5d1SDavid du Colombier 
1483e12c5d1SDavid du Colombier /*
1493e12c5d1SDavid du Colombier  *  dial, do UCB authentication, use as a byte stream with local echo
1503e12c5d1SDavid du Colombier  *
1513e12c5d1SDavid du Colombier  *  return if dial failed
1523e12c5d1SDavid du Colombier  */
1533e12c5d1SDavid du Colombier void
1543e12c5d1SDavid du Colombier rlogin(char *dest, char *cmd)
1553e12c5d1SDavid du Colombier {
1563e12c5d1SDavid du Colombier 	int net, fd;
1573e12c5d1SDavid du Colombier 	long n;
1583e12c5d1SDavid du Colombier 	char buf[2*NAMELEN];
1593e12c5d1SDavid du Colombier 	char *p;
1603e12c5d1SDavid du Colombier 	char *localuser;
1613e12c5d1SDavid du Colombier 
1623e12c5d1SDavid du Colombier 	/* only useful on TCP */
163bd389b36SDavid du Colombier 	if(strchr(dest, '!')
164bd389b36SDavid du Colombier 	&& (strncmp(dest, "tcp!", 4)!=0 && strncmp(dest, "net!", 4)!=0))
1653e12c5d1SDavid du Colombier 		return;
1663e12c5d1SDavid du Colombier 
1673e12c5d1SDavid du Colombier 	net = dodial(dest, "tcp", "login");
1683e12c5d1SDavid du Colombier 	if(net < 0)
1693e12c5d1SDavid du Colombier 		return;
1703e12c5d1SDavid du Colombier 
1713e12c5d1SDavid du Colombier 	/*
1723e12c5d1SDavid du Colombier 	 *  do UCB rlogin authentication
1733e12c5d1SDavid du Colombier 	 */
1743e12c5d1SDavid du Colombier 	fd = open("/dev/user", OREAD);
1753e12c5d1SDavid du Colombier 	n = read(fd, buf, sizeof(buf));
1763e12c5d1SDavid du Colombier 	close(fd);
1773e12c5d1SDavid du Colombier 	buf[n] = 0;
1783e12c5d1SDavid du Colombier 	localuser = buf;
1793e12c5d1SDavid du Colombier 	if(remuser == 0){
1803e12c5d1SDavid du Colombier 		if(limited)
1813e12c5d1SDavid du Colombier 			remuser = ":";
1823e12c5d1SDavid du Colombier 		else
1833e12c5d1SDavid du Colombier 			remuser = localuser;
1843e12c5d1SDavid du Colombier 	}
1853e12c5d1SDavid du Colombier 	p = getenv("TERM");
1863e12c5d1SDavid du Colombier 	if(p == 0)
1873e12c5d1SDavid du Colombier 		p = "p9";
1883e12c5d1SDavid du Colombier 	if(write(net, "", 1)<0
1893e12c5d1SDavid du Colombier 	|| write(net, localuser, strlen(localuser)+1)<0
1903e12c5d1SDavid du Colombier 	|| write(net, remuser, strlen(remuser)+1)<0
1913e12c5d1SDavid du Colombier 	|| write(net, p, strlen(p)+1)<0){
1923e12c5d1SDavid du Colombier 		close(net);
1933e12c5d1SDavid du Colombier 		punt("BSD authentication failed");
1943e12c5d1SDavid du Colombier 	}
1953e12c5d1SDavid du Colombier 	if(read(net, buf, 1) != 1)
1963e12c5d1SDavid du Colombier 		punt("BSD authentication failed1");
1973e12c5d1SDavid du Colombier 	if(buf[0] != 0){
1983e12c5d1SDavid du Colombier 		fprint(2, "con: remote error: ");
1993e12c5d1SDavid du Colombier 		while(read(net, buf, 1) == 1){
2003e12c5d1SDavid du Colombier 			write(2, buf, 1);
2013e12c5d1SDavid du Colombier 			if(buf[0] == '\n')
2023e12c5d1SDavid du Colombier 				break;
2033e12c5d1SDavid du Colombier 		}
2043e12c5d1SDavid du Colombier 		exits("read");
2053e12c5d1SDavid du Colombier 	}
2063e12c5d1SDavid du Colombier 
2073e12c5d1SDavid du Colombier 	if(cmd)
2083e12c5d1SDavid du Colombier 		dosystem(net, cmd);
2093e12c5d1SDavid du Colombier 
2103e12c5d1SDavid du Colombier 	if(!cooked)
2113e12c5d1SDavid du Colombier 		rawon();
2123e12c5d1SDavid du Colombier 	stdcon(net);
2133e12c5d1SDavid du Colombier 	exits(0);
2143e12c5d1SDavid du Colombier }
2153e12c5d1SDavid du Colombier 
2163e12c5d1SDavid du Colombier /*
2173e12c5d1SDavid du Colombier  *  dial, do DK authentication, use as a byte stream with remote echo
2183e12c5d1SDavid du Colombier  *
2193e12c5d1SDavid du Colombier  *  return if dial failed
2203e12c5d1SDavid du Colombier  */
2213e12c5d1SDavid du Colombier void
2223e12c5d1SDavid du Colombier dcon(char *dest, char *cmd)
2233e12c5d1SDavid du Colombier {
2243e12c5d1SDavid du Colombier 	int net;
2253e12c5d1SDavid du Colombier 
2263e12c5d1SDavid du Colombier 	net = dodial(dest, 0, "dcon");
2273e12c5d1SDavid du Colombier 	if(net < 0)
2283e12c5d1SDavid du Colombier 		return;
2293e12c5d1SDavid du Colombier 
2303e12c5d1SDavid du Colombier 	if(dkauth(net) < 0)
2313e12c5d1SDavid du Colombier 		punt("can't authenticate across datakit");
2323e12c5d1SDavid du Colombier 
2333e12c5d1SDavid du Colombier 	if(cmd)
2343e12c5d1SDavid du Colombier 		dosystem(net, cmd);
2353e12c5d1SDavid du Colombier 
2363e12c5d1SDavid du Colombier 	if(!cooked)
2373e12c5d1SDavid du Colombier 		rawon();
2383e12c5d1SDavid du Colombier 	stdcon(net);
2393e12c5d1SDavid du Colombier 	exits(0);
2403e12c5d1SDavid du Colombier }
2413e12c5d1SDavid du Colombier 
2423e12c5d1SDavid du Colombier /*
2433e12c5d1SDavid du Colombier  *  just open a device and use it as a connection
2443e12c5d1SDavid du Colombier  */
2453e12c5d1SDavid du Colombier void
2463e12c5d1SDavid du Colombier device(char *dest, char *cmd)
2473e12c5d1SDavid du Colombier {
2483e12c5d1SDavid du Colombier 	int net;
2493e12c5d1SDavid du Colombier 	char cname[3*NAMELEN];
2503e12c5d1SDavid du Colombier 
2513e12c5d1SDavid du Colombier 	net = open(dest, ORDWR);
2523e12c5d1SDavid du Colombier 	if(net < 0)
253*219b2ee8SDavid du Colombier 		punt(syserr());
2543e12c5d1SDavid du Colombier 	sprint(cname, "%sctl", dest);
2553e12c5d1SDavid du Colombier 	ctl = open(cname, ORDWR);
256*219b2ee8SDavid du Colombier 	if(ctl >= 0 && baud > 0)
257*219b2ee8SDavid du Colombier 		fprint(ctl, "b%d", baud);
2583e12c5d1SDavid du Colombier 
2593e12c5d1SDavid du Colombier 	if(cmd)
2603e12c5d1SDavid du Colombier 		dosystem(net, cmd);
2613e12c5d1SDavid du Colombier 
2623e12c5d1SDavid du Colombier 	if(!cooked)
2633e12c5d1SDavid du Colombier 		rawon();
2643e12c5d1SDavid du Colombier 	stdcon(net);
2653e12c5d1SDavid du Colombier 	exits(0);
2663e12c5d1SDavid du Colombier }
2673e12c5d1SDavid du Colombier 
2683e12c5d1SDavid du Colombier /*
2693e12c5d1SDavid du Colombier  *  ignore interrupts
2703e12c5d1SDavid du Colombier  */
2713e12c5d1SDavid du Colombier void
2723e12c5d1SDavid du Colombier notifyf(void *a, char *msg)
2733e12c5d1SDavid du Colombier {
2743e12c5d1SDavid du Colombier 	USED(a);
2753e12c5d1SDavid du Colombier 
2763e12c5d1SDavid du Colombier 	if(strstr(msg, "closed pipe")
2773e12c5d1SDavid du Colombier 	|| strcmp(msg, "interrupt") == 0
2783e12c5d1SDavid du Colombier 	|| strcmp(msg, "hangup") == 0)
2793e12c5d1SDavid du Colombier 		noted(NCONT);
2803e12c5d1SDavid du Colombier 	noted(NDFLT);
2813e12c5d1SDavid du Colombier }
2823e12c5d1SDavid du Colombier 
2833e12c5d1SDavid du Colombier /*
2843e12c5d1SDavid du Colombier  *  turn keyboard raw mode on
2853e12c5d1SDavid du Colombier  */
2863e12c5d1SDavid du Colombier void
2873e12c5d1SDavid du Colombier rawon(void)
2883e12c5d1SDavid du Colombier {
2893e12c5d1SDavid du Colombier 	if(debug)
2903e12c5d1SDavid du Colombier 		fprint(2, "rawon\n");
2913e12c5d1SDavid du Colombier 	if(raw)
2923e12c5d1SDavid du Colombier 		return;
2933e12c5d1SDavid du Colombier 	if(consctl < 0)
2943e12c5d1SDavid du Colombier 		consctl = open("/dev/consctl", OWRITE);
2953e12c5d1SDavid du Colombier 	if(consctl < 0){
2963e12c5d1SDavid du Colombier 		fprint(2, "can't open consctl\n");
2973e12c5d1SDavid du Colombier 		return;
2983e12c5d1SDavid du Colombier 	}
2993e12c5d1SDavid du Colombier 	write(consctl, "rawon", 5);
3003e12c5d1SDavid du Colombier 	raw = 1;
3013e12c5d1SDavid du Colombier }
3023e12c5d1SDavid du Colombier 
3033e12c5d1SDavid du Colombier /*
3043e12c5d1SDavid du Colombier  *  turn keyboard raw mode off
3053e12c5d1SDavid du Colombier  */
3063e12c5d1SDavid du Colombier void
3073e12c5d1SDavid du Colombier rawoff(void)
3083e12c5d1SDavid du Colombier {
3093e12c5d1SDavid du Colombier 	if(debug)
3103e12c5d1SDavid du Colombier 		fprint(2, "rawoff\n");
3113e12c5d1SDavid du Colombier 	if(raw == 0)
3123e12c5d1SDavid du Colombier 		return;
3133e12c5d1SDavid du Colombier 	if(consctl < 0)
3143e12c5d1SDavid du Colombier 		consctl = open("/dev/consctl", OWRITE);
3153e12c5d1SDavid du Colombier 	if(consctl < 0){
3163e12c5d1SDavid du Colombier 		fprint(2, "can't open consctl\n");
3173e12c5d1SDavid du Colombier 		return;
3183e12c5d1SDavid du Colombier 	}
3193e12c5d1SDavid du Colombier 	write(consctl, "rawoff", 6);
3203e12c5d1SDavid du Colombier 	raw = 0;
3213e12c5d1SDavid du Colombier }
3223e12c5d1SDavid du Colombier 
3233e12c5d1SDavid du Colombier /*
3243e12c5d1SDavid du Colombier  *  control menu
3253e12c5d1SDavid du Colombier  */
326*219b2ee8SDavid du Colombier #define STDHELP	"\t(b)reak, (q)uit, (i)nterrupt, (r)eturns, (.)continue, (!cmd)\n"
3273e12c5d1SDavid du Colombier 
3283e12c5d1SDavid du Colombier int
3293e12c5d1SDavid du Colombier menu(int net)
3303e12c5d1SDavid du Colombier {
3313e12c5d1SDavid du Colombier 	char buf[MAXMSG];
3323e12c5d1SDavid du Colombier 	long n;
3333e12c5d1SDavid du Colombier 	int done;
3343e12c5d1SDavid du Colombier 	int wasraw = raw;
3353e12c5d1SDavid du Colombier 
3363e12c5d1SDavid du Colombier 	if(wasraw)
3373e12c5d1SDavid du Colombier 		rawoff();
3383e12c5d1SDavid du Colombier 
3393e12c5d1SDavid du Colombier 	fprint(2, ">>> ");
3403e12c5d1SDavid du Colombier 	for(done = 0; !done; ){
3413e12c5d1SDavid du Colombier 		n = read(0, buf, sizeof(buf)-1);
3423e12c5d1SDavid du Colombier 		if(n <= 0)
3433e12c5d1SDavid du Colombier 			return -1;
3443e12c5d1SDavid du Colombier 		buf[n] = 0;
3453e12c5d1SDavid du Colombier 		switch(buf[0]){
3463e12c5d1SDavid du Colombier 		case '!':
3473e12c5d1SDavid du Colombier 			print(buf);
3483e12c5d1SDavid du Colombier 			system(net, buf+1);
3493e12c5d1SDavid du Colombier 			print("!\n");
3503e12c5d1SDavid du Colombier 			done = 1;
3513e12c5d1SDavid du Colombier 			break;
3523e12c5d1SDavid du Colombier 		case '.':
3533e12c5d1SDavid du Colombier 			done = 1;
3543e12c5d1SDavid du Colombier 			break;
3553e12c5d1SDavid du Colombier 		case 'q':
3563e12c5d1SDavid du Colombier 			return -1;
3573e12c5d1SDavid du Colombier 			break;
3583e12c5d1SDavid du Colombier 		case 'i':
3593e12c5d1SDavid du Colombier 			buf[0] = 0x1c;
3603e12c5d1SDavid du Colombier 			if(msgfd <= 0)
3613e12c5d1SDavid du Colombier 				write(net, buf, 1);
3623e12c5d1SDavid du Colombier 			else
3633e12c5d1SDavid du Colombier 				sendctl1(msgfd, M_SIGNAL, SIGQUIT);
3643e12c5d1SDavid du Colombier 			done = 1;
3653e12c5d1SDavid du Colombier 			break;
3663e12c5d1SDavid du Colombier 		case 'b':
3673e12c5d1SDavid du Colombier 			if(msgfd >= 0)
3683e12c5d1SDavid du Colombier 				sendctl(msgfd, M_BREAK);
3693e12c5d1SDavid du Colombier 			else if(ctl >= 0)
370*219b2ee8SDavid du Colombier 				write(ctl, "k", 1);
371*219b2ee8SDavid du Colombier 			done = 1;
372*219b2ee8SDavid du Colombier 			break;
373*219b2ee8SDavid du Colombier 		case 'r':
374*219b2ee8SDavid du Colombier 			returns = 1-returns;
3753e12c5d1SDavid du Colombier 			done = 1;
3763e12c5d1SDavid du Colombier 			break;
3773e12c5d1SDavid du Colombier 		default:
3783e12c5d1SDavid du Colombier 			fprint(2, STDHELP);
3793e12c5d1SDavid du Colombier 			break;
3803e12c5d1SDavid du Colombier 		}
3813e12c5d1SDavid du Colombier 		if(!done)
3823e12c5d1SDavid du Colombier 			fprint(2, ">>> ");
3833e12c5d1SDavid du Colombier 	}
3843e12c5d1SDavid du Colombier 
3853e12c5d1SDavid du Colombier 	if(wasraw)
3863e12c5d1SDavid du Colombier 		rawon();
3873e12c5d1SDavid du Colombier 	else
3883e12c5d1SDavid du Colombier 		rawoff();
3893e12c5d1SDavid du Colombier 	return 0;
3903e12c5d1SDavid du Colombier }
3913e12c5d1SDavid du Colombier 
3923e12c5d1SDavid du Colombier /*
3933e12c5d1SDavid du Colombier  *  the real work.  two processes pass bytes back and forth between the
3943e12c5d1SDavid du Colombier  *  terminal and the network.
3953e12c5d1SDavid du Colombier  */
3963e12c5d1SDavid du Colombier void
3973e12c5d1SDavid du Colombier stdcon(int net)
3983e12c5d1SDavid du Colombier {
3993e12c5d1SDavid du Colombier 	int netpid;
4003e12c5d1SDavid du Colombier 
4013e12c5d1SDavid du Colombier 	ttypid = getpid();
4023e12c5d1SDavid du Colombier 	switch(netpid = rfork(RFMEM|RFPROC)){
4033e12c5d1SDavid du Colombier 	case -1:
4043e12c5d1SDavid du Colombier 		perror("con");
4053e12c5d1SDavid du Colombier 		exits("fork");
4063e12c5d1SDavid du Colombier 	case 0:
4073e12c5d1SDavid du Colombier 		notify(notifyf);
4083e12c5d1SDavid du Colombier 		fromnet(net);
409*219b2ee8SDavid du Colombier 		postnote(PNPROC, ttypid, "kill");
4103e12c5d1SDavid du Colombier 		exits(0);
4113e12c5d1SDavid du Colombier 	default:
4123e12c5d1SDavid du Colombier 		notify(notifyf);
4133e12c5d1SDavid du Colombier 		fromkbd(net);
414*219b2ee8SDavid du Colombier 		postnote(PNPROC, netpid, "kill");
4153e12c5d1SDavid du Colombier 		exits(0);
4163e12c5d1SDavid du Colombier 	}
4173e12c5d1SDavid du Colombier }
4183e12c5d1SDavid du Colombier 
4193e12c5d1SDavid du Colombier /*
4203e12c5d1SDavid du Colombier  *  Read the keyboard and write it to the network.  '^\' gets us into
4213e12c5d1SDavid du Colombier  *  the menu.
4223e12c5d1SDavid du Colombier  */
4233e12c5d1SDavid du Colombier void
4243e12c5d1SDavid du Colombier fromkbd(int net)
4253e12c5d1SDavid du Colombier {
4263e12c5d1SDavid du Colombier 	long n;
4273e12c5d1SDavid du Colombier 	char buf[MAXMSG];
4283e12c5d1SDavid du Colombier 
4293e12c5d1SDavid du Colombier 	for(;;){
4303e12c5d1SDavid du Colombier 		n = read(0, buf, sizeof(buf));
4313e12c5d1SDavid du Colombier 		if(n < 0){
4323e12c5d1SDavid du Colombier 			if(wasintr()){
4333e12c5d1SDavid du Colombier 				if(cooked){
4343e12c5d1SDavid du Colombier 					buf[0] = 0x7f;
4353e12c5d1SDavid du Colombier 					n = 1;
4363e12c5d1SDavid du Colombier 				} else
4373e12c5d1SDavid du Colombier 					continue;
4383e12c5d1SDavid du Colombier 			} else
4393e12c5d1SDavid du Colombier 				return;
4403e12c5d1SDavid du Colombier 		}
4413e12c5d1SDavid du Colombier 		if(n && memchr(buf, 0x1c, n)){
4423e12c5d1SDavid du Colombier 			if(menu(net) < 0)
4433e12c5d1SDavid du Colombier 				return;
4443e12c5d1SDavid du Colombier 		}else{
4453e12c5d1SDavid du Colombier 			if(cooked && n==0){
4463e12c5d1SDavid du Colombier 				buf[0] = 0x4;
4473e12c5d1SDavid du Colombier 				n = 1;
4483e12c5d1SDavid du Colombier 			}
4493e12c5d1SDavid du Colombier 			if(iwrite(net, buf, n) != n)
4503e12c5d1SDavid du Colombier 				return;
4513e12c5d1SDavid du Colombier 		}
4523e12c5d1SDavid du Colombier 	}
4533e12c5d1SDavid du Colombier }
4543e12c5d1SDavid du Colombier 
4553e12c5d1SDavid du Colombier /*
4563e12c5d1SDavid du Colombier  *  Read from the network and write to the screen.
4573e12c5d1SDavid du Colombier  *  Filter out spurious carriage returns.
4583e12c5d1SDavid du Colombier  */
4593e12c5d1SDavid du Colombier void
4603e12c5d1SDavid du Colombier fromnet(int net)
4613e12c5d1SDavid du Colombier {
4623e12c5d1SDavid du Colombier 	long n;
4633e12c5d1SDavid du Colombier 	char buf[MAXMSG];
4643e12c5d1SDavid du Colombier 	char *cp, *ep;
4653e12c5d1SDavid du Colombier 
4663e12c5d1SDavid du Colombier 	for(;;){
4673e12c5d1SDavid du Colombier 		n = iread(net, buf, sizeof(buf));
4683e12c5d1SDavid du Colombier 		if(n < 0)
4693e12c5d1SDavid du Colombier 			return;
4703e12c5d1SDavid du Colombier 		if(n == 0)
4713e12c5d1SDavid du Colombier 			continue;
4723e12c5d1SDavid du Colombier 
473*219b2ee8SDavid du Colombier 		if (strip)
474*219b2ee8SDavid du Colombier 			for (cp=buf; cp<buf+n; cp++)
475*219b2ee8SDavid du Colombier 				*cp &= 0177;
476*219b2ee8SDavid du Colombier 
4773e12c5d1SDavid du Colombier 		if(!returns){
4783e12c5d1SDavid du Colombier 			/* convert cr's to null's */
4793e12c5d1SDavid du Colombier 			cp = buf;
4803e12c5d1SDavid du Colombier 			ep = buf + n;
4813e12c5d1SDavid du Colombier 			while(cp < ep && (cp = memchr(cp, '\r', ep-cp))){
4823e12c5d1SDavid du Colombier 				memmove(cp, cp+1, ep-cp-1);
4833e12c5d1SDavid du Colombier 				ep--;
4843e12c5d1SDavid du Colombier 				n--;
4853e12c5d1SDavid du Colombier 			}
4863e12c5d1SDavid du Colombier 		}
4873e12c5d1SDavid du Colombier 
4883e12c5d1SDavid du Colombier 		if(n > 0 && iwrite(outfd, buf, n) != n){
4893e12c5d1SDavid du Colombier 			if(outfd == 1)
4903e12c5d1SDavid du Colombier 				return;
4913e12c5d1SDavid du Colombier 			outfd = 1;
4923e12c5d1SDavid du Colombier 			if(iwrite(1, buf, n) != n)
4933e12c5d1SDavid du Colombier 				return;
4943e12c5d1SDavid du Colombier 		}
4953e12c5d1SDavid du Colombier 	}
4963e12c5d1SDavid du Colombier }
4973e12c5d1SDavid du Colombier 
4983e12c5d1SDavid du Colombier /*
4993e12c5d1SDavid du Colombier  *  dial and return a data connection
5003e12c5d1SDavid du Colombier  */
5013e12c5d1SDavid du Colombier int
5023e12c5d1SDavid du Colombier dodial(char *dest, char *net, char *service)
5033e12c5d1SDavid du Colombier {
5043e12c5d1SDavid du Colombier 	char name[3*NAMELEN];
5053e12c5d1SDavid du Colombier 	char devdir[3*NAMELEN];
5063e12c5d1SDavid du Colombier 	int data;
5073e12c5d1SDavid du Colombier 
5083e12c5d1SDavid du Colombier 	devdir[0] = 0;
5093e12c5d1SDavid du Colombier 	strcpy(name, netmkaddr(dest, net, service));
510bd389b36SDavid du Colombier 	data = dial(name, 0, devdir, &ctl);
5113e12c5d1SDavid du Colombier 	if(data < 0){
512*219b2ee8SDavid du Colombier 		seterr(name);
5133e12c5d1SDavid du Colombier 		return -1;
5143e12c5d1SDavid du Colombier 	}
5153e12c5d1SDavid du Colombier 	fprint(2, "connected to %s on %s\n", name, devdir);
5163e12c5d1SDavid du Colombier 	return data;
5173e12c5d1SDavid du Colombier }
5183e12c5d1SDavid du Colombier 
5193e12c5d1SDavid du Colombier /*
5203e12c5d1SDavid du Colombier  *  send a note to a process
5213e12c5d1SDavid du Colombier  */
5223e12c5d1SDavid du Colombier /*
5233e12c5d1SDavid du Colombier  *  datakit authentication
5243e12c5d1SDavid du Colombier  */
5253e12c5d1SDavid du Colombier int
5263e12c5d1SDavid du Colombier dkauth(int net)
5273e12c5d1SDavid du Colombier {
5283e12c5d1SDavid du Colombier 	char buf[128];
5293e12c5d1SDavid du Colombier 	long n;
5303e12c5d1SDavid du Colombier 	char *p;
5313e12c5d1SDavid du Colombier 
5323e12c5d1SDavid du Colombier 	for(;;){
5333e12c5d1SDavid du Colombier 		if(read(net, buf, 2)!=2)
5343e12c5d1SDavid du Colombier 			return -1;
5353e12c5d1SDavid du Colombier 		if(buf[0]=='O' && buf[1]=='K')
5363e12c5d1SDavid du Colombier 			break;
5373e12c5d1SDavid du Colombier 		if(buf[0]!='N' || buf[1]!='O')
5383e12c5d1SDavid du Colombier 			return -1;
5393e12c5d1SDavid du Colombier 		print("please login: ");
5403e12c5d1SDavid du Colombier 		n = read(0, buf, sizeof(buf)-1);
5413e12c5d1SDavid du Colombier 		if(n<=0)
5423e12c5d1SDavid du Colombier 			exits("login");
5433e12c5d1SDavid du Colombier 		buf[n-1] = ',';
5443e12c5d1SDavid du Colombier 		rawon();
5453e12c5d1SDavid du Colombier 		print("password: ");
5463e12c5d1SDavid du Colombier 		for(p = &buf[n]; p<&buf[127];p++){
5473e12c5d1SDavid du Colombier 			if(read(0, p, 1)!=1)
5483e12c5d1SDavid du Colombier 				return -1;
5493e12c5d1SDavid du Colombier 			if(*p=='\r' || *p=='\n'){
5503e12c5d1SDavid du Colombier 				*p++ = 0;
5513e12c5d1SDavid du Colombier 				break;
5523e12c5d1SDavid du Colombier 			}
5533e12c5d1SDavid du Colombier 		}
5543e12c5d1SDavid du Colombier 		n = p-buf;
5553e12c5d1SDavid du Colombier 		rawoff();
5563e12c5d1SDavid du Colombier 		if(write(net, buf, n)!=n)
5573e12c5d1SDavid du Colombier 			return -1;
5583e12c5d1SDavid du Colombier 	}
5593e12c5d1SDavid du Colombier 	return 0;
5603e12c5d1SDavid du Colombier }
5613e12c5d1SDavid du Colombier 
5623e12c5d1SDavid du Colombier void
5633e12c5d1SDavid du Colombier dosystem(int fd, char *cmd)
5643e12c5d1SDavid du Colombier {
5653e12c5d1SDavid du Colombier 	char *p;
5663e12c5d1SDavid du Colombier 
5673e12c5d1SDavid du Colombier 	p = system(fd, cmd);
5683e12c5d1SDavid du Colombier 	if(*p){
5693e12c5d1SDavid du Colombier 		print("con: %s terminated with %s\n", p);
5703e12c5d1SDavid du Colombier 		exits(p);
5713e12c5d1SDavid du Colombier 	}
5723e12c5d1SDavid du Colombier }
5733e12c5d1SDavid du Colombier 
5743e12c5d1SDavid du Colombier /*
5753e12c5d1SDavid du Colombier  *  run a command with the network connection as standard IO
5763e12c5d1SDavid du Colombier  */
5773e12c5d1SDavid du Colombier char *
5783e12c5d1SDavid du Colombier system(int fd, char *cmd)
5793e12c5d1SDavid du Colombier {
5803e12c5d1SDavid du Colombier 	int pid;
5813e12c5d1SDavid du Colombier 	int p;
5823e12c5d1SDavid du Colombier 	static Waitmsg msg;
5833e12c5d1SDavid du Colombier 	int pfd[2];
5843e12c5d1SDavid du Colombier 	int n;
5853e12c5d1SDavid du Colombier 	char buf[4096];
5863e12c5d1SDavid du Colombier 
5873e12c5d1SDavid du Colombier 	if(pipe(pfd) < 0){
5883e12c5d1SDavid du Colombier 		perror("pipe");
5893e12c5d1SDavid du Colombier 		return "pipe failed";
5903e12c5d1SDavid du Colombier 	}
5913e12c5d1SDavid du Colombier 	outfd = pfd[1];
5923e12c5d1SDavid du Colombier 
593*219b2ee8SDavid du Colombier 	close(consctl);
594*219b2ee8SDavid du Colombier 	consctl = -1;
5953e12c5d1SDavid du Colombier 	switch(pid = fork()){
5963e12c5d1SDavid du Colombier 	case -1:
5973e12c5d1SDavid du Colombier 		perror("con");
5983e12c5d1SDavid du Colombier 		return "fork failed";
5993e12c5d1SDavid du Colombier 	case 0:
6003e12c5d1SDavid du Colombier 		close(pfd[1]);
6013e12c5d1SDavid du Colombier 		dup(pfd[0], 0);
6023e12c5d1SDavid du Colombier 		dup(pfd[0], 1);
6033e12c5d1SDavid du Colombier 		close(ctl);
6043e12c5d1SDavid du Colombier 		close(fd);
6053e12c5d1SDavid du Colombier 		close(pfd[0]);
6063e12c5d1SDavid du Colombier 		if(*cmd)
6073e12c5d1SDavid du Colombier 			execl("/bin/rc", "rc", "-c", cmd, 0);
6083e12c5d1SDavid du Colombier 		else
6093e12c5d1SDavid du Colombier 			execl("/bin/rc", "rc", 0);
6103e12c5d1SDavid du Colombier 		perror("con");
6113e12c5d1SDavid du Colombier 		exits("exec");
6123e12c5d1SDavid du Colombier 		break;
6133e12c5d1SDavid du Colombier 	default:
6143e12c5d1SDavid du Colombier 		close(pfd[0]);
6153e12c5d1SDavid du Colombier 		while((n = read(pfd[1], buf, sizeof(buf))) > 0){
6163e12c5d1SDavid du Colombier 			if(msgfd >= 0){
6173e12c5d1SDavid du Colombier 				if(msgwrite(fd, buf, n) != n)
6183e12c5d1SDavid du Colombier 					break;
6193e12c5d1SDavid du Colombier 			} else {
6203e12c5d1SDavid du Colombier 				if(write(fd, buf, n) != n)
6213e12c5d1SDavid du Colombier 					break;
6223e12c5d1SDavid du Colombier 			}
6233e12c5d1SDavid du Colombier 		}
6243e12c5d1SDavid du Colombier 		p = wait(&msg);
6253e12c5d1SDavid du Colombier 		outfd = 1;
6263e12c5d1SDavid du Colombier 		close(pfd[1]);
627*219b2ee8SDavid du Colombier 		if(p < 0 || p != pid)
628*219b2ee8SDavid du Colombier 			return "lost child";
6293e12c5d1SDavid du Colombier 		break;
6303e12c5d1SDavid du Colombier 	}
631*219b2ee8SDavid du Colombier 	return msg.msg;
6323e12c5d1SDavid du Colombier }
6333e12c5d1SDavid du Colombier 
6343e12c5d1SDavid du Colombier int
6353e12c5d1SDavid du Colombier wasintr(void)
6363e12c5d1SDavid du Colombier {
6373e12c5d1SDavid du Colombier 	return strcmp(syserr(), "interrupted") == 0;
6383e12c5d1SDavid du Colombier }
6393e12c5d1SDavid du Colombier 
6403e12c5d1SDavid du Colombier void
6413e12c5d1SDavid du Colombier punt(char *msg)
6423e12c5d1SDavid du Colombier {
6433e12c5d1SDavid du Colombier 	if(*msg == 0)
6443e12c5d1SDavid du Colombier 		msg = transerr;
6453e12c5d1SDavid du Colombier 	fprint(2, "con: %s\n", msg);
6463e12c5d1SDavid du Colombier 	exits(msg);
6473e12c5d1SDavid du Colombier }
6483e12c5d1SDavid du Colombier 
6493e12c5d1SDavid du Colombier char*
6503e12c5d1SDavid du Colombier syserr(void)
6513e12c5d1SDavid du Colombier {
6523e12c5d1SDavid du Colombier 	static char err[ERRLEN];
6533e12c5d1SDavid du Colombier 	errstr(err);
6543e12c5d1SDavid du Colombier 	return err;
6553e12c5d1SDavid du Colombier }
6563e12c5d1SDavid du Colombier 
6573e12c5d1SDavid du Colombier void
658*219b2ee8SDavid du Colombier seterr(char *addr)
6593e12c5d1SDavid du Colombier {
6603e12c5d1SDavid du Colombier 	char *se = syserr();
6613e12c5d1SDavid du Colombier 
6623e12c5d1SDavid du Colombier 	if(verbose)
663*219b2ee8SDavid du Colombier 		fprint(2, "'%s' calling %s\n", se, addr);
6643e12c5d1SDavid du Colombier 	if(firsterr[0] && (strstr(se, "translate") ||
6653e12c5d1SDavid du Colombier 	 strstr(se, "file does not exist") ||
6663e12c5d1SDavid du Colombier 	 strstr(se, "unknown address") ||
6673e12c5d1SDavid du Colombier 	 strstr(se, "directory entry not found")))
6683e12c5d1SDavid du Colombier 		return;
6693e12c5d1SDavid du Colombier 	strcpy(firsterr, se);
6703e12c5d1SDavid du Colombier }
6713e12c5d1SDavid du Colombier 
6723e12c5d1SDavid du Colombier 
6733e12c5d1SDavid du Colombier long
6743e12c5d1SDavid du Colombier iread(int f, void *a, int n)
6753e12c5d1SDavid du Colombier {
6763e12c5d1SDavid du Colombier 	long m;
6773e12c5d1SDavid du Colombier 
6783e12c5d1SDavid du Colombier 	for(;;){
6793e12c5d1SDavid du Colombier 		m = read(f, a, n);
6803e12c5d1SDavid du Colombier 		if(m >= 0 || !wasintr())
6813e12c5d1SDavid du Colombier 			break;
6823e12c5d1SDavid du Colombier 	}
6833e12c5d1SDavid du Colombier 	return m;
6843e12c5d1SDavid du Colombier }
6853e12c5d1SDavid du Colombier 
6863e12c5d1SDavid du Colombier long
6873e12c5d1SDavid du Colombier iwrite(int f, void *a, int n)
6883e12c5d1SDavid du Colombier {
6893e12c5d1SDavid du Colombier 	long m;
6903e12c5d1SDavid du Colombier 
6913e12c5d1SDavid du Colombier 	m = write(f, a, n);
6923e12c5d1SDavid du Colombier 	if(m < 0 && wasintr())
6933e12c5d1SDavid du Colombier 		return n;
6943e12c5d1SDavid du Colombier 	return m;
6953e12c5d1SDavid du Colombier }
6963e12c5d1SDavid du Colombier 
6973e12c5d1SDavid du Colombier /*
6983e12c5d1SDavid du Colombier  *  The rest is to support the V10 mesgld protocol.
6993e12c5d1SDavid du Colombier  */
7003e12c5d1SDavid du Colombier 
7013e12c5d1SDavid du Colombier /*
7023e12c5d1SDavid du Colombier  *  network orderings
7033e12c5d1SDavid du Colombier  */
7043e12c5d1SDavid du Colombier #define get2byte(p) ((p)[0] + ((p)[1]<<8))
7053e12c5d1SDavid du Colombier #define get4byte(p) ((p)[0] + ((p)[1]<<8) + ((p)[2]<<16) + ((p)[3]<<24))
7063e12c5d1SDavid du Colombier #define put2byte(p, i) ((p)[0]=(i), (p)[1]=(i)>>8)
7073e12c5d1SDavid du Colombier #define put4byte(p, i) ((p)[0]=(i), (p)[1]=(i)>>8, (p)[2]=(i)>>16, (p)[3]=(i)>>24)
7083e12c5d1SDavid du Colombier 
7093e12c5d1SDavid du Colombier /*
7103e12c5d1SDavid du Colombier  *  tty parameters
7113e12c5d1SDavid du Colombier  */
7123e12c5d1SDavid du Colombier int sgflags = ECHO;
7133e12c5d1SDavid du Colombier 
7143e12c5d1SDavid du Colombier /*
7153e12c5d1SDavid du Colombier  *  a mesgld message
7163e12c5d1SDavid du Colombier  */
7173e12c5d1SDavid du Colombier struct Msg {
7183e12c5d1SDavid du Colombier 	struct mesg h;
7193e12c5d1SDavid du Colombier 	char b[MAXMSG];
7203e12c5d1SDavid du Colombier };
7213e12c5d1SDavid du Colombier 
7223e12c5d1SDavid du Colombier /*
7233e12c5d1SDavid du Colombier  *  connect using the mesgdcon protocol.  infinite ugliness to talk to a V10
7243e12c5d1SDavid du Colombier  *  system.
7253e12c5d1SDavid du Colombier  */
7263e12c5d1SDavid du Colombier void
7273e12c5d1SDavid du Colombier mesgdcon(char *dest, char *cmd)
7283e12c5d1SDavid du Colombier {
7293e12c5d1SDavid du Colombier 	int net;
7303e12c5d1SDavid du Colombier 	int netpid;
7313e12c5d1SDavid du Colombier 
732*219b2ee8SDavid du Colombier 	net = dodial(dest, "dk", "mesgdcon");
7333e12c5d1SDavid du Colombier 	if(net < 0)
7343e12c5d1SDavid du Colombier 		return;
7353e12c5d1SDavid du Colombier 
7363e12c5d1SDavid du Colombier 	if(dkauth(net) < 0)
7373e12c5d1SDavid du Colombier 		punt("can't authenticate across datakit");
7383e12c5d1SDavid du Colombier 
7393e12c5d1SDavid du Colombier 	if(cmd)
7403e12c5d1SDavid du Colombier 		dosystem(net, cmd);
7413e12c5d1SDavid du Colombier 
7423e12c5d1SDavid du Colombier 	msgfd = net;
7433e12c5d1SDavid du Colombier 	ttypid = getpid();
7443e12c5d1SDavid du Colombier 	switch(netpid = rfork(RFMEM|RFPROC)){
7453e12c5d1SDavid du Colombier 	case -1:
7463e12c5d1SDavid du Colombier 		perror("con");
7473e12c5d1SDavid du Colombier 		exits("fork");
7483e12c5d1SDavid du Colombier 	case 0:
7493e12c5d1SDavid du Colombier 		notify(notifyf);
7503e12c5d1SDavid du Colombier 		msgfromnet(net);
751*219b2ee8SDavid du Colombier 		postnote(PNPROC, ttypid, "kill");
7523e12c5d1SDavid du Colombier 		exits(0);
7533e12c5d1SDavid du Colombier 	default:
7543e12c5d1SDavid du Colombier 		notify(msgnotifyf);
7553e12c5d1SDavid du Colombier 		msgfromkbd(net);
756*219b2ee8SDavid du Colombier 		postnote(PNPROC, netpid, "kill");
7573e12c5d1SDavid du Colombier 		exits(0);
7583e12c5d1SDavid du Colombier 	}
7593e12c5d1SDavid du Colombier }
7603e12c5d1SDavid du Colombier 
7613e12c5d1SDavid du Colombier /*
7623e12c5d1SDavid du Colombier  *  convert certain interrupts into mesgld messages
7633e12c5d1SDavid du Colombier  */
7643e12c5d1SDavid du Colombier void
7653e12c5d1SDavid du Colombier msgnotifyf(void *a, char *msg)
7663e12c5d1SDavid du Colombier {
7673e12c5d1SDavid du Colombier 	USED(a);
7683e12c5d1SDavid du Colombier 
7693e12c5d1SDavid du Colombier 	if(strstr(msg, "closed pipe"))
7703e12c5d1SDavid du Colombier 		noted(NCONT);
7713e12c5d1SDavid du Colombier 	if(strcmp(msg, "interrupt") == 0){
7723e12c5d1SDavid du Colombier 		sendctl1(msgfd, M_SIGNAL, SIGINT);
7733e12c5d1SDavid du Colombier 		noted(NCONT);
7743e12c5d1SDavid du Colombier 	}
7753e12c5d1SDavid du Colombier 	if(strcmp(msg, "hangup") == 0){
7763e12c5d1SDavid du Colombier 		sendctl(msgfd, M_HANGUP);
7773e12c5d1SDavid du Colombier 		noted(NCONT);
7783e12c5d1SDavid du Colombier 	}
7793e12c5d1SDavid du Colombier 	noted(NDFLT);
7803e12c5d1SDavid du Colombier }
7813e12c5d1SDavid du Colombier 
7823e12c5d1SDavid du Colombier /*
7833e12c5d1SDavid du Colombier  *  send an empty mesgld message
7843e12c5d1SDavid du Colombier  */
7853e12c5d1SDavid du Colombier int
7863e12c5d1SDavid du Colombier sendctl(int net, int type)
7873e12c5d1SDavid du Colombier {
7883e12c5d1SDavid du Colombier 	Msg m;
7893e12c5d1SDavid du Colombier 
7903e12c5d1SDavid du Colombier 	m.h.type = type;
7913e12c5d1SDavid du Colombier 	m.h.magic = MSGMAGIC;
7923e12c5d1SDavid du Colombier 	put2byte(m.h.size, 0);
7933e12c5d1SDavid du Colombier 	if(iwrite(net, &m, sizeof(struct mesg)) != sizeof(struct mesg))
7943e12c5d1SDavid du Colombier 		return -1;
7953e12c5d1SDavid du Colombier 	return 0;
7963e12c5d1SDavid du Colombier }
7973e12c5d1SDavid du Colombier 
7983e12c5d1SDavid du Colombier /*
7993e12c5d1SDavid du Colombier  *  send a one byte mesgld message
8003e12c5d1SDavid du Colombier  */
8013e12c5d1SDavid du Colombier int
8023e12c5d1SDavid du Colombier sendctl1(int net, int type, int parm)
8033e12c5d1SDavid du Colombier {
8043e12c5d1SDavid du Colombier 	Msg m;
8053e12c5d1SDavid du Colombier 
8063e12c5d1SDavid du Colombier 	m.h.type = type;
8073e12c5d1SDavid du Colombier 	m.h.magic = MSGMAGIC;
8083e12c5d1SDavid du Colombier 	m.b[0] = parm;
8093e12c5d1SDavid du Colombier 	put2byte(m.h.size, 1);
8103e12c5d1SDavid du Colombier 	if(iwrite(net, &m, sizeof(struct mesg)+1) != sizeof(struct mesg)+1)
8113e12c5d1SDavid du Colombier 		return -1;
8123e12c5d1SDavid du Colombier 	return 0;
8133e12c5d1SDavid du Colombier }
8143e12c5d1SDavid du Colombier 
8153e12c5d1SDavid du Colombier /*
8163e12c5d1SDavid du Colombier  *  read n bytes.  return -1 if it fails, 0 otherwise.
8173e12c5d1SDavid du Colombier  */
8183e12c5d1SDavid du Colombier int
8193e12c5d1SDavid du Colombier readupto(int from, char *a, int len)
8203e12c5d1SDavid du Colombier {
8213e12c5d1SDavid du Colombier 	int n;
8223e12c5d1SDavid du Colombier 
8233e12c5d1SDavid du Colombier 	while(len > 0){
8243e12c5d1SDavid du Colombier 		n = iread(from, a, len);
8253e12c5d1SDavid du Colombier 		if(n < 0)
8263e12c5d1SDavid du Colombier 			return -1;
8273e12c5d1SDavid du Colombier 		a += n;
8283e12c5d1SDavid du Colombier 		len -= n;
8293e12c5d1SDavid du Colombier 	}
8303e12c5d1SDavid du Colombier 	return 0;
8313e12c5d1SDavid du Colombier }
8323e12c5d1SDavid du Colombier 
8333e12c5d1SDavid du Colombier /*
8343e12c5d1SDavid du Colombier  *  Decode a mesgld message from the network
8353e12c5d1SDavid du Colombier  */
8363e12c5d1SDavid du Colombier void
8373e12c5d1SDavid du Colombier msgfromnet(int net)
8383e12c5d1SDavid du Colombier {
8393e12c5d1SDavid du Colombier 	ulong com;
8403e12c5d1SDavid du Colombier 	struct stioctl *io;
8413e12c5d1SDavid du Colombier 	struct sgttyb *sg;
8423e12c5d1SDavid du Colombier 	struct ttydevb *td;
8433e12c5d1SDavid du Colombier 	struct tchars *tc;
8443e12c5d1SDavid du Colombier 	int len;
8453e12c5d1SDavid du Colombier 	Msg m;
8463e12c5d1SDavid du Colombier 
8473e12c5d1SDavid du Colombier 	for(;;){
8483e12c5d1SDavid du Colombier 		/* get a complete mesgld message */
8493e12c5d1SDavid du Colombier 		if(readupto(net, (char*)&m.h, sizeof(struct mesg)) < 0)
8503e12c5d1SDavid du Colombier 			break;
8513e12c5d1SDavid du Colombier 		if(m.h.magic != MSGMAGIC){
8523e12c5d1SDavid du Colombier 			fprint(2, "con: bad message magic 0x%ux\n", m.h.magic);
8533e12c5d1SDavid du Colombier 			break;
8543e12c5d1SDavid du Colombier 		}
8553e12c5d1SDavid du Colombier 		len = get2byte(m.h.size);
856*219b2ee8SDavid du Colombier 		if(len > sizeof(m.b)){
857*219b2ee8SDavid du Colombier 			len = sizeof(m.b);
858*219b2ee8SDavid du Colombier 			fprint(2, "con: mesgld message too long\n");
859*219b2ee8SDavid du Colombier 		}
8603e12c5d1SDavid du Colombier 		if(len && readupto(net, m.b, len) < 0)
8613e12c5d1SDavid du Colombier 			break;
8623e12c5d1SDavid du Colombier 
8633e12c5d1SDavid du Colombier 		/* decode */
8643e12c5d1SDavid du Colombier 		switch(m.h.type){
8653e12c5d1SDavid du Colombier 		case M_HANGUP:
8663e12c5d1SDavid du Colombier 			if(debug)
8673e12c5d1SDavid du Colombier 				fprint(2, "M_HANGUP\n");
8683e12c5d1SDavid du Colombier 			return;
8693e12c5d1SDavid du Colombier 		case M_DATA:
8703e12c5d1SDavid du Colombier 			if(debug)
8713e12c5d1SDavid du Colombier 				fprint(2, "M_DATA %d bytes\n", len);
8723e12c5d1SDavid du Colombier 			if(iwrite(outfd, m.b, len) != len){
8733e12c5d1SDavid du Colombier 				if(outfd == 1)
8743e12c5d1SDavid du Colombier 					return;
8753e12c5d1SDavid du Colombier 				outfd = 1;
8763e12c5d1SDavid du Colombier 				if(iwrite(outfd, m.b, len) != len)
8773e12c5d1SDavid du Colombier 					return;
8783e12c5d1SDavid du Colombier 			}
8793e12c5d1SDavid du Colombier 			continue;
8803e12c5d1SDavid du Colombier 		case M_IOCTL:
8813e12c5d1SDavid du Colombier 			break;
8823e12c5d1SDavid du Colombier 		default:
8833e12c5d1SDavid du Colombier 			/* ignore */
8843e12c5d1SDavid du Colombier 			if(debug)
885*219b2ee8SDavid du Colombier 				fprint(2, "con: unknown message\n");
8863e12c5d1SDavid du Colombier 			continue;
8873e12c5d1SDavid du Colombier 		}
8883e12c5d1SDavid du Colombier 
8893e12c5d1SDavid du Colombier 		/*
8903e12c5d1SDavid du Colombier 		 *  answer an ioctl
8913e12c5d1SDavid du Colombier 		 */
8923e12c5d1SDavid du Colombier 		io = (struct stioctl *)m.b;
8933e12c5d1SDavid du Colombier 		com = get4byte(io->com);
8943e12c5d1SDavid du Colombier 		if(debug)
8953e12c5d1SDavid du Colombier 			fprint(2, "M_IOCTL %d\n", com);
8963e12c5d1SDavid du Colombier 		switch(com){
8973e12c5d1SDavid du Colombier 		case FIOLOOKLD:
8983e12c5d1SDavid du Colombier 			put4byte(io->data, tty_ld);
8993e12c5d1SDavid du Colombier 			len = 0;
9003e12c5d1SDavid du Colombier 			break;
9013e12c5d1SDavid du Colombier 		case TIOCGETP:
9023e12c5d1SDavid du Colombier 			sg = (struct sgttyb *)io->data;
9033e12c5d1SDavid du Colombier 			sg->sg_ispeed = sg->sg_ospeed = B9600;
9043e12c5d1SDavid du Colombier 			sg->sg_erase = 0010;	/* back space */
9053e12c5d1SDavid du Colombier 			sg->sg_kill = 0025;	/* CNTL U */
9063e12c5d1SDavid du Colombier 			put2byte(sg->sg_flags, sgflags);
9073e12c5d1SDavid du Colombier 			len = sizeof(struct sgttyb);
9083e12c5d1SDavid du Colombier 			break;
9093e12c5d1SDavid du Colombier 		case TIOCSETN:
9103e12c5d1SDavid du Colombier 		case TIOCSETP:
9113e12c5d1SDavid du Colombier 			sg = (struct sgttyb *)io->data;
9123e12c5d1SDavid du Colombier 			sgflags = get2byte(sg->sg_flags);
9133e12c5d1SDavid du Colombier 			if((sgflags&(RAW|CBREAK)) || !(sgflags&ECHO))
9143e12c5d1SDavid du Colombier 				rawon();
9153e12c5d1SDavid du Colombier 			else
9163e12c5d1SDavid du Colombier 				rawoff();
9173e12c5d1SDavid du Colombier 			len = 0;
9183e12c5d1SDavid du Colombier 			break;
9193e12c5d1SDavid du Colombier 		case TIOCGETC:
9203e12c5d1SDavid du Colombier 			tc = (struct tchars *)io->data;
9213e12c5d1SDavid du Colombier 			tc->t_intrc = 0177;
9223e12c5d1SDavid du Colombier 			tc->t_quitc = 0034;
9233e12c5d1SDavid du Colombier 			tc->t_startc = 0;
9243e12c5d1SDavid du Colombier 			tc->t_stopc = 0;
9253e12c5d1SDavid du Colombier 			tc->t_eofc = 0004;
9263e12c5d1SDavid du Colombier 			tc->t_brkc = 0;
9273e12c5d1SDavid du Colombier 			len = sizeof(struct tchars);
9283e12c5d1SDavid du Colombier 			break;
9293e12c5d1SDavid du Colombier 		case TIOCSETC:
9303e12c5d1SDavid du Colombier 			len = 0;
9313e12c5d1SDavid du Colombier 			break;
9323e12c5d1SDavid du Colombier 		case TIOCGDEV:
9333e12c5d1SDavid du Colombier 			td = (struct ttydevb *)io->data;
9343e12c5d1SDavid du Colombier 			td->ispeed = td->ospeed = B9600;
9353e12c5d1SDavid du Colombier 			put2byte(td->flags, 0);
9363e12c5d1SDavid du Colombier 			len = sizeof(struct ttydevb);
9373e12c5d1SDavid du Colombier 			break;
9383e12c5d1SDavid du Colombier 		case TIOCSDEV:
9393e12c5d1SDavid du Colombier 			len = 0;
9403e12c5d1SDavid du Colombier 			break;
9413e12c5d1SDavid du Colombier 		default:
9423e12c5d1SDavid du Colombier 			/*
9433e12c5d1SDavid du Colombier 			 *  unimplemented
9443e12c5d1SDavid du Colombier 			 */
9453e12c5d1SDavid du Colombier 			m.b[len] = 0;
9463e12c5d1SDavid du Colombier 			if(sendctl(net, M_IOCNAK) < 0)
9473e12c5d1SDavid du Colombier 				return;
9483e12c5d1SDavid du Colombier 			continue;
9493e12c5d1SDavid du Colombier 		}
9503e12c5d1SDavid du Colombier 
9513e12c5d1SDavid du Colombier 		/*
9523e12c5d1SDavid du Colombier 		 *  acknowledge
9533e12c5d1SDavid du Colombier 		 */
9543e12c5d1SDavid du Colombier 		m.h.type = M_IOCACK;
9553e12c5d1SDavid du Colombier 		m.h.magic = MSGMAGIC;
9563e12c5d1SDavid du Colombier 		len += 4;
9573e12c5d1SDavid du Colombier 		put2byte(m.h.size, len);
9583e12c5d1SDavid du Colombier 		len += sizeof(struct mesg);
9593e12c5d1SDavid du Colombier 		if(iwrite(net, &m, len) != len)
9603e12c5d1SDavid du Colombier 			return;
9613e12c5d1SDavid du Colombier 	}
9623e12c5d1SDavid du Colombier }
9633e12c5d1SDavid du Colombier 
9643e12c5d1SDavid du Colombier /*
9653e12c5d1SDavid du Colombier  *  Read the keyboard, convert to mesgld messages, and write it to the network.
9663e12c5d1SDavid du Colombier  *  '^\' gets us into the menu.
9673e12c5d1SDavid du Colombier  */
9683e12c5d1SDavid du Colombier void
9693e12c5d1SDavid du Colombier msgfromkbd(int net)
9703e12c5d1SDavid du Colombier {
9713e12c5d1SDavid du Colombier 	long n;
9723e12c5d1SDavid du Colombier 	char buf[MAXMSG];
9733e12c5d1SDavid du Colombier 
9743e12c5d1SDavid du Colombier 	for(;;){
9753e12c5d1SDavid du Colombier 		n = iread(0, buf, sizeof(buf));
9763e12c5d1SDavid du Colombier 		if(n < 0)
9773e12c5d1SDavid du Colombier 			return;
9783e12c5d1SDavid du Colombier 		if(n && memchr(buf, 0034, n)){
9793e12c5d1SDavid du Colombier 			if(menu(net) < 0)
9803e12c5d1SDavid du Colombier 				return;
9813e12c5d1SDavid du Colombier 		} else {
9823e12c5d1SDavid du Colombier 			if(msgwrite(net, buf, n) != n)
9833e12c5d1SDavid du Colombier 				return;
9843e12c5d1SDavid du Colombier 		}
9853e12c5d1SDavid du Colombier 	}
9863e12c5d1SDavid du Colombier }
9873e12c5d1SDavid du Colombier 
9883e12c5d1SDavid du Colombier int
9893e12c5d1SDavid du Colombier msgwrite(int fd, void *buf, int len)
9903e12c5d1SDavid du Colombier {
9913e12c5d1SDavid du Colombier 	Msg m;
9923e12c5d1SDavid du Colombier 	int n;
9933e12c5d1SDavid du Colombier 
9943e12c5d1SDavid du Colombier 	n = len;
9953e12c5d1SDavid du Colombier 	memmove(m.b, buf, n);
9963e12c5d1SDavid du Colombier 	put2byte(m.h.size, n);
9973e12c5d1SDavid du Colombier 	m.h.magic = MSGMAGIC;
9983e12c5d1SDavid du Colombier 	m.h.type = M_DATA;
9993e12c5d1SDavid du Colombier 	n += sizeof(struct mesg);
10003e12c5d1SDavid du Colombier 	if(iwrite(fd, &m, n) != n)
10013e12c5d1SDavid du Colombier 		return -1;
10023e12c5d1SDavid du Colombier 
10033e12c5d1SDavid du Colombier 	put2byte(m.h.size, 0);
10043e12c5d1SDavid du Colombier 	m.h.magic = MSGMAGIC;
10053e12c5d1SDavid du Colombier 	m.h.type = M_DELIM;
10063e12c5d1SDavid du Colombier 	n = sizeof(struct mesg);
10073e12c5d1SDavid du Colombier 	if(iwrite(fd, &m, n) != n)
10083e12c5d1SDavid du Colombier 		return -1;
10093e12c5d1SDavid du Colombier 
10103e12c5d1SDavid du Colombier 	return len;
10113e12c5d1SDavid du Colombier }
10123e12c5d1SDavid du Colombier 
1013