[comp.unix.ultrix] Ultrix 4.X rlogin problem fix

brian@cimage.com (Brian Kelley) (12/05/90)

I called DEC tech support last week to check on the rlogin problem.  I first
reported the problem well over 4 weeks ago.  The software support person I
spoke with said that he first took a report on the problem a LONG time ago
(when Ultrix 4.0 came out).  When I placed my original call, I was told that
Ultrix engineers considered it "critical" and were working on the problem.

The support person mentioned that he had heard that if you run your rlogin 
in the background (rlogin host &) and bring it into the foreground, it will
work.  I was slightly skeptical, since this implied that the problem might
be in rlogin itself rather than something in the kernel.  I was quite
surprised when it worked.  It made me wonder just where the problem was.  

I dug down into my tahoe 4.3 sources and found I had rlogin source.
I compiled it, made it setuid to root, and it worked.

Am I missing something?  Am I just imagining that it's this simple?

How many DEC engineers does it take screw in a lightbulb?


Here's the tahoe source and Makefile (or if you have it around, you can use
your own).


  Brian


---
brian@cimage.com

----------------------------------Cut Here------------------------------------
#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  README Makefile rlogin.c
# Wrapped by brian@cimage.com on Tue Dec  4 23:39:26 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f README -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"README\"
else
echo shar: Extracting \"README\" \(820 characters\)
sed "s/^X//" >README <<'END_OF_README'
X
X
XTahoe 4.3 rlogin program
X
XThis shar file is the Tahoe 4.3 BSD rlogin program.  I used it to replace
Xthe rlogin shipped with Ultrix 4.0 and 4.1.   It has a bug that prevents
Xyou from doing an rlogin from Ultrix to a Sun running 4.1 or 4.1.1.
X
X
XI have made no changes and I, of course, don't warranty it.  I guess I also
Xhave to say that "this software was developed by the University of
XCalifornia, Berkeley."  Please see the copyright at the top of rlogin.c.  
X
X
XWhat worked for me:
X
XType make to build rlogin.  You may want to strip it after you've built it.
X
Xmv /usr/ucb/rlogin /usr/ucb/rlogin.old
X
Xcp rlogin /usr/ucb/rlogin
X
XThe new rlogin must be owned by root and setuid, just like the old one.
X
X
X
X
XIt should work.  I would like to hear if you have any trouble.
X
XWhy couldn't DEC do this?
X
X
X  Brian@cimage.com
X
X
X
END_OF_README
if test 820 -ne `wc -c <README`; then
    echo shar: \"README\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f Makefile -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"Makefile\"
else
echo shar: Extracting \"Makefile\" \(1314 characters\)
sed "s/^X//" >Makefile <<'END_OF_Makefile'
X#
X# Copyright (c) 1988 Regents of the University of California.
X# All rights reserved.
X#
X# Redistribution and use in source and binary forms are permitted
X# provided that the above copyright notice and this paragraph are
X# duplicated in all such forms and that any documentation, advertising
X# materials, and other materials related to such redistribution and
X# use acknowledge that the software was developed by the University
X# of California, Berkeley.  The name of the University may not be
X# used to endorse or promote products derived from this software
X# without specific prior written permission.  THIS SOFTWARE IS PROVIDED
X# ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
X# WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND
X# FITNESS FOR A PARTICULAR PURPOSE.
X#
X# @(#)Makefile	5.1 (Berkeley) 9/19/88
X#
X
XCFLAGS=	-O
XLIBC=	/lib/libc.a
XSRCS=	rlogin.c
XOBJS=
XMAN=	rlogin.0
X
Xall: rlogin
X
Xrlogin: ${LIBC}
X	${CC} -o $@ ${CFLAGS} $@.c
X
Xclean:
X	rm -f ${OBJS} core rlogin
X
Xcleandir: clean
X	rm -f ${MAN} tags .depend
X
Xdepend: ${SRCS}
X	mkdep -p ${CFLAGS} ${SRCS}
X
Xinstall: ${MAN}
X	install -s -o root -g bin -m 4755 rlogin ${DESTDIR}/usr/ucb/rlogin
X	install -c -o bin -g bin -m 444 rlogin.0 ${DESTDIR}/usr/man/cat1
X
Xlint: ${SRCS}
X	lint ${CFLAGS} ${SRCS}
X
Xtags: ${SRCS}
X	ctags ${SRCS}
END_OF_Makefile
if test 1314 -ne `wc -c <Makefile`; then
    echo shar: \"Makefile\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f rlogin.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"rlogin.c\"
