home *** CD-ROM | disk | FTP | other *** search
- /*
- *************
- * DISTRIBUTION NOTICE July 30 1985
- * A Revised Edition of WM, by Matt Lennon and Tom Truscott,
- * Research Triangle Institute, (919) 541-7005.
- * Based on the original by Robert Jacob (decvax!nrl-css!jacob),
- * Naval Research Laboratory, (202) 767-3365.
- * No claims or warranties of any sort are made for this distribution.
- * General permission is granted to copy, but not for profit,
- * any of this distribution, provided that this notice
- * is always included in the copies.
- *************
- */
- /*
- * This file contains routines dealing
- * with the window shells.
- */
-
- #include "wm.h"
- #include <signal.h>
- #include <errno.h>
-
- static struct sgttyb sgttybuf;
- static struct tchars tcharsbuf;
- static struct ltchars ltcharsbuf;
- static int ttymode;
- static int ttydisc;
- static int ttyfd; /* file descriptor for /dev/tty */
-
-
- /*
- * Initialize parameters needed for creating new window shells.
- */
- ShellInit()
- {
- (void) ioctl(0, (int)TIOCGETD, (char*)&ttydisc);
- (void) ioctl(0, (int)TIOCGETC, (char*)&tcharsbuf);
- (void) ioctl(0, (int)TIOCLGET, (char*)&ttymode);
- (void) ioctl(0, (int)TIOCGLTC, (char*)<charsbuf);
- (void) ioctl(0, (int)TIOCGETP, (char*)&sgttybuf);
-
- /*
- * The psuedo-tty driver should probably not produce
- * internal magic delay characters (cf. sys/tty.c (ttyoutput)).
- * It seems easiest to turn off all delays here.
- * (Even that is not all that easy, due to an XTABS glitch.)
- */
- {
- register int i = ALLDELAY;
- if ((sgttybuf.sg_flags&TBDELAY) == XTABS)
- i &= ~TBDELAY;
- sgttybuf.sg_flags &= ~i;
- }
-
- /* We will use 'ttyfd' later when setting
- * controlling terminals for new shells.
- */
- ttyfd = open("/dev/tty", 0);
-
- strcpy(shellpgm, getenv("SHELL") ? getenv("SHELL") : "sh");
- strcpy(shellname, rindex(shellpgm,'/') ? rindex(shellpgm,'/')+1 : shellpgm);
- }
-
- /*
- * spawn shell process for window number w
- * Finds first available pty and its matching pts and opens them
- * Returns TRUE if it found you some pty's else FALSE
- */
- NewShell(w)
-
- register int w;
- {
- static char ptlist[] = "0123456789abcdef";
- char ptyname[100], ptsname[100]; /* names of pty master/slave devices */
- int fpty, fpts; /* descriptors for "" "" "" */
- register int c, i; /* index */
- int ptydisc;
- extern int errno;
-
-
- /* Look for available pty master/slave pair.
- */
- for (c = 'p';; c++) {
- for (i = 0; ptlist[i]; i++) {
- (void) sprintf(ptyname, "/dev/pty%c%c", c, ptlist[i]);
- if ((fpty = open(ptyname, 2)) < 0) {
- if (errno == ENOENT)
- return(-1);
- continue;
- }
- (void) sprintf(ptsname, "/dev/tty%c%c", c, ptlist[i]);
- if ((fpts = open(ptsname, 2)) < 0) {
- (void) close(fpty);
- continue;
- }
- /* This doesn't close the security hole,
- * but it helps avoid certain problems.
- */
- if (ioctl(fpts, (int)TIOCGETD, (char *)&ptydisc) || ptydisc) {
- (void) close(fpts);
- (void) close(fpty);
- continue;
- }
- /* Okay, this one will do */
- goto gottatty;
- }
- }
- gottatty:;
- (void) ioctl(fpty, (int)FIOCLEX, (char *)0);
-
-
-
- /* Fork a new shell.
- */
- switch (win[w].pid=fork())
- {
- default: /* parent */
- (void) close(fpts);
- win[w].pty=fpty;
- break;
-
- case 0: /* child */
- /* Set up stdin, stdout, stderr streams. */
- dup2(fpts,0); dup2(fpts,1); dup2(fpts,2);
- if (fpts > 2)
- (void) close(fpts);
- /* Set up slave as new controlling terminal. */
- SetCntrlTerm(ptsname);
- /* Set up process groups. */
- SetProcGrp();
- /* Set pty terminal attributes. */
- InitPseudoTty();
- /* Set env variables TERM & TERMCAP. */
- #ifdef SNEAKYTERMCAP
- SetTerm(w, 1);
- #else
- (void) setenv("TERM", "wmvirt");
- (void) setenv("TERMCAP", termcap(w));
- #endif
- /* Exec the shell. */
- execlp(shellpgm, shellname, (char *)0);
- exit(1); /* exec failed */
- break;
-
- case -1: /* fork failed */
- (void) close(fpty);
- (void) close(fpts);
- break;
- }
-
- return(win[w].pid < 0);
- }
-
- /*
- * Set up terminal attributes for new pseudo-tty.
- * The attributes are those of user's regular terminal.
- * This way, the pseudo-tty will behave just like user's terminal.
- */
- InitPseudoTty()
- {
- /* Set tty discipline, edit characters,
- * mode, etc.
- */
- (void) ioctl(0, (int)TIOCSETP, (char*)&sgttybuf);
- (void) ioctl(0, (int)TIOCSETD, (char*)&ttydisc);
- (void) ioctl(0, (int)TIOCSETC, (char*)&tcharsbuf);
- (void) ioctl(0, (int)TIOCLSET, (char*)&ttymode);
- (void) ioctl(0, (int)TIOCSLTC, (char*)<charsbuf);
- }
-
- /*
- * Make 'cterm' the new controlling terminal for
- * this process. Use TIOCNOTTY to turn off
- * current control terminal. Then when we open
- * 'cterm', it automatically becomes the new
- * controlling terminal.
- * Can you say 'kludge'? I knew you could.
- */
- SetCntrlTerm(cterm)
-
- char *cterm;
- {
- /* We really ought to check the return values
- * of these calls. Oh, well.
- */
- (void) ioctl(ttyfd, (int)TIOCNOTTY, (char*)0);
- (void) close(ttyfd);
- ttyfd = open(cterm, 0);
- (void) close(ttyfd);
- }
-
- /*
- * Set up a new process group for a process.
- * Process group id will be the pid of the current process.
- * Also set up terminal process group for the benefit of
- * csh job control facilities.
- */
- SetProcGrp()
- {
- int pgrp;
-
- pgrp = getpid();
- (void) setpgrp(0, pgrp);
- (void) ioctl(0, (int)TIOCSPGRP, (char*)&pgrp);
- }
-
- /*
- * Kill shell (process group) in window 'w'.
- */
- KillShell(w)
-
- register int w;
- {
- if (win[w].pid <= 0)
- return;
-
- /* Close pty file.
- */
- (void) close(win[w].pty);
-
- /* Send SIGHUP to all process associated
- * with window w.
- */
- (void) kill(win[w].pid, SIGHUP);
-
- #ifdef SNEAKYTERMCAP
- SetTerm(w, 0);
- #endif
- win[w].pid = 0;
- }
-
- setenv(name, val)
-
- char *name, *val;
- {
- register int n, i;
- register char **ep, *oldval;
- char *namecmp();
- extern char **environ;
-
-
- ep = environ;
-
- /* See if the environment variable is already set.
- */
- for (n=0; ep[n]!=NULL; n++)
- if ((oldval=namecmp(name,ep[n])) != NULL)
- break;
-
- /* If the environment variable is already set and
- * the new value is no longer than the old one,
- * we can just overwrite the old one.
- */
- if (ep[n] != NULL && strlen(oldval) >= strlen(val))
- strcpy(oldval, val);
-
- /* Else we have to reallocate (name=value).
- */
- else
- {
- /* If environment variable not already set,
- * we have to reallocate entire 'environ' array
- * with one additional slot in order to add the new variable.
- * Make sure to terminate array with a NULL entry.
- */
- if (ep[n] == NULL)
- {
- if ((ep=alloc(n+2, char*)) == NULL)
- return(-1);
-
- for (i=0; i<n; i++)
- ep[i] = environ[i];
-
- ep[n+1] = NULL;
-
- environ = ep;
- }
-
- /* Allocate space for new variable, add it to 'environ'.
- */
- if ((ep[n]=alloc(strlen(name)+strlen(val)+2, char)) == NULL)
- return(-1);
- (void) sprintf(ep[n], "%s=%s", name, val);
- }
-
- return(0);
- }
-
- static char *namecmp(s1, s2)
-
- register char *s1, *s2;
- {
- for ( ; *s1==*s2; s1++,s2++)
- ;
-
- if (*s1 == '\0' && *s2 == '=')
- return(s2+1);
-
- return(NULL);
- }
-