DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - download
Index: ┃ T s

⟦6666aaf43⟧ TextFile

    Length: 7153 (0x1bf1)
    Types: TextFile
    Names: »shell.c«

Derivation

└─⟦87ddcff64⟧ Bits:30001253 CPHDIST85 Tape, 1985 Autumn Conference Copenhagen
    └─ ⟦this⟧ »cph85dist/wm/shell.c« 

TextFile

/*
 *************
 * 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*)&ltcharsbuf);
    (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*)&ltcharsbuf);
}

/*
 * 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);
}