home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 January
/
usenetsourcesnewsgroupsinfomagicjanuary1994.iso
/
sources
/
misc
/
volume28
/
screen-3.2
/
part06
< prev
next >
Wrap
Text File
|
1992-02-09
|
57KB
|
2,517 lines
Newsgroups: comp.sources.misc
From: jnweiger@immd4.informatik.uni-erlangen.de (Juergen Weigert)
Subject: v28i023: screen-3.2 - multiple windows on an ASCII terminal, v3.2, Part06/11
Message-ID: <1992Feb9.223654.6728@sparky.imd.sterling.com>
X-Md4-Signature: b9ad9b52526f30cb86ba88c5eb712017
Date: Sun, 9 Feb 1992 22:36:54 GMT
Approved: kent@sparky.imd.sterling.com
Submitted-by: jnweiger@immd4.informatik.uni-erlangen.de (Juergen Weigert)
Posting-number: Volume 28, Issue 23
Archive-name: screen-3.2/part06
Environment: UNIX
#!/bin/sh
# do not concatenate these parts, unpack them in order with /bin/sh
# file screen3.2/screen.c continued
#
if test ! -r _shar_seq_.tmp; then
echo 'Please unpack part 1 first!'
exit 1
fi
(read Scheck
if test "$Scheck" != 6; then
echo Please unpack part "$Scheck" next!
exit 1
else
exit 0
fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping screen3.2/screen.c'
else
echo 'x - continuing file screen3.2/screen.c'
sed 's/^X//' << 'SHAR_EOF' >> 'screen3.2/screen.c' &&
X switch (ap[2])
X {
X case 'n':
X case '0':
X default_flow = FLOW_NOW * 0;
X break;
X case 'y':
X case '1':
X case '\0':
X default_flow = FLOW_NOW * 1;
X break;
X case 'a':
X default_flow = FLOW_AUTOFLAG;
X break;
X default:
X exit_with_usage(myname);
X }
X break;
X case 'h':
X if (ap[2])
X default_histheight = atoi(ap + 2);
X else
X {
X if (--ac == 0)
X exit_with_usage(myname);
X default_histheight = atoi(*++av);
X }
X if (default_histheight < 0)
X default_histheight = 0;
X break;
X case 'i':
X iflag = 1;
X break;
X case 't': /* title is a synonym for AkA */
X case 'k':
X if (ap[2])
X aka = ap + 2;
X else
X {
X if (--ac == 0)
X exit_with_usage(myname);
X aka = *++av;
X }
X break;
X case 'l':
X switch (ap[2])
X {
X case 'n':
X case '0':
X loginflag = 0;
X break;
X case 'y':
X case '1':
X case '\0':
X loginflag = 1;
X break;
X case 's':
X case 'i':
X lsflag = 1;
X break;
X default:
X exit_with_usage(myname);
X }
X break;
X case 'w':
X lsflag = 1;
X wipeflag = 1;
X break;
X case 'L':
X assume_LP = 1;
X break;
X case 'm':
X mflag = 1;
X break;
X case 'O':
X force_vt = 0;
X break;
X case 'T':
X if (ap[2])
X {
X if (strlen(ap+2) < 20)
X strcpy(screenterm, ap + 2);
X }
X else
X {
X if (--ac == 0)
X exit_with_usage(myname);
X if (strlen(*++av) < 20)
X strcpy(screenterm, *av);
X }
X break;
X case 'q':
X quietflag = 1;
X break;
X case 'r':
X case 'R':
X if (ap[2])
X {
X SockName = ap + 2;
X if (ac != 1)
X exit_with_usage(myname);
X }
X else if (ac > 1 && *av[1] != '-')
X {
X SockName = *++av;
X ac--;
X }
X rflag = (ap[1] == 'r') ? 1 : 2;
X break;
#ifdef REMOTE_DETACH
X case 'd':
X dflag = 1;
X /* FALLTHRU */
X case 'D':
X if (!dflag)
X dflag = 2;
X if (ap[2])
X SockName = ap + 2;
X if (ac == 2)
X {
X if (*av[1] != '-')
X {
X SockName = *++av;
X ac--;
X }
X }
X break;
#endif
X case 's':
X if (ap[2])
X ShellProg = ap + 2;
X else
X {
X if (--ac == 0)
X exit_with_usage(myname);
X ShellProg = *++av;
X }
X break;
X default:
X exit_with_usage(myname);
X }
X }
X else
X break;
X }
X real_uid = getuid();
X real_gid = getgid();
X eff_uid = geteuid();
X eff_gid = getegid();
X if (eff_uid != real_uid)
X {
X /* if running with s-bit, we must install a special signal
X * handler routine that resets the s-bit, so that we get a
X * core file anyway.
X */
X signal(SIGBUS, CoreDump);
X signal(SIGSEGV, CoreDump);
X }
X if (!ShellProg && (ShellProg = getenv("SHELL")) == 0)
X ShellProg = DefaultShell;
X ShellArgs[0] = ShellProg;
#ifdef NETHACK
X nethackflag = (getenv("NETHACKOPTIONS") != NULL);
#endif
X home = getenv("HOME"); /* may or may not return a result. jw. */
X if ((LoginName = getlogin()) && LoginName[0] != '\0')
X {
X if ((ppp = getpwnam(LoginName)) != (struct passwd *) 0)
X if (ppp->pw_uid != real_uid)
X ppp = (struct passwd *) 0;
X }
X if (ppp == 0)
X {
X if ((ppp = getpwuid(real_uid)) == 0)
X {
#ifdef NETHACK
X if (nethackflag)
X Msg(0, "An alarm sounds through the dungeon...\nWarning, the kops are coming.");
X else
#endif
X Msg(0, "getpwuid() can't identify your account!");
X exit(1);
X }
X LoginName = ppp->pw_name;
X }
X if (home == 0 || *home == '\0')
X home = ppp->pw_dir;
X if (strlen(LoginName) > 20)
X Msg(0, "LoginName too long - sorry.");
X if (strlen(home) > MAXPATH - 25)
X Msg(0, "$HOME too long - sorry.");
#ifdef PASSWORD
X strcpy(Password, ppp->pw_passwd);
#endif
X
X /* ttyname implies isatty */
X if (!(attach_tty = ttyname(0)))
X {
#ifdef NETHACK
X if (nethackflag)
X Msg(0, "You must play from a terminal.");
X else
#endif
X Msg(0, "Must be connected to a terminal.");
X exit(1);
X }
X if (strlen(attach_tty) >= MAXPATH)
X Msg(0, "TtyName too long - sorry.");
X if ((n = secopen(attach_tty, O_RDWR, 0)) < 0)
X Msg(0, "Cannot open '%s' - please check.", attach_tty);
X close(n);
X
X debug1("attach_tty is %s\n", attach_tty);
X
#ifdef _MODE_T
X oumask = umask(0); /* well, unsigned never fails? jw. */
#else
X if ((oumask = umask(0)) == -1)
X Msg(errno, "Cannot change umask to zero");
#endif
X if ((SockDir = getenv("ISCREENDIR")) == NULL)
X SockDir = getenv("SCREENDIR");
X if (SockDir && strlen(SockDir) >= MAXPATH - 1)
X Msg(0, "ridiculous long $(I)SCREENDIR - try again.");
#ifndef SOCKDIR
X if (SockDir == 0)
X {
X sprintf(SockPath, "%s/.iscreen", home);
X SockDir = SockPath;
X }
#endif
X if (SockDir)
X {
X if (access(SockDir, F_OK))
X {
X if (UserContext() > 0)
X {
X if (mkdir(SockDir, 0700))
X UserReturn(0);
X UserReturn(1);
X }
X if (UserStatus() <= 0)
X Msg(0, "Cannot make directory '%s'", SockDir);
X }
X if (SockDir != SockPath)
X strcpy(SockPath, SockDir);
X }
#ifdef SOCKDIR
X else
X {
X SockDir = SOCKDIR;
X if (stat(SockDir, &st))
X {
X if (mkdir(SockDir, eff_uid ? 0777 : 0755) == -1)
X Msg(errno, "Cannot make directory '%s'", SockDir);
X }
X else
X {
X n = eff_uid ? 0777 : 0755;
X if ((st.st_mode & 0777) != n)
X Msg(0, "Directory '%s' must have mode %03o.", SockDir, n);
X }
X sprintf(SockPath, "%s/S-%s", SockDir, LoginName);
X if (access(SockPath, F_OK))
X {
X if (mkdir(SockPath, 0700) == -1)
X Msg(errno, "Cannot make directory '%s'", SockPath);
X (void) chown(SockPath, real_uid, real_gid);
X }
X }
#endif
X if (stat(SockPath, &st) == -1)
X {
X Msg(errno, "Cannot access %s", SockPath);
X }
X else
X {
#ifdef _POSIX_SOURCE
X if (S_ISDIR(st.st_mode) == 0)
#else
X if ((st.st_mode & S_IFMT) != S_IFDIR)
#endif
X Msg(0, "%s is not a directory.", SockPath);
X if (st.st_uid != real_uid)
X Msg(0, "You are not the owner of %s.", SockPath);
X if ((st.st_mode & 0777) != 0700)
X Msg(0, "Directory %s must have mode 700.", SockPath);
X }
X strcat(SockPath, "/");
X SockNamePtr = SockPath + strlen(SockPath);
X (void) umask(oumask);
#if defined(SYSV) && !defined(ISC)
X if (uname(&utsnam) == -1)
X Msg(0, "uname() failed, errno = %d", errno);
X else
X {
X strncpy(HostName, utsnam.nodename, MAXSTR);
X HostName[(sizeof(utsnam.nodename) <= MAXSTR) ?
X sizeof(utsnam.nodename) : MAXSTR] = '\0';
X }
#else
X (void) gethostname(HostName, MAXSTR);
#endif
X HostName[MAXSTR - 1] = '\0';
X if ((ap = index(HostName, '.')) != NULL)
X *ap = '\0';
X GetTTY(0, &OldMode);
#ifdef POSIX
X ospeed = (short) cfgetospeed(&OldMode.tio);
#else
# ifndef TERMIO
X ospeed = (short) OldMode.m_ttyb.sg_ospeed;
# endif
#endif
X debug1("...setting extern short ospeed = %d\n", ospeed);
X
X if (lsflag)
X {
X int i;
X i = FindSocket(0, (int *)NULL);
X /* MakeClientSocket appended the last (Sock)Name there: */
X *SockNamePtr = '\0';
X if (i == 0)
X {
#ifdef NETHACK
X if (nethackflag)
X Msg(0, "This room is empty (%s)\n", SockPath);
X else
#endif /* NETHACK */
X Msg(0, "No Sockets found in %s\n", SockPath);
X }
X else
X Msg(0, "%d Socket%s in %s.\n", i, i > 1 ? "s" : "", SockPath);
X /* NOTREACHED */
X }
X if (rflag)
X {
X debug("screen -r: - is there anybody out there?\n");
#ifdef SHADOWPW
X setspent(); /* open shadow file while we are still root */
#endif /* SHADOWPW */
X if (Attach(MSG_ATTACH))
X {
X Attacher();
X /* NOTREACHED */
X }
X debug("screen -r: backend not responding -- still crying\n");
X }
X else if (dflag)
X {
X (void) Attach(MSG_DETACH);
X DeadlyMsg = 0;
X Msg(0, "[%s %sdetached.]\n", SockName, (dflag > 1 ? "power " : ""));
X eexit(0);
X /* NOTREACHED */
X }
X if (!mflag && (SockName = getenv("STY")) != 0 && *SockName != '\0')
X {
X setuid(real_uid);
X setgid(real_gid);
X s = MakeClientSocket(1, SockName);
X if (ac == 0)
X {
X ac = 1;
X av = ShellArgs;
X }
X av[ac] = aka;
X SendCreateMsg(s, ac, av, allflag, default_flow, loginflag, default_histheight,
X screenterm);
X close(s);
X exit(0);
X }
#if defined(BSDJOBS) && !(defined(POSIX) || defined(SYSV))
X if ((DevTty = open("/dev/tty", O_RDWR | O_NDELAY)) == -1)
X Msg(errno, "/dev/tty");
#endif
X switch (MasterPid = fork())
X {
X case -1:
X Msg(errno, "fork");
X /* NOTREACHED */
X case 0:
X break;
X default:
X sprintf(socknamebuf, "%d.%s.%s", MasterPid, stripdev(attach_tty),
X HostName);
X for (ap = socknamebuf; *ap; ap++)
X if (*ap == '/')
X *ap = '-';
X SockName = socknamebuf;
#ifdef SHADOWPW
X setspent(); /* open shadow file while we are still root */
#endif /* SHADOWPW */
X Attacher();
X /* NOTREACHED */
X }
#ifdef DEBUG
X if (dfp != stderr)
X fclose(dfp);
X if ((dfp = fopen("/tmp/debug/screen.back", "w")) == NULL)
X dfp = stderr;
X else
X (void) chmod("/tmp/debug/screen.back", 0666);
#endif
X debug("-- screen.back debug started\n");
X ap = av0 + strlen(av0) - 1;
X while (ap >= av0)
X {
X if (!strncmp("screen", ap, 6))
X {
X strncpy(ap, "SCREEN", 6); /* name this process "SCREEN-BACKEND" */
X break;
X }
X ap--;
X }
X if (ap < av0)
X *av0 = 'S';
X
X AttacherPid = getppid();
X sprintf(socknamebuf, "%d.%s.%s", getpid(), stripdev(attach_tty), HostName);
X for (ap = socknamebuf; *ap; ap++)
X if (*ap == '/')
X *ap = '-';
X SockName = socknamebuf;
X ServerSocket = s = MakeServerSocket();
#ifdef ETCSCREENRC
X if ((ap = getenv("SYSSCREENRC")) == NULL)
X StartRc(ETCSCREENRC);
X else
X StartRc(ap);
#endif
X StartRc(RcFileName);
X InitTermcap();
X InitTerm(0);
X MakeNewEnv();
X strcpy(display_tty, attach_tty);
#ifdef UTMPOK
# ifdef apollo
X ReInitUtmp();
# else
X InitUtmp();
# endif /* apollo */
#endif
#ifdef LOADAV
# ifdef NeXT
X InitNeXTLoadAvg(); /* NeXT load average */
# else
X InitKmem();
# endif /* !NeXT */
#endif /* LOADAV */
X signal(SIGHUP, SigHup);
X signal(SIGINT, Finit);
X signal(SIGQUIT, Finit);
X signal(SIGTERM, Finit);
#ifdef BSDJOBS
X signal(SIGTTIN, SIG_IGN);
X signal(SIGTTOU, SIG_IGN);
#endif
X InitKeytab();
#ifdef ETCSCREENRC
X if ((ap = getenv("SYSSCREENRC")) == NULL)
X FinishRc(ETCSCREENRC);
X else
X FinishRc(ap);
#endif
X FinishRc(RcFileName);
X
X /* Note: SetMode must be called _after_ FinishRc (flow is set there).
X */
X SetMode(&OldMode, &NewMode);
X SetTTY(0, &NewMode);
X if (loginflag == -1)
X loginflag = LOGINDEFAULT;
X if (ac == 0)
X {
X ac = 1;
X av = ShellArgs;
X if (!aka)
X aka = shellaka;
X }
X if (!HasWindow)
X {
X debug("We open one default window, as screenrc did not specify one.\n");
X if (MakeWindow(aka, av, allflag, default_flow, 0, (char *)0, loginflag, -1, (char *)0) == -1)
X {
X Finit(1);
X /* NOTREACHED */
X }
X }
X if (default_startup)
X display_copyright();
#ifdef SYSV
X signal(SIGCLD, SigChld);
#else
X signal(SIGCHLD, SigChld);
#endif
X signal(SIGINT, SigInt);
X tv.tv_usec = 0;
X if (rflag == 2)
X {
#ifdef NETHACK
X if (nethackflag)
X Msg(0, "I can't seem to find a... Hey, wait a minute! Here comes a screen now.");
X else
#endif
X Msg(0, "New screen...");
X rflag = 0;
X }
X brktty();
X for (;;)
X {
X /*
X * check to see if message line should be removed
X */
X if (status)
X {
X int time_left;
X
X debug("checking status...\n");
X time_left = TimeDisplayed + (BellDisplayed ? VBellWait : MsgWait) - time((time_t *)0);
X if (time_left > 0)
X {
X tv.tv_sec = time_left;
X debug(" not yet.\n");
X }
X else
X {
X debug(" removing now.\n");
X RemoveStatus();
X }
X }
X /*
X * check for I/O on all available I/O descriptors
X */
X FD_ZERO(&r);
X FD_ZERO(&w);
X FD_ZERO(&e);
X if (inbuf_ct > 0)
X for (n = 0; n < MAXWIN; n++)
#ifdef COPY_PASTE /* wrong here? jw. */
X if (inlen[n] > 0 || (pastelen > 0 && n == ForeNum))
#else
X if (inlen[n] > 0)
#endif
X FD_SET(wtab[n]->ptyfd, &w);
X if (!Detached)
X FD_SET(0, &r);
X for (n = WinList; n != -1; n = p->WinLink)
X {
X p = wtab[n];
X if (p->active && status && !BellDisplayed && !HS)
X continue;
X if (p->outlen > 0)
X continue;
X if (in_ovl && ovl_blockfore && n == ForeNum)
X continue;
X FD_SET(p->ptyfd, &r);
X }
X FD_SET(s, &r);
X (void) fflush(stdout);
X if (GotSignal && !status)
X {
X SigHandler();
X continue;
X }
X if ((nsel = select(FD_SETSIZE, &r, &w, &e, (status) ? &tv : (struct timeval *) 0)) < 0)
X {
X debug1("Bad select - errno %d\n", errno);
X if (errno != EINTR)
X {
X perror("select");
X Finit(1);
X }
X else
X {
X errno = 0;
X if ((!GotSignal || status) && !InterruptPlease)
X continue;
X }
X }
X if (InterruptPlease)
X {
X char buf[1];
X
X debug("Backend received interrupt\n");
X *buf = intrc;
X write(wtab[ForeNum]->ptyfd, buf, 1);
X debug1("Backend wrote interrupt to %d\n", ForeNum);
X InterruptPlease = 0;
X
X continue;
X }
X if (GotSignal && !status)
X {
X SigHandler();
X continue;
X }
X /* Process a client connect attempt and message */
X if (nsel && FD_ISSET(s, &r))
X {
X nsel--;
X if (!HS)
X RemoveStatus();
X if (in_ovl)
X {
X SetOvlCurr();
X (*ovl_process)(0, 0); /* We have to abort first!! */
X CheckScreenSize(1); /* Change fore */
X DeadlyMsg = 0;
#ifdef NETHACK
X if (nethackflag)
X Msg(0, "KAABLAMM!!! You triggered a land mine!");
X else
#endif
X Msg(0, "Aborted because of window change or message.");
X }
X else
X CheckScreenSize(1); /* Change fore */
X ReceiveMsg(s);
X continue;
X }
X /*
X * Write the stored user input to the window descriptors first.
X * We do not want to choke, if he types fast.
X */
X if (nsel && inbuf_ct > 0)
X {
X for (n = 0; n < MAXWIN ; n++)
X {
X if (inlen[n] <= 0)
X continue;
X tmp = wtab[n]->ptyfd;
X if (FD_ISSET(tmp, &w))
X {
X if ((len = write(tmp, inbuf[n], inlen[n])) > 0)
X {
X if ((inlen[n] -= len) == 0)
X inbuf_ct--;
X bcopy(inbuf[n] + len, inbuf[n], inlen[n]);
X }
X if (--nsel == 0)
X break;
X }
X }
X }
X /* Read, process, and store the user input */
X if (nsel && FD_ISSET(0, &r))
X {
X nsel--;
X if (!HS)
X RemoveStatus();
X if (ESCseen)
X {
X buf[0] = Esc;
X buflen = read(0, buf + 1, IOSIZE - 1) + 1;
X ESCseen = 0;
X }
X else
X buflen = read(0, buf, IOSIZE);
X if (buflen < 0)
X {
X debug1("Read error: %d - SigHup()ing!\n", errno);
X SigHup(SIGARG);
X continue;
X }
X if (buflen == 0)
X {
X debug("Found EOF - SigHup()ing!\n");
X SigHup(SIGARG);
X continue;
X }
X bufp = buf;
X if (in_ovl)
X {
X SetOvlCurr();
X (*ovl_process)(&bufp, &buflen);
X }
X while (buflen > 0)
X {
X n = ForeNum;
X len = inlen[n];
X bufp = ProcessInput(bufp, &buflen, inbuf[n], &inlen[n],
X sizeof *inbuf);
X if (inlen[n] > 0 && len == 0)
X inbuf_ct++;
X }
X if (inbuf_ct > 0)
X continue;
X }
X if (GotSignal && !status)
X {
X SigHandler();
X continue;
X }
#ifdef COPY_PASTE
X /* Write the copybuffer contents first, if any. jw. */
X if (pastelen > 0)
X {
X n = ForeNum;
X debug1("writing pastebuffer (%d)\n", pastelen);
X tmp = wtab[n]->ptyfd;
X if ( /* FD_ISSET(tmp, &w) && */
X (len = write(tmp, pastebuffer,
X pastelen > IOSIZE ? IOSIZE : pastelen)) > 0)
X {
X pastebuffer += len;
X pastelen -= len;
X debug1("%d bytes pasted\n", len);
X if (slowpaste > 0)
X {
X struct timeval t;
X
X debug1("slowpaste %d\n", slowpaste);
X t.tv_usec = (long) (slowpaste * 1000);
X t.tv_sec = 0;
X select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &t);
X }
X else
X continue;
X }
X /*
X * We could not paste? Let's see if the pty did echo the lot.
X * Then continue by processing some pty output.
X */
X }
#endif
X if (GotSignal && !status)
X {
X SigHandler();
X continue;
X }
X /* Read and process the output from the window descriptors */
X for (n = WinList; n != -1; n = p->WinLink)
X {
X p = wtab[n];
X if (in_ovl && ovl_blockfore && n == ForeNum)
X continue;
X if (p->outlen)
X WriteString(p, p->outbuf, p->outlen);
X else if (nsel && FD_ISSET(p->ptyfd, &r))
X {
X nsel--;
X if ((len = read(p->ptyfd, buf, IOSIZE)) == -1)
X {
#ifdef EWOULDBLOCK
X if (errno == EWOULDBLOCK)
X len = 0;
#endif
X }
#if defined(TIOCPKT) && !defined(sgi)
X if (buf[0])
X {
X debug1("PAKET %x\n", buf[0]);
X if (buf[0] & TIOCPKT_NOSTOP)
X {
X NewAutoFlow(p, 0);
X }
X if (buf[0] & TIOCPKT_DOSTOP)
X {
X NewAutoFlow(p, 1);
X }
X }
X if (len > 1)
X WriteString(p, buf + 1, len - 1);
#else /* TIOCPKT && !sgi */
X if (len > 0)
X WriteString(p, buf, len);
#endif /* TIOCPKT && !sgi */
X }
X if (p->bell == BELL_ON)
X {
X p->bell = BELL_DONE;
X Msg(0, MakeWinMsg(BellString, n));
X if (p->monitor == MON_FOUND)
X p->monitor = MON_DONE;
X }
X else if (p->bell == BELL_VISUAL)
X {
X if (!BellDisplayed)
X {
X p->bell = BELL_DONE;
X Msg(0, VisualBellString);
X BellDisplayed = 1;
X }
X }
X else if (p->monitor == MON_FOUND)
X {
X p->monitor = MON_DONE;
X Msg(0, MakeWinMsg(ActivityString, n));
X }
X }
X if (GotSignal && !status)
X SigHandler();
#ifdef DEBUG
X if (nsel)
X debug1("Left over nsel: %d\n", nsel);
#endif
X }
X /* NOTREACHED */
}
X
static void SigHandler()
{
X struct stat st;
X while (GotSignal)
X {
X GotSignal = 0;
X DoWait();
#ifdef SYSV
X signal(SIGCLD, SigChld);
#endif
X }
X if (stat(SockPath, &st) == -1)
X {
X debug1("SigHandler: Yuck! cannot stat '%s'\n", SockPath);
X if (!RecoverSocket())
X {
X debug("SCREEN cannot recover from corrupt Socket, bye\n");
X Finit(1);
X }
X else
X debug1("'%s' reconstructed\n", SockPath);
X }
X else
X debug2("SigHandler: stat '%s' o.k. (%03o)\n", SockPath, st.st_mode);
}
X
#ifdef DEBUG
int FEpanic;
X
sig_t FEChld(SIGDEFARG)
{
X FEpanic=1;
#ifndef SIGVOID
X return((sig_t) 0);
#endif
}
#endif
X
static sig_t SigChld(SIGDEFARG)
{
X debug("SigChld()\n");
X GotSignal = 1;
#ifndef SIGVOID
X return((sig_t) 0);
#endif
}
X
sig_t SigHup(SIGDEFARG)
{
X debug("SigHup()\n");
X if (auto_detach)
X Detach(D_DETACH);
X else
X Finit(0);
#ifndef SIGVOID
X return((sig_t) 0);
#endif
}
X
/*
X * the frontend's Interrupt handler
X * we forward SIGINT to the backend
X */
static sig_t
AttacherSigInt(SIGDEFARG)
{
X Kill(MasterPid, SIGINT);
X signal(SIGINT, AttacherSigInt);
# ifndef SIGVOID
X return (sig_t) 0;
# endif
}
X
X
/*
X * the backend's Interrupt handler
X * we cannot insert the intrc directly, as we never know
X * if fore and ForeNum are valid.
X */
static sig_t SigInt(SIGDEFARG)
{
#if HAZARDOUS
X char buf[1];
X
X debug("SigInt()\n");
X *buf = (char) intrc;
X inlen[ForeNum] = 0;
X if (fore && !in_ovl)
X write(fore->ptyfd, buf, 1);
#else
X debug("SigInt() careful\n");
X InterruptPlease = 1;
X signal(SIGINT, SigInt);
#endif
#ifndef SIGVOID
X return((sig_t) 0);
#endif
}
X
static sig_t CoreDump(sig)
int sig;
{
X setgid(getgid());
X setuid(getuid());
X unlink("core");
X fprintf(stderr, "\r\n[screen caught signal %d.%s]\r\n", sig,
#ifdef SHADOWPW
X ""
#else /* SHADOWPW */
X " (core dumped)"
#endif /* SHADOWPW */
X );
X fflush(stderr);
X Kill(AttacherPid, SIG_BYE);
#ifdef SHADOWPW
X eexit(sig);
#else /* SHADOWPW */
X abort();
#endif /* SHADOWPW */
#ifndef SIGVOID
X return((sig_t) 0);
#endif
}
X
static void DoWait()
{
X register int n, next, pid;
#ifdef BSDWAIT
X union wait wstat;
#else
X int wstat;
#endif
X
#ifdef BSDJOBS
# ifndef BSDWAIT
X while ((pid = waitpid(-1, &wstat, WNOHANG | WUNTRACED)) > 0)
# else
X while ((pid = wait3(&wstat, WNOHANG | WUNTRACED, (struct rusage *) 0)) > 0)
# endif
#else /* BSDJOBS */
X while ((pid = wait(&wstat)) < 0)
X if (errno != EINTR)
X break;
X if (pid >= 0)
#endif /* BSDJOBS */
X {
X for (n = WinList; n != -1; n = next)
X {
X next = wtab[n]->WinLink;
X if (pid == wtab[n]->wpid)
X {
#ifdef BSDJOBS
X if (WIFSTOPPED(wstat))
X {
# ifdef NETHACK
X if (nethackflag)
X Msg(0, "You regain consciousness.");
X else
# endif /* NETHACK */
X Msg(0, "Child has been stopped, restarting.");
X debug1("WIFSTOPPED: %d SIGCONT\n", wtab[n]->wpid);
X if (killpg(wtab[n]->wpid, SIGCONT))
X kill(wtab[n]->wpid, SIGCONT);
X }
X else
#endif
X KillWindow(n);
X }
X }
X }
}
X
void KillWindow(n)
int n;
{
X register int i;
X /*
X * Remove window from linked list.
X */
X if (n == WinList) /* WinList = ForeNum */
X {
X RemoveStatus();
X WinList = fore->WinLink;
X fore = 0;
X }
X else
X {
X i = WinList;
X while (wtab[i]->WinLink != n)
X i = wtab[i]->WinLink;
X wtab[i]->WinLink = wtab[n]->WinLink;
X }
X FreeWindow(wtab[n]);
X wtab[n] = 0;
X if (inlen[n] > 0)
X {
X inlen[n] = 0;
X inbuf_ct--;
X }
X /*
X * If the foreground window disappeared check the head of the linked list
X * of windows for the most recently used window. If no window is alive at
X * all, exit.
X */
X if (WinList == -1)
X Finit(0);
X if (!fore)
X SwitchWindow(WinList);
}
X
static sig_t Finit(i)
int i;
{
X register int n, next;
X
#ifdef SYSV
X signal(SIGCLD, SIG_IGN);
#else
X signal(SIGCHLD, SIG_IGN);
#endif
X signal(SIGHUP, SIG_IGN);
X debug1("Finit(%d);\n", i);
X for (n = WinList; n != -1; n = next)
X {
X next = wtab[n]->WinLink;
X FreeWindow(wtab[n]);
X }
X FinitTerm();
X SetTTY(0, &OldMode);
#ifdef UTMPOK
X RestoreLoginSlot();
#endif
X printf("\n[screen is terminating]\n");
X freetty();
X if (ServerSocket != -1)
X {
X debug1("we unlink(%s)\n", SockPath);
X (void) unlink(SockPath);
X }
X Kill(AttacherPid, SIG_BYE);
X exit(i);
#ifndef SIGVOID
X return((sig_t) 0);
#endif
}
X
void
eexit(e)
int e;
{
X if (ServerSocket != -1)
X {
X debug1("we unlink(%s)\n", SockPath);
X (void) unlink(SockPath);
X }
X exit(e);
}
X
static void InitKeytab()
{
X register unsigned int i;
X
X for (i = 0; i < sizeof(ktab)/sizeof(*ktab); i++)
X ktab[i].type = KEY_IGNORE;
X
X ktab['h'].type = ktab[Ctrl('h')].type = KEY_HARDCOPY;
#ifdef BSDJOBS
X ktab['z'].type = ktab[Ctrl('z')].type = KEY_SUSPEND;
#endif
X ktab['c'].type = ktab[Ctrl('c')].type = KEY_SHELL;
X ktab[' '].type = ktab[Ctrl(' ')].type =
X ktab['n'].type = ktab[Ctrl('n')].type = KEY_NEXT;
X ktab['-'].type = ktab['p'].type = ktab[Ctrl('p')].type = KEY_PREV;
X ktab['k'].type = ktab[Ctrl('k')].type = KEY_KILL;
X ktab['l'].type = ktab[Ctrl('l')].type = KEY_REDISPLAY;
X ktab['w'].type = ktab[Ctrl('w')].type = KEY_WINDOWS;
X ktab['v'].type = ktab[Ctrl('v')].type = KEY_VERSION;
X ktab['q'].type = ktab[Ctrl('q')].type = KEY_XON;
X ktab['s'].type = ktab[Ctrl('s')].type = KEY_XOFF;
X ktab['t'].type = ktab[Ctrl('t')].type = KEY_TIME;
X ktab['i'].type = ktab[Ctrl('i')].type = KEY_INFO;
X ktab['m'].type = ktab[Ctrl('m')].type = KEY_LASTMSG;
X ktab['A'].type = KEY_AKA, ktab['A'].args = NULL;
X ktab['L'].type = KEY_LOGIN;
X ktab[','].type = KEY_LICENSE;
X ktab['W'].type = KEY_WIDTH;
X ktab['.'].type = KEY_TERMCAP;
X ktab[Ctrl('\\')].type = KEY_QUIT;
X ktab['d'].type = ktab[Ctrl('d')].type = KEY_DETACH;
X ktab['r'].type = ktab[Ctrl('r')].type = KEY_WRAP;
X ktab['f'].type = ktab[Ctrl('f')].type = KEY_FLOW;
X ktab['C'].type = KEY_CLEAR;
X ktab['Z'].type = KEY_RESET;
X ktab['H'].type = KEY_LOGTOGGLE;
X if (Esc != MetaEsc)
X ktab[Esc].type = KEY_OTHER;
X else
X ktab[Esc].type = KEY_IGNORE;
X ktab['M'].type = KEY_MONITOR;
X ktab['?'].type = KEY_HELP;
X for (i = 0; i <= 9; i++)
X ktab['0' + i].type = (enum keytype) (i + (int)KEY_0);
X ktab[Ctrl('G')].type = KEY_VBELL;
X ktab[':'].type = KEY_COLON;
#ifdef COPY_PASTE
X ktab['['].type = ktab[Ctrl('[')].type = KEY_COPY;
X ktab[']'].type = ktab[Ctrl(']')].type = KEY_PASTE;
X ktab['{'].type = KEY_HISTORY;
X ktab['}'].type = KEY_HISTNEXT;
X ktab['>'].type = KEY_WRITE_BUFFER;
X ktab['<'].type = KEY_READ_BUFFER;
X ktab['='].type = KEY_REMOVE_BUFFERS;
#endif
#ifdef POW_DETACH
X ktab['D'].type = KEY_POW_DETACH;
#endif
#ifdef LOCK
X ktab['x'].type = ktab[Ctrl('x')].type = KEY_LOCK;
#endif
}
X
/*
X * this is a braindamaged hack: if (obuf == NULL) then we provided
X * a key_type as a second char in ibuf. not a key.
X */
char *ProcessInput(ibuf, pilen, obuf, polen, obuf_size)
char *ibuf, *obuf;
register int *pilen, *polen, obuf_size;
{
X register int n;
X register enum keytype k;
X register char *s, *p;
X char buf[2];
X int newwidth;
X
X if (!obuf)
X obuf_size = 0;
X
X for (s = ibuf, p = obuf + *polen; *pilen > 0; --*pilen, s++)
X {
X if (*s == Esc)
X {
X debug2("'%c %c ", s[0], s[1]);
X debug2("%c %c' ", s[2], s[3]);
X if (*pilen > 1)
X {
X --*pilen;
X s++;
#if defined(GOULD_NP1)
X k = (obuf)?(ktab[*s].type):(enum keytype)(int)(*s);
#else
X k = (obuf)?(ktab[*s].type):(enum keytype)(*s);
#endif
X debug2("Processinput C-A %02x '%c' ", k, k);
X debug1("%s\n", (obuf)?"std":"NOOBUF");
X if (*s == MetaEsc)
X {
X if (*polen < obuf_size)
X {
X *p++ = Esc;
X ++*polen;
X }
X }
X else if ((int)k >= (int)KEY_0 && (int)k <= (int)KEY_9)
X SwitchWindow((int)k - (int)KEY_0);
X else
X switch (k)
X {
X case KEY_TERMCAP:
X WriteFile(DUMP_TERMCAP);
X break;
X case KEY_HARDCOPY:
X WriteFile(DUMP_HARDCOPY);
X break;
X case KEY_LOGTOGGLE:
X LogToggle();
X break;
#ifdef BSDJOBS
X case KEY_SUSPEND:
X *pilen = 0;
X Detach(D_STOP);
X break;
#endif
X case KEY_SHELL:
X debug("calling MakeWindow with shell\n");
X MakeWindow(shellaka, ShellArgs, allflag, default_flow,
X 0, (char *) 0, loginflag, -1, (char *)0);
X break;
X case KEY_NEXT:
X if (MoreWindows())
X SwitchWindow(NextWindow());
X break;
X case KEY_PREV:
X if (MoreWindows())
X SwitchWindow(PreviousWindow());
X break;
X case KEY_KILL:
X KillWindow(n = ForeNum);
#ifdef NETHACK
X if (nethackflag)
X Msg(0, "You destroy poor window %d", n);
#endif
X break;
X case KEY_QUIT:
X Finit(0);
X /* NOTREACHED */
X case KEY_DETACH:
X *pilen = 0;
X Detach(D_DETACH);
X break;
#ifdef POW_DETACH
X case KEY_POW_DETACH:
X *pilen = 0;
X if (obuf)
X {
X buf[0] = *s;
X buf[1] = '\0';
X Msg(0, buf);
X read(0, buf, 1);
X if (*buf != *s)
X {
X write(1, "\007", 1);
X RemoveStatus();
#ifdef NETHACK
X if (nethackflag)
X Msg(0, "The blast of disintegration whizzes by you!");
#endif
X break;
X }
X }
X Detach(D_POWER); /* detach and kill Attacher's
X * parent */
X break;
#endif
X case KEY_REDISPLAY:
X Activate(0);
X break;
X case KEY_WINDOWS:
X ShowWindows();
X break;
X case KEY_VERSION:
X Msg(0, "screen %d.%.2d.%.2d%s (%s) %s", REV, VERS,
X PATCHLEVEL, STATE, ORIGIN, DATE);
X break;
X case KEY_TIME:
X ShowTime();
X break;
X case KEY_INFO:
X ShowInfo();
X break;
X case KEY_OTHER:
X if (MoreWindows())
X SwitchWindow(fore->WinLink);
X break;
X case KEY_XON:
X if (*polen < obuf_size)
X {
X *p++ = Ctrl('q');
X ++*polen;
X }
X break;
X case KEY_XOFF:
X if (*polen < obuf_size)
X {
X *p++ = Ctrl('s');
X ++*polen;
X }
X break;
#ifdef LOCK
X case KEY_LOCK:
X Detach(D_LOCK); /* do it micha's way */
X break;
#endif
X case KEY_WIDTH:
X if (Z0 || WS)
X {
X if (fore->width == Z0width)
X newwidth = Z1width;
X else if (fore->width == Z1width)
X newwidth = Z0width;
X else if (fore->width > (Z0width+Z1width)/2)
X newwidth = Z0width;
X else
X newwidth = Z1width;
X ChangeWindowSize(fore, newwidth, fore->height);
X Activate(fore->norefresh);
X }
X else
X Msg(0, "Your termcap does not specify how to change the terminal's width.");
X break;
X case KEY_LOGIN:
X SlotToggle(0);
X break;
X case KEY_AKA:
X if (!ktab[*s].args)
X InputAKA();
X else
X strncpy(fore->cmd + fore->akapos, ktab[*s].args[0], 20);
X break;
X case KEY_COLON:
X InputColon();
X break;
X case KEY_LASTMSG:
X Msg(0, "%s", LastMsg);
X break;
X case KEY_SET:
X DoSet(ktab[*s].args);
X break;
X case KEY_SCREEN:
X debug3("KEY_SCREEN DoSc(, ktab[%d].args(='%s','%s')...)\n",
X *s, ktab[*s].args[0], ktab[*s].args[1]);
X DoScreen("key", ktab[*s].args);
X break;
X case KEY_CREATE:
X debug2("KEY_CREATE MaWi(0, ktab[%d].args(='%s')...)\n",
X *s, ktab[*s].args);
X MakeWindow((char *) 0, ktab[*s].args, allflag, default_flow, 0, (char *) 0, loginflag, -1, (char *)0);
X break;
X case KEY_WRAP:
X fore->wrap = !fore->wrap;
X Msg(0, "%cwrap", fore->wrap ? '+' : '-');
X break;
X case KEY_FLOW:
X if (fore->flow & FLOW_AUTOFLAG)
X fore->flow = (fore->flow & FLOW_AUTO) | FLOW_NOW;
X else if (fore->flow & FLOW_NOW)
X fore->flow &= ~FLOW_NOW;
X else
X fore->flow = fore->flow ? FLOW_AUTOFLAG|FLOW_AUTO|FLOW_NOW : FLOW_AUTOFLAG;
X SetFlow(fore->flow & FLOW_NOW);
X Msg(0, "%cflow%s", (fore->flow & FLOW_NOW) ? '+' : '-',
X (fore->flow & FLOW_AUTOFLAG) ? "(auto)" : "");
X break;
X case KEY_CLEAR:
X if (fore->state == LIT)
X WriteString(fore, "\033[H\033[J", 6);
X break;
X case KEY_RESET:
X if (fore->state == LIT)
X WriteString(fore, "\033c", 2);
X break;
X case KEY_MONITOR:
X if (fore->monitor == MON_OFF)
X {
X fore->monitor = MON_ON;
X Msg(0,
X "Window %d is now being monitored for all activity.",
X ForeNum);
X }
X else
X {
X fore->monitor = MON_OFF;
X Msg(0,
X "Window %d is no longer being monitored for activity.",
X ForeNum);
X }
X break;
X case KEY_HELP:
X display_help();
X break;
X case KEY_LICENSE:
X display_copyright();
X break;
#ifdef COPY_PASTE
X case KEY_COPY:
X (void) MarkRoutine(PLAIN);
X break;
X case KEY_HISTNEXT:
X if (MarkRoutine(CRAZY))
X if (copybuffer != NULL)
X {
X pastelen = copylen;
X pastebuffer = copybuffer;
X debug("histnext\n");
X }
X break;
X case KEY_HISTORY:
X if (MarkRoutine(TRICKY))
X if (copybuffer != NULL)
X {
X pastelen = copylen;
X pastebuffer = copybuffer;
X debug1("history new copylen: %d\n", pastelen);
X }
X break;
X case KEY_PASTE:
X if (copybuffer == NULL)
X {
#ifdef NETHACK
X if (nethackflag)
X Msg(0, "Nothing happens.");
X else
#endif
X Msg(0, "empty buffer");
X copylen = 0;
X break;
X }
X pastelen = copylen;
X pastebuffer = copybuffer;
X break;
X case KEY_WRITE_BUFFER:
X if (copybuffer == NULL)
X {
#ifdef NETHACK
X if (nethackflag)
X Msg(0, "Nothing happens.");
X else
#endif
X Msg(0, "empty buffer");
X copylen = 0;
X break;
X }
X WriteFile(DUMP_EXCHANGE);
X break;
X case KEY_READ_BUFFER:
X ReadFile();
X break;
X case KEY_REMOVE_BUFFERS:
X KillBuffers();
X break;
#endif /* COPY_PASTE */
X case KEY_VBELL:
X if (visual_bell)
X {
X visual_bell = 0;
X Msg(0, "switched to audible bell");
X }
X else
X {
X visual_bell = 1;
X Msg(0, "switched to visual bell");
X }
X break;
X default:
X break;
X }
X }
X else
X ESCseen = 1;
X --*pilen;
X s++;
X break;
X }
X else if (*polen < obuf_size)
X {
X *p++ = *s;
X ++*polen;
X }
X }
X return (s);
}
X
/* Send a terminal report as if it were typed. */
void
Report(wp, fmt, n1, n2)
struct win *wp;
char *fmt;
int n1, n2;
{
X register int n, len;
X char rbuf[40];
X
X sprintf(rbuf, fmt, n1, n2);
X len = strlen(rbuf);
X
X for (n = 0; n < MAXWIN; n++)
X {
X if (wp == wtab[n])
X {
X if ((unsigned)(inlen[n] + len) <= sizeof *inbuf)
X {
X bcopy(rbuf, inbuf[n] + inlen[n], len);
X if (inlen[n] == 0)
X inbuf_ct++;
X inlen[n] += len;
X }
X break;
X }
X }/* for */
}
X
void
SwitchWindow(n)
int n;
{
X debug1("SwitchWindow %d\n", n);
X if (!wtab[n])
X {
X ShowWindows();
X return;
X }
X if (wtab[n] == fore)
X {
X Msg(0, "This IS window %d.", n);
X return;
X }
X SetForeWindow(n);
X if (!Detached && !in_ovl)
X Activate(fore->norefresh);
}
X
static void SetForeWindow(n)
int n;
{
X /*
X * If we come from another window, make it inactive.
X */
X if (fore)
X fore->active = 0;
X ForeNum = n;
X fore = wtab[n];
X if (!Detached && !in_ovl)
X fore->active = 1;
X /*
X * Place the window at the head of the most-recently-used list.
X */
X if ((n = WinList) != ForeNum)
X {
X /*
X * we had a bug here. we sometimes ran into n = -1; and crashed.
X * (this is not the perfect fix. "if (...) break;" inserted. jw.)
X */
X while (wtab[n]->WinLink != ForeNum)
X {
X if (wtab[n]->WinLink == -1)
X break;
X n = wtab[n]->WinLink;
X }
X wtab[n]->WinLink = fore->WinLink;
X fore->WinLink = WinList;
X WinList = ForeNum;
X }
}
X
static int NextWindow()
{
X register struct win **pp;
X
X for (pp = wtab + ForeNum + 1; pp != wtab + ForeNum; ++pp)
X {
X if (pp == wtab + MAXWIN)
X pp = wtab;
X if (*pp)
X break;
X }
X return pp - wtab;
}
X
static int PreviousWindow()
{
X register struct win **pp;
X
X for (pp = wtab + ForeNum - 1; pp != wtab + ForeNum; --pp)
X {
X if (pp < wtab)
X pp = wtab + MAXWIN - 1;
X if (*pp)
X break;
X }
X return pp - wtab;
}
X
static int MoreWindows()
{
X if (fore->WinLink != -1)
X return 1;
#ifdef NETHACK
X if (nethackflag)
X Msg(0, "You cannot escape from window %d!", ForeNum);
X else
#endif
X Msg(0, "No other window.");
X return 0;
}
X
static void FreeWindow(wp)
struct win *wp;
{
#ifdef UTMPOK
X RemoveUtmp(wp);
#endif
#ifdef SUIDROOT
X (void) chmod(wp->tty, 0666);
X (void) chown(wp->tty, 0, 0);
#endif
X close(wp->ptyfd);
X if (wp->logfp != NULL)
X fclose(wp->logfp);
X ChangeWindowSize(wp, 0, 0);
X Free(wp);
}
X
int
MakeWindow(prog, args, aflag, flowflag, StartAt, dir, lflag, histheight, term)
char *prog, **args, *dir;
int aflag, flowflag, StartAt, lflag, histheight;
char *term; /* if term is nonzero we assume it "vt100" or the like.. */
{
X register struct win **pp, *p;
X register int n, f;
X int tf, tlflag;
X char ebuf[10];
#ifndef TIOCSWINSZ
X char libuf[20], cobuf[20];
#endif
X char tebuf[25];
X
X pp = wtab + StartAt;
X do
X {
X if (*pp == 0)
X break;
X if (++pp == wtab + MAXWIN)
X pp = wtab;
X } while (pp != wtab + StartAt);
X if (*pp)
X {
X Msg(0, "No more windows.");
X return -1;
X }
X
X if (((tlflag = lflag) == -1) && ((tlflag = loginflag) == -1))
X tlflag = LOGINDEFAULT;
X
#ifdef USRLIMIT
X /*
X * Count current number of users, if logging windows in.
X */
X if (tlflag == 1 && CountUsers() >= USRLIMIT)
X {
X Msg(0, "User limit reached. Window will not be logged in.");
X tlflag = 0;
X }
#endif
X n = pp - wtab;
X debug1("Makewin creating %d\n", n);
X if ((f = OpenPTY()) == -1)
X {
X Msg(0, "No more PTYs.");
X return -1;
X }
#ifdef SYSV
X (void) fcntl(f, F_SETFL, O_NDELAY);
#else
X (void) fcntl(f, F_SETFL, FNDELAY);
#endif
#ifdef TIOCPKT
X {
# ifdef sgi
X /*
X * on IRIX 3.3, regardless of stream head's read mode (RNORM/RMSGN/RMSGD)
X * we loose data in TIOCPKT mode if our buffer is too small (IOSIZE)
X * to hold the whole packet at first read().
X * (Marc Boucher)
X */
X int flag = 0;
# else /* sgi */
X int flag = 1;
# endif /* sgi */
X
X if (ioctl(f, TIOCPKT, &flag))
X {
X Msg(errno, "TIOCPKT ioctl");
X close(f);
X return -1;
X }
X }
#endif
X if ((p = (struct win *) malloc(sizeof(struct win))) == 0)
X {
X close(f);
X Msg_nomem;
X return -1;
X }
X bzero((char *) p, (int) sizeof(struct win));
X p->ptyfd = f;
X p->aflag = aflag;
X if (flowflag < 0)
X flowflag = default_flow;
X p->flow = flowflag | ((flowflag & FLOW_AUTOFLAG) ? (FLOW_AUTO|FLOW_NOW) : FLOW_AUTO);
X if (!prog)
X prog = Filename(args[0]);
X strncpy(p->cmd, prog, MAXSTR - 1);
X if ((prog = rindex(p->cmd, '|')) != NULL)
X {
X *prog++ = '\0';
X prog += strlen(prog);
X p->akapos = prog - p->cmd;
X p->autoaka = 0;
X }
X else
X p->akapos = 0;
X p->monitor = default_monitor;
X p->norefresh = 0;
X strncpy(p->tty, TtyName, MAXSTR - 1);
#ifdef SUIDROOT
X (void) chown(TtyName, real_uid, real_gid);
# ifdef UTMPOK
X (void) chmod(TtyName, tlflag ? TtyMode : (TtyMode & ~022));
# else
X (void) chmod(TtyName, TtyMode);
# endif
#endif
X
X if (histheight < 0)
X histheight = default_histheight;
X if (ChangeWindowSize(p, default_width, default_height))
X {
X FreeWindow(p);
X return -1;
X }
X ChangeScrollback(p, histheight, default_width);
X ResetScreen(p);
X debug("forking...\n");
X switch (p->wpid = fork())
X {
X case -1:
X Msg(errno, "fork");
X FreeWindow(p);
X return -1;
X case 0:
X signal(SIGHUP, SIG_DFL);
X signal(SIGINT, SIG_DFL);
X signal(SIGQUIT, SIG_DFL);
X signal(SIGTERM, SIG_DFL);
#ifdef BSDJOBS
X signal(SIGTTIN, SIG_DFL);
X signal(SIGTTOU, SIG_DFL);
#endif
X setuid(real_uid);
X setgid(real_gid);
X if (dir && chdir(dir) == -1)
X {
X SendErrorMsg("Cannot chdir to %s: %s", dir, sys_errlist[errno]);
X eexit(1);
X }
X
X freetty();
X if ((tf = open(TtyName, O_RDWR)) == -1)
X {
X SendErrorMsg("Cannot open %s: %s", TtyName, sys_errlist[errno]);
X eexit(1);
X }
#ifdef SVR4
X if (ioctl(tf, I_PUSH, "ptem"))
X {
X SendErrorMsg("Cannot I_PUSH ptem %s %s", TtyName, sys_errlist[errno]);
X eexit(1);
X }
X if (ioctl(tf, I_PUSH, "ldterm"))
X {
X SendErrorMsg("Cannot I_PUSH ldterm %s %s", TtyName, sys_errlist[errno]);
X eexit(1);
X }
X if (ioctl(tf, I_PUSH, "ttcompat"))
X {
X SendErrorMsg("Cannot I_PUSH ttcompat %s %s", TtyName, sys_errlist[errno]);
X eexit(1);
X }
#endif
X (void) dup2(tf, 0);
X (void) dup2(tf, 1);
X (void) dup2(tf, 2);
#ifdef DEBUG
X dfp = stderr;
#endif
X closeallfiles();
X fgtty();
#ifdef TIOCSWINSZ
X glwz.ws_col = p->width;
X glwz.ws_row = p->height;
X (void) ioctl(0, TIOCSWINSZ, &glwz);
#else
X sprintf(libuf, "LINES=%d", p->height);
X sprintf(cobuf, "COLUMNS=%d", p->width);
X NewEnv[4] = libuf;
X NewEnv[5] = cobuf;
#endif
X SetTTY(0, &OldMode);
X if (aflag)
X NewEnv[2] = MakeTermcap(1);
X else
X NewEnv[2] = Termcap;
X if (term && *term && strcmp(screenterm, term) &&
X (strlen(term) < 20))
X {
X char *s1, *s2, tl;
X
X sprintf(tebuf, "TERM=%s", term);
X debug2("Makewindow %d with %s\n", n, tebuf);
X tl = strlen(term);
X NewEnv[1] = tebuf;
X if (s1 = index(Termcap, '|'))
X {
X if (s2 = index(++s1, '|'))
X {
X if (strlen(Termcap) - (s2 - s1) + tl < 1024)
X {
X bcopy(s2, s1 + tl, strlen(s2) + 1);
X bcopy(term, s1, tl);
X }
X }
X }
X }
X sprintf(ebuf, "WINDOW=%d", n);
X NewEnv[3] = ebuf;
X
X execvpe(*args, args, NewEnv);
X SendErrorMsg("Cannot exec %s: %s", *args, sys_errlist[errno]);
X exit(1);
X } /* end fork switch */
X /*
X * Place the newly created window at the head of the most-recently-used list.
X */
X *pp = p;
X p->WinLink = WinList;
X WinList = n;
X HasWindow = 1;
#ifdef UTMPOK
X debug1("MakeWindow will %slog in.\n", tlflag?"":"not ");
X if (tlflag == 1)
X SetUtmp(p, n);
X else
X p->slot = (slot_t) -1;
#endif
X SetForeWindow(n);
X Activate(0);
X return n;
}
X
static void execvpe(prog, args, env)
char *prog, **args, **env;
{
X register char *path, *p;
X char buf[1024];
X char *shargs[MAXARGS + 1];
X register int i, eaccess = 0;
X
X if (prog[0] == '/')
X path = "";
X else if ((path = getenv("PATH")) == 0)
X path = DefaultPath;
X do
X {
X p = buf;
X while (*path && *path != ':')
X *p++ = *path++;
X if (p > buf)
X *p++ = '/';
X strcpy(p, prog);
X if (*path)
X ++path;
X execve(buf, args, env);
X switch (errno)
X {
X case ENOEXEC:
X shargs[0] = DefaultShell;
X shargs[1] = buf;
X for (i = 1; (shargs[i + 1] = args[i]) != NULL; ++i)
X ;
X execve(DefaultShell, shargs, env);
X return;
X case EACCES:
X eaccess = 1;
X break;
X case ENOMEM:
X case E2BIG:
X case ETXTBSY:
X return;
X }
X } while (*path);
X if (eaccess)
X errno = EACCES;
}
X
X
static void LogToggle()
{
X char buf[1024];
X
X sprintf(buf, "screenlog.%d", ForeNum);
X if (fore->logfp != NULL)
X {
X Msg(0, "Logfile \"%s\" closed.", buf);
X fclose(fore->logfp);
X fore->logfp = NULL;
X return;
X }
X if ((fore->logfp = secfopen(buf, "a")) == NULL)
X {
X Msg(errno, "Error opening logfile \"%s\"", buf);
X return;
X }
X Msg(0, "%s logfile \"%s\"", ftell(fore->logfp) ? "Appending to" : "Creating", buf);
}
X
#ifdef NOREUID
static int UserPID;
static sig_t (*Usersigcld)__P(SIGPROTOARG);
#endif
static int UserSTAT;
X
int UserContext()
{
#ifdef NOREUID
X if (eff_uid == real_uid)
X return(1);
# ifdef SYSV
X Usersigcld = signal(SIGCLD, SIG_DFL);
# else
X Usersigcld = signal(SIGCHLD, SIG_DFL);
# endif
X debug("UserContext: forking.\n");
X switch (UserPID = fork())
X {
X case -1:
X Msg(errno, "fork");
X return -1;
X case 0:
X signal(SIGHUP, SIG_DFL);
X signal(SIGINT, SIG_IGN);
X signal(SIGQUIT, SIG_DFL);
X signal(SIGTERM, SIG_DFL);
# ifdef BSDJOBS
X signal(SIGTTIN, SIG_DFL);
X signal(SIGTTOU, SIG_DFL);
# endif
X setuid(real_uid);
X setgid(real_gid);
X return 1;
X default:
X return 0;
X }
#else
X setreuid(eff_uid, real_uid);
X setregid(eff_gid, real_gid);
X return 1;
#endif
}
X
void
UserReturn(val)
int val;
{
#if defined(NOREUID)
X if (eff_uid == real_uid)
X UserSTAT = val;
X else
X exit(val);
#else
X setreuid(real_uid, eff_uid);
X setregid(real_gid, eff_gid);
X UserSTAT = val;
#endif
}
X
int UserStatus()
{
#ifdef NOREUID
X int i;
# ifdef BSDWAIT
X union wait wstat;
# else
X int wstat;
# endif
X
X if (eff_uid == real_uid)
X return UserSTAT;
X if (UserPID < 0)
X return -1;
X while ((errno = 0, i = wait(&wstat)) != UserPID)
X if (i < 0 && errno != EINTR)
X break;
# ifdef SYSV
X (void) signal(SIGCLD, Usersigcld);
# else
X (void) signal(SIGCHLD, Usersigcld);
# endif
X if (i == -1)
X return -1;
X return (WEXITSTATUS(wstat));
#else
X return UserSTAT;
#endif
}
X
static void ShowWindows()
{
X char buf[1024];
X register char *s;
X register struct win **pp, *p;
X register int i, OtherNum = fore->WinLink;
X register char *cmd;
X
X for (i = 0, s = buf, pp = wtab; pp < wtab + MAXWIN; ++i, ++pp)
X {
X if ((p = *pp) == 0)
X continue;
X
X if (p->akapos)
X {
X if (*(p->cmd + p->akapos) && *(p->cmd + p->akapos - 1) != ':')
X cmd = p->cmd + p->akapos;
X else
X cmd = p->cmd + strlen(p->cmd) + 1;
X }
X else
X cmd = p->cmd;
X if (s - buf + 5 + strlen(cmd) > fore->width - 1)
X break;
X if (s > buf)
X {
X *s++ = ' ';
X *s++ = ' ';
X }
X *s++ = i + '0';
X if (i == ForeNum)
X *s++ = '*';
X else if (i == OtherNum)
X *s++ = '-';
X if (p->monitor == MON_DONE)
X *s++ = '@';
X if (p->bell == BELL_DONE)
X *s++ = '!';
#ifdef UTMPOK
X if (p->slot != (slot_t) 0 && p->slot != (slot_t) -1)
X *s++ = '$';
#endif
X if (p->logfp != NULL)
X {
X strcpy(s, "(L)");
X s += 3;
X }
X *s++ = ' ';
X strcpy(s, cmd);
X s += strlen(s);
X if (i == ForeNum)
X {
X /*
X * this is usually done by Activate(), but when looking
X * on your current window, you may get annoyed, as there is still
X * that temporal '!' and '@' displayed.
X * So we remove that after displaying it once.
X */
X p->bell = BELL_OFF;
X if (p->monitor != MON_OFF)
X p->monitor = MON_ON;
X }
X }
X *s++ = ' ';
X *s = '\0';
X Msg(0, "%s", buf);
}
X
#ifdef LOADAV_3LONGS
extern long loadav[3];
#else
# ifdef LOADAV_4LONGS
extern long loadav[4];
# else
# ifdef LOADAV_NEXT
extern float loadav;
# else
extern double loadav[3];
# endif
# endif
#endif
extern avenrun;
X
static void ShowTime()
{
X char buf[512];
#ifdef LOADAV
X char *p;
#endif
X struct tm *tp;
X time_t now;
X
X (void) time(&now);
X tp = localtime(&now);
X sprintf(buf, "%2d:%02.2d:%02.2d %s", tp->tm_hour, tp->tm_min, tp->tm_sec,
X HostName);
#ifdef LOADAV
X if (avenrun && GetAvenrun())
X {
X p = buf + strlen(buf);
# ifdef LOADAV_3LONGS
X sprintf(p, " %2.2f %2.2f %2.2f", (double) loadav[0] / FSCALE,
X (double) loadav[1] / FSCALE, (double) loadav[2] / FSCALE);
# else
# ifdef LOADAV_4LONGS
X sprintf(p, " %2.2f %2.2f %2.2f %2.2f", (double) loadav[0] / 100,
X (double) loadav[1] / 100, (double) loadav[2] / 100,
X (double) loadav[3] / 100);
# else
# ifdef LOADAV_NEXT
X sprintf(p, " %2.2f", loadav);
# else
# ifdef apollo
X sprintf(p, " %2.2f %2.2f %2.2f", loadav[0]/65536.0, loadav[1]/65536.0,
X loadav[2]/65536.0);
# else
X sprintf(p, " %2.2f %2.2f %2.2f", loadav[0], loadav[1], loadav[2]);
# endif /* apollo */
# endif /* LOADAV_NEXT */
# endif /* LOADAV_4LONGS */
# endif /* LOADAV_3LONGS */
X }
#endif /* LOADAV */
X Msg(0, "%s", buf);
}
X
static void ShowInfo()
{
X char buf[512], *p;
X register struct win *wp = fore;
X register int i;
X
X sprintf(buf, "(%d,%d)/(%d,%d)+%d %c%sflow %cins %corg %cwrap %capp %clog %cmon %cr",
X wp->x + 1, wp->y + 1, wp->width, wp->height,
X wp->histheight,
X (wp->flow & FLOW_NOW) ? '+' : '-',
X (wp->flow & FLOW_AUTOFLAG) ? "" : ((wp->flow & FLOW_AUTO) ? "(+)" : "(-)"),
X wp->insert ? '+' : '-', wp->origin ? '+' : '-',
X wp->wrap ? '+' : '-', wp->keypad ? '+' : '-',
X (wp->logfp != NULL) ? '+' : '-',
X (wp->monitor != MON_OFF) ? '+' : '-',
X wp->norefresh ? '-' : '+');
X if (ISO2022)
X {
X p = buf + strlen(buf);
X sprintf(p, " G%1d [", wp->LocalCharset);
X for (i = 0; i < 4; i++)
X p[i + 5] = wp->charsets[i] ? wp->charsets[i] : 'B';
X p[9] = ']';
X p[10] = '\0';
X }
X Msg(0, "%s", buf);
}
X
#if defined(sequent) || defined(_SEQUENT_) || defined(SVR4)
X
static int OpenPTY()
{
X char *m, *s;
X register int f;
# ifdef SVR4
X char *ptsname();
X sig_t (*sigcld)();
X
X if ((f = open("/dev/ptmx", O_RDWR)) == -1)
X return(-1);
X
X /*
X * SIGCLD set to SIG_DFL for grantpt() because it fork()s and
X * exec()s pt_chmod
X */
X sigcld = signal(SIGCLD, SIG_DFL);
X
X if ((m = ptsname(f)) == NULL || unlockpt(f) || grantpt(f))
X {
X signal(SIGCLD, sigcld);
X close(f);
X return(-1);
X }
X signal(SIGCLD, sigcld);
X strncpy(TtyName, m, sizeof TtyName);
# else /* SVR4 */
X if ((f = getpseudotty(&s, &m)) < 0)
X return(-1);
X strncpy(PtyName, m, sizeof PtyName);
X strncpy(TtyName, s, sizeof TtyName);
# endif /* SVR4 */
# ifdef POSIX
X tcflush(f, TCIOFLUSH);
# else
X (void) ioctl(f, TIOCFLUSH, (char *) 0);
# endif
# ifdef LOCKPTY
X (void) ioctl(f, TIOCEXCL, (char *) 0);
# endif
X return (f);
}
X
#else /* defined(sequent) || defined(_SEQUENT_) || defined(SVR4) */
# ifdef MIPS
X
static int OpenPTY()
{
X register char *p, *l, *d;
X register f, tf;
X register my_minor;
X struct stat buf;
X
X strcpy(PtyName, PtyProto);
X for (p = PtyName; *p != 'X'; ++p)
X ;
X for (l = "zyxwvutsrqp"; *p = *l; ++l)
X {
X for (d = "0123456789abcdef"; p[1] = *d; ++d)
X {
X if ((f = open(PtyName, O_RDWR)) != -1)
X {
X fstat(f, &buf);
X my_minor = minor(buf.st_rdev);
X sprintf(TtyName, "/dev/ttyq%d", my_minor);
X if ((tf = open(TtyName, O_RDWR)) != -1)
X {
X close(tf);
#ifdef LOCKPTY
X (void) ioctl(f, TIOCEXCL, (char *)0);
#endif
X return f;
X }
X close(f);
X }
X }
X }
X return -1;
}
X
# else /* MIPS */
# ifdef sgi
X
static int OpenPTY()
{
X register f;
X register my_minor;
X struct stat buf;
X
X strcpy(PtyName, "/dev/ptc");
X f = open(PtyName, O_RDWR|O_NDELAY);
X if (f >= 0)
X {
X if (fstat(f, &buf) < 0)
X {
X close(f);
X return -1;
X }
X my_minor = minor(buf.st_rdev);
X sprintf(TtyName, "/dev/ttyq%d", my_minor);
X }
X return f;
}
X
# else /* sgi */
# ifdef _AIX /* RS6000 */
X
static int OpenPTY()
{
X register int i, f, tf;
X
X for (i = 0; i < 256; i++)
X {
X sprintf(PtyName, "/dev/ptc/%d", i);
X if ((f = open(PtyName, O_RDWR)) != -1)
X {
X sprintf(TtyName, "/dev/pts/%d", i);
X if ((tf = open(TtyName, O_RDWR)) != -1)
X {
X close(tf);
#ifdef LOCKPTY
X (void) ioctl(f, TIOCEXCL, (char *) 0);
#endif
X return f;
X }
X close(f);
X }
X }
X return -1;
}
X
# else /* _AIX, RS6000 */
X
static int OpenPTY()
{
X register char *p, *q, *l, *d;
X register int f, tf;
X
# if !defined(hpux)
X debug("Hello, You are none of: sequent, _SEQUENT_, SVR4, MIPS, sgi, AIX\n");
X debug(" This OpenPTY() is for hpux, ... and for you?\n");
# endif
X strcpy(PtyName, PtyProto);
X strcpy(TtyName, TtyProto);
X for (p = PtyName; *p != 'X'; ++p)
X ;
X for (q = TtyName; *q != 'X'; ++q)
X ;
#ifdef sequent
X /* why ask for sequent in #else (not sequent) section? jw. */
X for (l = "p"; (*p = *l) != '\0'; ++l)
X { /* } */
X for (d = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; (p[1] = *d) != '\0'; ++d)
X { /* } */
#else
# ifdef hpux
X for (l = "pqrstuvw"; (*p = *l) != '\0'; ++l)
# else
X for (l = "qpr"; (*p = *l) != '\0'; ++l)
#endif
X {
X for (d = "0123456789abcdef"; (p[1] = *d) != '\0'; ++d)
X {
#endif
X if ((f = open(PtyName, O_RDWR)) != -1)
X {
X q[0] = *l;
X q[1] = *d;
X if ((tf = open(TtyName, O_RDWR)) != -1)
X {
X /* close tf, thus we also get rid of an unwanted
X * controlling terminal!
X */
X close(tf);
#ifdef LOCKPTY
X (void) ioctl(f, TIOCEXCL, (char *) 0);
#endif
X return f;
X }
X close(f);
X }
X }
X }
X return -1;
}
X
# endif /* _AIX, RS6000 */
# endif /* sgi */
# endif /* MIPS */
#endif
X
void
SetTTY(fd, mp)
int fd;
struct mode *mp;
{
X errno = 0;
#ifdef POSIX
X tcsetattr(fd, TCSADRAIN, &mp->tio);
# ifdef hpux
X ioctl(fd, TIOCSLTC, &mp->m_ltchars);
# endif
#else
# ifdef TERMIO
X ioctl(fd, TCSETA, &mp->tio);
# else
X /* ioctl(fd, TIOCSETP, &mp->m_ttyb); */
X ioctl(fd, TIOCSETC, &mp->m_tchars);
X ioctl(fd, TIOCSLTC, &mp->m_ltchars);
X ioctl(fd, TIOCLSET, &mp->m_lmode);
X ioctl(fd, TIOCSETD, &mp->m_ldisc);
X ioctl(fd, TIOCSETP, &mp->m_ttyb);
# endif
#endif
X if (errno)
X Msg(0, "SetTTY: ioctl failed");
}
X
void
GetTTY(fd, mp)
int fd;
struct mode *mp;
{
X errno = 0;
#ifdef POSIX
X tcgetattr(fd, &mp->tio);
# ifdef hpux
X ioctl(fd, TIOCGLTC, &mp->m_ltchars);
# endif
#else
# ifdef TERMIO
X ioctl(fd, TCGETA, &mp->tio);
# else
X ioctl(fd, TIOCGETP, &mp->m_ttyb);
X ioctl(fd, TIOCGETC, &mp->m_tchars);
X ioctl(fd, TIOCGLTC, &mp->m_ltchars);
X ioctl(fd, TIOCLGET, &mp->m_lmode);
X ioctl(fd, TIOCGETD, &mp->m_ldisc);
# endif
#endif
X if (errno)
X Msg(0, "GetTTY: ioctl failed");
}
X
void
SetMode(op, np)
struct mode *op, *np;
{
X *np = *op;
X
#if defined(TERMIO) || defined(POSIX)
X np->tio.c_iflag &= ~ICRNL;
# ifdef ONLCR
X np->tio.c_oflag &= ~ONLCR;
# endif
X np->tio.c_lflag &= ~(ICANON | ECHO);
X
X /*
X * Unfortunately, the master process never will get SIGINT if the real
X * terminal is different from the one on which it was originaly started
X * (process group membership has not been restored or the new tty could not
X * be made controlling again). In my solution, it is the attacher who
X * receives SIGINT (because it is always correctly associated with the real
X * tty) and forwards it to the master [kill(MasterPid, SIGINT)].
X * Marc Boucher (marc@CAM.ORG)
X */
X np->tio.c_lflag |= ISIG;
X /*
X * careful, careful catche monkey..
X * never set VMIN and VTIME to zero, if you want blocking io.
X */
X np->tio.c_cc[VMIN] = 1;
X np->tio.c_cc[VTIME] = 0;
#ifdef VSTART
X startc = op->tio.c_cc[VSTART];
#endif
#ifdef VSTOP
X stopc = op->tio.c_cc[VSTOP];
#endif
X if (iflag)
X intrc = op->tio.c_cc[VINTR];
X else
X intrc = np->tio.c_cc[VINTR] = 0377;
X np->tio.c_cc[VQUIT] = 0377;
X if (flow == 0)
X {
X np->tio.c_cc[VINTR] = 0377;
#ifdef VSTART
X np->tio.c_cc[VSTART] = 0377;
#endif
#ifdef VSTOP
X np->tio.c_cc[VSTOP] = 0377;
#endif
X np->tio.c_iflag &= ~IXON;
X }
#ifdef VDISCARD
X np->tio.c_cc[VDISCARD] = 0377;
#endif
#ifdef VSUSP
X np->tio.c_cc[VSUSP] = 0377;
#endif
# ifdef hpux
X np->m_ltchars.t_suspc = 0377;
X np->m_ltchars.t_dsuspc = 0377;
X np->m_ltchars.t_flushc = 0377;
X np->m_ltchars.t_lnextc = 0377;
# else
# ifdef VDSUSP
X np->tio.c_cc[VDSUSP] = 0377;
# endif
# endif
#else
X startc = op->m_tchars.t_startc;
X stopc = op->m_tchars.t_stopc;
X if (iflag)
X intrc = op->m_tchars.t_intrc;
X else
X intrc = np->m_tchars.t_intrc = -1;
X np->m_ttyb.sg_flags &= ~(CRMOD | ECHO);
X np->m_ttyb.sg_flags |= CBREAK;
X np->m_tchars.t_quitc = -1;
X if (flow == 0)
X {
X np->m_tchars.t_intrc = -1;
X np->m_tchars.t_startc = -1;
X np->m_tchars.t_stopc = -1;
X }
X np->m_ltchars.t_suspc = -1;
X np->m_ltchars.t_dsuspc = -1;
X np->m_ltchars.t_flushc = -1;
X np->m_ltchars.t_lnextc = -1;
#endif /* defined(TERMIO) || defined(POSIX) */
SHAR_EOF
true || echo 'restore of screen3.2/screen.c failed'
fi
echo 'End of part 6'
echo 'File screen3.2/screen.c is continued in part 7'
echo 7 > _shar_seq_.tmp
exit 0
exit 0 # Just in case...