Ultrix-3.1/src/cmd/sh5/xec.c
/**********************************************************************
* Copyright (c) Digital Equipment Corporation 1984, 1985, 1986. *
* All Rights Reserved. *
* Reference "/usr/src/COPYRIGHT" for applicable restrictions. *
**********************************************************************/
/*
* SCCSID: @(#)xec.c 3.0 4/22/86
* (System V) xec.c 1.8
*/
/*
*
* UNIX shell
*
* Bell Telephone Laboratories
*
*/
#include "defs.h"
#include <errno.h>
#include "sym.h"
#include "hash.h"
static int parent;
/* ======== command execution ========*/
execute(argt, exec_link, errorflg, pf1, pf2)
struct trenod *argt;
int *pf1, *pf2;
{
/*
* `stakbot' is preserved by this routine
*/
register struct trenod *t;
char *sav = savstak();
sigchk();
if (!errorflg)
flags &= ~errflg;
if ((t = argt) && execbrk == 0)
{
register int treeflgs;
int type;
register char **com;
short pos;
int linked;
int execflg;
linked = exec_link >> 1;
execflg = exec_link & 01;
treeflgs = t->tretyp;
type = treeflgs & COMMSK;
switch (type)
{
case TFND:
{
struct fndnod *f = (struct fndnod *)t;
struct namnod *n = lookup(f->fndnam);
exitval = 0;
if (n->namflg & N_RDONLY)
failed(n->namid, wtfailed);
if (n->namflg & N_FUNCTN)
freefunc(n);
else
{
free(n->namval);
free(n->namenv);
n->namval = 0;
n->namflg &= ~(N_EXPORT | N_ENVCHG);
}
if (funcnt)
f->fndval->tretyp++;
n->namenv = (char *)f->fndval;
attrib(n, N_FUNCTN);
hash_func(n->namid);
break;
}
case TCOM:
{
char *a1;
int argn, internal;
struct argnod *schain = gchain;
struct ionod *io = t->treio;
short cmdhash;
short comtype;
exitval = 0;
gchain = 0;
argn = getarg(t);
com = scan(argn);
a1 = com[1];
gchain = schain;
if (argn != 0)
cmdhash = pathlook(com[0], 1, comptr(t)->comset);
if (argn == 0 || (comtype = hashtype(cmdhash)) == BUILTIN)
setlist(comptr(t)->comset, 0);
if (argn && (flags&noexec) == 0)
{
/* print command if execpr */
if (flags & execpr)
execprint(com);
if (comtype == NOTFOUND)
{
pos = hashdata(cmdhash);
if (pos == 1)
failed(*com, notfound);
else if (pos == 2)
failed(*com, badexec);
else
failed(*com, badperm);
break;
}
else if (comtype == PATH_COMMAND)
{
pos = -1;
}
else if (comtype & (COMMAND | REL_COMMAND))
{
pos = hashdata(cmdhash);
}
else if (comtype == BUILTIN)
{
short index;
internal = hashdata(cmdhash);
index = initio(io, (internal != SYSEXEC));
switch (internal)
{
case SYSDOT:
if (a1)
{
register int f;
if ((f = pathopen(getpath(a1), a1)) < 0)
failed(a1, notfound);
else
execexp(0, f);
}
break;
case SYSTIMES:
{
long int t[4];
times(t);
prt(t[2]);
prc_buff(SP);
prt(t[3]);
prc_buff(NL);
}
break;
case SYSEXIT:
flags |= forked; /* force exit */
exitsh(a1 ? stoi(a1) : retval);
case SYSNULL:
io = 0;
break;
case SYSCONT:
if (loopcnt)
{
execbrk = breakcnt = 1;
if (a1)
breakcnt = stoi(a1);
if (breakcnt > loopcnt)
breakcnt = loopcnt;
else
breakcnt = -breakcnt;
}
break;
case SYSBREAK:
if (loopcnt)
{
execbrk = breakcnt = 1;
if (a1)
breakcnt = stoi(a1);
if (breakcnt > loopcnt)
breakcnt = loopcnt;
}
break;
case SYSTRAP:
if (a1)
{
BOOL clear;
if ((clear = digit(*a1)) == 0)
++com;
while (*++com)
{
int i;
if ((i = stoi(*com)) >= MAXTRAP || i < MINTRAP)
failed(*com, badtrap);
else if (clear)
clrsig(i);
else
{
replace(&trapcom[i], a1);
if (*a1)
getsig(i);
else
ignsig(i);
}
}
}
else /* print out current traps */
{
int i;
for (i = 0; i < MAXTRAP; i++)
{
if (trapcom[i])
{
prn_buff(i);
prs_buff(colon);
prs_buff(trapcom[i]);
prc_buff(NL);
}
}
}
break;
case SYSEXEC:
com++;
ioset = 0;
io = 0;
if (a1 == 0)
{
break;
}
#ifdef RES /* Research includes login as part of the shell */
case SYSLOGIN:
oldsigs();
execa(com, -1);
done();
#else
case SYSNEWGRP:
if (flags & rshflg)
failed(com[0], restricted);
else
{
flags |= forked; /* force bad exec to terminate shell */
oldsigs();
execa(com, -1);
done();
}
#endif
case SYSCD:
if (flags & rshflg)
failed(com[0], restricted);
else if ((a1 && *a1) || (a1 == 0 && (a1 = homenod.namval)))
{
char *cdpath;
char *dir;
int f;
if ((cdpath = cdpnod.namval) == 0 ||
*a1 == '/' ||
cf(a1, ".") == 0 ||
cf(a1, "..") == 0 ||
(*a1 == '.' && (*(a1+1) == '/' || *(a1+1) == '.' && *(a1+2) == '/')))
cdpath = nullstr;
do
{
dir = cdpath;
cdpath = catpath(cdpath,a1);
}
while ((f = (chdir(curstak()) < 0)) && cdpath);
if (f)
failed(a1, baddir);
else
{
cwd(curstak());
if (cf(nullstr, dir) &&
*dir != ':' &&
any('/', curstak()) &&
flags & prompt)
{
prs_buff(curstak());
prc_buff(NL);
}
}
zapcd();
}
else
{
if (a1)
failed(a1, baddir);
else
error(nohome);
}
break;
case SYSSHFT:
{
int places;
places = a1 ? stoi(a1) : 1;
if ((dolc -= places) < 0)
{
dolc = 0;
error(badshift);
}
else
dolv += places;
}
break;
case SYSWAIT:
await(a1 ? stoi(a1) : -1, 1);
break;
case SYSREAD:
rwait = 1;
exitval = readvar(&com[1]);
rwait = 0;
break;
case SYSSET:
if (a1)
{
int argc;
argc = options(argn, com);
if (argc > 1)
setargs(com + argn - argc);
}
else if (comptr(t)->comset == 0)
{
/*
* scan name chain and print
*/
namscan(printnam);
}
break;
case SYSRDONLY:
exitval = 0;
if (a1)
{
while (*++com)
attrib(lookup(*com), N_RDONLY);
}
else
namscan(printro);
break;
case SYSXPORT:
{
struct namnod *n;
exitval = 0;
if (a1)
{
while (*++com)
{
n = lookup(*com);
if (n->namflg & N_FUNCTN)
error(badexport);
else
attrib(n, N_EXPORT);
}
}
else
namscan(printexp);
}
break;
case SYSEVAL:
if (a1)
execexp(a1, &com[2]);
break;
#ifndef RES
case SYSULIMIT:
{
long int i;
long ulimit();
int command = 2;
if (*a1 == '-')
{ switch(*(a1+1))
{
case 'f':
command = 2;
break;
#ifdef rt
case 'p':
command = 5;
break;
#endif
default:
error(badopt);
}
a1 = com[2];
}
if (a1)
{
int c;
i = 0;
while ((c = *a1++) >= '0' && c <= '9')
{
i = (i * 10) + (long)(c - '0');
if (i < 0)
error(badulimit);
}
if (c || i < 0)
error(badulimit);
}
else
{
i = -1;
command--;
}
if ((i = ulimit(command,i)) < 0)
error(badulimit);
if (command == 1 || command == 4)
{
prl(i);
prc_buff('\n');
}
break;
}
case SYSUMASK:
if (a1)
{
int c, i;
i = 0;
while ((c = *a1++) >= '0' && c <= '7')
i = (i << 3) + c - '0';
umask(i);
}
else
{
int i, j;
umask(i = umask(0));
prc_buff('0');
for (j = 6; j >= 0; j -= 3)
prc_buff(((i >> j) & 07) +'0');
prc_buff(NL);
}
break;
#endif
case SYSTST:
exitval = test(argn, com);
break;
case SYSECHO:
exitval = echo(argn, com);
break;
case SYSHASH:
exitval = 0;
if (a1)
{
if (a1[0] == '-')
{
if (a1[1] == 'r')
zaphash();
else
error(badopt);
}
else
{
while (*++com)
{
if (hashtype(hash_cmd(*com)) == NOTFOUND)
failed(*com, notfound);
}
}
}
else
hashpr();
break;
case SYSPWD:
{
exitval = 0;
cwdprint();
}
break;
case SYSRETURN:
if (funcnt == 0)
error(badreturn);
execbrk = 1;
exitval = (a1 ? stoi(a1) : retval);
break;
case SYSTYPE:
exitval = 0;
if (a1)
{
while (*++com)
what_is_path(*com);
}
break;
case SYSUNS:
exitval = 0;
if (a1)
{
while (*++com)
unset_name(*com);
}
break;
default:
prs_buff("unknown builtin\n");
}
flushb();
restore(index);
chktrap();
break;
}
else if (comtype == FUNCTION)
{
struct namnod *n;
short index;
n = findnam(com[0]);
funcnt++;
index = initio(io, 1);
setargs(com);
execute((struct trenod *)(n->namenv), exec_link, errorflg, pf1, pf2);
execbrk = 0;
restore(index);
funcnt--;
break;
}
}
else if (t->treio == 0)
{
chktrap();
break;
}
}
case TFORK:
exitval = 0;
if (execflg && (treeflgs & (FAMP | FPOU)) == 0)
parent = 0;
else
{
int forkcnt = 1;
if (treeflgs & (FAMP | FPOU))
{
link_iodocs(iotemp);
linked = 1;
}
/*
* FORKLIM is the max period between forks -
* power of 2 usually. Currently shell tries after
* 2,4,8,16, and 32 seconds and then quits
*/
while ((parent = fork()) == -1)
{
if ((forkcnt = (forkcnt * 2)) > FORKLIM) /* 32 */
{
switch (errno)
{
case ENOMEM:
error(noswap);
break;
default:
case EAGAIN:
error(nofork);
break;
}
}
sigchk();
alarm(forkcnt);
pause();
}
}
if (parent)
{
/*
* This is the parent branch of fork;
* it may or may not wait for the child
*/
if (treeflgs & FPRS && flags & ttyflg)
{
prn(parent);
newline();
}
if (treeflgs & FPCL)
closepipe(pf1);
if ((treeflgs & (FAMP | FPOU)) == 0)
await(parent, 0);
else if ((treeflgs & FAMP) == 0)
post(parent);
else
assnum(&pcsadr, parent);
chktrap();
break;
}
else /* this is the forked branch (child) of execute */
{
flags |= forked;
fiotemp = 0;
if (linked == 1)
{
swap_iodoc_nm(iotemp);
exec_link |= 06;
}
else if (linked == 0)
iotemp = 0;
#ifdef ACCT
suspacct();
#endif
postclr();
settmp();
/*
* Turn off INTR and QUIT if `FINT'
* Reset ramaining signals to parent
* except for those `lost' by trap
*/
oldsigs();
if (treeflgs & FINT)
{
signal(SIGINT, 1);
signal(SIGQUIT, 1);
#ifdef NICE
nice(NICEVAL);
#endif
}
/*
* pipe in or out
*/
if (treeflgs & FPIN)
{
rename(pf1[INPIPE], 0);
close(pf1[OTPIPE]);
}
if (treeflgs & FPOU)
{
close(pf2[INPIPE]);
rename(pf2[OTPIPE], 1);
}
/*
* default std input for &
*/
if (treeflgs & FINT && ioset == 0)
rename(chkopen(devnull), 0);
/*
* io redirection
*/
initio(t->treio, 0);
if (type != TCOM)
{
execute(forkptr(t)->forktre, exec_link | 01, errorflg);
}
else if (com[0] != ENDARGS)
{
eflag = 0;
setlist(comptr(t)->comset, N_EXPORT);
rmtemp(0);
execa(com, pos);
}
done();
}
case TPAR:
execute(parptr(t)->partre, exec_link, errorflg);
done();
case TFIL:
{
int pv[2];
chkpipe(pv);
if (execute(lstptr(t)->lstlef, 0, errorflg, pf1, pv) == 0)
execute(lstptr(t)->lstrit, exec_link, errorflg, pv, pf2);
else
closepipe(pv);
}
break;
case TLST:
execute(lstptr(t)->lstlef, 0, errorflg);
execute(lstptr(t)->lstrit, exec_link, errorflg);
break;
case TAND:
if (execute(lstptr(t)->lstlef, 0, 0) == 0)
execute(lstptr(t)->lstrit, exec_link, errorflg);
break;
case TORF:
if (execute(lstptr(t)->lstlef, 0, 0) != 0)
execute(lstptr(t)->lstrit, exec_link, errorflg);
break;
case TFOR:
{
struct namnod *n = lookup(forptr(t)->fornam);
char **args;
struct dolnod *argsav = 0;
if (forptr(t)->forlst == 0)
{
args = dolv + 1;
argsav = useargs();
}
else
{
struct argnod *schain = gchain;
gchain = 0;
trim((args = scan(getarg(forptr(t)->forlst)))[0]);
gchain = schain;
}
loopcnt++;
while (*args != ENDARGS && execbrk == 0)
{
assign(n, *args++);
execute(forptr(t)->fortre, 0, errorflg);
if (breakcnt < 0)
execbrk = (++breakcnt != 0);
}
if (breakcnt > 0)
execbrk = (--breakcnt != 0);
loopcnt--;
argfor = (struct dolnod *)freeargs(argsav);
}
break;
case TWH:
case TUN:
{
int i = 0;
loopcnt++;
while (execbrk == 0 && (execute(whptr(t)->whtre, 0, 0) == 0) == (type == TWH))
{
i = execute(whptr(t)->dotre, 0, errorflg);
if (breakcnt < 0)
execbrk = (++breakcnt != 0);
}
if (breakcnt > 0)
execbrk = (--breakcnt != 0);
loopcnt--;
exitval = i;
}
break;
case TIF:
if (execute(ifptr(t)->iftre, 0, 0) == 0)
execute(ifptr(t)->thtre, exec_link, errorflg);
else if (ifptr(t)->eltre)
execute(ifptr(t)->eltre, exec_link, errorflg);
else
exitval = 0; /* force zero exit for if-then-fi */
break;
case TSW:
{
register char *r = mactrim(swptr(t)->swarg);
register struct regnod *regp;
regp = swptr(t)->swlst;
while (regp)
{
struct argnod *rex = regp->regptr;
while (rex)
{
register char *s;
if (gmatch(r, s = macro(rex->argval)) || (trim(s), eq(r, s)))
{
execute(regp->regcom, 0, errorflg);
regp = 0;
break;
}
else
rex = rex->argnxt;
}
if (regp)
regp = regp->regnxt;
}
}
break;
}
exitset();
}
sigchk();
tdystak(sav);
flags |= eflag;
return(exitval);
}
execexp(s, f)
char *s;
int f;
{
struct fileblk fb;
push(&fb);
if (s)
{
estabf(s);
fb.feval = (char **)(f);
}
else if (f >= 0)
initf(f);
execute(cmd(NL, NLFLG | MTFLG), 0, (int)(flags & errflg));
pop();
}
execprint(com)
char **com;
{
register int argn = 0;
prs(execpmsg);
while(com[argn] != ENDARGS)
{
prs(com[argn++]);
blank();
}
newline();
}