Files
seta75D 7c4988eac0 Init
2021-10-11 19:38:01 -03:00

711 lines
14 KiB
C
Executable File

#ident "@(#)main.c 1.13 95/07/17 SMI" /* From AT&T Toolchest */
/*
* UNIX shell
*
* S. R. Bourne
* Rewritten by David Korn
* AT&T Bell Laboratories
*
*/
#include <errno.h>
#include "defs.h"
#include "jobs.h"
#include "sym.h"
#include "history.h"
#include "timeout.h"
#include "builtins.h"
#ifdef pdp11
# include <execargs.h>
#endif /* pdp11 */
#ifdef TIOCLBIC
# undef TIOCLBIC
# ifdef _sys_ioctl_
# include <sys/ioctl.h>
# endif /* _sys_ioctl_ */
#endif /* TIOCLBIC */
/* These routines are referenced by this module */
extern int gscan_some();
static void exfile();
static void pr_prompt();
static void chkmail();
static int notstacked();
static void dfault();
static void swallow();
static char *nospace();
extern char **environ;
static struct fileblk topfile;
static time_t mailtime;
static char beenhere = 0;
#ifdef _lib_sigvec
void clearsigmask(sig)
register int sig;
{
struct sigvec vec;
if(sigvec(sig,(struct sigvec*)0,&vec)>=0 && vec.sv_mask)
{
vec.sv_mask = 0;
sigvec(sig,&vec,(struct sigvec*)0);
}
}
#endif /* _lib_sigvec */
main(c, v)
int c;
register char *v[];
{
register char *sim;
register int rsflag; /* local restricted flag */
char *command;
int prof;
#ifdef MTRACE
extern int Mt_certify;
Mt_certify = 1;
#endif /* MTRACE */
#ifdef _lib_sigvec
clearsigmask(SIGALRM);
clearsigmask(SIGHUP);
clearsigmask(SIGCHLD);
#endif /* _lib_sigvec */
st.standout = 1;
sh.cpipe[0] = -1;
sh.userid=getuid();
sh.euserid=geteuid();
sh.groupid=getgid();
sh.egroupid=getegid();
time(&mailtime);
stakinstall((Stak_t*)0,nospace);
/* set up memory for name-value pairs */
nam_init();
/* set name-value pairs from userenv
* 'rsflag' is zero if SHELL variable is
* set in environment and contains an'r' in
* the basename part of the value.
*/
rsflag=env_init();
/* a shell is also restricted if argv(0) has
* an 'rsh' for its basename
*/
sim = path_basename(*v);
if(*sim=='-')
{
sim++;
sh.login_sh = 2;
signal(SIGXCPU, SIG_DFL);
signal(SIGXFSZ, SIG_DFL);
}
sig_init();
/* check for restricted shell */
if(c>0 && strmatch(sim,"@(rk|kr|r)sh"))
rsflag=0;
/* look for options */
/* st.dolc is $# */
st.dolc=arg_opts(c,v,0);
st.dolv=v+c-st.dolc--;
st.dolv[0] = v[0];
if(st.dolc < 1)
on_option(STDFLG);
if(!is_option(STDFLG))
{
st.dolc--;
st.dolv++;
}
/* set[ug]id scripts require the -p flag */
prof = !is_option(PRIVM);
if(sh.userid!=sh.euserid || sh.groupid!=sh.egroupid)
{
#ifdef P_SUID
/* require sh -p to run setuid and/or setgid */
if(!is_option(PRIVM) && sh.userid >= P_SUID)
{
setuid(sh.euserid=sh.userid);
setgid(sh.egroupid=sh.groupid);
}
else
#else
{
on_option(PRIVM);
prof = 0;
}
#endif /* P_SUID */
#ifdef SHELLMAGIC
/* careful of #! setuid scripts with name beginning with - */
if(sh.login_sh && eq(v[0],v[1]))
sh_fail(e_prohibited,NIL);
#endif /*SHELLMAGIC*/
}
else
off_option(PRIVM);
if(is_option(RSHFLG))
{
rsflag = 0;
off_option(RSHFLG);
}
sh.shname = st.dolv[0]; /* shname for $0 in profiles */
/*
* return here for shell file execution
* but not for parenthesis subshells
*/
st.cmdadr = st.dolv[0]; /* cmdadr is $0 */
SETJMP(sh.subshell);
command = st.cmdadr;
/* set pidname '$$' */
sh.pid = getpid();
io_settemp(sh.pid);
srand(sh.pid&0x7fff);
sh.ppid = getppid();
dfault(PS4NOD,e_traceprompt);
#ifdef apollo
/*
* The following code initializes apollo specific features.
* See description below for more details.
*/
{
extern char *getenv();
/*
* initialize the SYSTYPENOD internal data. Use
* the current "SYSTYPE" environment variable value
* as the initial value.
*/
dfault(SYSTYPENOD,getenv("SYSTYPE"));
/*
* if the current systype is not bsd..., then
* set the default path to the sys5.3 default path.
* It is setup in this order because the default path
* for bsd4.3 is longer than the sys5.3, this order insures that
* there is always enough storage space allocated.
*/
if (strncmp(SYSTYPENOD->value.namval.cp, "bsd", 3) != 0)
{
/* change the default path of bsd4.3 to sys5.3 */
strcpy(e_defpath,"/bin:/usr/bin:/usr/apollo/bin:");
}
/*
* setup cd and pwd to use physical instead of
* logical path.
*/
on_option(PHYSICAL);
}
#endif /* apollo */
path_pwd(1);
if((beenhere++)==0)
{
st.states |= PROFILE;
/* decide whether shell is interactive */
#ifdef WEXP
if (is_option(ONEFLG|CFLAG) == 0 && is_option(STDFLG) &&
!is_option(WEXP_E) &&
#else
if (is_option(ONEFLG|CFLAG) == 0 && is_option(STDFLG) &&
#endif
tty_check(0) && tty_check(ERRIO))
on_option(INTFLG|BGNICE);
if(sh.ppid==1)
sh.login_sh++;
if(sh.login_sh >= 2)
{
/* ? profile */
sh.login_sh += 2;
job_init(1);
/* system profile */
if((input=path_open(e_sysprofile,NULLSTR)) >= 0)
{
st.cmdadr = (char*)e_sysprofile;
exfile(); /* file exists */
io_fclose(input);
}
if(prof && (input=path_open(mac_try((char*)e_profile),NULLSTR)) >= 0)
{
st.cmdadr = path_basename(e_profile);
exfile();
io_fclose(input);
}
}
/* make sure PWD is set up correctly */
path_pwd(0);
if(prof)
sim = mac_try(nam_strval(ENVNOD));
else if(is_option(PRIVM))
sim = (char*)e_suidprofile;
else
sim = NULLSTR;
if(*sim && (input = path_open(sim,NULLSTR)) >= 0)
{
st.cmdadr = sh_heap(sim);
exfile();
free(st.cmdadr);
st.cmdadr = command;
io_fclose(input);
}
st.cmdadr = command;
st.states &= ~PROFILE;
if(rsflag==0)
{
on_option(RSHFLG);
nam_ontype(PATHNOD,N_RESTRICT);
nam_ontype(ENVNOD,N_RESTRICT);
nam_ontype(SHELLNOD,N_RESTRICT);
}
/* open input file if specified */
st.cmdline = 0;
st.standin = 0;
if(sh.comdiv)
{
shell_c:
st.standin = &topfile;
io_sopen(sh.comdiv);
input = F_STRING;
}
else
{
sim = st.cmdadr;
st.cmdadr = v[0];
if(is_option(STDFLG))
input = 0;
else
{
char *sp;
/* open stream should have been passed into shell */
if(strmatch(sim,e_devfdNN))
{
struct stat statb;
input = atoi(sim+8);
if(fstat(input,&statb)<0)
sh_fail(st.cmdadr,e_open);
sim = st.cmdadr;
off_option(EXECPR|READPR);
}
else
{
#ifdef VFORK
if(strcmp(sim,path_basename(*environ))==0)
sp = (*environ)+2;
else
#endif /* VFORK */
sp = path_absolute(sim);
if(!sp || (input=open(sp,O_RDONLY))<0)
{
#ifndef VFORK
/* for compatibility with bsh */
if((input=open(sim,O_RDONLY))<0)
#endif /* VFORK */
{
if(sp || errno!=ENOENT)
sh_fail(sim,e_open);
/* try sh -c 'name "$@"' */
on_option(CFLAG);
sh.comdiv = malloc(strlen(sim)+7);
sim = sh_copy(sim,sh.comdiv);
if(st.dolc)
sh_copy(" \"$@\"",sim);
goto shell_c;
}
}
}
sh.readscript = v[0];
}
st.cmdadr = sim;
sh.comdiv--;
#ifdef ACCT
initacct();
if(input != 0)
preacct(st.cmdadr);
#endif /* ACCT */
}
if(!is_option(INTFLG))
{
/* eliminate local aliases and functions */
gscan_some(env_nolocal,sh.alias_tree,N_EXPORT,0);
gscan_some(env_nolocal,sh.fun_tree,N_EXPORT,0);
}
}
#ifdef pdp11
else
*execargs=(char *) st.dolv; /* for `ps' cmd */
#endif /* pdp11 */
st.states |= is_option(INTFLG);
#ifdef WEXP
if (is_option(WEXP_E)) {
char *ifsptr;
if ((ifsptr=(char *)getenv((node_names+
(IFSNOD-sh.bltin_nodes))->nv_name)) != (char *)NULL)
nam_fputval(IFSNOD,ifsptr);
else
nam_fputval(IFSNOD,(char*)e_sptbnl);
} else
#endif /* WEXP */
nam_fputval(IFSNOD,(char*)e_sptbnl);
exfile();
if(st.states&PROMPT)
newline();
sh_done(0);
/* NOTREACHED */
}
static void exfile()
{
time_t curtime;
union anynode *t;
register struct fileblk *fp = st.standin;
register int fno = input;
int maxtry = MAXTRY;
int execflags;
int jmpval;
/* move input */
if(fno!=F_STRING)
{
if(fno > 0)
{
fno = input = io_renumber(fno,INIO);
io_ftable[0] = 0;
}
io_init(input=fno,(struct fileblk*)0,NIL);
st.standin = fp = io_ftable[fno];
if(is_option(ONEFLG) && !(st.states&PROFILE))
fp->flag |= IONBF;
}
if(st.states&INTFLG)
{
dfault(PS1NOD, (sh.euserid?e_stdprompt:e_supprompt));
fp->flag |= IOEDIT;
sig_ignore(SIGTERM);
if(hist_open())
{
on_option(FIXFLG);
}
if(sh.login_sh<=1)
job_init(0);
}
else
{
if(!(st.states&PROFILE))
{
on_option(HASHALL);
off_option(MONITOR);
}
st.states &= ~(PROMPT|MONITOR|FIXFLG);
off_option(FIXFLG);
}
jmpval = SETJMP(sh.errshell);
if(jmpval && (st.states&PROFILE))
{
io_fclose(fno);
st.states &= ~(INTFLG|MONITOR);
return;
}
else if (!is_option(INTFLG) && jmpval == 5) /* exit */
{
/* jmpval == 5 for error in special builtin - Exit immediately */
st.states &= ~(PROMPT|PROFILE|BUILTIN|FUNCTION|LASTPIPE);
sh_exit(sh.exitval);
}
/* error return here */
opt_char = 0;
opt_index = 1;
sh.freturn = (jmp_buf*)sh.errshell;
st.loopcnt = 0;
st.peekn = 0;
st.linked = 0;
st.fn_depth = 0;
sh.trapnote = 0;
sh.intrap = 0;
if(fiseof(fp))
goto eof_or_error;
/* command loop */
while(1)
{
sh_freeup();
stakset((char*)0,0);
exitset();
st.states &= ~(ERRFLG|READPR|GRACE|MONITOR);
st.states |= is_option(READPR)|WAITING|ERRFLG;
/* -eim flags don't apply to profiles */
if(st.states&PROFILE)
st.states &= ~(INTFLG|ERRFLG|MONITOR);
p_setout(ERRIO);
if((st.states&PROMPT) && notstacked() && !fiseof(fp))
{
register char *mail;
#ifdef JOBS
st.states |= is_option(MONITOR);
job_walk(job_list,N_FLAG,(char**)0);
#endif /* JOBS */
if((mail=nam_strval(MAILPNOD)) || (mail=nam_strval(MAILNOD)))
{
time(&curtime);
if ((curtime - mailtime) >= sh_mailchk)
{
chkmail(mail);
mailtime = curtime;
}
}
if(hist_ptr)
hist_eof();
pr_prompt(mac_try(nam_strval(PS1NOD)));
/* sets timeout for command entry */
#ifdef TIMEOUT
if(sh_timeout <= 0 || sh_timeout > TIMEOUT)
sh_timeout = TIMEOUT;
#endif /* TIMEOUT */
if(sh_timeout>0)
alarm((unsigned)sh_timeout);
fp->flin = 1;
}
st.peekn = io_readc();
if(fiseof(fp) || fiserror(fp))
{
eof_or_error:
if((st.states&PROMPT) && notstacked() && fiserror(fp)==0)
{
clearerr(fp);
st.peekn = 0;
if(--maxtry>0 && is_option(NOEOF) &&
!fiserror(&io_stdout) && tty_check(fno))
{
p_str(e_logout,NL);
continue;
}
else if(job_close()<0)
continue;
hist_close();
}
return;
}
maxtry = MAXTRY;
if(sh_timeout>0)
alarm(0);
if((st.states&PROMPT) && hist_ptr && st.peekn)
{
hist_eof();
p_char(st.peekn);
p_setout(ERRIO);
}
st.states |= is_option(FIXFLG);
st.states &= ~ WAITING;
st.cmdline = fp->flin;
job.waitall = job.pipeflag = 0;
t = sh_parse(NL,MTFLG);
sh.readscript = 0;
if((st.states&PROMPT) && hist_ptr)
{
if(t==0 && nextchar(st.standin)=='#')
swallow(st.standin);
hist_flush();
}
if(t)
{
execflags = (ERRFLG|MONITOR|PROMPT);
/* sh -c simple-command may not have to fork */
if(!(st.states&PROFILE) && is_option(CFLAG) && nextchar(fp)==0)
execflags |= 1;
st.execbrk = 0;
p_setout(ERRIO);
sh_exec(t,execflags);
/* This is for sh -t */
if(is_option(ONEFLG))
{
io_unreadc(NL);
fp->flag |= IOEOF;
}
}
}
}
/*
* if there is pending input, the prompt is not printed.
* prints PS2 if flag is zero otherwise PS3
*/
void sh_prompt(flag)
register int flag;
{
register char *cp;
register struct fileblk *fp;
if(flag || (st.states&PROMPT) && notstacked())
{
if(flag)
fp = io_ftable[0];
else
fp = st.standin;
/* if characters are in input buffer don't issue prompt */
if(fp && finbuff(fp))
return;
if(cp = nam_fstrval(flag?PS3NOD:PS2NOD))
{
flag = output;
p_setout(ERRIO);
p_str(cp,0);
p_setout(flag);
}
}
}
/* prints out messages if files in list have been modified since last call */
static void chkmail(files)
char *files;
{
register char *cp,*sp,*qp;
register char save;
struct stat statb;
if(*(cp=files) == 0)
return;
sp = cp;
do
{
/* skip to : or end of string saving first '?' */
for(qp=0;*sp && *sp != ':';sp++)
if((*sp == '?' || *sp=='%') && qp == 0)
qp = sp;
save = *sp;
*sp = 0;
/* change '?' to end-of-string */
if(qp)
*qp = 0;
st.gchain = NULL;
do
{
/* see if time has been modified since last checked
* and the access time <= the modification time
*/
if(stat(cp,&statb) >= 0 && statb.st_mtime >= mailtime
&& statb.st_atime <= statb.st_mtime)
{
/* check for directory */
if(st.gchain==NULL && S_ISDIR(statb.st_mode))
{
/* generate list of directory entries */
f_complete(cp,"/*");
}
else
{
/*
* If the size is zero
* then don't print anything
*/
if(statb.st_size != 0)
{
/* save and restore $_ */
char *save = sh.lastarg;
sh.lastarg = cp;
p_str(mac_try(qp==0?(char*)e_mailmsg:qp+1),NL);
sh.lastarg = save;
}
break;
}
}
if(st.gchain)
{
cp = st.gchain->argval;
st.gchain = st.gchain->argchn;
}
else
cp = NULL;
}
while(cp);
if(qp)
*qp = '?';
*sp++ = save;
cp = sp;
}
while(save);
stakset((char*)0,0);
}
/*
* print the primary prompt
*/
static void pr_prompt(str)
register char *str;
{
register int c;
static short cmdno;
#ifdef TIOCLBIC
int mode;
mode = LFLUSHO;
ioctl(ERRIO,TIOCLBIC,&mode);
#endif /* TIOCLBIC */
p_flush();
p_setout(ERRIO);
for(;c= *str;str++)
{
if(c==FC_CHAR)
{
/* look at next character */
c = *++str;
/* print out line number if not !! */
if(c!= FC_CHAR)
p_num(hist_ptr?hist_ptr->fixind:++cmdno,0);
if(c==0)
break;
}
p_char(c);
}
#if VSH || ESH
*io_ftable[ERRIO]->ptr = 0;
/* prompt flushed later */
#else
p_flush();
#endif
}
static void dfault(np,value)
register struct namnod *np;
char *value;
{
if(isnull(np))
nam_fputval(np,value);
}
static notstacked()
{
register struct fileblk *fp;
/* clean up any completed aliases */
while((fp=st.standin)->ftype==F_ISALIAS && fp->flast==0)
io_pop(1);
return(fp->fstak==0);
}
/*
* swallow up additional comment lines and put them into the history file
*/
static void swallow(fp)
struct fileblk *fp;
{
register char *sp = fp->ptr;
register char *ep;
p_setout(hist_ptr->fixfd);
for(ep=sp; *ep; ep++)
{
if(*ep==NL)
{
*ep = 0;
p_str(sp,NL);
*ep++ = NL;
if(*(sp=ep)!='#')
break;
}
}
fp->ptr = sp;
}
static char *nospace()
{
sh_fail(e_space,NIL);
return((char*)0);
}