jdb@mordor.UUCP (John Bruner) (08/16/85)
: This is a shar archive. Extract with sh, not csh. echo x - uw.old.c cat > uw.old.c << '!Funky!Stuff!' # /* * uw - UNIX windows program for the Macintosh (VAX end) * * Copyright 1985 by John D. Bruner. All rights reserved. Permission to * copy this program is given provided that the copy is not sold and that * this copyright notice is included. * * Compile: cc -o uw -O uw.c */ #include <sys/types.h> #include <sys/stat.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <sys/wait.h> #include <sys/time.h> #include <sys/resource.h> #include <sys/uio.h> #include <signal.h> #include <setjmp.h> #include <errno.h> #include <fcntl.h> #include <stdio.h> #include "uw.h" #define MAXENV 128 /* maximum environment size */ #define W_IN 0 #define W_OUT 1 #define NFDS 20 /* max number of file descriptors */ #define XON 0021 /* ASCII XON */ #define XOFF 0023 /* ASCII XOFF */ #define RUB 0177 /* ASCII RUBOUT */ #define META 0200 /* "meta" bit for whatever it's worth */ #define RCV_OK (-1) /* see recvcmd() */ #define RCV_META (-2) /* see recvcmd() */ typedef int fildes_t; /* file descriptor data type */ typedef int nwin_t; /* window index data type */ struct window { fildes_t w_fd; char w_tty[32]; }; struct window window[NWINDOW]; /* window data structures */ struct window *fdmap[NFDS]; /* mapping from fd's to windows */ struct window *curwin[2]; /* current input and output windows */ char portal[] = "/tmp/uwXXXXXX"; /* UNIX-domain network address */ /* The following are added to the environment of all child processes */ char env_uwin[64] = "UWIN="; char *env[] = { env_uwin, "TERM=adm31", "TERMCAP=adm31:cr=^M:do=^J:nl=^J:al=\\EE:am:le=^H:bs:ce=\\ET:cm=\\E=%+ %+ :cl=^Z:cd=\\EY:co#80:dc=\\EW:dl=\\ER:ei=\\Er:ho=^^:im=\\Eq:li#24:mi:nd=^L:up=^K:MT:km:", NULL }; int ctlch[] = { -1, IAC, XON, XOFF, -1, -1, -1, -1 }; /* CTL char mapping */ struct selmask { int sm_rd; int sm_wt; int sm_ex; } selmask[2]; extern char *strncpy(), *strncat(); extern char *mktemp(); extern char *getenv(); extern done(), cwait(), onalarm(); extern int errno; main(argc, argv) char **argv; { register fildes_t fd, sd; register struct window *w; struct sockaddr sa; /* * Make sure we don't accidentally try to run this inside itself. */ if (getenv("UWIN")) { fprintf(stderr, "%s is already running\n", *argv); exit(1); } /* * Close all file descriptors except 0, 1, and 2. */ for (fd=3; fd < NFDS; fd++) (void)close(fd); /* * Mark all windows closed. */ for (w=window; w < window+NWINDOW; w++) w->w_fd = -1; /* * Create a UNIX-domain network address, and put its name into * the environment so that descendents can contact us with new * window requests. */ (void)strncat(env_uwin, mktemp(portal), sizeof env_uwin - 1); setenv(env); if ((sd=socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) { perror("socket"); exit(1); } sa.sa_family = AF_UNIX; (void)strncpy(sa.sa_data, portal, sizeof sa.sa_data-1); sa.sa_data[sizeof sa.sa_data-1] = '\0'; if (bind(sd, &sa, sizeof sa.sa_family + strlen(sa.sa_data)) < 0) { perror("bind"); exit(1); } if (fcntl(sd, F_SETFL, FNDELAY)) perror("fcntl(sd, F_SETFL, FNDELAY)"); /* * Ignore interrupts, quits, and terminal stops. Clean up and exit * if a hangup or termination is received. Also catch changes in * child status (so that we can wait for them). Set up the terminal * modes. */ (void)signal(SIGHUP, done); (void)signal(SIGINT, SIG_IGN); (void)signal(SIGQUIT, SIG_IGN); (void)signal(SIGTERM, done); (void)signal(SIGTSTP, SIG_IGN); (void)signal(SIGCHLD, cwait); tmode(1); /* * Tell the Macintosh to initialize. Initialize the current input * and output windows to NULL. */ xmitcmd(CB_FN_MAINT|CB_MF_ENTRY); curwin[W_IN] = curwin[W_OUT] = NULL; /* * Initialize the "select" masks, create window 1 (to start * things off) and wait for input. When input is available, * process it. */ selmask[0].sm_rd = (1<<0)|(1<<sd); selmask[0].sm_wt = 0; selmask[0].sm_ex = selmask[0].sm_rd | 2; if (newwind(window) == 0) xmitcmd(CB_FN_NEWW|1); while (1) { selmask[1] = selmask[0]; if (select(NFDS, &selmask[1].sm_rd, &selmask[1].sm_wt, &selmask[1].sm_ex, (struct timeval *)0) < 0) { if (errno == EINTR) continue; perror("select"); done(1); /* for now -- fix this! */ } for (fd=0; fd < NFDS; selmask[1].sm_rd >>= 1, fd++) { if (selmask[1].sm_rd&(1<<0)) { if (fd < 2) mrecv(); else if (fd == sd) netrecv(sd); else mxmit(fd); } } } } mrecv() { register int len; register char *cp, *cq; auto int nready; char ibuf[512], obuf[512]; static int seen_iac, seen_meta; /* * The received bytestream is examined. Non-command bytes are * written to the file descriptor corresponding to the current * "input" window (relative to the Macintosh -- the window the * user types input to). */ if (ioctl(0, (int)FIONREAD, (char *)&nready) < 0) { perror("FIONREAD"); return; } cq = obuf; while (nready > 0) { if (nready > sizeof ibuf) len = read(0, ibuf, sizeof ibuf); else len = read(0, ibuf, nready); if (len <= 0) { perror("read"); return; } for (cp=ibuf; cp < ibuf+len; cp++) { if (seen_iac) { if ((*cp&CB_DIR) == CB_DIR_MTOH) { if (cq > obuf) { (void)write(curwin[W_IN]->w_fd, obuf, cq-obuf); cq = obuf; } switch (*cq = recvcmd(*cp)) { case RCV_OK: break; case RCV_META: seen_meta = 1; break; default: if (seen_meta) { seen_meta = 0; *cq |= META; } if (curwin[W_IN]) cq++; break; } } seen_iac = 0; } else if (*cp == IAC) seen_iac++; else if (curwin[W_IN]) { if (seen_meta) { seen_meta = 0; *cq++ = *cp|META; } else *cq++ = *cp; if (cq >= obuf+sizeof obuf) { (void)write(curwin[W_IN]->w_fd, obuf, cq-obuf); cq = obuf; } } } nready -= len; } if (cq > obuf) (void)write(curwin[W_IN]->w_fd, obuf, cq-obuf); } recvcmd(cmd) char cmd; { register int nwin, fn; register struct window *w; /* * Perform the function the Mac is asking for. There are three * broad categories of these functions: RCV_META, which tells * the caller that the next character is a "meta" character; * an ASCII data character, which is passed back to the caller * for proper handling; and RCV_OK, which means that this routine * has done everything which was required to process the command. */ fn = cmd&CB_FN; switch (fn) { case CB_FN_NEWW: case CB_FN_KILLW: case CB_FN_ISELW: nwin = cmd&CB_WINDOW; if (!nwin) break; w = &window[nwin-1]; switch (fn) { case CB_FN_NEWW: if (w->w_fd < 0 && newwind(w) < 0) xmitcmd(CB_FN_KILLW|nwin); break; case CB_FN_KILLW: killwind(w, 0); break; case CB_FN_ISELW: if (w->w_fd >= 0) curwin[W_IN] = w; break; } break; case CB_FN_META: return(RCV_META); case CB_FN_CTLCH: return(ctlch[cmd&CB_CC]); case CB_FN_MAINT: if ((cmd&CB_MF) == CB_MF_EXIT) done(0); /*NOTREACHED*/ } return(RCV_OK); } xmitcmd(cmd) char cmd; { static char cmdbuf[2] = { IAC, '\0' }; /* * Transmit the command "cmd" to the Macintosh. The byte is ORed * with the host-to-Mac direction indicator. */ cmdbuf[1] = cmd|CB_DIR_HTOM; (void)write(1, cmdbuf, sizeof cmdbuf); } netrecv(sd) register fildes_t sd; { register struct window *w; register int cnt; struct msghdr msg; auto int fd; struct iovec iov; struct stat st1, st2; static int unity = 1; char buf[256]; /* * main() calls this routine when there is a message waiting on * the UNIX-domain socket. The message's access rights are * expected to contain the file descriptor for the "master" side * of a pseudo-tty. The message contains the name of the pty. * The sender is expected to start up a process on the slave side * of the pty. This allows the host end to create windows which * run something other than the shell. */ fd = -1; iov.iov_base = (caddr_t)buf; iov.iov_len = sizeof buf - 1; msg.msg_name = (caddr_t)0; msg.msg_namelen = 0; msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_accrights = (caddr_t)&fd; msg.msg_accrightslen = sizeof fd; if ((cnt=recvmsg(sd, &msg, 0)) < 0) perror("recvmsg"); if (msg.msg_accrightslen > 0 && fd >= 0) { /* * We can't trust the process which connected to us, so * we verify that it really passed us a pseudo-tty's * file descriptor by checking the device name and its * inode number. [Of course, if someone else wants to * hand us a terminal session running under their uid....] */ buf[cnt] = 0; if (strncmp(buf, "/dev/ptyp", sizeof "/dev/ptyp" - 1) || fstat(fd, &st1) < 0 || stat(buf, &st2) < 0 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino) { (void)close(fd); return; } /* * OK, we believe the sender. We allocate a window and * tell the Macintosh to create that window on its end. */ buf[5] = 't'; /* switch to "/dev/ttyp?" */ for (w=window; w < window+NWINDOW; w++) { if (w->w_fd < 0) { w->w_fd = fd; fdmap[fd] = w; selmask[0].sm_rd |= (1<<fd); (void)strncpy(w->w_tty, buf, sizeof w->w_tty-1); xmitcmd(CB_FN_NEWW|(w-window+1)); break; } } /* * If we have no free windows, then we close the file * descriptor (which will terminate the slave process). */ if (w == window+NWINDOW) (void)close(fd); /* * Set non-blocking I/O on the master side. */ (void)ioctl(fd, FIONBIO, &unity); } } mxmit(fd) register fildes_t fd; { register char *cp, *cq, i; register int len; char ibuf[32], obuf[32]; /* * Copy input from file "fd" to the Macintosh. Be sure to convert * any embedded IAC characters. * * Note that the input/output buffers should NOT be very large. * It is undesirable to perform large reads and effectively * "lock out" all other file descriptors. The chosen size * should preserve a reasonable amount of efficiency. */ if (fdmap[fd]) { curwin[W_OUT] = fdmap[fd]; xmitcmd(CB_FN_OSELW|(fdmap[fd]-window+1)); cq = obuf; if ((len = read(fd, ibuf, sizeof ibuf)) < 0 && errno != EWOULDBLOCK) { killwind(fdmap[fd], 1); return; } for (cp=ibuf; cp < ibuf+len; cp++) { if (*cp&META) { if (cq > obuf) { (void)write(1, obuf, cq-obuf); cq = obuf; } xmitcmd(CB_FN_META); *cp &= ~META; } i = -1; if (*cp == RUB || *cp < ' ') { i = sizeof ctlch; while (i >= 0 && ctlch[i] != *cp) i--; } if (i >= 0) { if (cq > obuf) { (void)write(1, obuf, cq-obuf); cq = obuf; } xmitcmd(CB_FN_CTLCH|i); } else { *cq++ = *cp; if (cq >= obuf+sizeof obuf) { (void)write(1, obuf, cq-obuf); cq = obuf; } } } } else (void)read(fd, ibuf, sizeof ibuf); if (cq > obuf) (void)write(1, obuf, cq-obuf); } killwind(w, notify) register struct window *w; { register int mask; /* * Kill window "w". Notify the Macintosh that it is gone if * "notify" is nonzero. */ (void)close(w->w_fd); mask = ~(1<<w->w_fd); fdmap[w->w_fd] = NULL; w->w_fd = -1; if (curwin[W_IN] == w) curwin[W_IN] = NULL; if (curwin[W_OUT] == w) curwin[W_OUT] = NULL; selmask[0].sm_rd &= mask; selmask[0].sm_wt &= mask; selmask[0].sm_ex &= mask; if (notify) xmitcmd(CB_FN_KILLW|(w-window+1)); } newwind(w) register struct window *w; { register char *cp; register fildes_t fd; register int pid; register char *shell; char pty[32], ptysufx[2]; static char ptyidx[] = "0123456789abcdefghijklmnopqrstuvwxyz"; static int unity = 1; extern char *getenv(); /* * Create a new window using the specified component of "window". * This routine isn't very smart at finding pseudo-ttys. */ ptysufx[1] = '\0'; for (cp=ptyidx; *cp; cp++) { ptysufx[0] = *cp; (void)strncpy(pty, "/dev/ptyp", sizeof pty-1); (void)strncat(pty, ptysufx, sizeof pty-1); if ((fd = open(pty, 2)) >= 0) break; } if (fd < 0) return(-1); (void)ioctl(fd, FIONBIO, &unity); /* set non-blocking I/O */ fdmap[fd] = w; w->w_fd = fd; selmask[0].sm_rd |= (1<<fd); (void)strncpy(w->w_tty, "/dev/ttyp", sizeof w->w_tty-1); (void)strncat(w->w_tty, ptysufx, sizeof w->w_tty-1); while ((pid=fork()) < 0) sleep(5); if (!pid) { (void)signal(SIGHUP, SIG_DFL); (void)signal(SIGINT, SIG_DFL); (void)signal(SIGQUIT, SIG_DFL); (void)signal(SIGTERM, SIG_DFL); (void)signal(SIGTSTP, SIG_IGN); (void)signal(SIGCHLD, SIG_DFL); (void)ioctl(open("/dev/tty", 2), (int)TIOCNOTTY, (char *)0); (void)setuid(getuid()); /* shouldn't need this */ if ((fd=open(w->w_tty, 2)) < 0) _exit(1); if (!(shell = getenv("SHELL"))) shell = "/bin/sh"; (void)dup2(fd, 0); (void)dup2(0, 1); (void)dup2(0, 2); for (fd=3; fd < NFDS; fd++) (void)close(fd); tmode(0); /* HACK! */ execl(shell, shell, (char *)0); _exit(1); } return(0); } tmode(f) { static struct sgttyb ostty, nstty; static struct tchars otchars, ntchars; static struct ltchars oltchars, nltchars; static int olmode, nlmode; static saved; /* * This routine either saves the current terminal modes and then * sets up the terminal line or resets the terminal modes (depending * upon the value of "f"). The terminal line is used in "cbreak" * mode with all special characters except XON/XOFF disabled. The * hated (by me) LDECCTQ mode is required for the Macintosh to * handle flow control properly. */ if (f == 1) { if (ioctl(0, (int)TIOCGETP, (char *)&ostty) < 0) { perror("ioctl((int)TIOCGETP)"); done(1); } if (ioctl(0, (int)TIOCGETC, (char *)&otchars) < 0) { perror("ioctl((int)TIOCGETC)"); done(1); } if (ioctl(0, (int)TIOCGLTC, (char *)&oltchars) < 0) { perror("ioctl((int)TIOCGLTC)"); done(1); } if (ioctl(0, (int)TIOCLGET, (char *)&olmode) < 0) { perror("ioctl((int)TIOCLGET)"); done(1); } nstty = ostty; nstty.sg_erase = nstty.sg_kill = -1; nstty.sg_flags |= CBREAK; nstty.sg_flags &= ~(RAW|CRMOD|ECHO|LCASE|XTABS); ntchars.t_intrc = ntchars.t_quitc = -1; ntchars.t_eofc = ntchars.t_brkc = -1; ntchars.t_startc = XON; ntchars.t_stopc = XOFF; nltchars.t_suspc = nltchars.t_dsuspc = -1; nltchars.t_rprntc = nltchars.t_flushc = -1; nltchars.t_werasc = nltchars.t_lnextc = -1; nlmode = olmode | LDECCTQ; if (ioctl(0, (int)TIOCSETN, (char *)&nstty) < 0) { perror("ioctl((int)TIOCSETN)"); done(1); } if (ioctl(0, (int)TIOCSETC, (char *)&ntchars) < 0) { perror("ioctl((int)TIOCSETC"); done(1); } if (ioctl(0, (int)TIOCSLTC, (char *)&nltchars) < 0) { perror("ioctl((int)TIOCSLTC"); done(1); } if (ioctl(0, (int)TIOCLSET, (char *)&nlmode) < 0) { perror("ioctl((int)TIOCLSET)"); done(1); } saved = 1; } else if (saved) { (void)ioctl(0, (int)TIOCSETP, (char *)&ostty); (void)ioctl(0, (int)TIOCSETC, (char *)&otchars); (void)ioctl(0, (int)TIOCSLTC, (char *)&oltchars); (void)ioctl(0, (int)TIOCLSET, (char *)&olmode); } } done(s) { register struct window *w; register fildes_t fd; /* * Clean up and exit. It is overkill to close all of the file * descriptors, but it causes no harm. After we are sure that * our UNIX-domain network connection is closed we remove the * entry that it created (as a side effect) in the filesystem. * * We also restore the terminal modes. */ /*xmitcmd(CB_FN_MAINT|CB_MF_EXIT);*/ for (fd=3; fd < NFDS; fd++) (void)close(fd); (void)unlink(portal); tmode(0); exit(s); } cwait() { union wait status; struct rusage rusage; /* * Collect dead children. We don't use the information that * wait3() returns. (Someday we might.) */ while (wait3(&status, WNOHANG, &rusage) > 0) ; } static char *earray[MAXENV+1]; setenv(env) char **env; { register char **ep1, **ep2, *cp; char **ep3; extern char **environ; /* * Merge the set of environment strings in "env" into the * environment. */ /* * The first time through, copy the environment from its * original location to the array "earray". This makes it a * little easier to change things. */ if (environ != earray){ ep1=environ; ep2=earray; while(*ep1 && ep2 <= earray+MAXENV) *ep2++ = *ep1++; *ep2++ = NULL; environ = earray; } /* * If "env" is non-NULL, it points to a list of new items to * be added to the environment. These replace existing items * with the same name. */ if (env){ for(ep1=env; *ep1; ep1++){ for(ep2=environ; *ep2; ep2++) if (!envcmp(*ep1, *ep2)) break; if (ep2 < earray+MAXENV) { if (!*ep2) ep2[1] = NULL; *ep2 = *ep1; } } } /* Finally, use an insertion sort to put things in order. */ for(ep1=environ+1; cp = *ep1; ep1++){ for(ep2=environ; ep2 < ep1; ep2++) if (envcmp(*ep1, *ep2) < 0) break; ep3 = ep2; for(ep2=ep1; ep2 > ep3; ep2--) ep2[0] = ep2[-1]; *ep2 = cp; } } static envcmp(e1, e2) register char *e1, *e2; { register d; do { if (d = *e1 - *e2++) return(d); } while(*e1 && *e1++ != '='); return(0); } !Funky!Stuff! echo x - uwtool.old.c cat > uwtool.old.c << '!Funky!Stuff!' # /* * uwtool * * Copyright 1985 by John D. Bruner. All rights reserved. Permission to * copy this program is given provided that the copy is not sold and that * this copyright notice is included. * * Compile: cc -o uwtool -O uwtool.c */ #include <sys/types.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <sys/wait.h> #include <sys/time.h> #include <sys/resource.h> #include <sys/uio.h> #include <signal.h> #include <stdio.h> #define NFDS 20 /* max number of file descriptors */ typedef int fildes_t; extern char *strncpy(), *strncat(); extern char *getenv(); main(argc, argv) char **argv; { register char *cp; register int pid; register fildes_t sd; auto fildes_t fd; char *portal, *shell; char tty[32], pty[32], ptysufx[2]; int lmode; struct sgttyb sg; struct tchars tc; struct ltchars ltc; struct iovec iov; struct msghdr msg; static char ptyidx[] = "0123456789abcdefghijklmnopqrstuvwxyz"; struct sockaddr sa; /* * Close all file descriptors except 0, 1, and 2. */ for (fd=3; fd < NFDS; fd++) (void)close(fd); /* * Get the terminal configuration for this tty. */ (void)ioctl(0, (int)TIOCGETP, (char *)&sg); (void)ioctl(0, (int)TIOCGETC, (char *)&tc); (void)ioctl(0, (int)TIOCGLTC, (char *)<c); (void)ioctl(0, (int)TIOCLGET, (char *)&lmode); /* * Create a UNIX-domain socket. */ if (!(portal=getenv("UWIN"))) { fprintf(stderr, "You must run %s under the window manager\n", *argv); exit(1); } if ((sd=socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) { perror("socket"); exit(1); } sa.sa_family = AF_UNIX; (void)strncpy(sa.sa_data, portal, sizeof sa.sa_data-1); sa.sa_data[sizeof sa.sa_data-1] = '\0'; /* * Obtain a pseudo-tty. This code isn't very smart about finding one. */ ptysufx[1] = '\0'; for (cp=ptyidx; *cp; cp++) { ptysufx[0] = *cp; (void)strncpy(pty, "/dev/ptyp", sizeof pty-1); (void)strncat(pty, ptysufx, sizeof pty-1); if ((fd = open(pty, 2)) >= 0) break; } if (fd < 0) { fprintf(stderr, "Can't obtain a pseudo-tty for a new window\n"); exit(1); } (void)strncpy(tty, "/dev/ttyp", sizeof tty-1); (void)strncat(tty, ptysufx, sizeof tty-1); /* * Fork a child process using this pseudo-tty. Initialize the * terminal modes on the pseudo-tty to match those of the parent * tty. */ while ((pid=fork()) < 0) sleep(5); if (!pid) { setuid(getuid()); /* in case it is setuid-root by mistake */ (void)signal(SIGTSTP, SIG_IGN); (void)ioctl(open("/dev/tty", 2), (int)TIOCNOTTY, (char *)0); if ((fd=open(tty, 2)) < 0) _exit(1); (void)dup2(fd, 0); (void)dup2(0, 1); (void)dup2(0, 2); for (fd=3; fd < NFDS; fd++) (void)close(fd); (void)ioctl(0, (int)TIOCSETN, (char *)&sg); (void)ioctl(0, (int)TIOCSETC, (char *)&tc); (void)ioctl(0, (int)TIOCSLTC, (char *)<c); (void)ioctl(0, (int)TIOCLSET, (char *)&lmode); if (argc == 1) { if (!(shell=getenv("SHELL"))) shell = "/bin/sh"; execl(shell, shell, (char *)0); perror(shell); } else { execvp(argv[1], argv+1); perror(argv[1]); } _exit(1); } /* * Pass the file descriptor to the window server and exit. */ iov.iov_base = pty; iov.iov_len = strlen(pty); msg.msg_name = (caddr_t)&sa; msg.msg_namelen = sizeof sa.sa_family + strlen(sa.sa_data); msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_accrights = (caddr_t)&fd; msg.msg_accrightslen = sizeof fd; if (sendmsg(sd, &msg, 0) < 0) { perror("sendmsg"); exit(1); } exit(0); } !Funky!Stuff! echo x - foo cat > foo << '!Funky!Stuff!' Here are fixes to my original version of "uw.c" from mcvax!guido. (Unfortunately, I lost the article he posted to "net.sources.mac" so I can't provide a reference ID.) -------------------------------------------------------------------------- *** uw.c.orig Sun Jul 21 18:11:31 1985 --- uw.c Sun Jul 28 22:04:48 1985 *************** *** 387,393 * hand us a terminal session running under their uid....] */ buf[cnt] = 0; ! if (strncmp(buf, "/dev/ptyp", sizeof "/dev/ptyp" - 1) || fstat(fd, &st1) < 0 || stat(buf, &st2) < 0 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino) { (void)close(fd); --- 387,393 ----- * hand us a terminal session running under their uid....] */ buf[cnt] = 0; ! if (strncmp(buf, "/dev/pty", sizeof "/dev/pty" - 1) || fstat(fd, &st1) < 0 || stat(buf, &st2) < 0 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino) { (void)close(fd); *************** *** 510,517 newwind(w) register struct window *w; { ! register char *cp; ! register fildes_t fd; register int pid; register char *shell; char pty[32], ptysufx[2]; --- 510,517 ----- newwind(w) register struct window *w; { ! register char *cpmajor, *cp; ! register fildes_t fd, fd2; register int pid; register char *shell; char pty[32], ptysufx[3]; *************** *** 514,520 register fildes_t fd; register int pid; register char *shell; ! char pty[32], ptysufx[2]; static char ptyidx[] = "0123456789abcdefghijklmnopqrstuvwxyz"; static int unity = 1; extern char *getenv(); --- 514,521 ----- register fildes_t fd, fd2; register int pid; register char *shell; ! char pty[32], ptysufx[3]; ! static char ptyidmajor[] = "pqrs"; static char ptyidx[] = "0123456789abcdefghijklmnopqrstuvwxyz"; static int unity = 1; extern char *getenv(); *************** *** 521,527 /* * Create a new window using the specified component of "window". ! * This routine isn't very smart at finding pseudo-ttys. */ ptysufx[1] = '\0'; --- 522,534 ----- /* * Create a new window using the specified component of "window". ! * This routine tries to be smart at finding pseudo-ttys: ! * it tries all of /dev/pty[p-s][0-9a-z] until it finds one ! * that can be opened AND whose slave end can be opened. ! * (The latter is necessary because we often suffer from pty's ! * whose slave end is still busy while the master has been ! * closed; the slave ends are usually open exclusively ! * so another open would fail.) */ ptysufx[2] = '\0'; *************** *** 524,533 * This routine isn't very smart at finding pseudo-ttys. */ ! ptysufx[1] = '\0'; ! for (cp=ptyidx; *cp; cp++) { ! ptysufx[0] = *cp; ! (void)strncpy(pty, "/dev/ptyp", sizeof pty-1); (void)strncat(pty, ptysufx, sizeof pty-1); if ((fd = open(pty, 2)) >= 0) break; --- 531,542 ----- * so another open would fail.) */ ! ptysufx[2] = '\0'; ! for (cpmajor=ptyidmajor; *cpmajor; ++cpmajor) { ! ptysufx[0]= *cpmajor; ! for (cp=ptyidx; *cp; cp++) { ! ptysufx[1] = *cp; ! (void)strncpy(pty, "/dev/pty", sizeof pty-1); (void)strncat(pty, ptysufx, sizeof pty-1); if ((fd = open(pty, 2)) >= 0) { /* Now check slave end. */ *************** *** 529,535 ptysufx[0] = *cp; (void)strncpy(pty, "/dev/ptyp", sizeof pty-1); (void)strncat(pty, ptysufx, sizeof pty-1); ! if ((fd = open(pty, 2)) >= 0) break; } if (fd < 0) --- 538,560 ----- ptysufx[1] = *cp; (void)strncpy(pty, "/dev/pty", sizeof pty-1); (void)strncat(pty, ptysufx, sizeof pty-1); ! if ((fd = open(pty, 2)) >= 0) { ! /* Now check slave end. */ ! (void)strncpy(w->w_tty, "/dev/tty", sizeof w->w_tty-1); ! (void)strncat(w->w_tty, ptysufx, sizeof w->w_tty-1); ! if ((fd2 = open(w->w_tty, 2)) < 0) { ! close(fd); ! continue; /* Bad luck, try another. */ ! } ! goto found_one; ! } ! /* ! * If a file really isn't there, don't check the rest of ! * this major series. This avoids trying to open 48 ! * nonexistent pty's when the system is configured with ! * only 16 instead of the expected 64. ! */ ! if (errno == ENOENT) break; } } *************** *** 531,536 (void)strncat(pty, ptysufx, sizeof pty-1); if ((fd = open(pty, 2)) >= 0) break; } if (fd < 0) return(-1); --- 556,562 ----- */ if (errno == ENOENT) break; + } } return(-1); *************** *** 532,539 if ((fd = open(pty, 2)) >= 0) break; } ! if (fd < 0) ! return(-1); (void)ioctl(fd, FIONBIO, &unity); /* set non-blocking I/O */ fdmap[fd] = w; w->w_fd = fd; --- 558,566 ----- break; } } ! return(-1); ! ! found_one: (void)ioctl(fd, FIONBIO, &unity); /* set non-blocking I/O */ fdmap[fd] = w; w->w_fd = fd; *************** *** 538,545 fdmap[fd] = w; w->w_fd = fd; selmask[0].sm_rd |= (1<<fd); - (void)strncpy(w->w_tty, "/dev/ttyp", sizeof w->w_tty-1); - (void)strncat(w->w_tty, ptysufx, sizeof w->w_tty-1); while ((pid=fork()) < 0) sleep(5); --- 565,570 ----- fdmap[fd] = w; w->w_fd = fd; selmask[0].sm_rd |= (1<<fd); while ((pid=vfork()) < 0) sleep(5); *************** *** 541,547 (void)strncpy(w->w_tty, "/dev/ttyp", sizeof w->w_tty-1); (void)strncat(w->w_tty, ptysufx, sizeof w->w_tty-1); ! while ((pid=fork()) < 0) sleep(5); if (!pid) { (void)signal(SIGHUP, SIG_DFL); --- 566,572 ----- w->w_fd = fd; selmask[0].sm_rd |= (1<<fd); ! while ((pid=vfork()) < 0) sleep(5); if (!pid) { (void)signal(SIGHUP, SIG_DFL); *************** *** 552,559 (void)signal(SIGCHLD, SIG_DFL); (void)ioctl(open("/dev/tty", 2), (int)TIOCNOTTY, (char *)0); (void)setuid(getuid()); /* shouldn't need this */ - if ((fd=open(w->w_tty, 2)) < 0) - _exit(1); if (!(shell = getenv("SHELL"))) shell = "/bin/sh"; (void)dup2(fd, 0); --- 577,582 ----- (void)signal(SIGCHLD, SIG_DFL); (void)ioctl(open("/dev/tty", 2), (int)TIOCNOTTY, (char *)0); (void)setuid(getuid()); /* shouldn't need this */ if (!(shell = getenv("SHELL"))) shell = "/bin/sh"; (void)dup2(fd2, 0); *************** *** 556,562 _exit(1); if (!(shell = getenv("SHELL"))) shell = "/bin/sh"; ! (void)dup2(fd, 0); (void)dup2(0, 1); (void)dup2(0, 2); for (fd=3; fd < NFDS; fd++) --- 579,585 ----- (void)setuid(getuid()); /* shouldn't need this */ if (!(shell = getenv("SHELL"))) shell = "/bin/sh"; ! (void)dup2(fd2, 0); (void)dup2(0, 1); (void)dup2(0, 2); for (fd=3; fd < NFDS; fd++) *************** *** 566,571 _exit(1); } return(0); } --- 589,595 ----- _exit(1); } + close(fd2); return(0); } !Funky!Stuff! exit 0 : end of shell archive -- John Bruner (S-1 Project, Lawrence Livermore National Laboratory) MILNET: jdb@mordor [jdb@s1-c.ARPA] (415) 422-0758 UUCP: ...!ucbvax!dual!mordor!jdb ...!seismo!mordor!jdb