File:  [MW Coherent from dump] / coherent / d / bin / sh / exec3.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Wed May 29 04:56:39 2019 UTC (7 years, 2 months ago) by root
Branches: MarkWilliams, MAIN
CVS tags: relic, HEAD
coherent

/*
 * sh/exec3.c
 * Bourne shell.
 * Builtin commands.
 */

#include "sh.h"
#include <sys/times.h>
#include <sys/const.h>		/* HZ defined here */

#define HOUR	(60L*60L*HZ)
#define MINUTE	(60L*HZ)
#define SECOND	HZ

char	*cd();

extern	s_colon();
extern	s_dot();
extern	s_break();
#define s_continue	s_break
extern	s_cd();
extern	s_dirs();
extern	s_eval();
extern	s_exec();
extern	s_exit();
extern	s_export();
extern	s_login();
#define s_newgrp	s_login
extern	s_popd();
extern	s_pushd();
extern	s_read();
#define s_readonly	s_export
extern	s_set();
extern	s_shift();
extern	s_times();
extern	s_trap();
extern	s_umask();
extern	s_wait();
#define SNULL	((int (*)())0)

typedef struct {
	int	i_hash;
	char	*i_name;
	int	(*i_func)();
} INLINE;

INLINE inls[] = {
	0,	":",		s_colon,
	0,	".",		s_dot,
	0,	"break",	s_break,
	0,	"continue",	s_continue,
	0,	"cd",		s_cd,
	0,	"dirs",		s_dirs,
	0,	"eval",		s_eval,
	0,	"exec",		s_exec,
	0,	"exit",		s_exit,
	0,	"export",	s_export,
	0,	"login",	s_login,
	0,	"newgrp",	s_newgrp,
	0,	"popd",		s_popd,
	0,	"pushd",	s_pushd,
	0,	"read",		s_read,
	0,	"readonly",	s_readonly,
	0,	"set",		s_set,
	0,	"shift",	s_shift,
	0,	"times",	s_times,
	0,	"trap",		s_trap,
	0,	"umask",	s_umask,
	0,	"wait",		s_wait,
	0,	NULL,		SNULL
};

inline()
{
	register int (*s_func)();
	register INLINE *ip;
	register int ahash;
	int pid, status;

	if (inls[0].i_hash==0)
		for (ip=inls; ip->i_name!=NULL; ip++)
			ip->i_hash = ihash(ip->i_name);
	if (nargv[0] == NULL)
		return 0;
	ahash = ihash(nargv[0]);
	for (ip=inls; ip->i_name!=NULL; ip++)
		if (ip->i_hash==ahash && strcmp(nargv[0], ip->i_name)==0)
			break;
	if ((s_func=ip->i_func) == SNULL)
		return 0;
	if (*niovp != NULL && s_func != s_exec) {
		/* Redirection with built-in command. */
		/* Allowed only with eval, export, readonly, set, times. */
		if (s_func != s_eval
		 && s_func != s_export
		 && s_func != s_set
		 && s_func != s_times) {
			eredir();
			slret = 1;
			return 1;
		}
		if ((pid = clone()) == 0) {
			/* Perform redirection in child process. */
			if (redirect(niovp) < 0)
				slret = 1;
			else if (s_func == s_eval)
				slret = (*s_func)();
			else {
				/* Kludge stderr output to stdout. */
				dup2(1, 2);
				close(1);
				slret = (*s_func)();
			}
			exit(slret);
			/* NOTREACHED */
		} else {
			/* Parent waits for child and takes its exit status. */
			while (wait(&status) != pid)
				;
			slret = status >> 8;
		}
	} else
		slret = (*s_func)();
	return 1;
}

ihash(cp)
register char *cp;
{
	register int i;
	for (i=0; *cp; i+=*cp++);
	return i;
}

/*
 * Actual builtin functions.
 */
s_colon()
{
	return 0;
}

s_dot()
{
	if (nargc==2) {
		ffind(NULL);
		if (ffind(vpath, nargv[1], 4))
			return session(SFILE, duplstr(strt, 0));
		else {
			ecantfind(nargv[1]);
			return 1;
		}
	} else if (nargc==1)
		return 0;
	syntax();
	return 1;
}

s_break()
{
	register CON *cp;
	register int t;
	register int n;
	int ret;

	ret = nargv[0][0]=='b' ? 2 : 1;
	n = nargc>1 ? atoi(nargv[1]) : 1;
	for (cp = sesp->s_con; cp; cp = cp->c_next) {
		t = cp->c_node->n_type;
		if ((t==NWHILE || t==NFOR || t==NUNTIL) && --n == 0) {
			sesp->s_con = cp;
			longjmp(cp->c_envl, ret);
			break;
		}
		freebuf(cp->c_bpp);
	}
	printe("%s out of bounds", ret==1 ? "Continue" : "Break");
}

