692 lines · 11.1 KB · C
RawDownload
/*  * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include <u.h>#include <libc.h> int debug;		/* true if debugging */int ctl = -1;		/* control fd (for break's) */int raw;		/* true if raw is on */int consctl = -1;	/* control fd for cons */int ttypid;		/* pid's if the 2 processes (used to kill them) */int outfd = 1;		/* local output file descriptor */int cooked;		/* non-zero forces cooked mode */int returns;		/* non-zero forces carriage returns not to be filtered out */int crtonl;			/* non-zero forces carriage returns to be converted to nls coming from net */int	strip;		/* strip off parity bits */char firsterr[2*ERRMAX];char transerr[2*ERRMAX];int limited;char *remuser;		/* for BSD rlogin authentication */int verbose;int baud;int notkbd;int nltocr;		/* translate kbd nl to cr  and vice versa */ static char *srv; #define MAXMSG (2*8192) int	dodial(char*, char*, char*);void	fromkbd(int);void	fromnet(int);long	iread(int, void*, int);long	iwrite(int, void*, int);int	menu(int);void	notifyf(void*, char*);void	pass(int, int, int);void	rawoff(void);void	rawon(void);void	stdcon(int);char*	system(int, char*);void	dosystem(int, char*);int	wasintr(void);void	punt(char*);char*	syserr(void);void	seterr(char*); /* protocols */void	device(char*, char*);void	rlogin(char*, char*);void	simple(char*, char*); voidusage(void){	punt("usage: con [-CdnrRsTv] [-b baud] [-l [user]] [-c cmd] [-S svc] "		"net!host[!service]");} voidmain(int argc, char *argv[]){	char *dest;	char *cmd = 0; 	returns = 1;	ARGBEGIN{	case 'b':		baud = atoi(EARGF(usage()));		break;	case 'C':		cooked = 1;		break;	case 'c':		cmd = EARGF(usage());		break;	case 'd':		debug = 1;		break;	case 'l':		limited = 1;		if(argv[1] != nil && argv[1][0] != '-')			remuser = EARGF(usage());		break;	case 'n':		notkbd = 1;		break;	case 'r':		returns = 0;		break;	case 's':		strip = 1;		break;	case 'S':		srv = EARGF(usage());		break;	case 'R':		nltocr = 1;		break;	case 'T':		crtonl = 1;		break;	case 'v':		verbose = 1;		break;	default:		usage();	}ARGEND 	if(argc != 1){		if(remuser == 0)			usage();		dest = remuser;		remuser = 0;	} else		dest = argv[0];	if(*dest == '/' && strchr(dest, '!') == 0)		device(dest, cmd);	else if(limited){		simple(dest, cmd);	/* doesn't return if dialout succeeds */		rlogin(dest, cmd);	/* doesn't return if dialout succeeds */	} else {		rlogin(dest, cmd);	/* doesn't return if dialout succeeds */		simple(dest, cmd);	/* doesn't return if dialout succeeds */	}	punt(firsterr);} /* *  just dial and use as a byte stream with remote echo */voidsimple(char *dest, char *cmd){	int net; 	net = dodial(dest, 0, 0);	if(net < 0)		return; 	if(cmd)		dosystem(net, cmd); 	if(!cooked)		rawon();	stdcon(net);	exits(0);} /* *  dial, do UCB authentication, use as a byte stream with local echo * *  return if dial failed */voidrlogin(char *dest, char *cmd){	int net;	char buf[128];	char *p;	char *localuser; 	/* only useful on TCP */	if(strchr(dest, '!')	&& (strncmp(dest, "tcp!", 4)!=0 && strncmp(dest, "net!", 4)!=0))		return; 	net = dodial(dest, "tcp", "login");	if(net < 0)		return; 	/*	 *  do UCB rlogin authentication	 */	localuser = getuser();	if(remuser == 0){		if(limited)			remuser = ":";		else			remuser = localuser;	}	p = getenv("TERM");	if(p == 0)		p = "p9";	if(write(net, "", 1)<0	|| write(net, localuser, strlen(localuser)+1)<0	|| write(net, remuser, strlen(remuser)+1)<0	|| write(net, p, strlen(p)+1)<0){		close(net);		punt("BSD authentication failed");	}	if(read(net, buf, 1) != 1)		punt("BSD authentication failed1");	if(buf[0] != 0){		fprint(2, "con: remote error: ");		while(read(net, buf, 1) == 1){			write(2, buf, 1);			if(buf[0] == '\n')				break;		}		exits("read");	} 	if(cmd)		dosystem(net, cmd); 	if(!cooked)		rawon();	nltocr = 1;	stdcon(net);	exits(0);} /* *  just open a device and use it as a connection */voiddevice(char *dest, char *cmd){	int net;	char cname[128]; 	net = open(dest, ORDWR);	if(net < 0) {		fprint(2, "con: cannot open %s: %r\n", dest);		exits("open");	}	snprint(cname, sizeof cname, "%sctl", dest);	ctl = open(cname, ORDWR);	if (baud > 0) {		if(ctl >= 0){			/* set speed and use fifos if available */			fprint(ctl, "b%d i1", baud);		}		else			fprint(2, "con: cannot open %s: %r\n", cname);	} 	if(cmd)		dosystem(net, cmd); 	if(!cooked)		rawon();	stdcon(net);	exits(0);} /* *  ignore interrupts */voidnotifyf(void *a, char *msg){	USED(a); 	if(strstr(msg, "yankee"))		noted(NDFLT);	if(strstr(msg, "closed pipe")	|| strcmp(msg, "interrupt") == 0	|| strcmp(msg, "hangup") == 0)		noted(NCONT);	noted(NDFLT);} /* *  turn keyboard raw mode on */voidrawon(void){	if(debug)		fprint(2, "rawon\n");	if(raw)		return;	if(consctl < 0)		consctl = open("/dev/consctl", OWRITE);	if(consctl < 0){//		fprint(2, "can't open consctl\n");		return;	}	write(consctl, "rawon", 5);	raw = 1;} /* *  turn keyboard raw mode off */voidrawoff(void){	if(debug)		fprint(2, "rawoff\n");	if(raw == 0)		return;	if(consctl < 0)		consctl = open("/dev/consctl", OWRITE);	if(consctl < 0){//		fprint(2, "can't open consctl\n");		return;	}	write(consctl, "rawoff", 6);	raw = 0;} /* *  control menu */#define STDHELP	"\t(b)reak, (q)uit, (i)nterrupt, toggle printing (r)eturns, (.)continue, (!cmd)\n" intmenu(int net){	char buf[MAXMSG];	long n;	int done;	int wasraw = raw; 	if(wasraw)		rawoff(); 	fprint(2, ">>> ");	for(done = 0; !done; ){		n = read(0, buf, sizeof(buf)-1);		if(n <= 0)			return -1;		buf[n] = 0;		switch(buf[0]){		case '!':			print(buf);			system(net, buf+1);			print("!\n");			done = 1;			break;		case '.':			done = 1;			break;		case 'q':			return -1;		case 'i':			buf[0] = 0x1c;			write(net, buf, 1);			done = 1;			break;		case 'b':			if(ctl >= 0)				write(ctl, "k", 1);			done = 1;			break;		case 'r':			returns = 1-returns;			done = 1;			break;		default:			fprint(2, STDHELP);			break;		}		if(!done)			fprint(2, ">>> ");	} 	if(wasraw)		rawon();	else		rawoff();	return 0;} voidpost(char *srv, int fd){	int f;	char buf[32]; 	f = create(srv, OWRITE /* |ORCLOSE */ , 0666);	if(f < 0)		sysfatal("create %s: %r", srv);	snprint(buf, sizeof buf, "%d", fd);	if(write(f, buf, strlen(buf)) != strlen(buf))		sysfatal("write %s: %r", srv);	close(f);} /* *  the real work.  two processes pass bytes back and forth between the *  terminal and the network. */voidstdcon(int net){	int netpid;	int p[2];	char *svc; 	svc = nil;	if (srv) {		if(pipe(p) < 0)			sysfatal("pipe: %r");		if (srv[0] != '/')			svc = smprint("/srv/%s", srv);		else			svc = srv;		post(svc, p[0]);		close(p[0]);		dup(p[1], 0);		dup(p[1], 1);		/* pipe is now std in & out */	}	ttypid = getpid();	switch(netpid = rfork(RFMEM|RFPROC)){	case -1:		perror("con");		exits("fork");	case 0:		notify(notifyf);		fromnet(net);		if (svc)			remove(svc);		postnote(PNPROC, ttypid, "die yankee dog");		exits(0);	default:		notify(notifyf);		fromkbd(net);		if (svc)			remove(svc);		if(notkbd)			for(;;)				sleep(0);		postnote(PNPROC, netpid, "die yankee dog");		exits(0);	}} /* *  Read the keyboard and write it to the network.  '^\' gets us into *  the menu. */voidfromkbd(int net){	long n;	char buf[MAXMSG];	char *p, *ep;	int eofs; 	eofs = 0;	for(;;){		n = read(0, buf, sizeof(buf));		if(n < 0){			if(wasintr()){				if(!raw){					buf[0] = 0x7f;					n = 1;				} else					continue;			} else				return;		}		if(n == 0){			if(++eofs > 32)				return;		} else			eofs = 0;		if(n && memchr(buf, 0x1c, n)){			if(menu(net) < 0)				return;		}else{			if(!raw && n==0){				buf[0] = 0x4;				n = 1;			}			if(nltocr){				ep = buf+n;				for(p = buf; p < ep; p++)					switch(*p){					case '\r':						*p = '\n';						break;					case '\n':						*p = '\r';						break;					}			}			if(iwrite(net, buf, n) != n)				return;		}	}} /* *  Read from the network and write to the screen. *  Filter out spurious carriage returns. */voidfromnet(int net)

Lines 1–500 of 692.