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 e

⟦90bcbb65d⟧ TextFile

    Length: 7711 (0x1e1f)
    Types: TextFile
    Names: »exec.c«

Derivation

└─⟦a0efdde77⟧ Bits:30001252 EUUGD11 Tape, 1987 Spring Conference Helsinki
    └─ ⟦this⟧ »EUUGD11/euug-87hel/sec8/uutty/exec.c« 

TextFile

#include "uutty.h"
/* 
** Start up a new program in the current process.  This is normally
** to start up a shell for a logged-in user.   If the command can't
** be executed, -1 is returned.	 Note that we can define a new search
** path here which will overwrite the one we were given.
*/
	Flag  forkfl = 0;	/* Should we fork or exec directly? */
	Flag  pathfl = 0;	/* True if PATH defined in environment */
/*
** The 'path' variable should be defined appropriately for your
** system.  If it is null, we will just pass on the path that
** was handed to us, which may be right on many systems.
*/
#ifdef Cadmus
	char *path = "PATH=:.:/bin:/bin.cadmus:/bin.sys5:/bin.sys3:/bin.ver7:/usr/ucb:/usr/bin:/etc:/usr/local:/usr/new:";
#define Path
#endif
#ifdef VME
	char *path = "PATH=:.:/bin:/usr/bin:/etc:";
#define Path
#endif
#ifndef Path
	char *path = 0;		/* No search path */
#endif

exec(cook,cmd,pp)
	int   cook;		/* Should we do cooked or raw I/O? */
	char *cmd;		/* Null-terminated command */
	struct passwd *pp;	/* The user's /etc/passwd entry, unpacked */
{	int   a, c, e, i, n, r;
	int   child;
	Flag  lognfl, shelfl, homefl;
	char *av[10];		/* This should be room enough */
	char *cp, *dp;
	char**ev;
	char  arg0[30];		/* For shell's visible name */
	char  logn[30];		/* For LOGNAME=<id> string */
	char  home[30];		/* For HOME=<dir> string */
	char  shll[30];		/* For SHELL=<prog> string */
	char *shell="/bin/sh";	/* default shell */
	extern long malloc();

	D5("exec(%d,\"%s\",%06lX)",cook,cmd,pp);
	r = -1;
	for (i=0; environ[i]; i++);	/* How big is environ[]? */
	n = (i+5) * sizeof(char**);	/* Space for copy + 5 entries */
	D5("exec: Get %d bytes for %d+5 environment entries.",n,i);
	ev = (char**)malloc(n);		/* Allocate a copy for us */
	if (ev == NULL) {
		E("Can't get %d bytes for environment table [exec].",n);
		Fail;
	}
	for (e=0; environ[e]; e++) {	/* Copy the environment vector */
		ev[e] = environ[e];
		D6("ev[%2d]=\"%s\"",e,ev[e]);
	}
	ev[e] = 0;
	D3("exec: There are %d environment entries.",e);
	pid = getpid();
	D4("exec: This is process %d.",pid);
	a = e = 0;			/* indices for av[] and ev[] */
	for (cp=cmd; *cp; ++cp) {	/* Scan the command for whitespace */
		c = *cp;
		if (c == ' ' || c == '\t') {
			av[a++] = "-sh";
			av[a++] = "-c";
			av[a++] = cmd;
			break;
		} else
		if (c == ':' || c == '\n') break;
	}
	if (a == 0) {				/* the command is just a program name */
		shell = cmd;			/* Note that it's our shell */
		dp = av[a++] = arg0;		/* Name to tell shell */
		*dp++ = '-';			/* Build arg0 with initial '-' */
		cp = lastfield(cmd,'/');	/* Find the last field of the name */
		while (*cp) *dp++ = *cp++;	/* Copy name to arg0 */
		*dp = 0;			/* Gotta have a null terminator */
		D4("exec: arg0=\"%s\"",arg0);
	}
	D3("av[%2d]=\"%s\"",a-1,av[a-1]);

	D7("exec:before sprintf(%06lX,\"%s\",%06lX)",logn,"LOGNAME=%s\0",pp->pw_name);
	sprintf(logn,"LOGNAME=%s\0",pp->pw_name);
	D6("exec: after sprintf() logn=\"%s\"",logn);

	D7("exec:before sprintf(%06lX,\"%s\",%06lX)",home,"HOME=%s\0"   ,pp->pw_dir);
	sprintf(home,"HOME=%s\0"   ,pp->pw_dir);
	D6("exec: after sprintf() home=\"%s\"",home);

	D7("exec:before sprintf(%06lX,\"%s\",%06lX)",shll,"SHELL=%s\0"  ,shell);
	sprintf(shll,"SHELL=%s\0"  ,shell);
	D6("exec: after sprintf() shll=\"%s\"",shll);

