xref: /csrg-svn/usr.bin/rlogin/rlogin.c (revision 26981)
121595Sdist /*
221595Sdist  * Copyright (c) 1983 Regents of the University of California.
321595Sdist  * All rights reserved.  The Berkeley software License Agreement
421595Sdist  * specifies the terms and conditions for redistribution.
521595Sdist  */
621595Sdist 
76444Swnj #ifndef lint
821595Sdist char copyright[] =
921595Sdist "@(#) Copyright (c) 1983 Regents of the University of California.\n\
1021595Sdist  All rights reserved.\n";
1121595Sdist #endif not lint
126444Swnj 
1321595Sdist #ifndef lint
14*26981Skarels static char sccsid[] = "@(#)rlogin.c	5.10 (Berkeley) 03/30/86";
1521595Sdist #endif not lint
1621595Sdist 
1712990Ssam /*
1812990Ssam  * rlogin - remote login
1912990Ssam  */
20*26981Skarels #include <sys/param.h>
2125424Skarels #include <sys/errno.h>
2224727Smckusick #include <sys/file.h>
236444Swnj #include <sys/socket.h>
2413620Ssam #include <sys/wait.h>
259365Ssam 
269207Ssam #include <netinet/in.h>
279365Ssam 
289365Ssam #include <stdio.h>
299365Ssam #include <sgtty.h>
306444Swnj #include <errno.h>
316444Swnj #include <pwd.h>
329365Ssam #include <signal.h>
3325424Skarels #include <setjmp.h>
349365Ssam #include <netdb.h>
356444Swnj 
3624726Smckusick # ifndef TIOCPKT_WINDOW
3724726Smckusick # define TIOCPKT_WINDOW 0x80
3824726Smckusick # endif TIOCPKT_WINDOW
3924726Smckusick 
406444Swnj char	*index(), *rindex(), *malloc(), *getenv();
416444Swnj struct	passwd *getpwuid();
429365Ssam char	*name;
436444Swnj int	rem;
446444Swnj char	cmdchar = '~';
456444Swnj int	eight;
4621583Sbloom int	litout;
476444Swnj char	*speeds[] =
486444Swnj     { "0", "50", "75", "110", "134", "150", "200", "300",
496444Swnj       "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400" };
5018358Ssam char	term[256] = "network";
519365Ssam extern	int errno;
529365Ssam int	lostpeer();
5324726Smckusick int	dosigwinch = 0;
54*26981Skarels #ifndef sigmask
55*26981Skarels #define sigmask(m)	(1 << ((m)-1))
56*26981Skarels #endif
57*26981Skarels #ifdef sun
58*26981Skarels struct	ttysize winsize;
59*26981Skarels struct winsize {
60*26981Skarels 	unsigned short ws_row, ws_col;
61*26981Skarels 	unsigned short ws_xpixel, ws_ypixel;
62*26981Skarels };
63*26981Skarels #else sun
6418358Ssam struct	winsize winsize;
65*26981Skarels #endif sun
6624726Smckusick int	sigwinch(), oob();
676444Swnj 
686444Swnj main(argc, argv)
696444Swnj 	int argc;
706444Swnj 	char **argv;
716444Swnj {
729365Ssam 	char *host, *cp;
736444Swnj 	struct sgttyb ttyb;
746444Swnj 	struct passwd *pwd;
759365Ssam 	struct servent *sp;
7624726Smckusick 	int uid, options = 0, oldmask;
7717449Slepreau 	int on = 1;
786444Swnj 
796444Swnj 	host = rindex(argv[0], '/');
806444Swnj 	if (host)
816444Swnj 		host++;
826444Swnj 	else
836444Swnj 		host = argv[0];
846444Swnj 	argv++, --argc;
856444Swnj 	if (!strcmp(host, "rlogin"))
866444Swnj 		host = *argv++, --argc;
876444Swnj another:
8810839Ssam 	if (argc > 0 && !strcmp(*argv, "-d")) {
896444Swnj 		argv++, argc--;
9010415Ssam 		options |= SO_DEBUG;
916444Swnj 		goto another;
926444Swnj 	}
9310839Ssam 	if (argc > 0 && !strcmp(*argv, "-l")) {
946444Swnj 		argv++, argc--;
956444Swnj 		if (argc == 0)
966444Swnj 			goto usage;
976444Swnj 		name = *argv++; argc--;
986444Swnj 		goto another;
996444Swnj 	}
10010839Ssam 	if (argc > 0 && !strncmp(*argv, "-e", 2)) {
1016444Swnj 		cmdchar = argv[0][2];
1026444Swnj 		argv++, argc--;
1036444Swnj 		goto another;
1046444Swnj 	}
10510839Ssam 	if (argc > 0 && !strcmp(*argv, "-8")) {
1066444Swnj 		eight = 1;
1076444Swnj 		argv++, argc--;
1086444Swnj 		goto another;
1096444Swnj 	}
11021583Sbloom 	if (argc > 0 && !strcmp(*argv, "-L")) {
11121583Sbloom 		litout = 1;
11221583Sbloom 		argv++, argc--;
11321583Sbloom 		goto another;
11421583Sbloom 	}
1156444Swnj 	if (host == 0)
1166444Swnj 		goto usage;
1176444Swnj 	if (argc > 0)
1186444Swnj 		goto usage;
1196444Swnj 	pwd = getpwuid(getuid());
1206444Swnj 	if (pwd == 0) {
1216444Swnj 		fprintf(stderr, "Who are you?\n");
1226444Swnj 		exit(1);
1236444Swnj 	}
1249365Ssam 	sp = getservbyname("login", "tcp");
1259365Ssam 	if (sp == 0) {
1269365Ssam 		fprintf(stderr, "rlogin: login/tcp: unknown service\n");
1279365Ssam 		exit(2);
1289365Ssam 	}
1299241Ssam 	cp = getenv("TERM");
1309241Ssam 	if (cp)
1319241Ssam 		strcpy(term, cp);
13218358Ssam 	if (ioctl(0, TIOCGETP, &ttyb) == 0) {
1336444Swnj 		strcat(term, "/");
1346444Swnj 		strcat(term, speeds[ttyb.sg_ospeed]);
1356444Swnj 	}
136*26981Skarels #ifdef sun
137*26981Skarels 	(void) ioctl(0, TIOCGSIZE, &winsize);
138*26981Skarels #else sun
13924726Smckusick 	(void) ioctl(0, TIOCGWINSZ, &winsize);
140*26981Skarels #endif sun
14112990Ssam 	signal(SIGPIPE, lostpeer);
14224726Smckusick 	signal(SIGURG, oob);
14324726Smckusick 	oldmask = sigblock(sigmask(SIGURG));
1449365Ssam         rem = rcmd(&host, sp->s_port, pwd->pw_name,
1456444Swnj 	    name ? name : pwd->pw_name, term, 0);
1466444Swnj         if (rem < 0)
1476444Swnj                 exit(1);
14810415Ssam 	if (options & SO_DEBUG &&
14917449Slepreau 	    setsockopt(rem, SOL_SOCKET, SO_DEBUG, &on, sizeof (on)) < 0)
15010415Ssam 		perror("rlogin: setsockopt (SO_DEBUG)");
1519365Ssam 	uid = getuid();
1529365Ssam 	if (setuid(uid) < 0) {
1539365Ssam 		perror("rlogin: setuid");
1549365Ssam 		exit(1);
1559365Ssam 	}
15624726Smckusick 	doit(oldmask);
1579365Ssam 	/*NOTREACHED*/
1586444Swnj usage:
1596444Swnj 	fprintf(stderr,
16025341Smckusick 	    "usage: rlogin host [ -ex ] [ -l username ] [ -8 ] [ -L ]\n");
1616444Swnj 	exit(1);
1626444Swnj }
1636444Swnj 
1646444Swnj #define CRLF "\r\n"
1656444Swnj 
1669365Ssam int	child;
16711803Sedward int	catchild();
16824726Smckusick int	writeroob();
1699365Ssam 
17013075Ssam int	defflags, tabflag;
17121583Sbloom int	deflflags;
17213075Ssam char	deferase, defkill;
17313075Ssam struct	tchars deftc;
17413075Ssam struct	ltchars defltc;
17513075Ssam struct	tchars notc =	{ -1, -1, -1, -1, -1, -1 };
17613075Ssam struct	ltchars noltc =	{ -1, -1, -1, -1, -1, -1 };
1776444Swnj 
17824726Smckusick doit(oldmask)
1796444Swnj {
1806444Swnj 	int exit();
18113075Ssam 	struct sgttyb sb;
1826444Swnj 
18313075Ssam 	ioctl(0, TIOCGETP, (char *)&sb);
18413075Ssam 	defflags = sb.sg_flags;
18512155Ssam 	tabflag = defflags & TBDELAY;
1869962Ssam 	defflags &= ECHO | CRMOD;
18713075Ssam 	deferase = sb.sg_erase;
18813075Ssam 	defkill = sb.sg_kill;
18921583Sbloom 	ioctl(0, TIOCLGET, (char *)&deflflags);
19013075Ssam 	ioctl(0, TIOCGETC, (char *)&deftc);
19113075Ssam 	notc.t_startc = deftc.t_startc;
19213075Ssam 	notc.t_stopc = deftc.t_stopc;
19313075Ssam 	ioctl(0, TIOCGLTC, (char *)&defltc);
19424726Smckusick 	signal(SIGINT, SIG_IGN);
19512990Ssam 	signal(SIGHUP, exit);
19612990Ssam 	signal(SIGQUIT, exit);
1979365Ssam 	child = fork();
1989365Ssam 	if (child == -1) {
1999365Ssam 		perror("rlogin: fork");
20025424Skarels 		done(1);
2019365Ssam 	}
2029365Ssam 	if (child == 0) {
20324726Smckusick 		mode(1);
20424726Smckusick 		sigsetmask(oldmask);
20525424Skarels 		if (reader() == 0) {
20625424Skarels 			prf("Connection closed.");
20725424Skarels 			exit(0);
20825424Skarels 		}
20912155Ssam 		sleep(1);
21012155Ssam 		prf("\007Connection closed.");
2116444Swnj 		exit(3);
2126444Swnj 	}
21324726Smckusick 	signal(SIGURG, writeroob);
21424726Smckusick 	sigsetmask(oldmask);
21512990Ssam 	signal(SIGCHLD, catchild);
2169365Ssam 	writer();
21712155Ssam 	prf("Closed connection.");
21825424Skarels 	done(0);
2196444Swnj }
2206444Swnj 
22125424Skarels done(status)
22225424Skarels 	int status;
2236444Swnj {
2246444Swnj 
2256444Swnj 	mode(0);
2269365Ssam 	if (child > 0 && kill(child, SIGKILL) >= 0)
2279365Ssam 		wait((int *)0);
22825424Skarels 	exit(status);
2296444Swnj }
2306444Swnj 
23124726Smckusick /*
23224726Smckusick  * This is called when the reader process gets the out-of-band (urgent)
23324726Smckusick  * request to turn on the window-changing protocol.
23424726Smckusick  */
23524726Smckusick writeroob()
23624726Smckusick {
23724726Smckusick 
23825341Smckusick 	if (dosigwinch == 0) {
23924919Smckusick 		sendwindow();
24025341Smckusick 		signal(SIGWINCH, sigwinch);
24125341Smckusick 	}
24224726Smckusick 	dosigwinch = 1;
24324726Smckusick }
24424726Smckusick 
24511803Sedward catchild()
24611803Sedward {
24711803Sedward 	union wait status;
24811803Sedward 	int pid;
24911803Sedward 
25011803Sedward again:
25111803Sedward 	pid = wait3(&status, WNOHANG|WUNTRACED, 0);
25211803Sedward 	if (pid == 0)
25311803Sedward 		return;
25411803Sedward 	/*
25511803Sedward 	 * if the child (reader) dies, just quit
25611803Sedward 	 */
25711803Sedward 	if (pid < 0 || pid == child && !WIFSTOPPED(status))
25825424Skarels 		done(status.w_termsig | status.w_retcode);
25911803Sedward 	goto again;
26011803Sedward }
26111803Sedward 
2626444Swnj /*
2639365Ssam  * writer: write to remote: 0 -> line.
2649365Ssam  * ~.	terminate
2659365Ssam  * ~^Z	suspend rlogin process.
26610415Ssam  * ~^Y  suspend rlogin process, but leave reader alone.
2676444Swnj  */
2689365Ssam writer()
2696444Swnj {
27023530Sbloom 	char c;
27111803Sedward 	register n;
27223530Sbloom 	register bol = 1;               /* beginning of line */
27323530Sbloom 	register local = 0;
2746444Swnj 
27511803Sedward 	for (;;) {
27611803Sedward 		n = read(0, &c, 1);
27718358Ssam 		if (n <= 0) {
27818358Ssam 			if (n < 0 && errno == EINTR)
27918358Ssam 				continue;
28011803Sedward 			break;
28118358Ssam 		}
2829365Ssam 		/*
2839365Ssam 		 * If we're at the beginning of the line
2849365Ssam 		 * and recognize a command character, then
2859365Ssam 		 * we echo locally.  Otherwise, characters
2869365Ssam 		 * are echo'd remotely.  If the command
2879365Ssam 		 * character is doubled, this acts as a
2889365Ssam 		 * force and local echo is suppressed.
2899365Ssam 		 */
29023530Sbloom 		if (bol) {
29123530Sbloom 			bol = 0;
29223530Sbloom 			if (c == cmdchar) {
29323530Sbloom 				bol = 0;
29423530Sbloom 				local = 1;
29523530Sbloom 				continue;
2966444Swnj 			}
29723530Sbloom 		} else if (local) {
29823530Sbloom 			local = 0;
29923530Sbloom 			if (c == '.' || c == deftc.t_eofc) {
30023530Sbloom 				echo(c);
30123530Sbloom 				break;
3026444Swnj 			}
30323530Sbloom 			if (c == defltc.t_suspc || c == defltc.t_dsuspc) {
30423530Sbloom 				bol = 1;
30523530Sbloom 				echo(c);
30623530Sbloom 				stop(c);
30723530Sbloom 				continue;
30823530Sbloom 			}
30923530Sbloom 			if (c != cmdchar)
31023530Sbloom 				write(rem, &cmdchar, 1);
3116444Swnj 		}
31223530Sbloom 		if (write(rem, &c, 1) == 0) {
31323530Sbloom 			prf("line gone");
31423530Sbloom 			break;
3156444Swnj 		}
31623530Sbloom 		bol = c == defkill || c == deftc.t_eofc ||
31725424Skarels 		    c == deftc.t_intrc || c == defltc.t_suspc ||
31823530Sbloom 		    c == '\r' || c == '\n';
3196444Swnj 	}
3206444Swnj }
3216444Swnj 
32223530Sbloom echo(c)
32323530Sbloom register char c;
32423530Sbloom {
32523530Sbloom 	char buf[8];
32623530Sbloom 	register char *p = buf;
32723530Sbloom 
32823530Sbloom 	c &= 0177;
32923530Sbloom 	*p++ = cmdchar;
33023530Sbloom 	if (c < ' ') {
33123530Sbloom 		*p++ = '^';
33223530Sbloom 		*p++ = c + '@';
33323530Sbloom 	} else if (c == 0177) {
33423530Sbloom 		*p++ = '^';
33523530Sbloom 		*p++ = '?';
33623530Sbloom 	} else
33723530Sbloom 		*p++ = c;
33823530Sbloom 	*p++ = '\r';
33923530Sbloom 	*p++ = '\n';
34023530Sbloom 	write(1, buf, p - buf);
34123530Sbloom }
34223530Sbloom 
34318358Ssam stop(cmdc)
34418358Ssam 	char cmdc;
34518358Ssam {
34618358Ssam 	mode(0);
34718358Ssam 	signal(SIGCHLD, SIG_IGN);
34818358Ssam 	kill(cmdc == defltc.t_suspc ? 0 : getpid(), SIGTSTP);
34918358Ssam 	signal(SIGCHLD, catchild);
35018358Ssam 	mode(1);
35118358Ssam 	sigwinch();			/* check for size changes */
35218358Ssam }
35318358Ssam 
354*26981Skarels #ifdef sun
35518358Ssam sigwinch()
35618358Ssam {
357*26981Skarels 	struct ttysize ws;
358*26981Skarels 
359*26981Skarels 	if (dosigwinch && ioctl(0, TIOCGSIZE, &ws) == 0 &&
360*26981Skarels 	    bcmp(&ws, &winsize, sizeof (ws))) {
361*26981Skarels 		winsize = ws;
362*26981Skarels 		sendwindow();
363*26981Skarels 	}
364*26981Skarels }
365*26981Skarels 
366*26981Skarels #else sun
367*26981Skarels sigwinch()
368*26981Skarels {
36918358Ssam 	struct winsize ws;
37018358Ssam 
37125341Smckusick 	if (dosigwinch && ioctl(0, TIOCGWINSZ, &ws) == 0 &&
37218358Ssam 	    bcmp(&ws, &winsize, sizeof (ws))) {
37318358Ssam 		winsize = ws;
37424726Smckusick 		sendwindow();
37518358Ssam 	}
37618358Ssam }
377*26981Skarels #endif
37818358Ssam 
37924726Smckusick /*
38024726Smckusick  * Send the window size to the server via the magic escape
38124726Smckusick  */
38224726Smckusick sendwindow()
38324726Smckusick {
38424726Smckusick 	char obuf[4 + sizeof (struct winsize)];
38524726Smckusick 	struct winsize *wp = (struct winsize *)(obuf+4);
38624726Smckusick 
38724726Smckusick 	obuf[0] = 0377;
38824726Smckusick 	obuf[1] = 0377;
38924726Smckusick 	obuf[2] = 's';
39024726Smckusick 	obuf[3] = 's';
391*26981Skarels #ifdef sun
392*26981Skarels 	wp->ws_row = htons(winsize.ts_lines);
393*26981Skarels 	wp->ws_col = htons(winsize.ts_cols);
394*26981Skarels 	wp->ws_xpixel = 0;
395*26981Skarels 	wp->ws_ypixel = 0;
396*26981Skarels #else sun
39724726Smckusick 	wp->ws_row = htons(winsize.ws_row);
39824726Smckusick 	wp->ws_col = htons(winsize.ws_col);
39924726Smckusick 	wp->ws_xpixel = htons(winsize.ws_xpixel);
40024726Smckusick 	wp->ws_ypixel = htons(winsize.ws_ypixel);
401*26981Skarels #endif sun
40224726Smckusick 	(void) write(rem, obuf, sizeof(obuf));
40324726Smckusick }
40424726Smckusick 
40525424Skarels /*
40625424Skarels  * reader: read from remote: line -> 1
40725424Skarels  */
40825424Skarels #define	READING	1
40925424Skarels #define	WRITING	2
41025424Skarels 
41125424Skarels char	rcvbuf[8 * 1024];
41225424Skarels int	rcvcnt;
41325424Skarels int	rcvstate;
414*26981Skarels int	ppid;
41525424Skarels jmp_buf	rcvtop;
41625424Skarels 
4176444Swnj oob()
4186444Swnj {
41925424Skarels 	int out = FWRITE, atmark, n;
42025424Skarels 	int rcvd = 0;
4219365Ssam 	char waste[BUFSIZ], mark;
42224726Smckusick 	struct sgttyb sb;
4236444Swnj 
42425424Skarels 	while (recv(rem, &mark, 1, MSG_OOB) < 0)
42525424Skarels 		switch (errno) {
42625424Skarels 
42725424Skarels 		case EWOULDBLOCK:
42825424Skarels 			/*
42925424Skarels 			 * Urgent data not here yet.
43025424Skarels 			 * It may not be possible to send it yet
43125424Skarels 			 * if we are blocked for output
43225424Skarels 			 * and our input buffer is full.
43325424Skarels 			 */
43425424Skarels 			if (rcvcnt < sizeof(rcvbuf)) {
43525424Skarels 				n = read(rem, rcvbuf + rcvcnt,
43625424Skarels 					sizeof(rcvbuf) - rcvcnt);
43725424Skarels 				if (n <= 0)
43825424Skarels 					return;
43925424Skarels 				rcvd += n;
44025424Skarels 			} else {
44125424Skarels 				n = read(rem, waste, sizeof(waste));
44225424Skarels 				if (n <= 0)
44325424Skarels 					return;
44425424Skarels 			}
44525424Skarels 			continue;
44625424Skarels 
44725424Skarels 		default:
44825424Skarels 			return;
4496444Swnj 	}
45025424Skarels 	if (mark & TIOCPKT_WINDOW) {
45124726Smckusick 		/*
45224726Smckusick 		 * Let server know about window size changes
45324726Smckusick 		 */
454*26981Skarels 		kill(ppid, SIGURG);
45524726Smckusick 	}
45625424Skarels 	if (!eight && (mark & TIOCPKT_NOSTOP)) {
45724726Smckusick 		ioctl(0, TIOCGETP, (char *)&sb);
45824726Smckusick 		sb.sg_flags &= ~CBREAK;
45924726Smckusick 		sb.sg_flags |= RAW;
46024726Smckusick 		ioctl(0, TIOCSETN, (char *)&sb);
46113075Ssam 		notc.t_stopc = -1;
46213075Ssam 		notc.t_startc = -1;
46313075Ssam 		ioctl(0, TIOCSETC, (char *)&notc);
4646444Swnj 	}
46525424Skarels 	if (!eight && (mark & TIOCPKT_DOSTOP)) {
46624726Smckusick 		ioctl(0, TIOCGETP, (char *)&sb);
46724726Smckusick 		sb.sg_flags &= ~RAW;
46824726Smckusick 		sb.sg_flags |= CBREAK;
46924726Smckusick 		ioctl(0, TIOCSETN, (char *)&sb);
47013075Ssam 		notc.t_stopc = deftc.t_stopc;
47113075Ssam 		notc.t_startc = deftc.t_startc;
47213075Ssam 		ioctl(0, TIOCSETC, (char *)&notc);
4736444Swnj 	}
47425424Skarels 	if (mark & TIOCPKT_FLUSHWRITE) {
47525424Skarels 		ioctl(1, TIOCFLUSH, (char *)&out);
47625424Skarels 		for (;;) {
47725424Skarels 			if (ioctl(rem, SIOCATMARK, &atmark) < 0) {
47825424Skarels 				perror("ioctl");
47925424Skarels 				break;
48025424Skarels 			}
48125424Skarels 			if (atmark)
48225424Skarels 				break;
48325424Skarels 			n = read(rem, waste, sizeof (waste));
48425424Skarels 			if (n <= 0)
48525424Skarels 				break;
48625424Skarels 		}
48725424Skarels 		/*
48825424Skarels 		 * Don't want any pending data to be output,
48925424Skarels 		 * so clear the recv buffer.
49025424Skarels 		 * If we were hanging on a write when interrupted,
49125424Skarels 		 * don't want it to restart.  If we were reading,
49225424Skarels 		 * restart anyway.
49325424Skarels 		 */
49425424Skarels 		rcvcnt = 0;
49525424Skarels 		longjmp(rcvtop, 1);
49625424Skarels 	}
49725424Skarels 	/*
49825424Skarels 	 * If we filled the receive buffer while a read was pending,
49925424Skarels 	 * longjmp to the top to restart appropriately.  Don't abort
50025424Skarels 	 * a pending write, however, or we won't know how much was written.
50125424Skarels 	 */
50225424Skarels 	if (rcvd && rcvstate == READING)
50325424Skarels 		longjmp(rcvtop, 1);
5046444Swnj }
5056444Swnj 
5069365Ssam /*
5079365Ssam  * reader: read from remote: line -> 1
5089365Ssam  */
5099365Ssam reader()
5106444Swnj {
511*26981Skarels #if !defined(BSD) || BSD < 43
512*26981Skarels 	int pid = -getpid();
513*26981Skarels #else
51425424Skarels 	int pid = getpid();
515*26981Skarels #endif
51625424Skarels 	int n, remaining;
51725424Skarels 	char *bufp = rcvbuf;
5186444Swnj 
51923530Sbloom 	signal(SIGTTOU, SIG_IGN);
52025424Skarels 	fcntl(rem, F_SETOWN, pid);
521*26981Skarels 	ppid = getppid();
52225424Skarels 	(void) setjmp(rcvtop);
5236444Swnj 	for (;;) {
52425424Skarels 		while ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) {
52525424Skarels 			rcvstate = WRITING;
52625424Skarels 			n = write(1, bufp, remaining);
52725424Skarels 			if (n < 0) {
52825424Skarels 				if (errno != EINTR)
52926189Slepreau 					return (-1);
53025424Skarels 				continue;
53125424Skarels 			}
53225424Skarels 			bufp += n;
53325424Skarels 		}
53425424Skarels 		bufp = rcvbuf;
53525424Skarels 		rcvcnt = 0;
53625424Skarels 		rcvstate = READING;
53725424Skarels 		rcvcnt = read(rem, rcvbuf, sizeof (rcvbuf));
53825424Skarels 		if (rcvcnt == 0)
53925424Skarels 			return (0);
54025424Skarels 		if (rcvcnt < 0) {
5419365Ssam 			if (errno == EINTR)
5426444Swnj 				continue;
543*26981Skarels 			perror("read");
54425424Skarels 			return (-1);
5456444Swnj 		}
5466444Swnj 	}
5476444Swnj }
5486444Swnj 
5496444Swnj mode(f)
5506444Swnj {
55113075Ssam 	struct tchars *tc;
55213075Ssam 	struct ltchars *ltc;
55313075Ssam 	struct sgttyb sb;
55421583Sbloom 	int	lflags;
5559365Ssam 
55613075Ssam 	ioctl(0, TIOCGETP, (char *)&sb);
55721583Sbloom 	ioctl(0, TIOCLGET, (char *)&lflags);
5589962Ssam 	switch (f) {
5599962Ssam 
5609962Ssam 	case 0:
56113075Ssam 		sb.sg_flags &= ~(CBREAK|RAW|TBDELAY);
56213075Ssam 		sb.sg_flags |= defflags|tabflag;
5639962Ssam 		tc = &deftc;
56413075Ssam 		ltc = &defltc;
56513075Ssam 		sb.sg_kill = defkill;
56613075Ssam 		sb.sg_erase = deferase;
56721583Sbloom 		lflags = deflflags;
5689962Ssam 		break;
5699962Ssam 
5709962Ssam 	case 1:
57113075Ssam 		sb.sg_flags |= (eight ? RAW : CBREAK);
57213075Ssam 		sb.sg_flags &= ~defflags;
57312155Ssam 		/* preserve tab delays, but turn off XTABS */
57413075Ssam 		if ((sb.sg_flags & TBDELAY) == XTABS)
57513075Ssam 			sb.sg_flags &= ~TBDELAY;
5769962Ssam 		tc = &notc;
57713075Ssam 		ltc = &noltc;
57813075Ssam 		sb.sg_kill = sb.sg_erase = -1;
57921583Sbloom 		if (litout)
58021583Sbloom 			lflags |= LLITOUT;
5819962Ssam 		break;
5829962Ssam 
5839962Ssam 	default:
5849962Ssam 		return;
5856444Swnj 	}
58613075Ssam 	ioctl(0, TIOCSLTC, (char *)ltc);
58713075Ssam 	ioctl(0, TIOCSETC, (char *)tc);
58813075Ssam 	ioctl(0, TIOCSETN, (char *)&sb);
58921583Sbloom 	ioctl(0, TIOCLSET, (char *)&lflags);
5906444Swnj }
5916444Swnj 
5929365Ssam /*VARARGS*/
59324726Smckusick prf(f, a1, a2, a3, a4, a5)
5949365Ssam 	char *f;
5956444Swnj {
59624726Smckusick 	fprintf(stderr, f, a1, a2, a3, a4, a5);
5976444Swnj 	fprintf(stderr, CRLF);
5986444Swnj }
5996444Swnj 
6009365Ssam lostpeer()
6016444Swnj {
60212990Ssam 	signal(SIGPIPE, SIG_IGN);
60312155Ssam 	prf("\007Connection closed.");
60425424Skarels 	done(1);
6056444Swnj }
606*26981Skarels 
607