xref: /plan9/sys/src/cmd/con/con.c (revision 3b86f2f88bade1f00206c7aa750b7add255f5724)
13e12c5d1SDavid du Colombier #include <u.h>
23e12c5d1SDavid du Colombier #include <libc.h>
33e12c5d1SDavid du Colombier 
43e12c5d1SDavid du Colombier int debug;		/* true if debugging */
53e12c5d1SDavid du Colombier int ctl = -1;		/* control fd (for break's) */
63e12c5d1SDavid du Colombier int raw;		/* true if raw is on */
73e12c5d1SDavid du Colombier int consctl = -1;	/* control fd for cons */
83e12c5d1SDavid du Colombier int ttypid;		/* pid's if the 2 processes (used to kill them) */
93e12c5d1SDavid du Colombier int outfd = 1;		/* local output file descriptor */
103e12c5d1SDavid du Colombier int cooked;		/* non-zero forces cooked mode */
113e12c5d1SDavid du Colombier int returns;		/* non-zero forces carriage returns not to be filtered out */
125d459b5aSDavid du Colombier int crtonl;			/* non-zero forces carriage returns to be converted to nls coming from net */
13219b2ee8SDavid du Colombier int	strip;		/* strip off parity bits */
149a747e4fSDavid du Colombier char firsterr[2*ERRMAX];
159a747e4fSDavid du Colombier char transerr[2*ERRMAX];
163e12c5d1SDavid du Colombier int limited;
176dc4800dSDavid du Colombier char *remuser;		/* for BSD rlogin authentication */
183e12c5d1SDavid du Colombier int verbose;
19219b2ee8SDavid du Colombier int baud;
207dd7cddfSDavid du Colombier int notkbd;
217dd7cddfSDavid du Colombier int nltocr;		/* translate kbd nl to cr  and vice versa */
223e12c5d1SDavid du Colombier 
23*3b86f2f8SDavid du Colombier static char *srv;
24*3b86f2f8SDavid du Colombier 
25219b2ee8SDavid du Colombier #define MAXMSG (2*8192)
263e12c5d1SDavid du Colombier 
273e12c5d1SDavid du Colombier int	dodial(char*, char*, char*);
283e12c5d1SDavid du Colombier void	fromkbd(int);
293e12c5d1SDavid du Colombier void	fromnet(int);
303e12c5d1SDavid du Colombier long	iread(int, void*, int);
313e12c5d1SDavid du Colombier long	iwrite(int, void*, int);
323e12c5d1SDavid du Colombier int	menu(int);
333e12c5d1SDavid du Colombier void	notifyf(void*, char*);
343e12c5d1SDavid du Colombier void	pass(int, int, int);
353e12c5d1SDavid du Colombier void	rawoff(void);
363e12c5d1SDavid du Colombier void	rawon(void);
373e12c5d1SDavid du Colombier void	stdcon(int);
383e12c5d1SDavid du Colombier char*	system(int, char*);
393e12c5d1SDavid du Colombier void	dosystem(int, char*);
403e12c5d1SDavid du Colombier int	wasintr(void);
413e12c5d1SDavid du Colombier void	punt(char*);
423e12c5d1SDavid du Colombier char*	syserr(void);
43219b2ee8SDavid du Colombier void	seterr(char*);
443e12c5d1SDavid du Colombier 
453e12c5d1SDavid du Colombier /* protocols */
463e12c5d1SDavid du Colombier void	device(char*, char*);
473e12c5d1SDavid du Colombier void	rlogin(char*, char*);
483e12c5d1SDavid du Colombier void	simple(char*, char*);
493e12c5d1SDavid du Colombier 
503e12c5d1SDavid du Colombier void
usage(void)513e12c5d1SDavid du Colombier usage(void)
523e12c5d1SDavid du Colombier {
53*3b86f2f8SDavid du Colombier 	punt("usage: con [-CdnrRsTv] [-b baud] [-l [user]] [-c cmd] [-S svc] "
54*3b86f2f8SDavid du Colombier 		"net!host[!service]");
553e12c5d1SDavid du Colombier }
563e12c5d1SDavid du Colombier 
573e12c5d1SDavid du Colombier void
main(int argc,char * argv[])583e12c5d1SDavid du Colombier main(int argc, char *argv[])
593e12c5d1SDavid du Colombier {
603e12c5d1SDavid du Colombier 	char *dest;
613e12c5d1SDavid du Colombier 	char *cmd = 0;
623e12c5d1SDavid du Colombier 
633e12c5d1SDavid du Colombier 	returns = 1;
643e12c5d1SDavid du Colombier 	ARGBEGIN{
65219b2ee8SDavid du Colombier 	case 'b':
66e40528acSDavid du Colombier 		baud = atoi(EARGF(usage()));
67219b2ee8SDavid du Colombier 		break;
68*3b86f2f8SDavid du Colombier 	case 'C':
69*3b86f2f8SDavid du Colombier 		cooked = 1;
70*3b86f2f8SDavid du Colombier 		break;
71*3b86f2f8SDavid du Colombier 	case 'c':
72*3b86f2f8SDavid du Colombier 		cmd = EARGF(usage());
73*3b86f2f8SDavid du Colombier 		break;
743e12c5d1SDavid du Colombier 	case 'd':
753e12c5d1SDavid du Colombier 		debug = 1;
763e12c5d1SDavid du Colombier 		break;
773e12c5d1SDavid du Colombier 	case 'l':
783e12c5d1SDavid du Colombier 		limited = 1;
799a747e4fSDavid du Colombier 		if(argv[1] != nil && argv[1][0] != '-')
80*3b86f2f8SDavid du Colombier 			remuser = EARGF(usage());
813e12c5d1SDavid du Colombier 		break;
827dd7cddfSDavid du Colombier 	case 'n':
837dd7cddfSDavid du Colombier 		notkbd = 1;
847dd7cddfSDavid du Colombier 		break;
853e12c5d1SDavid du Colombier 	case 'r':
863e12c5d1SDavid du Colombier 		returns = 0;
873e12c5d1SDavid du Colombier 		break;
88*3b86f2f8SDavid du Colombier 	case 's':
89*3b86f2f8SDavid du Colombier 		strip = 1;
90*3b86f2f8SDavid du Colombier 		break;
91*3b86f2f8SDavid du Colombier 	case 'S':
92*3b86f2f8SDavid du Colombier 		srv = EARGF(usage());
93*3b86f2f8SDavid du Colombier 		break;
947dd7cddfSDavid du Colombier 	case 'R':
957dd7cddfSDavid du Colombier 		nltocr = 1;
967dd7cddfSDavid du Colombier 		break;
975d459b5aSDavid du Colombier 	case 'T':
985d459b5aSDavid du Colombier 		crtonl = 1;
995d459b5aSDavid du Colombier 		break;
1003e12c5d1SDavid du Colombier 	case 'v':
1013e12c5d1SDavid du Colombier 		verbose = 1;
1023e12c5d1SDavid du Colombier 		break;
1033e12c5d1SDavid du Colombier 	default:
1043e12c5d1SDavid du Colombier 		usage();
1053e12c5d1SDavid du Colombier 	}ARGEND
1063e12c5d1SDavid du Colombier 
1073e12c5d1SDavid du Colombier 	if(argc != 1){
1083e12c5d1SDavid du Colombier 		if(remuser == 0)
1093e12c5d1SDavid du Colombier 			usage();
1103e12c5d1SDavid du Colombier 		dest = remuser;
1113e12c5d1SDavid du Colombier 		remuser = 0;
1123e12c5d1SDavid du Colombier 	} else
1133e12c5d1SDavid du Colombier 		dest = argv[0];
1147dd7cddfSDavid du Colombier 	if(*dest == '/' && strchr(dest, '!') == 0)
1153e12c5d1SDavid du Colombier 		device(dest, cmd);
1163e12c5d1SDavid du Colombier 	else if(limited){
1173e12c5d1SDavid du Colombier 		simple(dest, cmd);	/* doesn't return if dialout succeeds */
1183e12c5d1SDavid du Colombier 		rlogin(dest, cmd);	/* doesn't return if dialout succeeds */
1193e12c5d1SDavid du Colombier 	} else {
120219b2ee8SDavid du Colombier 		rlogin(dest, cmd);	/* doesn't return if dialout succeeds */
1213e12c5d1SDavid du Colombier 		simple(dest, cmd);	/* doesn't return if dialout succeeds */
1223e12c5d1SDavid du Colombier 	}
1233e12c5d1SDavid du Colombier 	punt(firsterr);
1243e12c5d1SDavid du Colombier }
1253e12c5d1SDavid du Colombier 
1263e12c5d1SDavid du Colombier /*
1273e12c5d1SDavid du Colombier  *  just dial and use as a byte stream with remote echo
1283e12c5d1SDavid du Colombier  */
1293e12c5d1SDavid du Colombier void
simple(char * dest,char * cmd)1303e12c5d1SDavid du Colombier simple(char *dest, char *cmd)
1313e12c5d1SDavid du Colombier {
1323e12c5d1SDavid du Colombier 	int net;
1333e12c5d1SDavid du Colombier 
1343e12c5d1SDavid du Colombier 	net = dodial(dest, 0, 0);
1353e12c5d1SDavid du Colombier 	if(net < 0)
1363e12c5d1SDavid du Colombier 		return;
1373e12c5d1SDavid du Colombier 
1383e12c5d1SDavid du Colombier 	if(cmd)
1393e12c5d1SDavid du Colombier 		dosystem(net, cmd);
1403e12c5d1SDavid du Colombier 
1413e12c5d1SDavid du Colombier 	if(!cooked)
1423e12c5d1SDavid du Colombier 		rawon();
1433e12c5d1SDavid du Colombier 	stdcon(net);
1443e12c5d1SDavid du Colombier 	exits(0);
1453e12c5d1SDavid du Colombier }
1463e12c5d1SDavid du Colombier 
1473e12c5d1SDavid du Colombier /*
1483e12c5d1SDavid du Colombier  *  dial, do UCB authentication, use as a byte stream with local echo
1493e12c5d1SDavid du Colombier  *
1503e12c5d1SDavid du Colombier  *  return if dial failed
1513e12c5d1SDavid du Colombier  */
1523e12c5d1SDavid du Colombier void
rlogin(char * dest,char * cmd)1533e12c5d1SDavid du Colombier rlogin(char *dest, char *cmd)
1543e12c5d1SDavid du Colombier {
1557dd7cddfSDavid du Colombier 	int net;
1569a747e4fSDavid du Colombier 	char buf[128];
1573e12c5d1SDavid du Colombier 	char *p;
1583e12c5d1SDavid du Colombier 	char *localuser;
1593e12c5d1SDavid du Colombier 
1603e12c5d1SDavid du Colombier 	/* only useful on TCP */
161bd389b36SDavid du Colombier 	if(strchr(dest, '!')
162bd389b36SDavid du Colombier 	&& (strncmp(dest, "tcp!", 4)!=0 && strncmp(dest, "net!", 4)!=0))
1633e12c5d1SDavid du Colombier 		return;
1643e12c5d1SDavid du Colombier 
1653e12c5d1SDavid du Colombier 	net = dodial(dest, "tcp", "login");
1663e12c5d1SDavid du Colombier 	if(net < 0)
1673e12c5d1SDavid du Colombier 		return;
1683e12c5d1SDavid du Colombier 
1693e12c5d1SDavid du Colombier 	/*
1703e12c5d1SDavid du Colombier 	 *  do UCB rlogin authentication
1713e12c5d1SDavid du Colombier 	 */
1727dd7cddfSDavid du Colombier 	localuser = getuser();
1733e12c5d1SDavid du Colombier 	if(remuser == 0){
1743e12c5d1SDavid du Colombier 		if(limited)
1753e12c5d1SDavid du Colombier 			remuser = ":";
1763e12c5d1SDavid du Colombier 		else
1773e12c5d1SDavid du Colombier 			remuser = localuser;
1783e12c5d1SDavid du Colombier 	}
1793e12c5d1SDavid du Colombier 	p = getenv("TERM");
1803e12c5d1SDavid du Colombier 	if(p == 0)
1813e12c5d1SDavid du Colombier 		p = "p9";
1823e12c5d1SDavid du Colombier 	if(write(net, "", 1)<0
1833e12c5d1SDavid du Colombier 	|| write(net, localuser, strlen(localuser)+1)<0
1843e12c5d1SDavid du Colombier 	|| write(net, remuser, strlen(remuser)+1)<0
1853e12c5d1SDavid du Colombier 	|| write(net, p, strlen(p)+1)<0){
1863e12c5d1SDavid du Colombier 		close(net);
1873e12c5d1SDavid du Colombier 		punt("BSD authentication failed");
1883e12c5d1SDavid du Colombier 	}
1893e12c5d1SDavid du Colombier 	if(read(net, buf, 1) != 1)
1903e12c5d1SDavid du Colombier 		punt("BSD authentication failed1");
1913e12c5d1SDavid du Colombier 	if(buf[0] != 0){
1923e12c5d1SDavid du Colombier 		fprint(2, "con: remote error: ");
1933e12c5d1SDavid du Colombier 		while(read(net, buf, 1) == 1){
1943e12c5d1SDavid du Colombier 			write(2, buf, 1);
1953e12c5d1SDavid du Colombier 			if(buf[0] == '\n')
1963e12c5d1SDavid du Colombier 				break;
1973e12c5d1SDavid du Colombier 		}
1983e12c5d1SDavid du Colombier 		exits("read");
1993e12c5d1SDavid du Colombier 	}
2003e12c5d1SDavid du Colombier 
2013e12c5d1SDavid du Colombier 	if(cmd)
2023e12c5d1SDavid du Colombier 		dosystem(net, cmd);
2033e12c5d1SDavid du Colombier 
2043e12c5d1SDavid du Colombier 	if(!cooked)
2053e12c5d1SDavid du Colombier 		rawon();
2067dd7cddfSDavid du Colombier 	nltocr = 1;
2073e12c5d1SDavid du Colombier 	stdcon(net);
2083e12c5d1SDavid du Colombier 	exits(0);
2093e12c5d1SDavid du Colombier }
2103e12c5d1SDavid du Colombier 
2113e12c5d1SDavid du Colombier /*
2123e12c5d1SDavid du Colombier  *  just open a device and use it as a connection
2133e12c5d1SDavid du Colombier  */
2143e12c5d1SDavid du Colombier void
device(char * dest,char * cmd)2153e12c5d1SDavid du Colombier device(char *dest, char *cmd)
2163e12c5d1SDavid du Colombier {
2173e12c5d1SDavid du Colombier 	int net;
2189a747e4fSDavid du Colombier 	char cname[128];
2193e12c5d1SDavid du Colombier 
2203e12c5d1SDavid du Colombier 	net = open(dest, ORDWR);
2217dd7cddfSDavid du Colombier 	if(net < 0) {
2227dd7cddfSDavid du Colombier 		fprint(2, "con: cannot open %s: %r\n", dest);
2237dd7cddfSDavid du Colombier 		exits("open");
2247dd7cddfSDavid du Colombier 	}
2259a747e4fSDavid du Colombier 	snprint(cname, sizeof cname, "%sctl", dest);
2263e12c5d1SDavid du Colombier 	ctl = open(cname, ORDWR);
2279a747e4fSDavid du Colombier 	if (baud > 0) {
228f845c312SDavid du Colombier 		if(ctl >= 0){
229f845c312SDavid du Colombier 			/* set speed and use fifos if available */
230f845c312SDavid du Colombier 			fprint(ctl, "b%d i1", baud);
231f845c312SDavid du Colombier 		}
2329a747e4fSDavid du Colombier 		else
2339a747e4fSDavid du Colombier 			fprint(2, "con: cannot open %s: %r\n", cname);
2349a747e4fSDavid du Colombier 	}
2353e12c5d1SDavid du Colombier 
2363e12c5d1SDavid du Colombier 	if(cmd)
2373e12c5d1SDavid du Colombier 		dosystem(net, cmd);
2383e12c5d1SDavid du Colombier 
2393e12c5d1SDavid du Colombier 	if(!cooked)
2403e12c5d1SDavid du Colombier 		rawon();
2413e12c5d1SDavid du Colombier 	stdcon(net);
2423e12c5d1SDavid du Colombier 	exits(0);
2433e12c5d1SDavid du Colombier }
2443e12c5d1SDavid du Colombier 
2453e12c5d1SDavid du Colombier /*
2463e12c5d1SDavid du Colombier  *  ignore interrupts
2473e12c5d1SDavid du Colombier  */
2483e12c5d1SDavid du Colombier void
notifyf(void * a,char * msg)2493e12c5d1SDavid du Colombier notifyf(void *a, char *msg)
2503e12c5d1SDavid du Colombier {
2513e12c5d1SDavid du Colombier 	USED(a);
2523e12c5d1SDavid du Colombier 
253d3c05884SDavid du Colombier 	if(strstr(msg, "yankee"))
254d3c05884SDavid du Colombier 		noted(NDFLT);
2553e12c5d1SDavid du Colombier 	if(strstr(msg, "closed pipe")
2563e12c5d1SDavid du Colombier 	|| strcmp(msg, "interrupt") == 0
2573e12c5d1SDavid du Colombier 	|| strcmp(msg, "hangup") == 0)
2583e12c5d1SDavid du Colombier 		noted(NCONT);
2593e12c5d1SDavid du Colombier 	noted(NDFLT);
2603e12c5d1SDavid du Colombier }
2613e12c5d1SDavid du Colombier 
2623e12c5d1SDavid du Colombier /*
2633e12c5d1SDavid du Colombier  *  turn keyboard raw mode on
2643e12c5d1SDavid du Colombier  */
2653e12c5d1SDavid du Colombier void
rawon(void)2663e12c5d1SDavid du Colombier rawon(void)
2673e12c5d1SDavid du Colombier {
2683e12c5d1SDavid du Colombier 	if(debug)
2693e12c5d1SDavid du Colombier 		fprint(2, "rawon\n");
2703e12c5d1SDavid du Colombier 	if(raw)
2713e12c5d1SDavid du Colombier 		return;
2723e12c5d1SDavid du Colombier 	if(consctl < 0)
2733e12c5d1SDavid du Colombier 		consctl = open("/dev/consctl", OWRITE);
2743e12c5d1SDavid du Colombier 	if(consctl < 0){
2759a747e4fSDavid du Colombier //		fprint(2, "can't open consctl\n");
2763e12c5d1SDavid du Colombier 		return;
2773e12c5d1SDavid du Colombier 	}
2783e12c5d1SDavid du Colombier 	write(consctl, "rawon", 5);
2793e12c5d1SDavid du Colombier 	raw = 1;
2803e12c5d1SDavid du Colombier }
2813e12c5d1SDavid du Colombier 
2823e12c5d1SDavid du Colombier /*
2833e12c5d1SDavid du Colombier  *  turn keyboard raw mode off
2843e12c5d1SDavid du Colombier  */
2853e12c5d1SDavid du Colombier void
rawoff(void)2863e12c5d1SDavid du Colombier rawoff(void)
2873e12c5d1SDavid du Colombier {
2883e12c5d1SDavid du Colombier 	if(debug)
2893e12c5d1SDavid du Colombier 		fprint(2, "rawoff\n");
2903e12c5d1SDavid du Colombier 	if(raw == 0)
2913e12c5d1SDavid du Colombier 		return;
2923e12c5d1SDavid du Colombier 	if(consctl < 0)
2933e12c5d1SDavid du Colombier 		consctl = open("/dev/consctl", OWRITE);
2943e12c5d1SDavid du Colombier 	if(consctl < 0){
2959a747e4fSDavid du Colombier //		fprint(2, "can't open consctl\n");
2963e12c5d1SDavid du Colombier 		return;
2973e12c5d1SDavid du Colombier 	}
2983e12c5d1SDavid du Colombier 	write(consctl, "rawoff", 6);
2993e12c5d1SDavid du Colombier 	raw = 0;
3003e12c5d1SDavid du Colombier }
3013e12c5d1SDavid du Colombier 
3023e12c5d1SDavid du Colombier /*
3033e12c5d1SDavid du Colombier  *  control menu
3043e12c5d1SDavid du Colombier  */
3057dd7cddfSDavid du Colombier #define STDHELP	"\t(b)reak, (q)uit, (i)nterrupt, toggle printing (r)eturns, (.)continue, (!cmd)\n"
3063e12c5d1SDavid du Colombier 
3073e12c5d1SDavid du Colombier int
menu(int net)3083e12c5d1SDavid du Colombier menu(int net)
3093e12c5d1SDavid du Colombier {
3103e12c5d1SDavid du Colombier 	char buf[MAXMSG];
3113e12c5d1SDavid du Colombier 	long n;
3123e12c5d1SDavid du Colombier 	int done;
3133e12c5d1SDavid du Colombier 	int wasraw = raw;
3143e12c5d1SDavid du Colombier 
3153e12c5d1SDavid du Colombier 	if(wasraw)
3163e12c5d1SDavid du Colombier 		rawoff();
3173e12c5d1SDavid du Colombier 
3183e12c5d1SDavid du Colombier 	fprint(2, ">>> ");
3193e12c5d1SDavid du Colombier 	for(done = 0; !done; ){
3203e12c5d1SDavid du Colombier 		n = read(0, buf, sizeof(buf)-1);
3213e12c5d1SDavid du Colombier 		if(n <= 0)
3223e12c5d1SDavid du Colombier 			return -1;
3233e12c5d1SDavid du Colombier 		buf[n] = 0;
3243e12c5d1SDavid du Colombier 		switch(buf[0]){
3253e12c5d1SDavid du Colombier 		case '!':
3263e12c5d1SDavid du Colombier 			print(buf);
3273e12c5d1SDavid du Colombier 			system(net, buf+1);
3283e12c5d1SDavid du Colombier 			print("!\n");
3293e12c5d1SDavid du Colombier 			done = 1;
3303e12c5d1SDavid du Colombier 			break;
3313e12c5d1SDavid du Colombier 		case '.':
3323e12c5d1SDavid du Colombier 			done = 1;
3333e12c5d1SDavid du Colombier 			break;
3343e12c5d1SDavid du Colombier 		case 'q':
3353e12c5d1SDavid du Colombier 			return -1;
3363e12c5d1SDavid du Colombier 		case 'i':
3373e12c5d1SDavid du Colombier 			buf[0] = 0x1c;
3383e12c5d1SDavid du Colombier 			write(net, buf, 1);
3393e12c5d1SDavid du Colombier 			done = 1;
3403e12c5d1SDavid du Colombier 			break;
3413e12c5d1SDavid du Colombier 		case 'b':
342*3b86f2f8SDavid du Colombier 			if(ctl >= 0)
343219b2ee8SDavid du Colombier 				write(ctl, "k", 1);
344219b2ee8SDavid du Colombier 			done = 1;
345219b2ee8SDavid du Colombier 			break;
346219b2ee8SDavid du Colombier 		case 'r':
347219b2ee8SDavid du Colombier 			returns = 1-returns;
3483e12c5d1SDavid du Colombier 			done = 1;
3493e12c5d1SDavid du Colombier 			break;
3503e12c5d1SDavid du Colombier 		default:
3513e12c5d1SDavid du Colombier 			fprint(2, STDHELP);
3523e12c5d1SDavid du Colombier 			break;
3533e12c5d1SDavid du Colombier 		}
3543e12c5d1SDavid du Colombier 		if(!done)
3553e12c5d1SDavid du Colombier 			fprint(2, ">>> ");
3563e12c5d1SDavid du Colombier 	}
3573e12c5d1SDavid du Colombier 
3583e12c5d1SDavid du Colombier 	if(wasraw)
3593e12c5d1SDavid du Colombier 		rawon();
3603e12c5d1SDavid du Colombier 	else
3613e12c5d1SDavid du Colombier 		rawoff();
3623e12c5d1SDavid du Colombier 	return 0;
3633e12c5d1SDavid du Colombier }
3643e12c5d1SDavid du Colombier 
365*3b86f2f8SDavid du Colombier void
post(char * srv,int fd)366*3b86f2f8SDavid du Colombier post(char *srv, int fd)
367*3b86f2f8SDavid du Colombier {
368*3b86f2f8SDavid du Colombier 	int f;
369*3b86f2f8SDavid du Colombier 	char buf[32];
370*3b86f2f8SDavid du Colombier 
371*3b86f2f8SDavid du Colombier 	f = create(srv, OWRITE /* |ORCLOSE */ , 0666);
372*3b86f2f8SDavid du Colombier 	if(f < 0)
373*3b86f2f8SDavid du Colombier 		sysfatal("create %s: %r", srv);
374*3b86f2f8SDavid du Colombier 	snprint(buf, sizeof buf, "%d", fd);
375*3b86f2f8SDavid du Colombier 	if(write(f, buf, strlen(buf)) != strlen(buf))
376*3b86f2f8SDavid du Colombier 		sysfatal("write %s: %r", srv);
377*3b86f2f8SDavid du Colombier 	close(f);
378*3b86f2f8SDavid du Colombier }
379*3b86f2f8SDavid du Colombier 
3803e12c5d1SDavid du Colombier /*
3813e12c5d1SDavid du Colombier  *  the real work.  two processes pass bytes back and forth between the
3823e12c5d1SDavid du Colombier  *  terminal and the network.
3833e12c5d1SDavid du Colombier  */
3843e12c5d1SDavid du Colombier void
stdcon(int net)3853e12c5d1SDavid du Colombier stdcon(int net)
3863e12c5d1SDavid du Colombier {
3873e12c5d1SDavid du Colombier 	int netpid;
388*3b86f2f8SDavid du Colombier 	int p[2];
389*3b86f2f8SDavid du Colombier 	char *svc;
3903e12c5d1SDavid du Colombier 
391*3b86f2f8SDavid du Colombier 	svc = nil;
392*3b86f2f8SDavid du Colombier 	if (srv) {
393*3b86f2f8SDavid du Colombier 		if(pipe(p) < 0)
394*3b86f2f8SDavid du Colombier 			sysfatal("pipe: %r");
395*3b86f2f8SDavid du Colombier 		if (srv[0] != '/')
396*3b86f2f8SDavid du Colombier 			svc = smprint("/srv/%s", srv);
397*3b86f2f8SDavid du Colombier 		else
398*3b86f2f8SDavid du Colombier 			svc = srv;
399*3b86f2f8SDavid du Colombier 		post(svc, p[0]);
400*3b86f2f8SDavid du Colombier 		close(p[0]);
401*3b86f2f8SDavid du Colombier 		dup(p[1], 0);
402*3b86f2f8SDavid du Colombier 		dup(p[1], 1);
403*3b86f2f8SDavid du Colombier 		/* pipe is now std in & out */
404*3b86f2f8SDavid du Colombier 	}
4053e12c5d1SDavid du Colombier 	ttypid = getpid();
4063e12c5d1SDavid du Colombier 	switch(netpid = rfork(RFMEM|RFPROC)){
4073e12c5d1SDavid du Colombier 	case -1:
4083e12c5d1SDavid du Colombier 		perror("con");
4093e12c5d1SDavid du Colombier 		exits("fork");
4103e12c5d1SDavid du Colombier 	case 0:
4113e12c5d1SDavid du Colombier 		notify(notifyf);
4123e12c5d1SDavid du Colombier 		fromnet(net);
413*3b86f2f8SDavid du Colombier 		if (svc)
414*3b86f2f8SDavid du Colombier 			remove(svc);
415d3c05884SDavid du Colombier 		postnote(PNPROC, ttypid, "die yankee dog");
4163e12c5d1SDavid du Colombier 		exits(0);
4173e12c5d1SDavid du Colombier 	default:
4183e12c5d1SDavid du Colombier 		notify(notifyf);
4193e12c5d1SDavid du Colombier 		fromkbd(net);
420*3b86f2f8SDavid du Colombier 		if (svc)
421*3b86f2f8SDavid du Colombier 			remove(svc);
4227dd7cddfSDavid du Colombier 		if(notkbd)
423*3b86f2f8SDavid du Colombier 			for(;;)
424*3b86f2f8SDavid du Colombier 				sleep(0);
425d3c05884SDavid du Colombier 		postnote(PNPROC, netpid, "die yankee dog");
4263e12c5d1SDavid du Colombier 		exits(0);
4273e12c5d1SDavid du Colombier 	}
4283e12c5d1SDavid du Colombier }
4293e12c5d1SDavid du Colombier 
4303e12c5d1SDavid du Colombier /*
4313e12c5d1SDavid du Colombier  *  Read the keyboard and write it to the network.  '^\' gets us into
4323e12c5d1SDavid du Colombier  *  the menu.
4333e12c5d1SDavid du Colombier  */
4343e12c5d1SDavid du Colombier void
fromkbd(int net)4353e12c5d1SDavid du Colombier fromkbd(int net)
4363e12c5d1SDavid du Colombier {
4373e12c5d1SDavid du Colombier 	long n;
4383e12c5d1SDavid du Colombier 	char buf[MAXMSG];
4397dd7cddfSDavid du Colombier 	char *p, *ep;
4407dd7cddfSDavid du Colombier 	int eofs;
4413e12c5d1SDavid du Colombier 
4427dd7cddfSDavid du Colombier 	eofs = 0;
4433e12c5d1SDavid du Colombier 	for(;;){
4443e12c5d1SDavid du Colombier 		n = read(0, buf, sizeof(buf));
4453e12c5d1SDavid du Colombier 		if(n < 0){
4463e12c5d1SDavid du Colombier 			if(wasintr()){
447d3c05884SDavid du Colombier 				if(!raw){
4483e12c5d1SDavid du Colombier 					buf[0] = 0x7f;
4493e12c5d1SDavid du Colombier 					n = 1;
4503e12c5d1SDavid du Colombier 				} else
4513e12c5d1SDavid du Colombier 					continue;
4523e12c5d1SDavid du Colombier 			} else
4533e12c5d1SDavid du Colombier 				return;
4543e12c5d1SDavid du Colombier 		}
4557dd7cddfSDavid du Colombier 		if(n == 0){
4567dd7cddfSDavid du Colombier 			if(++eofs > 32)
4577dd7cddfSDavid du Colombier 				return;
4587dd7cddfSDavid du Colombier 		} else
4597dd7cddfSDavid du Colombier 			eofs = 0;
4603e12c5d1SDavid du Colombier 		if(n && memchr(buf, 0x1c, n)){
4613e12c5d1SDavid du Colombier 			if(menu(net) < 0)
4623e12c5d1SDavid du Colombier 				return;
4633e12c5d1SDavid du Colombier 		}else{
464d3c05884SDavid du Colombier 			if(!raw && n==0){
4653e12c5d1SDavid du Colombier 				buf[0] = 0x4;
4663e12c5d1SDavid du Colombier 				n = 1;
4673e12c5d1SDavid du Colombier 			}
4687dd7cddfSDavid du Colombier 			if(nltocr){
4697dd7cddfSDavid du Colombier 				ep = buf+n;
4707dd7cddfSDavid du Colombier 				for(p = buf; p < ep; p++)
4717dd7cddfSDavid du Colombier 					switch(*p){
4727dd7cddfSDavid du Colombier 					case '\r':
4737dd7cddfSDavid du Colombier 						*p = '\n';
4747dd7cddfSDavid du Colombier 						break;
4757dd7cddfSDavid du Colombier 					case '\n':
4767dd7cddfSDavid du Colombier 						*p = '\r';
4777dd7cddfSDavid du Colombier 						break;
4787dd7cddfSDavid du Colombier 					}
4797dd7cddfSDavid du Colombier 			}
4803e12c5d1SDavid du Colombier 			if(iwrite(net, buf, n) != n)
4813e12c5d1SDavid du Colombier 				return;
4823e12c5d1SDavid du Colombier 		}
4833e12c5d1SDavid du Colombier 	}
4843e12c5d1SDavid du Colombier }
4853e12c5d1SDavid du Colombier 
4863e12c5d1SDavid du Colombier /*
4873e12c5d1SDavid du Colombier  *  Read from the network and write to the screen.
4883e12c5d1SDavid du Colombier  *  Filter out spurious carriage returns.
4893e12c5d1SDavid du Colombier  */
4903e12c5d1SDavid du Colombier void
fromnet(int net)4913e12c5d1SDavid du Colombier fromnet(int net)
4923e12c5d1SDavid du Colombier {
4933e12c5d1SDavid du Colombier 	long n;
4943e12c5d1SDavid du Colombier 	char buf[MAXMSG];
4953e12c5d1SDavid du Colombier 	char *cp, *ep;
4963e12c5d1SDavid du Colombier 
4973e12c5d1SDavid du Colombier 	for(;;){
4983e12c5d1SDavid du Colombier 		n = iread(net, buf, sizeof(buf));
4993e12c5d1SDavid du Colombier 		if(n < 0)
5003e12c5d1SDavid du Colombier 			return;
5013e12c5d1SDavid du Colombier 		if(n == 0)
5023e12c5d1SDavid du Colombier 			continue;
5033e12c5d1SDavid du Colombier 
504219b2ee8SDavid du Colombier 		if (strip)
505219b2ee8SDavid du Colombier 			for (cp=buf; cp<buf+n; cp++)
506219b2ee8SDavid du Colombier 				*cp &= 0177;
507219b2ee8SDavid du Colombier 
5085d459b5aSDavid du Colombier 		if(crtonl) {
5095d459b5aSDavid du Colombier 			/* convert cr's to nl's */
5105d459b5aSDavid du Colombier 			for (cp = buf; cp < buf + n; cp++)
5115d459b5aSDavid du Colombier 				if (*cp == '\r')
5125d459b5aSDavid du Colombier 					*cp = '\n';
5135d459b5aSDavid du Colombier 		}
5145d459b5aSDavid du Colombier 		else if(!returns){
5153e12c5d1SDavid du Colombier 			/* convert cr's to null's */
5163e12c5d1SDavid du Colombier 			cp = buf;
5173e12c5d1SDavid du Colombier 			ep = buf + n;
5183e12c5d1SDavid du Colombier 			while(cp < ep && (cp = memchr(cp, '\r', ep-cp))){
5193e12c5d1SDavid du Colombier 				memmove(cp, cp+1, ep-cp-1);
5203e12c5d1SDavid du Colombier 				ep--;
5213e12c5d1SDavid du Colombier 				n--;
5223e12c5d1SDavid du Colombier 			}
5233e12c5d1SDavid du Colombier 		}
5243e12c5d1SDavid du Colombier 
5253e12c5d1SDavid du Colombier 		if(n > 0 && iwrite(outfd, buf, n) != n){
5263e12c5d1SDavid du Colombier 			if(outfd == 1)
5273e12c5d1SDavid du Colombier 				return;
5283e12c5d1SDavid du Colombier 			outfd = 1;
5293e12c5d1SDavid du Colombier 			if(iwrite(1, buf, n) != n)
5303e12c5d1SDavid du Colombier 				return;
5313e12c5d1SDavid du Colombier 		}
5323e12c5d1SDavid du Colombier 	}
5333e12c5d1SDavid du Colombier }
5343e12c5d1SDavid du Colombier 
5353e12c5d1SDavid du Colombier /*
5363e12c5d1SDavid du Colombier  *  dial and return a data connection
5373e12c5d1SDavid du Colombier  */
5383e12c5d1SDavid du Colombier int
dodial(char * dest,char * net,char * service)5393e12c5d1SDavid du Colombier dodial(char *dest, char *net, char *service)
5403e12c5d1SDavid du Colombier {
5419a747e4fSDavid du Colombier 	char name[128];
5429a747e4fSDavid du Colombier 	char devdir[128];
5433e12c5d1SDavid du Colombier 	int data;
5443e12c5d1SDavid du Colombier 
5453e12c5d1SDavid du Colombier 	devdir[0] = 0;
5463e12c5d1SDavid du Colombier 	strcpy(name, netmkaddr(dest, net, service));
547bd389b36SDavid du Colombier 	data = dial(name, 0, devdir, &ctl);
5483e12c5d1SDavid du Colombier 	if(data < 0){
549219b2ee8SDavid du Colombier 		seterr(name);
5503e12c5d1SDavid du Colombier 		return -1;
5513e12c5d1SDavid du Colombier 	}
5523e12c5d1SDavid du Colombier 	fprint(2, "connected to %s on %s\n", name, devdir);
5533e12c5d1SDavid du Colombier 	return data;
5543e12c5d1SDavid du Colombier }
5553e12c5d1SDavid du Colombier 
5563e12c5d1SDavid du Colombier void
dosystem(int fd,char * cmd)5573e12c5d1SDavid du Colombier dosystem(int fd, char *cmd)
5583e12c5d1SDavid du Colombier {
5593e12c5d1SDavid du Colombier 	char *p;
5603e12c5d1SDavid du Colombier 
5613e12c5d1SDavid du Colombier 	p = system(fd, cmd);
562fbdb243dSDavid du Colombier 	if(p){
5637dd7cddfSDavid du Colombier 		print("con: %s terminated with %s\n", cmd, p);
5643e12c5d1SDavid du Colombier 		exits(p);
5653e12c5d1SDavid du Colombier 	}
5663e12c5d1SDavid du Colombier }
5673e12c5d1SDavid du Colombier 
5683e12c5d1SDavid du Colombier /*
5693e12c5d1SDavid du Colombier  *  run a command with the network connection as standard IO
5703e12c5d1SDavid du Colombier  */
5713e12c5d1SDavid du Colombier char *
system(int fd,char * cmd)5723e12c5d1SDavid du Colombier system(int fd, char *cmd)
5733e12c5d1SDavid du Colombier {
5743e12c5d1SDavid du Colombier 	int pid;
5753e12c5d1SDavid du Colombier 	int p;
5763e12c5d1SDavid du Colombier 	static Waitmsg msg;
5773e12c5d1SDavid du Colombier 	int pfd[2];
5783e12c5d1SDavid du Colombier 	int n;
5793e12c5d1SDavid du Colombier 	char buf[4096];
5803e12c5d1SDavid du Colombier 
5813e12c5d1SDavid du Colombier 	if(pipe(pfd) < 0){
5823e12c5d1SDavid du Colombier 		perror("pipe");
5833e12c5d1SDavid du Colombier 		return "pipe failed";
5843e12c5d1SDavid du Colombier 	}
5853e12c5d1SDavid du Colombier 	outfd = pfd[1];
5863e12c5d1SDavid du Colombier 
587219b2ee8SDavid du Colombier 	close(consctl);
588219b2ee8SDavid du Colombier 	consctl = -1;
5893e12c5d1SDavid du Colombier 	switch(pid = fork()){
5903e12c5d1SDavid du Colombier 	case -1:
5913e12c5d1SDavid du Colombier 		perror("con");
5923e12c5d1SDavid du Colombier 		return "fork failed";
5933e12c5d1SDavid du Colombier 	case 0:
5943e12c5d1SDavid du Colombier 		close(pfd[1]);
5953e12c5d1SDavid du Colombier 		dup(pfd[0], 0);
5963ff48bf5SDavid du Colombier 		dup(fd, 1);
5973e12c5d1SDavid du Colombier 		close(ctl);
5983e12c5d1SDavid du Colombier 		close(fd);
5993e12c5d1SDavid du Colombier 		close(pfd[0]);
6003e12c5d1SDavid du Colombier 		if(*cmd)
601f19e7b74SDavid du Colombier 			execl("/bin/rc", "rc", "-c", cmd, nil);
6023e12c5d1SDavid du Colombier 		else
603f19e7b74SDavid du Colombier 			execl("/bin/rc", "rc", nil);
6043e12c5d1SDavid du Colombier 		perror("con");
6053e12c5d1SDavid du Colombier 		exits("exec");
6063e12c5d1SDavid du Colombier 		break;
6073e12c5d1SDavid du Colombier 	default:
6083e12c5d1SDavid du Colombier 		close(pfd[0]);
609*3b86f2f8SDavid du Colombier 		while((n = read(pfd[1], buf, sizeof(buf))) > 0)
6103e12c5d1SDavid du Colombier 			if(write(fd, buf, n) != n)
6113e12c5d1SDavid du Colombier 				break;
6129a747e4fSDavid du Colombier 		p = waitpid();
6133e12c5d1SDavid du Colombier 		outfd = 1;
6143e12c5d1SDavid du Colombier 		close(pfd[1]);
615219b2ee8SDavid du Colombier 		if(p < 0 || p != pid)
616219b2ee8SDavid du Colombier 			return "lost child";
6173e12c5d1SDavid du Colombier 		break;
6183e12c5d1SDavid du Colombier 	}
619219b2ee8SDavid du Colombier 	return msg.msg;
6203e12c5d1SDavid du Colombier }
6213e12c5d1SDavid du Colombier 
6223e12c5d1SDavid du Colombier int
wasintr(void)6233e12c5d1SDavid du Colombier wasintr(void)
6243e12c5d1SDavid du Colombier {
6253e12c5d1SDavid du Colombier 	return strcmp(syserr(), "interrupted") == 0;
6263e12c5d1SDavid du Colombier }
6273e12c5d1SDavid du Colombier 
6283e12c5d1SDavid du Colombier void
punt(char * msg)6293e12c5d1SDavid du Colombier punt(char *msg)
6303e12c5d1SDavid du Colombier {
6313e12c5d1SDavid du Colombier 	if(*msg == 0)
6323e12c5d1SDavid du Colombier 		msg = transerr;
6333e12c5d1SDavid du Colombier 	fprint(2, "con: %s\n", msg);
6343e12c5d1SDavid du Colombier 	exits(msg);
6353e12c5d1SDavid du Colombier }
6363e12c5d1SDavid du Colombier 
6373e12c5d1SDavid du Colombier char*
syserr(void)6383e12c5d1SDavid du Colombier syserr(void)
6393e12c5d1SDavid du Colombier {
6409a747e4fSDavid du Colombier 	static char err[ERRMAX];
6419a747e4fSDavid du Colombier 	errstr(err, sizeof err);
6423e12c5d1SDavid du Colombier 	return err;
6433e12c5d1SDavid du Colombier }
6443e12c5d1SDavid du Colombier 
6453e12c5d1SDavid du Colombier void
seterr(char * addr)646219b2ee8SDavid du Colombier seterr(char *addr)
6473e12c5d1SDavid du Colombier {
6483e12c5d1SDavid du Colombier 	char *se = syserr();
6493e12c5d1SDavid du Colombier 
6503e12c5d1SDavid du Colombier 	if(verbose)
651219b2ee8SDavid du Colombier 		fprint(2, "'%s' calling %s\n", se, addr);
6523e12c5d1SDavid du Colombier 	if(firsterr[0] && (strstr(se, "translate") ||
6533e12c5d1SDavid du Colombier 	 strstr(se, "file does not exist") ||
6543e12c5d1SDavid du Colombier 	 strstr(se, "unknown address") ||
6553e12c5d1SDavid du Colombier 	 strstr(se, "directory entry not found")))
6563e12c5d1SDavid du Colombier 		return;
6573e12c5d1SDavid du Colombier 	strcpy(firsterr, se);
6583e12c5d1SDavid du Colombier }
6593e12c5d1SDavid du Colombier 
6603e12c5d1SDavid du Colombier 
6613e12c5d1SDavid du Colombier long
iread(int f,void * a,int n)6623e12c5d1SDavid du Colombier iread(int f, void *a, int n)
6633e12c5d1SDavid du Colombier {
6643e12c5d1SDavid du Colombier 	long m;
6653e12c5d1SDavid du Colombier 
6663e12c5d1SDavid du Colombier 	for(;;){
6673e12c5d1SDavid du Colombier 		m = read(f, a, n);
6683e12c5d1SDavid du Colombier 		if(m >= 0 || !wasintr())
6693e12c5d1SDavid du Colombier 			break;
6703e12c5d1SDavid du Colombier 	}
6713e12c5d1SDavid du Colombier 	return m;
6723e12c5d1SDavid du Colombier }
6733e12c5d1SDavid du Colombier 
6743e12c5d1SDavid du Colombier long
iwrite(int f,void * a,int n)6753e12c5d1SDavid du Colombier iwrite(int f, void *a, int n)
6763e12c5d1SDavid du Colombier {
6773e12c5d1SDavid du Colombier 	long m;
6783e12c5d1SDavid du Colombier 
6793e12c5d1SDavid du Colombier 	m = write(f, a, n);
6803e12c5d1SDavid du Colombier 	if(m < 0 && wasintr())
6813e12c5d1SDavid du Colombier 		return n;
6823e12c5d1SDavid du Colombier 	return m;
6833e12c5d1SDavid du Colombier }
684