xref: /csrg-svn/usr.bin/rlogin/rlogin.c (revision 29729)
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*29729Smckusick static char sccsid[] = "@(#)rlogin.c	5.11 (Berkeley) 08/07/86";
1521595Sdist #endif not lint
1621595Sdist 
1712990Ssam /*
1812990Ssam  * rlogin - remote login
1912990Ssam  */
2026981Skarels #include <sys/param.h>
2125424Skarels #include <sys/errno.h>
2224727Smckusick #include <sys/file.h>
236444Swnj #include <sys/socket.h>
24*29729Smckusick #include <sys/time.h>
25*29729Smckusick #include <sys/resource.h>
2613620Ssam #include <sys/wait.h>
279365Ssam 
289207Ssam #include <netinet/in.h>
299365Ssam 
309365Ssam #include <stdio.h>
319365Ssam #include <sgtty.h>
326444Swnj #include <errno.h>
336444Swnj #include <pwd.h>
349365Ssam #include <signal.h>
3525424Skarels #include <setjmp.h>
369365Ssam #include <netdb.h>
376444Swnj 
3824726Smckusick # ifndef TIOCPKT_WINDOW
3924726Smckusick # define TIOCPKT_WINDOW 0x80
4024726Smckusick # endif TIOCPKT_WINDOW
4124726Smckusick 
42*29729Smckusick /* concession to sun */
43*29729Smckusick # ifndef SIGUSR1
44*29729Smckusick # define SIGUSR1 30
45*29729Smckusick # endif SIGUSR1
46*29729Smckusick 
47*29729Smckusick char	*index(), *rindex(), *malloc(), *getenv(), *strcat(), *strcpy();
486444Swnj struct	passwd *getpwuid();
499365Ssam char	*name;
506444Swnj int	rem;
516444Swnj char	cmdchar = '~';
526444Swnj int	eight;
5321583Sbloom int	litout;
546444Swnj char	*speeds[] =
556444Swnj     { "0", "50", "75", "110", "134", "150", "200", "300",
566444Swnj       "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400" };
5718358Ssam char	term[256] = "network";
589365Ssam extern	int errno;
599365Ssam int	lostpeer();
6024726Smckusick int	dosigwinch = 0;
6126981Skarels #ifndef sigmask
6226981Skarels #define sigmask(m)	(1 << ((m)-1))
6326981Skarels #endif
6426981Skarels #ifdef sun
6526981Skarels struct winsize {
6626981Skarels 	unsigned short ws_row, ws_col;
6726981Skarels 	unsigned short ws_xpixel, ws_ypixel;
6826981Skarels };
69*29729Smckusick #endif sun
7018358Ssam struct	winsize winsize;
7124726Smckusick int	sigwinch(), oob();
726444Swnj 
73*29729Smckusick /*
74*29729Smckusick  * The following routine provides compatibility (such as it is)
75*29729Smckusick  * between 4.2BSD Suns and others.  Suns have only a `ttysize',
76*29729Smckusick  * so we convert it to a winsize.
77*29729Smckusick  */
78*29729Smckusick #ifdef sun
79*29729Smckusick int
80*29729Smckusick get_window_size(fd, wp)
81*29729Smckusick 	int fd;
82*29729Smckusick 	struct winsize *wp;
83*29729Smckusick {
84*29729Smckusick 	struct ttysize ts;
85*29729Smckusick 	int error;
86*29729Smckusick 
87*29729Smckusick 	if ((error = ioctl(0, TIOCGSIZE, &ts)) != 0)
88*29729Smckusick 		return (error);
89*29729Smckusick 	wp->ws_row = ts.ts_lines;
90*29729Smckusick 	wp->ws_col = ts.ts_cols;
91*29729Smckusick 	wp->ws_xpixel = 0;
92*29729Smckusick 	wp->ws_ypixel = 0;
93*29729Smckusick 	return (0);
94*29729Smckusick }
95*29729Smckusick #else sun
96*29729Smckusick #define get_window_size(fd, wp)	ioctl(fd, TIOCGWINSZ, wp)
97*29729Smckusick #endif sun
98*29729Smckusick 
996444Swnj main(argc, argv)
1006444Swnj 	int argc;
1016444Swnj 	char **argv;
1026444Swnj {
1039365Ssam 	char *host, *cp;
1046444Swnj 	struct sgttyb ttyb;
1056444Swnj 	struct passwd *pwd;
1069365Ssam 	struct servent *sp;
10724726Smckusick 	int uid, options = 0, oldmask;
10817449Slepreau 	int on = 1;
1096444Swnj 
1106444Swnj 	host = rindex(argv[0], '/');
1116444Swnj 	if (host)
1126444Swnj 		host++;
1136444Swnj 	else
1146444Swnj 		host = argv[0];
1156444Swnj 	argv++, --argc;
1166444Swnj 	if (!strcmp(host, "rlogin"))
1176444Swnj 		host = *argv++, --argc;
1186444Swnj another:
11910839Ssam 	if (argc > 0 && !strcmp(*argv, "-d")) {
1206444Swnj 		argv++, argc--;
12110415Ssam 		options |= SO_DEBUG;
1226444Swnj 		goto another;
1236444Swnj 	}
12410839Ssam 	if (argc > 0 && !strcmp(*argv, "-l")) {
1256444Swnj 		argv++, argc--;
1266444Swnj 		if (argc == 0)
1276444Swnj 			goto usage;
1286444Swnj 		name = *argv++; argc--;
1296444Swnj 		goto another;
1306444Swnj 	}
13110839Ssam 	if (argc > 0 && !strncmp(*argv, "-e", 2)) {
1326444Swnj 		cmdchar = argv[0][2];
1336444Swnj 		argv++, argc--;
1346444Swnj 		goto another;
1356444Swnj 	}
13610839Ssam 	if (argc > 0 && !strcmp(*argv, "-8")) {
1376444Swnj 		eight = 1;
1386444Swnj 		argv++, argc--;
1396444Swnj 		goto another;
1406444Swnj 	}
14121583Sbloom 	if (argc > 0 && !strcmp(*argv, "-L")) {
14221583Sbloom 		litout = 1;
14321583Sbloom 		argv++, argc--;
14421583Sbloom 		goto another;
14521583Sbloom 	}
1466444Swnj 	if (host == 0)
1476444Swnj 		goto usage;
1486444Swnj 	if (argc > 0)
1496444Swnj 		goto usage;
1506444Swnj 	pwd = getpwuid(getuid());
1516444Swnj 	if (pwd == 0) {
1526444Swnj 		fprintf(stderr, "Who are you?\n");
1536444Swnj 		exit(1);
1546444Swnj 	}
1559365Ssam 	sp = getservbyname("login", "tcp");
1569365Ssam 	if (sp == 0) {
1579365Ssam 		fprintf(stderr, "rlogin: login/tcp: unknown service\n");
1589365Ssam 		exit(2);
1599365Ssam 	}
1609241Ssam 	cp = getenv("TERM");
1619241Ssam 	if (cp)
162*29729Smckusick 		(void) strcpy(term, cp);
16318358Ssam 	if (ioctl(0, TIOCGETP, &ttyb) == 0) {
164*29729Smckusick 		(void) strcat(term, "/");
165*29729Smckusick 		(void) strcat(term, speeds[ttyb.sg_ospeed]);
1666444Swnj 	}
167*29729Smckusick 	(void) get_window_size(0, &winsize);
168*29729Smckusick 	(void) signal(SIGPIPE, lostpeer);
169*29729Smckusick 	/* will use SIGUSR1 for window size hack, so hold it off */
170*29729Smckusick 	oldmask = sigblock(sigmask(SIGURG) | sigmask(SIGUSR1));
1719365Ssam         rem = rcmd(&host, sp->s_port, pwd->pw_name,
1726444Swnj 	    name ? name : pwd->pw_name, term, 0);
1736444Swnj         if (rem < 0)
1746444Swnj                 exit(1);
17510415Ssam 	if (options & SO_DEBUG &&
17617449Slepreau 	    setsockopt(rem, SOL_SOCKET, SO_DEBUG, &on, sizeof (on)) < 0)
17710415Ssam 		perror("rlogin: setsockopt (SO_DEBUG)");
1789365Ssam 	uid = getuid();
1799365Ssam 	if (setuid(uid) < 0) {
1809365Ssam 		perror("rlogin: setuid");
1819365Ssam 		exit(1);
1829365Ssam 	}
18324726Smckusick 	doit(oldmask);
1849365Ssam 	/*NOTREACHED*/
1856444Swnj usage:
1866444Swnj 	fprintf(stderr,
18725341Smckusick 	    "usage: rlogin host [ -ex ] [ -l username ] [ -8 ] [ -L ]\n");
1886444Swnj 	exit(1);
1896444Swnj }
1906444Swnj 
1916444Swnj #define CRLF "\r\n"
1926444Swnj 
1939365Ssam int	child;
19411803Sedward int	catchild();
195*29729Smckusick int	copytochild(), writeroob();
1969365Ssam 
19713075Ssam int	defflags, tabflag;
19821583Sbloom int	deflflags;
19913075Ssam char	deferase, defkill;
20013075Ssam struct	tchars deftc;
20113075Ssam struct	ltchars defltc;
20213075Ssam struct	tchars notc =	{ -1, -1, -1, -1, -1, -1 };
20313075Ssam struct	ltchars noltc =	{ -1, -1, -1, -1, -1, -1 };
2046444Swnj 
20524726Smckusick doit(oldmask)
2066444Swnj {
2076444Swnj 	int exit();
20813075Ssam 	struct sgttyb sb;
2096444Swnj 
210*29729Smckusick 	(void) ioctl(0, TIOCGETP, (char *)&sb);
21113075Ssam 	defflags = sb.sg_flags;
21212155Ssam 	tabflag = defflags & TBDELAY;
2139962Ssam 	defflags &= ECHO | CRMOD;
21413075Ssam 	deferase = sb.sg_erase;
21513075Ssam 	defkill = sb.sg_kill;
216*29729Smckusick 	(void) ioctl(0, TIOCLGET, (char *)&deflflags);
217*29729Smckusick 	(void) ioctl(0, TIOCGETC, (char *)&deftc);
21813075Ssam 	notc.t_startc = deftc.t_startc;
21913075Ssam 	notc.t_stopc = deftc.t_stopc;
220*29729Smckusick 	(void) ioctl(0, TIOCGLTC, (char *)&defltc);
221*29729Smckusick 	(void) signal(SIGINT, SIG_IGN);
222*29729Smckusick 	setsignal(SIGHUP, exit);
223*29729Smckusick 	setsignal(SIGQUIT, exit);
2249365Ssam 	child = fork();
2259365Ssam 	if (child == -1) {
2269365Ssam 		perror("rlogin: fork");
22725424Skarels 		done(1);
2289365Ssam 	}
2299365Ssam 	if (child == 0) {
23024726Smckusick 		mode(1);
231*29729Smckusick 		if (reader(oldmask) == 0) {
23225424Skarels 			prf("Connection closed.");
23325424Skarels 			exit(0);
23425424Skarels 		}
23512155Ssam 		sleep(1);
23612155Ssam 		prf("\007Connection closed.");
2376444Swnj 		exit(3);
2386444Swnj 	}
239*29729Smckusick 
240*29729Smckusick 	/*
241*29729Smckusick 	 * We may still own the socket, and may have a pending SIGURG
242*29729Smckusick 	 * (or might receive one soon) that we really want to send to
243*29729Smckusick 	 * the reader.  Set a trap that simply copies such signals to
244*29729Smckusick 	 * the child.
245*29729Smckusick 	 */
246*29729Smckusick 	(void) signal(SIGURG, copytochild);
247*29729Smckusick 	(void) signal(SIGUSR1, writeroob);
248*29729Smckusick 	(void) sigsetmask(oldmask);
249*29729Smckusick 	(void) signal(SIGCHLD, catchild);
2509365Ssam 	writer();
25112155Ssam 	prf("Closed connection.");
25225424Skarels 	done(0);
2536444Swnj }
2546444Swnj 
255*29729Smckusick /*
256*29729Smckusick  * Trap a signal, unless it is being ignored.
257*29729Smckusick  */
258*29729Smckusick setsignal(sig, act)
259*29729Smckusick 	int sig, (*act)();
260*29729Smckusick {
261*29729Smckusick 	int omask = sigblock(sigmask(sig));
262*29729Smckusick 
263*29729Smckusick 	if (signal(sig, act) == SIG_IGN)
264*29729Smckusick 		(void) signal(sig, SIG_IGN);
265*29729Smckusick 	(void) sigsetmask(omask);
266*29729Smckusick }
267*29729Smckusick 
26825424Skarels done(status)
26925424Skarels 	int status;
2706444Swnj {
271*29729Smckusick 	int w;
2726444Swnj 
2736444Swnj 	mode(0);
274*29729Smckusick 	if (child > 0) {
275*29729Smckusick 		/* make sure catchild does not snap it up */
276*29729Smckusick 		(void) signal(SIGCHLD, SIG_DFL);
277*29729Smckusick 		if (kill(child, SIGKILL) >= 0)
278*29729Smckusick 			while ((w = wait((union wait *)0)) > 0 && w != child)
279*29729Smckusick 				/*void*/;
280*29729Smckusick 	}
28125424Skarels 	exit(status);
2826444Swnj }
2836444Swnj 
28424726Smckusick /*
285*29729Smckusick  * Copy SIGURGs to the child process.
286*29729Smckusick  */
287*29729Smckusick copytochild()
288*29729Smckusick {
289*29729Smckusick 
290*29729Smckusick 	(void) kill(child, SIGURG);
291*29729Smckusick }
292*29729Smckusick 
293*29729Smckusick /*
29424726Smckusick  * This is called when the reader process gets the out-of-band (urgent)
29524726Smckusick  * request to turn on the window-changing protocol.
29624726Smckusick  */
29724726Smckusick writeroob()
29824726Smckusick {
29924726Smckusick 
30025341Smckusick 	if (dosigwinch == 0) {
30124919Smckusick 		sendwindow();
302*29729Smckusick 		(void) signal(SIGWINCH, sigwinch);
30325341Smckusick 	}
30424726Smckusick 	dosigwinch = 1;
30524726Smckusick }
30624726Smckusick 
30711803Sedward catchild()
30811803Sedward {
30911803Sedward 	union wait status;
31011803Sedward 	int pid;
31111803Sedward 
31211803Sedward again:
313*29729Smckusick 	pid = wait3(&status, WNOHANG|WUNTRACED, (struct rusage *)0);
31411803Sedward 	if (pid == 0)
31511803Sedward 		return;
31611803Sedward 	/*
31711803Sedward 	 * if the child (reader) dies, just quit
31811803Sedward 	 */
31911803Sedward 	if (pid < 0 || pid == child && !WIFSTOPPED(status))
320*29729Smckusick 		done((int)(status.w_termsig | status.w_retcode));
32111803Sedward 	goto again;
32211803Sedward }
32311803Sedward 
3246444Swnj /*
3259365Ssam  * writer: write to remote: 0 -> line.
3269365Ssam  * ~.	terminate
3279365Ssam  * ~^Z	suspend rlogin process.
32810415Ssam  * ~^Y  suspend rlogin process, but leave reader alone.
3296444Swnj  */
3309365Ssam writer()
3316444Swnj {
33223530Sbloom 	char c;
33311803Sedward 	register n;
33423530Sbloom 	register bol = 1;               /* beginning of line */
33523530Sbloom 	register local = 0;
3366444Swnj 
33711803Sedward 	for (;;) {
33811803Sedward 		n = read(0, &c, 1);
33918358Ssam 		if (n <= 0) {
34018358Ssam 			if (n < 0 && errno == EINTR)
34118358Ssam 				continue;
34211803Sedward 			break;
34318358Ssam 		}
3449365Ssam 		/*
3459365Ssam 		 * If we're at the beginning of the line
3469365Ssam 		 * and recognize a command character, then
3479365Ssam 		 * we echo locally.  Otherwise, characters
3489365Ssam 		 * are echo'd remotely.  If the command
3499365Ssam 		 * character is doubled, this acts as a
3509365Ssam 		 * force and local echo is suppressed.
3519365Ssam 		 */
35223530Sbloom 		if (bol) {
35323530Sbloom 			bol = 0;
35423530Sbloom 			if (c == cmdchar) {
35523530Sbloom 				bol = 0;
35623530Sbloom 				local = 1;
35723530Sbloom 				continue;
3586444Swnj 			}
35923530Sbloom 		} else if (local) {
36023530Sbloom 			local = 0;
36123530Sbloom 			if (c == '.' || c == deftc.t_eofc) {
36223530Sbloom 				echo(c);
36323530Sbloom 				break;
3646444Swnj 			}
36523530Sbloom 			if (c == defltc.t_suspc || c == defltc.t_dsuspc) {
36623530Sbloom 				bol = 1;
36723530Sbloom 				echo(c);
36823530Sbloom 				stop(c);
36923530Sbloom 				continue;
37023530Sbloom 			}
37123530Sbloom 			if (c != cmdchar)
372*29729Smckusick 				(void) write(rem, &cmdchar, 1);
3736444Swnj 		}
37423530Sbloom 		if (write(rem, &c, 1) == 0) {
37523530Sbloom 			prf("line gone");
37623530Sbloom 			break;
3776444Swnj 		}
37823530Sbloom 		bol = c == defkill || c == deftc.t_eofc ||
37925424Skarels 		    c == deftc.t_intrc || c == defltc.t_suspc ||
38023530Sbloom 		    c == '\r' || c == '\n';
3816444Swnj 	}
3826444Swnj }
3836444Swnj 
38423530Sbloom echo(c)
38523530Sbloom register char c;
38623530Sbloom {
38723530Sbloom 	char buf[8];
38823530Sbloom 	register char *p = buf;
38923530Sbloom 
39023530Sbloom 	c &= 0177;
39123530Sbloom 	*p++ = cmdchar;
39223530Sbloom 	if (c < ' ') {
39323530Sbloom 		*p++ = '^';
39423530Sbloom 		*p++ = c + '@';
39523530Sbloom 	} else if (c == 0177) {
39623530Sbloom 		*p++ = '^';
39723530Sbloom 		*p++ = '?';
39823530Sbloom 	} else
39923530Sbloom 		*p++ = c;
40023530Sbloom 	*p++ = '\r';
40123530Sbloom 	*p++ = '\n';
402*29729Smckusick 	(void) write(1, buf, p - buf);
40323530Sbloom }
40423530Sbloom 
40518358Ssam stop(cmdc)
40618358Ssam 	char cmdc;
40718358Ssam {
40818358Ssam 	mode(0);
409*29729Smckusick 	(void) signal(SIGCHLD, SIG_IGN);
410*29729Smckusick 	(void) kill(cmdc == defltc.t_suspc ? 0 : getpid(), SIGTSTP);
411*29729Smckusick 	(void) signal(SIGCHLD, catchild);
41218358Ssam 	mode(1);
41318358Ssam 	sigwinch();			/* check for size changes */
41418358Ssam }
41518358Ssam 
41618358Ssam sigwinch()
41718358Ssam {
41818358Ssam 	struct winsize ws;
41918358Ssam 
420*29729Smckusick 	if (dosigwinch && get_window_size(0, &ws) == 0 &&
42118358Ssam 	    bcmp(&ws, &winsize, sizeof (ws))) {
42218358Ssam 		winsize = ws;
42324726Smckusick 		sendwindow();
42418358Ssam 	}
42518358Ssam }
42618358Ssam 
42724726Smckusick /*
42824726Smckusick  * Send the window size to the server via the magic escape
42924726Smckusick  */
43024726Smckusick sendwindow()
43124726Smckusick {
43224726Smckusick 	char obuf[4 + sizeof (struct winsize)];
43324726Smckusick 	struct winsize *wp = (struct winsize *)(obuf+4);
43424726Smckusick 
43524726Smckusick 	obuf[0] = 0377;
43624726Smckusick 	obuf[1] = 0377;
43724726Smckusick 	obuf[2] = 's';
43824726Smckusick 	obuf[3] = 's';
43924726Smckusick 	wp->ws_row = htons(winsize.ws_row);
44024726Smckusick 	wp->ws_col = htons(winsize.ws_col);
44124726Smckusick 	wp->ws_xpixel = htons(winsize.ws_xpixel);
44224726Smckusick 	wp->ws_ypixel = htons(winsize.ws_ypixel);
44324726Smckusick 	(void) write(rem, obuf, sizeof(obuf));
44424726Smckusick }
44524726Smckusick 
44625424Skarels /*
44725424Skarels  * reader: read from remote: line -> 1
44825424Skarels  */
44925424Skarels #define	READING	1
45025424Skarels #define	WRITING	2
45125424Skarels 
45225424Skarels char	rcvbuf[8 * 1024];
45325424Skarels int	rcvcnt;
45425424Skarels int	rcvstate;
45526981Skarels int	ppid;
45625424Skarels jmp_buf	rcvtop;
45725424Skarels 
4586444Swnj oob()
4596444Swnj {
46025424Skarels 	int out = FWRITE, atmark, n;
46125424Skarels 	int rcvd = 0;
4629365Ssam 	char waste[BUFSIZ], mark;
46324726Smckusick 	struct sgttyb sb;
4646444Swnj 
46525424Skarels 	while (recv(rem, &mark, 1, MSG_OOB) < 0)
46625424Skarels 		switch (errno) {
46725424Skarels 
46825424Skarels 		case EWOULDBLOCK:
46925424Skarels 			/*
47025424Skarels 			 * Urgent data not here yet.
47125424Skarels 			 * It may not be possible to send it yet
47225424Skarels 			 * if we are blocked for output
47325424Skarels 			 * and our input buffer is full.
47425424Skarels 			 */
47525424Skarels 			if (rcvcnt < sizeof(rcvbuf)) {
47625424Skarels 				n = read(rem, rcvbuf + rcvcnt,
47725424Skarels 					sizeof(rcvbuf) - rcvcnt);
47825424Skarels 				if (n <= 0)
47925424Skarels 					return;
48025424Skarels 				rcvd += n;
48125424Skarels 			} else {
48225424Skarels 				n = read(rem, waste, sizeof(waste));
48325424Skarels 				if (n <= 0)
48425424Skarels 					return;
48525424Skarels 			}
48625424Skarels 			continue;
48725424Skarels 
48825424Skarels 		default:
48925424Skarels 			return;
4906444Swnj 	}
49125424Skarels 	if (mark & TIOCPKT_WINDOW) {
49224726Smckusick 		/*
49324726Smckusick 		 * Let server know about window size changes
49424726Smckusick 		 */
495*29729Smckusick 		(void) kill(ppid, SIGUSR1);
49624726Smckusick 	}
49725424Skarels 	if (!eight && (mark & TIOCPKT_NOSTOP)) {
498*29729Smckusick 		(void) ioctl(0, TIOCGETP, (char *)&sb);
49924726Smckusick 		sb.sg_flags &= ~CBREAK;
50024726Smckusick 		sb.sg_flags |= RAW;
501*29729Smckusick 		(void) ioctl(0, TIOCSETN, (char *)&sb);
50213075Ssam 		notc.t_stopc = -1;
50313075Ssam 		notc.t_startc = -1;
504*29729Smckusick 		(void) ioctl(0, TIOCSETC, (char *)&notc);
5056444Swnj 	}
50625424Skarels 	if (!eight && (mark & TIOCPKT_DOSTOP)) {
507*29729Smckusick 		(void) ioctl(0, TIOCGETP, (char *)&sb);
50824726Smckusick 		sb.sg_flags &= ~RAW;
50924726Smckusick 		sb.sg_flags |= CBREAK;
510*29729Smckusick 		(void) ioctl(0, TIOCSETN, (char *)&sb);
51113075Ssam 		notc.t_stopc = deftc.t_stopc;
51213075Ssam 		notc.t_startc = deftc.t_startc;
513*29729Smckusick 		(void) ioctl(0, TIOCSETC, (char *)&notc);
5146444Swnj 	}
51525424Skarels 	if (mark & TIOCPKT_FLUSHWRITE) {
516*29729Smckusick 		(void) ioctl(1, TIOCFLUSH, (char *)&out);
51725424Skarels 		for (;;) {
51825424Skarels 			if (ioctl(rem, SIOCATMARK, &atmark) < 0) {
51925424Skarels 				perror("ioctl");
52025424Skarels 				break;
52125424Skarels 			}
52225424Skarels 			if (atmark)
52325424Skarels 				break;
52425424Skarels 			n = read(rem, waste, sizeof (waste));
52525424Skarels 			if (n <= 0)
52625424Skarels 				break;
52725424Skarels 		}
52825424Skarels 		/*
52925424Skarels 		 * Don't want any pending data to be output,
53025424Skarels 		 * so clear the recv buffer.
53125424Skarels 		 * If we were hanging on a write when interrupted,
53225424Skarels 		 * don't want it to restart.  If we were reading,
53325424Skarels 		 * restart anyway.
53425424Skarels 		 */
53525424Skarels 		rcvcnt = 0;
53625424Skarels 		longjmp(rcvtop, 1);
53725424Skarels 	}
538*29729Smckusick 
53925424Skarels 	/*
540*29729Smckusick 	 * oob does not do FLUSHREAD (alas!)
541*29729Smckusick 	 */
542*29729Smckusick 
543*29729Smckusick 	/*
54425424Skarels 	 * If we filled the receive buffer while a read was pending,
54525424Skarels 	 * longjmp to the top to restart appropriately.  Don't abort
54625424Skarels 	 * a pending write, however, or we won't know how much was written.
54725424Skarels 	 */
54825424Skarels 	if (rcvd && rcvstate == READING)
54925424Skarels 		longjmp(rcvtop, 1);
5506444Swnj }
5516444Swnj 
5529365Ssam /*
5539365Ssam  * reader: read from remote: line -> 1
5549365Ssam  */
555*29729Smckusick reader(oldmask)
556*29729Smckusick 	int oldmask;
5576444Swnj {
55826981Skarels #if !defined(BSD) || BSD < 43
55926981Skarels 	int pid = -getpid();
56026981Skarels #else
56125424Skarels 	int pid = getpid();
56226981Skarels #endif
56325424Skarels 	int n, remaining;
56425424Skarels 	char *bufp = rcvbuf;
5656444Swnj 
566*29729Smckusick 	(void) signal(SIGTTOU, SIG_IGN);
567*29729Smckusick 	(void) signal(SIGURG, oob);
56826981Skarels 	ppid = getppid();
569*29729Smckusick 	(void) fcntl(rem, F_SETOWN, pid);
57025424Skarels 	(void) setjmp(rcvtop);
571*29729Smckusick 	(void) sigsetmask(oldmask);
5726444Swnj 	for (;;) {
57325424Skarels 		while ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) {
57425424Skarels 			rcvstate = WRITING;
57525424Skarels 			n = write(1, bufp, remaining);
57625424Skarels 			if (n < 0) {
57725424Skarels 				if (errno != EINTR)
57826189Slepreau 					return (-1);
57925424Skarels 				continue;
58025424Skarels 			}
58125424Skarels 			bufp += n;
58225424Skarels 		}
58325424Skarels 		bufp = rcvbuf;
58425424Skarels 		rcvcnt = 0;
58525424Skarels 		rcvstate = READING;
58625424Skarels 		rcvcnt = read(rem, rcvbuf, sizeof (rcvbuf));
58725424Skarels 		if (rcvcnt == 0)
58825424Skarels 			return (0);
58925424Skarels 		if (rcvcnt < 0) {
5909365Ssam 			if (errno == EINTR)
5916444Swnj 				continue;
59226981Skarels 			perror("read");
59325424Skarels 			return (-1);
5946444Swnj 		}
5956444Swnj 	}
5966444Swnj }
5976444Swnj 
5986444Swnj mode(f)
5996444Swnj {
60013075Ssam 	struct tchars *tc;
60113075Ssam 	struct ltchars *ltc;
60213075Ssam 	struct sgttyb sb;
60321583Sbloom 	int	lflags;
6049365Ssam 
605*29729Smckusick 	(void) ioctl(0, TIOCGETP, (char *)&sb);
606*29729Smckusick 	(void) ioctl(0, TIOCLGET, (char *)&lflags);
6079962Ssam 	switch (f) {
6089962Ssam 
6099962Ssam 	case 0:
61013075Ssam 		sb.sg_flags &= ~(CBREAK|RAW|TBDELAY);
61113075Ssam 		sb.sg_flags |= defflags|tabflag;
6129962Ssam 		tc = &deftc;
61313075Ssam 		ltc = &defltc;
61413075Ssam 		sb.sg_kill = defkill;
61513075Ssam 		sb.sg_erase = deferase;
61621583Sbloom 		lflags = deflflags;
6179962Ssam 		break;
6189962Ssam 
6199962Ssam 	case 1:
62013075Ssam 		sb.sg_flags |= (eight ? RAW : CBREAK);
62113075Ssam 		sb.sg_flags &= ~defflags;
62212155Ssam 		/* preserve tab delays, but turn off XTABS */
62313075Ssam 		if ((sb.sg_flags & TBDELAY) == XTABS)
62413075Ssam 			sb.sg_flags &= ~TBDELAY;
6259962Ssam 		tc = &notc;
62613075Ssam 		ltc = &noltc;
62713075Ssam 		sb.sg_kill = sb.sg_erase = -1;
62821583Sbloom 		if (litout)
62921583Sbloom 			lflags |= LLITOUT;
6309962Ssam 		break;
6319962Ssam 
6329962Ssam 	default:
6339962Ssam 		return;
6346444Swnj 	}
635*29729Smckusick 	(void) ioctl(0, TIOCSLTC, (char *)ltc);
636*29729Smckusick 	(void) ioctl(0, TIOCSETC, (char *)tc);
637*29729Smckusick 	(void) ioctl(0, TIOCSETN, (char *)&sb);
638*29729Smckusick 	(void) ioctl(0, TIOCLSET, (char *)&lflags);
6396444Swnj }
6406444Swnj 
6419365Ssam /*VARARGS*/
64224726Smckusick prf(f, a1, a2, a3, a4, a5)
6439365Ssam 	char *f;
6446444Swnj {
645*29729Smckusick 
64624726Smckusick 	fprintf(stderr, f, a1, a2, a3, a4, a5);
6476444Swnj 	fprintf(stderr, CRLF);
6486444Swnj }
6496444Swnj 
6509365Ssam lostpeer()
6516444Swnj {
652*29729Smckusick 
653*29729Smckusick 	(void) signal(SIGPIPE, SIG_IGN);
65412155Ssam 	prf("\007Connection closed.");
65525424Skarels 	done(1);
6566444Swnj }
65726981Skarels 
658