diff options
Diffstat (limited to 'window.c')
-rw-r--r-- | window.c | 1118 |
1 files changed, 1118 insertions, 0 deletions
diff --git a/window.c b/window.c new file mode 100644 index 0000000..021c9a0 --- /dev/null +++ b/window.c @@ -0,0 +1,1118 @@ +/* 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 <sys/types.h> +#include <sys/stat.h> +#include <signal.h> +#include <fcntl.h> +#ifndef sun +#include <sys/ioctl.h> +#endif + +#include "config.h" + +#ifdef SVR4 +# include <sys/stropts.h> +#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<<F_PSHIFT) | F_PFRONT); + wfdused = 0; + for(i = 0; i < 3; i++) + { + if (pat & F_PFRONT << F_PSHIFT * i) + { + if (newfd < 0) + { + if ((newfd = open(ttyn, O_RDWR)) < 0) + { + SendErrorMsg("Cannot open %s: %s", ttyn, strerror(errno)); + exit(1); + } + } + else + dup(newfd); + } + else + { + dup(win->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 + |