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

2851 lines
51 KiB
C
Executable File

#ident "@(#)builtin.c 1.19 95/04/10 SMI" /* From AT&T Toolchest */
/*
* builtin routines for the shell
*
* David Korn
* AT&T Bell Laboratories
* Room 3C-526B
* Murray Hill, N. J. 07974
* Tel. x7975
*
*/
#include <limits.h>
#include <wait.h>
#include <errno.h>
#include "defs.h"
#include "history.h"
#include "builtins.h"
#include "jobs.h"
#include "sym.h"
#define NOT_USED(x) (&x,1) /* prevents not used messages */
#ifdef _sys_resource_
# ifndef included_sys_time_
# include <sys/time.h>
# endif
# include <sys/resource.h>/* needed for ulimit */
# define LIM_FSIZE RLIMIT_FSIZE
# define LIM_DATA RLIMIT_DATA
# define LIM_STACK RLIMIT_STACK
# define LIM_CORE RLIMIT_CORE
# define LIM_CPU RLIMIT_CPU
# define INFINITY RLIM_INFINITY
# ifdef RLIMIT_RSS
# define LIM_MAXRSS RLIMIT_RSS
# endif /* RLIMIT_RSS */
#else
# ifdef VLIMIT
# include <sys/vlimit.h>
# endif /* VLIMIT */
#endif /* _sys_resource_ */
#ifdef UNIVERSE
static int att_univ = -1;
# ifdef _sys_universe_
# include <sys/universe.h>
# ifdef sequent
define NUMUNIV 2
static char *univ_name[] = { "ucb", "att", 0};
# define getuniverse(x) (flag=universe(U_GET),\
(flag>-1?strncpy(x,univ_name[flag],TMPSIZ):0),\
flag)
# define univ_index(n) (n)
# define setuniverse(x) universe(x)
# else /* !sequent */
# define getuniverse(x) (setuniverse(flag=setuniverse(0)),\
(--flag>=0?strncpy(x,univ_name[flag],TMPSIZ):0),\
flag)
# define univ_index(n) ((n)+1)
# endif /* sequent */
# else
# define univ_number(x) (x)
# endif /* _sys_universe_ */
#endif /* UNIVERSE */
#ifdef ECHOPRINT
# undef ECHO_RAW
# undef ECHO_N
#endif /* ECHOPRINT */
#define DOTMAX 32 /* maximum level of . nesting */
#define PHYS_MODE H_FLAG
#define LOG_MODE N_LJUST
/* This module references these external routines */
#ifdef ECHO_RAW
extern char *echo_mode();
#endif /* ECHO_RAW */
extern int gscan_all();
extern char *utos();
extern void ltou();
static int b_common();
static int b_unall();
static int flagset();
static int sig_number();
static int scanargs();
#ifdef JOBS
static void sig_list();
#endif /* JOBS */
static int argnum;
static int aflag;
static int newflag;
static int echon;
static int scoped;
void rehash();
extern const char *xecmsg;
#define READ S_IRUSR|S_IRGRP|S_IROTH
#define WRITE S_IWUSR|S_IWGRP|S_IWOTH
#define EXEC S_IXUSR|S_IXGRP|S_IXOTH
static void unalias_nam();
static void unalias_all();
static void umask_sprint();
extern int optind;
extern char *optarg;
extern int _sp;
int b_exec(argn,com)
char **com;
{
st.ioset = 0;
if(*++com)
b_login(argn,com);
return(0);
}
int b_login(argn,com)
char **com;
{
NOT_USED(argn);
if(is_option(RSHFLG))
sh_cfail(e_restricted);
else
{
#ifdef JOBS
if(job_close() < 0)
return(1);
#endif /* JOBS */
/* force bad exec to terminate shell */
st.states &= ~(PROFILE|PROMPT|BUILTIN|LASTPIPE);
sig_reset(0);
hist_close();
sh_freeup();
if(st.states&RM_TMP)
/* clean up all temp files */
rm_files(io_tmpname);
path_exec(com,(struct argnod*)0);
sh_done(0);
}
return(1);
}
int b_pwd(argn,com)
char **com;
{
register int flag=0;
register char *a1 = com[1];
NOT_USED(argn);
#if defined(LSTAT) || defined(FS_3D)
while(a1 && *a1=='-'&&
(flag = flagset(a1,~(PHYS_MODE|LOG_MODE))))
{
if(flag&LOG_MODE)
flag = 0;
com++;
a1 = com[1];
}
#endif /* LSTAT||FS_3D */
if(*(a1 = path_pwd(0))!='/')
sh_cfail(e_pwd);
#if defined(LSTAT) || defined(FS_3D)
if(flag)
{
char *path = a1;
/* reserve PATH_MAX bytes on stack */
int offset = staktell();
stakseek(offset+PATH_MAX);
a1 = stakseek(offset)+offset;
# ifdef FS_3D
if(umask(flag=umask(0)),flag&01000)
mount(".", a1, 10|(PATH_MAX)<<4);
else
# endif /* FS_3D */
a1 = strncpy(stakseek(offset),path,PATH_MAX);
#ifdef LSTAT
path_physical(a1);
stakseek(offset);
#endif /* LSTAT */
}
#endif /* LSTAT||FS_3D */
p_setout(st.standout);
p_str(a1,NL);
return(0);
}
#ifndef ECHOPRINT
int b_echo(argn,com)
int argn;
char **com;
{
register int r;
char *save = *com;
# ifdef ECHO_RAW
/* This mess is because /bin/echo on BSD is archaic */
# ifdef UNIVERSE
if(att_univ < 0)
{
int flag;
char Xuniverse[TMPSIZ];
if(getuniverse(Xuniverse) >= 0)
att_univ = (strcmp(Xuniverse,"att")==0);
}
if(att_univ>0)
*com = (char*)e_minus;
else
# endif /* UNIVERSE */
*com = echo_mode();
r = b_print(argn+1,com-1);
*com = save;
return(r);
# else
# ifdef ECHO_N
/* same as echo except -n special */
echon = 1;
return(b_print(argn,com));
# else
/* equivalent to print - */
*com = (char*)e_minus;
r = b_print(argn+1,com-1);
*com = save;
return(r);
# endif /* ECHO_N */
# endif /* ECHO_RAW */
}
#endif /* ECHOPRINT */
int b_print(argn,com)
int argn;
char **com;
{
register int fd;
register char *a1 = com[1];
register int flag = 0;
register int r=0;
const char *msg = e_file;
int raw = 0;
NOT_USED(argn);
argnum = 1;
while(a1 && *a1 == '-')
{
int c = *(a1+1);
com++;
/* echon set when only -n is legal */
if(echon)
{
if(strcmp(a1,"-n")==0)
c = 0;
else
{
com--;
break;
}
}
newflag = flagset(a1,~(N_FLAG|R_FLAG|P_FLAG|U_FLAG|S_FLAG|N_RJUST));
flag |= newflag;
/* handle the -R flag for BSD style echo */
if(flag&N_RJUST)
echon = 1;
if(c==0 || newflag==0)
break;
a1 = com[1];
}
echon = 0;
argnum %= 10;
if(flag&(R_FLAG|N_RJUST))
raw = 1;
if(flag&S_FLAG)
{
/* print to history file */
if(!hist_open())
sh_cfail(e_history);
fd = hist_ptr->fixfd;
st.states |= FIXFLG;
goto skip;
}
else if(flag&P_FLAG)
{
fd = COTPIPE;
msg = e_query;
}
else if(flag&U_FLAG)
fd = argnum;
else
fd = st.standout;
if(r = !fiswrite(fd))
{
if(fd==st.standout)
return(r);
sh_cfail(msg);
}
if(fd==input)
sh_cfail(msg);
skip:
p_setout(fd);
if(echo_list(raw,com+1) && (flag&N_FLAG)==0)
#ifdef WEXP
{
if (opt_flags & WEXP_E)
p_char(0);
else
newline();
}
#else
newline();
#endif /* WEXP */
if(flag&S_FLAG)
hist_flush();
return(r);
}
int b_let(argn,com)
register int argn;
char **com;
{
register int r;
if(argn < 2)
sh_cfail(e_nargs);
while(--argn)
r = !sh_arith(*++com);
return(r);
}
/*
* The following few builtins are provided to set,print,
* and test attributes and variables for shell variables,
* aliases, and functions.
* In addition, typeset -f can be used to test whether a
* function has been defined or to list all defined functions
* Note readonly is same as typeset -r.
* Note export is same as typeset -x.
*/
int b_readonly(argn,com)
char **com;
{
NOT_USED(argn);
if (com[1] && *com[1] == '-')
com += scanargs(com,~P_FLAG);
aflag = '-';
argnum = scoped = 0;
return(b_common(com,R_FLAG,sh.var_tree));
}
int b_export(argn,com)
char **com;
{
NOT_USED(argn);
if (com[1] && *com[1] == '-')
com += scanargs(com,~P_FLAG);
aflag = '-';
argnum = scoped = 0;
return(b_common(com,X_FLAG,sh.var_tree));
}
int b_alias(argn,com)
register char **com;
{
register int ch;
register int flag = 0;
register struct Amemory *troot;
int save_index = opt_index;
int save_char = opt_char;
NOT_USED(argn);
argnum = scoped = 0;
if (com[1])
aflag= *com[1];
else
aflag = 0;
opt_char = 0;
opt_index = 1;
opt_plus = 1;
while((ch = optget(com, ":tx"))) {
switch (ch) {
case 't':
flag |= T_FLAG;
break;
case 'x':
flag |= N_EXPORT;
break;
default:
sh_cfail(e_option);
break;
}
}
com += opt_index - 1;
opt_index = save_index;
opt_char = save_char;
if(flag&T_FLAG)
troot = sh.track_tree;
else
troot = sh.alias_tree;
return(b_common(com,flag,troot));
}
int b_typeset(argn,com)
register char **com;
{
register int flag = 0;
struct Amemory *troot;
NOT_USED(argn);
argnum = scoped = 0;
if(com[1])
{
if( (aflag= *com[1]) == '-' || aflag == '+')
{
com += scanargs(com,~(N_LJUST|N_RJUST|N_ZFILL
|N_INTGER|N_LTOU |N_UTOL|X_FLAG|R_FLAG
|F_FLAG|T_FLAG|N_HOST
|N_DOUBLE|N_EXPNOTE));
flag = newflag;
}
}
else
aflag = 0;
/* G_FLAG forces name to be in newest scope */
if(st.fn_depth)
scoped = G_FLAG;
if((flag&N_INTGER) && (flag&(N_LJUST|N_RJUST|N_ZFILL|F_FLAG)))
sh_cfail(e_option);
else if(flag&F_FLAG)
{
if(flag&~(N_EXPORT|F_FLAG|T_FLAG|U_FLAG))
sh_cfail(e_option);
troot = sh.fun_tree;
flag &= ~F_FLAG;
}
else
troot = sh.var_tree;
return(b_common(com,flag,troot));
}
static int b_common(com,flag,troot)
register int flag;
char **com;
struct Amemory *troot;
{
register int fd;
register char *a1;
register int type = 0;
int r = 0;
fd = st.standout;
p_setout(fd);
if(troot==sh.alias_tree)
/* env_namset treats this value specially */
type = (V_FLAG|G_FLAG);
if(aflag == 0)
{
if(type)
env_scan(fd,0,troot,0);
else
gscan_all(env_prattr,troot);
return(0);
}
if(com[1])
{
while(a1 = *++com)
{
register unsigned newflag;
register struct namnod *np;
unsigned curflag;
if(st.subflag && (flag || strchr(a1,'=')))
continue;
if(troot == sh.fun_tree)
{
/*
*functions can be exported or
* traced but not set
*/
if(flag&U_FLAG)
np = env_namset(a1,sh.fun_tree,P_FLAG|V_FLAG);
else
np = nam_search(a1,sh.fun_tree,0);
if(np && is_abuiltin(np))
np = 0;
if(np && ((flag&U_FLAG) || !isnull(np) || nam_istype(np,U_FLAG)))
{
if(flag==0)
{
env_prnamval(np,0);
continue;
}
if(aflag=='-')
nam_ontype(np,flag|N_FUNCTION);
else if(aflag=='+')
nam_offtype(np,~flag);
}
else
r++;
continue;
}
np = env_namset(a1,troot,(type|scoped));
/* tracked alias */
if(troot==sh.track_tree && aflag=='-')
{
nam_ontype(np,NO_ALIAS);
path_alias(np,path_absolute(np->namid));
continue;
}
if(flag==0 && aflag!='-' && strchr(a1,'=') == NULL)
{
/* type==0 for TYPESET */
if(type && (isnull(np) || !env_prnamval(np,0)))
{
p_setout(ERRIO);
p_str(a1,':');
p_str(e_alias,NL);
r++;
p_setout(st.standout);
}
continue;
}
curflag = namflag(np);
if (aflag == '-')
{
newflag = curflag;
if(flag&~NO_CHANGE)
newflag &= NO_CHANGE;
newflag |= flag;
if (flag & (N_LJUST|N_RJUST))
{
if (flag & N_LJUST)
newflag &= ~N_RJUST;
else
newflag &= ~N_LJUST;
}
if (flag & N_UTOL)
newflag &= ~N_LTOU;
else if (flag & N_LTOU)
newflag &= ~N_UTOL;
}
else
{
if((flag&R_FLAG) && (curflag&R_FLAG))
sh_fail(np->namid,e_readonly);
newflag = curflag & ~flag;
}
if (aflag && (argnum>0 || (curflag!=newflag)))
{
if(type)
namflag(np) = newflag;
else
nam_newtype (np, newflag,argnum);
nam_newtype (np, newflag,argnum);
}
}
}
else
env_scan(fd,flag,troot,aflag=='+');
return(r);
}
/*
* The removing of Shell variable names, aliases, and functions
* is performed here.
* Unset functions with unset -f
* Non-existent items being deleted give non-zero exit status
*/
int b_unalias(argn,com)
char **com;
{
register int ch;
register int aflg = 0;
int save_index = opt_index;
int save_char = opt_char;
NOT_USED(argn);
if (com[1])
aflag = (*com[1] == '-' ? '-' : 1);
else
aflag = 0;
opt_char = 0;
opt_index = 1;
opt_plus = 0;
while((ch = optget(com, ":a"))) {
switch (ch) {
case 'a':
aflg++;
break;
default:
sh_cfail(e_option);
break;
}
}
com += opt_index -1;
argn -= opt_index -1;
opt_index = save_index;
opt_char = save_char;
if (aflg) {
unalias_all(sh.alias_tree);
return (0);
} else
return(b_unall(argn,com,sh.alias_tree));
}
int b_unset(argn,com)
register char **com;
{
register int ch;
struct Amemory *troot;
int save_index = opt_index;
int save_char = opt_char;
troot = sh.var_tree;
if (com[1])
aflag = (*com[1] == '-' ? '-' : 1);
else
aflag = 0;
opt_char = 0;
opt_index = 1;
opt_plus = 0;
while((ch = optget(com, ":fv"))) {
switch (ch) {
case 'f':
troot = sh.fun_tree;
break;
case 'v':
troot = sh.var_tree;
break;
default:
sh_cfail(e_option);
break;
}
}
com += opt_index - 1;
argn -= opt_index - 1;
opt_index = save_index;
opt_char = save_char;
return(b_unall(argn,com,troot));
}
static int b_unall(argn,com,troot)
register int argn;
char **com;
struct Amemory *troot;
{
register char *a1;
register struct namnod *np;
register struct slnod *slp;
int r = 0;
if(st.subflag)
return(0);
if(argn < 2)
sh_cfail(e_nargs);
while(a1 = *++com)
{
np=env_namset(a1,troot,P_FLAG);
if(np && !isnull(np))
{
if(troot==sh.var_tree)
{
if (nam_istype (np, N_RDONLY))
sh_fail(np->namid,e_readonly);
else if (nam_istype (np, N_RESTRICT))
sh_fail(np->namid,e_restricted);
#ifdef apollo
{
short namlen;
namlen =strlen(np->namid);
ev_$delete_var(np->namid,&namlen);
}
#endif /* apollo */
}
else if(is_abuiltin(np))
{
r = 1;
continue;
}
else if(slp=(struct slnod*)(np->value.namenv))
{
/* free function definition */
stakdelete(slp->slptr);
np->value.namenv = 0;
}
nam_free(np);
}
else
r = 1;
}
return(r);
}
int b_dot(argn,com)
char **com;
{
register char *a1 = com[1];
st.states &= ~MONITOR;
if(a1)
{
register int flag;
jmp_buf retbuf;
jmp_buf *savreturn = sh.freturn;
#ifdef notdef /* #ifdef POSIX */
/* check for function first */
register struct namnod *np;
np = nam_search(a1,sh.fun_tree,0);
if(np && !np->value.namval.ip)
{
if(!nam_istype(np,N_FUNCTION))
np = 0;
else
{
path_search(a1,0);
if(np->value.namval.ip==0)
sh_fail(a1,e_found);
}
}
if(!np)
#endif /* POSIX */
if((sh.un.fd=path_open(a1,path_get(a1))) < 0)
sh_fail(a1,e_found);
else
{
if(st.dot_depth++ > DOTMAX)
sh_cfail(e_recursive);
if(argn > 2)
arg_set(com+1);
st.states |= BUILTIN;
sh.freturn = (jmp_buf*)retbuf;
flag = SETJMP(retbuf);
if(flag==0)
{
#ifdef notdef /* ifdef POSIX */
if(np)
sh_exec((union anynode*)(funtree(np))
,(int)(st.states&(ERRFLG|MONITOR)));
else
#endif /* POSIX */
sh_eval((char*)0);
}
st.states &= ~BUILTIN;
sh.freturn = savreturn;
st.dot_depth--;
if(sh.exitval > SIGFAIL)
sh_fault(sh.exitval-SIGFAIL);
if(flag && flag!=2)
if (flag == 4) /* exit command */
sh_exit(sh.exitval);
else
LONGJMP(*sh.freturn,flag);
}
}
else
sh_cfail(e_argexp);
return(sh.exitval);
}
int b_times()
{
struct tms tt;
times(&tt);
p_setout(st.standout);
p_time(tt.tms_utime,' ');
p_time(tt.tms_stime,NL);
p_time(tt.tms_cutime,' ');
p_time(tt.tms_cstime,NL);
return(0);
}
/*
* return and exit
*/
int b_ret_exit(argn,com)
register char **com;
{
register int flag;
register int isexit = (**com=='e');
NOT_USED(argn);
if(st.subflag)
return(0);
flag = ((com[1]?atoi(com[1]):sh.oldexit)&EXITMASK);
if(st.fn_depth>0 || (!isexit && (st.dot_depth>0||(st.states&PROFILE))))
{
sh.exitval = flag;
LONGJMP(*sh.freturn,isexit?4:2);
}
/* force exit */
st.states &= ~(PROMPT|PROFILE|BUILTIN|FUNCTION|LASTPIPE);
sh_exit(flag);
return(1);
}
/*
* null command
*/
int b_null(argn,com)
register char **com;
{
NOT_USED(argn);
return(**com=='f');
}
int b_continue(argn,com)
register char **com;
{
NOT_USED(argn);
if(!st.subflag && st.loopcnt)
{
st.execbrk = st.breakcnt = 1;
if (com[1]) {
if (getnum(com[1], &st.breakcnt) == 0) {
if (st.breakcnt < 1)
return (1);
} else
/* Serious syntax error ? */
sh_cfail(e_number);
}
if(st.breakcnt > st.loopcnt)
st.breakcnt = st.loopcnt;
else
st.breakcnt = -st.breakcnt;
}
return(0);
}
int b_break(argn,com)
register char **com;
{
NOT_USED(argn);
if(!st.subflag && st.loopcnt)
{
st.execbrk = st.breakcnt = 1;
if(com[1]) {
if (getnum(com[1], &st.breakcnt) == 0) {
if (st.breakcnt < 1)
return (1);
} else
/* Serious syntax error ? */
sh_cfail(e_number);
}
if(st.breakcnt > st.loopcnt)
st.breakcnt = st.loopcnt;
}
return(0);
}
int b_trap(argn,com)
char **com;
{
register char *a1 = com[1];
register int sig;
register int r = 0;
NOT_USED(argn);
if(a1)
{
register int clear;
char *action = a1;
if(st.subflag)
return(0);
/* first argument all digits or - means clear */
while(isdigit(*a1))
a1++;
clear = (a1!=action && *a1==0);
if(!clear)
{
++com;
if(*action=='-' && action[1]==0)
clear++;
}
while(a1 = *++com)
{
sig = sig_number(a1);
if(sig>=MAXTRAP || sig<MINTRAP)
/* XPG4: shell does not abort */
r = ERROR;
else if(clear)
sig_clear(sig);
else
{
if(a1=st.trapcom[sig])
free(a1);
st.trapcom[sig] = sh_heap(action);
if(*action)
sig_ontrap(sig);
else
sig_ignore(sig);
}
}
}
else /* print out current traps */
#ifdef POSIX
sig_list(-1);
#else
{
p_setout(st.standout);
for(sig=0; sig<MAXTRAP; sig++)
if(st.trapcom[sig])
{
p_num(sig,':');
p_str(st.trapcom[sig],NL);
}
}
#endif /* POSIX */
return(r);
}
int b_chdir(argn,com)
char **com;
{
register char *a1 = com[1];
register const char *dp;
register char *cdpath = NULLSTR;
int flag = 0;
int rval = -1;
char *oldpwd;
if(st.subflag)
return(0);
if(is_option(RSHFLG))
sh_cfail(e_restricted);
#ifdef LSTAT
#ifdef apollo
/*
* support for the apollo "set -o physical" feature.
*/
flag = is_option(PHYSICAL);
#endif /* apollo */
while(a1 && *a1=='-' && a1[1])
{
flag = flagset(a1,~(PHYS_MODE|LOG_MODE));
if(flag&LOG_MODE)
flag = 0;
com++;
argn--;
a1 = com[1];
}
#endif /* LSTAT */
if(argn >3)
sh_cfail(e_nargs);
oldpwd = sh.pwd;
if(argn==3)
a1 = sh_substitute((oldpwd?oldpwd:a1),a1,com[2]);
else if(a1==0 || *a1==0)
a1 = nam_strval(HOME);
else if(*a1 == '-' && *(a1+1) == 0)
a1 = nam_strval(OLDPWDNOD);
if(a1==0 || *a1==0)
sh_cfail(argn==3?e_subst:e_direct);
if(*a1 != '/')
cdpath = nam_fstrval(CDPNOD);
if(cdpath==0)
cdpath = NULLSTR;
if(*a1=='.')
{
/* test for pathname . ./ .. or ../ */
if(*(dp=a1+1) == '.')
dp++;
if(*dp==0 || *dp=='/')
cdpath = NULLSTR;
}
do
{
dp = cdpath;
cdpath=path_join((char*)dp,a1);
if(*stakptr(OPATH)!='/')
{
char *last=(char*)stakfreeze(1);
if(!oldpwd)
oldpwd = path_pwd(0);
stakseek(OPATH);
stakputs(oldpwd);
stakputc('/');
stakputs(last+OPATH);
stakputc(0);
}
#ifdef LSTAT
if(!flag)
#endif /* LSTAT */
{
register char *cp;
#ifdef FS_3D
if(!(cp = pathcanon(stakptr(OPATH))))
continue;
/* eliminate trailing '/' */
while(*--cp == '/' && cp>stakptr(OPATH))
*cp = 0;
#else
if(*(cp=stakptr(OPATH))=='/')
if(!pathcanon(cp))
continue;
#endif /* FS_3D */
}
rval = chdir(path_relative(stakptr(OPATH)));
}
while(rval<0 && cdpath);
/* use absolute chdir() if relative chdir() fails */
if(rval<0 && *a1=='/' && *(path_relative(stakptr(OPATH)))!='/')
rval = chdir(a1);
#ifdef apollo
/*
* The label is used to display the error message if path_physical()
* routine fails.(See below)
*/
unavoidable_goto:
#endif /* apollo */
if(rval<0)
{
switch(errno)
{
#ifdef ENAMETOOLONG
case ENAMETOOLONG:
dp = e_longname;
break;
#endif /* ENAMETOOLONG */
#ifdef EMULTIHOP
case EMULTIHOP:
dp = e_multihop;
break;
#endif /* EMULTIHOP */
case ENOTDIR:
dp = e_notdir;
break;
case ENOENT:
dp = e_found;
break;
case EACCES:
dp = e_access;
break;
#ifdef ENOLINK
case ENOLINK:
dp = e_link;
break;
#endif /* ENOLINK */
default:
dp = e_direct;
break;
}
sh_fail(a1,dp);
}
if(a1 == nam_strval(OLDPWDNOD) || argn==3)
dp = a1; /* print out directory for cd - */
#ifdef LSTAT
if(flag)
{
/* make sure at least PATH_MAX bytes on stack */
if((flag=staktell()) < OPATH+PATH_MAX)
stakseek(OPATH+PATH_MAX);
a1 = stakseek(OPATH)+OPATH;
#ifdef apollo
/*
* check the return status of path_physical().
* if the return status is 0 then the getwd() has
* failed, so print an error message.
*/
if ( !path_physical(a1) )
{
rval = -1;
goto unavoidable_goto;
}
#else
path_physical(a1);
#endif /* apollo */
stakseek(OPATH+strlen(a1));
a1 = (char*)stakfreeze(1)+OPATH;
}
else
#endif /* LSTAT */
a1 = (char*)stakfreeze(1)+OPATH;
/*
* ksh was used to suppress the output if
* it was not run interactively. However,
* XPG4 standard requires to see the output
* all the times.
*/
if (*dp && *dp != ':' && strchr(a1, '/'))
{
p_setout(st.standout);
p_str(a1,NL);
}
if(*a1 != '/')
return(0);
nam_fputval(OLDPWDNOD,oldpwd);
if(oldpwd)
free(oldpwd);
nam_free(PWDNOD);
nam_fputval(PWDNOD,a1);
nam_ontype(PWDNOD,N_FREE|N_EXPORT);
sh.pwd = PWDNOD->value.namval.cp;
return(0);
}
int b_shift(argn,com)
register char **com;
{
register int flag = (com[1]?(int)sh_arith(com[1]):1);
NOT_USED(argn);
if(flag<0 || st.dolc<flag)
sh_cfail(e_number);
else
{
if(st.subflag)
return(0);
st.dolv += flag;
st.dolc -= flag;
}
return(0);
}
int b_wait(argn,com)
register char **com;
{
NOT_USED(argn);
st.states &= ~MONITOR;
if(!st.subflag)
job_bwait(com+1);
return(sh.exitval);
}
int b_read(argn,com)
char **com;
{
register char *a1 = com[1];
register int flag;
register int fd;
int r;
NOT_USED(argn);
st.states &= ~MONITOR;
argnum = 0;
com += scanargs(com,~(R_FLAG|P_FLAG|U_FLAG|S_FLAG));
a1 = com[1];
flag = newflag;
if(flag&P_FLAG)
{
if((fd = sh.cpipe[INPIPE])<=0)
sh_cfail(e_query);
}
else if(flag&U_FLAG)
fd = argnum;
else
fd = 0;
if(fd && !fisread(fd))
sh_cfail(e_file);
/* look for prompt */
if(a1 && (a1=strchr(a1,'?')) && tty_check(fd))
{
p_setout(ERRIO);
p_str(a1+1,0);
}
env_readline(&com[1],fd,flag&(R_FLAG|S_FLAG));
if(r=(fiseof(io_ftable[fd])!=0))
{
if(flag&P_FLAG)
{
io_pclose(sh.cpipe);
return(1);
}
}
clearerr(io_ftable[fd]);
return(r);
}
int b_set(argn,com)
register char **com;
{
if(com[1])
{
arg_opts(argn,com,1);
st.states &= ~(READPR|MONITOR);
st.states |= is_option(READPR|MONITOR);
}
else
/*scan name chain and print*/
env_scan(st.standout,0,sh.var_tree,0);
return(sh.exitval);
}
int b_eval(argn,com)
register char **com;
{
NOT_USED(argn);
st.states &= ~MONITOR;
if(com[1])
{
sh.un.com = com+2;
sh_eval(com[1]);
}
return(sh.exitval);
}
int b_fc(argn,com)
char **com;
{
register char *a1;
register int flag;
register struct history *fp;
#ifdef notdef
struct stat statb;
time_t before = 0;
#endif
int fdo;
char *argv[2];
char fname[TMPSIZ];
int index2;
int indx = -1; /* used as subscript for range */
char *edit = NULL; /* name of editor */
char *replace = NULL; /* replace old=new */
int incr;
int range[2]; /* upper and lower range of commands */
int lflag = 0;
int nflag = 0;
int rflag = 0;
int sflag = 0;
histloc location;
NOT_USED(argn);
if(!hist_open())
sh_cfail(e_history);
fp = hist_ptr;
while((a1=com[1]) && *a1 == '-')
{
argnum = -1;
flag = flagset(a1,~(S_FLAG|E_FLAG|L_FLAG|N_FLAG|R_FLAG));
if(flag==0)
{
if(argnum < 0)
{
com++;
break;
}
flag = fp->fixind - argnum-1;
if(flag <= 0)
flag = 1;
range[++indx] = flag;
argnum = 0;
if(indx==1)
break;
}
else
{
if(flag&E_FLAG)
{
/* name of editor specified */
com++;
if((edit=com[1]) == NULL)
sh_cfail(e_argexp);
}
if(flag&N_FLAG)
nflag++;
if(flag&L_FLAG)
lflag++;
if(flag&R_FLAG)
rflag++;
if (flag & S_FLAG)
sflag++;
}
com++;
}
/* XPG4: Do some error checkings for input options */
if (sflag && edit != NULL)
sh_cfail(e_option);
/* XPG4: Set edit to skip -e handler */
if (sflag)
edit = "-";
flag = indx;
while(flag<1 && (a1=com[1]))
{
/* look for old=new argument */
if(replace==NULL && strchr(a1+1,'='))
{
replace = a1;
com++;
continue;
}
else if(isdigit(*a1) || *a1 == '-')
{
/* see if completely numeric */
do a1++;
while(isdigit(*a1));
if(*a1==0)
{
a1 = com[1];
range[++flag] = atoi(a1);
if(*a1 == '-')
range[flag] += (fp->fixind-1);
com++;
continue;
}
}
/* search for last line starting with string */
location = hist_find(com[1],fp->fixind-1,0,-1);
if((range[++flag] = location.his_command) < 0)
sh_fail(com[1],e_found);
com++;
}
if(flag <0)
{
/* set default starting range */
if(lflag)
{
flag = fp->fixind-16;
if(flag<1)
flag = 1;
}
else
flag = fp->fixind-2;
range[0] = flag;
flag = 0;
}
if(flag==0)
/* set default termination range */
range[1] = (lflag?fp->fixind-1:range[0]);
if((index2 = fp->fixind - fp->fixmax) <=0)
index2 = 1;
/*
* There is no invalid range for
* XPG4.
* So, check for valid ranges
*/
for (flag = 0; flag < 2; flag++) {
if (range[flag] < index2)
range[flag] = index2;
else if (range[flag] >= (fp->fixind-(lflag == 0)))
range[flag] = fp->fixind - 1;
}
if(edit && *edit=='-' && range[0]!=range[1])
sh_cfail(e_number);
/* now list commands from range[rflag] to range[1-rflag] */
incr = 1;
flag = rflag>0;
if(range[1-flag] < range[flag])
incr = -1;
if(lflag)
{
fdo = st.standout;
a1 = "\n\t";
}
else
{
fdo = io_mktmp(fname);
a1 = "\n";
nflag++;
}
p_setout(fdo);
while(1)
{
if(nflag==0)
p_num(range[flag],'\t');
else if(lflag)
p_char('\t');
hist_list(hist_position(range[flag]),0,a1);
if(lflag && (sh.trapnote&SIGSET))
sh_exit(SIGFAIL);
if(range[flag] == range[1-flag])
break;
range[flag] += incr;
}
if(lflag)
return(0);
#ifdef notdef
if(fstat(fdo,&statb)>=0)
before = statb.st_mtime;
#endif
io_fclose(fdo);
hist_eof();
p_setout(ERRIO);
a1 = edit;
if(a1==NULL && (a1=nam_strval(FCEDNOD)) == NULL)
a1 = (char*)e_defedit;
#ifdef apollo
/*
* Code to support the FC using the pad editor.
* Exampled of how to use: FCEDIT=pad
*/
if (strcmp (a1, "pad") == 0)
{
int pad_create();
io_fclose(fdo);
fdo = pad_create(fname);
pad_wait(fdo);
unlink(fname);
strcat(fname, ".bak");
unlink(fname);
io_seek(fdo,(off_t)0,SEEK_SET);
}
else
{
#endif /* apollo */
if(*a1 != '-')
{
sh.un.com = argv;
argv[0] = fname;
argv[1] = NULL;
sh_eval(a1);
}
fdo = io_fopen(fname);
#ifdef notdef
/*
* Korn says this is the right thing to do, but our customers,
* the ksh man page, the ksh book, and the POSIX shell spec
* all disagree with Korn. None of the docs make any mention
* of checking for modification of the file. And besides, the
* mod check fails if you modify the file *very* quickly.
*/
/* if the file hasn't changed, treat this as a error */
if(*a1!='-' && fstat(fdo,&statb)>=0 && before==statb.st_mtime)
sh.exitval = 1;
#endif
unlink(fname);
#ifdef apollo
}
#endif /* apollo */
/* don't history fc itself unless forked */
if(!(st.states&FORKED))
hist_cancel();
st.states |= (READPR|FIXFLG); /* echo lines as read */
st.exec_flag--; /* needed for command numbering */
if(replace!=NULL)
hist_subst(sh.cmdname,fdo,replace);
else if(sh.exitval == 0)
{
/* read in and run the command */
st.states &= ~BUILTIN;
sh.un.fd = fdo;
sh_eval((char*)0);
}
else
{
io_fclose(fdo);
if(!is_option(READPR))
st.states &= ~(READPR|FIXFLG);
}
st.exec_flag++;
return(sh.exitval);
}
int b_getopts(argn,com)
char **com;
{
register char *a1 = com[1];
register int flag;
register struct namnod *n;
int r = 0;
extern char opt_option[];
extern char *opt_arg;
static char value[2];
const char *message = e_argexp;
if(argn < 3)
sh_cfail(e_argexp);
n = env_namset(com[2],sh.var_tree,P_FLAG);
if(argn>3)
{
com +=2;
argn -=2;
}
else
{
com = st.dolv;
argn = st.dolc;
}
opt_plus = 1;
switch(opt_index<=argn?flag=optget(com,a1):0)
{
case '?':
message = e_option;
/* fall through */
case ':':
if(*a1==':')
opt_arg = opt_option+1;
else
{
p_setout(ERRIO);
p_prp(sh.cmdname);
p_str(e_colon,opt_option[1]);
p_char(' ');
p_str(message,NL);
flag = '?';
}
*(a1 = value) = flag;
break;
case 0:
a1 = "?"; /* XPG4: End of option char */
r = ERROR;
opt_char = 0;
break;
default:
a1 = opt_option + (*opt_option=='-');
}
nam_putval(n, a1);
n = nam_search(OPTARG->namid,sh.var_tree,N_ADD|G_FLAG);
nam_fputval(n,opt_arg);
return(r);
}
int b_whence(argn,com)
register char **com;
{
NOT_USED(argn);
com += scanargs(com,~(V_FLAG|P_FLAG));
if(com[1] == 0)
sh_cfail(e_nargs);
p_setout(st.standout);
return(sh_whence(com,newflag));
}
int b_umask(argn,com)
char **com;
{
register int ch;
register int sflag = 0;
int save_index = opt_index;
int save_char = opt_char;
register char *a1;
register int flag = 0;
NOT_USED(argn);
opt_char = 0;
opt_index = 1;
opt_plus = 0;
while((ch = optget(com, ":S"))) {
switch (ch) {
case 'S':
sflag++;
argn--;
break;
default:
sh_cfail(e_option);
break;
}
}
com += opt_index;
opt_index = save_index;
opt_char = save_char;
NOT_USED(argn);
if(a1=com[0])
{
register int c;
if(st.subflag)
return(0);
if(isdigit(*a1))
{
while(c = *a1++)
{
if (c>='0' && c<='7')
flag = (flag<<3) + (c-'0');
else
sh_cfail(e_number);
}
}
else
{
char **cp = com+1;
flag = umask(0);
c = strperm(a1,cp,~flag);
if(**cp)
{
umask(flag);
sh_cfail(e_format);
}
flag = (~c&0777);
}
umask(flag);
}
else
{
flag = umask(0); /* Original Mask */
(void) umask(flag); /* Restore it */
p_setout(st.standout);
if (sflag)
umask_sprint(flag);
else {
a1 = utos((ulong)flag,8);
*++a1 = '0';
p_str(a1,NL);
}
}
return(0);
}
#ifdef LIM_CPU
# define HARD 1
# define SOFT 2
/* BSD style ulimit */
int b_ulimit(argn,com)
char **com;
{
register char *a1;
register int flag = 0;
# ifdef RLIMIT_CPU
struct rlimit rlp;
# endif /* RLIMIT_CPU */
const struct sysnod *sp;
long i;
int label;
register int n;
register int mode = 0;
int unit;
int noargs;
int save_index = opt_index;
int save_char = opt_char;
NOT_USED(argn);
opt_char = 0;
opt_index = 1;
opt_plus = 0;
while((n = optget(com,":HSacdfmnstv")))
{
switch(n)
{
case 'H':
mode |= HARD;
continue;
case 'S':
mode |= SOFT;
continue;
case 'a':
flag = (0x2f
# ifdef LIM_MAXRSS
|(1<<4)
# endif /* LIM_MAXRSS */
# ifdef RLIMIT_NOFILE
|(1<<6)
# endif /* RLIMIT_NOFILE */
# ifdef RLIMIT_VMEM
|(1<<7)
# endif /* RLIMIT_VMEM */
);
break;
case 't':
flag |= 1;
break;
# ifdef LIM_MAXRSS
case 'm':
flag |= (1<<4);
break;
# endif /* LIM_MAXRSS */
case 'd':
flag |= (1<<2);
break;
case 's':
flag |= (1<<3);
break;
case 'f':
flag |= (1<<1);
break;
case 'c':
flag |= (1<<5);
break;
# ifdef RLIMIT_NOFILE
case 'n':
flag |= (1<<6);
break;
# endif /* RLIMIT_NOFILE */
# ifdef RLIMIT_VMEM
case 'v':
flag |= (1<<7);
break;
# endif /* RLIMIT_VMEM */
default:
sh_cfail(e_option);
}
}
com += opt_index;
a1 = *com;
opt_index = save_index;
opt_char = save_char;
/* default to -f */
if(noargs=(flag==0))
flag |= (1<<1);
/* only one option at a time for setting */
label = (flag&(flag-1));
if(a1)
{
if(label)
sh_cfail(e_option);
if(com[1])
sh_cfail(e_nargs);
}
sp = limit_names;
if(mode==0)
mode = (HARD|SOFT);
for(; flag; sp++,flag>>=1)
{
if(!(flag&1))
continue;
n = sp->sysval>>11;
unit = sp->sysval&0x7ff;
if(a1)
{
if(st.subflag)
return(0);
if(strcmp(a1,e_unlimited)==0)
i = INFINITY;
else
{
if((i=sh_arith(a1)) < 0)
sh_cfail(e_number);
i *= unit;
}
# ifdef RLIMIT_CPU
if(getrlimit(n,&rlp) <0)
sh_cfail(e_number);
if(mode&HARD)
rlp.rlim_max = i;
if(mode&SOFT)
rlp.rlim_cur = i;
if(setrlimit(n,&rlp) <0)
sh_cfail(e_ulimit);
# endif /* RLIMIT_CPU */
}
else
{
# ifdef RLIMIT_CPU
if(getrlimit(n,&rlp) <0)
sh_cfail(e_number);
if(mode&HARD)
i = rlp.rlim_max;
if(mode&SOFT)
i = rlp.rlim_cur;
# else
i = -1;
}
if((i=vlimit(n,i)) < 0)
sh_cfail(e_number);
if(a1==0)
{
# endif /* RLIMIT_CPU */
p_setout(st.standout);
if(label)
p_str(sp->sysnam,SP);
/* ulimit without args give numerical limit */
if(i!=INFINITY || noargs)
{
if(!noargs)
i += (unit-1);
i /= unit;
p_str(utos((ulong)i,10),NL);
}
else
p_str(e_unlimited,NL);
}
}
return(0);
}
#else
int b_ulimit(argn,com)
char **com;
{
register char *a1 = com[1];
register int flag = 0;
# ifndef VENIX
long i;
long ulimit();
register int mode = 2;
NOT_USED(argn);
if(a1 && *a1 == '-')
{
# ifdef RT
flag = flagset(a1,~(F_FLAG|P_FLAG));
# else
flag = flagset(a1,~F_FLAG);
# endif /* RT */
a1 = com[2];
}
if(flag&P_FLAG)
mode = 5;
if(a1)
{
if(st.subflag)
return(0);
if((i=sh_arith(a1)) < 0)
sh_cfail(e_number);
}
else
{
mode--;
i = -1;
}
if((i=ulimit(mode,i)) < 0)
sh_cfail(e_number);
if(a1==0)
{
p_setout(st.standout);
p_str(utos((ulong)i,10),NL);
}
# endif /* VENIX */
return(0);
}
#endif /* LIM_CPU */
#ifdef JOBS
# ifdef SIGTSTP
int b_bgfg(argn,com)
register char **com;
{
register int flag = (**com=='b');
register char *a1 = com[1];
NOT_USED(argn);
if (a1 && (*a1++ == '-')) {
if (*a1 == '-')
com++;
else
sh_cfail(e_option);
}
if(!(st.states&MONITOR) && job.jobcontrol)
sh_cfail(e_no_jctl);
if(job_walk(job_switch,flag,com+1))
sh_cfail(e_no_job);
return(sh.exitval);
}
# endif /* SIGTSTP */
int b_jobs(argn,com)
char **com;
{
NOT_USED(argn);
com += scanargs(com,~(N_FLAG|L_FLAG|P_FLAG));
if(*++com==0)
com = 0;
p_setout(st.standout);
if(job_walk(job_list,newflag,com))
sh_cfail(e_no_job);
return(sh.exitval);
}
int b_kill(argn,com)
char **com;
{
register int flag;
register int sflg = 0;
register char *a1 = com[1];
if(argn < 2)
sh_cfail(e_nargs);
/* just in case we send a kill -9 $$ */
p_flush();
flag = SIGTERM;
if((*a1 == '-') && (a1[1] != '-'))
{
a1++;
if(*a1 == 'l')
{
int n;
#ifdef POSIX
if(argn>2)
{
com++;
while(a1= *++com)
{
if(isdigit(*a1)) {
/* Validate the input sig no. */
if ((getnum(a1, &n) != 0) ||
(n < 0 || n >= NSIG))
/* Serious syntax error ? */
sh_cfail(e_badarg);
sig_list(n+1);
} else
{
if((flag=sig_number(a1)) < 0)
sh_cfail(e_option);
p_num(flag,NL);
}
}
}
else
#endif /* POSIX */
sig_list(0);
return(0);
}
else if(*a1=='s')
{
sflg++;
com++;
a1 = com[1];
}
if(!a1 || (flag=sig_number(a1)) <0 || flag >= NSIG)
sh_cfail(e_option);
com++;
}
if(*++com==0)
sh_cfail(e_nargs);
/* Check for -- for bad mix options */
a1 = com[0];
if (*a1 == '-') {
if (*++a1 == '-')
com++; /* -- */
else if (sflg)
sh_cfail(e_option); /* Something like kill -s sig -l */
}
if(job_walk(job_kill,flag,com))
sh.exitval = 2;
return(sh.exitval);
}
#endif
#ifdef LDYNAMIC
# ifdef apollo
/*
* Apollo system support library loads into the virtual address space
*/
int b_inlib(argn,com)
char **com;
{
register char *a1 = com[1];
int status;
short len;
std_$call void loader_$inlib();
if(!st.subflag && a1)
{
len = strlen(a1);
loader_$inlib(*a1, len, status);
if(status!=0)
sh_fail(a1, e_badinlib);
}
return(0);
}
#else
/*
* dynamic library loader from Ted Kowalski
*/
int b_inlib(argn,com)
char **com;
{
register char *a1;
if(!st.subflag)
{
ldinit();
addfunc(ldname("nam_putval", 0), (int (*)())nam_putval);
addfunc(ldname("nam_strval", 0), (int (*)())nam_strval);
addfunc(ldname("p_setout", 0), (int (*)())p_setout);
addfunc(ldname("p_str", 0), (int (*)())p_str);
addfunc(ldname("p_flush", 0), (int (*)())p_flush);
while(a1= *++com)
{
if(!ldfile(a1))
sh_fail(a1, e_badinlib);
}
loadend();
if(undefined()!=0)
sh_cfail("undefined symbols");
}
}
/*
* bind a built-in name to the function that implements it
* uses Ted Kowalski's run-time loader
*/
int b_builtin(argn,com)
char **com;
{
register struct namnod *np;
int (*fn)();
int (*ret_func())();
if(argn!=3)
sh_cfail(e_nargs);
if(!(np = nam_search(com[1],sh.fun_tree,N_ADD)))
sh_fail(com[1],e_create);
if(!isnull(np))
sh_fail(com[1],is_builtin);
if(!(fn = ret_func(ldname(com[2],0))))
sh_fail(com[2],e_found);
funptr(np) = fn;
nam_ontype(np,N_BLTIN);
}
# endif /* !apollo */
#endif /* LDYNAMIC */
int
b_command(argn, com)
int argn;
char **com;
{
register int ch;
char *rpath;
int r = 0;
int flag = 0;
int pflag = 0;
int vflag = 0;
int Vflag = 0;
int save_index = opt_index;
int save_char = opt_char;
if (argn < 2)
sh_cfail(e_option);
opt_char = 0;
opt_index = 1;
opt_plus = 0;
/*
* Check on -p | -v | -V mutual exclusive
*/
while (ch = optget(com, ":vVp")) {
switch (ch) {
case 'p':
if (vflag || Vflag)
sh_cfail(e_option);
pflag++;
break;
case 'v':
if (pflag || Vflag)
sh_cfail(e_option);
vflag++;
break;
case 'V':
if (pflag || vflag)
sh_cfail(e_option);
Vflag++;
break;
default:
sh_cfail(e_option);
break;
} /* switch */
}
com += opt_index;
argn -= opt_index;
opt_index = save_index;
opt_char = save_char;
p_setout(st.standout);
if (vflag) {
if (com[0] == (char *)NULL)
sh_cfail(e_option);
com--;
r = sh_whence(com, 0);
} else if (Vflag) {
if (com[0] == (char *)NULL)
sh_cfail(e_option);
com--;
r = sh_whence(com, V_FLAG);
} else if (pflag || (argn > 0)) {
if (com[0] == (char *)NULL)
sh_cfail(e_option);
r = command_popt(argn, com);
if (r == ENOTFOUND)
cmd_shcfail(e_found, ENOTFOUND);
}
return (r);
}
#ifdef FS_3D
# define VLEN 14
int b_vpath_map(argn,com)
char **com;
{
register int flag = (com[0][1]=='p'?2:4);
register char *a1 = com[1];
char version[VLEN+1];
char *vend;
int n;
switch(argn)
{
case 1:
case 2:
flag |= 8;
p_setout(st.standout);
if((n = mount(a1,version,flag)) >= 0)
{
vend = stakalloc(++n);
n = mount(a1,vend,flag|(n<<4));
}
if(n < 0)
{
if(flag==2)
sh_cfail("cannot get mapping");
else
sh_cfail("cannot get versions");
}
if(argn==2)
{
p_str(vend,NL);
break;
}
n = 0;
while(flag = *vend++)
{
if(flag==' ')
{
flag = e_sptbnl[n+1];
n = !n;
}
p_char(flag);
}
if(n)
newline();
break;
default:
if(!(argn&1))
sh_cfail(e_nargs);
/*FALLTHROUGH*/
case 3:
if(st.subflag)
break;
for(n=1;n<argn;n+=2)
if(mount(com[n+1],com[n],flag)<0)
{
if(flag==2)
sh_cfail("cannot set mapping");
else
sh_cfail("cannot set vpath");
}
}
return(0);
}
#endif /* FS_3D */
#ifdef UNIVERSE
/*
* there are three styles of universe
* Pyramid and Sequent universes have <sys/universe.h> file
* Masscomp universes do not
*/
int b_universe(argn,com)
char **com;
{
register char *a1 = com[1];
if(a1)
{
if(setuniverse(univ_number(a1)) < 0)
sh_cfail("invalid name");
att_univ = (strcmp(a1,"att")==0);
/* set directory in new universe */
if(*(a1 = path_pwd(0))=='/')
chdir(a1);
/* clear out old tracked alias */
stakseek(0);
stakputs((PATHNOD)->namid);
stakputc('=');
stakputs(nam_strval(PATHNOD));
a1 = stakfreeze(1);
env_namset(a1,sh.var_tree,nam_istype(PATHNOD,~0));
}
else
{
int flag;
char Xuniverse[TMPSIZ];
if(getuniverse(Xuniverse) < 0)
sh_cfail("not accessible");
else
p_str(Xuniverse,NL);
}
return(0);
}
#endif /* UNIVERSE */
#ifdef SYSSLEEP
/* fine granularity sleep builtin someday */
int b_sleep(argn,com)
char **com;
{
extern double atof();
register char *a1 = com[1];
if(a1)
{
if(strmatch(a1,"*([0-9])?(.)*([0-9])"))
sh_delay(atof(a1));
else
sh_cfail(e_number);
}
else
sh_cfail(e_argexp);
return(0);
}
#endif /* SYSSLEEP */
static const char flgchar[] = "efgilmnprstuvxEFHLPRZ";
static const int flgval[] = {E_FLAG,F_FLAG,G_FLAG,I_FLAG,L_FLAG,M_FLAG,
N_FLAG,P_FLAG,R_FLAG,S_FLAG,T_FLAG,U_FLAG,V_FLAG,
X_FLAG,N_DOUBLE|N_INTGER|N_EXPNOTE,N_DOUBLE|N_INTGER,
N_HOST,N_LJUST,H_FLAG,N_RJUST,N_RJUST|N_ZFILL};
/*
* process option flags for built-ins
* flagmask are the invalid options
*/
static int flagset(flaglist,flagmask)
char *flaglist;
{
register int flag = 0;
register int c;
register char *cp,*sp;
int numset = 0;
for(cp=flaglist+1;c = *cp;cp++)
{
if(isdigit(c))
{
if(argnum < 0)
{
argnum = 0;
numset = -100;
}
else
numset++;
argnum = 10*argnum + (c - '0');
}
else if(sp=strchr(flgchar,c))
flag |= flgval[sp-flgchar];
else if(c!= *flaglist)
goto badoption;
}
if(numset>0 && flag==0)
goto badoption;
if((flag&flagmask)==0)
return(flag);
badoption:
sh_cfail(e_option);
/* NOTREACHED */
}
/*
* process command line options and store into newflag
*/
static int scanargs(com,flags)
char *com[];
{
register char **argv = ++com;
register int flag;
register char *a1;
newflag = 0;
if(*argv)
aflag = **argv;
else
aflag = 0;
if(aflag!='+' && aflag!='-')
return(0);
while((a1 = *argv) && *a1==aflag)
{
if(a1[1] && a1[1]!=aflag)
flag = flagset(a1,flags);
else
flag = 0;
argv++;
if(flag==0)
break;
newflag |= flag;
}
return(argv-com);
}
/*
* evaluate the string <s> or the contents of file <un.fd> as shell script
* If <s> is not null, un is interpreted as an argv[] list instead of a file
*/
void sh_eval(s)
register char *s;
{
struct fileblk fb;
union anynode *t;
char inbuf[IOBSIZE+1];
struct ionod *saviotemp = st.iotemp;
struct slnod *saveslp = st.staklist;
io_push(&fb);
if(s)
{
io_sopen(s);
if(sh.un.com)
{
fb.feval=sh.un.com;
if(*fb.feval)
fb.ftype = F_ISEVAL;
}
}
else if(sh.un.fd>=0)
{
io_init(input=sh.un.fd,&fb,inbuf);
}
sh.un.com = 0;
st.exec_flag++;
t = sh_parse(NL,NLFLG|MTFLG);
st.exec_flag--;
if(is_option(READPR)==0)
st.states &= ~READPR;
if(s==NULL && hist_ptr)
hist_flush();
p_setout(ERRIO);
io_pop(0);
sh_exec(t,(int)(st.states&(ERRFLG|MONITOR)));
sh_freeup();
st.iotemp = saviotemp;
st.staklist = saveslp;
}
/*
* Given the name or number of a signal return the signal number
*/
static int sig_number(string)
register char *string;
{
#ifndef SIGSTRINGS
register int n;
#else /* SIGSTRINGS */
int n;
#endif /* SIGSTRINGS */
if(isdigit(*string))
n = atoi(string);
else
{
ltou(string,string);
n = sh_lookup(string,sig_names);
n &= (1<<SIGBITS)-1;
n--;
#ifdef SIGSTRINGS
if (n >= 0)
return(n);
if (str2sig(string, &n) < 0)
return (-1);
#endif /* SIGSTRINGS */
}
return(n);
}
#ifdef JOBS
/*
* list all the possible signals
* If flag is 1, then the current trap settings are displayed
*/
static void sig_list(flag)
{
register const struct sysnod *syscan;
register int n = MAXTRAP;
const char *names[MAXTRAP+3];
#ifdef SIGSTRINGS
char signames[MAXTRAP*10], *signamealloc;
#endif /* SIGSTRINGS */
syscan=sig_names;
p_setout(st.standout);
/* not all signals may be defined */
#ifdef POSIX
if(flag<0)
n += 2;
#else
NOT_USED(flag);
#endif /* POSIX */
while(--n >= 0)
names[n] = e_trap;
while(*syscan->sysnam)
{
n = syscan->sysval;
n &= ((1<<SIGBITS)-1);
names[n] = syscan->sysnam;
syscan++;
}
#ifdef SIGSTRINGS
signamealloc = signames;
for (n = 1; n < NSIG; n++) {
if (names[n+1] == e_trap) {
if (sig2str(n, signamealloc) >= 0) {
names[n+1] = signamealloc;
signamealloc += strlen(signamealloc) + 1;
}
}
}
#endif /* SIGSTRINGS */
n = MAXTRAP-1;
#ifdef POSIX
if(flag<0)
n += 2;
#endif /* POSIX */
while(names[--n]==e_trap);
names[n+1] = NULL;
#ifdef POSIX
if(flag<0)
{
int sig;
for(sig = 0; sig < MAXTRAP; sig++)
if(st.trapcom[sig])
{
char sigtstr[SIG2STR_MAX];
if (sig == NSIG)
continue;
p_str("trap -- ", 0);
p_qstr(st.trapcom[sig], ' ');
if (sig < NSIG)
strcpy(sigtstr, names[sig+1]);
else {
switch (sig) {
case NSIG+1:
strcpy(sigtstr, "ERR");
break;
case NSIG+2:
strcpy(sigtstr, "DEBUG");
break;
}
}
p_str(sigtstr, NL);
}
}
else if(flag)
{
if(flag <= n && names[flag])
p_str(names[flag],NL);
else
p_num(flag-1,NL);
}
else {
#endif /* POSIX */
register int n;
char tmpstr[SIG2STR_MAX];
/*
* XPG4: sig_list(0) does not print the
* correct output format for kill -l.
* The original ksh sig_list(0) does
* not print all the signals upto NSIG.
* Only kill -l will get here.
*/
for (n = 0; n < NSIG; n++) {
if (sig2str(n, tmpstr) == -1) {
if (n > SIGTHAW)
continue;
sh_cfail(e_sigtrans);
}
p_str(tmpstr, SP);
}
p_str("", NL);
}
}
#endif /* JOBS */
#ifdef SYSSLEEP
/*
* delay execution for time <t>
*/
#ifdef _poll_
# include <poll.h>
#endif /* _poll_ */
#ifndef TIC_SEC
# ifdef HZ
# define TIC_SEC HZ /* number of ticks per second */
# else
# define TIC_SEC 60 /* number of ticks per second */
# endif /* HZ */
#endif /* TIC_SEC */
int sh_delay(t)
double t;
{
register int n = t;
#ifdef _poll_
struct pollfd fd;
if(t<=0)
return;
else if(n > 30)
{
sleep(n);
t -= n;
}
if(n=1000*t)
poll(&fd,0,n);
#else
# ifdef _SELECT5_
struct timeval timeloc;
if(t<=0)
return;
timeloc.tv_sec = n;
timeloc.tv_usec = 1000000*(t-(double)n);
select(0,(fd_set*)0,(fd_set*)0,(fd_set*)0,&timeloc);
# else
# ifdef _SELECT4_
/* for 9th edition machines */
if(t<=0)
return;
if(n > 30)
{
sleep(n);
t -= n;
}
if(n=1000*t)
select(0,(fd_set*)0,(fd_set*)0,n);
# else
struct tms tt;
if(t<=0)
return;
sleep(n);
t -= n;
if(t)
{
clock_t begin = times(&tt);
if(begin==0)
return;
t *= TIC_SEC;
n += (t+.5);
while((times(&tt)-begin) < n);
}
# endif /* _SELECT4_ */
# endif /* _SELECT5_ */
#endif /* _poll_ */
}
#endif /* SYSSLEEP */
#ifdef UNIVERSE
# ifdef _sys_universe_
int univ_number(str)
char *str;
{
register int n = 0;
while( n < NUMUNIV)
{
if(strcmp(str,univ_name[n])==0)
return(univ_index(n));
n++;
}
return(-1);
}
# endif /* _sys_universe_ */
#endif /* UNIVERSE */
static char **ddash_handler(cmdline)
char **cmdline;
{
char *p = cmdline[0];
if (p && *p == '-' && p[1] == '-')
cmdline++;
return (cmdline);
}
static int
command_opt(argn, com, cmdp)
int argn;
char **com;
char **cmdp;
{
register struct namnod *np;
register struct namnod *np1;
register char *a1, *a2, *a3;
int sh_resword; /* Shell reserved word */
int sh_bltin; /* Shell builtin */
int sh_func; /* Shell function */
int sh_alias; /* Shell alias - non-tracked */
int u_func; /* User function */
int t_alias; /* Tracked alias */
int notrack;
int q;
int nopath;
com -= 1;
a1 = a2 = *++com;
sh_resword = sh_bltin = sh_func = sh_alias = u_func = 0;
q = 0; /* Error flag for each command */
nopath = 1;
t_alias = 1;
sh_resword = sh_lookup(a1, tab_reserved);
np = nam_search(a1, sh.fun_tree, N_NULL);
np1 = nam_search(a1, sh.alias_tree, N_NULL);
/*
* Absolute path name for:
* - Utilities
* - Regular built-in utilities
* - Command name with slash character
* - Functions
* found using PATH variable
*
* Name itself for:
* - Shell functions
* - Special built-in utilities
* - Regular built-in utilities
* not associated with a PATH search
* - Shell reserved words
* Alias definition
* - aliases
*
* command [-p] overrides only user and shell functions
*
*/
/*
* XPG4: Buffer the output as we don't know
* whether there will be an error until
* after search and XPG4 requires the error
* output goes to STDERR.
*/
a3 = (char *)NULL;
if (!sh_resword) {
if (np1 && (t_alias = (nam_istype(np1, T_FLAG) == 0)) &&
(a3 = nam_strval(np1)))
sh_alias++; /* non-tracked alias */
/* built-ins and functions next */
else if (np) {
if (is_abuiltin(np))
sh_bltin++;
else {
if (!isnull(np) && is_afunction(np))
u_func++;
else if (isnull(np) && !is_afunction(np))
goto search;
else
sh_func++;
if (u_func|sh_func)
goto search; /* Override user functions ? */
}
} else {
/*
* The output needs a path search
*/
search:
if (path_search(a1, 2) == 0) {
a2 = sh.lastpath;
nopath = (a2 == (char *)NULL);
}
sh.lastpath = 0;
if (!a2)
q = ((xecmsg == e_exec) ? ECANTEXEC: ENOTFOUND);
}
}
if (q) {
sh.cmdname = a1;
sh.exitval = q;
} else {
*cmdp = 0; /* No need to exec later */
if (sh_resword|sh_alias|sh_bltin)
sh.exitval = (*funptr(np))(argn,com);
else if (nopath && (u_func|sh_func)) {
struct slnod *slp;
/* increase refcnt for unset */
slp = (struct slnod*)np->value.namenv;
sh_funstaks(slp->slchild,1);
staklink(slp->slptr);
sh_funct((union anynode*)(funtree(np)), com,
(int)(nam_istype(np,T_FLAG)?EXECPR:0),0);
sh_funstaks(slp->slchild,-1);
stakdelete(slp->slptr);
} else
*cmdp = a2;
}
return (q);
}
static int
command_popt(argn, com)
int argn;
char **com;
{
char *cmdp = (char *)NULL;
register int r = 0;
int ret_stat = 0;
int child_id;
if (strchr(com[0], '/'))
cmdp = com[0]; /* Path command - no need to search */
else {
if (r = command_opt(argn, com, &cmdp))
return (r);
}
if (cmdp == (char *) NULL)
return (sh.exitval); /* already done if builtin */
else {
char inp[LINE_MAX];
register int argno;
char *p;
char *s;
char *q = inp;
/*
* Put double quote around arguments to build
* the new command line for re-parsing.
*/
for (argno = 1; argno < argn; argno++) {
p = q;
*q++ = DQUOTE;
s = com[argno];
while (s && *s)
*q++ = *s++;
*q++ = DQUOTE;
*q++ = 0;
com[argno] = p;
}
sh.un.com = com+1;
com[0] = cmdp;
sh_eval(com[0]);
return(sh.exitval);
}
}
/*
* From MKS c_umask()
*/
static mode_t mapping[3][3] = {
/* x: 1, w: 2, r: 4 */
S_IXOTH, S_IWOTH, S_IROTH, /* o: 000_ */
S_IXGRP, S_IWGRP, S_IRGRP, /* g: 00_0 */
S_IXUSR, S_IWUSR, S_IRUSR, /* u: 0_00 */
};
static void
umask_sprint(m)
mode_t m;
{
char buf[3*6], *op = buf;
register int i, j;
mode_t smode = ~m & (READ|WRITE|EXEC);
/*
* Turn mode_t into u=[rwx],g=[rwx],o=[rwx]
*/
for (i = 3; --i >= 0; ) {
*op++ = "ogu"[i];
*op++ = '=';
for (j = 3; --j >= 0; )
if (smode & mapping[i][j])
*op++ = "xwr"[j];
*op++ = "\0,,"[i];
}
p_str(buf, NL);
}
static void
unalias_all(troot)
struct Amemory *troot;
{
register char *a1;
register struct namnod *np;
register struct slnod *slp;
int r = 0;
if (troot)
(void) gscan_some(unalias_nam, troot, 0, 0);
}
static void
unalias_nam(np)
struct namnod *np;
{
if ((np->value.namflg !=
(unsigned) (N_FREE|N_EXPORT|T_FLAG|NO_ALIAS)))
nam_free(np);
}
static int
getnum(numstr, argnum)
char *numstr;
int *argnum;
{
char *pestr;
errno = 0;
if (isdigit(*numstr)) {
*argnum = strtol(numstr, &pestr, 10);
if (errno || (pestr && *pestr != '\0'))
return (-1);
} else
return (-1);
return (0);
}
int
b_hash(argn, com)
register int argn;
register char **com;
{
register int ch;
int save_index = opt_index;
int save_char = opt_char;
if (com[1])
aflag = (*com[1] == '-' ? '-' : 1);
else
aflag = 0;
opt_char = 0;
opt_index = 1;
opt_plus = 0;
while (ch = optget(com, ":r")) {
switch (ch) {
case 'r':
/* hash -r processing */
(void) gscan_some(rehash, sh.track_tree,
T_FLAG, T_FLAG);
break;
default:
sh_cfail(e_option);
break;
}
}
com += opt_index -1;
opt_index = save_index;
opt_char = save_char;
aflag = '-';
return (b_common(com, T_FLAG, sh.track_tree));
}
int
b_type(argn, com)
int argn;
register char **com;
{
register int ch;
register char *a1 = com[1];
NOT_USED(argn);
if (a1 && (*a1++ == '-')) {
if (*a1 == '-')
com++;
else
sh_cfail(e_option);
}
p_setout(st.standout);
return (sh_whence(com, V_FLAG));
}