home *** CD-ROM | disk | FTP | other *** search
- /* Copyright (c) 1993
- * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
- * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
- * Copyright (c) 1987 Oliver Laumann
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (see the file COPYING); if not, write to the
- * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- ****************************************************************
- */
-
- #include "rcs.h"
- RCS_ID("$Id: screen.c,v 1.15 1993/08/05 14:24:06 mlschroe Exp $ FAU")
-
-
- #include <ctype.h>
- #ifdef __sgi
- # include <stdio.h> /* needed before pwd.h to avoid ansi compiler whining */
- #endif /* __sgi */
-
- #include <pwd.h>
- #include <fcntl.h>
- #ifdef sgi
- # include <sys/sysmacros.h>
- #endif /* sgi */
-
- #include <sys/types.h>
- #ifdef ISC
- # include <sys/bsdtypes.h>
- #endif
- #include <sys/stat.h>
- #ifndef sgi
- # include <sys/file.h>
- #endif /* sgi */
- #ifndef sun
- # include <sys/ioctl.h>
- #endif /* sun */
-
- #include <signal.h>
-
- #include "config.h"
-
- #ifdef SHADOWPW
- # include <shadow.h>
- #endif /* SHADOWPW */
-
- #ifdef SVR4
- # include <sys/stropts.h>
- #endif
-
- #ifdef SYSV
- # include <sys/utsname.h>
- #endif
-
- #if defined(sequent) || defined(SVR4)
- # include <sys/resource.h>
- #endif /* sequent || SVR4 */
-
- #ifdef ISC
- # include <sys/tty.h>
- # include <sys/sioctl.h>
- # include <sys/pty.h>
- #endif /* ISC */
-
- #include "screen.h"
-
- #include "patchlevel.h"
-
-
- #ifdef DEBUG
- FILE *dfp;
- #endif
-
-
- extern char *blank, *null, Term[], screenterm[], **environ, Termcap[];
- int force_vt = 1, assume_LP = 0;
- int VBellWait, MsgWait, MsgMinWait, SilenceWait;
-
- extern struct plop plop_tab[];
- extern struct user *users;
- extern struct display *displays, *display;
- extern struct layer BlankLayer;
-
- /* tty.c */
- extern int intrc;
-
-
- extern int use_hardstatus;
- #ifdef COPY_PASTE
- extern char mark_key_tab[];
- #endif
- extern char version[];
- extern char DefaultShell[];
-
-
- char *ShellProg;
- char *ShellArgs[2];
-
- extern struct NewWindow nwin_undef, nwin_default, nwin_options;
-
- static char *MakeWinMsg __P((char *, int));
- static void SigChldHandler __P((void));
- static sig_t SigChld __P(SIGPROTOARG);
- static sig_t SigInt __P(SIGPROTOARG);
- static sig_t CoreDump __P((int));
- static void DoWait __P((void));
-
-
- #ifdef PASSWORD
- extern char Password[];
- #endif
-
-
- /* the attacher */
- struct passwd *ppp;
- char *attach_tty;
- char *attach_term;
- char *LoginName;
- struct mode attach_Mode;
-
-
- #ifdef SOCKDIR
- char *SockDir = SOCKDIR;
- #else
- char *SockDir = ".iscreen";
- #endif
- extern char SockPath[], *SockNamePtr, *SockName;
- int ServerSocket = -1;
- char **NewEnv = NULL;
-
- char *RcFileName = NULL;
- extern char Esc;
- char *home;
-
- char *screenlogdir = NULL;
- char *hardcopydir = NULL;
- char *BellString;
- char *VisualBellString;
- char *ActivityString;
- #ifdef COPY_PASTE
- char *BufferFile;
- #endif
- #ifdef POW_DETACH
- char *PowDetachString;
- #endif
- int auto_detach = 1;
- int iflag, rflag, dflag, lsflag, quietflag, wipeflag, xflag;
- int adaptflag;
-
- time_t Now;
-
- #ifdef MULTIUSER
- char *multi;
- char *multi_home;
- int multi_uid;
- int own_uid;
- int multiattach;
- int tty_mode;
- int tty_oldmode = -1;
- #endif
-
- char HostName[MAXSTR];
- int MasterPid;
- int real_uid, real_gid, eff_uid, eff_gid;
- int default_startup;
- int slowpaste;
- int ZombieKey;
-
- #ifdef NETHACK
- int nethackflag = 0;
- #endif
-
-
- struct win *fore = NULL;
- struct win *windows = NULL;
- struct win *console_window;
-
-
-
- /*
- * Do this last
- */
- #include "extern.h"
-
-
- #ifdef NETHACK
- char strnomem[] = "Who was that Maude person anyway?";
- #else
- char strnomem[] = "Out of memory.";
- #endif
-
-
- static int InterruptPlease = 0;
- static int GotSigChld;
-
-
- static void
- mkfdsets(rp, wp)
- fd_set *rp, *wp;
- {
- register struct win *p;
-
- FD_ZERO(rp);
- FD_ZERO(wp);
- for (display = displays; display; display = display->_d_next)
- {
- if (d_obufp != d_obuf)
- FD_SET(d_userfd, wp);
-
- FD_SET(d_userfd, rp); /* Do that always */
-
- /* read from terminal if there is room in the destination buffer
- *
- * Removed, so we can always input a command sequence
- *
- * if (d_fore == 0)
- * continue;
- * if (W_UWP(d_fore))
- * {
- * check pseudowin buffer
- * if (d_fore->w_pwin->p_inlen < sizeof(d_fore->w_pwin->p_inbuf))
- * FD_SET(d_userfd, rp);
- * }
- * else
- * {
- * check window buffer
- * if (d_fore->w_inlen < sizeof(d_fore->w_inbuf))
- * FD_SET(d_userfd, rp);
- * }
- */
- }
- for (p = windows; p; p = p->w_next)
- {
- if (p->w_ptyfd < 0)
- continue;
- #ifdef COPY_PASTE
- if (p->w_pastelen)
- {
- /* paste to win/pseudo */
- # ifdef PSEUDOS
- FD_SET(W_UWP(p) ? p->w_pwin->p_ptyfd : p->w_ptyfd, wp);
- # else
- FD_SET(p->w_ptyfd, wp);
- # endif
- }
- #endif
- /* query window buffer */
- if (p->w_inlen > 0)
- FD_SET(p->w_ptyfd, wp);
- #ifdef PSEUDOS
- /* query pseudowin buffer */
- if (p->w_pwin && p->w_pwin->p_inlen > 0)
- FD_SET(p->w_pwin->p_ptyfd, wp);
- #endif
-
- display = p->w_display;
- if (p->w_active && d_status && !d_status_bell && !(use_hardstatus && HS))
- continue;
- if (p->w_outlen > 0)
- continue;
- if (p->w_lay->l_block)
- continue;
- /*
- * Don't accept input from window or pseudowin if there is to much
- * output pending on display .
- */
- if (p->w_active && (d_obufp - d_obuf) > d_obufmax)
- {
- debug1("too much output pending, window %d\n", p->w_number);
- continue;
- }
- #ifdef PSEUDOS
- if (W_RW(p))
- {
- /* Check free space if we stuff window output in pseudo */
- if (p->w_pwin && W_WTOP(p) && (p->w_pwin->p_inlen >= sizeof(p->w_pwin->p_inbuf)))
- {
- debug2("pseudowin %d buffer full (%d bytes)\n", p->w_number, p->w_pwin->p_inlen);
- }
- else
- FD_SET(p->w_ptyfd, rp);
- }
- if (W_RP(p))
- {
- /* Check free space if we stuff pseudo output in window */
- if (W_PTOW(p) && p->w_inlen >= sizeof(p->w_inbuf))
- {
- debug2("window %d buffer full (%d bytes)\n", p->w_number, p->w_inlen);
- }
- else
- FD_SET(p->w_pwin->p_ptyfd, rp);
- }
- #else /* PSEUDOS */
- FD_SET(p->w_ptyfd, rp);
- #endif /* PSEUDOS */
- }
- FD_SET(ServerSocket, rp);
- }
-
- void
- main(ac, av)
- int ac;
- char **av;
- {
- register int n, len;
- register struct win *p;
- char *ap;
- char *av0;
- char socknamebuf[2 * MAXSTR];
- fd_set r, w;
- int mflag = 0;
- struct timeval tv;
- int nsel;
- char buf[IOSIZE], *myname = (ac == 0) ? "screen" : av[0];
- struct stat st;
- int buflen, tmp;
- #ifdef _MODE_T /* (jw) */
- mode_t oumask;
- #else
- int oumask;
- #endif
- #ifdef SYSV
- struct utsname utsnam;
- #endif
- struct NewWindow nwin;
- int detached = 0; /* start up detached */
- struct display *ndisplay;
- #ifdef MULTIUSER
- char *sockp;
- #endif
-
- /*
- * First, close all unused descriptors
- * (otherwise, we might have problems with the select() call)
- */
- closeallfiles(0);
- #ifdef DEBUG
- {
- char buf[255];
-
- sprintf(buf, "%s/screen.%d", DEBUGDIR, getpid());
- (void) mkdir(DEBUGDIR, 0777);
- if ((dfp = fopen(buf, "w")) == NULL)
- dfp = stderr;
- else
- (void) chmod(buf, 0666);
- }
- #endif
- sprintf(version, "%d.%.2d.%.2d%s (%s) %s", REV, VERS,
- PATCHLEVEL, STATE, ORIGIN, DATE);
- debug2("-- screen debug started %s (%s)\n", *av, version);
- #ifdef POSIX
- debug("POSIX\n");
- #endif
- #ifdef TERMIO
- debug("TERMIO\n");
- #endif
- #ifdef SYSV
- debug("SYSV\n");
- #endif
- #ifdef SYSVSIGS
- debug("SYSVSIGS\n");
- #endif
- #ifdef NAMEDPIPE
- debug("NAMEDPIPE\n");
- #endif
- #if defined(SIGWINCH) && defined(TIOCGWINSZ)
- debug("Window changing enabled\n");
- #endif
- #ifdef NOREUID
- debug("NOREUID\n");
- #endif
- #ifdef hpux
- debug("hpux\n");
- #endif
- #ifdef USEBCOPY
- debug("USEBCOPY\n");
- #endif
- #ifdef UTMPOK
- debug("UTMPOK\n");
- #endif
- #ifdef LOADAV
- debug("LOADAV\n");
- #endif
- #ifdef NETHACK
- debug("NETHACK\n");
- #endif
- #ifdef TERMINFO
- debug("TERMINFO\n");
- #endif
- #ifdef SHADOWPW
- debug("SHADOWPW\n");
- #endif
- #ifdef NAME_MAX
- debug1("NAME_MAX = %d\n", NAME_MAX);
- #endif
-
- BellString = SaveStr("Bell in window %");
- VisualBellString = SaveStr(" Wuff, Wuff!! ");
- ActivityString = SaveStr("Activity in window %");
- #ifdef COPY_PASTE
- BufferFile = SaveStr(DEFAULT_BUFFERFILE);
- #endif
- ShellProg = NULL;
- #ifdef POW_DETACH
- PowDetachString = 0;
- #endif
- default_startup = (ac > 1) ? 0 : 1;
- adaptflag = 0;
- slowpaste = 0;
- VBellWait = VBELLWAIT;
- MsgWait = MSGWAIT;
- MsgMinWait = MSGMINWAIT;
- SilenceWait = SILENCEWAIT;
- #ifdef COPY_PASTE
- CompileKeys((char *)NULL, mark_key_tab);
- #endif
- nwin = nwin_undef;
- nwin_options = nwin_undef;
-
- av0 = *av;
- /* if this is a login screen, assume -R */
- if (*av0 == '-')
- {
- rflag = 2;
- #ifdef MULTI
- xflag = 1;
- #endif
- ShellProg = SaveStr(DefaultShell); /* to prevent nasty circles */
- }
- while (ac > 0)
- {
- ap = *++av;
- if (--ac > 0 && *ap == '-')
- {
- switch (ap[1])
- {
- case 'a':
- nwin_options.aflag = 1;
- break;
- case 'A':
- adaptflag = 1;
- break;
- case 'c':
- if (ap[2])
- RcFileName = ap + 2;
- else
- {
- if (--ac == 0)
- exit_with_usage(myname);
- RcFileName = *++av;
- }
- break;
- case 'e':
- if (ap[2])
- ap += 2;
- else
- {
- if (--ac == 0)
- exit_with_usage(myname);
- ap = *++av;
- }
- if (ParseEscape(NULL, ap))
- Panic(0, "Two characters are required with -e option.");
- break;
- case 'f':
- switch (ap[2])
- {
- case 'n':
- case '0':
- nwin_options.flowflag = FLOW_NOW * 0;
- break;
- case 'y':
- case '1':
- case '\0':
- nwin_options.flowflag = FLOW_NOW * 1;
- break;
- case 'a':
- nwin_options.flowflag = FLOW_AUTOFLAG;
- break;
- default:
- exit_with_usage(myname);
- }
- break;
- case 'h':
- if (ap[2])
- nwin_options.histheight = atoi(ap + 2);
- else
- {
- if (--ac == 0)
- exit_with_usage(myname);
- nwin_options.histheight = atoi(*++av);
- }
- if (nwin_options.histheight < 0)
- exit_with_usage(myname);
- break;
- case 'i':
- iflag = 1;
- break;
- case 't': /* title is a synonym for AkA */
- case 'k':
- if (ap[2])
- nwin_options.aka = ap + 2;
- else
- {
- if (--ac == 0)
- exit_with_usage(myname);
- nwin_options.aka = *++av;
- }
- break;
- case 'l':
- switch (ap[2])
- {
- case 'n':
- case '0':
- nwin_options.lflag = 0;
- break;
- case 'y':
- case '1':
- case '\0':
- nwin_options.lflag = 1;
- break;
- case 's':
- case 'i':
- lsflag = 1;
- if (ac > 1)
- {
- SockName = *++av;
- ac--;
- }
- break;
- default:
- exit_with_usage(myname);
- }
- break;
- case 'w':
- lsflag = 1;
- wipeflag = 1;
- break;
- case 'L':
- assume_LP = 1;
- break;
- case 'm':
- mflag = 1;
- break;
- case 'O':
- force_vt = 0;
- break;
- case 'T':
- if (ap[2])
- {
- if (strlen(ap+2) < 20)
- strcpy(screenterm, ap + 2);
- }
- else
- {
- if (--ac == 0)
- exit_with_usage(myname);
- if (strlen(*++av) < 20)
- strcpy(screenterm, *av);
- }
- nwin_options.term = screenterm;
- break;
- case 'q':
- quietflag = 1;
- break;
- case 'r':
- case 'R':
- #ifdef MULTI
- case 'x':
- #endif
- if (ap[2])
- {
- SockName = ap + 2;
- if (ac != 1)
- exit_with_usage(myname);
- }
- else if (ac > 1 && *av[1] != '-')
- {
- SockName = *++av;
- ac--;
- }
- #ifdef MULTI
- if (ap[1] == 'x')
- xflag = 1;
- else
- #endif
- rflag = (ap[1] == 'r') ? 1 : 2;
- break;
- #ifdef REMOTE_DETACH
- case 'd':
- dflag = 1;
- /* FALLTHROUGH */
- case 'D':
- if (!dflag)
- dflag = 2;
- if (ap[2])
- SockName = ap + 2;
- if (ac == 2)
- {
- if (*av[1] != '-')
- {
- SockName = *++av;
- ac--;
- }
- }
- break;
- #endif
- case 's':
- if (ap[2])
- {
- if (ShellProg)
- free(ShellProg);
- ShellProg = SaveStr(ap + 2);
- }
- else
- {
- if (--ac == 0)
- exit_with_usage(myname);
- if (ShellProg)
- free(ShellProg);
- ShellProg = SaveStr(*++av);
- }
- debug1("ShellProg: '%s'\n", ShellProg);
- break;
- case 'S':
- if (ap[2])
- SockName = ap + 2;
- else
- {
- if (--ac == 0)
- exit_with_usage(myname);
- SockName = *++av;
- if (!*SockName)
- exit_with_usage(myname);
- }
- break;
- case 'v':
- Panic(0, "Screen version %s", version);
- /* NOTREACHED */
- default:
- exit_with_usage(myname);
- }
- }
- else
- break;
- }
- if (dflag && mflag && SockName && !(rflag || xflag))
- detached = 1;
- nwin = nwin_options;
- if (ac)
- nwin.args = av;
- real_uid = getuid();
- real_gid = getgid();
- eff_uid = geteuid();
- eff_gid = getegid();
- if (eff_uid != real_uid)
- {
- /* if running with s-bit, we must install a special signal
- * handler routine that resets the s-bit, so that we get a
- * core file anyway.
- */
- #ifdef SIGBUS /* OOPS, linux has no bus errors ??? */
- signal(SIGBUS, CoreDump);
- #endif /* SIGBUS */
- signal(SIGSEGV, CoreDump);
- }
- if (!ShellProg)
- {
- register char *sh;
-
- sh = getenv("SHELL");
- ShellProg = SaveStr(sh ? sh : DefaultShell);
- }
- ShellArgs[0] = ShellProg;
- #ifdef NETHACK
- nethackflag = (getenv("NETHACKOPTIONS") != NULL);
- #endif
- #ifdef MULTIUSER
- own_uid = multi_uid = real_uid;
- if (SockName && (sockp = index(SockName, '/')))
- {
- if (eff_uid)
- Panic(0, "Must run suid root for multi support.");
- *sockp = 0;
- multi = SockName;
- SockName = sockp + 1;
- if (*multi)
- {
- struct passwd *mppp;
- if ((mppp = getpwnam(multi)) == (struct passwd *) 0)
- Panic(0, "Cannot identify account '%s'.", multi);
- multi_uid = mppp->pw_uid;
- multi_home = SaveStr(mppp->pw_dir);
- #ifdef MULTI
- if (rflag || lsflag)
- {
- xflag = 1;
- rflag = 0;
- }
- #endif
- detached = 0;
- multiattach = 1;
- }
- }
- if (SockName && *SockName == 0)
- SockName = 0;
- #endif
- if ((LoginName = getlogin()) && LoginName[0] != '\0')
- {
- if ((ppp = getpwnam(LoginName)) != (struct passwd *) 0)
- if (ppp->pw_uid != real_uid)
- ppp = (struct passwd *) 0;
- }
- if (ppp == 0)
- {
- if ((ppp = getpwuid(real_uid)) == 0)
- {
- #ifdef NETHACK
- if (nethackflag)
- Panic(0, "An alarm sounds through the dungeon...\nWarning, the kops are coming.");
- else
- #endif
- Panic(0, "getpwuid() can't identify your account!");
- exit(1);
- }
- LoginName = ppp->pw_name;
- }
- home = getenv("HOME"); /* may or may not return a result. jw. */
- #if !defined(SOCKDIR) && defined(MULTIUSER)
- if (multi && !multiattach)
- {
- if (home && strcmp(home, ppp->pw_dir))
- Panic(0, "$HOME must match passwd entry for multi screens");
- }
- #endif
- if (home == 0 || *home == '\0')
- home = ppp->pw_dir;
- if (strlen(LoginName) > 20)
- Panic(0, "LoginName too long - sorry.");
- if (strlen(home) > MAXPATHLEN - 25)
- Panic(0, "$HOME too long - sorry.");
- #ifdef PASSWORD
- strcpy(Password, ppp->pw_passwd);
- #endif
-
- if (!detached && !lsflag)
- {
- /* ttyname implies isatty */
- if (!(attach_tty = ttyname(0)))
- {
- #ifdef NETHACK
- if (nethackflag)
- Panic(0, "You must play from a terminal.");
- else
- #endif
- Panic(0, "Must be connected to a terminal.");
- exit(1);
- }
- if (strlen(attach_tty) >= MAXPATHLEN)
- Panic(0, "TtyName too long - sorry.");
- if (stat(attach_tty, &st))
- Panic(errno, "Cannot access '%s'", attach_tty);
- #ifdef MULTIUSER
- tty_mode = st.st_mode & 0777;
- #endif
- if ((n = secopen(attach_tty, O_RDWR, 0)) < 0)
- Panic(0, "Cannot open '%s' - please check.", attach_tty);
- close(n);
- debug1("attach_tty is %s\n", attach_tty);
- if ((attach_term = getenv("TERM")) == 0)
- Panic(0, "Please set a terminal type.");
- if (strlen(attach_term) > sizeof(d_termname) - 1)
- Panic(0, "$TERM too long - sorry.");
- GetTTY(0, &attach_Mode);
- #ifdef DEBUGGGGGGGGGGGGGGG
- DebugTTY(&attach_Mode);
- #endif /* DEBUG */
- }
-
- #ifdef _MODE_T
- oumask = umask(0); /* well, unsigned never fails? jw. */
- #else
- if ((oumask = umask(0)) == -1)
- Panic(errno, "Cannot change umask to zero");
- #endif
- if ((SockDir = getenv("ISCREENDIR")) == NULL)
- SockDir = getenv("SCREENDIR");
- if (SockDir)
- {
- if (strlen(SockDir) >= MAXPATHLEN - 1)
- Panic(0, "Ridiculously long $(I)SCREENDIR - try again.");
- #ifdef MULTIUSER
- if (multi)
- Panic(0, "No $(I)SCREENDIR with multi screens, please.");
- #endif
- }
- #ifdef MULTIUSER
- if (multiattach)
- {
- # ifndef SOCKDIR
- sprintf(SockPath, "%s/.iscreen", multi_home);
- SockDir = SockPath;
- # else
- SockDir = SOCKDIR;
- sprintf(SockPath, "%s/S-%s", SockDir, multi);
- # endif
- }
- else
- #endif
- {
- #ifndef SOCKDIR
- if (SockDir == 0)
- {
- sprintf(SockPath, "%s/.iscreen", home);
- SockDir = SockPath;
- }
- #endif
- if (SockDir)
- {
- if (access(SockDir, F_OK))
- {
- debug1("SockDir '%s' missing ...\n", SockDir);
- if (UserContext() > 0)
- {
- if (mkdir(SockDir, 0700))
- UserReturn(0);
- UserReturn(1);
- }
- if (UserStatus() <= 0)
- Panic(0, "Cannot make directory '%s'.", SockDir);
- }
- if (SockDir != SockPath)
- strcpy(SockPath, SockDir);
- }
- #ifdef SOCKDIR
- else
- {
- SockDir = SOCKDIR;
- if (stat(SockDir, &st))
- {
- if (mkdir(SockDir, eff_uid ? 0777 : 0755) == -1)
- Panic(errno, "Cannot make directory '%s'", SockDir);
- }
- else
- {
- n = eff_uid ? 0777 : 0755;
- if ((st.st_mode & 0777) != n)
- Panic(0, "Directory '%s' must have mode %03o.", SockDir, n);
- }
- sprintf(SockPath, "%s/S-%s", SockDir, LoginName);
- if (access(SockPath, F_OK))
- {
- if (mkdir(SockPath, 0700) == -1)
- Panic(errno, "Cannot make directory '%s'", SockPath);
- (void) chown(SockPath, real_uid, real_gid);
- }
- }
- #endif
- }
-
- if (stat(SockPath, &st) == -1)
- {
- Panic(errno, "Cannot access %s", SockPath);
- }
- else
- {
- #ifdef _POSIX_SOURCE
- if (S_ISDIR(st.st_mode) == 0)
- #else
- if ((st.st_mode & S_IFMT) != S_IFDIR)
- #endif
- Panic(0, "%s is not a directory.", SockPath);
- #ifdef MULTIUSER
- if (multi)
- {
- if (st.st_uid != multi_uid)
- Panic(0, "%s is not the owner of %s.", multi, SockPath);
- }
- else
- #endif
- {
- if (st.st_uid != real_uid)
- Panic(0, "You are not the owner of %s.", SockPath);
- }
- if ((st.st_mode & 0777) != 0700)
- Panic(0, "Directory %s must have mode 700.", SockPath);
- }
- strcat(SockPath, "/");
- SockNamePtr = SockPath + strlen(SockPath);
- (void) umask(oumask);
- debug2("SockPath: %s SockName: %s\n", SockPath, SockName ? SockName : "NULL");
-
- #if defined(SYSV) && !defined(ISC)
- if (uname(&utsnam) == -1)
- Panic(0, "uname() failed, errno = %d.", errno);
- else
- {
- strncpy(HostName, utsnam.nodename, MAXSTR);
- HostName[(sizeof(utsnam.nodename) <= MAXSTR) ?
- sizeof(utsnam.nodename) : MAXSTR] = '\0';
- }
- #else
- (void) gethostname(HostName, MAXSTR);
- #endif
- HostName[MAXSTR - 1] = '\0';
- if ((ap = index(HostName, '.')) != NULL)
- *ap = '\0';
-
- if (lsflag)
- {
- int i;
-
- #ifdef MULTIUSER
- if (multi)
- real_uid = multi_uid;
- setuid(real_uid);
- setgid(real_gid);
- eff_uid = real_uid;
- eff_gid = real_gid;
- #endif
- i = FindSocket(0, (int *)NULL);
- /* MakeClientSocket appended the last (Sock)Name there: */
- *SockNamePtr = '\0';
- if (i == 0)
- {
- #ifdef NETHACK
- if (nethackflag)
- Panic(0, "This room is empty (%s).\n", SockPath);
- else
- #endif /* NETHACK */
- Panic(0, "No Sockets found in %s.\n", SockPath);
- }
- Panic(0, "%d Socket%s in %s.\n", i, i > 1 ? "s" : "", SockPath);
- /* NOTREACHED */
- }
- signal(SIG_BYE, AttacherFinit); /* prevent races */
- if (rflag || xflag)
- {
- debug("screen -r: - is there anybody out there?\n");
- #ifdef SHADOWPW
- setspent(); /* open shadow file while we are still root */
- #endif /* SHADOWPW */
- if (Attach(MSG_ATTACH))
- {
- Attacher();
- /* NOTREACHED */
- }
- debug("screen -r: backend not responding -- still crying\n");
- }
- else if (dflag && !mflag)
- {
- (void) Attach(MSG_DETACH);
- Msg(0, "[%s %sdetached.]\n", SockName, (dflag > 1 ? "power " : ""));
- eexit(0);
- /* NOTREACHED */
- }
- if (!SockName && !mflag)
- {
- register char *sty;
- int s;
-
- if ((sty = getenv("STY")) != 0 && *sty != '\0')
- {
- setuid(real_uid);
- setgid(real_gid);
- eff_uid = real_uid;
- eff_gid = real_gid;
- if ((s = MakeClientSocket(1, sty)) > 0)
- {
- nwin_options.args = av;
- SendCreateMsg(s, &nwin);
- close(s);
- }
- exit(0);
- /* NOTREACHED */
- }
- }
- nwin_compose(&nwin_default, &nwin_options, &nwin_default);
- if (SockName && !*SockName)
- SockName = NULL;
- switch (MasterPid = fork())
- {
- case -1:
- Panic(errno, "fork");
- /* NOTREACHED */
- #ifdef FORKDEBUG
- default:
- break;
- case 0:
- MasterPid = getppid();
- #else
- case 0:
- break;
- default:
- #endif
- if (detached)
- exit(0);
- if (SockName)
- {
- /* user started us with -S option */
- sprintf(socknamebuf, "%d.%s", MasterPid, SockName);
- }
- else
- {
- sprintf(socknamebuf, "%d.%s.%s", MasterPid, stripdev(attach_tty),
- HostName);
- }
- for (ap = socknamebuf; *ap; ap++)
- if (*ap == '/')
- *ap = '-';
- SockName = socknamebuf;
- #ifdef SHADOWPW
- setspent(); /* open shadow file while we are still root */
- #endif /* SHADOWPW */
- setuid(real_uid);
- setgid(real_gid);
- eff_uid = real_uid;
- eff_gid = real_gid;
- Attacher();
- /* NOTREACHED */
- }
-
- ap = av0 + strlen(av0) - 1;
- while (ap >= av0)
- {
- if (!strncmp("screen", ap, 6))
- {
- strncpy(ap, "SCREEN", 6); /* name this process "SCREEN-BACKEND" */
- break;
- }
- ap--;
- }
- if (ap < av0)
- *av0 = 'S';
-
- #ifdef DEBUG
- {
- char buf[256];
-
- if (dfp && dfp != stderr)
- fclose(dfp);
- sprintf(buf, "%s/SCREEN.%d", DEBUGDIR, getpid());
- if ((dfp = fopen(buf, "w")) == NULL)
- dfp = stderr;
- else
- (void) chmod(buf, 0666);
- }
- #endif
- if (!detached)
- n = dup(0);
- else
- n = -1;
- freopen("/dev/null", "r", stdin);
- freopen("/dev/null", "w", stdout);
- #ifdef DEBUG
- if (dfp != stderr)
- #endif
- freopen("/dev/null", "w", stderr);
- debug("-- screen.back debug started\n");
-
- if (!detached)
- {
- #ifdef FORKDEBUG
- if (MakeDisplay(LoginName, attach_tty, attach_term, n, MasterPid, &attach_Mode) == 0)
- #else
- if (MakeDisplay(LoginName, attach_tty, attach_term, n, getppid(), &attach_Mode) == 0)
- #endif
- Panic(0, "Could not alloc display");
- }
-
- if (SockName)
- {
- /* user started us with -S option */
- sprintf(socknamebuf, "%d.%s", getpid(), SockName);
- }
- else
- {
- sprintf(socknamebuf, "%d.%s.%s", getpid(), stripdev(attach_tty),
- HostName);
- }
- for (ap = socknamebuf; *ap; ap++)
- if (*ap == '/')
- *ap = '-';
- SockName = socknamebuf;
- ServerSocket = MakeServerSocket();
- #ifdef ETCSCREENRC
- # ifdef ALLOW_SYSSCREENRC
- if ((ap = getenv("SYSSCREENRC")))
- StartRc(ap);
- else
- # endif
- StartRc(ETCSCREENRC);
- #endif
- StartRc(RcFileName);
- # ifdef UTMPOK
- # ifndef UTNOKEEP
- InitUtmp();
- # endif /* UTNOKEEP */
- # endif /* UTMPOK */
- if (display)
- {
- if (InitTermcap(0, 0))
- {
- debug("Could not init termcap - exiting\n");
- fcntl(d_userfd, F_SETFL, 0); /* Flush sets NDELAY */
- freetty();
- if (d_userpid)
- Kill(d_userpid, SIG_BYE);
- eexit(1);
- }
- InitTerm(0);
- #ifdef UTMPOK
- RemoveLoginSlot();
- #endif
- }
- else
- {
- MakeTermcap(1);
- }
- #ifdef LOADAV
- InitLoadav();
- #endif /* LOADAV */
- MakeNewEnv();
- signal(SIGHUP, SigHup);
- signal(SIGINT, Finit);
- signal(SIGQUIT, Finit);
- signal(SIGTERM, Finit);
- #ifdef BSDJOBS
- signal(SIGTTIN, SIG_IGN);
- signal(SIGTTOU, SIG_IGN);
- #endif
- InitKeytab();
- if (display)
- {
- brktty(d_userfd);
- SetMode(&d_OldMode, &d_NewMode);
- /* Note: SetMode must be called _before_ FinishRc. */
- SetTTY(d_userfd, &d_NewMode);
- if (fcntl(d_userfd, F_SETFL, FNDELAY))
- Msg(errno, "Warning: NDELAY fcntl failed");
- }
- else
- brktty(-1); /* just try */
- #ifdef ETCSCREENRC
- # ifdef ALLOW_SYSSCREENRC
- if ((ap = getenv("SYSSCREENRC")))
- FinishRc(ap);
- else
- # endif
- FinishRc(ETCSCREENRC);
- #endif
- FinishRc(RcFileName);
-
- debug2("UID %d EUID %d\n", getuid(), geteuid());
- if (windows == NULL)
- {
- debug("We open one default window, as screenrc did not specify one.\n");
- if (MakeWindow(&nwin) == -1)
- {
- AddStr("Sorry, could not find a PTY.");
- sleep(2);
- Finit(0);
- /* NOTREACHED */
- }
- }
- if (default_startup)
- display_copyright();
- signal(SIGCHLD, SigChld);
- signal(SIGINT, SigInt);
- tv.tv_usec = 0;
- if (rflag == 2)
- {
- #ifdef NETHACK
- if (nethackflag)
- Msg(0, "I can't seem to find a... Hey, wait a minute! Here comes a screen now.");
- else
- #endif
- Msg(0, "New screen...");
- rflag = 0;
- }
-
- Now = time((time_t *)0);
-
- for (;;)
- {
- tv.tv_sec = 0;
- /*
- * check for silence
- */
- for (p = windows; p; p = p->w_next)
- {
- int time_left;
-
- if (p->w_tstamp.seconds == 0)
- continue;
- debug1("checking silence win %d\n", p->w_number);
- time_left = p->w_tstamp.lastio + p->w_tstamp.seconds - Now;
- if (time_left > 0)
- {
- if (tv.tv_sec == 0 || time_left < tv.tv_sec)
- tv.tv_sec = time_left;
- }
- else
- {
- for (display = displays; display; display = display->_d_next)
- if (p != d_fore)
- Msg(0, "Window %d: silence for %d seconds",
- p->w_number, p->w_tstamp.seconds);
- p->w_tstamp.lastio = Now;
- }
- }
-
- /*
- * check to see if message line should be removed
- */
- for (display = displays; display; display = display->_d_next)
- {
- int time_left;
-
- if (d_status == 0)
- continue;
- debug("checking status...\n");
- time_left = d_status_time + (d_status_bell?VBellWait:MsgWait) - Now;
- if (time_left > 0)
- {
- if (tv.tv_sec == 0 || time_left < tv.tv_sec)
- tv.tv_sec = time_left;
- debug(" not yet.\n");
- }
- else
- {
- debug(" removing now.\n");
- RemoveStatus();
- }
- }
- /*
- * check for I/O on all available I/O descriptors
- */
- #ifdef DEBUG
- if (tv.tv_sec)
- debug1("select timeout %d seconds\n", tv.tv_sec);
- #endif
- mkfdsets(&r, &w);
- if (GotSigChld && !tv.tv_sec)
- {
- SigChldHandler();
- continue;
- }
- if ((nsel = select(FD_SETSIZE, &r, &w, (fd_set *)0, tv.tv_sec ? &tv : (struct timeval *) 0)) < 0)
- {
- debug1("Bad select - errno %d\n", errno);
- if (errno != EINTR)
- Panic(errno, "select");
- errno = 0;
- nsel = 0;
- }
- #ifdef SELECT_BROKEN
- /*
- * Sequents select emulation counts an descriptor which is
- * readable and writeable only as one. waaaaa.
- */
- if (nsel)
- nsel = 2 * FD_SETSIZE;
- #endif
- if (GotSigChld && !tv.tv_sec)
- {
- SigChldHandler();
- continue;
- }
- if (InterruptPlease)
- {
- debug("Backend received interrupt\n");
- if (fore)
- {
- char ibuf;
- ibuf = intrc;
- #ifdef PSEUDOS
- write(W_UWP(fore) ? fore->w_pwin->p_ptyfd : fore->w_ptyfd,
- &ibuf, 1);
- debug1("Backend wrote interrupt to %d", fore->w_number);
- debug1("%s\n", W_UWP(fore) ? " (pseudowin)" : "");
- #else
- write(fore->w_ptyfd, &ibuf, 1);
- debug1("Backend wrote interrupt to %d\n", fore->w_number);
- #endif
- }
- InterruptPlease = 0;
- }
-
- /*
- * Process a client connect attempt and message
- */
- if (nsel && FD_ISSET(ServerSocket, &r))
- {
- nsel--;
- debug("Knock - knock!\n");
- ReceiveMsg();
- continue;
- }
-
- /*
- * Write the (already processed) user input to the window
- * descriptors first. We do not want to choke, if he types fast.
- */
- if (nsel)
- {
- for (p = windows; p; p = p->w_next)
- {
- int pastefd = -1;
-
- if (p->w_ptyfd < 0)
- continue;
- #ifdef COPY_PASTE
- if (p->w_pastelen)
- {
- /*
- * Write the copybuffer contents first, if any.
- */
- #ifdef PSEUDOS
- pastefd = W_UWP(p) ? p->w_pwin->p_ptyfd : p->w_ptyfd;
- #else
- pastefd = p->w_ptyfd;
- #endif
- if (FD_ISSET(pastefd, &w))
- {
- debug1("writing pastebuffer (%d)\n", p->w_pastelen);
- len = write(pastefd, p->w_pasteptr,
- (slowpaste > 0) ? 1 :
- (p->w_pastelen > IOSIZE ?
- IOSIZE : p->w_pastelen));
- if (len < 0) /* Problems... window is dead */
- p->w_pastelen = 0;
- if (len > 0)
- {
- p->w_pasteptr += len;
- p->w_pastelen -= len;
- }
- debug1("%d bytes pasted\n", len);
- if (p->w_pastelen == 0)
- {
- if (p->w_pastebuf)
- free(p->w_pastebuf);
- p->w_pasteptr = 0;
- pastefd = -1;
- }
- if (slowpaste > 0)
- {
- struct timeval t;
-
- debug1("slowpaste %d\n", slowpaste);
- t.tv_sec = (long) (slowpaste / 1000);
- t.tv_usec = (long) ((slowpaste % 1000) * 1000);
- select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &t);
- }
- if (--nsel == 0)
- break;
- }
- }
- #endif
-
- #ifdef PSEUDOS
- if (p->w_pwin && p->w_pwin->p_inlen > 0)
- {
- /* stuff w_pwin->p_inbuf into pseudowin */
- tmp = p->w_pwin->p_ptyfd;
- if (tmp != pastefd && FD_ISSET(tmp, &w))
- {
- if ((len = write(tmp, p->w_pwin->p_inbuf,
- p->w_pwin->p_inlen)) > 0)
- {
- if ((p->w_pwin->p_inlen -= len))
- bcopy(p->w_pwin->p_inbuf + len, p->w_pwin->p_inbuf,
- p->w_pwin->p_inlen);
- }
- if (--nsel == 0)
- break;
- }
- }
- #endif
- if (p->w_inlen > 0)
- {
- /* stuff w_inbuf buffer into window */
- tmp = p->w_ptyfd;
- if (tmp != pastefd && FD_ISSET(tmp, &w))
- {
- if ((len = write(tmp, p->w_inbuf, p->w_inlen)) > 0)
- {
- if ((p->w_inlen -= len))
- bcopy(p->w_inbuf + len, p->w_inbuf, p->w_inlen);
- }
- if (--nsel == 0)
- break;
- }
- }
- }
- }
-
- Now = time((time_t *)0);
-
- if (nsel)
- {
- for (display = displays; display; display = ndisplay)
- {
- int maxlen;
-
- ndisplay = display->_d_next;
- /*
- * stuff d_obuf into user's tty
- */
- if (FD_ISSET(d_userfd, &w))
- {
- int size = OUTPUT_BLOCK_SIZE;
-
- len = d_obufp - d_obuf;
- if (len < size)
- size = len;
- ASSERT(len >= 0);
- size = write(d_userfd, d_obuf, size);
- if (size >= 0)
- {
- len -= size;
- if (len)
- {
- bcopy(d_obuf + size, d_obuf, len);
- debug2("ASYNC: wrote %d - remaining %d\n", size, len);
- }
- d_obufp -= size;
- d_obuffree += size;
- }
- else
- {
- if (errno != EINTR)
- # ifdef EWOULDBLOCK
- if (errno != EWOULDBLOCK)
- # endif
- Msg(errno, "Error writing output to display");
- }
- if (--nsel == 0)
- break;
- }
- /*
- * O.k. All streams are fed, now look what comes back
- * to us. First of all: user input.
- */
- if (! FD_ISSET(d_userfd, &r))
- continue;
- if (d_status && !(use_hardstatus && HS))
- RemoveStatus();
- if (d_fore == 0)
- maxlen = IOSIZE;
- else
- {
- #ifdef PSEUDOS
- if (W_UWP(d_fore))
- maxlen = sizeof(d_fore->w_pwin->p_inbuf) - d_fore->w_pwin->p_inlen;
- else
- #endif
- maxlen = sizeof(d_fore->w_inbuf) - d_fore->w_inlen;
- }
- if (maxlen > IOSIZE)
- maxlen = IOSIZE;
- if (maxlen <= 0)
- maxlen = 1; /* Allow one char for command keys */
- if (d_ESCseen)
- {
- if (maxlen == 1)
- maxlen = 2; /* Allow one char for command keys */
- buf[0] = d_user->u_Esc;
- buflen = read(d_userfd, buf + 1, maxlen - 1) + 1;
- d_ESCseen = 0;
- }
- else
- buflen = read(d_userfd, buf, maxlen);
- if (buflen < 0)
- {
- if (errno == EINTR)
- continue;
- debug1("Read error: %d - SigHup()ing!\n", errno);
- SigHup(SIGARG);
- sleep(1);
- }
- else if (buflen == 0)
- {
- debug("Found EOF - SigHup()ing!\n");
- SigHup(SIGARG);
- sleep(1);
- }
- else
- {
- /* This refills inbuf or p_inbuf */
- ProcessInput(buf, buflen);
- }
- if (--nsel == 0)
- break;
- }
- }
-
- /*
- * Read and process the output from the window descriptors
- */
- for (p = windows; p; p = p->w_next)
- {
- if (p->w_lay->l_block)
- continue;
- display = p->w_display;
- if (p->w_outlen)
- WriteString(p, p->w_outbuf, p->w_outlen);
- else if (p->w_ptyfd >= 0)
- {
- #ifdef PSEUDOS
- /* gather pseudowin output */
- if (W_RP(p) && nsel && FD_ISSET(p->w_pwin->p_ptyfd, &r))
- {
- nsel--;
- n = 0;
- if (W_PTOW(p))
- {
- /* Window wants a copy of the pseudowin output */
- tmp = sizeof(p->w_inbuf) - p->w_inlen;
- ASSERT(tmp > 0);
- n++;
- }
- else
- tmp = IOSIZE;
- if ((len = read(p->w_pwin->p_ptyfd, buf, tmp)) <= 0)
- {
- if (errno != EINTR)
- #ifdef EWOULDBLOCK
- if (errno != EWOULDBLOCK)
- #endif
- {
- debug2("Window %d: pseudowin read error (errno %d) -- removing pseudowin\n", p->w_number, len ? errno : 0);
- FreePseudowin(p);
- }
- }
- /* HERE WE ASSUME THAT THERE IS NO PACKET MODE ON PSEUDOWINS */
- else
- {
- if (n)
- {
- bcopy(buf, p->w_inbuf + p->w_inlen, len);
- p->w_inlen += len;
- }
- WriteString(p, buf, len);
- }
- }
- #endif /* PSEUDOS */
- /* gather window output */
- if (nsel && FD_ISSET(p->w_ptyfd, &r))
- {
- nsel--;
- #ifdef PSEUDOS
- n = 0;
- ASSERT(W_RW(p));
- if (p->w_pwin && W_WTOP(p))
- {
- /* Pseudowin wants a copy of the window output */
- tmp = sizeof(p->w_pwin->p_inbuf) - p->w_pwin->p_inlen;
- ASSERT(tmp > 0);
- n++;
- }
- else
- #endif
- tmp = IOSIZE;
- if ((len = read(p->w_ptyfd, buf, tmp)) <= 0)
- {
- if (errno == EINTR)
- continue;
- #ifdef EWOULDBLOCK
- if (errno == EWOULDBLOCK)
- continue;
- #endif
- debug2("Window %d: read error (errno %d) - killing window\n", p->w_number, len ? errno : 0);
- if (ZombieKey)
- {
- debug3("window %d (%s) going into zombie state fd %d",
- p->w_number, p->w_title, p->w_ptyfd);
- p->w_ptyfd = -1;
- debug("changed to -1\n");
- }
- else
- KillWindow(p);
- nsel = 0; /* KillWindow may change window order */
- break; /* so we just break */
- }
- #ifdef TIOCPKT
- if ((p->w_t.flags & TTY_FLAG_PLAIN) == 0)
- {
- if (buf[0])
- {
- debug1("PAKET %x\n", buf[0]);
- if (buf[0] & TIOCPKT_NOSTOP)
- NewAutoFlow(p, 0);
- if (buf[0] & TIOCPKT_DOSTOP)
- NewAutoFlow(p, 1);
- }
- if (len > 1)
- {
- #ifdef PSEUDOS
- if (n)
- {
- bcopy(buf + 1,
- p->w_pwin->p_inbuf + p->w_pwin->p_inlen,
- len - 1);
- p->w_pwin->p_inlen += len - 1;
- }
- #endif
- WriteString(p, buf + 1, len - 1);
- }
- }
- else
- #endif /* TIOCPKT */
- {
- if (len > 0)
- {
- #ifdef PSEUDOS
- if (n)
- {
- bcopy(buf, p->w_pwin->p_inbuf + p->w_pwin->p_inlen,
- len);
- p->w_pwin->p_inlen += len;
- }
- #endif
- WriteString(p, buf, len);
- }
- }
- }
- }
- if (p->w_bell == BELL_ON)
- {
- p->w_bell = BELL_MSG;
- for (display = displays; display; display = display->_d_next)
- Msg(0, MakeWinMsg(BellString, p->w_number));
- if (p->w_monitor == MON_FOUND)
- p->w_monitor = MON_DONE;
- }
- else if (p->w_bell == BELL_VISUAL)
- {
- if (display && !d_status_bell)
- {
- /*
- * Stop the '!' appearing in the ^A^W display if it is an
- * active at the time of the bell. (Tim MacKenzie)
- */
- p->w_bell = BELL_OFF;
- Msg(0, VisualBellString);
- if (d_status)
- d_status_bell = 1;
- }
- }
- if (p->w_monitor == MON_FOUND)
- {
- p->w_monitor = MON_MSG;
- for (display = displays; display; display = display->_d_next)
- Msg(0, MakeWinMsg(ActivityString, p->w_number));
- }
- }
- #if defined(DEBUG) && !defined(_SEQUENT_)
- if (nsel)
- debug1("*** Left over nsel: %d\n", nsel);
- #endif
- }
- /* NOTREACHED */
- }
-
- static void
- SigChldHandler()
- {
- struct stat st;
- while (GotSigChld)
- {
- GotSigChld = 0;
- DoWait();
- #ifdef SYSVSIGS
- signal(SIGCHLD, SigChld);
- #endif
- }
- if (stat(SockPath, &st) == -1)
- {
- debug1("SigChldHandler: Yuck! cannot stat '%s'\n", SockPath);
- if (!RecoverSocket())
- {
- debug("SCREEN cannot recover from corrupt Socket, bye\n");
- Finit(1);
- }
- else
- debug1("'%s' reconstructed\n", SockPath);
- }
- else
- debug2("SigChldHandler: stat '%s' o.k. (%03o)\n", SockPath, st.st_mode);
- }
-
- static sig_t
- SigChld(SIGDEFARG)
- {
- debug("SigChld()\n");
- GotSigChld = 1;
- #ifndef SIGVOID
- return((sig_t) 0);
- #endif
- }
-
- sig_t
- SigHup(SIGDEFARG)
- {
- if (display == 0)
- return;
- debug("SigHup()\n");
- if (d_userfd >= 0)
- {
- close(d_userfd);
- d_userfd = -1;
- }
- if (auto_detach || displays->_d_next)
- Detach(D_DETACH);
- else
- Finit(0);
- #ifndef SIGVOID
- return((sig_t) 0);
- #endif
- }
-
- /*
- * the backend's Interrupt handler
- * we cannot d_insert the intrc directly, as we never know
- * if fore is valid.
- */
- static sig_t
- SigInt(SIGDEFARG)
- {
- #if HAZARDOUS
- char buf[1];
-
- debug("SigInt()\n");
- *buf = (char) intrc;
- if (fore)
- fore->w_inlen = 0;
- if (fore)
- write(fore->w_ptyfd, buf, 1);
- #else
- signal(SIGINT, SigInt);
- debug("SigInt() careful\n");
- InterruptPlease = 1;
- #endif
- #ifndef SIGVOID
- return((sig_t) 0);
- #endif
- }
-
- static sig_t
- CoreDump(sig)
- int sig;
- {
- struct display *disp;
- char buf[80];
-
- #ifdef SYSVSIGS
- signal(sig, SIG_IGN);
- #endif /* SYSV */
- setgid(getgid());
- setuid(getuid());
- unlink("core");
- sprintf(buf, "\r\n[screen caught signal %d.%s]\r\n", sig,
- #if defined(SHADOWPW) && !defined(DEBUG) && !defined(DUMPSHADOW)
- ""
- #else /* SHADOWPW && !DEBUG */
- " (core dumped)"
- #endif /* SHADOWPW && !DEBUG */
- );
- for (disp = displays; disp; disp = disp->_d_next)
- {
- fcntl(disp->_d_userfd, F_SETFL, 0);
- write(disp->_d_userfd, buf, strlen(buf));
- Kill(disp->_d_userpid, SIG_BYE);
- }
- #if defined(SHADOWPW) && !defined(DEBUG) && !defined(DUMPSHADOW)
- eexit(sig);
- #else /* SHADOWPW && !DEBUG */
- abort();
- #endif /* SHADOWPW && !DEBUG */
- #ifndef SIGVOID
- return((sig_t) 0);
- #endif
- }
-
- static void
- DoWait()
- {
- register int pid;
- struct win *p, *next;
- #ifdef BSDWAIT
- union wait wstat;
- #else
- int wstat;
- #endif
-
- #ifdef BSDJOBS
- # ifndef BSDWAIT
- while ((pid = waitpid(-1, &wstat, WNOHANG | WUNTRACED)) > 0)
- # else
- # ifdef USE_WAIT2
- /*
- * From: rouilj@sni-usa.com (John Rouillard)
- * note that WUNTRACED is not documented to work, but it is defined in
- * /usr/include/sys/wait.h, so it may work
- */
- while ((pid = wait2(&wstat, WNOHANG | WUNTRACED )) > 0)
- # else /* USE_WAIT2 */
- while ((pid = wait3(&wstat, WNOHANG | WUNTRACED, (struct rusage *) 0)) > 0)
- # endif /* USE_WAIT2 */
- # endif
- #else /* BSDJOBS */
- while ((pid = wait(&wstat)) < 0)
- if (errno != EINTR)
- break;
- if (pid > 0)
- #endif /* BSDJOBS */
- {
- for (p = windows; p; p = next)
- {
- next = p->w_next;
- if (pid == p->w_pid)
- {
- #ifdef BSDJOBS
- if (WIFSTOPPED(wstat))
- {
- debug3("Window %d pid %d: WIFSTOPPED (sig %d)\n", p->w_number, p->w_pid, WSTOPSIG(wstat));
- #ifdef SIGTTIN
- if (WSTOPSIG(wstat) == SIGTTIN)
- {
- Msg(0, "Suspended (tty input)");
- continue;
- }
- #endif
- #ifdef SIGTTOU
- if (WSTOPSIG(wstat) == SIGTTOU)
- {
- Msg(0, "Suspended (tty output)");
- continue;
- }
- #endif
- /* Try to restart process */
- # ifdef NETHACK
- if (nethackflag)
- Msg(0, "You regain consciousness.");
- else
- # endif /* NETHACK */
- Msg(0, "Child has been stopped, restarting.");
- if (killpg(p->w_pid, SIGCONT))
- kill(p->w_pid, SIGCONT);
- }
- else
- #endif
- {
- if (ZombieKey)
- {
- debug3("window %d (%s) going into zombie state fd %d",
- p->w_number, p->w_title, p->w_ptyfd);
- p->w_ptyfd = -1;
- debug("changed to -1\n");
- }
- else
- KillWindow(p);
- }
- break;
- }
- #ifdef PSEUDOS
- if (p->w_pwin && pid == p->w_pwin->p_pid)
- {
- debug2("pseudo of win Nr %d died. pid == %d\n", p->w_number, p->w_pwin->p_pid);
- FreePseudowin(p);
- break;
- }
- #endif
- }
- if (p == 0)
- {
- debug1("pid %d not found - hope that's ok\n", pid);
- }
- }
- }
-
-
- sig_t
- Finit(i)
- int i;
- {
- struct win *p, *next;
-
- signal(SIGCHLD, SIG_IGN);
- signal(SIGHUP, SIG_IGN);
- debug1("Finit(%d);\n", i);
- for (p = windows; p; p = next)
- {
- next = p->w_next;
- FreeWindow(p);
- }
- if (ServerSocket != -1)
- {
- debug1("we unlink(%s)\n", SockPath);
- #ifndef NOREUID
- setreuid(eff_uid, real_uid);
- setregid(eff_gid, real_gid);
- #endif
- (void) unlink(SockPath);
- #ifndef NOREUID
- setreuid(real_uid, eff_uid);
- setregid(real_gid, eff_gid);
- #endif
- }
- for (display = displays; display; display = display->_d_next)
- {
- if (d_status)
- RemoveStatus();
- FinitTerm();
- #ifdef UTMPOK
- RestoreLoginSlot();
- #endif
- AddStr("[screen is terminating]\r\n");
- Flush();
- SetTTY(d_userfd, &d_OldMode);
- fcntl(d_userfd, F_SETFL, 0);
- freetty();
- Kill(d_userpid, SIG_BYE);
- }
- /*
- * we _cannot_ call eexit(i) here,
- * instead of playing with the Socket above. Sigh.
- */
- exit(i);
- #ifndef SIGVOID
- return((sig_t) 0);
- #endif
- }
-
- void
- eexit(e)
- int e;
- {
- if (ServerSocket != -1)
- {
- debug1("we unlink(%s)\n", SockPath);
- setuid(real_uid);
- setgid(real_gid);
- (void) unlink(SockPath);
- }
- exit(e);
- }
-
-
- /*
- * Detach now has the following modes:
- * D_DETACH SIG_BYE detach backend and exit attacher
- * D_STOP SIG_STOP stop attacher (and detach backend)
- * D_REMOTE SIG_BYE remote detach -- reattach to new attacher
- * D_POWER SIG_POWER_BYE power detach -- attacher kills his parent
- * D_REMOTE_POWER SIG_POWER_BYE remote power detach -- both
- * D_LOCK SIG_LOCK lock the attacher
- * (jw)
- * we always remove our utmp slots. (even when "lock" or "stop")
- * Note: Take extra care here, we may be called by interrupt!
- */
- void
- Detach(mode)
- int mode;
- {
- int sign = 0, pid;
- #ifdef UTMPOK
- struct win *p;
- #endif
-
- if (display == 0)
- return;
- signal(SIGHUP, SIG_IGN);
- debug1("Detach(%d)\n", mode);
- if (d_status)
- RemoveStatus();
- FinitTerm();
- switch (mode)
- {
- case D_DETACH:
- AddStr("[detached]\r\n");
- sign = SIG_BYE;
- break;
- #ifdef BSDJOBS
- case D_STOP:
- sign = SIG_STOP;
- break;
- #endif
- #ifdef REMOTE_DETACH
- case D_REMOTE:
- AddStr("[remote detached]\r\n");
- sign = SIG_BYE;
- break;
- #endif
- #ifdef POW_DETACH
- case D_POWER:
- AddStr("[power detached]\r\n");
- if (PowDetachString)
- {
- AddStr(expand_vars(PowDetachString));
- AddStr("\r\n");
- }
- sign = SIG_POWER_BYE;
- break;
- #ifdef REMOTE_DETACH
- case D_REMOTE_POWER:
- AddStr("[remote power detached]\r\n");
- if (PowDetachString)
- {
- AddStr(expand_vars(PowDetachString));
- AddStr("\r\n");
- }
- sign = SIG_POWER_BYE;
- break;
- #endif
- #endif
- case D_LOCK:
- ClearDisplay();
- sign = SIG_LOCK;
- /* tell attacher to lock terminal with a lockprg. */
- break;
- }
- #ifdef UTMPOK
- if (displays->_d_next == 0)
- {
- for (p = windows; p; p = p->w_next)
- if (p->w_slot != (slot_t) -1)
- {
- RemoveUtmp(p);
- /*
- * Set the slot to 0 to get the window
- * logged in again.
- */
- p->w_slot = (slot_t) 0;
- }
- if (console_window)
- {
- if (TtyGrabConsole(console_window->w_ptyfd, 0, "detach"))
- {
- debug("could not release console - killing window\n");
- KillWindow(console_window);
- display = displays;
- }
- }
- }
- RestoreLoginSlot();
- #endif
- if (d_fore)
- {
- ReleaseAutoWritelock(display, d_fore);
- if (d_fore->w_tstamp.seconds)
- d_fore->w_tstamp.lastio = Now;
- d_fore->w_active = 0;
- d_fore->w_display = 0;
- d_lay = &BlankLayer;
- d_layfn = d_lay->l_layfn;
- d_user->u_detachwin = d_fore->w_number;
- }
- while (d_lay != &BlankLayer)
- ExitOverlayPage();
- if (d_userfd >= 0)
- {
- Flush();
- SetTTY(d_userfd, &d_OldMode);
- fcntl(d_userfd, F_SETFL, 0);
- }
- freetty();
- pid = d_userpid;
- debug2("display: %#x displays: %#x\n", (unsigned int)display, (unsigned int)displays);
- FreeDisplay();
- if (displays == 0)
- /* Flag detached-ness */
- (void) chsock();
- /*
- * tell father to father what to do. We do that after we
- * freed the tty, thus getty feels more comfortable on hpux
- * if it was a power detach.
- */
- Kill(pid, sign);
- debug2("Detach: Signal %d to Attacher(%d)!\n", sign, pid);
- debug("Detach returns, we are successfully detached.\n");
- signal(SIGHUP, SigHup);
- }
-
- static int
- IsSymbol(e, s)
- register char *e, *s;
- {
- register int l;
-
- l = strlen(s);
- return strncmp(e, s, l) == 0 && e[l] == '=';
- }
-
- void
- MakeNewEnv()
- {
- register char **op, **np;
- static char stybuf[MAXSTR];
-
- for (op = environ; *op; ++op)
- ;
- if (NewEnv)
- free(NewEnv);
- NewEnv = np = (char **) malloc((unsigned) (op - environ + 7 + 1) * sizeof(char **));
- if (!NewEnv)
- Panic(0, strnomem);
- SockName = SockNamePtr;
- if (strlen(SockNamePtr) > MAXSTR - 5)
- SockName = "?";
- sprintf(stybuf, "STY=%s", SockNamePtr);
- *np++ = stybuf; /* NewEnv[0] */
- *np++ = Term; /* NewEnv[1] */
- np++; /* room for SHELL */
- #ifdef TIOCSWINSZ
- np += 2; /* room for TERMCAP and WINDOW */
- #else
- np += 4; /* room for TERMCAP WINDOW LINES COLUMNS */
- #endif
-
- for (op = environ; *op; ++op)
- {
- debug1("MakeNewEnv: %s\n", *op);
- if (!IsSymbol(*op, "TERM") && !IsSymbol(*op, "TERMCAP")
- && !IsSymbol(*op, "STY") && !IsSymbol(*op, "WINDOW")
- && !IsSymbol(*op, "SCREENCAP") && !IsSymbol(*op, "SHELL")
- && !IsSymbol(*op, "LINES") && !IsSymbol(*op, "COLUMNS")
- )
- *np++ = *op;
- }
- *np = 0;
- }
-
- void
- #ifdef USEVARARGS
- /*VARARGS2*/
- # if defined(__STDC__)
- Msg(int err, char *fmt, ...)
- # else /* __STDC__ */
- Msg(err, fmt, va_alist)
- int err;
- char *fmt;
- va_dcl
- # endif /* __STDC__ */
- {
- static va_list ap;
- #else /* USEVARARRGS */
- /*VARARGS2*/
- Msg(err, fmt, p1, p2, p3, p4, p5, p6)
- int err;
- char *fmt;
- unsigned long p1, p2, p3, p4, p5, p6;
- {
- #endif /* USEVARARRGS */
- char buf[MAXPATHLEN*2];
- char *p = buf;
-
- #ifdef USEVARARGS
- # if defined(__STDC__)
- va_start(ap, fmt);
- # else /* __STDC__ */
- va_start(ap);
- # endif /* __STDC__ */
- (void) vsprintf(p, fmt, ap);
- va_end(ap);
- #else /* USEVARARRGS */
- sprintf(p, fmt, p1, p2, p3, p4, p5, p6);
- #endif /* USEVARARRGS */
- if (err)
- {
- p += strlen(p);
- if (err > 0 && err < sys_nerr)
- sprintf(p, ": %s", sys_errlist[err]);
- else
- sprintf(p, ": Error %d", err);
- }
- debug2("Msg('%s') (%#x);\n", buf, (unsigned int)display);
- if (display)
- MakeStatus(buf);
- else if (displays)
- {
- for (display = displays; display; display = display->_d_next)
- MakeStatus(buf);
- }
- else
- printf("%s\r\n", buf);
- }
-
- void
- #ifdef USEVARARGS
- /*VARARGS2*/
- # if defined(__STDC__)
- Panic(int err, char *fmt, ...)
- # else /* __STDC__ */
- Panic(err, fmt, va_alist)
- int err;
- char *fmt;
- va_dcl
- # endif /* __STDC__ */
- {
- static va_list ap;
- #else /* USEVARARRGS */
- /*VARARGS2*/
- Panic(err, fmt, p1, p2, p3, p4, p5, p6)
- int err;
- char *fmt;
- unsigned long p1, p2, p3, p4, p5, p6;
- {
- #endif /* USEVARARRGS */
- char buf[MAXPATHLEN*2];
- char *p = buf;
-
- #ifdef USEVARARGS
- # if defined(__STDC__)
- va_start(ap, fmt);
- # else /* __STDC__ */
- va_start(ap);
- # endif /* __STDC__ */
- (void) vsprintf(p, fmt, ap);
- va_end(ap);
- #else /* USEVARARRGS */
- sprintf(p, fmt, p1, p2, p3, p4, p5, p6);
- #endif /* USEVARARRGS */
- if (err)
- {
- p += strlen(p);
- if (err > 0 && err < sys_nerr)
- sprintf(p, ": %s", sys_errlist[err]);
- else
- sprintf(p, ": Error %d", err);
- }
- debug1("Panic('%s');\n", buf);
- if (displays == 0)
- printf("%s\r\n", buf);
- else
- for (display = displays; display; display = display->_d_next)
- {
- if (d_status)
- RemoveStatus();
- FinitTerm();
- Flush();
- #ifdef UTMPOK
- RestoreLoginSlot();
- #endif
- SetTTY(d_userfd, &d_OldMode);
- fcntl(d_userfd, F_SETFL, 0);
- write(d_userfd, buf, strlen(buf));
- write(d_userfd, "\n", 1);
- freetty();
- if (d_userpid)
- Kill(d_userpid, SIG_BYE);
- }
- #ifdef MULTIUSER
- if (tty_oldmode >= 0)
- {
- # ifdef NOREUID
- setuid(eff_uid);
- # else
- setreuid(real_uid, eff_uid);
- # endif
- debug1("Panic: changing back modes from %s\n", attach_tty);
- chmod(attach_tty, tty_oldmode);
- }
- #endif
- eexit(1);
- }
-
-
- /*
- * '^' is allowed as an escape mechanism for control characters. jw.
- */
- static char *
- MakeWinMsg(s, n)
- register char *s;
- int n;
- {
- static char buf[MAXSTR];
- register char *p = buf;
- register int ctrl;
-
- ctrl = 0;
- for (; *s && p < buf + MAXSTR - 1; s++, p++)
- if (ctrl)
- {
- ctrl = 0;
- if (*s == '^' || *s < 64)
- *p = *s;
- else
- *p = *s - 64;
- }
- else
- {
- switch (*s)
- {
- case '%':
- sprintf(p, "%d", n);
- p += strlen(p) - 1;
- break;
- case '~':
- *p = BELL;
- break;
- case '^':
- ctrl = 1;
- *p-- = '^';
- break;
- default:
- *p = *s;
- break;
- }
- }
- *p = '\0';
- return buf;
- }
-
- void
- DisplaySleep(n)
- int n;
- {
- char buf;
- fd_set r;
- struct timeval t;
-
- if (!display)
- {
- debug("DisplaySleep has no display sigh\n");
- sleep(n);
- return;
- }
- t.tv_usec = 0;
- t.tv_sec = n;
- FD_ZERO(&r);
- FD_SET(d_userfd, &r);
- if (select(FD_SETSIZE, &r, (fd_set *)0, (fd_set *)0, &t) > 0)
- {
- debug("display activity stopped sleep\n");
- read(d_userfd, &buf, 1);
- }
- debug1("DisplaySleep(%d) ending\n", n);
- }
-