home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume27 / screen-3.5.1 / part04 / window.c < prev   
Encoding:
C/C++ Source or Header  |  1993-08-08  |  20.4 KB  |  928 lines

  1. /* Copyright (c) 1993
  2.  *      Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
  3.  *      Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
  4.  * Copyright (c) 1987 Oliver Laumann
  5.  *
  6.  * This program is free software; you can redistribute it and/or modify
  7.  * it under the terms of the GNU General Public License as published by
  8.  * the Free Software Foundation; either version 2, or (at your option)
  9.  * any later version.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program (see the file COPYING); if not, write to the
  18.  * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  *
  20.  ****************************************************************
  21.  */
  22.  
  23. #include "rcs.h"
  24. RCS_ID("$Id: window.c,v 1.14 1993/08/05 14:24:15 mlschroe Exp $ FAU")
  25.  
  26. #include <sys/types.h>
  27. #include <sys/stat.h>
  28. #include <signal.h>
  29. #include <fcntl.h>
  30. #ifndef sun
  31. #include <sys/ioctl.h>
  32. #endif
  33.  
  34. #include "config.h"
  35. #include "screen.h"
  36. #include "extern.h"
  37.  
  38. #ifdef SVR4    /* for solaris 2.1 */
  39. # include <sys/stropts.h>
  40. #endif
  41.  
  42. extern struct display *displays, *display;
  43. extern struct win *windows, *fore, *wtab[], *console_window;
  44. extern char *ShellArgs[];
  45. extern char *ShellProg;
  46. extern char screenterm[];
  47. extern char HostName[];
  48. extern int default_monitor, TtyMode;
  49. extern struct LayFuncs WinLf;
  50. extern int real_uid, real_gid;
  51. extern char Termcap[];
  52. extern char **NewEnv;
  53.  
  54. #if defined(TIOCSWINSZ) || defined(TIOCGWINSZ)
  55. extern struct winsize glwz;
  56. #endif
  57.  
  58.  
  59. static int OpenDevice __P((char *, int, int *, char **));
  60. static int ForkWindow __P((char **, char *, char *, char *, struct win *));
  61. static void execvpe __P((char *, char **, char **));
  62.  
  63.  
  64. char DefaultShell[] = "/bin/sh";
  65. static char DefaultPath[] = ":/usr/ucb:/bin:/usr/bin";
  66.  
  67.  
  68. struct NewWindow nwin_undef   = 
  69. {
  70.   -1, (char *)0, (char **)0, (char *)0, (char *)0, -1, -1, 
  71.   -1, -1, -1
  72. };
  73.  
  74. struct NewWindow nwin_default = 
  75.   0, 0, ShellArgs, 0, screenterm, 0, 1*FLOW_NOW, 
  76.   LOGINDEFAULT, DEFAULTHISTHEIGHT, -1
  77. };
  78.  
  79. struct NewWindow nwin_options;
  80.  
  81. void
  82. nwin_compose(def, new, res)
  83. struct NewWindow *def, *new, *res;
  84. {
  85.   res->StartAt = new->StartAt != nwin_undef.StartAt ? new->StartAt : def->StartAt;
  86.   res->aka = new->aka != nwin_undef.aka ? new->aka : def->aka;
  87.   res->args = new->args != nwin_undef.args ? new->args : def->args;
  88.   res->dir = new->dir != nwin_undef.dir ? new->dir : def->dir;
  89.   res->term = new->term != nwin_undef.term ? new->term : def->term;
  90.   res->aflag = new->aflag != nwin_undef.aflag ? new->aflag : def->aflag;
  91.   res->flowflag = new->flowflag != nwin_undef.flowflag ? new->flowflag : def->flowflag;
  92.   res->lflag = new->lflag != nwin_undef.lflag ? new->lflag : def->lflag;
  93.   res->histheight = new->histheight != nwin_undef.histheight ? new->histheight : def->histheight;
  94.   res->monitor = new->monitor != nwin_undef.monitor ? new->monitor : def->monitor;
  95. }
  96.  
  97. int
  98. MakeWindow(newwin)
  99. struct NewWindow *newwin;
  100. {
  101.   register struct win **pp, *p;
  102.   register int n;
  103.   int f = -1;
  104.   struct NewWindow nwin;
  105.   int ttyflag;
  106.   char *TtyName;
  107.  
  108.   debug1("NewWindow: StartAt %d\n", newwin->StartAt);
  109.   debug1("NewWindow: aka     %s\n", newwin->aka?newwin->aka:"NULL");
  110.   debug1("NewWindow: dir     %s\n", newwin->dir?newwin->dir:"NULL");
  111.   debug1("NewWindow: term    %s\n", newwin->term?newwin->term:"NULL");
  112.   nwin_compose(&nwin_default, newwin, &nwin);
  113.   debug1("NWin: aka     %s\n", nwin.aka ? nwin.aka : "NULL");
  114.   pp = wtab + nwin.StartAt;
  115.  
  116.   do
  117.     {
  118.       if (*pp == 0)
  119.     break;
  120.       if (++pp == wtab + MAXWIN)
  121.     pp = wtab;
  122.     }
  123.   while (pp != wtab + nwin.StartAt);
  124.   if (*pp)
  125.     {
  126.       Msg(0, "No more windows.");
  127.       return -1;
  128.     }
  129.  
  130. #if defined(USRLIMIT) && defined(UTMPOK)
  131.   /*
  132.    * Count current number of users, if logging windows in.
  133.    */
  134.   if (nwin.lflag && CountUsers() >= USRLIMIT)
  135.     {
  136.       Msg(0, "User limit reached.  Window will not be logged in.");
  137.       nwin.lflag = 0;
  138.     }
  139. #endif
  140.   n = pp - wtab;
  141.   debug1("Makewin creating %d\n", n);
  142.  
  143.   if ((f = OpenDevice(nwin.args[0], nwin.lflag, &ttyflag, &TtyName)) < 0)
  144.     return -1;
  145.  
  146.   if ((p = (struct win *) malloc(sizeof(struct win))) == 0)
  147.     {
  148.       close(f);
  149.       Msg(0, strnomem);
  150.       return -1;
  151.     }
  152.   bzero((char *) p, (int) sizeof(struct win)); /* looks like a calloc above */
  153. #ifdef MULTIUSER
  154.   if (NewWindowAcl(p))
  155.     {
  156.       free(p);
  157.       close(f);
  158.       Msg(0, strnomem);
  159.       return -1;
  160.     }
  161. #endif
  162.   p->w_wlock = WLOCK_AUTO;
  163.   p->w_dupto = -1;
  164.   p->w_winlay.l_next = 0;
  165.   p->w_winlay.l_layfn = &WinLf;
  166.   p->w_winlay.l_data = (char *)p;
  167.   p->w_lay = &p->w_winlay;
  168.   p->w_display = display;
  169.   if (display)
  170.     p->w_wlockuser = d_user;
  171.   p->w_number = n;
  172.   p->w_ptyfd = f;
  173.   p->w_aflag = nwin.aflag;
  174.   p->w_flow = nwin.flowflag | ((nwin.flowflag & FLOW_AUTOFLAG) ? (FLOW_AUTO|FLOW_NOW) : FLOW_AUTO);
  175.   if (!nwin.aka)
  176.     nwin.aka = Filename(nwin.args[0]);
  177.   strncpy(p->w_akabuf, nwin.aka, MAXSTR - 1);
  178.   if ((nwin.aka = rindex(p->w_akabuf, '|')) != NULL)
  179.     {
  180.       p->w_autoaka = 0;
  181.       *nwin.aka++ = 0;
  182.       p->w_title = nwin.aka;
  183.       p->w_akachange = nwin.aka + strlen(nwin.aka);
  184.     }
  185.   else
  186.     p->w_title = p->w_akachange = p->w_akabuf;
  187.   if ((p->w_monitor = nwin.monitor) == -1)
  188.     p->w_monitor = default_monitor;
  189.   p->w_norefresh = 0;
  190.   strncpy(p->w_tty, TtyName, MAXSTR - 1);
  191.  
  192.   if (ChangeWindowSize(p, display ? d_defwidth : 80, display ? d_defheight : 24))
  193.     {
  194.       FreeWindow(p);
  195.       return -1;
  196.     }
  197. #ifdef COPY_PASTE
  198.   ChangeScrollback(p, nwin.histheight, p->w_width);
  199. #endif
  200.   ResetWindow(p);    /* sets p->w_wrap */
  201.  
  202.   if (ttyflag == TTY_FLAG_PLAIN)
  203.     {
  204.       p->w_t.flags |= TTY_FLAG_PLAIN;
  205.       p->w_pid = 0;
  206.     }
  207.   else
  208.     {
  209.       debug("forking...\n");
  210. #ifdef PSEUDOS
  211.       p->w_pwin = NULL;
  212. #endif
  213.       p->w_pid = ForkWindow(nwin.args, nwin.dir, nwin.term, TtyName, p);
  214.       if (p->w_pid < 0)
  215.     {
  216.       FreeWindow(p);
  217.       return -1;
  218.     }
  219.     }
  220.   /*
  221.    * Place the newly created window at the head of the most-recently-used list.
  222.    */
  223.   if (display && d_fore)
  224.     d_other = d_fore;
  225.   *pp = p;
  226.   p->w_next = windows;
  227.   windows = p;
  228. #ifdef UTMPOK
  229.   debug1("MakeWindow will %slog in.\n", nwin.lflag?"":"not ");
  230.   if (nwin.lflag == 1)
  231.     {
  232.       if (display)
  233.         SetUtmp(p);
  234.       else
  235.     p->w_slot = (slot_t) 0;
  236.     }
  237.   else
  238.     p->w_slot = (slot_t) -1;
  239. #endif
  240.   SetForeWindow(p);
  241.   Activate(p->w_norefresh);
  242.   return n;
  243. }
  244.  
  245. void
  246. FreeWindow(wp)
  247. struct win *wp;
  248. {
  249.   struct display *d;
  250.  
  251. #ifdef PSEUDOS
  252.   if (wp->w_pwin)
  253.     FreePseudowin(wp);
  254. #endif
  255. #ifdef UTMPOK
  256.   RemoveUtmp(wp);
  257. #endif
  258.   (void) chmod(wp->w_tty, 0666);
  259.   (void) chown(wp->w_tty, 0, 0);
  260.   close(wp->w_ptyfd);
  261.   if (wp == console_window)
  262.     console_window = 0;
  263.   if (wp->w_logfp != NULL)
  264.     fclose(wp->w_logfp);
  265.   ChangeWindowSize(wp, 0, 0);
  266.   for (d = displays; d; d = d->_d_next)
  267.     if (d->_d_other == wp)
  268.       d->_d_other = 0;
  269.   free(wp);
  270. }
  271.  
  272. static int
  273. OpenDevice(arg, lflag, typep, namep)
  274. char *arg;
  275. int lflag;
  276. int *typep;
  277. char **namep;
  278. {
  279.   struct stat st;
  280.   int f;
  281.  
  282.   if ((stat(arg, &st)) == 0 && (st.st_mode & S_IFCHR))
  283.     {
  284.       if (access(arg, R_OK | W_OK) == -1)
  285.     {
  286.       Msg(errno, "Cannot access line '%s' for R/W", arg); 
  287.       return -1;
  288.     }
  289.       debug("OpenDevice: OpenTTY\n");
  290.       if ((f = OpenTTY(arg)) < 0)
  291.     return -1;
  292.       *typep = TTY_FLAG_PLAIN;
  293.       *namep = arg;
  294.     }
  295.   else
  296.     {
  297.       *typep = 0;    /* for now we hope it is a program */
  298.       f = OpenPTY(namep);
  299.       if (f == -1)
  300.     {
  301.       Msg(0, "No more PTYs.");
  302.       return -1;
  303.     }
  304. #ifdef TIOCPKT
  305.       {
  306.     int flag = 1;
  307.  
  308.     if (ioctl(f, TIOCPKT, (char *)&flag))
  309.       {
  310.         Msg(errno, "TIOCPKT ioctl");
  311.         close(f);
  312.         return -1;
  313.       }
  314.       }
  315. #endif /* TIOCPKT */
  316.     }
  317.   (void) fcntl(f, F_SETFL, FNDELAY);
  318. #ifdef PTYGROUP
  319.   (void) chown(*namep, real_uid, PTYGROUP);
  320. #else
  321.   (void) chown(*namep, real_uid, real_gid);
  322. #endif
  323. #ifdef UTMPOK
  324.   (void) chmod(*namep, lflag ? TtyMode : (TtyMode & ~022));
  325. #else
  326.   (void) chmod(*namep, TtyMode);
  327. #endif
  328.   return f;
  329. }
  330.  
  331. /*
  332.  * Fields w_width, w_height, aflag, number (and w_tty)
  333.  * are read from struct win *win. No fields written.
  334.  * If pwin is nonzero, filedescriptors are distributed 
  335.  * between win->w_tty and open(ttyn)
  336.  *
  337.  */
  338. static int 
  339. ForkWindow(args, dir, term, ttyn, win)
  340. char **args, *dir, *term, *ttyn;
  341. struct win *win;
  342. {
  343.   int pid;
  344.   char tebuf[25];
  345.   char ebuf[10];
  346.   char shellbuf[7 + MAXPATHLEN];
  347.   char *proc;
  348. #ifndef TIOCSWINSZ
  349.   char libuf[20], cobuf[20];
  350. #endif
  351.   int newfd;
  352.   int w = win->w_width;
  353.   int h = win->w_height;
  354. #ifdef PSEUDOS
  355.   int i, pat, wfdused;
  356.   struct pseudowin *pwin = win->w_pwin;
  357. #endif
  358.  
  359.   proc = *args;
  360.   if (proc == 0)
  361.     {
  362.       args = ShellArgs;
  363.       proc = *args;
  364.     }
  365.   switch (pid = fork())
  366.     {
  367.     case -1:
  368.       Msg(errno, "fork");
  369.       return -1;
  370.     case 0:
  371.       signal(SIGHUP, SIG_DFL);
  372.       signal(SIGINT, SIG_DFL);
  373.       signal(SIGQUIT, SIG_DFL);
  374.       signal(SIGTERM, SIG_DFL);
  375. #ifdef BSDJOBS
  376.       signal(SIGTTIN, SIG_DFL);
  377.       signal(SIGTTOU, SIG_DFL);
  378. #endif
  379.       if (setuid(real_uid) || setgid(real_gid))
  380.     {
  381.       SendErrorMsg("Setuid/gid: %s", sys_errlist[errno]);
  382.       eexit(1);
  383.     }
  384.       if (dir && *dir && chdir(dir) == -1)
  385.     {
  386.       SendErrorMsg("Cannot chdir to %s: %s", dir, sys_errlist[errno]);
  387.       eexit(1);
  388.     }
  389.  
  390.       if (display)
  391.     {
  392.       brktty(d_userfd);
  393.       freetty();
  394.     }
  395.       else
  396.     brktty(-1);
  397. #ifdef DEBUG
  398.       if (dfp && dfp != stderr)
  399.     fclose(dfp);
  400. #endif
  401.       closeallfiles(win->w_ptyfd);
  402. #ifdef DEBUG
  403.     {
  404.       char buf[256];
  405.       
  406.       sprintf(buf, "%s/screen.child", DEBUGDIR);
  407.       if ((dfp = fopen(buf, "a")) == 0)
  408.         dfp = stderr;
  409.       else
  410.         (void) chmod(buf, 0666);
  411.     }
  412.       debug1("=== ForkWindow: pid %d\n", getpid());
  413. #endif
  414.       /* Close the three /dev/null descriptors */
  415.       close(0);
  416.       close(1);
  417.       close(2);
  418.       newfd = -1;
  419.       /* 
  420.        * distribute filedescriptors between the ttys
  421.        */
  422. #ifdef PSEUDOS
  423.       pat = pwin ? pwin->fdpat : 
  424.            ((F_PFRONT<<(F_PSHIFT*2)) | (F_PFRONT<<F_PSHIFT) | F_PFRONT);
  425.       wfdused = 0;
  426.       for(i = 0; i < 3; i++)
  427.     {
  428.       if (pat & F_PFRONT << F_PSHIFT * i)
  429.         {
  430.           if (newfd < 0)
  431.         {
  432.           if ((newfd = open(ttyn, O_RDWR)) < 0)
  433.             {
  434.               SendErrorMsg("Cannot open %s: %s",
  435.                    ttyn, sys_errlist[errno]);
  436.               eexit(1);
  437.             }
  438.         }
  439.           else
  440.         dup(newfd);
  441.         }
  442.       else
  443.         {
  444.           dup(win->w_ptyfd);
  445.           wfdused = 1;
  446.         }
  447.     }
  448.       if (wfdused)
  449.     {
  450.         /* 
  451.          * the pseudo window process should not be surprised with a 
  452.          * nonblocking filedescriptor. Poor Backend!
  453.          */
  454.         debug1("Clearing NDELAY on window-fd(%d)\n", win->w_ptyfd);
  455.         if (fcntl(win->w_ptyfd, F_SETFL, 0))
  456.           SendErrorMsg("Warning: ForkWindow clear NDELAY fcntl failed, %d", errno);
  457.     }
  458. #else /* PSEUDOS */
  459.       if ((newfd = open(ttyn, O_RDWR)) != 0)
  460.     {
  461.       SendErrorMsg("Cannot open %s: %s", ttyn, sys_errlist[errno]);
  462.       eexit(1);
  463.     }
  464.       dup(0);
  465.       dup(0);
  466. #endif /* PSEUDOS */
  467.       close(win->w_ptyfd);
  468.  
  469.       if (newfd >= 0)
  470.     {
  471.       struct mode fakemode, *modep;
  472. #if defined(SVR4) && !defined(sgi)
  473.       if (ioctl(newfd, I_PUSH, "ptem"))
  474.         {
  475.           SendErrorMsg("Cannot I_PUSH ptem %s %s", ttyn, sys_errlist[errno]);
  476.           eexit(1);
  477.         }
  478.       if (ioctl(newfd, I_PUSH, "ldterm"))
  479.         {
  480.           SendErrorMsg("Cannot I_PUSH ldterm %s %s", ttyn, sys_errlist[errno]);
  481.           eexit(1);
  482.         }
  483.       if (ioctl(newfd, I_PUSH, "ttcompat"))
  484.         {
  485.           SendErrorMsg("Cannot I_PUSH ttcompat %s %s", ttyn, sys_errlist[errno]);
  486.           eexit(1);
  487.         }
  488. #endif
  489.       if (fgtty(newfd))
  490.         SendErrorMsg("fgtty: %s (%d)", sys_errlist[errno], errno);
  491.       if (display)
  492.         {
  493.           debug("ForkWindow: using display tty mode for new child.\n");
  494.           modep = &d_OldMode;
  495.         }
  496.       else
  497.         {
  498.           debug("No display - creating tty setting\n");
  499.           modep = &fakemode;
  500.           InitTTY(modep, 0);
  501. #ifdef DEBUG
  502.           DebugTTY(modep);
  503. #endif
  504.         }
  505.       /* We only want echo if the users input goes to the pseudo
  506.        * and the pseudo's stdout is not send to the window.
  507.        */
  508. #ifdef PSEUDOS
  509.       if (pwin && (!(pat & F_UWP) || (pat & F_PBACK << F_PSHIFT)))
  510.         {
  511.           debug1("clearing echo on pseudywin fd (pat %x)\n", pat);
  512. # if defined(POSIX) || defined(TERMIO)
  513.           modep->tio.c_lflag &= ~ECHO;
  514.           modep->tio.c_iflag &= ~ICRNL;
  515. # else
  516.           modep->m_ttyb.sg_flags &= ~ECHO;
  517. # endif
  518.         }
  519. #endif
  520.       SetTTY(newfd, modep);
  521. #ifdef TIOCSWINSZ
  522.       glwz.ws_col = w;
  523.       glwz.ws_row = h;
  524.       (void) ioctl(newfd, TIOCSWINSZ, (char *)&glwz);
  525. #endif
  526.     }
  527. #ifndef TIOCSWINSZ
  528.       sprintf(libuf, "LINES=%d", h);
  529.       sprintf(cobuf, "COLUMNS=%d", w);
  530.       NewEnv[5] = libuf;
  531.       NewEnv[6] = cobuf;
  532. #endif
  533.       if (win->w_aflag)
  534.     NewEnv[2] = MakeTermcap(1);
  535.       else
  536.     NewEnv[2] = Termcap;
  537.       strcpy(shellbuf, "SHELL=");
  538.       strncpy(shellbuf + 6, ShellProg, MAXPATHLEN);
  539.       shellbuf[MAXPATHLEN + 6] = 0;
  540.       NewEnv[4] = shellbuf;
  541.       debug1("ForkWindow: NewEnv[4] = '%s'\n", shellbuf);
  542.       if (term && *term && strcmp(screenterm, term) &&
  543.       (strlen(term) < 20))
  544.     {
  545.       char *s1, *s2, tl;
  546.  
  547.       sprintf(tebuf, "TERM=%s", term);
  548.       debug2("Makewindow %d with %s\n", win->w_number, tebuf);
  549.       tl = strlen(term);
  550.       NewEnv[1] = tebuf;
  551.       if ((s1 = index(Termcap, '|')))
  552.         {
  553.           if ((s2 = index(++s1, '|')))
  554.         {
  555.           if (strlen(Termcap) - (s2 - s1) + tl < 1024)
  556.             {
  557.               bcopy(s2, s1 + tl, strlen(s2) + 1);
  558.               bcopy(term, s1, tl);
  559.             }
  560.         }
  561.         }
  562.     }
  563.       sprintf(ebuf, "WINDOW=%d", win->w_number);
  564.       NewEnv[3] = ebuf;
  565.  
  566.       if (*proc == '-')
  567.     proc++;
  568.       debug1("calling execvpe %s\n", proc);
  569.       execvpe(proc, args, NewEnv);
  570.       debug1("exec error: %d\n", errno);
  571.       SendErrorMsg("Cannot exec %s: %s", proc, sys_errlist[errno]);
  572.       exit(1);
  573.     default:
  574.       return pid;
  575.     } /* end fork switch */
  576.   /* NOTREACHED */
  577. }
  578.  
  579. static void
  580. execvpe(prog, args, env)
  581. char *prog, **args, **env;
  582. {
  583.   register char *path = NULL, *p;
  584.   char buf[1024];
  585.   char *shargs[MAXARGS + 1];
  586.   register int i, eaccess = 0;
  587.  
  588.   for (i = 0; i < 3; i++)
  589.     if (!strncmp("../" + i, prog, 3 - i))
  590.       path = "";
  591.   if (!path && !(path = getenv("PATH")))
  592.     path = DefaultPath;
  593.   do
  594.     {
  595.       p = buf;
  596.       while (*path && *path != ':')
  597.     *p++ = *path++;
  598.       if (p > buf)
  599.     *p++ = '/';
  600.       strcpy(p, prog);
  601.       execve(buf, args, env);
  602.       switch (errno)
  603.     {
  604.     case ENOEXEC:
  605.       shargs[0] = DefaultShell;
  606.       shargs[1] = buf;
  607.       for (i = 1; (shargs[i + 1] = args[i]) != NULL; ++i)
  608.         ;
  609.       execve(DefaultShell, shargs, env);
  610.       return;
  611.     case EACCES:
  612.       eaccess = 1;
  613.       break;
  614.     case ENOMEM:
  615.     case E2BIG:
  616.     case ETXTBSY:
  617.       return;
  618.     }
  619.     } while (*path++);
  620.   if (eaccess)
  621.     errno = EACCES;
  622. }
  623.  
  624. #ifdef PSEUDOS
  625.  
  626. int
  627. winexec(av)
  628. char **av;
  629. {
  630.   char **pp;
  631.   char *p, *s, *t;
  632.   int i, r = 0, l = 0;
  633.   struct win *w;
  634.   extern struct display *display;
  635.   extern struct win *windows;
  636.   struct pseudowin *pwin;
  637.   
  638.   if ((w = display ? fore : windows) == NULL)
  639.     return -1;
  640.   if (!*av || w->w_pwin)
  641.     {
  642.       Msg(0, "Filter running: %s", w->w_pwin ? w->w_pwin->p_cmd : "(none)");
  643.       return -1;
  644.     }
  645.   if (w->w_ptyfd < 0)
  646.     {
  647.       Msg(0, "You feel dead inside.");
  648.       return -1;
  649.     }
  650.   if (!(pwin = (struct pseudowin *)malloc(sizeof(struct pseudowin))))
  651.     {
  652.       Msg(0, strnomem);
  653.       return -1;
  654.     }
  655.   bzero((char *)pwin, (int)sizeof(*pwin));
  656.  
  657.   /* allow ^a:!!./ttytest as a short form for ^a:exec !.. ./ttytest */
  658.   for (s = *av; *s == ' '; s++)
  659.     ;
  660.   for (p = s; *p == ':' || *p == '.' || *p == '!'; p++)
  661.     ;
  662.   if (*p != '|')
  663.     while (*p && p > s && p[-1] == '.')
  664.       p--;
  665.   if (*p == '|')
  666.     {
  667.       l = F_UWP;
  668.       p++;
  669.     }
  670.   if (*p) 
  671.     av[0] = p;
  672.   else
  673.     av++;
  674.  
  675.   t = pwin->p_cmd;
  676.   for (i = 0; i < 3; i++)
  677.     {
  678.       *t = (s < p) ? *s++ : '.';
  679.       switch (*t++)
  680.     {
  681.     case '.':
  682.     case '|':
  683.       l |= F_PFRONT << (i * F_PSHIFT);
  684.       break;
  685.     case '!':
  686.       l |= F_PBACK << (i * F_PSHIFT);
  687.       break;
  688.     case ':':
  689.       l |= F_PBOTH << (i * F_PSHIFT);
  690.       break;
  691.     }
  692.     }
  693.   
  694.   if (l & F_UWP)
  695.     {
  696.       *t++ = '|';
  697.       if ((l & F_PMASK) == F_PFRONT)
  698.     {
  699.       *pwin->p_cmd = '!';
  700.       l ^= F_PFRONT | F_PBACK;
  701.     }
  702.     }
  703.   if (!(l & F_PBACK))
  704.     l |= F_UWP;
  705.   *t++ = ' ';
  706.   pwin->fdpat = l;
  707.   debug1("winexec: '%#x'\n", pwin->fdpat);
  708.   
  709.   l = MAXSTR - 4;
  710.   for (pp = av; *pp; pp++)
  711.     {
  712.       p = *pp;
  713.       while (*p && l-- > 0)
  714.         *t++ = *p++;
  715.       if (l <= 0)
  716.     break;
  717.       *t++ = ' ';
  718.     }
  719.   *--t = '\0';
  720.   debug1("%s\n", pwin->p_cmd);
  721.   
  722.   if ((pwin->p_ptyfd = OpenDevice(av[0], 0, &l, &t)) < 0)
  723.     {
  724.       free(pwin);
  725.       return -1;
  726.     }
  727.   strncpy(pwin->p_tty, t, MAXSTR - 1);
  728.   w->w_pwin = pwin;
  729.   if (l == TTY_FLAG_PLAIN)
  730.     {
  731.       FreePseudowin(w);
  732.       Msg(0, "Cannot handle a TTY as a pseudo win.");
  733.       return -1;
  734.     }
  735. #ifdef TIOCPKT
  736.   {
  737.     int flag = 0;
  738.  
  739.     if (ioctl(pwin->p_ptyfd, TIOCPKT, (char *)&flag))
  740.       {
  741.     Msg(errno, "TIOCPKT ioctl");
  742.     FreePseudowin(w);
  743.     return -1;
  744.       }
  745.   }
  746. #endif /* TIOCPKT */
  747.   pwin->p_pid = ForkWindow(av, NULL, NULL, t, w);
  748.   if ((r = pwin->p_pid) < 0)
  749.     FreePseudowin(w);
  750.   return r;
  751. }
  752.  
  753. void
  754. FreePseudowin(w)
  755. struct win *w;
  756. {
  757.   struct pseudowin *pwin = w->w_pwin;
  758.  
  759.   ASSERT(pwin);
  760.   if (fcntl(w->w_ptyfd, F_SETFL, FNDELAY))
  761.     Msg(errno, "Warning: FreePseudowin: NDELAY fcntl failed");
  762.   (void) chmod(pwin->p_tty, 0666);
  763.   (void) chown(pwin->p_tty, 0, 0);
  764.   if (pwin->p_ptyfd >= 0)
  765.     close(pwin->p_ptyfd);
  766.   free(pwin);
  767.   w->w_pwin = NULL;
  768. }
  769.  
  770. #endif /* PSEUDOS */
  771.  
  772.  
  773. #ifdef MULTI
  774.  
  775. static void CloneTermcap __P((struct display *));
  776. extern char **environ;
  777.  
  778. int
  779. execclone(av)
  780. char **av;
  781. {
  782.   int f, sf;
  783.   char specialbuf[6];
  784.   struct display *old = display;
  785.   char **avp, *namep;
  786.  
  787.   sf = OpenPTY(&namep);
  788.   if (sf == -1)
  789.     {
  790.       Msg(0, "No more PTYs.");
  791.       return -1;
  792.     }
  793.   f = open(namep, O_RDWR);
  794.   if (f == -1)
  795.     {
  796.       close(sf);
  797.       Msg(errno, "Cannot open slave");
  798.       return -1;
  799.     }
  800.   brktty(f);
  801.   signal(SIGHUP, SIG_IGN);    /* No hangups, please */
  802.   if (MakeDisplay(d_username, namep, d_termname, f, -1, &d_OldMode) == 0)
  803.     {
  804.       display = old;
  805.       Msg(0, "Could not make display.");
  806.       close(f);
  807.       return -1;
  808.     }
  809.   SetMode(&d_OldMode, &d_NewMode);
  810.   SetTTY(f, &d_NewMode);
  811.   switch (fork())
  812.     {
  813.     case -1:
  814.       FreeDisplay();
  815.       display = old;
  816.       Msg(errno, "fork");
  817.       return -1;
  818.     case 0:
  819.       d_usertty[0] = 0;        /* for SendErrorMsg */
  820.       if (setuid(real_uid) || setgid(real_gid))
  821.     {
  822.       SendErrorMsg("Setuid/gid: %s", sys_errlist[errno]);
  823.       eexit(1);
  824.     }
  825.       closeallfiles(sf);
  826.       close(1);
  827.       dup(sf);
  828.       close(sf);
  829. #ifdef DEBUG
  830.     {
  831.       char buf[256];
  832.  
  833.       sprintf(buf, "%s/screen.child", DEBUGDIR);
  834.       if ((dfp = fopen(buf, "a")) == 0)
  835.         dfp = stderr;
  836.       else
  837.         (void) chmod(buf, 0666);
  838.     }
  839.       debug1("=== Clone: pid %d\n", getpid());
  840. #endif
  841.       for (avp = av; *avp; avp++)
  842.         {
  843.           if (strcmp(*avp, "%p") == 0)
  844.             *avp = namep;
  845.           if (strcmp(*avp, "%X") == 0)
  846.             *avp = specialbuf;
  847.         }
  848.       sprintf(specialbuf, "-SXX1");
  849.       namep += strlen(namep);
  850.       specialbuf[3] = *--namep;
  851.       specialbuf[2] = *--namep;
  852. #ifdef DEBUG
  853.       debug("Calling:");
  854.       for (avp = av; *avp; avp++)
  855.         debug1(" %s", *avp);
  856.       debug("\n");
  857. #endif
  858.       execvpe(*av, av, environ);
  859.       SendErrorMsg("Cannot exec %s: %s", *av, sys_errlist[errno]);
  860.       exit(1);
  861.     default:
  862.       break;
  863.     }
  864.   close(sf);
  865.   CloneTermcap(old);
  866.   InitTerm(0);
  867.   Activate(0);
  868.   if (d_fore == 0)
  869.     ShowWindows();
  870.   return 0;
  871. }
  872.  
  873. extern struct term term[];      /* terminal capabilities */
  874.  
  875. static void
  876. CloneTermcap(old)
  877. struct display *old;
  878. {
  879.   char *tp;
  880.   int i;
  881.  
  882.   tp = d_tentry;
  883.   for (i = 0; i < T_N; i++)
  884.     {
  885.       switch(term[i].type)
  886.         {
  887.         case T_FLG:
  888.           d_tcs[i].flg = old->_d_tcs[i].flg;
  889.           break;
  890.         case T_NUM:
  891.           d_tcs[i].num = old->_d_tcs[i].num;
  892.           break;
  893.         case T_STR:
  894.           d_tcs[i].str = old->_d_tcs[i].str;
  895.           if (d_tcs[i].str)
  896.             {
  897.               strcpy(tp, d_tcs[i].str);
  898.               d_tcs[i].str = tp;
  899.               tp += strlen(tp) + 1;
  900.             }
  901.       break;
  902.         default:
  903.           Panic(0, "Illegal tc type in entry #%d", i);
  904.         }
  905.     }
  906.   CheckScreenSize(0);
  907.   for (i = 0; i < NATTR; i++)
  908.     d_attrtab[i] = old->_d_attrtab[i];
  909.   for (i = 0; i < 256; i++)
  910.     d_c0_tab[i] = old->_d_c0_tab[i];
  911.   d_UPcost = old->_d_UPcost;
  912.   d_DOcost = old->_d_DOcost;
  913.   d_NLcost = old->_d_NLcost;
  914.   d_LEcost = old->_d_LEcost;
  915.   d_NDcost = old->_d_NDcost;
  916.   d_CRcost = old->_d_CRcost;
  917.   d_IMcost = old->_d_IMcost;
  918.   d_EIcost = old->_d_EIcost;
  919. #ifdef AUTO_NUKE
  920.   d_auto_nuke = old->_d_auto_nuke;
  921. #endif
  922.   d_tcinited = 1;
  923. }
  924.  
  925. #endif
  926.  
  927.