#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 #include #include #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 # endif # include /* 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 # endif /* VLIMIT */ #endif /* _sys_resource_ */ #ifdef UNIVERSE static int att_univ = -1; # ifdef _sys_universe_ # include # 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 || sig3) 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.dolcfixind - 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 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 or the contents of file as shell script * If 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<= 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<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 */ #ifdef _poll_ # include #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)); }