summaryrefslogtreecommitdiff
path: root/window.c
diff options
context:
space:
mode:
Diffstat (limited to 'window.c')
-rw-r--r--window.c1118
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
+