/* s_continue is overlaid with s_break */

s_cd()
{
	register char *dir;

	if ((dir = cd((nargc<2) ? vhome : nargv[1])) == NULL)
		return -1;			/* cd failed */
	if (dstack[dstkp] != NULL)
		sfree(dstack[dstkp]);
	dstack[dstkp] = duplstr(dir, 1);	/* update dir stack */
	return 0;
}

s_dirs()
{
	register int i;

	for (i = dstkp; i >= 0; i--)
		fprintf(stderr, "%s ", dstack[i]);
	fputc('\n', stderr);
}

s_eval()
{
	if (nargc>1)
		return session(SARGV, ++nargv);
	else
		return 0;
}

s_exec()
{
	if (redirect(niovp) < 0) {
		if (nargc>1) {
			exit(1);
			NOTREACHED;
		}
		return 1;
	}
	if (nargc==1)
		return 0;
	if (no1flag)
		cleanup(2, NULL);
	dflttrp(ICMD);
	++nargv;
	--nargc;
	nenvp = envlvar(nenvp);
	flexec();
	exit(1);
	NOTREACHED;
}

s_exit()
{
	if (nargc > 1)
		slret = atoi(nargv[1]);
	reset(RUEXITS);
	NOTREACHED;
}

s_export()
{
	register int flag;
	register char **varv;

	flag = nargv[0][0]=='e' ? VEXP : VRDO;
	if (nargc < 2)
		tellvar(flag);
	else
		for (varv=++nargv; *varv; )
			if (namevar(*varv))
				flagvar(*varv++, flag);
			else
				eillvar(*varv++);
	return 0;
}

s_login()
{
	register char *cmd;

	cmd = nargv[0][0]=='l' ? "/bin/login" : "/bin/newgrp";
	execve(cmd, nargv, envlvar(nenvp));
	ecantfind(cmd);
	return 1;
}

/* s_newgrp is overlaid with s_login */

s_popd()
{
	register int i, j, n, ret;

	if (nargc == 1)
		return popd();
	/*
	 * Kludge to pop one or more specific dir stack elements.
	 * Do args backwards so e.g. "popd 2 3 4" works as expected.
	 * Internal indices [0, dstkp] are user indices [dstkp, 0].
	 */
	for (ret = 0, i = nargc-1; i > 0; i--) {
		if ((n = atoi(nargv[i])) == 0)
			ret |= popd();
		else if (n < 0 || n > dstkp) {
			printe("Illegal arg: %d", n);
			ret = -1;
			continue;
		} else {
			j = dstkp - n;
			if (dstack[j] != NULL)
				sfree(dstack[j]);
			for ( ; j < dstkp; j++)
				dstack[j] = dstack[j+1];
			--dstkp;
		}
	}
	return ret;
}

s_pushd()
{
	register char *dir;
	register int i, ret;

	if (nargc == 1) {
		/* Exchange top two stack elements. */
		if (dstkp == 0)
			return 1;		/* only one element on stack */
		dir = dstack[dstkp-1];
		dstack[dstkp-1] = dstack[dstkp];
		dstack[dstkp] = dir;		/* exchange top two */
		return ((cd(dir) == NULL) ? -1 : 0);	/* and cd accordingly */
	}
	/* Push one or more directories to stack. */
	for (ret = 0, i = 1; i < nargc; i++)
		ret |= pushd(nargv[i]);
	return ret;
}

s_read()
{
	SES s;
	register int n, c;
	register char **vp;
	int eol;

	s.s_type = SSTR;
	s.s_flag = 0;
	s.s_ifp = stdin;
	s.s_next = sesp;
	sesp = &s;
	for (eol=0, vp=++nargv, n=--nargc; n; n-=1, vp+=1) {
		if (n==1 && ! eol) {
			strp = strt;
			c = collect('\n', 2);
			if (c == '\n')
				--strp;
			*strp = '\0';
		} else if (! eol) {
			readflag = 1;
			c = yylex();
			readflag = 0;
		} else
			*strt = '\0';
		if (namevar(*vp))
			assnvar(*vp, duplstr(strt, 0));
		else
			eillvar(*vp);
		eol = c=='\n' || c==EOF;
	}
	sesp = s.s_next;
	return c==EOF;
}

/* s_readonly overlaid with s_export */

s_set()
{
	if (nargc < 2) {
		tellvar(0);
		return 0;
	}
	return set(nargc, nargv, 0);
}

s_shift()
{
	register int n;

	n = nargc > 1 ? atoi(nargv[1]) : 1;
	while (n > 0 && sargc > 0) {
		n -= 1;
		sargc -= 1;
		sargp += 1;
	}
	return n!=0;
}