else
echo shar: Extracting \"rlogin.c\" \(13838 characters\)
sed "s/^X//" >rlogin.c <<'END_OF_rlogin.c'
X/*
X * Copyright (c) 1983 The Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice and this paragraph are
X * duplicated in all such forms and that any documentation,
X * advertising materials, and other materials related to such
X * distribution and use acknowledge that the software was developed
X * by the University of California, Berkeley.  The name of the
X * University may not be used to endorse or promote products derived
X * from this software without specific prior written permission.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X */
X
X#ifndef lint
Xchar copyright[] =
X"@(#) Copyright (c) 1983 The Regents of the University of California.\n\
X All rights reserved.\n";
X#endif /* not lint */
X
X#ifndef lint
Xstatic char sccsid[] = "@(#)rlogin.c	5.12 (Berkeley) 9/19/88";
X#endif /* not lint */
X
X/*
X * rlogin - remote login
X */
X#include <sys/param.h>
X#include <sys/errno.h>
X#include <sys/file.h>
X#include <sys/socket.h>
X#include <sys/time.h>
X#include <sys/resource.h>
X#include <sys/wait.h>
X
X#include <netinet/in.h>
X
X#include <stdio.h>
X#include <sgtty.h>
X#include <errno.h>
X#include <pwd.h>
X#include <signal.h>
X#include <setjmp.h>
X#include <netdb.h>
X
X# ifndef TIOCPKT_WINDOW
X# define TIOCPKT_WINDOW 0x80
X# endif TIOCPKT_WINDOW
X
X/* concession to sun */
X# ifndef SIGUSR1
X# define SIGUSR1 30
X# endif SIGUSR1
X
Xchar	*index(), *rindex(), *malloc(), *getenv(), *strcat(), *strcpy();
Xstruct	passwd *getpwuid();
Xchar	*name;
Xint	rem;
Xchar	cmdchar = '~';
Xint	eight;
Xint	litout;
Xchar	*speeds[] =
X    { "0", "50", "75", "110", "134", "150", "200", "300",
X      "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400" };
Xchar	term[256] = "network";
Xextern	int errno;
Xint	lostpeer();
Xint	dosigwinch = 0;
X#ifndef sigmask
X#define sigmask(m)	(1 << ((m)-1))
X#endif
X#ifdef sun
Xstruct winsize {
X	unsigned short ws_row, ws_col;
X	unsigned short ws_xpixel, ws_ypixel;
X};
X#endif sun
Xstruct	winsize winsize;
Xint	sigwinch(), oob();
X
X/*
X * The following routine provides compatibility (such as it is)
X * between 4.2BSD Suns and others.  Suns have only a `ttysize',
X * so we convert it to a winsize.
X */
X#ifdef sun
Xint
Xget_window_size(fd, wp)
X	int fd;
X	struct winsize *wp;
X{
X	struct ttysize ts;
X	int error;
X
X	if ((error = ioctl(0, TIOCGSIZE, &ts)) != 0)
X		return (error);
X	wp->ws_row = ts.ts_lines;
X	wp->ws_col = ts.ts_cols;
X	wp->ws_xpixel = 0;
X	wp->ws_ypixel = 0;
X	return (0);
X}
X#else sun
X#define get_window_size(fd, wp)	ioctl(fd, TIOCGWINSZ, wp)
X#endif sun
X
Xmain(argc, argv)
X	int argc;
X	char **argv;
X{
X	char *host, *cp;
X	struct sgttyb ttyb;
X	struct passwd *pwd;
X	struct servent *sp;
X	int uid, options = 0, oldmask;
X	int on = 1;
X
X	host = rindex(argv[0], '/');
X	if (host)
X		host++;
X	else
X		host = argv[0];
X	argv++, --argc;
X	if (!strcmp(host, "rlogin"))
X		host = *argv++, --argc;
Xanother:
X	if (argc > 0 && !strcmp(*argv, "-d")) {
X		argv++, argc--;
X		options |= SO_DEBUG;
X		goto another;
X	}
X	if (argc > 0 && !strcmp(*argv, "-l")) {
X		argv++, argc--;
X		if (argc == 0)
X			goto usage;
X		name = *argv++; argc--;
X		goto another;
X	}
X	if (argc > 0 && !strncmp(*argv, "-e", 2)) {
X		cmdchar = argv[0][2];
X		argv++, argc--;
X		goto another;
X	}
X	if (argc > 0 && !strcmp(*argv, "-8")) {
X		eight = 1;
X		argv++, argc--;
X		goto another;
X	}
X	if (argc > 0 && !strcmp(*argv, "-L")) {
X		litout = 1;
X		argv++, argc--;
X		goto another;
X	}
X	if (host == 0)
X		goto usage;
X	if (argc > 0)
X		goto usage;
X	pwd = getpwuid(getuid());
X	if (pwd == 0) {
X		fprintf(stderr, "Who are you?\n");
X		exit(1);
X	}
X	sp = getservbyname("login", "tcp");
X	if (sp == 0) {
X		fprintf(stderr, "rlogin: login/tcp: unknown service\n");
X		exit(2);
X	}
X	cp = getenv("TERM");
X	if (cp)
X		(void) strcpy(term, cp);
X	if (ioctl(0, TIOCGETP, &ttyb) == 0) {
X		(void) strcat(term, "/");
X		(void) strcat(term, speeds[ttyb.sg_ospeed]);
X	}
X	(void) get_window_size(0, &winsize);
X	(void) signal(SIGPIPE, lostpeer);
X	/* will use SIGUSR1 for window size hack, so hold it off */
X	oldmask = sigblock(sigmask(SIGURG) | sigmask(SIGUSR1));
X        rem = rcmd(&host, sp->s_port, pwd->pw_name,
X	    name ? name : pwd->pw_name, term, 0);
X        if (rem < 0)
X                exit(1);
X	if (options & SO_DEBUG &&
X	    setsockopt(rem, SOL_SOCKET, SO_DEBUG, &on, sizeof (on)) < 0)
X		perror("rlogin: setsockopt (SO_DEBUG)");
X	uid = getuid();
X	if (setuid(uid) < 0) {
X		perror("rlogin: setuid");
X		exit(1);
X	}
X	doit(oldmask);
X	/*NOTREACHED*/
Xusage:
X	fprintf(stderr,
X	    "usage: rlogin host [ -ex ] [ -l username ] [ -8 ] [ -L ]\n");
X	exit(1);
X}
X
X#define CRLF "\r\n"
X
Xint	child;
Xint	catchild();
Xint	copytochild(), writeroob();
X
Xint	defflags, tabflag;
Xint	deflflags;
Xchar	deferase, defkill;
Xstruct	tchars deftc;
Xstruct	ltchars defltc;
Xstruct	tchars notc =	{ -1, -1, -1, -1, -1, -1 };
Xstruct	ltchars noltc =	{ -1, -1, -1, -1, -1, -1 };
X
Xdoit(oldmask)
X{
X	int exit();
X	struct sgttyb sb;
X
X	(void) ioctl(0, TIOCGETP, (char *)&sb);
X	defflags = sb.sg_flags;
X	tabflag = defflags & TBDELAY;
X	defflags &= ECHO | CRMOD;
X	deferase = sb.sg_erase;
X	defkill = sb.sg_kill;
X	(void) ioctl(0, TIOCLGET, (char *)&deflflags);
X	(void) ioctl(0, TIOCGETC, (char *)&deftc);
X	notc.t_startc = deftc.t_startc;
X	notc.t_stopc = deftc.t_stopc;
X	(void) ioctl(0, TIOCGLTC, (char *)&defltc);
X	(void) signal(SIGINT, SIG_IGN);
X	setsignal(SIGHUP, exit);
X	setsignal(SIGQUIT, exit);
X	child = fork();
X	if (child == -1) {
X		perror("rlogin: fork");
X		done(1);
X	}
X	if (child == 0) {
X		mode(1);
X		if (reader(oldmask) == 0) {
X			prf("Connection closed.");
X			exit(0);
X		}
X		sleep(1);
X		prf("\007Connection closed.");
X		exit(3);
X	}
X
X	/*
X	 * We may still own the socket, and may have a pending SIGURG
X	 * (or might receive one soon) that we really want to send to
X	 * the reader.  Set a trap that simply copies such signals to
X	 * the child.
X	 */
X	(void) signal(SIGURG, copytochild);
X	(void) signal(SIGUSR1, writeroob);
X	(void) sigsetmask(oldmask);
X	(void) signal(SIGCHLD, catchild);
X	writer();
X	prf("Closed connection.");
X	done(0);
X}
X
X/*
X * Trap a signal, unless it is being ignored.
X */
Xsetsignal(sig, act)
X	int sig, (*act)();
X{
X	int omask = sigblock(sigmask(sig));
X
X	if (signal(sig, act) == SIG_IGN)
X		(void) signal(sig, SIG_IGN);
X	(void) sigsetmask(omask);
X}
X
Xdone(status)
X	int status;
X{
X	int w;
X
X	mode(0);
X	if (child > 0) {
X		/* make sure catchild does not snap it up */
X		(void) signal(SIGCHLD, SIG_DFL);
X		if (kill(child, SIGKILL) >= 0)
X			while ((w = wait((union wait *)0)) > 0 && w != child)
X				/*void*/;
X	}
X	exit(status);
X}
X
X/*
X * Copy SIGURGs to the child process.
X */
Xcopytochild()
X{
X
X	(void) kill(child, SIGURG);
X}
X
X/*
X * This is called when the reader process gets the out-of-band (urgent)
X * request to turn on the window-changing protocol.
X */
Xwriteroob()
X{
X
X	if (dosigwinch == 0) {
X		sendwindow();
X		(void) signal(SIGWINCH, sigwinch);
X	}
X	dosigwinch = 1;
X}
X
Xcatchild()
X{
X	union wait status;
X	int pid;
X
Xagain:
X	pid = wait3(&status, WNOHANG|WUNTRACED, (struct rusage *)0);
X	if (pid == 0)
X		return;
X	/*
X	 * if the child (reader) dies, just quit
X	 */
X	if (pid < 0 || pid == child && !WIFSTOPPED(status))
X		done((int)(status.w_termsig | status.w_retcode));
X	goto again;
X}
X
X/*
X * writer: write to remote: 0 -> line.
X * ~.	terminate
X * ~^Z	suspend rlogin process.
X * ~^Y  suspend rlogin process, but leave reader alone.
X */
Xwriter()
X{
X	char c;
X	register n;
X	register bol = 1;               /* beginning of line */
X	register local = 0;
X
X	for (;;) {
X		n = read(0, &c, 1);
X		if (n <= 0) {
X			if (n < 0 && errno == EINTR)
X				continue;
X			break;
X		}
X		/*
X		 * If we're at the beginning of the line
X		 * and recognize a command character, then
X		 * we echo locally.  Otherwise, characters
X		 * are echo'd remotely.  If the command
X		 * character is doubled, this acts as a 
X		 * force and local echo is suppressed.
X		 */
X		if (bol) {
X			bol = 0;
X			if (c == cmdchar) {
X				bol = 0;
X				local = 1;
X				continue;
X			}
X		} else if (local) {
X			local = 0;
X			if (c == '.' || c == deftc.t_eofc) {
X				echo(c);
X				break;
X			}
X			if (c == defltc.t_suspc || c == defltc.t_dsuspc) {
X				bol = 1;
X				echo(c);
X				stop(c);
X				continue;
X			}
X			if (c != cmdchar)
X				(void) write(rem, &cmdchar, 1);
X		}
X		if (write(rem, &c, 1) == 0) {
X			prf("line gone");
X			break;
X		}
X		bol = c == defkill || c == deftc.t_eofc ||
X		    c == deftc.t_intrc || c == defltc.t_suspc ||
X		    c == '\r' || c == '\n';
X	}
X}
X
Xecho(c)
Xregister char c;
X{
X	char buf[8];
X	register char *p = buf;
X
X	c &= 0177;
X	*p++ = cmdchar;
X	if (c < ' ') {
X		*p++ = '^';
X		*p++ = c + '@';
X	} else if (c == 0177) {
X		*p++ = '^';
X		*p++ = '?';
X	} else
X		*p++ = c;
X	*p++ = '\r';
X	*p++ = '\n';
X	(void) write(1, buf, p - buf);
X}
X
Xstop(cmdc)
X	char cmdc;
X{
X	mode(0);
X	(void) signal(SIGCHLD, SIG_IGN);
X	(void) kill(cmdc == defltc.t_suspc ? 0 : getpid(), SIGTSTP);
X	(void) signal(SIGCHLD, catchild);
X	mode(1);
X	sigwinch();			/* check for size changes */
X}
X
Xsigwinch()
X{
X	struct winsize ws;
X
X	if (dosigwinch && get_window_size(0, &ws) == 0 &&
X	    bcmp(&ws, &winsize, sizeof (ws))) {
X		winsize = ws;
X		sendwindow();
X	}
X}
X
X/*
X * Send the window size to the server via the magic escape
X */
Xsendwindow()
X{
X	char obuf[4 + sizeof (struct winsize)];
X	struct winsize *wp = (struct winsize *)(obuf+4);
X
X	obuf[0] = 0377;
X	obuf[1] = 0377;
X	obuf[2] = 's';
X	obuf[3] = 's';
X	wp->ws_row = htons(winsize.ws_row);
X	wp->ws_col = htons(winsize.ws_col);
X	wp->ws_xpixel = htons(winsize.ws_xpixel);
X	wp->ws_ypixel = htons(winsize.ws_ypixel);
X	(void) write(rem, obuf, sizeof(obuf));
X}
X
X/*
X * reader: read from remote: line -> 1
X */
X#define	READING	1
X#define	WRITING	2
X
Xchar	rcvbuf[8 * 1024];
Xint	rcvcnt;
Xint	rcvstate;
Xint	ppid;
Xjmp_buf	rcvtop;
X
Xoob()
X{
X	int out = FWRITE, atmark, n;
X	int rcvd = 0;
X	char waste[BUFSIZ], mark;
X	struct sgttyb sb;
X
X	while (recv(rem, &mark, 1, MSG_OOB) < 0)
X		switch (errno) {
X		
X		case EWOULDBLOCK:
X			/*
X			 * Urgent data not here yet.
X			 * It may not be possible to send it yet
X			 * if we are blocked for output
X			 * and our input buffer is full.
X			 */
X			if (rcvcnt < sizeof(rcvbuf)) {
X				n = read(rem, rcvbuf + rcvcnt,
X					sizeof(rcvbuf) - rcvcnt);
X				if (n <= 0)
X					return;
X				rcvd += n;
X			} else {
X				n = read(rem, waste, sizeof(waste));
X				if (n <= 0)
X					return;
X			}
X			continue;
X				
X		default:
X			return;
X	}
X	if (mark & TIOCPKT_WINDOW) {
X		/*
X		 * Let server know about window size changes
X		 */
X		(void) kill(ppid, SIGUSR1);
X	}
X	if (!eight && (mark & TIOCPKT_NOSTOP)) {
X		(void) ioctl(0, TIOCGETP, (char *)&sb);
X		sb.sg_flags &= ~CBREAK;
X		sb.sg_flags |= RAW;
X		(void) ioctl(0, TIOCSETN, (char *)&sb);
X		notc.t_stopc = -1;
X		notc.t_startc = -1;
X		(void) ioctl(0, TIOCSETC, (char *)&notc);
X	}
X	if (!eight && (mark & TIOCPKT_DOSTOP)) {
X		(void) ioctl(0, TIOCGETP, (char *)&sb);
X		sb.sg_flags &= ~RAW;
X		sb.sg_flags |= CBREAK;
X		(void) ioctl(0, TIOCSETN, (char *)&sb);
X		notc.t_stopc = deftc.t_stopc;
X		notc.t_startc = deftc.t_startc;
X		(void) ioctl(0, TIOCSETC, (char *)&notc);
X	}
X	if (mark & TIOCPKT_FLUSHWRITE) {
X		(void) ioctl(1, TIOCFLUSH, (char *)&out);
X		for (;;) {
X			if (ioctl(rem, SIOCATMARK, &atmark) < 0) {
X				perror("ioctl");
X				break;
X			}
X			if (atmark)
X				break;
X			n = read(rem, waste, sizeof (waste));
X			if (n <= 0)
X				break;
X		}
X		/*
X		 * Don't want any pending data to be output,
X		 * so clear the recv buffer.
X		 * If we were hanging on a write when interrupted,
X		 * don't want it to restart.  If we were reading,
X		 * restart anyway.
X		 */
X		rcvcnt = 0;
X		longjmp(rcvtop, 1);
X	}
X
X	/*
X	 * oob does not do FLUSHREAD (alas!)
X	 */
X
X	/*
X	 * If we filled the receive buffer while a read was pending,
X	 * longjmp to the top to restart appropriately.  Don't abort
X	 * a pending write, however, or we won't know how much was written.
X	 */
X	if (rcvd && rcvstate == READING)
X		longjmp(rcvtop, 1);
X}
X
X/*
X * reader: read from remote: line -> 1
X */
Xreader(oldmask)
X	int oldmask;
X{
X#if !defined(BSD) || BSD < 43
X	int pid = -getpid();
X#else
X	int pid = getpid();
X#endif
X	int n, remaining;
X	char *bufp = rcvbuf;
X
X	(void) signal(SIGTTOU, SIG_IGN);
X	(void) signal(SIGURG, oob);
X	ppid = getppid();
X	(void) fcntl(rem, F_SETOWN, pid);
X	(void) setjmp(rcvtop);
X	(void) sigsetmask(oldmask);
X	for (;;) {
X		while ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) {
X			rcvstate = WRITING;
X			n = write(1, bufp, remaining);
X			if (n < 0) {
X				if (errno != EINTR)
X					return (-1);
X				continue;
X			}
X			bufp += n;
X		}
X		bufp = rcvbuf;
X		rcvcnt = 0;
X		rcvstate = READING;
X		rcvcnt = read(rem, rcvbuf, sizeof (rcvbuf));
X		if (rcvcnt == 0)
X			return (0);
X		if (rcvcnt < 0) {
X			if (errno == EINTR)
X				continue;
X			perror("read");
X			return (-1);
X		}
X	}
X}
X
Xmode(f)
X{
X	struct tchars *tc;
X	struct ltchars *ltc;
X	struct sgttyb sb;
X	int	lflags;
X
X	(void) ioctl(0, TIOCGETP, (char *)&sb);
X	(void) ioctl(0, TIOCLGET, (char *)&lflags);
X	switch (f) {
X
X	case 0:
X		sb.sg_flags &= ~(CBREAK|RAW|TBDELAY);
X		sb.sg_flags |= defflags|tabflag;
X		tc = &deftc;
X		ltc = &defltc;
X		sb.sg_kill = defkill;
X		sb.sg_erase = deferase;
X		lflags = deflflags;
X		break;
X
X	case 1:
X		sb.sg_flags |= (eight ? RAW : CBREAK);
X		sb.sg_flags &= ~defflags;
X		/* preserve tab delays, but turn off XTABS */
X		if ((sb.sg_flags & TBDELAY) == XTABS)
X			sb.sg_flags &= ~TBDELAY;
X		tc = &notc;
X		ltc = &noltc;
X		sb.sg_kill = sb.sg_erase = -1;
X		if (litout)
X			lflags |= LLITOUT;
X		break;
X
X	default:
X		return;
X	}
X	(void) ioctl(0, TIOCSLTC, (char *)ltc);
X	(void) ioctl(0, TIOCSETC, (char *)tc);
X	(void) ioctl(0, TIOCSETN, (char *)&sb);
X	(void) ioctl(0, TIOCLSET, (char *)&lflags);
X}
X
X/*VARARGS*/
Xprf(f, a1, a2, a3, a4, a5)
X	char *f;
X{
X
X	fprintf(stderr, f, a1, a2, a3, a4, a5);
X	fprintf(stderr, CRLF);
X}
X
Xlostpeer()
X{
X
X	(void) signal(SIGPIPE, SIG_IGN);
X	prf("\007Connection closed.");
X	done(1);
X}
END_OF_rlogin.c
if test 13838 -ne `wc -c <rlogin.c`; then
    echo shar: \"rlogin.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of shell archive.
exit 0