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 *)¬c); 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 *)¬c); 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 = ¬c; 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