xref: /csrg-svn/usr.bin/rlogin/rlogin.c (revision 35539)
121595Sdist /*
2*35539Sbostic  * Copyright (c) 1983 The Regents of the University of California.
3*35539Sbostic  * All rights reserved.
4*35539Sbostic  *
5*35539Sbostic  * Redistribution and use in source and binary forms are permitted
6*35539Sbostic  * provided that the above copyright notice and this paragraph are
7*35539Sbostic  * duplicated in all such forms and that any documentation,
8*35539Sbostic  * advertising materials, and other materials related to such
9*35539Sbostic  * distribution and use acknowledge that the software was developed
10*35539Sbostic  * by the University of California, Berkeley.  The name of the
11*35539Sbostic  * University may not be used to endorse or promote products derived
12*35539Sbostic  * from this software without specific prior written permission.
13*35539Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14*35539Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15*35539Sbostic  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1621595Sdist  */
1721595Sdist 
186444Swnj #ifndef lint
1921595Sdist char copyright[] =
20*35539Sbostic "@(#) Copyright (c) 1983 The Regents of the University of California.\n\
2121595Sdist  All rights reserved.\n";
22*35539Sbostic #endif /* not lint */
236444Swnj 
2421595Sdist #ifndef lint
25*35539Sbostic static char sccsid[] = "@(#)rlogin.c	5.12 (Berkeley) 09/19/88";
26*35539Sbostic #endif /* not lint */
2721595Sdist 
2812990Ssam /*
2912990Ssam  * rlogin - remote login
3012990Ssam  */
3126981Skarels #include <sys/param.h>
3225424Skarels #include <sys/errno.h>
3324727Smckusick #include <sys/file.h>
346444Swnj #include <sys/socket.h>
3529729Smckusick #include <sys/time.h>
3629729Smckusick #include <sys/resource.h>
3713620Ssam #include <sys/wait.h>
389365Ssam 
399207Ssam #include <netinet/in.h>
409365Ssam 
419365Ssam #include <stdio.h>
429365Ssam #include <sgtty.h>
436444Swnj #include <errno.h>
446444Swnj #include <pwd.h>
459365Ssam #include <signal.h>
4625424Skarels #include <setjmp.h>
479365Ssam #include <netdb.h>
486444Swnj 
4924726Smckusick # ifndef TIOCPKT_WINDOW
5024726Smckusick # define TIOCPKT_WINDOW 0x80
5124726Smckusick # endif TIOCPKT_WINDOW
5224726Smckusick 
5329729Smckusick /* concession to sun */
5429729Smckusick # ifndef SIGUSR1
5529729Smckusick # define SIGUSR1 30
5629729Smckusick # endif SIGUSR1
5729729Smckusick 
5829729Smckusick char	*index(), *rindex(), *malloc(), *getenv(), *strcat(), *strcpy();
596444Swnj struct	passwd *getpwuid();
609365Ssam char	*name;
616444Swnj int	rem;
626444Swnj char	cmdchar = '~';
636444Swnj int	eight;
6421583Sbloom int	litout;
656444Swnj char	*speeds[] =
666444Swnj     { "0", "50", "75", "110", "134", "150", "200", "300",
676444Swnj       "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400" };
6818358Ssam char	term[256] = "network";
699365Ssam extern	int errno;
709365Ssam int	lostpeer();
7124726Smckusick int	dosigwinch = 0;
7226981Skarels #ifndef sigmask
7326981Skarels #define sigmask(m)	(1 << ((m)-1))
7426981Skarels #endif
7526981Skarels #ifdef sun
7626981Skarels struct winsize {
7726981Skarels 	unsigned short ws_row, ws_col;
7826981Skarels 	unsigned short ws_xpixel, ws_ypixel;
7926981Skarels };
8029729Smckusick #endif sun
8118358Ssam struct	winsize winsize;
8224726Smckusick int	sigwinch(), oob();
836444Swnj 
8429729Smckusick /*
8529729Smckusick  * The following routine provides compatibility (such as it is)
8629729Smckusick  * between 4.2BSD Suns and others.  Suns have only a `ttysize',
8729729Smckusick  * so we convert it to a winsize.
8829729Smckusick  */
8929729Smckusick #ifdef sun
9029729Smckusick int
9129729Smckusick get_window_size(fd, wp)
9229729Smckusick 	int fd;
9329729Smckusick 	struct winsize *wp;
9429729Smckusick {
9529729Smckusick 	struct ttysize ts;
9629729Smckusick 	int error;
9729729Smckusick 
9829729Smckusick 	if ((error = ioctl(0, TIOCGSIZE, &ts)) != 0)
9929729Smckusick 		return (error);
10029729Smckusick 	wp->ws_row = ts.ts_lines;
10129729Smckusick 	wp->ws_col = ts.ts_cols;
10229729Smckusick 	wp->ws_xpixel = 0;
10329729Smckusick 	wp->ws_ypixel = 0;
10429729Smckusick 	return (0);
10529729Smckusick }
10629729Smckusick #else sun
10729729Smckusick #define get_window_size(fd, wp)	ioctl(fd, TIOCGWINSZ, wp)
10829729Smckusick #endif sun
10929729Smckusick 
1106444Swnj main(argc, argv)
1116444Swnj 	int argc;
1126444Swnj 	char **argv;
1136444Swnj {
1149365Ssam 	char *host, *cp;
1156444Swnj 	struct sgttyb ttyb;
1166444Swnj 	struct passwd *pwd;
1179365Ssam 	struct servent *sp;
11824726Smckusick 	int uid, options = 0, oldmask;
11917449Slepreau 	int on = 1;
1206444Swnj 
1216444Swnj 	host = rindex(argv[0], '/');
1226444Swnj 	if (host)
1236444Swnj 		host++;
1246444Swnj 	else
1256444Swnj 		host = argv[0];
1266444Swnj 	argv++, --argc;
1276444Swnj 	if (!strcmp(host, "rlogin"))
1286444Swnj 		host = *argv++, --argc;
1296444Swnj another:
13010839Ssam 	if (argc > 0 && !strcmp(*argv, "-d")) {
1316444Swnj 		argv++, argc--;
13210415Ssam 		options |= SO_DEBUG;
1336444Swnj 		goto another;
1346444Swnj 	}
13510839Ssam 	if (argc > 0 && !strcmp(*argv, "-l")) {
1366444Swnj 		argv++, argc--;
1376444Swnj 		if (argc == 0)
1386444Swnj 			goto usage;
1396444Swnj 		name = *argv++; argc--;
1406444Swnj 		goto another;
1416444Swnj 	}
14210839Ssam 	if (argc > 0 && !strncmp(*argv, "-e", 2)) {
1436444Swnj 		cmdchar = argv[0][2];
1446444Swnj 		argv++, argc--;
1456444Swnj 		goto another;
1466444Swnj 	}
14710839Ssam 	if (argc > 0 && !strcmp(*argv, "-8")) {
1486444Swnj 		eight = 1;
1496444Swnj 		argv++, argc--;
1506444Swnj 		goto another;
1516444Swnj 	}
15221583Sbloom 	if (argc > 0 && !strcmp(*argv, "-L")) {
15321583Sbloom 		litout = 1;
15421583Sbloom 		argv++, argc--;
15521583Sbloom 		goto another;
15621583Sbloom 	}
1576444Swnj 	if (host == 0)
1586444Swnj 		goto usage;
1596444Swnj 	if (argc > 0)
1606444Swnj 		goto usage;
1616444Swnj 	pwd = getpwuid(getuid());
1626444Swnj 	if (pwd == 0) {
1636444Swnj 		fprintf(stderr, "Who are you?\n");
1646444Swnj 		exit(1);
1656444Swnj 	}
1669365Ssam 	sp = getservbyname("login", "tcp");
1679365Ssam 	if (sp == 0) {
1689365Ssam 		fprintf(stderr, "rlogin: login/tcp: unknown service\n");
1699365Ssam 		exit(2);
1709365Ssam 	}
1719241Ssam 	cp = getenv("TERM");
1729241Ssam 	if (cp)
17329729Smckusick 		(void) strcpy(term, cp);
17418358Ssam 	if (ioctl(0, TIOCGETP, &ttyb) == 0) {
17529729Smckusick 		(void) strcat(term, "/");
17629729Smckusick 		(void) strcat(term, speeds[ttyb.sg_ospeed]);
1776444Swnj 	}
17829729Smckusick 	(void) get_window_size(0, &winsize);
17929729Smckusick 	(void) signal(SIGPIPE, lostpeer);
18029729Smckusick 	/* will use SIGUSR1 for window size hack, so hold it off */
18129729Smckusick 	oldmask = sigblock(sigmask(SIGURG) | sigmask(SIGUSR1));
1829365Ssam         rem = rcmd(&host, sp->s_port, pwd->pw_name,
1836444Swnj 	    name ? name : pwd->pw_name, term, 0);
1846444Swnj         if (rem < 0)
1856444Swnj                 exit(1);
18610415Ssam 	if (options & SO_DEBUG &&
18717449Slepreau 	    setsockopt(rem, SOL_SOCKET, SO_DEBUG, &on, sizeof (on)) < 0)
18810415Ssam 		perror("rlogin: setsockopt (SO_DEBUG)");
1899365Ssam 	uid = getuid();
1909365Ssam 	if (setuid(uid) < 0) {
1919365Ssam 		perror("rlogin: setuid");
1929365Ssam 		exit(1);
1939365Ssam 	}
19424726Smckusick 	doit(oldmask);
1959365Ssam 	/*NOTREACHED*/
1966444Swnj usage:
1976444Swnj 	fprintf(stderr,
19825341Smckusick 	    "usage: rlogin host [ -ex ] [ -l username ] [ -8 ] [ -L ]\n");
1996444Swnj 	exit(1);
2006444Swnj }
2016444Swnj 
2026444Swnj #define CRLF "\r\n"
2036444Swnj 
2049365Ssam int	child;
20511803Sedward int	catchild();
20629729Smckusick int	copytochild(), writeroob();
2079365Ssam 
20813075Ssam int	defflags, tabflag;
20921583Sbloom int	deflflags;
21013075Ssam char	deferase, defkill;
21113075Ssam struct	tchars deftc;
21213075Ssam struct	ltchars defltc;
21313075Ssam struct	tchars notc =	{ -1, -1, -1, -1, -1, -1 };
21413075Ssam struct	ltchars noltc =	{ -1, -1, -1, -1, -1, -1 };
2156444Swnj 
21624726Smckusick doit(oldmask)
2176444Swnj {
2186444Swnj 	int exit();
21913075Ssam 	struct sgttyb sb;
2206444Swnj 
22129729Smckusick 	(void) ioctl(0, TIOCGETP, (char *)&sb);
22213075Ssam 	defflags = sb.sg_flags;
22312155Ssam 	tabflag = defflags & TBDELAY;
2249962Ssam 	defflags &= ECHO | CRMOD;
22513075Ssam 	deferase = sb.sg_erase;
22613075Ssam 	defkill = sb.sg_kill;
22729729Smckusick 	(void) ioctl(0, TIOCLGET, (char *)&deflflags);
22829729Smckusick 	(void) ioctl(0, TIOCGETC, (char *)&deftc);
22913075Ssam 	notc.t_startc = deftc.t_startc;
23013075Ssam 	notc.t_stopc = deftc.t_stopc;
23129729Smckusick 	(void) ioctl(0, TIOCGLTC, (char *)&defltc);
23229729Smckusick 	(void) signal(SIGINT, SIG_IGN);
23329729Smckusick 	setsignal(SIGHUP, exit);
23429729Smckusick 	setsignal(SIGQUIT, exit);
2359365Ssam 	child = fork();
2369365Ssam 	if (child == -1) {
2379365Ssam 		perror("rlogin: fork");
23825424Skarels 		done(1);
2399365Ssam 	}
2409365Ssam 	if (child == 0) {
24124726Smckusick 		mode(1);
24229729Smckusick 		if (reader(oldmask) == 0) {
24325424Skarels 			prf("Connection closed.");
24425424Skarels 			exit(0);
24525424Skarels 		}
24612155Ssam 		sleep(1);
24712155Ssam 		prf("\007Connection closed.");
2486444Swnj 		exit(3);
2496444Swnj 	}
25029729Smckusick 
25129729Smckusick 	/*
25229729Smckusick 	 * We may still own the socket, and may have a pending SIGURG
25329729Smckusick 	 * (or might receive one soon) that we really want to send to
25429729Smckusick 	 * the reader.  Set a trap that simply copies such signals to
25529729Smckusick 	 * the child.
25629729Smckusick 	 */
25729729Smckusick 	(void) signal(SIGURG, copytochild);
25829729Smckusick 	(void) signal(SIGUSR1, writeroob);
25929729Smckusick 	(void) sigsetmask(oldmask);
26029729Smckusick 	(void) signal(SIGCHLD, catchild);
2619365Ssam 	writer();
26212155Ssam 	prf("Closed connection.");
26325424Skarels 	done(0);
2646444Swnj }
2656444Swnj 
26629729Smckusick /*
26729729Smckusick  * Trap a signal, unless it is being ignored.
26829729Smckusick  */
26929729Smckusick setsignal(sig, act)
27029729Smckusick 	int sig, (*act)();
27129729Smckusick {
27229729Smckusick 	int omask = sigblock(sigmask(sig));
27329729Smckusick 
27429729Smckusick 	if (signal(sig, act) == SIG_IGN)
27529729Smckusick 		(void) signal(sig, SIG_IGN);
27629729Smckusick 	(void) sigsetmask(omask);
27729729Smckusick }
27829729Smckusick 
27925424Skarels done(status)
28025424Skarels 	int status;
2816444Swnj {
28229729Smckusick 	int w;
2836444Swnj 
2846444Swnj 	mode(0);
28529729Smckusick 	if (child > 0) {
28629729Smckusick 		/* make sure catchild does not snap it up */
28729729Smckusick 		(void) signal(SIGCHLD, SIG_DFL);
28829729Smckusick 		if (kill(child, SIGKILL) >= 0)
28929729Smckusick 			while ((w = wait((union wait *)0)) > 0 && w != child)
29029729Smckusick 				/*void*/;
29129729Smckusick 	}
29225424Skarels 	exit(status);
2936444Swnj }
2946444Swnj 
29524726Smckusick /*
29629729Smckusick  * Copy SIGURGs to the child process.
29729729Smckusick  */
29829729Smckusick copytochild()
29929729Smckusick {
30029729Smckusick 
30129729Smckusick 	(void) kill(child, SIGURG);
30229729Smckusick }
30329729Smckusick 
30429729Smckusick /*
30524726Smckusick  * This is called when the reader process gets the out-of-band (urgent)
30624726Smckusick  * request to turn on the window-changing protocol.
30724726Smckusick  */
30824726Smckusick writeroob()
30924726Smckusick {
31024726Smckusick 
31125341Smckusick 	if (dosigwinch == 0) {
31224919Smckusick 		sendwindow();
31329729Smckusick 		(void) signal(SIGWINCH, sigwinch);
31425341Smckusick 	}
31524726Smckusick 	dosigwinch = 1;
31624726Smckusick }
31724726Smckusick 
31811803Sedward catchild()
31911803Sedward {
32011803Sedward 	union wait status;
32111803Sedward 	int pid;
32211803Sedward 
32311803Sedward again:
32429729Smckusick 	pid = wait3(&status, WNOHANG|WUNTRACED, (struct rusage *)0);
32511803Sedward 	if (pid == 0)
32611803Sedward 		return;
32711803Sedward 	/*
32811803Sedward 	 * if the child (reader) dies, just quit
32911803Sedward 	 */
33011803Sedward 	if (pid < 0 || pid == child && !WIFSTOPPED(status))
33129729Smckusick 		done((int)(status.w_termsig | status.w_retcode));
33211803Sedward 	goto again;
33311803Sedward }
33411803Sedward 
3356444Swnj /*
3369365Ssam  * writer: write to remote: 0 -> line.
3379365Ssam  * ~.	terminate
3389365Ssam  * ~^Z	suspend rlogin process.
33910415Ssam  * ~^Y  suspend rlogin process, but leave reader alone.
3406444Swnj  */
3419365Ssam writer()
3426444Swnj {
34323530Sbloom 	char c;
34411803Sedward 	register n;
34523530Sbloom 	register bol = 1;               /* beginning of line */
34623530Sbloom 	register local = 0;
3476444Swnj 
34811803Sedward 	for (;;) {
34911803Sedward 		n = read(0, &c, 1);
35018358Ssam 		if (n <= 0) {
35118358Ssam 			if (n < 0 && errno == EINTR)
35218358Ssam 				continue;
35311803Sedward 			break;
35418358Ssam 		}
3559365Ssam 		/*
3569365Ssam 		 * If we're at the beginning of the line
3579365Ssam 		 * and recognize a command character, then
3589365Ssam 		 * we echo locally.  Otherwise, characters
3599365Ssam 		 * are echo'd remotely.  If the command
3609365Ssam 		 * character is doubled, this acts as a
3619365Ssam 		 * force and local echo is suppressed.
3629365Ssam 		 */
36323530Sbloom 		if (bol) {
36423530Sbloom 			bol = 0;
36523530Sbloom 			if (c == cmdchar) {
36623530Sbloom 				bol = 0;
36723530Sbloom 				local = 1;
36823530Sbloom 				continue;
3696444Swnj 			}
37023530Sbloom 		} else if (local) {
37123530Sbloom 			local = 0;
37223530Sbloom 			if (c == '.' || c == deftc.t_eofc) {
37323530Sbloom 				echo(c);
37423530Sbloom 				break;
3756444Swnj 			}
37623530Sbloom 			if (c == defltc.t_suspc || c == defltc.t_dsuspc) {
37723530Sbloom 				bol = 1;
37823530Sbloom 				echo(c);
37923530Sbloom 				stop(c);
38023530Sbloom 				continue;
38123530Sbloom 			}
38223530Sbloom 			if (c != cmdchar)
38329729Smckusick 				(void) write(rem, &cmdchar, 1);
3846444Swnj 		}
38523530Sbloom 		if (write(rem, &c, 1) == 0) {
38623530Sbloom 			prf("line gone");
38723530Sbloom 			break;
3886444Swnj 		}
38923530Sbloom 		bol = c == defkill || c == deftc.t_eofc ||
39025424Skarels 		    c == deftc.t_intrc || c == defltc.t_suspc ||
39123530Sbloom 		    c == '\r' || c == '\n';
3926444Swnj 	}
3936444Swnj }
3946444Swnj 
39523530Sbloom echo(c)
39623530Sbloom register char c;
39723530Sbloom {
39823530Sbloom 	char buf[8];
39923530Sbloom 	register char *p = buf;
40023530Sbloom 
40123530Sbloom 	c &= 0177;
40223530Sbloom 	*p++ = cmdchar;
40323530Sbloom 	if (c < ' ') {
40423530Sbloom 		*p++ = '^';
40523530Sbloom 		*p++ = c + '@';
40623530Sbloom 	} else if (c == 0177) {
40723530Sbloom 		*p++ = '^';
40823530Sbloom 		*p++ = '?';
40923530Sbloom 	} else
41023530Sbloom 		*p++ = c;
41123530Sbloom 	*p++ = '\r';
41223530Sbloom 	*p++ = '\n';
41329729Smckusick 	(void) write(1, buf, p - buf);
41423530Sbloom }
41523530Sbloom 
41618358Ssam stop(cmdc)
41718358Ssam 	char cmdc;
41818358Ssam {
41918358Ssam 	mode(0);
42029729Smckusick 	(void) signal(SIGCHLD, SIG_IGN);
42129729Smckusick 	(void) kill(cmdc == defltc.t_suspc ? 0 : getpid(), SIGTSTP);
42229729Smckusick 	(void) signal(SIGCHLD, catchild);
42318358Ssam 	mode(1);
42418358Ssam 	sigwinch();			/* check for size changes */
42518358Ssam }
42618358Ssam 
42718358Ssam sigwinch()
42818358Ssam {
42918358Ssam 	struct winsize ws;
43018358Ssam 
43129729Smckusick 	if (dosigwinch && get_window_size(0, &ws) == 0 &&
43218358Ssam 	    bcmp(&ws, &winsize, sizeof (ws))) {
43318358Ssam 		winsize = ws;
43424726Smckusick 		sendwindow();
43518358Ssam 	}
43618358Ssam }
43718358Ssam 
43824726Smckusick /*
43924726Smckusick  * Send the window size to the server via the magic escape
44024726Smckusick  */
44124726Smckusick sendwindow()
44224726Smckusick {
44324726Smckusick 	char obuf[4 + sizeof (struct winsize)];
44424726Smckusick 	struct winsize *wp = (struct winsize *)(obuf+4);
44524726Smckusick 
44624726Smckusick 	obuf[0] = 0377;
44724726Smckusick 	obuf[1] = 0377;
44824726Smckusick 	obuf[2] = 's';
44924726Smckusick 	obuf[3] = 's';
45024726Smckusick 	wp->ws_row = htons(winsize.ws_row);
45124726Smckusick 	wp->ws_col = htons(winsize.ws_col);
45224726Smckusick 	wp->ws_xpixel = htons(winsize.ws_xpixel);
45324726Smckusick 	wp->ws_ypixel = htons(winsize.ws_ypixel);
45424726Smckusick 	(void) write(rem, obuf, sizeof(obuf));
45524726Smckusick }
45624726Smckusick 
45725424Skarels /*
45825424Skarels  * reader: read from remote: line -> 1
45925424Skarels  */
46025424Skarels #define	READING	1
46125424Skarels #define	WRITING	2
46225424Skarels 
46325424Skarels char	rcvbuf[8 * 1024];
46425424Skarels int	rcvcnt;
46525424Skarels int	rcvstate;
46626981Skarels int	ppid;
46725424Skarels jmp_buf	rcvtop;
46825424Skarels 
4696444Swnj oob()
4706444Swnj {
47125424Skarels 	int out = FWRITE, atmark, n;
47225424Skarels 	int rcvd = 0;
4739365Ssam 	char waste[BUFSIZ], mark;
47424726Smckusick 	struct sgttyb sb;
4756444Swnj 
47625424Skarels 	while (recv(rem, &mark, 1, MSG_OOB) < 0)
47725424Skarels 		switch (errno) {
47825424Skarels 
47925424Skarels 		case EWOULDBLOCK:
48025424Skarels 			/*
48125424Skarels 			 * Urgent data not here yet.
48225424Skarels 			 * It may not be possible to send it yet
48325424Skarels 			 * if we are blocked for output
48425424Skarels 			 * and our input buffer is full.
48525424Skarels 			 */
48625424Skarels 			if (rcvcnt < sizeof(rcvbuf)) {
48725424Skarels 				n = read(rem, rcvbuf + rcvcnt,
48825424Skarels 					sizeof(rcvbuf) - rcvcnt);
48925424Skarels 				if (n <= 0)
49025424Skarels 					return;
49125424Skarels 				rcvd += n;
49225424Skarels 			} else {
49325424Skarels 				n = read(rem, waste, sizeof(waste));
49425424Skarels 				if (n <= 0)
49525424Skarels 					return;
49625424Skarels 			}
49725424Skarels 			continue;
49825424Skarels 
49925424Skarels 		default:
50025424Skarels 			return;
5016444Swnj 	}
50225424Skarels 	if (mark & TIOCPKT_WINDOW) {
50324726Smckusick 		/*
50424726Smckusick 		 * Let server know about window size changes
50524726Smckusick 		 */
50629729Smckusick 		(void) kill(ppid, SIGUSR1);
50724726Smckusick 	}
50825424Skarels 	if (!eight && (mark & TIOCPKT_NOSTOP)) {
50929729Smckusick 		(void) ioctl(0, TIOCGETP, (char *)&sb);
51024726Smckusick 		sb.sg_flags &= ~CBREAK;
51124726Smckusick 		sb.sg_flags |= RAW;
51229729Smckusick 		(void) ioctl(0, TIOCSETN, (char *)&sb);
51313075Ssam 		notc.t_stopc = -1;
51413075Ssam 		notc.t_startc = -1;
51529729Smckusick 		(void) ioctl(0, TIOCSETC, (char *)&notc);
5166444Swnj 	}
51725424Skarels 	if (!eight && (mark & TIOCPKT_DOSTOP)) {
51829729Smckusick 		(void) ioctl(0, TIOCGETP, (char *)&sb);
51924726Smckusick 		sb.sg_flags &= ~RAW;
52024726Smckusick 		sb.sg_flags |= CBREAK;
52129729Smckusick 		(void) ioctl(0, TIOCSETN, (char *)&sb);
52213075Ssam 		notc.t_stopc = deftc.t_stopc;
52313075Ssam 		notc.t_startc = deftc.t_startc;
52429729Smckusick 		(void) ioctl(0, TIOCSETC, (char *)&notc);
5256444Swnj 	}
52625424Skarels 	if (mark & TIOCPKT_FLUSHWRITE) {
52729729Smckusick 		(void) ioctl(1, TIOCFLUSH, (char *)&out);
52825424Skarels 		for (;;) {
52925424Skarels 			if (ioctl(rem, SIOCATMARK, &atmark) < 0) {
53025424Skarels 				perror("ioctl");
53125424Skarels 				break;
53225424Skarels 			}
53325424Skarels 			if (atmark)
53425424Skarels 				break;
53525424Skarels 			n = read(rem, waste, sizeof (waste));
53625424Skarels 			if (n <= 0)
53725424Skarels 				break;
53825424Skarels 		}
53925424Skarels 		/*
54025424Skarels 		 * Don't want any pending data to be output,
54125424Skarels 		 * so clear the recv buffer.
54225424Skarels 		 * If we were hanging on a write when interrupted,
54325424Skarels 		 * don't want it to restart.  If we were reading,
54425424Skarels 		 * restart anyway.
54525424Skarels 		 */
54625424Skarels 		rcvcnt = 0;
54725424Skarels 		longjmp(rcvtop, 1);
54825424Skarels 	}
54929729Smckusick 
55025424Skarels 	/*
55129729Smckusick 	 * oob does not do FLUSHREAD (alas!)
55229729Smckusick 	 */
55329729Smckusick 
55429729Smckusick 	/*
55525424Skarels 	 * If we filled the receive buffer while a read was pending,
55625424Skarels 	 * longjmp to the top to restart appropriately.  Don't abort
55725424Skarels 	 * a pending write, however, or we won't know how much was written.
55825424Skarels 	 */
55925424Skarels 	if (rcvd && rcvstate == READING)
56025424Skarels 		longjmp(rcvtop, 1);
5616444Swnj }
5626444Swnj 
5639365Ssam /*
5649365Ssam  * reader: read from remote: line -> 1
5659365Ssam  */
56629729Smckusick reader(oldmask)
56729729Smckusick 	int oldmask;
5686444Swnj {
56926981Skarels #if !defined(BSD) || BSD < 43
57026981Skarels 	int pid = -getpid();
57126981Skarels #else
57225424Skarels 	int pid = getpid();
57326981Skarels #endif
57425424Skarels 	int n, remaining;
57525424Skarels 	char *bufp = rcvbuf;
5766444Swnj 
57729729Smckusick 	(void) signal(SIGTTOU, SIG_IGN);
57829729Smckusick 	(void) signal(SIGURG, oob);
57926981Skarels 	ppid = getppid();
58029729Smckusick 	(void) fcntl(rem, F_SETOWN, pid);
58125424Skarels 	(void) setjmp(rcvtop);
58229729Smckusick 	(void) sigsetmask(oldmask);
5836444Swnj 	for (;;) {
58425424Skarels 		while ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) {
58525424Skarels 			rcvstate = WRITING;
58625424Skarels 			n = write(1, bufp, remaining);
58725424Skarels 			if (n < 0) {
58825424Skarels 				if (errno != EINTR)
58926189Slepreau 					return (-1);
59025424Skarels 				continue;
59125424Skarels 			}
59225424Skarels 			bufp += n;
59325424Skarels 		}
59425424Skarels 		bufp = rcvbuf;
59525424Skarels 		rcvcnt = 0;
59625424Skarels 		rcvstate = READING;
59725424Skarels 		rcvcnt = read(rem, rcvbuf, sizeof (rcvbuf));
59825424Skarels 		if (rcvcnt == 0)
59925424Skarels 			return (0);
60025424Skarels 		if (rcvcnt < 0) {
6019365Ssam 			if (errno == EINTR)
6026444Swnj 				continue;
60326981Skarels 			perror("read");
60425424Skarels 			return (-1);
6056444Swnj 		}
6066444Swnj 	}
6076444Swnj }
6086444Swnj 
6096444Swnj mode(f)
6106444Swnj {
61113075Ssam 	struct tchars *tc;
61213075Ssam 	struct ltchars *ltc;
61313075Ssam 	struct sgttyb sb;
61421583Sbloom 	int	lflags;
6159365Ssam 
61629729Smckusick 	(void) ioctl(0, TIOCGETP, (char *)&sb);
61729729Smckusick 	(void) ioctl(0, TIOCLGET, (char *)&lflags);
6189962Ssam 	switch (f) {
6199962Ssam 
6209962Ssam 	case 0:
62113075Ssam 		sb.sg_flags &= ~(CBREAK|RAW|TBDELAY);
62213075Ssam 		sb.sg_flags |= defflags|tabflag;
6239962Ssam 		tc = &deftc;
62413075Ssam 		ltc = &defltc;
62513075Ssam 		sb.sg_kill = defkill;
62613075Ssam 		sb.sg_erase = deferase;
62721583Sbloom 		lflags = deflflags;
6289962Ssam 		break;
6299962Ssam 
6309962Ssam 	case 1:
63113075Ssam 		sb.sg_flags |= (eight ? RAW : CBREAK);
63213075Ssam 		sb.sg_flags &= ~defflags;
63312155Ssam 		/* preserve tab delays, but turn off XTABS */
63413075Ssam 		if ((sb.sg_flags & TBDELAY) == XTABS)
63513075Ssam 			sb.sg_flags &= ~TBDELAY;
6369962Ssam 		tc = &notc;
63713075Ssam 		ltc = &noltc;
63813075Ssam 		sb.sg_kill = sb.sg_erase = -1;
63921583Sbloom 		if (litout)
64021583Sbloom 			lflags |= LLITOUT;
6419962Ssam 		break;
6429962Ssam 
6439962Ssam 	default:
6449962Ssam 		return;
6456444Swnj 	}
64629729Smckusick 	(void) ioctl(0, TIOCSLTC, (char *)ltc);
64729729Smckusick 	(void) ioctl(0, TIOCSETC, (char *)tc);
64829729Smckusick 	(void) ioctl(0, TIOCSETN, (char *)&sb);
64929729Smckusick 	(void) ioctl(0, TIOCLSET, (char *)&lflags);
6506444Swnj }
6516444Swnj 
6529365Ssam /*VARARGS*/
65324726Smckusick prf(f, a1, a2, a3, a4, a5)
6549365Ssam 	char *f;
6556444Swnj {
65629729Smckusick 
65724726Smckusick 	fprintf(stderr, f, a1, a2, a3, a4, a5);
6586444Swnj 	fprintf(stderr, CRLF);
6596444Swnj }
6606444Swnj 
6619365Ssam lostpeer()
6626444Swnj {
66329729Smckusick 
66429729Smckusick 	(void) signal(SIGPIPE, SIG_IGN);
66512155Ssam 	prf("\007Connection closed.");
66625424Skarels 	done(1);
6676444Swnj }
668