home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume2 / window / part3 / shell.c < prev    next >
Encoding:
C/C++ Source or Header  |  1986-11-30  |  7.0 KB  |  301 lines

  1. /*
  2.  *************
  3.  * DISTRIBUTION NOTICE  July 30 1985
  4.  * A Revised Edition of WM, by Matt Lennon and Tom Truscott,
  5.  *        Research Triangle Institute, (919) 541-7005.
  6.  * Based on the original by Robert Jacob (decvax!nrl-css!jacob),
  7.  *        Naval Research Laboratory, (202) 767-3365.
  8.  * No claims or warranties of any sort are made for this distribution.
  9.  * General permission is granted to copy, but not for profit,
  10.  * any of this distribution, provided that this notice
  11.  * is always included in the copies.
  12.  *************
  13.  */
  14. /*
  15.  * This file contains routines dealing
  16.  * with the window shells.
  17.  */
  18.  
  19. #include "wm.h"
  20. #include <signal.h>
  21. #include <errno.h>
  22.  
  23. static struct sgttyb sgttybuf;
  24. static struct tchars tcharsbuf;
  25. static struct ltchars ltcharsbuf;
  26. static int ttymode;
  27. static int ttydisc;
  28. static int ttyfd;        /* file descriptor for /dev/tty */
  29.  
  30.  
  31. /*
  32.  * Initialize parameters needed for creating new window shells.
  33.  */
  34. ShellInit()
  35. {
  36.     (void) ioctl(0, (int)TIOCGETD, (char*)&ttydisc);
  37.     (void) ioctl(0, (int)TIOCGETC, (char*)&tcharsbuf);
  38.     (void) ioctl(0, (int)TIOCLGET, (char*)&ttymode);
  39.     (void) ioctl(0, (int)TIOCGLTC, (char*)<charsbuf);
  40.     (void) ioctl(0, (int)TIOCGETP, (char*)&sgttybuf);
  41.  
  42.      /*
  43.       * The psuedo-tty driver should probably not produce
  44.       * internal magic delay characters (cf. sys/tty.c (ttyoutput)).
  45.       * It seems easiest to turn off all delays here.
  46.       * (Even that is not all that easy, due to an XTABS glitch.)
  47.       */
  48.     {
  49.     register int i = ALLDELAY;
  50.     if ((sgttybuf.sg_flags&TBDELAY) == XTABS)
  51.         i &= ~TBDELAY;
  52.     sgttybuf.sg_flags &= ~i;
  53.     }
  54.  
  55.      /* We will use 'ttyfd' later when setting
  56.       * controlling terminals for new shells.
  57.       */
  58.     ttyfd = open("/dev/tty", 0);
  59.  
  60.     strcpy(shellpgm, getenv("SHELL") ? getenv("SHELL") : "sh");
  61.     strcpy(shellname, rindex(shellpgm,'/') ? rindex(shellpgm,'/')+1 : shellpgm);
  62. }
  63.  
  64. /*
  65.  * spawn shell process for window number w
  66.  * Finds first available pty and its matching pts and opens them
  67.  * Returns TRUE if it found you some pty's else FALSE
  68.  */
  69. NewShell(w)
  70.  
  71. register int w;
  72. {
  73.     static char ptlist[] = "0123456789abcdef";
  74.     char ptyname[100], ptsname[100];    /* names of pty master/slave devices */
  75.     int fpty, fpts;            /* descriptors for ""   ""    ""     */
  76.     register int c, i;            /* index */
  77.     int ptydisc;
  78.     extern int errno;
  79.  
  80.  
  81.      /* Look for available pty master/slave pair.
  82.       */
  83.     for (c = 'p';; c++) {
  84.     for (i = 0; ptlist[i]; i++) {
  85.         (void) sprintf(ptyname, "/dev/pty%c%c", c, ptlist[i]);
  86.         if ((fpty = open(ptyname, 2)) < 0) {
  87.         if (errno == ENOENT)
  88.             return(-1);
  89.         continue;
  90.         }
  91.         (void) sprintf(ptsname, "/dev/tty%c%c", c, ptlist[i]);
  92.         if ((fpts = open(ptsname, 2)) < 0) {
  93.         (void) close(fpty);
  94.         continue;
  95.         }
  96.         /* This doesn't close the security hole,
  97.          * but it helps avoid certain problems.
  98.          */
  99.         if (ioctl(fpts, (int)TIOCGETD, (char *)&ptydisc) || ptydisc) {
  100.         (void) close(fpts);
  101.         (void) close(fpty);
  102.         continue;
  103.         }
  104.         /* Okay, this one will do */
  105.         goto gottatty;
  106.     }
  107.     }
  108. gottatty:;
  109.     (void) ioctl(fpty, (int)FIOCLEX, (char *)0);
  110.  
  111.  
  112.  
  113.      /* Fork a new shell.
  114.       */
  115.     switch (win[w].pid=fork())
  116.     {
  117.     default:        /* parent */
  118.     (void) close(fpts);
  119.     win[w].pty=fpty;
  120.     break;
  121.  
  122.     case 0:        /* child */
  123.      /* Set up stdin, stdout, stderr streams. */
  124.     dup2(fpts,0); dup2(fpts,1); dup2(fpts,2);
  125.     if (fpts > 2)
  126.         (void) close(fpts);
  127.      /* Set up slave as new controlling terminal. */
  128.     SetCntrlTerm(ptsname);
  129.      /* Set up process groups. */
  130.     SetProcGrp();
  131.      /* Set pty terminal attributes. */
  132.     InitPseudoTty();
  133.      /* Set env variables TERM & TERMCAP. */
  134. #ifdef SNEAKYTERMCAP
  135.     SetTerm(w, 1);
  136. #else
  137.     (void) setenv("TERM", "wmvirt");
  138.     (void) setenv("TERMCAP", termcap(w));
  139. #endif
  140.      /* Exec the shell. */
  141.     execlp(shellpgm, shellname, (char *)0);
  142.     exit(1);            /* exec failed */
  143.     break;
  144.  
  145.     case -1:        /* fork failed */
  146.     (void) close(fpty);
  147.     (void) close(fpts);
  148.     break;
  149.     }
  150.  
  151.     return(win[w].pid < 0);
  152. }
  153.  
  154. /*
  155.  * Set up terminal attributes for new pseudo-tty.
  156.  * The attributes are those of user's regular terminal.
  157.  * This way, the pseudo-tty will behave just like user's terminal.
  158.  */
  159. InitPseudoTty()
  160. {
  161.      /* Set tty discipline, edit characters,
  162.       * mode, etc.
  163.       */
  164.     (void) ioctl(0, (int)TIOCSETP, (char*)&sgttybuf);
  165.     (void) ioctl(0, (int)TIOCSETD, (char*)&ttydisc);
  166.     (void) ioctl(0, (int)TIOCSETC, (char*)&tcharsbuf);
  167.     (void) ioctl(0, (int)TIOCLSET, (char*)&ttymode);
  168.     (void) ioctl(0, (int)TIOCSLTC, (char*)<charsbuf);
  169. }
  170.  
  171. /*
  172.  * Make 'cterm' the new controlling terminal for
  173.  * this process. Use TIOCNOTTY to turn off
  174.  * current control terminal. Then when we open
  175.  * 'cterm', it automatically becomes the new
  176.  * controlling terminal.
  177.  * Can you say 'kludge'? I knew you could.
  178.  */
  179. SetCntrlTerm(cterm)
  180.  
  181. char *cterm;
  182. {
  183.      /* We really ought to check the return values
  184.       * of these calls. Oh, well.
  185.       */
  186.     (void) ioctl(ttyfd, (int)TIOCNOTTY, (char*)0);
  187.     (void) close(ttyfd);
  188.     ttyfd = open(cterm, 0);
  189.     (void) close(ttyfd);
  190. }
  191.  
  192. /*
  193.  * Set up a new process group for a process.
  194.  * Process group id will be the pid of the current process.
  195.  * Also set up terminal process group for the benefit of
  196.  * csh job control facilities.
  197.  */
  198. SetProcGrp()
  199. {
  200.     int pgrp;
  201.  
  202.     pgrp = getpid();
  203.     (void) setpgrp(0, pgrp);
  204.     (void) ioctl(0, (int)TIOCSPGRP, (char*)&pgrp);
  205. }
  206.  
  207. /*
  208.  * Kill shell (process group) in window 'w'.
  209.  */
  210. KillShell(w)
  211.  
  212. register int w;
  213. {
  214.     if (win[w].pid <= 0)
  215.     return;
  216.  
  217.      /* Close pty file.
  218.       */
  219.     (void) close(win[w].pty);
  220.  
  221.      /* Send SIGHUP to all process associated
  222.       * with window w.
  223.       */
  224.     (void) kill(win[w].pid, SIGHUP);
  225.  
  226. #ifdef SNEAKYTERMCAP
  227.     SetTerm(w, 0);
  228. #endif
  229.     win[w].pid = 0;
  230. }
  231.  
  232. setenv(name, val)
  233.  
  234. char *name, *val;
  235. {
  236.     register int n, i;
  237.     register char **ep, *oldval;
  238.     char *namecmp();
  239.     extern char **environ;
  240.  
  241.  
  242.     ep = environ;
  243.  
  244.      /* See if the environment variable is already set.
  245.       */
  246.     for (n=0; ep[n]!=NULL; n++)
  247.     if ((oldval=namecmp(name,ep[n])) != NULL)
  248.         break;
  249.     
  250.      /* If the environment variable is already set and
  251.       * the new value is no longer than the old one,
  252.       * we can just overwrite the old one.
  253.       */
  254.     if (ep[n] != NULL && strlen(oldval) >= strlen(val))
  255.     strcpy(oldval, val);
  256.  
  257.      /* Else we have to reallocate (name=value).
  258.       */
  259.     else
  260.     {
  261.      /* If environment variable not already set,
  262.       * we have to reallocate entire 'environ' array
  263.       * with one additional slot in order to add the new variable.
  264.       * Make sure to terminate array with a NULL entry.
  265.       */
  266.     if (ep[n] == NULL)
  267.     {
  268.         if ((ep=alloc(n+2, char*)) == NULL)
  269.         return(-1);
  270.  
  271.         for (i=0; i<n; i++)
  272.         ep[i] = environ[i];
  273.  
  274.         ep[n+1] = NULL;
  275.  
  276.         environ = ep;
  277.     }
  278.  
  279.      /* Allocate space for new variable, add it to 'environ'.
  280.       */
  281.     if ((ep[n]=alloc(strlen(name)+strlen(val)+2, char)) == NULL)
  282.         return(-1);
  283.     (void) sprintf(ep[n], "%s=%s", name, val);
  284.     }
  285.  
  286.     return(0);
  287. }
  288.  
  289. static char *namecmp(s1, s2)
  290.  
  291. register char *s1, *s2;
  292. {
  293.     for ( ; *s1==*s2; s1++,s2++)
  294.     ;
  295.  
  296.     if (*s1 == '\0' && *s2 == '=')
  297.     return(s2+1);
  298.  
  299.     return(NULL);
  300. }
  301.