/* 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., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * **************************************************************** */ #include "rcs.h" RCS_ID("$Id: window.c,v 1.20 1994/05/31 12:33:24 mlschroe Exp $ FAU") #include #include #include #include #ifndef sun #include #endif #include "config.h" #ifdef SVR4 # include #endif #include "screen.h" #include "extern.h" extern struct display *displays, *display; extern struct win *windows, *fore, *wtab[], *console_window; extern char *ShellArgs[]; extern char *ShellProg; extern char screenterm[]; extern char HostName[]; extern int TtyMode; extern struct LayFuncs WinLf; extern int real_uid, real_gid, eff_uid, eff_gid; extern char Termcap[]; extern char **NewEnv; #if defined(TIOCSWINSZ) || defined(TIOCGWINSZ) extern struct winsize glwz; #endif #ifdef _IBMR2 extern int aixhack; #endif static int OpenDevice __P((char *, int, int *, char **)); static int ForkWindow __P((char **, char *, char *, char *, struct win *)); static void execvpe __P((char *, char **, char **)); char DefaultShell[] = "/bin/sh"; static char DefaultPath[] = ":/usr/ucb:/bin:/usr/bin"; struct NewWindow nwin_undef = { -1, (char *)0, (char **)0, (char *)0, (char *)0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, (char *)0, (char *)0 }; struct NewWindow nwin_default = { 0, (char *)0, ShellArgs, (char *)0, screenterm, 0, 1*FLOW_NOW, LOGINDEFAULT, DEFAULTHISTHEIGHT, MON_OFF, WLOCK_AUTO, 1, 1, 0, 0, (char *)0, (char *)0 }; struct NewWindow nwin_options; void nwin_compose(def, new, res) struct NewWindow *def, *new, *res; { res->StartAt = new->StartAt != nwin_undef.StartAt ? new->StartAt : def->StartAt; res->aka = new->aka != nwin_undef.aka ? new->aka : def->aka; res->args = new->args != nwin_undef.args ? new->args : def->args; res->dir = new->dir != nwin_undef.dir ? new->dir : def->dir; res->term = new->term != nwin_undef.term ? new->term : def->term; res->aflag = new->aflag != nwin_undef.aflag ? new->aflag : def->aflag; res->flowflag = new->flowflag != nwin_undef.flowflag ? new->flowflag : def->flowflag; res->lflag = new->lflag != nwin_undef.lflag ? new->lflag : def->lflag; res->histheight = new->histheight != nwin_undef.histheight ? new->histheight : def->histheight; res->monitor = new->monitor != nwin_undef.monitor ? new->monitor : def->monitor; res->wlock = new->wlock != nwin_undef.wlock ? new->wlock : def->wlock; res->wrap = new->wrap != nwin_undef.wrap ? new->wrap : def->wrap; res->c1 = new->c1 != nwin_undef.c1 ? new->c1 : def->c1; res->gr = new->gr != nwin_undef.gr ? new->gr : def->gr; #ifdef KANJI res->kanji = new->kanji != nwin_undef.kanji ? new->kanji : def->kanji; #endif res->hstatus = new->hstatus != nwin_undef.hstatus ? new->hstatus : def->hstatus; res->charset = new->charset != nwin_undef.charset ? new->charset : def->charset; } int MakeWindow(newwin) struct NewWindow *newwin; { register struct win **pp, *p; register int n, i; int f = -1; struct NewWindow nwin; int ttyflag; char *TtyName; debug1("NewWindow: StartAt %d\n", newwin->StartAt); debug1("NewWindow: aka %s\n", newwin->aka?newwin->aka:"NULL"); debug1("NewWindow: dir %s\n", newwin->dir?newwin->dir:"NULL"); debug1("NewWindow: term %s\n", newwin->term?newwin->term:"NULL"); nwin_compose(&nwin_default, newwin, &nwin); debug1("NWin: aka %s\n", nwin.aka ? nwin.aka : "NULL"); debug1("NWin: wlock %d\n", nwin.wlock); pp = wtab + nwin.StartAt; do { if (*pp == 0) break; if (++pp == wtab + MAXWIN) pp = wtab; } while (pp != wtab + nwin.StartAt); if (*pp) { Msg(0, "No more windows."); return -1; } #if defined(USRLIMIT) && defined(UTMPOK) /* * Count current number of users, if logging windows in. */ if (nwin.lflag && CountUsers() >= USRLIMIT) { Msg(0, "User limit reached. Window will not be logged in."); nwin.lflag = 0; } #endif n = pp - wtab; debug1("Makewin creating %d\n", n); if ((f = OpenDevice(nwin.args[0], nwin.lflag, &ttyflag, &TtyName)) < 0) return -1; if ((p = (struct win *) malloc(sizeof(struct win))) == 0) { close(f); Msg(0, strnomem); return -1; } bzero((char *) p, (int) sizeof(struct win)); /* looks like a calloc above */ /* save the command line so that zombies can be resurrected */ for (i = 0; nwin.args[i] && i < MAXARGS - 1; i++) p->w_cmdargs[i] = SaveStr(nwin.args[i]); p->w_cmdargs[i] = 0; #ifdef MULTIUSER if (NewWindowAcl(p)) { free((char *)p); close(f); Msg(0, strnomem); return -1; } #endif p->w_winlay.l_next = 0; p->w_winlay.l_layfn = &WinLf; p->w_winlay.l_data = (char *)p; p->w_lay = &p->w_winlay; p->w_display = display; p->w_pdisplay = 0; #ifdef MULTIUSER if (display && !AclCheckPermWin(D_user, ACL_WRITE, p)) #else if (display) #endif p->w_wlockuser = D_user; p->w_number = n; p->w_ptyfd = f; p->w_aflag = nwin.aflag; p->w_flow = nwin.flowflag | ((nwin.flowflag & FLOW_AUTOFLAG) ? (FLOW_AUTO|FLOW_NOW) : FLOW_AUTO); if (!nwin.aka) nwin.aka = Filename(nwin.args[0]); strncpy(p->w_akabuf, nwin.aka, MAXSTR - 1); if ((nwin.aka = rindex(p->w_akabuf, '|')) != NULL) { p->w_autoaka = 0; *nwin.aka++ = 0; p->w_title = nwin.aka; p->w_akachange = nwin.aka + strlen(nwin.aka); } else p->w_title = p->w_akachange = p->w_akabuf; if (nwin.hstatus) p->w_hstatus = SaveStr(nwin.hstatus); p->w_monitor = nwin.monitor; p->w_norefresh = 0; strncpy(p->w_tty, TtyName, MAXSTR - 1); #ifndef COPY_PASTE nwin.histheight = 0; #endif if (ChangeWindowSize(p, display ? D_defwidth : 80, display ? D_defheight : 24, nwin.histheight)) { FreeWindow(p); return -1; } #ifdef KANJI p->w_kanji = nwin.kanji; #endif ResetWindow(p); /* sets w_wrap, w_c1, w_gr */ if (nwin.charset) SetCharsets(p, nwin.charset); if (ttyflag == TTY_FLAG_PLAIN) { p->w_t.flags |= TTY_FLAG_PLAIN; p->w_pid = 0; } else { debug("forking...\n"); #ifdef PSEUDOS p->w_pwin = NULL; #endif p->w_pid = ForkWindow(nwin.args, nwin.dir, nwin.term, TtyName, p); if (p->w_pid < 0) { FreeWindow(p); return -1; } } /* * Place the newly created window at the head of the most-recently-used list. */ if (display && D_fore) D_other = D_fore; *pp = p; p->w_next = windows; windows = p; #ifdef UTMPOK p->w_slot = (slot_t) -1; # ifdef LOGOUTOK debug1("MakeWindow will %slog in.\n", nwin.lflag?"":"not "); if (nwin.lflag) # else /* LOGOUTOK */ debug1("MakeWindow will log in, LOGOUTOK undefined in config.h%s.\n", nwin.lflag?"":" (although lflag=0)"); # endif /* LOGOUTOK */ { p->w_slot = (slot_t) 0; if (display) SetUtmp(p); } #endif SetForeWindow(p); Activate(p->w_norefresh); return n; } /* * Resurrect a window from Zombie state. * The command vector is therefore stored in the window structure. * Note: The terminaltype defaults to screenterm again, the current * working directory is lost. */ int RemakeWindow(p) struct win *p; { int ttyflag; char *TtyName; int lflag, f; lflag = nwin_default.lflag; if ((f = OpenDevice(p->w_cmdargs[0], lflag, &ttyflag, &TtyName)) < 0) return -1; strncpy(p->w_tty, *TtyName ? TtyName : p->w_title, MAXSTR - 1); p->w_ptyfd = f; p->w_t.flags &= ~TTY_FLAG_PLAIN; if (ttyflag == TTY_FLAG_PLAIN) { p->w_t.flags |= TTY_FLAG_PLAIN; /* Just in case... */ WriteString(p, p->w_cmdargs[0], strlen(p->w_cmdargs[0])); WriteString(p, ": ", 2); WriteString(p, p->w_title, strlen(p->w_title)); WriteString(p, "\r\n", 2); p->w_pid = 0; } else { for (f = 0; p->w_cmdargs[f]; f++) { if (f) WriteString(p, " ", 1); WriteString(p, p->w_cmdargs[f], strlen(p->w_cmdargs[f])); } WriteString(p, "\r\n", 2); p->w_pid = ForkWindow(p->w_cmdargs, (char *)0, nwin_default.term, TtyName, p); if (p->w_pid < 0) return -1; } #ifdef UTMPOK p->w_slot = (slot_t) -1; debug1("RemakeWindow will %slog in.\n", lflag ? "" : "not "); # ifdef LOGOUTOK if (lflag) # endif { p->w_slot = (slot_t) 0; if (display) SetUtmp(p); } #endif return p->w_number; } void FreeWindow(wp) struct win *wp; { struct display *d; int i; #ifdef PSEUDOS if (wp->w_pwin) FreePseudowin(wp); #endif #ifdef UTMPOK RemoveUtmp(wp); #endif if (wp->w_ptyfd >= 0) { (void) chmod(wp->w_tty, 0666); (void) chown(wp->w_tty, 0, 0); close(wp->w_ptyfd); wp->w_ptyfd = -1; } if (wp == console_window) console_window = 0; if (wp->w_logfp != NULL) fclose(wp->w_logfp); ChangeWindowSize(wp, 0, 0, 0); if (wp->w_hstatus) free(wp->w_hstatus); for (i = 0; wp->w_cmdargs[i]; i++) free(wp->w_cmdargs[i]); for (d = displays; d; d = d->d_next) if (d->d_other == wp) d->d_other = 0; #ifdef MULTIUSER for (i = 0; i < ACL_BITS_PER_WIN; i++) free((char *)wp->w_userbits[i]); #endif free((char *)wp); } static int OpenDevice(arg, lflag, typep, namep) char *arg; int lflag; int *typep; char **namep; { struct stat st; int f; if ((stat(arg, &st)) == 0 && S_ISCHR(st.st_mode)) { if (access(arg, R_OK | W_OK) == -1) { Msg(errno, "Cannot access line '%s' for R/W", arg); return -1; } debug("OpenDevice: OpenTTY\n"); if ((f = OpenTTY(arg)) < 0) return -1; *typep = TTY_FLAG_PLAIN; *namep = arg; } else { *typep = 0; /* for now we hope it is a program */ f = OpenPTY(namep); if (f == -1) { Msg(0, "No more PTYs."); return -1; } #ifdef TIOCPKT { int flag = 1; if (ioctl(f, TIOCPKT, (char *)&flag)) { Msg(errno, "TIOCPKT ioctl"); close(f); return -1; } } #endif /* TIOCPKT */ } (void) fcntl(f, F_SETFL, FNBLOCK); #ifdef linux /* * Tenebreux (zeus@ns.acadiacom.net) has Linux 1.3.70 where select gets * confused in the following condition: * Open a pty-master side, request a flush on it, then set packet mode. * and call select(). Select will return a possible read, where the * one byte response to the flush can be found. Select will thereafter * return a possible read, which yields I/O error. * * If we request another flush *after* switching into packet mode, this * I/O error does not occur. We receive a single response byte although we * send two flush requests now. Maybe we should not flush at all. * * 10.5.96 jw. */ tcflush(f, TCIOFLUSH); #endif #ifdef PTYGROUP (void) chown(*namep, real_uid, PTYGROUP); #else (void) chown(*namep, real_uid, real_gid); #endif #ifdef UTMPOK (void) chmod(*namep, lflag ? TtyMode : (TtyMode & ~022)); #else (void) chmod(*namep, TtyMode); #endif return f; } /* * Fields w_width, w_height, aflag, number (and w_tty) * are read from struct win *win. No fields written. * If pwin is nonzero, filedescriptors are distributed * between win->w_tty and open(ttyn) * */ static int ForkWindow(args, dir, term, ttyn, win) char **args, *dir, *term, *ttyn; struct win *win; { int pid; char tebuf[25]; char ebuf[10]; char shellbuf[7 + MAXPATHLEN]; char *proc; #ifndef TIOCSWINSZ char libuf[20], cobuf[20]; #endif int newfd; int w = win->w_width; int h = win->w_height; #ifdef PSEUDOS int i, pat, wfdused; struct pseudowin *pwin = win->w_pwin; #endif proc = *args; if (proc == 0) { args = ShellArgs; proc = *args; } switch (pid = fork()) { case -1: Msg(errno, "fork"); break; case 0: signal(SIGHUP, SIG_DFL); signal(SIGINT, SIG_DFL); signal(SIGQUIT, SIG_DFL); signal(SIGTERM, SIG_DFL); #ifdef BSDJOBS signal(SIGTTIN, SIG_DFL); signal(SIGTTOU, SIG_DFL); #endif #ifdef SIGPIPE signal(SIGPIPE, SIG_DFL); #endif #ifdef SIGXFSZ signal(SIGXFSZ, SIG_DFL); #endif displays = 0; /* beware of Panic() */ if (setuid(real_uid) || setgid(real_gid)) { SendErrorMsg("Setuid/gid: %s", strerror(errno)); exit(1); } eff_uid = real_uid; eff_gid = real_gid; if (dir && *dir && chdir(dir) == -1) { SendErrorMsg("Cannot chdir to %s: %s", dir, strerror(errno)); exit(1); } if (display) { brktty(D_userfd); freetty(); } else brktty(-1); #ifdef DEBUG if (dfp && dfp != stderr) fclose(dfp); #endif #ifdef _IBMR2 close(0); dup(aixhack); close(aixhack); #endif closeallfiles(win->w_ptyfd); #ifdef _IBMR2 aixhack = dup(0); #endif #ifdef DEBUG { char buf[256]; sprintf(buf, "%s/screen.child", DEBUGDIR); if ((dfp = fopen(buf, "a")) == 0) dfp = stderr; else (void) chmod(buf, 0666); } debug1("=== ForkWindow: pid %d\n", getpid()); #endif /* Close the three /dev/null descriptors */ close(0); close(1); close(2); newfd = -1; /* * distribute filedescriptors between the ttys */ #ifdef PSEUDOS pat = pwin ? pwin->fdpat : ((F_PFRONT<<(F_PSHIFT*2)) | (F_PFRONT<w_ptyfd); wfdused = 1; } } if (wfdused) { /* * the pseudo window process should not be surprised with a * nonblocking filedescriptor. Poor Backend! */ debug1("Clearing NBLOCK on window-fd(%d)\n", win->w_ptyfd); if (fcntl(win->w_ptyfd, F_SETFL, 0)) SendErrorMsg("Warning: ForkWindow clear NBLOCK fcntl failed, %d", errno); } #else /* PSEUDOS */ if ((newfd = open(ttyn, O_RDWR)) != 0) { SendErrorMsg("Cannot open %s: %s", ttyn, strerror(errno)); exit(1); } dup(0); dup(0); #endif /* PSEUDOS */ close(win->w_ptyfd); #ifdef _IBMR2 close(aixhack); #endif if (newfd >= 0) { struct mode fakemode, *modep; #if defined(SVR4) && !defined(sgi) if (ioctl(newfd, I_PUSH, "ptem")) { SendErrorMsg("Cannot I_PUSH ptem %s %s", ttyn, strerror(errno)); exit(1); } if (ioctl(newfd, I_PUSH, "ldterm")) { SendErrorMsg("Cannot I_PUSH ldterm %s %s", ttyn, strerror(errno)); exit(1); } if (ioctl(newfd, I_PUSH, "ttcompat")) { SendErrorMsg("Cannot I_PUSH ttcompat %s %s", ttyn, strerror(errno)); exit(1); } #endif if (fgtty(newfd)) SendErrorMsg("fgtty: %s (%d)", strerror(errno), errno); if (display) { debug("ForkWindow: using display tty mode for new child.\n"); modep = &D_OldMode; } else { debug("No display - creating tty setting\n"); modep = &fakemode; InitTTY(modep, 0); #ifdef DEBUG DebugTTY(modep); #endif } /* We only want echo if the users input goes to the pseudo * and the pseudo's stdout is not send to the window. */ #ifdef PSEUDOS if (pwin && (!(pat & F_UWP) || (pat & F_PBACK << F_PSHIFT))) { debug1("clearing echo on pseudywin fd (pat %x)\n", pat); # if defined(POSIX) || defined(TERMIO) modep->tio.c_lflag &= ~ECHO; modep->tio.c_iflag &= ~ICRNL; # else modep->m_ttyb.sg_flags &= ~ECHO; # endif } #endif SetTTY(newfd, modep); #ifdef TIOCSWINSZ glwz.ws_col = w; glwz.ws_row = h; (void) ioctl(newfd, TIOCSWINSZ, (char *)&glwz); #endif /* Always turn off nonblocking mode */ (void)fcntl(newfd, F_SETFL, 0); } #ifndef TIOCSWINSZ sprintf(libuf, "LINES=%d", h); sprintf(cobuf, "COLUMNS=%d", w); NewEnv[5] = libuf; NewEnv[6] = cobuf; #endif #ifdef MAPKEYS NewEnv[2] = MakeTermcap(display == 0 || win->w_aflag); #else if (win->w_aflag) NewEnv[2] = MakeTermcap(1); else NewEnv[2] = Termcap; #endif strcpy(shellbuf, "SHELL="); strncpy(shellbuf + 6, ShellProg, MAXPATHLEN); shellbuf[MAXPATHLEN + 6] = 0; NewEnv[4] = shellbuf; debug1("ForkWindow: NewEnv[4] = '%s'\n", shellbuf); if (term && *term && strcmp(screenterm, term) && (strlen(term) < 20)) { char *s1, *s2, tl; sprintf(tebuf, "TERM=%s", term); debug2("Makewindow %d with %s\n", win->w_number, tebuf); tl = strlen(term); NewEnv[1] = tebuf; if ((s1 = index(NewEnv[2], '|'))) { if ((s2 = index(++s1, '|'))) { if (strlen(NewEnv[2]) - (s2 - s1) + tl < 1024) { bcopy(s2, s1 + tl, strlen(s2) + 1); bcopy(term, s1, tl); } } } } sprintf(ebuf, "WINDOW=%d", win->w_number); NewEnv[3] = ebuf; if (*proc == '-') proc++; if (!*proc) proc = DefaultShell; debug1("calling execvpe %s\n", proc); execvpe(proc, args, NewEnv); debug1("exec error: %d\n", errno); SendErrorMsg("Cannot exec '%s': %s", proc, strerror(errno)); exit(1); default: break; } #ifdef _IBMR2 close(aixhack); aixhack = -1; #endif return pid; } static void execvpe(prog, args, env) char *prog, **args, **env; { register char *path = NULL, *p; char buf[1024]; char *shargs[MAXARGS + 1]; register int i, eaccess = 0; if (rindex(prog, '/')) path = ""; if (!path && !(path = getenv("PATH"))) path = DefaultPath; do { p = buf; while (*path && *path != ':') *p++ = *path++; if (p > buf) *p++ = '/'; strcpy(p, prog); execve(buf, args, env); switch (errno) { case ENOEXEC: shargs[0] = DefaultShell; shargs[1] = buf; for (i = 1; (shargs[i + 1] = args[i]) != NULL; ++i) ; execve(DefaultShell, shargs, env); return; case EACCES: eaccess = 1; break; case ENOMEM: case E2BIG: case ETXTBSY: return; } } while (*path++); if (eaccess) errno = EACCES; } #ifdef PSEUDOS int winexec(av) char **av; { char **pp; char *p, *s, *t; int i, r = 0, l = 0; struct win *w; extern struct display *display; extern struct win *windows; struct pseudowin *pwin; if ((w = display ? fore : windows) == NULL) return -1; if (!*av || w->w_pwin) { Msg(0, "Filter running: %s", w->w_pwin ? w->w_pwin->p_cmd : "(none)"); return -1; } if (w->w_ptyfd < 0) { Msg(0, "You feel dead inside."); return -1; } if (!(pwin = (struct pseudowin *)malloc(sizeof(struct pseudowin)))) { Msg(0, strnomem); return -1; } bzero((char *)pwin, (int)sizeof(*pwin)); /* allow ^a:!!./ttytest as a short form for ^a:exec !.. ./ttytest */ for (s = *av; *s == ' '; s++) ; for (p = s; *p == ':' || *p == '.' || *p == '!'; p++) ; if (*p != '|') while (*p && p > s && p[-1] == '.') p--; if (*p == '|') { l = F_UWP; p++; } if (*p) av[0] = p; else av++; t = pwin->p_cmd; for (i = 0; i < 3; i++) { *t = (s < p) ? *s++ : '.'; switch (*t++) { case '.': case '|': l |= F_PFRONT << (i * F_PSHIFT); break; case '!': l |= F_PBACK << (i * F_PSHIFT); break; case ':': l |= F_PBOTH << (i * F_PSHIFT); break; } } if (l & F_UWP) { *t++ = '|'; if ((l & F_PMASK) == F_PFRONT) { *pwin->p_cmd = '!'; l ^= F_PFRONT | F_PBACK; } } if (!(l & F_PBACK)) l |= F_UWP; *t++ = ' '; pwin->fdpat = l; debug1("winexec: '%#x'\n", pwin->fdpat); l = MAXSTR - 4; for (pp = av; *pp; pp++) { p = *pp; while (*p && l-- > 0) *t++ = *p++; if (l <= 0) break; *t++ = ' '; } *--t = '\0'; debug1("%s\n", pwin->p_cmd); if ((pwin->p_ptyfd = OpenDevice(av[0], 0, &l, &t)) < 0) { free((char *)pwin); return -1; } strncpy(pwin->p_tty, t, MAXSTR - 1); w->w_pwin = pwin; if (l == TTY_FLAG_PLAIN) { FreePseudowin(w); Msg(0, "Cannot handle a TTY as a pseudo win."); return -1; } #ifdef TIOCPKT { int flag = 0; if (ioctl(pwin->p_ptyfd, TIOCPKT, (char *)&flag)) { Msg(errno, "TIOCPKT ioctl"); FreePseudowin(w); return -1; } } #endif /* TIOCPKT */ pwin->p_pid = ForkWindow(av, (char *)0, (char *)0, t, w); if ((r = pwin->p_pid) < 0) FreePseudowin(w); return r; } void FreePseudowin(w) struct win *w; { struct pseudowin *pwin = w->w_pwin; ASSERT(pwin); if (fcntl(w->w_ptyfd, F_SETFL, FNBLOCK)) Msg(errno, "Warning: FreePseudowin: NBLOCK fcntl failed"); (void) chmod(pwin->p_tty, 0666); (void) chown(pwin->p_tty, 0, 0); if (pwin->p_ptyfd >= 0) close(pwin->p_ptyfd); free((char *)pwin); w->w_pwin = NULL; } #endif /* PSEUDOS */ #ifdef MULTI /* * Clone routines. To be removed... */ static int CloneTermcap __P((struct display *)); extern char **environ; int execclone(av) char **av; { int f, sf; char specialbuf[6]; struct display *old = display; char **avp, *namep; sf = OpenPTY(&namep); if (sf == -1) { Msg(0, "No more PTYs."); return -1; } #ifdef _IBMR2 close(aixhack); aixhack = -1; #endif f = open(namep, O_RDWR); if (f == -1) { close(sf); Msg(errno, "Cannot open slave"); return -1; } brktty(f); signal(SIGHUP, SIG_IGN); /* No hangups, please */ if (MakeDisplay(D_username, namep, D_termname, f, -1, &D_OldMode) == 0) { display = old; Msg(0, "Could not make display."); close(f); close(sf); return -1; } if (CloneTermcap(old)) { FreeDisplay(); display = old; close(sf); return -1; } SetMode(&D_OldMode, &D_NewMode); SetTTY(f, &D_NewMode); switch (fork()) { case -1: FreeDisplay(); display = old; Msg(errno, "fork"); close(sf); return -1; case 0: D_usertty[0] = 0; /* for SendErrorMsg */ displays = 0; /* beware of Panic() */ if (setuid(real_uid) || setgid(real_gid)) { SendErrorMsg("Setuid/gid: %s", strerror(errno)); exit(1); } eff_uid = real_uid; eff_gid = real_gid; closeallfiles(sf); close(1); dup(sf); close(sf); #ifdef DEBUG { char buf[256]; sprintf(buf, "%s/screen.child", DEBUGDIR); if ((dfp = fopen(buf, "a")) == 0) dfp = stderr; else (void) chmod(buf, 0666); } debug1("=== Clone: pid %d\n", getpid()); #endif for (avp = av; *avp; avp++) { if (strcmp(*avp, "%p") == 0) *avp = namep; if (strcmp(*avp, "%X") == 0) *avp = specialbuf; } sprintf(specialbuf, "-SXX1"); namep += strlen(namep); specialbuf[3] = *--namep; specialbuf[2] = *--namep; #ifdef DEBUG debug("Calling:"); for (avp = av; *avp; avp++) debug1(" %s", *avp); debug("\n"); #endif execvpe(*av, av, environ); SendErrorMsg("Cannot exec '%s': %s", *av, strerror(errno)); exit(1); default: break; } close(sf); InitTerm(0); Activate(0); if (D_fore == 0) ShowWindows(); return 0; } extern struct term term[]; /* terminal capabilities */ static int CloneTermcap(old) struct display *old; { char *tp; int i, l; l = 0; for (i = 0; i < T_N; i++) if (term[i].type == T_STR && old->d_tcs[i].str) l += strlen(old->d_tcs[i].str) + 1; if ((D_tentry = (char *)malloc(l)) == 0) { Msg(0, strnomem); return -1; } tp = D_tentry; for (i = 0; i < T_N; i++) { switch(term[i].type) { case T_FLG: D_tcs[i].flg = old->d_tcs[i].flg; break; case T_NUM: D_tcs[i].num = old->d_tcs[i].num; break; case T_STR: D_tcs[i].str = old->d_tcs[i].str; if (D_tcs[i].str) { strcpy(tp, D_tcs[i].str); D_tcs[i].str = tp; tp += strlen(tp) + 1; } break; default: Panic(0, "Illegal tc type in entry #%d", i); } } CheckScreenSize(0); for (i = 0; i < NATTR; i++) D_attrtab[i] = old->d_attrtab[i]; for (i = 0; i < 256; i++) D_c0_tab[i] = old->d_c0_tab[i]; D_UPcost = old->d_UPcost; D_DOcost = old->d_DOcost; D_NLcost = old->d_NLcost; D_LEcost = old->d_LEcost; D_NDcost = old->d_NDcost; D_CRcost = old->d_CRcost; D_IMcost = old->d_IMcost; D_EIcost = old->d_EIcost; #ifdef AUTO_NUKE D_auto_nuke = old->d_auto_nuke; #endif if (D_CXC) CreateTransTable(D_CXC); D_tcinited = 1; return 0; } #endif