s_times()
{
#if	_I386
#define	tb_cutime	tms_cutime
#define	tb_cstime	tms_cstime
	struct	tms	tb;
#else
	struct tbuffer tb;

#endif

	times(&tb);
	ptime(tb.tb_cutime);
	ptime(tb.tb_cstime);
	prints("\n");
	return 0;
}

s_trap()
{
	register char **vp;
	register char *cp;
	register int err;

	err = 0;
	if (nargc==1)
		return telltrp();
	vp = ++nargv;
	cp = *vp;
	if (class(cp[0], MDIGI)
	 && (cp[1]=='\0' || (class(cp[1], MDIGI) && cp[2]=='\0')))
		cp = NULL;
	else
		++vp;
	while (*vp) {
		if (class(vp[0][0], MDIGI))
			err |= setstrp(atoi(*vp++), cp);
		else {
			printe("Bad trap: %s", *vp++);
			err |= 1;
		}
	}
	return err;
}

s_umask()
{
	if (nargc < 2)
		prints("%03o\n", ufmask);
	else
		umask(ufmask = atoi(nargv[1]));
	return 0;
}

s_wait()
{
	register int f;

	f = (nargc > 1) ? atoi(nargv[1]) : 0;
	if (f > 0)
		f = -f;
	waitc(f);
	return slret;
}

/*
 * Change to given directory.
 * Update global variable CWD accordingly.
 * Return NULL if bad, otherwise full pathname of the directory.
 */
char *
cd(dir) register char *dir;
{
	if (chdir(dir) < 0) {
		printe("%s: bad directory", dir);
		return NULL;
	}
	if (*dir != '/') {
		/*
		 * Find an absolute pathname for the dstack and $CWD.
		 * The directory now in dstack[dstkp] is "." if _getwd() failed
		 * for any reason (e.g., the user lacks search permission
		 * down the path to "/", or "." was rm'ed by another process).
		 * Avoid _getwd() in this case, it can undo the chdir() above.
		 */
		if ((strcmp(dstack[dstkp], ".") == 0)
		 || ((dir = _getwd()) == NULL))
			return NULL;
	}
	assnvar("CWD", dir);
	return dir;
}

/*
 * Pop the directory stack and change to the previous stacked directory.
 */
popd()
{
	if (dstkp == 0) {
		printe("Directory stack underflow");
		return -1;
	}
	if (dstack[dstkp] != NULL)
		sfree(dstack[dstkp]);
	return (cd(dstack[--dstkp]) == NULL ? -1 : 0);
}

/*
 * Change to given directory and add it to the directory stack.
 */
pushd(dir) register char *dir;
{
	if ((dir = cd(dir)) == NULL)
		return -1;			/* cd failed */
	if (++dstkp >= DSTACKN) {
		--dstkp;
		printe("Directory stack overflow");
		return -1;
	}
	dstack[dstkp] = duplstr(dir, 1);
	return 0;
}

/*
 * The set command.  This is also called from `main' to set
 * options from the command line.  In this case `flag' is
 * set.
 */
set(argc, argv, flag)
register char *argv[];
{
	int n;
	register char *cp;

	if (flag) {
		cflag = 0;
		iflag = 0;
		sflag = 0;
	}
	n = 0;
	if (argc > 0)
		n = 1;
	if (argc>1 && argv[1][0]=='-') {
		register char *fp;

		n++;
		for (cp = &argv[1][1]; *cp; cp++) {
			if ((fp=index(shfnams, *cp)) == NULL
			 || (fp+=shflags-shfnams) == NULL
			 || (fp != &lgnflag && fp > &xflag && flag == 0))
				printe("-%c: Bad option", *cp);
			else if (fp != &lgnflag)
				*fp = *cp;
		}
		if (cp == &argv[1][1]) {
			vflag = 0;
			xflag = 0;
		}
		if (flag == 0 && argc == 2)
			return errflag;
	}
	if (errflag)
		return 1;
	if (sargv != NULL)
		vfree(sargv);
	sargv = vdupl(argv);
	sargc = argc - n;
	sargp = sargv + n;
	return 0;
}

/*
 * print the time as XmX.Xs
 * as fixed by Randall.
 */
ptime(t)
long t;
{
	register int ticks, tenths, seconds;

	prints("%Dm", t/MINUTE);
	ticks = t%MINUTE;
	seconds = ticks/SECOND;
	tenths = (ticks%SECOND + SECOND/20)/(SECOND/10);
	if (tenths == 10) {
		tenths = 0;
		seconds++;
	}
	prints("%d.%ds ", seconds, tenths);
}

/* end of sh/exec3.c */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.