#endif not lint
#ifndef lint
-static char sccsid[] = "@(#)rlogin.c 5.3.1.1 (Berkeley) %G%";
+static char sccsid[] = "@(#)rlogin.c 5.9 (Berkeley) %G%";
#endif not lint
/*
* rlogin - remote login
*/
#include <sys/types.h>
+#include <sys/errno.h>
#include <sys/file.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <errno.h>
#include <pwd.h>
#include <signal.h>
-#include <netdb.h>
#include <setjmp.h>
+#include <netdb.h>
+
+# ifndef TIOCPKT_WINDOW
+# define TIOCPKT_WINDOW 0x80
+# endif TIOCPKT_WINDOW
char *index(), *rindex(), *malloc(), *getenv();
struct passwd *getpwuid();
char term[256] = "network";
extern int errno;
int lostpeer();
-int nosigwin;
-jmp_buf winsizechanged;
+int dosigwinch = 0;
struct winsize winsize;
-int sigwinch();
+int sigwinch(), oob();
main(argc, argv)
int argc;
struct sgttyb ttyb;
struct passwd *pwd;
struct servent *sp;
- int uid, options = 0;
+ int uid, options = 0, oldmask;
int on = 1;
host = rindex(argv[0], '/');
argv++, argc--;
goto another;
}
- if (argc > 0 && !strcmp(*argv, "-w")) {
- nosigwin++;
- argv++, argc--;
- goto another;
- }
if (host == 0)
goto usage;
if (argc > 0)
strcat(term, "/");
strcat(term, speeds[ttyb.sg_ospeed]);
}
- if (!nosigwin && ioctl(0, TIOCGWINSZ, &winsize) == 0) {
- cp = index(term, '\0');
- sprintf(cp, "/%u,%u,%u,%u", winsize.ws_row, winsize.ws_col,
- winsize.ws_xpixel, winsize.ws_ypixel);
- }
+ (void) ioctl(0, TIOCGWINSZ, &winsize);
signal(SIGPIPE, lostpeer);
+ signal(SIGURG, oob);
+ oldmask = sigblock(sigmask(SIGURG));
rem = rcmd(&host, sp->s_port, pwd->pw_name,
name ? name : pwd->pw_name, term, 0);
if (rem < 0)
perror("rlogin: setuid");
exit(1);
}
- doit();
+ doit(oldmask);
/*NOTREACHED*/
usage:
fprintf(stderr,
- "usage: rlogin host [ -ex ] [ -l username ] [ -8 ] [ -L ] [ -w ]\n");
+ "usage: rlogin host [ -ex ] [ -l username ] [ -8 ] [ -L ]\n");
exit(1);
}
int child;
int catchild();
+int writeroob();
int defflags, tabflag;
int deflflags;
struct tchars notc = { -1, -1, -1, -1, -1, -1 };
struct ltchars noltc = { -1, -1, -1, -1, -1, -1 };
-doit()
+doit(oldmask)
{
int exit();
struct sgttyb sb;
notc.t_startc = deftc.t_startc;
notc.t_stopc = deftc.t_stopc;
ioctl(0, TIOCGLTC, (char *)&defltc);
- signal(SIGINT, exit);
+ signal(SIGINT, SIG_IGN);
signal(SIGHUP, exit);
signal(SIGQUIT, exit);
child = fork();
if (child == -1) {
perror("rlogin: fork");
- done();
+ done(1);
}
- signal(SIGINT, SIG_IGN);
- mode(1);
if (child == 0) {
- reader();
+ mode(1);
+ sigsetmask(oldmask);
+ if (reader() == 0) {
+ prf("Connection closed.");
+ exit(0);
+ }
sleep(1);
prf("\007Connection closed.");
exit(3);
}
+ signal(SIGURG, writeroob);
+ sigsetmask(oldmask);
signal(SIGCHLD, catchild);
- if (!nosigwin)
- signal(SIGWINCH, sigwinch);
writer();
prf("Closed connection.");
- done();
+ done(0);
}
-done()
+done(status)
+ int status;
{
mode(0);
if (child > 0 && kill(child, SIGKILL) >= 0)
wait((int *)0);
- exit(0);
+ exit(status);
+}
+
+/*
+ * This is called when the reader process gets the out-of-band (urgent)
+ * request to turn on the window-changing protocol.
+ */
+writeroob()
+{
+
+ if (dosigwinch == 0) {
+ sendwindow();
+ signal(SIGWINCH, sigwinch);
+ }
+ dosigwinch = 1;
}
catchild()
* if the child (reader) dies, just quit
*/
if (pid < 0 || pid == child && !WIFSTOPPED(status))
- done();
+ done(status.w_termsig | status.w_retcode);
goto again;
}
register bol = 1; /* beginning of line */
register local = 0;
- /*
- * Handle SIGWINCH's with in-band signaling of new
- * window size. It seems reasonable that we flush
- * pending input and not force out of band signal
- * as this most likely will occur from an input device
- * other than the keyboard (e.g. a mouse).
- *
- * The hack of using 0377 to signal an in-band signal
- * is pretty bad, but otherwise we'd be forced to
- * either get complicated (use MSG_OOB) or go to a
- * serious (telnet-style) protocol.
- */
- if (setjmp(winsizechanged)) {
- char obuf[4 + sizeof (struct winsize)];
- struct winsize *wp = (struct winsize *)(obuf+4);
-
- obuf[0] = 0377; /* XXX */
- obuf[1] = 0377; /* XXX */
- obuf[2] = 's'; /* XXX */
- obuf[3] = 's'; /* XXX */
- wp->ws_row = htons(winsize.ws_row);
- wp->ws_col = htons(winsize.ws_col);
- wp->ws_xpixel = htons(winsize.ws_xpixel);
- wp->ws_ypixel = htons(winsize.ws_ypixel);
- (void) write(rem, obuf, 4+sizeof (*wp));
- }
-
for (;;) {
n = read(0, &c, 1);
if (n <= 0) {
continue;
break;
}
- if (!eight)
- c &= 0177;
/*
* If we're at the beginning of the line
* and recognize a command character, then
break;
}
bol = c == defkill || c == deftc.t_eofc ||
+ c == deftc.t_intrc || c == defltc.t_suspc ||
c == '\r' || c == '\n';
}
}
stop(cmdc)
char cmdc;
{
- struct winsize ws;
-
mode(0);
signal(SIGCHLD, SIG_IGN);
kill(cmdc == defltc.t_suspc ? 0 : getpid(), SIGTSTP);
{
struct winsize ws;
- if (!nosigwin && ioctl(0, TIOCGWINSZ, &ws) == 0 &&
+ if (dosigwinch && ioctl(0, TIOCGWINSZ, &ws) == 0 &&
bcmp(&ws, &winsize, sizeof (ws))) {
winsize = ws;
- longjmp(winsizechanged, 1);
+ sendwindow();
}
}
+/*
+ * Send the window size to the server via the magic escape
+ */
+sendwindow()
+{
+ char obuf[4 + sizeof (struct winsize)];
+ struct winsize *wp = (struct winsize *)(obuf+4);
+
+ obuf[0] = 0377;
+ obuf[1] = 0377;
+ obuf[2] = 's';
+ obuf[3] = 's';
+ wp->ws_row = htons(winsize.ws_row);
+ wp->ws_col = htons(winsize.ws_col);
+ wp->ws_xpixel = htons(winsize.ws_xpixel);
+ wp->ws_ypixel = htons(winsize.ws_ypixel);
+ (void) write(rem, obuf, sizeof(obuf));
+}
+
+/*
+ * reader: read from remote: line -> 1
+ */
+#define READING 1
+#define WRITING 2
+
+char rcvbuf[8 * 1024];
+int rcvcnt;
+int rcvstate;
+jmp_buf rcvtop;
+
oob()
{
- int out = 1+1, atmark;
+ int out = FWRITE, atmark, n;
+ int rcvd = 0;
char waste[BUFSIZ], mark;
+ struct sgttyb sb;
- ioctl(1, TIOCFLUSH, (char *)&out);
- for (;;) {
- if (ioctl(rem, SIOCATMARK, &atmark) < 0) {
- perror("ioctl");
- break;
- }
- if (atmark)
- break;
- if (read(rem, waste, sizeof (waste)) <= 0)
- break;
+ while (recv(rem, &mark, 1, MSG_OOB) < 0)
+ switch (errno) {
+
+ case EWOULDBLOCK:
+ /*
+ * Urgent data not here yet.
+ * It may not be possible to send it yet
+ * if we are blocked for output
+ * and our input buffer is full.
+ */
+ if (rcvcnt < sizeof(rcvbuf)) {
+ n = read(rem, rcvbuf + rcvcnt,
+ sizeof(rcvbuf) - rcvcnt);
+ if (n <= 0)
+ return;
+ rcvd += n;
+ } else {
+ n = read(rem, waste, sizeof(waste));
+ if (n <= 0)
+ return;
+ }
+ continue;
+
+ default:
+ return;
}
- recv(rem, &mark, 1, MSG_OOB);
- if (mark & TIOCPKT_NOSTOP) {
+ if (mark & TIOCPKT_WINDOW) {
+ /*
+ * Let server know about window size changes
+ */
+ kill(getppid(), SIGURG);
+ }
+ if (!eight && (mark & TIOCPKT_NOSTOP)) {
+ ioctl(0, TIOCGETP, (char *)&sb);
+ sb.sg_flags &= ~CBREAK;
+ sb.sg_flags |= RAW;
+ ioctl(0, TIOCSETN, (char *)&sb);
notc.t_stopc = -1;
notc.t_startc = -1;
ioctl(0, TIOCSETC, (char *)¬c);
}
- if (mark & TIOCPKT_DOSTOP) {
+ if (!eight && (mark & TIOCPKT_DOSTOP)) {
+ ioctl(0, TIOCGETP, (char *)&sb);
+ sb.sg_flags &= ~RAW;
+ sb.sg_flags |= CBREAK;
+ ioctl(0, TIOCSETN, (char *)&sb);
notc.t_stopc = deftc.t_stopc;
notc.t_startc = deftc.t_startc;
ioctl(0, TIOCSETC, (char *)¬c);
}
+ if (mark & TIOCPKT_FLUSHWRITE) {
+ ioctl(1, TIOCFLUSH, (char *)&out);
+ for (;;) {
+ if (ioctl(rem, SIOCATMARK, &atmark) < 0) {
+ perror("ioctl");
+ break;
+ }
+ if (atmark)
+ break;
+ n = read(rem, waste, sizeof (waste));
+ if (n <= 0)
+ break;
+ }
+ /*
+ * Don't want any pending data to be output,
+ * so clear the recv buffer.
+ * If we were hanging on a write when interrupted,
+ * don't want it to restart. If we were reading,
+ * restart anyway.
+ */
+ rcvcnt = 0;
+ longjmp(rcvtop, 1);
+ }
+ /*
+ * If we filled the receive buffer while a read was pending,
+ * longjmp to the top to restart appropriately. Don't abort
+ * a pending write, however, or we won't know how much was written.
+ */
+ if (rcvd && rcvstate == READING)
+ longjmp(rcvtop, 1);
}
/*
*/
reader()
{
- char rb[BUFSIZ];
- register int cnt;
+ int pid = getpid();
+ int n, remaining;
+ char *bufp = rcvbuf;
- signal(SIGURG, oob);
signal(SIGTTOU, SIG_IGN);
- { int pid = getpid();
- fcntl(rem, F_SETOWN, pid); }
+ fcntl(rem, F_SETOWN, pid);
+ (void) setjmp(rcvtop);
for (;;) {
- cnt = read(rem, rb, sizeof (rb));
- if (cnt == 0)
- break;
- if (cnt < 0) {
+ while ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) {
+ rcvstate = WRITING;
+ n = write(1, bufp, remaining);
+ if (n < 0) {
+ if (errno != EINTR)
+ return (-1);
+ continue;
+ }
+ bufp += n;
+ }
+ bufp = rcvbuf;
+ rcvcnt = 0;
+ rcvstate = READING;
+ rcvcnt = read(rem, rcvbuf, sizeof (rcvbuf));
+ if (rcvcnt == 0)
+ return (0);
+ if (rcvcnt < 0) {
if (errno == EINTR)
continue;
- break;
+ return (-1);
}
- write(1, rb, cnt);
}
}
}
/*VARARGS*/
-prf(f, a1, a2, a3)
+prf(f, a1, a2, a3, a4, a5)
char *f;
{
- fprintf(stderr, f, a1, a2, a3);
+ fprintf(stderr, f, a1, a2, a3, a4, a5);
fprintf(stderr, CRLF);
}
{
signal(SIGPIPE, SIG_IGN);
prf("\007Connection closed.");
- done();
+ done(1);
}