	if (debug >= 5) {
		av[a++] = "-VX";		/* This turns on shell debugging */
		D3("av[%2d]=\"%s\"",a-1,av[a-1]);
	}
	av[a] = 0;			/* Paranoia */
/*
** This is supposed to help, but seems not to:
**
	D4("exec: before setpgrp()");
	i = setpgrp();
	D4("exec: setpgrp()=%d",i);
*/
	lognfl = shelfl = homefl = 0;		/* Flags for noticing environment entries */
	for (e=0; ev[e]; e++) {			/* Examine the environment table */
		D3("exec: Examine ev[%2d]=%06lX=\"%s\"",e,ev[e],ev[e]);
		if (st_init("PATH=",ev[e]) > 0) {
			D7("exec: Matched \"PATH=\"; path=%06lX=\"%s\"",path,path);
			if (path) ev[e] = path;	/* Use special path */
			D6("ev[%2d]=\"%s\"",e,ev[e]);
			pathfl++;		/* Note we did it */
		}
		if (st_init("LOGNAME=",ev[e]) > 0) {
			ev[e] = logn;		/* Use special path */
			D6("ev[%2d]=\"%s\"",e,ev[e]);
			lognfl++;		/* Note we did it */
		}
		if (st_init("HOME=",ev[e]) > 0) {
			ev[e] = home;		/* Use special path */
			D6("ev[%2d]=\"%s\"",e,ev[e]);
			homefl++;		/* Note we did it */
		}
		if (st_init("SHELL=",ev[e]) > 0) {
			ev[e] = shll;		/* Use special path */
			D6("ev[%2d]=\"%s\"",e,ev[e]);
			shelfl++;		/* Note we did it */
		}
	}
	if (!homefl) ev[e++] = home;	/* Add the home directory */
	if (!lognfl) ev[e++] = logn;	/* Add the login id */
	if (!shelfl) ev[e++] = shll;	/* Add the shell's name */
	if (!pathfl) ev[e++] = path;	/* Add the search path (may be null) */
	D3("exec: There are %d environment entries.",e);
	ev[e] = 0;			/* Paranoia */
	if (debug >= 3) {		/* Display the shell's parameters */
		P("before execve(\"%s\",%lX,%lX)",shell,av,ev);
		for (i=0; av[i]; i++)
			P("arg[%2d]=\"%s\"",i,av[i]);
		for (i=0; ev[i]; i++)
			P("env[%2d]=\"%s\"",i,ev[i]);
	}
	if (debug) P("%s Start %s for u=%d=%s g=%d.",getime(),shell,pp->pw_uid,pp->pw_name,pp->pw_gid);
	if (cook) makesane(dev);
	if (dev != 0) {close(0); i = dup(dev); D3("exec: File %d=\"%s\"",i,device); }
	if (dev != 1) {close(1); i = dup(dev); D3("exec: File %d=\"%s\"",i,device); }
	child = -1;			/* Default is no child process */
	pid = getpid();			/* Note which process we are now */
	if (forkfl) {			/* Are we forking or execing directly? */
		D4("exec: Forking sub-process for shell.");
		if (lockfl) {		/* Should we create a lockfile? */
			lockfn = creat(lockfile,0);
			if (debug >= 2)
				P("%s: Create lockfile %d=\"%s\".",getime(),lockfn,lockfile);
			if (lockfn < 0) {	/* Either locked or directory isn't writable */
				E("Can't create lockfile \"%s\" [errno=%d]",lockfile,errno);
				die(errno);
			}
			locked = 1;		/* Note that there's a lockfile */
		}
		if ((child = fork()) > 0) {	/* Are we the parent? */
			D3("exec: %s: Shell process %d created.",getime(),child);	
			if (lsleep > 0) sleep(lsleep);
			for (;;) {		/* Loop until shell goes away */
				errno = 0;
				r = wait(0);		/* Sleep until a subprocess dies */
				D3("%s: wait(0)=%d",getime(),r);
				if (r == child)		/* Was it the shell process? */
					Done;		/* If so, all's fine */
				D3("%s: After wait(0)=%d [errno=%d]",getime(),r,errno);
				if (r > 0) {
					E("%s: Wrong child %d died; waiting for %d.",getime(),r,child);
					continue;
				}
				switch(errno) {
				case ECHILD:
					D3("exec: wait(0)=%d [errno=%d=No child]",r,errno);
					Done;
				default:
					E("Unknown errno=%d after wait(0)=%d",errno,r);
					Done;
				}
			}			/* Hang until the shell process dies */
done:			if (debug) sleep(1);
			D3("exec: %s: Child %d gone.",getime(),r);
			if (r > 0) r = 0;
			if (lockfl) unlock();
			if (debug) P("%s: \"%s\" done , die(%d)",getime(),shell,r);
			Fail;
		}
	}
/* 
** If we fall through to here, we are the process to exec a shell.
** We may be the original process or a subprocess.
*/
	if (debug > 1) {
		pid = getpid();
		P("%s: Shell process %d.",getime(),pid);
	}
	if (dev != 2) { close(2); i = dup(dev); }
	/**** Don't produce debug output after this! */
	errno = 0;
	if (dev>2) close(dev);	/* Don't give excess open files to the shell */
	r = execve(shell,av,ev);
	E("Can't exec \"%s\"\t[errno=%d]",shell,errno);
/*
** Note that we always terminate, regardless of how we get here.
** If we are being run from init(1), a new process will be started
** up.  If not, we just go away.  This isn't necessary, but seems
** in general to be a good idea.
*/
fail:				/* Both processes come here to terminate */
	if (lsleep > 0)
		sleep(lsleep);	/* Don't respawn too fast */
	die(r);			/* This will respawn if we're a daemon */
}