/* * system.c * * command line analysis */ #ifdef FD #include "fd.h" #include "term.h" #include "types.h" #include "kconv.h" #else #define K_EXTERN #include "headers.h" #include "depend.h" #include "printf.h" #include "kctype.h" #include "string.h" #include "malloc.h" #endif #include "dirent.h" #include "sysemu.h" #if !defined (FD) && !defined (MINIMUMSHELL) #include "time.h" #endif #ifdef DEP_ORIGSHELL #include "system.h" #endif #if defined (DEP_ORIGSHELL) && !defined (MINIMUMSHELL) #include "posixsh.h" #endif #ifdef DEP_PTY #include "termemu.h" #endif #ifdef DEP_SOCKET #include "socket.h" #include "url.h" #endif #ifdef DEP_URLPATH #include "urldisk.h" #endif #if MSDOS #include # ifdef USERESOURCEH # include # include # endif #else /* !MSDOS */ # ifdef USERESOURCEH # include # endif # ifdef USETIMES # include # endif # ifdef USEULIMITH # include # endif #endif /* !MSDOS */ #ifndef FD typedef struct _lockbuf_t { int fd; } lockbuf_t; # ifdef PATHNOCASE # define TMPPREFIX "TM" # else # define TMPPREFIX "tm" # endif #endif /* !FD */ #ifdef GETPGRPVOID #define getpgroup getpgrp #else #define getpgroup() getpgrp(0) #endif #ifdef USESETPGID #define setpgroup setpgid #else #define setpgroup setpgrp #endif #if MSDOS #define havetty() (1) #else # ifdef NOJOB # define havetty() (mypid == shellpid) # else # define havetty() (ttypgrp >= (p_id_t)0 && mypid == ttypgrp) # endif #endif #define getwaitsig(x) ((WIFSTOPPED(x)) ? WSTOPSIG(x) : \ ((WIFSIGNALED(x)) ? (128 + WTERMSIG(x)) : -1)) #ifndef RLIM_INFINITY #define RLIM_INFINITY 0x7fffffff #endif #ifndef RLIMIT_FSIZE #define RLIMIT_FSIZE 255 #endif #ifndef UL_GETFSIZE #define UL_GETFSIZE 1 #endif #ifndef UL_SETFSIZE #define UL_SETFSIZE 2 #endif #if !defined (RLIMIT_NOFILE) && defined (RLIMIT_OFILE) #define RLIMIT_NOFILE RLIMIT_OFILE #endif #if !defined (RLIMIT_VMEM) && defined (RLIMIT_AS) #define RLIMIT_VMEM RLIMIT_AS #endif #if defined (USESYSCONF) && defined (_SC_CLK_TCK) #define CLKPERSEC sysconf(_SC_CLK_TCK) #else # ifdef CLK_TCK # define CLKPERSEC CLK_TCK # else # ifdef HZ # define CLKPERSEC HZ # else # define CLKPERSEC 60 # endif # endif #endif #if MSDOS #define LSH_DEFRC "\\etc\\profile" #define LSH_RCFILE "~\\profile.rc" #define SH_RCFILE "~\\fdsh.rc" #else /* !MSDOS */ #define LSH_DEFRC "/etc/profile" #define LSH_RCFILE "~/.profile" #define SH_RCFILE "~/.fdshrc" #endif /* !MSDOS */ #define PS1STR "$ " #define PS1ROOT "# " #define PS2STR "> " #define PS4STR "+ " #define UNLIMITED "unlimited" #define MAXTMPNAMLEN 8 #define getconstvar(s) (getshellvar(s, strsize(s))) #define constequal(s, c, l) ((l) == strsize(c) && !strnenvcmp(s, c, l)) #ifdef WITHSOCKREDIR #define TYPE_CONNECT 3 #define TYPE_ACCEPT 4 #define TYPE_BIND 5 #endif #ifdef PSIGNALSTYLE #define MESHUP "Hangup" #define MESINT "Interrupt" #define MESQUIT "Quit" #define MESILL "Illegal instruction" #define MESTRAP "Trace/BPT trap" #define MESIOT "IOT trap" #define MESABRT "Aborted" #define MESEMT "EMT trap" #define MESFPE "Floating point exception" #define MESKILL "Killed" #define MESBUS "Bus error" #define MESSEGV "Segmentation fault" #define MESSYS "Bad system call" #define MESPIPE "Broken pipe" #define MESALRM "Alarm clock" #define MESTERM "Terminated" #define MESSTKFLT "Stack fault" #define MESURG "Urgent I/O condition" #define MESSTOP "Stopped (signal)" #define MESTSTP "Stopped" #define MESCONT "Continued" #define MESCHLD "Child exited" #define MESTTIN "Stopped (tty input)" #define MESTTOU "Stopped (tty output)" #define MESIO "I/O possible" #define MESPOLL "Profiling alarm clock" #define MESXCPU "Cputime limit exceeded" #define MESXFSZ "Filesize limit exceeded" #define MESVTALRM "Virtual timer expired" #define MESPROF "Profiling timer expired" #define MESWINCH "Window changed" #define MESLOST "Resource lost" #define MESINFO "Information request" #define MESPWR "Power failure" #define MESUSR1 "User defined signal 1" #define MESUSR2 "User defined signal 2" #else /* !PSIGNALSTYLE */ #define MESHUP "Hangup" #define MESINT "" #define MESQUIT "Quit" #define MESILL "Illegal instruction" #define MESTRAP "Trace/BPT trap" #define MESIOT "IOT trap" #define MESABRT "Aborted" #define MESEMT "EMT trap" #define MESFPE "Floating exception" #define MESKILL "Killed" #define MESBUS "Bus error" #define MESSEGV "Memory fault" #define MESSYS "Bad system call" #define MESPIPE "" #define MESALRM "Alarm call" #define MESTERM "Terminated" #define MESSTKFLT "Stack fault" #define MESURG "Urgent condition" #define MESSTOP "Stopped" #define MESTSTP "Stopped from terminal" #define MESCONT "Continued" #define MESCHLD "Child terminated" #define MESTTIN "Stopped on terminal input" #define MESTTOU "Stopped on terminal output" #define MESIO "Asynchronous I/O" #define MESPOLL "Profiling alarm clock" #define MESXCPU "Exceeded cpu time limit" #define MESXFSZ "Exceeded file size limit" #define MESVTALRM "Virtual time alarm" #define MESPROF "Profiling time alarm" #define MESWINCH "Window changed" #define MESLOST "Resource lost" #define MESINFO "Information request" #define MESPWR "Power failure" #define MESUSR1 "User defined signal 1" #define MESUSR2 "User defined signal 2" #endif /* !PSIGNALSTYLE */ #ifdef DEBUG #define PSIGNALSTYLE #define SHOWSTREE #endif #ifdef DEP_ORIGSHELL /* * Notes: extension from original Bourne shell * * 1. pathname globing: wildcard `**' matches any directories recursively. * 2. `export' & `readonly' allows arguments with `=value'. * 3. redirector `<>' and `><' mean redirection for read and write. * 4. command hash is always valid. Instead, * -h option means to check command-path ahead for pipe line, * and to check command-path when a function is defined (not executed). * 5. job control: `jobs', `fg', `bg', ^Z/^Y(suspend) are valid. * -m option means to validate the job control. * this option is valid by default for the interactive shell. * 6. builtin command: `echo', `test', `kill' is builtin. * 7. job name: `%' introduces job name in `fg', `bg', `wait', `kill'. * `%%', `%', '%+' mean the current job. * `%-' means the previous job. * `%n' means the job which has job number n. * `%string' means the job whose command begins with `string'. * 8. builtin commands of COMMAND.COM for MS-DOS: * `rem', `dir', `mkdir(md)', `rmdir(rd)', `erase(del)', * `rename(ren)', `copy' is builtin on MS-DOS. * 9. aliases: `alias', `unalias' is builtin. * 10. optional POSIX utilities are added. */ #ifdef FD extern VOID calcwin __P_((VOID_A)); extern VOID main_fd __P_((char *CONST *, int)); extern VOID checkscreen __P_((int, int)); # ifdef SIGWINCH extern VOID pollscreen __P_((int)); # endif extern int sigvecset __P_((int)); # ifndef _NOCUSTOMIZE extern VOID saveorigenviron __P_((VOID_A)); # endif extern VOID initfd __P_((char *CONST *)); extern VOID prepareexitfd __P_((int)); extern int savestdio __P_((int)); extern int checkbuiltin __P_((CONST char *)); extern int checkinternal __P_((CONST char *)); extern int execbuiltin __P_((int, int, char *CONST [])); extern int execinternal __P_((int, int, char *CONST [])); # ifndef _NOCOMPLETE extern int completebuiltin __P_((CONST char *, int, int, char ***)); extern int completeinternal __P_((CONST char *, int, int, char ***)); # endif extern VOID initenv __P_((VOID_A)); extern VOID evalenv __P_((CONST char *, int)); extern int underhome __P_((char *)); extern int replaceargs __P_((int *, char ***, char *CONST *, int)); extern int replacearg __P_((char **)); extern VOID demacroarg __P_((char **)); extern char *inputshellstr __P_((CONST char *, int, CONST char *)); extern int evalprompt __P_((char **, CONST char *)); #endif /* !FD */ #ifdef DOSCOMMAND extern int doscomdir __P_((int, char *CONST [])); extern int doscommkdir __P_((int, char *CONST [])); extern int doscomrmdir __P_((int, char *CONST [])); extern int doscomerase __P_((int, char *CONST [])); extern int doscomrename __P_((int, char *CONST [])); extern int doscomcopy __P_((int, char *CONST [])); extern int doscomcls __P_((int, char *CONST [])); extern int doscomtype __P_((int, char *CONST [])); #endif /* DOSCOMMAND */ #ifdef DEBUG extern VOID mtrace __P_ ((VOID_A)); extern VOID muntrace __P_ ((VOID_A)); extern char *_mtrace_file; #endif #if MSDOS extern int setcurdrv __P_((int, int)); #endif #ifdef FD # ifndef _NOEDITMODE extern char *editmode; # endif extern int internal_status; extern char fullpath[]; extern char *origpath; extern int inruncom; extern int fd_restricted; extern int fdmode; extern int physical_path; extern char *deftmpdir; #else /* !FD */ # ifdef __TURBOC__ extern u_int _stklen = 0x8000; # endif # if MSDOS # define deftmpdir _SS_ # else # define deftmpdir "/tmp" # endif int ttyio = -1; XFILE *ttyout = NULL; #endif /* !FD */ #ifndef MINIMUMSHELL # ifndef NOJOB extern jobtable *joblist; extern int maxjobs; # endif # if !MSDOS extern int mailcheck; # endif # ifndef NOALIAS extern shaliastable *shellalias; # endif # ifndef NOPOSIXUTIL extern int posixoptind; # endif #endif /* !MINIMUMSHELL */ #ifdef FD extern lockbuf_t *lockopen __P_((CONST char *, int, int)); extern VOID lockclose __P_((lockbuf_t *)); extern int mktmpfile __P_((char *)); extern int rmtmpfile __P_((CONST char *)); extern int chdir2 __P_((CONST char *)); extern int chdir3 __P_((CONST char *, int)); extern int chdir4 __P_((CONST char *, int, CONST char *)); extern int setenv2 __P_((CONST char *, CONST char *, int)); extern char *getenv2 __P_((CONST char *)); # ifdef USESIGACTION extern sigcst_t signal2 __P_((int, sigcst_t)); # else # define signal2 signal # endif # if MSDOS && !defined (BSPATHDELIM) extern char *adjustpname __P_((char *)); # endif #else /* !FD */ static lockbuf_t *NEAR lockopen __P_((CONST char *, int, int)); static VOID NEAR lockclose __P_((lockbuf_t *)); static int NEAR genrand __P_((int)); static char *NEAR genrandname __P_((char *, int)); static int NEAR mktmpfile __P_((char *)); static int NEAR rmtmpfile __P_((CONST char *)); # define chdir2 Xchdir int chdir3 __P_((CONST char *, int)); # define chdir4(p, r, a) chdir3(p, r) int setenv2 __P_((CONST char *, CONST char *, int)); # ifdef USESIGACTION static sigcst_t NEAR signal2 __P_((int, sigcst_t)); # else # define signal2 signal # endif # if MSDOS && !defined (BSPATHDELIM) static char *NEAR adjustpname __P_((char *)); # endif # if !MSDOS && !defined (NOJOB) static VOID NEAR stdiomode __P_((VOID_A)); # endif #endif /* !FD */ #ifndef NOJOB static VOID NEAR notifyjob __P_((VOID_A)); #endif static VOID NEAR setsignal __P_((VOID_A)); static VOID NEAR resetsignal __P_((int)); static VOID NEAR exectrapcomm __P_((VOID_A)); static VOID NEAR killmyself __P_((int)); static int NEAR trap_common __P_((int)); #ifdef SIGHUP static int trap_hup __P_((VOID_A)); #endif #ifdef SIGINT static int trap_int __P_((VOID_A)); #endif #ifdef SIGQUIT static int trap_quit __P_((VOID_A)); #endif #ifdef SIGILL static int trap_ill __P_((VOID_A)); #endif #ifdef SIGTRAP static int trap_trap __P_((VOID_A)); #endif #ifdef SIGIOT static int trap_iot __P_((VOID_A)); #else # ifdef SIGABRT static int trap_abrt __P_((VOID_A)); # endif #endif #ifdef SIGEMT static int trap_emt __P_((VOID_A)); #endif #ifdef SIGFPE static int trap_fpe __P_((VOID_A)); #endif #ifdef SIGBUS static int trap_bus __P_((VOID_A)); #endif #ifdef SIGSEGV static int trap_segv __P_((VOID_A)); #endif #ifdef SIGSYS static int trap_sys __P_((VOID_A)); #endif #ifdef SIGPIPE static int trap_pipe __P_((VOID_A)); #endif #ifdef SIGALRM static int trap_alrm __P_((VOID_A)); #endif #ifdef SIGTERM static int trap_term __P_((VOID_A)); #endif #ifdef SIGSTKFLT static int trap_stkflt __P_((VOID_A)); #endif #ifdef SIGURG static int trap_urg __P_((VOID_A)); #endif #ifdef SIGSTOP static int trap_stop __P_((VOID_A)); #endif #ifdef SIGTSTP static int trap_tstp __P_((VOID_A)); #endif #ifdef SIGCONT static int trap_cont __P_((VOID_A)); #endif #ifdef SIGCHLD static int trap_chld __P_((VOID_A)); #endif #ifdef SIGTTIN static int trap_ttin __P_((VOID_A)); #endif #ifdef SIGTTOU static int trap_ttou __P_((VOID_A)); #endif #ifdef SIGIO static int trap_io __P_((VOID_A)); #else # ifdef SIGPOLL static int trap_poll __P_((VOID_A)); # endif #endif #ifdef SIGXCPU static int trap_xcpu __P_((VOID_A)); #endif #ifdef SIGXFSZ static int trap_xfsz __P_((VOID_A)); #endif #ifdef SIGVTALRM static int trap_vtalrm __P_((VOID_A)); #endif #ifdef SIGPROF static int trap_prof __P_((VOID_A)); #endif #ifdef SIGWINCH static int trap_winch __P_((VOID_A)); #endif #ifdef SIGLOST static int trap_lost __P_((VOID_A)); #endif #ifdef SIGINFO static int trap_info __P_((VOID_A)); #endif #ifdef SIGPWR static int trap_pwr __P_((VOID_A)); #endif #ifdef SIGUSR1 static int trap_usr1 __P_((VOID_A)); #endif #ifdef SIGUSR2 static int trap_usr2 __P_((VOID_A)); #endif #ifdef FD static VOID NEAR argfputs __P_((CONST char *, XFILE *)); #else #define argfputs Xfputs #endif #ifdef DEP_FILECONV static int NEAR Kopen __P_((CONST char *, int, int)); #else #define Kopen Xopen #endif static VOID NEAR syntaxerror __P_((CONST char *)); #if !MSDOS && !defined (NOJOB) && defined (DEP_PTY) && defined (CYGWIN) static VOID NEAR addmychild __P_((p_id_t)); #endif #if !MSDOS static VOID NEAR setstopsig __P_((int)); static p_id_t NEAR makechild __P_((int, p_id_t)); #endif static VOID NEAR safermtmpfile __P_((CONST char *)); static int NEAR getoption __P_((int, char *CONST *, int)); static ALLOC_T NEAR c_allocsize __P_((int)); static int NEAR readchar __P_((int)); static char *NEAR readline __P_((int, int)); static char *NEAR readfile __P_((int, ALLOC_T *)); static heredoc_t *NEAR newheredoc __P_((char *, char *, int, int)); static redirectlist *NEAR newrlist __P_((int, char *, int, redirectlist *)); static command_t *NEAR newcomm __P_((VOID_A)); static syntaxtree *NEAR eldeststree __P_((syntaxtree *)); static syntaxtree *NEAR childstree __P_((syntaxtree *, int)); static syntaxtree *NEAR skipfuncbody __P_((syntaxtree *)); static syntaxtree *NEAR insertstree __P_((syntaxtree *, syntaxtree *, int)); static syntaxtree *NEAR linkstree __P_((syntaxtree *, int)); #if !MSDOS || defined (DEP_PTY) || !defined (USEFAKEPIPE) static VOID NEAR nownstree __P_((syntaxtree *)); #endif static int NEAR evalfiledesc __P_((CONST char *)); static int NEAR redmode __P_((int)); static int NEAR cancelredirect __P_((redirectlist *)); static VOID NEAR closeredirect __P_((redirectlist *)); static heredoc_t *NEAR searchheredoc __P_((syntaxtree *, int)); static int NEAR saveheredoc __P_((CONST char *, syntaxtree *)); static int NEAR openheredoc __P_((heredoc_t *, int)); #ifdef DEP_DOSDRIVE static int NEAR fdcopy __P_((int, int)); static int NEAR openpseudofd __P_((redirectlist *)); static int NEAR closepseudofd __P_((redirectlist *)); #endif #ifdef WITHSOCKREDIR static int NEAR parsesocket __P_((CONST char *, char **, int *)); #endif static redirectlist *NEAR doredirect __P_((redirectlist *)); static heredoc_t *NEAR heredoc __P_((char *, int)); static int NEAR redirect __P_((syntaxtree *, int, char *, int)); #if !MSDOS && defined (MINIMUMSHELL) static VOID NEAR checkmail __P_((int)); #endif static int NEAR searchvar __P_((char *CONST *, CONST char *, int, int)); static char *NEAR searchvar2 __P_((int, CONST char **, CONST char *, int)); static char **NEAR expandvar __P_((char **, CONST char *, int)); static char *NEAR getvar __P_((char *CONST *, CONST char *, int)); static char **NEAR putvar __P_((char **, char *, int)); static int NEAR checkprimal __P_((CONST char *, int)); static int NEAR checkrestrict __P_((CONST char *, int)); static int NEAR checkronly __P_((CONST char *, int)); static int NEAR _putshellvar __P_((char *, int)); #ifndef MINIMUMSHELL static VOID NEAR setshlineno __P_((long)); #endif static heredoc_t *NEAR duplheredoc __P_((heredoc_t *)); static redirectlist *NEAR duplrlist __P_((redirectlist *)); static shfunctable *NEAR duplfunc __P_((shfunctable *)); static VOID NEAR freefunc __P_((shfunctable *)); static int cmpfunc __P_((CONST VOID_P, CONST VOID_P)); static char *NEAR getifs __P_((VOID_A)); static int getretval __P_((VOID_A)); static p_id_t getorgpid __P_((VOID_A)); static p_id_t getlastpid __P_((VOID_A)); static char *getflagstr __P_((VOID_A)); static int checkundefvar __P_((CONST char *, CONST char *, int)); static VOID safeexit __P_((VOID_A)); static int NEAR getparenttype __P_((syntaxtree *)); static int NEAR parsestatement __P_((syntaxtree **, int, int, int)); static syntaxtree *NEAR _addarg __P_((syntaxtree *, CONST char *)); static int NEAR addarg __P_((syntaxtree **, redirectlist *, char *, int *, int)); static int NEAR evalredprefix __P_((syntaxtree **, redirectlist *, int *)); static syntaxtree *NEAR rparen __P_((syntaxtree *)); static syntaxtree *NEAR semicolon __P_((syntaxtree *, redirectlist *, CONST char *, int *)); static syntaxtree *NEAR ampersand __P_((syntaxtree *, redirectlist *, CONST char *, int *)); static syntaxtree *NEAR vertline __P_((syntaxtree *, CONST char *, int *)); static syntaxtree *NEAR lessthan __P_((syntaxtree *, redirectlist *, CONST char *, int *)); static syntaxtree *NEAR morethan __P_((syntaxtree *, redirectlist *, CONST char *, int *)); #if defined (BASHSTYLE) || !defined (MINIMUMSHELL) static syntaxtree *NEAR endvar __P_((syntaxtree *, redirectlist *, CONST char *, int *, int *, ALLOC_T *, int)); static syntaxtree *NEAR addvar __P_((syntaxtree *, CONST char *, int *, CONST char *, int *, int)); #endif static syntaxtree *NEAR normaltoken __P_((syntaxtree *, redirectlist *, CONST char *, int *, int *, ALLOC_T *)); static syntaxtree *NEAR casetoken __P_((syntaxtree *, redirectlist *, CONST char *, int *, int *)); #if !defined (BASHBUG) && !defined (MINIMUMSHELL) static int NEAR cmpstatement __P_((CONST char *, int)); static syntaxtree *NEAR comsubtoken __P_((syntaxtree *, redirectlist *, CONST char *, int *, int *, ALLOC_T *)); #endif static syntaxtree *NEAR analyzeloop __P_((syntaxtree *, redirectlist *, CONST char *, int)); static syntaxtree *NEAR analyzeeof __P_((syntaxtree *)); static syntaxtree *NEAR statementcheck __P_((syntaxtree *, int)); static int NEAR check_statement __P_((syntaxtree *)); static int NEAR check_command __P_((syntaxtree *)); static int NEAR check_stree __P_((syntaxtree *)); static syntaxtree *NEAR analyzeline __P_((CONST char *)); #ifdef DEBUG static VOID NEAR Xexecve __P_((CONST char *, char *[], char *[], int)); #define Xexecve2 Xexecve #else static VOID NEAR Xexecve __P_((CONST char *, char *[], char *[])); #define Xexecve2(p, a, e, b) Xexecve(p, a, e) #endif #if MSDOS static char *NEAR addext __P_((char *, int)); static char **NEAR replacebat __P_((char **, char **)); #endif #ifdef USEFAKEPIPE static int NEAR openpipe __P_((p_id_t *, int, int)); #define openpipe2(p, f, n, t, pp) \ openpipe(p, f, n) #else static int NEAR openpipe __P_((p_id_t *, int, int, int, p_id_t)); #define openpipe2 openpipe #endif static pipelist **NEAR searchpipe __P_((int)); static int NEAR reopenpipe __P_((int, int)); static XFILE *NEAR fdopenpipe __P_((int)); #ifndef _NOUSEHASH static VOID NEAR disphash __P_((VOID_A)); #endif #ifdef BASHSTYLE static char *NEAR quotemeta __P_((char *)); #endif static int NEAR substvar __P_((char **, int)); static int NEAR evalargv __P_((command_t *, int *, int *)); static char *NEAR evalexternal __P_((command_t *)); static VOID NEAR printindent __P_((int, XFILE *)); static VOID NEAR printnewline __P_((int, XFILE *)); static int NEAR printredirect __P_((redirectlist *, XFILE *)); #ifndef MINIMUMSHELL static VOID NEAR printheredoc __P_((redirectlist *, XFILE *)); static redirectlist **NEAR _printstree __P_((syntaxtree *, redirectlist **, int, XFILE *)); #endif static VOID NEAR printshfunc __P_((shfunctable *, XFILE *)); static int NEAR dochild __P_((syntaxtree *)); static int NEAR doif __P_((syntaxtree *)); static int NEAR dowhile __P_((syntaxtree *)); static int NEAR dountil __P_((syntaxtree *)); static int NEAR dofor __P_((syntaxtree *)); static int NEAR docase __P_((syntaxtree *)); static int NEAR dolist __P_((syntaxtree *)); static int NEAR donull __P_((syntaxtree *)); static int NEAR dobreak __P_((syntaxtree *)); static int NEAR docontinue __P_((syntaxtree *)); static int NEAR doreturn __P_((syntaxtree *)); static int NEAR execpath __P_((command_t *, int)); static int NEAR doexec __P_((syntaxtree *)); #ifndef MINIMUMSHELL static int NEAR dologin __P_((syntaxtree *)); static int NEAR dologout __P_((syntaxtree *)); #endif static int NEAR doeval __P_((syntaxtree *)); static int NEAR doexit __P_((syntaxtree *)); static int NEAR doread __P_((syntaxtree *)); static int NEAR doshift __P_((syntaxtree *)); static int NEAR doset __P_((syntaxtree *)); static int NEAR dounset __P_((syntaxtree *)); #ifndef _NOUSEHASH static int NEAR dohash __P_((syntaxtree *)); #endif static int NEAR dochdir __P_((syntaxtree *)); static int NEAR dopwd __P_((syntaxtree *)); static int NEAR dosource __P_((syntaxtree *)); static int NEAR expandlist __P_((char ***, CONST char *)); static int NEAR doexport __P_((syntaxtree *)); static int NEAR doreadonly __P_((syntaxtree *)); static int NEAR dotimes __P_((syntaxtree *)); static int NEAR dowait __P_((syntaxtree *)); static int NEAR doumask __P_((syntaxtree *)); static int NEAR doulimit __P_((syntaxtree *)); static int NEAR dotrap __P_((syntaxtree *)); #ifndef NOJOB static int NEAR dojobs __P_((syntaxtree *)); static int NEAR dofg __P_((syntaxtree *)); static int NEAR dobg __P_((syntaxtree *)); static int NEAR dodisown __P_((syntaxtree *)); #endif static int NEAR dotype __P_((syntaxtree *)); #ifdef DOSCOMMAND static int NEAR dodir __P_((syntaxtree *)); static int NEAR domkdir __P_((syntaxtree *)); static int NEAR dormdir __P_((syntaxtree *)); static int NEAR doerase __P_((syntaxtree *)); static int NEAR dorename __P_((syntaxtree *)); static int NEAR docopy __P_((syntaxtree *)); static int NEAR docls __P_((syntaxtree *)); static int NEAR dodtype __P_((syntaxtree *)); #endif #ifndef NOALIAS static int NEAR doalias __P_((syntaxtree *)); static int NEAR dounalias __P_((syntaxtree *)); #endif static int NEAR doecho __P_((syntaxtree *)); #ifndef MINIMUMSHELL static int NEAR dokill __P_((syntaxtree *)); static int NEAR dotest __P_((syntaxtree *)); #endif #ifndef NOPOSIXUTIL static int NEAR dofalse __P_((syntaxtree *)); static int NEAR docommand __P_((syntaxtree *)); static int NEAR dogetopts __P_((syntaxtree *)); static int NEAR donewgrp __P_((syntaxtree *)); # if 0 /* exists in FD original builtin */ static int NEAR dofc __P_((syntaxtree *)); # endif #endif /* !NOPOSIXUTIL */ #ifndef MINIMUMSHELL static int NEAR getworkdir __P_((char *)); static int NEAR dopushd __P_((syntaxtree *)); static int NEAR dopopd __P_((syntaxtree *)); static int NEAR dodirs __P_((syntaxtree *)); static int NEAR doenable __P_((syntaxtree *)); static int NEAR dobuiltin __P_((syntaxtree *)); static int NEAR doaddcr __P_((syntaxtree *)); #endif #ifdef WITHSOCKET static int NEAR doaccept __P_((syntaxtree *)); static int NEAR dosocketinfo __P_((syntaxtree *)); #endif #ifdef FD static int NEAR dofd __P_((syntaxtree *)); #endif static int NEAR doshfunc __P_((syntaxtree *, int)); #ifdef SHOWSTREE static VOID NEAR show_stree __P_((syntaxtree *, int)); #endif static int NEAR dosetshfunc __P_((CONST char *, syntaxtree *)); static int NEAR exec_statement __P_((syntaxtree *)); static char **NEAR checkshellbuiltinargv __P_((int, char **)); static int NEAR checkshellbuiltin __P_((syntaxtree *)); #if MSDOS static int NEAR exec_command __P_((syntaxtree *, int *)); #define exec_command2(tr, c, b) exec_command(tr, c) #else static int NEAR exec_command __P_((syntaxtree *, int *, int)); #define exec_command2 exec_command #endif #ifdef USEFAKEPIPE static int NEAR exec_process __P_((syntaxtree *)); #define exec_process2(tr, p) exec_process(tr) #else static int NEAR exec_process __P_((syntaxtree *, p_id_t)); #define exec_process2 exec_process #endif static int NEAR exec_stree __P_((syntaxtree *, int)); static syntaxtree *NEAR execline __P_((CONST char *, syntaxtree *, syntaxtree *, int)); static int NEAR exec_line __P_((CONST char *)); static int NEAR _dosystem __P_((CONST char *)); static XFILE *NEAR _dopopen __P_((CONST char *)); #ifndef FDSH int dosystem __P_((CONST char *)); XFILE *dopopen __P_((CONST char *)); int dopclose __P_((XFILE *)); #endif static int NEAR sourcefile __P_((int, CONST char *, int)); #if MSDOS && !defined (BSPATHDELIM) static VOID NEAR adjustdelim __P_((char *CONST *)); #endif static VOID NEAR initrc __P_((int)); #ifdef FDSH int main __P_((int, char *CONST [], char *CONST [])); #endif int shellmode = 0; p_id_t mypid = (p_id_t)-1; p_id_t orgpid = (p_id_t)-1; p_id_t shellpid = (p_id_t)-1; int ret_status = RET_SUCCESS; int interactive = 0; int errorexit = 0; #ifdef DEP_PTY int shptymode = 0; #define isshptymode() (!fdmode && shptymode) #endif #ifndef NOJOB int lastjob = -1; int prevjob = -1; int stopped = 0; p_id_t orgpgrp = (p_id_t)-1; p_id_t childpgrp = (p_id_t)-1; p_id_t ttypgrp = (p_id_t)-1; #endif int interrupted = 0; int nottyout = 0; int syntaxerrno = 0; #if !MSDOS int sigconted = 0; #endif CONST statementtable statementlist[] = { {doif, "if", STT_NEEDLIST, {0, 0, 0, 0}}, {NULL, "then", STT_NEEDLIST, {SM_IF, SM_ELIF, 0, 0}}, {NULL, "elif", STT_NEEDLIST, {SM_THEN, 0, 0, 0}}, {NULL, "else", STT_NEEDLIST, {SM_THEN, 0, 0, 0}}, {NULL, "fi", STT_NEEDNONE, {SM_THEN, SM_ELSE, 0, 0}}, {dowhile, "while", STT_NEEDLIST, {0, 0, 0, 0}}, {dountil, "until", STT_NEEDLIST, {0, 0, 0, 0}}, {NULL, "do", STT_NEEDLIST, {SM_WHILE, SM_UNTIL, SM_FOR, SM_IN}}, {NULL, "done", STT_NEEDNONE, {SM_DO, 0, 0, 0}}, {dofor, "for", STT_NEEDIDENT | STT_FOR, {0, 0, 0, 0}}, {NULL, "in", STT_NEEDIDENT | STT_IN, {SM_FOR, SM_ANOTHER, 0, 0}}, {docase, "case", STT_NEEDIDENT | STT_CASE, {0, 0, 0, 0}}, {NULL, "in", STT_NEEDIDENT | STT_INCASE, {SM_CASE, 0, 0, 0}}, {NULL, ")", STT_NEEDLIST, {SM_INCASE, SM_CASEEND, SM_ANOTHER, 0}}, {NULL, ";;", STT_CASEEND, {SM_RPAREN, 0, 0, 0}}, {NULL, "esac", STT_NEEDNONE, {SM_CASEEND, SM_RPAREN, 0, 0}}, {NULL, "(", STT_LPAREN, {0, 0, 0, 0}}, {NULL, ")", STT_FUNC, {SM_LPAREN, 0, 0, 0}}, {dolist, "{", STT_LIST | STT_NEEDLIST, {0, 0, 0, 0}}, {NULL, "}", STT_NEEDNONE, {SM_LIST, 0, 0, 0}}, }; #define STATEMENTSIZ arraysize(statementlist) CONST signaltable signallist[] = { #ifdef SIGHUP {SIGHUP, trap_hup, "HUP", MESHUP, TR_TERM | TR_BLOCK}, #endif #ifdef SIGINT {SIGINT, trap_int, "INT", MESINT, TR_TERM | TR_BLOCK | TR_READBL}, #endif #ifdef SIGQUIT {SIGQUIT, trap_quit, "QUIT", MESQUIT, TR_TERM | TR_BLOCK}, #endif #ifdef SIGILL {SIGILL, trap_ill, "ILL", MESILL, TR_TERM}, #endif #ifdef SIGTRAP {SIGTRAP, trap_trap, "TRAP", MESTRAP, TR_TERM}, #endif #ifdef SIGIOT {SIGIOT, trap_iot, "IOT", MESIOT, TR_TERM}, #else # ifdef SIGABRT {SIGABRT, trap_abrt, "ABRT", MESABRT, TR_TERM}, # endif #endif #ifdef SIGEMT {SIGEMT, trap_emt, "EMT", MESEMT, TR_TERM}, #endif #ifdef SIGFPE {SIGFPE, trap_fpe, "FPE", MESFPE, TR_TERM}, #endif #ifdef SIGKILL {SIGKILL, NULL, "KILL", MESKILL, 0}, #endif #ifdef SIGBUS {SIGBUS, trap_bus, "BUS", MESBUS, TR_TERM}, #endif #ifdef SIGSEGV # ifdef BASHSTYLE {SIGSEGV, trap_segv, "SEGV", MESSEGV, TR_TERM}, # else {SIGSEGV, trap_segv, "SEGV", MESSEGV, TR_TERM | TR_BLOCK | TR_NOTRAP}, # endif #endif #ifdef SIGSYS {SIGSYS, trap_sys, "SYS", MESSYS, TR_TERM}, #endif #ifdef SIGPIPE {SIGPIPE, trap_pipe, "PIPE", MESPIPE, TR_TERM}, #endif #ifdef SIGALRM {SIGALRM, trap_alrm, "ALRM", MESALRM, TR_TERM | TR_READBL}, #endif #ifdef SIGTERM {SIGTERM, trap_term, "TERM", MESTERM, TR_TERM | TR_BLOCK | TR_READBL}, #endif #ifdef SIGSTKFLT {SIGSTKFLT, trap_stkflt, "STKFLT", MESSTKFLT, TR_TERM}, #endif #ifdef SIGURG {SIGURG, trap_urg, "URG", MESURG, TR_IGN}, #endif #ifdef SIGSTOP {SIGSTOP, trap_stop, "STOP", MESSTOP, TR_STOP}, #endif #ifdef SIGTSTP {SIGTSTP, trap_tstp, "TSTP", MESTSTP, TR_STOP | TR_BLOCK}, #endif #ifdef SIGCONT # if MSDOS {SIGCONT, trap_cont, "CONT", MESCONT, TR_IGN}, # else {SIGCONT, trap_cont, "CONT", MESCONT, TR_IGN | TR_BLOCK}, # endif #endif #ifdef SIGCHLD # ifdef NOJOB {SIGCHLD, trap_chld, "CHLD", MESCHLD, TR_IGN}, # else {SIGCHLD, trap_chld, "CHLD", MESCHLD, TR_IGN | TR_BLOCK}, # endif #endif #ifdef SIGTTIN {SIGTTIN, trap_ttin, "TTIN", MESTTIN, TR_STOP | TR_BLOCK}, #endif #ifdef SIGTTOU {SIGTTOU, trap_ttou, "TTOU", MESTTOU, TR_STOP | TR_BLOCK}, #endif #ifdef SIGIO {SIGIO, trap_io, "IO", MESIO, TR_IGN}, #else # ifdef SIGPOLL {SIGPOLL, trap_poll, "POLL", MESPOLL, TR_TERM}, # endif #endif #ifdef SIGXCPU {SIGXCPU, trap_xcpu, "XCPU", MESXCPU, TR_TERM}, #endif #ifdef SIGXFSZ {SIGXFSZ, trap_xfsz, "XFSZ", MESXFSZ, TR_TERM}, #endif #ifdef SIGVTALRM {SIGVTALRM, trap_vtalrm, "VTALRM", MESVTALRM, TR_TERM}, #endif #ifdef SIGPROF {SIGPROF, trap_prof, "PROF", MESPROF, TR_TERM}, #endif #ifdef SIGWINCH # ifdef FD {SIGWINCH, trap_winch, "WINCH", MESWINCH, TR_IGN | TR_BLOCK}, # else {SIGWINCH, trap_winch, "WINCH", MESWINCH, TR_IGN}, # endif #endif #ifdef SIGLOST {SIGLOST, trap_lost, "LOST", MESLOST, TR_TERM}, #endif #ifdef SIGINFO {SIGINFO, trap_info, "INFO", MESINFO, TR_IGN}, #endif #ifdef SIGPWR {SIGPWR, trap_pwr, "PWR", MESPWR, TR_TERM}, #endif #ifdef SIGUSR1 # ifdef BASHSTYLE {SIGUSR1, trap_usr1, "USR1", MESUSR1, TR_TERM}, # else {SIGUSR1, trap_usr1, "USR1", MESUSR1, TR_TERM | TR_BLOCK}, # endif #endif #ifdef SIGUSR2 # ifdef BASHSTYLE {SIGUSR2, trap_usr2, "USR2", MESUSR2, TR_TERM}, # else {SIGUSR2, trap_usr2, "USR2", MESUSR2, TR_TERM | TR_BLOCK}, # endif #endif {-1, NULL, NULL, NULL, 0} }; int verboseexec = 0; int notexec = 0; int verboseinput = 0; int terminated = 0; int forcedstdin = 0; int interactive_io = 0; int tmperrorexit = 0; int restricted = 0; int freeenviron = 0; int undeferror = 0; int hashahead = 0; #if MSDOS int noglob = 1; #else int noglob = 0; #endif int autoexport = 0; #ifndef MINIMUMSHELL int noclobber = 0; int ignoreeof = 0; #endif #ifndef NOJOB int bgnotify = 0; int jobok = -1; #endif #ifdef FD # ifndef _NOEDITMODE int emacsmode = 0; int vimode = 0; # endif # ifdef DEP_PTY int tmpshptymode = 0; # endif # if !MSDOS int autosavetty = 0; # endif #endif /* FD */ int loginshell = 0; int noruncom = 0; static char **shellvar = NULL; static char **exportvar = NULL; static u_long exportsize = (u_long)0; static char **exportlist = NULL; static char **ronlylist = NULL; static char *shellname = NULL; static int definput = -1; static int exit_status = RET_SUCCESS; #if !MSDOS static sigmask_t oldsigmask; #endif static p_id_t lastpid = (p_id_t)-1; #ifndef NOJOB static p_id_t oldttypgrp = (p_id_t)-1; #endif static int setsigflag = 0; static int trapok = 0; static shfunctable *shellfunc = NULL; static pipelist *pipetop = NULL; static int childdepth = 0; static int loopdepth = 0; static int breaklevel = 0; static int continuelevel = 0; static int shfunclevel = 0; static int returnlevel = 0; #ifndef MINIMUMSHELL static char **dirstack = NULL; static long shlineno = 0L; static int lastsig = -1; #endif static int isshellbuiltin = 0; static int execerrno = 0; #if !MSDOS && defined (DEP_PTY) && defined (CYGWIN) static p_id_t *mychildren = (p_id_t *)NULL; #endif static CONST char *CONST syntaxerrstr[] = { NULL, #define ER_UNEXPTOK 1 "unexpected token", #define ER_UNEXPNL 2 "unexpected newline or `;'", #define ER_UNEXPEOF 3 "unexpected end of file", }; #define SYNTAXERRSIZ arraysize(syntaxerrstr) static CONST char *CONST execerrstr[] = { NULL, #define ER_COMNOFOUND 1 "command not found", #define ER_NOTFOUND 2 "not found", #define ER_CANNOTEXE 3 "cannot execute", #define ER_NOTIDENT 4 "is not an identifier", #define ER_BADSUBST 5 "bad substitution", #define ER_BADNUMBER 6 "bad number", #define ER_BADDIR 7 "bad directory", #define ER_CANNOTRET 8 "cannot return when not in function", #define ER_CANNOTSTAT 9 "cannot stat .", #define ER_CANNOTUNSET 10 "cannot unset", #define ER_ISREADONLY 11 "is read only", #define ER_CANNOTSHIFT 12 "cannot shift", #define ER_BADOPTIONS 13 "bad option(s)", #define ER_PARAMNOTSET 14 "parameter not set", #define ER_RESTRICTED 15 "restricted", #define ER_BADULIMIT 16 "bad ulimit", #define ER_BADTRAP 17 "bad trap", #define ER_NUMOUTRANGE 18 "number out of range", #define ER_NOHOMEDIR 19 "no home directory", #ifdef NOALIAS NULL, #else #define ER_NOTALIAS 20 "is not an alias", #endif #ifdef NOPOSIXUTIL NULL, #else #define ER_MISSARG 21 "missing argument", #endif #ifdef NOJOB NULL, NULL, #else #define ER_NOSUCHJOB 22 "no such job", #define ER_TERMINATED 23 "job has terminated", #endif #ifdef MINIMUMSHELL NULL, NULL, NULL, #else #define ER_NOTLOGINSH 24 "not login shell", #define ER_DIREMPTY 25 "directory stack empty", #define ER_UNKNOWNSIG 26 "unknown signal; kill -l lists signals", #endif #if !MSDOS NULL, #else #define ER_INVALDRIVE 27 "invalid drive specification", #endif #ifdef WITHSOCKET #define ER_NOTSOCKET 28 "not socket", #define ER_INVALSOCKET 29 "invalid socket", #else NULL, NULL, #endif #ifdef FD #define ER_RECURSIVEFD 30 "recursive call for FDclone", #define ER_INVALTERMFD 31 "invalid terminal for FDclone", #endif }; #define EXECERRSIZ arraysize(execerrstr) static CONST opetable opelist[] = { {OP_FG, 4, ";"}, {OP_BG, 4, "&"}, #ifndef MINIMUMSHELL {OP_NOWN, 4, "&|"}, #endif {OP_AND, 3, "&&"}, {OP_OR, 3, "||"}, {OP_PIPE, 2, "|"}, #ifndef MINIMUMSHELL {OP_NOT, 2, "!"}, #endif }; #define OPELISTSIZ arraysize(opelist) #if !defined (BASHBUG) && !defined (MINIMUMSHELL) static CONST opetable delimlist[] = { {OP_NONE, 1, "{"}, {OP_NONE, 1, ";;"}, {OP_FG, 1, ";"}, {OP_NONE, 0, "&>>"}, {OP_NONE, 0, "&>|"}, {OP_NONE, 0, "&>"}, {OP_AND, 1, "&&"}, {OP_NOWN, 1, "&|"}, {OP_BG, 1, "&"}, {OP_OR, 1, "||"}, {OP_PIPE, 1, "|&"}, {OP_PIPE, 1, "|"}, {OP_NOT, 1, "!"}, {OP_NONE, 0, "<<-"}, {OP_NONE, 0, "<<"}, {OP_NONE, 0, "<>"}, {OP_NONE, 0, "<&-"}, {OP_NONE, 0, "<&"}, {OP_NONE, 0, "<-"}, {OP_NONE, 0, "<"}, {OP_NONE, 0, "><"}, {OP_NONE, 0, ">>"}, {OP_NONE, 0, ">&-"}, {OP_NONE, 0, ">&"}, {OP_NONE, 0, ">-"}, {OP_NONE, 0, ">|"}, {OP_NONE, 0, ">"}, }; #define DELIMLISTSIZ arraysize(delimlist) #endif /* !BASHBUG && !MINIMUMSHELL */ static shbuiltintable shbuiltinlist[] = { {donull, ":", BT_POSIXSPECIAL}, {dobreak, "break", BT_POSIXSPECIAL}, {docontinue, "continue", BT_POSIXSPECIAL}, {doreturn, "return", BT_POSIXSPECIAL}, {doexec, "exec", BT_POSIXSPECIAL | BT_NOKANJIFGET}, #ifndef MINIMUMSHELL {dologin, "login", 0}, {dologout, "logout", 0}, #endif {doeval, "eval", BT_POSIXSPECIAL | BT_NOKANJIFGET}, {doexit, "exit", BT_POSIXSPECIAL}, {doread, "read", 0}, {doshift, "shift", BT_POSIXSPECIAL}, {doset, "set", BT_POSIXSPECIAL}, {dounset, "unset", BT_POSIXSPECIAL}, #ifndef _NOUSEHASH {dohash, "hash", 0}, #endif {dochdir, "cd", BT_RESTRICT | BT_FILENAME}, {dopwd, "pwd", 0}, {dosource, ".", BT_POSIXSPECIAL | BT_FILENAME}, #ifndef MINIMUMSHELL {dosource, "source", BT_FILENAME}, #endif {doexport, "export", BT_POSIXSPECIAL}, {doreadonly, "readonly", BT_POSIXSPECIAL}, {dotimes, "times", BT_POSIXSPECIAL}, {dowait, "wait", 0}, {doumask, "umask", 0}, {doulimit, "ulimit", 0}, {dotrap, "trap", BT_POSIXSPECIAL}, #ifndef NOJOB {dojobs, "jobs", 0}, {dofg, "fg", 0}, {dobg, "bg", 0}, {dodisown, "disown", 0}, #endif {dotype, "type", 0}, #ifdef DOSCOMMAND {donull, "rem", 0}, {dodir, "dir", BT_NOGLOB | BT_FILENAME}, {dochdir, "chdir", BT_RESTRICT | BT_FILENAME}, # if MSDOS {domkdir, "mkdir", BT_RESTRICT | BT_FILENAME}, {dormdir, "rmdir", BT_RESTRICT | BT_FILENAME}, # endif {domkdir, "md", BT_RESTRICT | BT_FILENAME}, {dormdir, "rd", BT_RESTRICT | BT_FILENAME}, {doerase, "erase", BT_NOGLOB | BT_RESTRICT | BT_FILENAME}, {doerase, "del", BT_NOGLOB | BT_RESTRICT | BT_FILENAME}, {dorename, "rename", BT_NOGLOB | BT_RESTRICT | BT_FILENAME}, {dorename, "ren", BT_NOGLOB | BT_RESTRICT | BT_FILENAME}, {docopy, "copy", BT_NOGLOB | BT_RESTRICT | BT_FILENAME}, {docls, "cls", 0}, {dodtype, "dtype", BT_FILENAME}, #endif /* DOSCOMMAND */ #ifndef NOALIAS {doalias, "alias", 0}, {dounalias, "unalias", BT_NOGLOB}, #endif {doecho, "echo", 0}, #ifndef MINIMUMSHELL {dokill, "kill", 0}, {dotest, "test", 0}, {dotest, "[", 0}, #endif #ifndef NOPOSIXUTIL {donull, "true", 0}, {dofalse, "false", 0}, {docommand, "command", BT_NOKANJIFGET}, {dogetopts, "getopts", 0}, {donewgrp, "newgrp", BT_RESTRICT}, # if 0 /* exists in FD original builtin */ {dofc, "fc", 0}, # endif #endif #ifndef MINIMUMSHELL {dopushd, "pushd", BT_RESTRICT | BT_FILENAME}, {dopopd, "popd", 0}, {dodirs, "dirs", 0}, {doenable, "enable", 0}, {dobuiltin, "builtin", 0}, {doaddcr, "addcr", 0}, #endif #ifdef WITHSOCKET {doaccept, "accept", BT_RESTRICT}, {dosocketinfo, "socketinfo", BT_RESTRICT}, #endif #ifdef FD {dofd, "fd", BT_FILENAME}, #endif }; #define SHBUILTINSIZ arraysize(shbuiltinlist) static CONST char *primalvar[] = { ENVPATH, ENVPS1, ENVPS2, ENVIFS, #if !MSDOS && !defined (MINIMUMSHELL) ENVMAILCHECK, ENVPPID, #endif }; #define PRIMALVARSIZ arraysize(primalvar) static CONST char *restrictvar[] = { ENVPATH, #ifdef FD "FD_SHELL", #else ENVSHELL, #endif #ifndef MINIMUMSHELL ENVENV, #endif }; #define RESTRICTVARSIZ arraysize(restrictvar) #if MSDOS && !defined (BSPATHDELIM) static CONST char *adjustvar[] = { ENVPATH, ENVHOME, # ifndef MINIMUMSHELL ENVENV, # endif # ifdef FD ENVPWD, "FD_HISTFILE", # ifdef FD >= 2 "FD_DIRHISTFILE", # endif # if FD >= 3 "FD_FREQFILE", # endif "FD_TMPDIR", # ifndef _NOROCKRIDGE "FD_RRPATH", # endif # ifndef _NOPRECEDE "FD_PRECEDEPATH", # endif # ifdef DEP_LOGGING "FD_LOGFILE", # endif # ifdef DEP_FTPPATH "FD_FTPLOGFILE", # endif # ifdef DEP_HTTPPATH "FD_HTTPLOGFILE", "FD_HTMLLOGFILE", # endif # ifdef DEP_FILECONV "FD_SJISPATH", "FD_EUCPATH", "FD_JISPATH", "FD_JIS8PATH", "FD_JUNETPATH", "FD_OJISPATH", "FD_OJIS8PATH", "FD_OJUNETPATH", "FD_HEXPATH", "FD_CAPPATH", "FD_UTF8PATH", "FD_UTF8MACPATH", "FD_UTF8ICONVPATH", "FD_NOCONVPATH", # endif "FD_PAGER", "FD_EDITOR", "FD_SHELL", # ifndef NOPOSIXUTIL "FD_FCEDIT", # endif # if MSDOS "FD_COMSPEC", # endif # else /* !FD */ ENVSHELL, # if MSDOS ENVCOMSPEC, # endif # endif /* !FD */ }; #define ADJUSTVARSIZ arraysize(adjustvar) #endif /* MSDOS && !BSPATHDELIM */ static CONST shflagtable shflaglist[] = { {"xtrace", &verboseexec, 'x'}, {"noexec", ¬exec, 'n'}, {"verbose", &verboseinput, 'v'}, {"onecmd", &terminated, 't'}, {NULL, &forcedstdin, 's'}, {NULL, &interactive_io, 'i'}, {"errexit", &tmperrorexit, 'e'}, {NULL, &restricted, 'r'}, {"keyword", &freeenviron, 'k'}, {"nounset", &undeferror, 'u'}, {"hashahead", &hashahead, 'h'}, {"noglob", &noglob, 'f'}, {"allexport", &autoexport, 'a'}, #ifndef MINIMUMSHELL {"noclobber", &noclobber, 'C'}, {"ignoreeof", &ignoreeof, '\0'}, #endif #ifndef NOJOB {"notify", &bgnotify, 'b'}, {"monitor", &jobok, 'm'}, #endif #ifdef FD {"physical", &physical_path, 'P'}, # ifndef _NOEDITMODE {"emacs", &emacsmode, '\0'}, {"vi", &vimode, '\0'}, # endif # ifdef DEP_PTY {"ptyshell", &tmpshptymode, 'T'}, # endif # if !MSDOS {"autosavetty", &autosavetty, 'S'}, # endif #endif /* FD */ {NULL, &loginshell, 'l'}, {NULL, &noruncom, 'N'}, }; #define FLAGSSIZ arraysize(shflaglist) #ifdef USERESOURCEH static CONST ulimittable ulimitlist[] = { #ifdef RLIMIT_CPU {'t', RLIMIT_CPU, 1, "time(seconds)"}, #endif #ifdef RLIMIT_FSIZE {'f', RLIMIT_FSIZE, DEV_BSIZE, "file(blocks)"}, #endif #ifdef RLIMIT_DATA {'d', RLIMIT_DATA, 1024, "data(kbytes)"}, #endif #ifdef RLIMIT_STACK {'s', RLIMIT_STACK, 1024, "stack(kbytes)"}, #endif #ifdef RLIMIT_CORE {'c', RLIMIT_CORE, DEV_BSIZE, "coredump(blocks)"}, #endif #ifdef RLIMIT_RSS {'m', RLIMIT_RSS, 1024, "memory(kbytes)"}, #endif #ifdef RLIMIT_MEMLOCK {'l', RLIMIT_MEMLOCK, 1024, "locked memory(kbytes)"}, #endif #ifdef RLIMIT_NPROC {'u', RLIMIT_NPROC, 1, "processes(units)"}, #endif #ifdef RLIMIT_NOFILE {'n', RLIMIT_NOFILE, 1, "nofiles(descriptors)"}, #endif #ifdef RLIMIT_VMEM {'v', RLIMIT_VMEM, 1024, "virtual memory(kbytes)"}, #endif }; #define ULIMITSIZ arraysize(ulimitlist) #endif /* USERESOURCEH */ static int trapmode[NSIG]; static char *trapcomm[NSIG]; static sigarg_t (*oldsigfunc[NSIG])__P_((sigfnc_t)); #ifdef WITHSOCKREDIR static scheme_t schemelist[] = { #define DEFSCHEME(i, t) {i, strsize(i), -1, t} DEFSCHEME("connect", TYPE_CONNECT), DEFSCHEME("accept", TYPE_ACCEPT), DEFSCHEME("bind", TYPE_BIND), {NULL, 0, 0}, }; #endif #ifndef FD static lockbuf_t *NEAR lockopen(path, flags, mode) CONST char *path; int flags, mode; { lockbuf_t *lck; int fd; if ((fd = newdup(Xopen(path, flags, mode))) >= 0) /*EMPTY*/; else if (errno != ENOENT) return(NULL); lck = (lockbuf_t *)Xmalloc(sizeof(lockbuf_t)); lck -> fd = fd; return(lck); } static VOID NEAR lockclose(lck) lockbuf_t *lck; { if (lck) { if (lck -> fd >= 0) VOID_C Xclose(lck -> fd); Xfree(lck); } } static int NEAR genrand(max) int max; { # ifdef MINIMUMSHELL static u_int last = 0; static int init = 0; if (!init) { init++; last = getpid(); } last = last * 12345 + 101; return(last % max); # else /* !MINIMUMSHELL */ static long last = -1L; time_t now; if (last < 0L) { now = Xtime(NULL); last = ((now & 0xff) << 16) + (now & ~0xff) + getpid(); } do { last = last * (u_long)1103515245 + 12345; } while (last < 0L); return((last / 65537L) % max); # endif /* !MINIMUMSHELL */ } static char *NEAR genrandname(buf, len) char *buf; int len; { static char seq[] = { # ifdef PATHNOCASE '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '_' # else '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '_' # endif }; int i, j, c; if (!buf) { for (i = 0; i < arraysize(seq); i++) { j = genrand(arraysize(seq)); c = seq[i]; seq[i] = seq[j]; seq[j] = c; } } else { for (i = 0; i < len; i++) { j = genrand(arraysize(seq)); buf[i] = seq[j]; } buf[i] = '\0'; } return(buf); } static int NEAR mktmpfile(file) char *file; { char *cp, path[MAXPATHLEN]; int fd, n, len; Xstrcpy(path, deftmpdir); cp = strcatdelim(path); n = strsize(TMPPREFIX); Xstrncpy(cp, TMPPREFIX, n); len = strsize(path) - (cp - path); if (len > MAXTMPNAMLEN) len = MAXTMPNAMLEN; len -= n; genrandname(NULL, 0); for (;;) { genrandname(cp + n, len); fd = Xopen(path, O_BINARY | O_WRONLY | O_CREAT | O_EXCL, 0644); if (fd >= 0) { Xstrcpy(file, path); return(fd); } if (errno != EEXIST) break; } return(-1); } static int NEAR rmtmpfile(file) CONST char *file; { if (Xunlink(file) < 0 && errno != ENOENT) return(-1); return(0); } /*ARGSUSED*/ int chdir3(dir, raw) CONST char *dir; int raw; { if (chdir2(dir) < 0) return(-1); # ifndef _NOUSEHASH VOID_C searchhash(NULL, nullstr, nullstr); # endif return(0); } int setenv2(name, value, export) CONST char *name, *value; int export; { char *cp; int len; len = strlen(name); if (!value) return(unset(name, len)); else { cp = Xmalloc(len + strlen(value) + 2); memcpy(cp, name, len); cp[len] = '='; Xstrcpy(&(cp[len + 1]), value); } if (((export) ? putexportvar(cp, len) : putshellvar(cp, len)) < 0) { Xfree(cp); return(-1); } return(0); } # ifdef USESIGACTION static sigcst_t NEAR signal2(sig, func) int sig; sigcst_t func; { struct sigaction act, oact; act.sa_handler = func; #ifdef SA_INTERRUPT act.sa_flags = SA_INTERRUPT; #else act.sa_flags = 0; #endif sigemptyset(&(act.sa_mask)); sigemptyset(&(oact.sa_mask)); if (sigaction(sig, &act, &oact) < 0) return(SIG_ERR); return(oact.sa_handler); } # endif /* USESIGACTION */ # if MSDOS && !defined (BSPATHDELIM) static char *NEAR adjustpname(path) char *path; { int i; for (i = 0; path[i]; i++) { if (path[i] == '\\') path[i] = _SC_; else if (iskanji1(path, i)) i++; } return(path); } # endif /* MSDOS && !BSPATHDELIM */ # if !MSDOS && !defined (NOJOB) static VOID NEAR stdiomode(VOID_A) { # ifdef USESGTTY int lflag; # endif termioctl_t tty; if (tioctl(ttyio, REQGETP, &tty) >= 0) { # ifdef USESGTTY tty.sg_flags |= ECHO | CRMOD; tty.sg_flags &= ~(RAW | CBREAK | XTABS); # else tty.c_lflag |= (TIO_LCOOKED | TIO_LECHO); tty.c_lflag &= ~(PENDIN | ECHONL); tty.c_iflag |= (TIO_ICOOKED | ICRNL); tty.c_iflag &= TIO_INOCOOKED; tty.c_oflag |= TIO_ONL; tty.c_oflag &= (TIO_ONONL & ~TAB3); # endif VOID_C tioctl(ttyio, REQSETP, &tty); } # ifdef USESGTTY if (Xioctl(ttyio, TIOCLGET, &lflag) >= 0) { lflag |= LPASS8 | LCRTBS | LCRTERA | LCRTKIL | LCTLECH; lflag &= ~(LLITOUT | LPENDIN); VOID_C Xioctl(ttyio, TIOCLSET, &lflag); } # endif } # endif /* !MSDOS && !NOJOB */ #endif /* !FD */ #ifndef NOJOB static VOID NEAR notifyjob(VOID_A) { XFILE *fp; int fd; if ((fd = Xdup(STDERR_FILENO)) < 0) fp = Xstderr; else if (!(fp = Xfdopen(fd, "a"))) { VOID_C Xclose(fd); fp = Xstderr; } else Xsetlinebuf(fp); checkjob(fp); safefclose(fp); } #endif /* !NOJOB */ static VOID NEAR setsignal(VOID_A) { int i, sig; if (setsigflag++) return; #if defined (FD) && defined (SIGALRM) noalrm++; #endif for (i = 0; signallist[i].sig >= 0; i++) { sig = signallist[i].sig; if (signallist[i].flags & TR_BLOCK) /*EMPTY*/; else if (signallist[i].flags & TR_READBL) /*EMPTY*/; else if ((trapmode[sig] & TR_STAT) != TR_TRAP) continue; else if ((signallist[i].flags & TR_STAT) == TR_STOP) continue; signal2(sig, (sigcst_t)(signallist[i].func)); } } static VOID NEAR resetsignal(forced) int forced; { #if !MSDOS && defined (NOJOB) p_id_t tmp; #endif #if defined (SIGCHLD) && !defined (NOJOB) int n; #endif int i, duperrno; duperrno = errno; #if !MSDOS # ifdef NOJOB do { tmp = Xwait3(NULL, WNOHANG | WUNTRACED, NULL); } while (tmp > (p_id_t)0 || (tmp < (p_id_t)0 && errno == EINTR)); # else notifyjob(); stopped = 0; # endif #endif /* !MSDOS */ if (havetty() && interrupted && interactive && !nottyout) { Xfflush(Xstdout); VOID_C fputnl(Xstderr); } interrupted = 0; if (setsigflag) { if (forced) setsigflag = 1; if (!(--setsigflag)) { #if defined (FD) && defined (SIGALRM) noalrm--; #endif for (i = 0; i < NSIG; i++) { #if defined (SIGCHLD) && !defined (NOJOB) if (i == SIGCHLD && bgnotify) { for (n = 0; n < maxjobs; n++) if (joblist[n].pids) break; if (n < maxjobs) continue; } #endif if (oldsigfunc[i] != SIG_ERR) signal2(i, oldsigfunc[i]); } #if !MSDOS Xsigsetmask(oldsigmask); #endif } } errno = duperrno; } static VOID NEAR exectrapcomm(VOID_A) { #if MSDOS sigcst_t ofunc; #else sigmask_t mask, omask; #endif int i, dupinterrupted; #if !MSDOS if (!havetty()) return; #endif for (i = 0; i < NSIG; i++) { if (!(trapmode[i] & TR_CATCH)) continue; trapmode[i] &= ~TR_CATCH; if (!trapcomm[i] || !*(trapcomm[i])) continue; #if MSDOS ofunc = signal2(i, SIG_IGN); #else Xsigemptyset(mask); Xsigaddset(mask, i); Xsigblock(omask, mask); #endif dupinterrupted = interrupted; interrupted = 0; _dosystem(trapcomm[i]); interrupted = dupinterrupted; #if MSDOS signal2(i, ofunc); #else Xsigsetmask(omask); #endif } } static VOID NEAR killmyself(sig) int sig; { printf_urgent++; prepareexit(0); printf_urgent--; signal2(sig, SIG_DFL); VOID_C kill(mypid, sig); exit(sig + 128); } static int NEAR trap_common(sig) int sig; { #if !MSDOS && defined (DEP_PTY) && defined (CYGWIN) int n; #endif #if !MSDOS sigmask_t mask, omask; #endif int i, trapped, flags, duperrno, duptrapok; duperrno = errno; duptrapok = trapok; trapok = -1; #ifndef MINIMUMSHELL lastsig = -1; #endif #if !MSDOS Xsigemptyset(mask); Xsigaddset(mask, sig); Xsigblock(omask, mask); /* for obsolete signal() */ #endif for (i = 0; signallist[i].sig >= 0; i++) if (sig == signallist[i].sig) break; if (signallist[i].sig < 0) { signal2(sig, SIG_DFL); #if !MSDOS Xsigsetmask(omask); #endif errno = duperrno; trapok = duptrapok; VOID_C kill(mypid, sig); return(0); } trapped = 0; flags = signallist[i].flags; if (mypid != shellpid) { if ((flags & TR_BLOCK) && (flags & TR_STAT) == TR_TERM) trapped = -1; } else if ((trapmode[sig] & TR_STAT) == TR_TRAP) trapped = 1; else if (flags & TR_BLOCK) /*EMPTY*/; else if ((flags & TR_STAT) == TR_TERM) trapped = -1; if (trapped > 0) { trapmode[sig] |= TR_CATCH; if (duptrapok > 0) exectrapcomm(); } else if (trapped < 0 && signallist[i].mes && *(signallist[i].mes)) { Xfputs(signallist[i].mes, Xstderr); VOID_C fputnl(Xstderr); } #if !MSDOS && defined (DEP_PTY) && defined (CYGWIN) if (mychildren && (flags & TR_STAT) == TR_TERM) { for (n = 0; mychildren[n] >= (p_id_t)0; n++) { VOID_C kill(mychildren[n], sig); # ifdef SIGCONT VOID_C kill(mychildren[n], SIGCONT); # endif } Xfree(mychildren); mychildren = NULL; } #endif /* !MSDOS && DEP_PTY && CYGWIN */ if (trapped < 0) { #if !MSDOS Xsigsetmask(omask); #endif killmyself(sig); } #ifndef MINIMUMSHELL lastsig = i; #endif switch (sig) { #ifdef SIGHUP case SIGHUP: if (trapped) break; # ifndef NOJOB if (havetty()) killjob(); # endif if (oldsigfunc[sig] && oldsigfunc[sig] != SIG_ERR && oldsigfunc[sig] != SIG_DFL && oldsigfunc[sig] != SIG_IGN) { # ifdef SIGFNCINT (*oldsigfunc[sig])(sig); # else (*oldsigfunc[sig])(); # endif } #if !MSDOS Xsigsetmask(omask); #endif killmyself(sig); break; #endif /* SIGHUP */ #if !MSDOS && defined (SIGCONT) case SIGCONT: # ifdef FD suspended = 1; # endif sigconted = 1; break; #endif /* !MSDOS && SIGCONT */ #ifdef SIGINT case SIGINT: interrupted = 1; break; #endif #if defined (SIGCHLD) && (!defined (NOJOB) || defined (SYSV)) case SIGCHLD: # ifndef NOJOB if (bgnotify) { notifyjob(); break; } # endif # ifdef SYSV /* TIPS for obsolete SystemV signal() */ while (waitjob(-1, NULL, WNOHANG | WUNTRACED) > 0) /*EMPTY*/; # endif break; #endif /* SIGCHLD && (!NOJOB || SYSV) */ #if defined (FD) && defined (SIGWINCH) case SIGWINCH: pollscreen(1); break; #endif /* FD && SIGWINCH */ default: break; } if (signallist[i].func) signal2(sig, (sigcst_t)(signallist[i].func)); #if !MSDOS Xsigsetmask(omask); #endif errno = duperrno; trapok = duptrapok; return(trapped); } #ifdef SIGHUP static int trap_hup(VOID_A) { return(trap_common(SIGHUP)); } #endif #ifdef SIGINT static int trap_int(VOID_A) { return(trap_common(SIGINT)); } #endif #ifdef SIGQUIT static int trap_quit(VOID_A) { return(trap_common(SIGQUIT)); } #endif #ifdef SIGILL static int trap_ill(VOID_A) { return(trap_common(SIGILL)); } #endif #ifdef SIGTRAP static int trap_trap(VOID_A) { return(trap_common(SIGTRAP)); } #endif #ifdef SIGIOT static int trap_iot(VOID_A) { return(trap_common(SIGIOT)); } #else # ifdef SIGABRT static int trap_abrt(VOID_A) { return(trap_common(SIGABRT)); } # endif #endif /* SIGIOT */ #ifdef SIGEMT static int trap_emt(VOID_A) { return(trap_common(SIGEMT)); } #endif #ifdef SIGFPE static int trap_fpe(VOID_A) { return(trap_common(SIGFPE)); } #endif #ifdef SIGBUS static int trap_bus(VOID_A) { return(trap_common(SIGBUS)); } #endif #ifdef SIGSEGV static int trap_segv(VOID_A) { return(trap_common(SIGSEGV)); } #endif #ifdef SIGSYS static int trap_sys(VOID_A) { return(trap_common(SIGSYS)); } #endif #ifdef SIGPIPE static int trap_pipe(VOID_A) { return(trap_common(SIGPIPE)); } #endif #ifdef SIGALRM static int trap_alrm(VOID_A) { return(trap_common(SIGALRM)); } #endif #ifdef SIGTERM static int trap_term(VOID_A) { return(trap_common(SIGTERM)); } #endif #ifdef SIGSTKFLT static int trap_stkflt(VOID_A) { return(trap_common(SIGSTKFLT)); } #endif #ifdef SIGURG static int trap_urg(VOID_A) { return(trap_common(SIGURG)); } #endif #ifdef SIGSTOP static int trap_stop(VOID_A) { return(trap_common(SIGSTOP)); } #endif #ifdef SIGTSTP static int trap_tstp(VOID_A) { return(trap_common(SIGTSTP)); } #endif #ifdef SIGCONT static int trap_cont(VOID_A) { return(trap_common(SIGCONT)); } #endif #ifdef SIGCHLD static int trap_chld(VOID_A) { return(trap_common(SIGCHLD)); } #endif #ifdef SIGTTIN static int trap_ttin(VOID_A) { return(trap_common(SIGTTIN)); } #endif #ifdef SIGTTOU static int trap_ttou(VOID_A) { return(trap_common(SIGTTOU)); } #endif #ifdef SIGIO static int trap_io(VOID_A) { return(trap_common(SIGIO)); } #else # ifdef SIGPOLL static int trap_poll(VOID_A) { return(trap_common(SIGPOLL)); } # endif #endif /* SIGIO */ #ifdef SIGXCPU static int trap_xcpu(VOID_A) { return(trap_common(SIGXCPU)); } #endif #ifdef SIGXFSZ static int trap_xfsz(VOID_A) { return(trap_common(SIGXFSZ)); } #endif #ifdef SIGVTALRM static int trap_vtalrm(VOID_A) { return(trap_common(SIGVTALRM)); } #endif #ifdef SIGPROF static int trap_prof(VOID_A) { return(trap_common(SIGPROF)); } #endif #ifdef SIGWINCH static int trap_winch(VOID_A) { return(trap_common(SIGWINCH)); } #endif #ifdef SIGLOST static int trap_lost(VOID_A) { return(trap_common(SIGLOST)); } #endif #ifdef SIGINFO static int trap_info(VOID_A) { return(trap_common(SIGINFO)); } #endif #ifdef SIGPWR static int trap_pwr(VOID_A) { return(trap_common(SIGPWR)); } #endif #ifdef SIGUSR1 static int trap_usr1(VOID_A) { return(trap_common(SIGUSR1)); } #endif #ifdef SIGUSR2 static int trap_usr2(VOID_A) { return(trap_common(SIGUSR2)); } #endif #ifndef MINIMUMSHELL int catchsignal(verbose) int verbose; { int n, duperrno; if (verbose < 0) { lastsig = -1; return(0); } if (lastsig < 0) return(0); switch (signallist[lastsig].sig) { # ifdef SIGTTIN case SIGTTIN: n = -1; break; # endif # ifdef SIGTTOU case SIGTTOU: n = -1; break; # endif default: n = 0; break; } if (n >= 0 || !verbose) /*EMPTY*/; else if (signallist[lastsig].mes && *(signallist[lastsig].mes)) { duperrno = errno; Xfputs(signallist[lastsig].mes, Xstderr); VOID_C fputnl(Xstderr); errno = duperrno; } return(n); } #endif /* !MINIMUMSHELL */ VOID prepareexit(noexit) int noexit; { #ifdef DEBUG int i; #endif int duperrno; if (noexit > 0) { resetsignal(1); return; } duperrno = errno; exectrapcomm(); if (mypid == orgpid && !noexit && (trapmode[0] & TR_STAT) == TR_TRAP) { trapmode[0] = 0; if (trapcomm[0] && *(trapcomm[0])) _dosystem(trapcomm[0]); } #ifndef NOJOB if (ttyio >= 0) VOID_C gettermio(oldttypgrp, 1); #endif #ifdef DEP_URLPATH VOID_C urlallclose(); #endif resetsignal(1); freefunc(shellfunc); shellfunc = NULL; #ifdef DEBUG if (definput >= 0) { if (definput != ttyio) safeclose(definput); definput = -1; } freevar(shellvar); shellvar = NULL; freevar(exportvar); exportvar = NULL; exportsize = (u_long)0; freevar(exportlist); exportlist = NULL; freevar(ronlylist); ronlylist = NULL; freevar(argvar); argvar = NULL; # ifndef MINIMUMSHELL freevar(dirstack); dirstack = NULL; # endif /* !MINIMUMSHELL */ # ifndef NOALIAS freealias(shellalias); shellalias = NULL; # endif # ifndef _NOUSEHASH VOID_C searchhash(NULL, NULL, NULL); # endif # if !MSDOS && !defined (MINIMUMSHELL) checkmail(1); # endif for (i = 0; i < NSIG; i++) { signal2(i, SIG_IGN); Xfree(trapcomm[i]); trapcomm[i] = NULL; signal2(i, oldsigfunc[i]); } # ifndef NOJOB if (joblist) { for (i = 0; i < maxjobs; i++) freejob(i); maxjobs = 0; Xfree(joblist); joblist = NULL; } # endif /* !NOJOB */ # ifdef CYGWIN freecygdrive(); # endif # if defined (DEP_KANJIPATH) || defined (DEP_ROCKRIDGE) \ || defined (DEP_PSEUDOPATH) freeopenlist(); # endif #endif /* DEBUG */ errno = duperrno; } VOID Xexit2(n) int n; { if (mypid == orgpid) { #ifndef NOJOB if (loginshell && interactive_io) killjob(); #endif #ifdef FD if (havetty() && interactive && !nottyout) { if (!dumbterm) putterm(T_NORMAL); endterm(); inittty(1); keyflush(); } #endif exec_line(NULL); _dosystem(NULL); } prepareexit(0); #ifdef FD if (mypid == orgpid) prepareexitfd(n); #endif #ifdef DEBUG if (havetty() && mypid == orgpid) { # if !MSDOS && defined (FD) freeterment(); # endif closetty(&ttyio, &ttyout); muntrace(); } #endif /* DEBUG */ exit(n); } #ifdef FD static VOID NEAR argfputs(s, fp) CONST char *s; XFILE *fp; { # ifdef DEP_FILECONV char *cp; # endif # ifdef DEP_FILECONV cp = newkanjiconv(s, defaultkcode, DEFCODE, L_FNAME); VOID_C Xfprintf(fp, "%a", cp); if (cp != s) Xfree(cp); # else VOID_C Xfprintf(fp, "%a", s); # endif } #endif /* FD */ #ifdef DEP_FILECONV static int NEAR Kopen(path, flags, mode) CONST char *path; int flags, mode; { char buf[MAXPATHLEN]; path = kanjiconv2(buf, path, MAXPATHLEN - 1, defaultkcode, DEFCODE, L_FNAME); return(Xopen(path, flags, mode)); } #endif /* DEP_FILECONV */ static VOID NEAR syntaxerror(s) CONST char *s; { if (syntaxerrno <= 0 || syntaxerrno >= SYNTAXERRSIZ) return; #ifndef BASHSTYLE /* bash shows its name, even in interective shell */ if (interactive) /*EMPTY*/; else #endif if (argvar && argvar[0]) VOID_C Xfprintf(Xstderr, "%k: ", argvar[0]); #ifndef MINIMUMSHELL if (!interactive && shlineno > 0L) VOID_C Xfprintf(Xstderr, "%ld: ", shlineno); #endif if (s) VOID_C Xfprintf(Xstderr, "%a: ", (*s && syntaxerrno != ER_UNEXPNL) ? s : "syntax error"); if (syntaxerrstr[syntaxerrno]) Xfputs(syntaxerrstr[syntaxerrno], Xstderr); VOID_C fputnl(Xstderr); ret_status = RET_SYNTAXERR; if (errorexit) Xexit2(RET_SYNTAXERR); safeexit(); } /*ARGSUSED*/ VOID execerror(argv, s, n, noexit) char *CONST *argv; CONST char *s; int n, noexit; { if (n == ER_BADSUBST && (execerrno == ER_ISREADONLY || execerrno == ER_PARAMNOTSET)) return; if (!n || n >= EXECERRSIZ) return; #ifndef BASHSTYLE /* bash shows its name, even in interective shell */ if (interactive) /*EMPTY*/; else #endif if (argvar && argvar[0]) VOID_C Xfprintf(Xstderr, "%k: ", argvar[0]); #ifndef MINIMUMSHELL if (!interactive && shlineno > 0L) VOID_C Xfprintf(Xstderr, "%ld: ", shlineno); #endif if (argv && argv[0]) VOID_C Xfprintf(Xstderr, "%k: ", argv[0]); if (s) VOID_C Xfprintf(Xstderr, "%a: ", s); if (execerrstr[n]) Xfputs(execerrstr[n], Xstderr); VOID_C fputnl(Xstderr); execerrno = n; #ifndef BASHSTYLE /* bash does not break any statement on error */ if (noexit < 2) breaklevel = loopdepth; #endif #if MSDOS /* child process fake */ if (childdepth) return; #endif if (noexit < 0) safeexit(); else if (noexit) /*EMPTY*/; #if !defined (BASHSTYLE) || defined (STRICTPOSIX) /* bash does not exit on error, in non interactive shell */ else if (isshellbuiltin) safeexit(); #endif } VOID doperror(command, s) CONST char *command, *s; { int duperrno; duperrno = errno; if (errno < 0) return; if (!command) command = (argvar && argvar[0]) ? argvar[0] : shellname; VOID_C Xfprintf(Xstderr, "%k: ", command); if (s) VOID_C Xfprintf(Xstderr, "%a: ", s); Xfputs(Xstrerror(duperrno), Xstderr); VOID_C fputnl(Xstderr); errno = 0; #ifndef BASHSTYLE /* bash does not break any statement on error */ breaklevel = loopdepth; #endif #if MSDOS /* child process fake */ if (childdepth) return; #endif #if !defined (BASHSTYLE) || defined (STRICTPOSIX) /* bash does not exit on error, in non interactive shell */ if (isshellbuiltin) safeexit(); #endif } int isnumeric(s) CONST char *s; { int i, n; i = 0; if ((n = getnum(s, &i)) < 0) return(-1); #ifndef BASHSTYLE /* bash always treats non numeric character as error */ if (s[i]) return(-1); #endif return(n); } #if !MSDOS VOID dispsignal(sig, width, fp) int sig, width; XFILE *fp; { int i; for (i = 0; signallist[i].sig >= 0; i++) if (sig == signallist[i].sig) break; if (signallist[i].sig < 0) { if ((width -= strsize("Signal ")) < 0) width = 0; VOID_C Xfprintf(fp, "Signal %-*d", width, sig); } else if (!signallist[i].mes || !*(signallist[i].mes)) /*EMPTY*/; else if (!width) Xfputs(signallist[i].mes, fp); else VOID_C Xfprintf(fp, "%-*.*s", width, width, signallist[i].mes); } int waitjob(pid, wp, opt) p_id_t pid; wait_pid_t *wp; int opt; { # if !defined (NOJOB) || defined (SYSV) static wait_pid_t *waitlist = NULL; static p_id_t *pidlist = NULL; static int maxtrap = 0; # endif # ifndef NOJOB int i, n, sig; # endif sigmask_t mask, omask; wait_pid_t w; p_id_t tmp; int ret; Xsigemptyset(mask); # ifdef SIGCHLD Xsigaddset(mask, SIGCHLD); # endif Xsigblock(omask, mask); for (;;) { # ifndef JOBTEST tmp = (pid < (p_id_t)0) ? Xwait3(&w, opt, NULL) : Xwait4(pid, &w, opt, NULL); # else /* JOBTEST */ tmp = Xwait3(&w, opt, NULL); if (pid >= (p_id_t)0 && tmp >= (p_id_t)0 && pid != tmp) { if ((n = searchjob(tmp, &i)) < 0) continue; sig = joblist[n].stats[i]; joblist[n].stats[i] = getwaitsig(w); # if defined (SIGCONT) && (defined (SIGTTIN) || defined (SIGTTOU)) if (sig == joblist[n].stats[i]) sig = 0; # ifdef SIGTTIN else if (joblist[n].stats[i] == SIGTTIN) /*EMPTY*/; # endif # ifdef SIGTTOU else if (joblist[n].stats[i] == SIGTTOU) /*EMPTY*/; # endif else sig = 0; if (sig) { usleep(100000L); VOID_C kill(tmp, SIGCONT); } # endif /* SIGCONT && (SIGTTIN || SIGTTOU) */ continue; } # endif /* JOBTEST */ if (tmp >= (p_id_t)0 || errno != EINTR) break; } # if !defined (NOJOB) || defined (SYSV) if (pid >= (p_id_t)0) { if (tmp < (p_id_t)0 && errno == ECHILD) { while (maxtrap-- > 0) if (pid == pidlist[maxtrap]) { tmp = pidlist[maxtrap]; w = waitlist[maxtrap]; break; } } Xfree(waitlist); waitlist = NULL; Xfree(pidlist); pidlist = NULL; maxtrap = 0; } else if (tmp >= (p_id_t)0) { waitlist = (wait_pid_t *)Xrealloc(waitlist, (maxtrap + 1) * sizeof(wait_pid_t)); pidlist = (p_id_t *)Xrealloc(pidlist, (maxtrap + 1) * sizeof(p_id_t)); pidlist[maxtrap] = tmp; waitlist[maxtrap] = w; maxtrap++; } # endif /* !NOJOB || SYSV */ Xsigsetmask(omask); if (!tmp) return(0); else if (tmp < (p_id_t)0) return(-1); else { ret = (pid < (p_id_t)0 || tmp == pid) ? 1 : 0; # ifndef NOJOB sig = getwaitsig(w); # endif } # ifndef NOJOB if (ret < 0) /*EMPTY*/; else if ((n = searchjob(tmp, &i)) >= 0 && sig != joblist[n].stats[i]) { joblist[n].stats[i] = sig; if (pid == tmp || i < joblist[n].npipe || !WIFSTOPPED(w)) /*EMPTY*/; else if (jobok && interactive && !nottyout) dispjob(n, Xstderr); } # endif if (wp) *wp = w; return(ret); } # if !defined (NOJOB) && defined (DEP_PTY) && defined (CYGWIN) static VOID NEAR addmychild(pid) p_id_t pid; { int n; n = 0; if (mychildren) while (mychildren[n] >= (p_id_t)0) n++; mychildren = (p_id_t *)Xrealloc(mychildren, (n + 2) * sizeof(p_id_t)); mychildren[n++] = pid; mychildren[n] = (p_id_t)-1; } # endif /* !NOJOB && DEP_PTY && CYGWIN */ static VOID NEAR setstopsig(valid) int valid; { sigcst_t func; int i; for (i = 0; signallist[i].sig >= 0; i++) { func = (valid) ? SIG_DFL : (sigcst_t)(signallist[i].func); if ((signallist[i].flags & TR_STAT) == TR_STOP) { if (valid < 0) func = SIG_IGN; } else if (!(signallist[i].flags & TR_BLOCK)) continue; signal2(signallist[i].sig, func); } } /*ARGSUSED*/ static p_id_t NEAR makechild(tty, ppid) int tty; p_id_t ppid; { # ifdef DEBUG extern VOID (*__free_hook) __P_((VOID_P)); extern VOID_P (*__malloc_hook) __P_((ALLOC_T)); extern VOID_P (*__realloc_hook) __P_((VOID_P, ALLOC_T)); # endif sigmask_t mask, omask; p_id_t pid; int i, stop; Xsigfillset(mask); Xsigblock(omask, mask); if (!(pid = Xfork())) { # ifdef DEBUG __free_hook = NULL; __malloc_hook = NULL; __realloc_hook = NULL; # endif memcpy((char *)&omask, (char *)&oldsigmask, sizeof(sigmask_t)); # ifdef SIGCHLD Xsigdelset(omask, SIGCHLD); # endif mypid = getpid(); stop = -1; # ifdef NOJOB if (loginshell) stop = 0; # else if (jobok) stop = (tty && childpgrp != orgpgrp) ? 1 : 0; # endif setstopsig(stop); } Xsigsetmask(omask); if (pid < (p_id_t)0) return(pid); # ifndef NOJOB if (childpgrp < (p_id_t)0) childpgrp = (ppid >= (p_id_t)0) ? ppid : (pid) ? pid : mypid; if (pid) { if (jobok) VOID_C setpgroup(pid, childpgrp); if (tty && ttypgrp >= (p_id_t)0) ttypgrp = childpgrp; # if defined (DEP_PTY) && defined (CYGWIN) if (parentfd >= 0) addmychild(pid); # endif } else { if (jobok && setpgroup(mypid, childpgrp) < 0) { doperror(NULL, "fatal error"); prepareexit(-1); Xexit(RET_FATALERR); } if (tty) VOID_C gettermio(childpgrp, jobok); # if defined (DEP_PTY) && defined (CYGWIN) Xfree(mychildren); mychildren = NULL; # endif } # endif /* !NOJOB */ if (!pid) for (i = 0; shellfunc[i].ident; i++) nownstree(shellfunc[i].func); return(pid); } int waitchild(pid, trp) p_id_t pid; syntaxtree *trp; { # ifndef NOJOB int n; # endif wait_pid_t w; int ret; if (trapok >= 0) trapok = 1; sigconted = 0; for (;;) { if (interrupted) { if (trapok >= 0) trapok = 0; # ifdef FD checkscreen(-1, -1); # endif return(RET_INTR); } if ((ret = waitjob(pid, &w, WUNTRACED)) < 0) break; if (!ret) continue; if (!WIFSTOPPED(w)) break; ret = WSTOPSIG(w); if (sigconted) { sigconted = 0; # ifdef SIGSTOP if (ret == SIGSTOP) continue; # endif } # ifdef NOJOB # ifdef SIGCONT if (loginshell) VOID_C kill(pid, SIGCONT); # endif # else /* !NOJOB */ # ifdef BASHBUG /* bash cannot be suspended with +m mode */ if (!jobok) continue; # endif if (mypid != orgpgrp) continue; if (trapok >= 0) trapok = 0; VOID_C gettermio(orgpgrp, jobok); # ifdef FD checkscreen(-1, -1); # endif prevjob = lastjob; lastjob = stackjob(pid, ret, -1, trp); breaklevel = loopdepth; stopped = 1; if (!jobok) return(RET_SUCCESS); Xfree(joblist[lastjob].tty); savetermio(ttyio, &(joblist[lastjob].tty), NULL); if (interactive && !nottyout) { stdiomode(); dispjob(lastjob, Xstderr); } return(RET_SUCCESS); # endif /* !NOJOB */ } if (trapok >= 0) trapok = 0; # ifndef NOJOB if (childpgrp >= (p_id_t)0 && pid != childpgrp) /*EMPTY*/; else if (mypid == orgpgrp) { VOID_C gettermio(orgpgrp, jobok); # ifdef FD checkscreen(-1, -1); # endif childpgrp = (p_id_t)-1; } # endif /* !NOJOB */ if (ret < 0) { if (!trp && errno == ECHILD) ret = errno = 0; } else if (WIFSIGNALED(w)) { ret = WTERMSIG(w); # ifndef NOJOB if ((n = searchjob(pid, NULL)) >= 0) Xkillpg(joblist[n].pids[0], ret); # endif # ifdef SIGINT if (ret == SIGINT) interrupted = 1; else # endif # if defined (SIGPIPE) && !defined (PSIGNALSTYLE) if (ret == SIGPIPE) /*EMPTY*/; else # endif if (!nottyout) { if (!interactive && argvar && argvar[0]) VOID_C Xfprintf(Xstderr, "%k: %id ", argvar[0], pid); dispsignal(ret, 0, Xstderr); VOID_C fputnl(Xstderr); } ret += 128; } else ret = (WEXITSTATUS(w) & 0377); if (ret < 0) return(-1); # ifndef NOJOB if ((n = searchjob(pid, NULL)) >= 0 && statjob(n) < 0) freejob(n); # endif return((int)ret); } #endif /* !MSDOS */ static VOID NEAR safermtmpfile(file) CONST char *file; { int duperrno; duperrno = errno; rmtmpfile(file); errno = duperrno; } VOID setshflag(n, val) int n, val; { #if defined (FD) && !defined (_NOEDITMODE) CONST char *cp; #endif *(shflaglist[n].var) = val; #if defined (FD) && !defined (_NOEDITMODE) if (shflaglist[n].var == &emacsmode) cp = "emacs"; else if (shflaglist[n].var == &vimode) cp = "vi"; else cp = NULL; if (cp) { emacsmode = vimode = 0; if (editmode && !strcmp(editmode, cp)) cp = NULL; /* * The stupid HP cc says that * ternary operator with NULL is const char *, * not to be converted to char *. */ if (!val) cp = (cp) ? NULL : nullstr; if (cp) { setenv2("FD_EDITMODE", cp, 0); editmode = getconstvar("FD_EDITMODE"); } } #endif /* FD && !_NOEDITMODE */ #ifdef DEP_PTY sendparent(TE_SETSHFLAG, n, val); #endif } static int NEAR getoption(argc, argv, isopt) int argc; char *CONST *argv; int isopt; { u_long flags; CONST char *arg; int i, j, com; #if defined (FD) && !defined (_NOEDITMODE) emacsmode = vimode = 0; if (editmode) { if (!strcmp(editmode, "emacs")) emacsmode = 1; else if (!strcmp(editmode, "vi")) vimode = 1; } #endif if (argc <= 1) return(1); arg = argv[1]; if (arg[0] != '-' && arg[0] != '+') return(1); else if (arg[1] == '-') return(2); com = 0; flags = (u_long)0; for (i = 1; arg[i]; i++) { if (isopt) { #ifdef FD if (fdmode) /*EMPTY*/; else #endif if (arg[i] == 'c' && !com && argc > 2) { com = 1; continue; } } else { if (arg[i] == 'o' && !com) { com = (arg[0] == '-') ? 1 : 2; continue; } } for (j = 0; j < FLAGSSIZ; j++) { if (!isopt && !(shflaglist[j].ident)) continue; if (arg[i] == shflaglist[j].letter) break; } if (j < FLAGSSIZ) flags |= ((u_long)1 << j); else if (arg[0] == '-') { execerror(argv, arg, ER_BADOPTIONS, 0); return(-1); } } for (j = 0; j < FLAGSSIZ; j++) { if (flags & (u_long)1) setshflag(j, (arg[0] == '-') ? 1 : 0); flags >>= 1; } return(com + 2); } static ALLOC_T NEAR c_allocsize(n) int n; { ALLOC_T size; n++; for (size = BUFUNIT; size < n; size *= 2) /*EMPTY*/; return(size); } static int NEAR readchar(fd) int fd; { u_char ch; int n; if (trapok >= 0) trapok = 1; #ifdef USESIGACTION n = sureread(fd, &ch, sizeof(ch)); #else n = checkread(fd, &ch, sizeof(ch), 0); #endif if (n > 0) n = (int)ch; else if (!n) n = READ_EOF; if (trapok >= 0) trapok = 0; return(n); } /*ARGSUSED*/ static char *NEAR readline(fd, opt) int fd, opt; { char *cp; ALLOC_T i, size; int c; cp = c_realloc(NULL, 0, &size); for (i = 0; (c = readchar(fd)) != '\n'; i++) { if (c < 0) { Xfree(cp); return(NULL); } if (c == READ_EOF) { if (i) break; Xfree(cp); return(vnullstr); } cp = c_realloc(cp, i, &size); cp[i] = c; } #ifndef USECRNL if (opt != 'N') /*EMPTY*/; else #endif if (c == '\n' && i > 0 && cp[i - 1] == '\r') i--; cp[i++] = '\0'; return(Xrealloc(cp, i)); } static char *NEAR readfile(fd, lenp) int fd; ALLOC_T *lenp; { char *cp; ALLOC_T i, size; int c; cp = c_realloc(NULL, 0, &size); for (i = 0; (c = readchar(fd)) != READ_EOF; i++) { if (c < 0) { Xfree(cp); return(NULL); } #ifdef USECRNL if (c == '\n' && i > 0 && cp[i - 1] == '\r') i--; #endif cp = c_realloc(cp, i, &size); cp[i] = c; } if (lenp) *lenp = i; cp[i++] = '\0'; return(Xrealloc(cp, i)); } char *evalvararg(arg, flags, noexit) char *arg; int flags, noexit; { char *tmp; if ((tmp = evalarg(arg, flags))) return(tmp); #if defined (BASHSTYLE) && defined (STRICTPOSIX) if (!noexit) noexit = -1; #endif if (*arg) execerror(NULL, arg, ER_BADSUBST, noexit); return(NULL); } static heredoc_t *NEAR newheredoc(eof, path, fd, flags) char *eof, *path; int fd, flags; { heredoc_t *new; new = (heredoc_t *)Xmalloc(sizeof(heredoc_t)); new -> eof = eof; new -> filename = path; new -> buf = NULL; new -> fd = fd; #ifndef USEFAKEPIPE new -> pipein = (p_id_t)-1; #endif new -> flags = flags; return(new); } VOID freeheredoc(hdp, nown) heredoc_t *hdp; int nown; { if (!hdp) return; Xfree(hdp -> eof); safeclose(hdp -> fd); if (hdp -> filename) { if (!nown) safermtmpfile(hdp -> filename); Xfree(hdp -> filename); } Xfree(hdp -> buf); Xfree(hdp); } static redirectlist *NEAR newrlist(fd, filename, type, next) int fd; char *filename; int type; redirectlist *next; { redirectlist *new; new = (redirectlist *)Xmalloc(sizeof(redirectlist)); new -> fd = fd; new -> filename = filename; new -> type = (u_short)type; new -> new = new -> old = -1; #ifdef DEP_DOSDRIVE new -> fakepipe = NULL; new -> dosfd = -1; #endif new -> next = next; return(new); } VOID freerlist(rp, nown) redirectlist *rp; int nown; { if (!rp) return; freerlist(rp -> next, nown); if (rp -> type & MD_HEREDOC) freeheredoc((heredoc_t *)(rp -> filename), nown); else Xfree(rp -> filename); Xfree(rp); } static command_t *NEAR newcomm() { command_t *new; new = (command_t *)Xmalloc(sizeof(command_t)); new -> hash = NULL; new -> argc = -1; new -> argv = NULL; new -> redp = NULL; new -> type = new -> id = 0; return(new); } VOID freecomm(comm, nown) command_t *comm; int nown; { int i; if (!comm) return; if (comm -> argv) { if (isstatement(comm)) freestree((syntaxtree *)(comm -> argv)); else for (i = 0; i <= comm -> argc; i++) Xfree(comm -> argv[i]); Xfree(comm -> argv); } if (comm -> redp) { closeredirect(comm -> redp); freerlist(comm -> redp, nown); } Xfree(comm); } syntaxtree *newstree(parent) syntaxtree *parent; { syntaxtree *new; new = (syntaxtree *)Xmalloc(sizeof(syntaxtree)); new -> comm = NULL; new -> parent = parent; new -> next = NULL; #ifndef MINIMUMSHELL new -> lineno = shlineno; #endif new -> type = OP_NONE; if (parent) { new -> cont = (parent -> cont & CN_INHR); new -> flags = 0; } else { new -> cont = 0; new -> flags = ST_TOP; } return(new); } VOID freestree(trp) syntaxtree *trp; { #ifndef MINIMUMSHELL redirectlist *rp; #endif int duperrno; if (!trp) return; duperrno = errno; if (trp -> comm) { if (!(trp -> flags & ST_NODE)) freecomm(trp -> comm, trp -> flags & ST_NOWN); else { freestree((syntaxtree *)(trp -> comm)); Xfree(trp -> comm); } trp -> comm = NULL; } if (trp -> next) { #ifndef MINIMUMSHELL if (trp -> flags & ST_BUSY) { rp = (redirectlist *)(trp -> next); Xfree(rp -> filename); freestree((syntaxtree *)(rp -> next)); Xfree(rp -> next); } else #endif if (!(trp -> cont & (CN_QUOT | CN_ESCAPE))) freestree(trp -> next); else Xfree(((redirectlist *)(trp -> next)) -> filename); Xfree(trp -> next); trp -> next = NULL; } trp -> type = OP_NONE; trp -> cont = trp -> flags = 0; errno = duperrno; } static syntaxtree *NEAR eldeststree(trp) syntaxtree *trp; { syntaxtree *tmptr; while (trp) { tmptr = getparent(trp); if (!(trp -> flags & ST_NEXT)) return(tmptr); trp = tmptr; } return(NULL); } syntaxtree *parentstree(trp) syntaxtree *trp; { while ((trp = eldeststree(trp))) if (!(trp -> flags & ST_NODE) && isstatement(trp -> comm)) return(trp); return(NULL); } static syntaxtree *NEAR childstree(trp, n) syntaxtree *trp; int n; { syntaxtree *new; new = newstree(trp); if (!(trp -> comm)) trp -> comm = newcomm(); (trp -> comm) -> argc = 0; (trp -> comm) -> argv = (char **)new; (trp -> comm) -> type = CT_STATEMENT; (trp -> comm) -> id = n; trp -> type = OP_NONE; trp -> flags &= ~ST_NODE; return(new); } static syntaxtree *NEAR skipfuncbody(trp) syntaxtree *trp; { syntaxtree *tmptr; if (trp -> flags & ST_BUSY) return(trp); tmptr = statementcheck(trp -> next, SM_STATEMENT); if (getstatid(tmptr) == SM_LPAREN - 1) trp = trp -> next; return(trp); } static syntaxtree *NEAR insertstree(trp, parent, type) syntaxtree *trp, *parent; int type; { syntaxtree *new, *tmptr; int i, l1, l2; for (i = 0; i < OPELISTSIZ; i++) if (type == opelist[i].op) break; l1 = (i < OPELISTSIZ) ? opelist[i].level : 0; if (!parent) l2 = 0; else { for (i = 0; i < OPELISTSIZ; i++) if (parent -> type == opelist[i].op) break; l2 = (i < OPELISTSIZ) ? opelist[i].level : 0; } if (!l1) /*EMPTY*/; #ifndef BASHSTYLE /* bash does not allow the format like as "foo | ; bar" */ else if (parent && isoppipe(parent) && l1 > l2) /*EMPTY*/; #endif #ifndef MINIMUMSHELL else if (type == OP_NOT && (!l2 || l1 < l2)) /*EMPTY*/; #endif else if (!hascomm(trp)) { if (type != OP_FG) { syntaxerrno = ER_UNEXPTOK; return(trp); } #ifdef BASHSTYLE /* bash does not allow a null before ";" */ else { syntaxerrno = ER_UNEXPNL; return(trp); } #endif } /* && or || */ if (l1 == 3 && l2 == 3) l2--; if (!l1 || !l2) /*EMPTY*/; else if (l1 < l2) { new = newstree(trp); new -> comm = trp -> comm; new -> next = trp -> next; #ifndef MINIMUMSHELL new -> lineno = trp -> lineno; #endif new -> type = trp -> type; new -> cont = trp -> cont; if (trp -> flags & ST_NODE) { new -> flags = trp -> flags; trp -> flags = 0; } trp -> comm = (command_t *)new; trp -> type = OP_NONE; trp -> flags |= ST_NODE; trp = new; } else if (l1 > l2) { if (!(tmptr = eldeststree(parent))) { while (hasparent(trp)) trp = trp -> parent; new = newstree(trp); new -> comm = trp -> comm; new -> next = trp -> next; #ifndef MINIMUMSHELL new -> lineno = trp -> lineno; #endif new -> type = trp -> type; new -> cont = trp -> cont; new -> flags = trp -> flags; if (trp -> next) (trp -> next) -> parent = new; trp -> comm = (command_t *)new; trp -> type = type; trp -> cont = 0; trp -> flags = ST_NODE; } else if (tmptr -> flags & ST_NODE) trp = insertstree(tmptr, eldeststree(tmptr), type); else if (!isstatement(tmptr -> comm)) trp = insertstree(trp, tmptr, type); else { new = newstree(tmptr); new -> comm = (command_t *)((tmptr -> comm) -> argv); new -> next = trp -> next; (tmptr -> comm) -> argv = (char **)new; trp = new; trp -> type = type; trp -> cont = 0; trp -> flags = ST_NODE; } } return(trp); } static syntaxtree *NEAR linkstree(trp, type) syntaxtree *trp; int type; { syntaxtree *new, *tmptr; int cont; cont = ((trp -> cont) & CN_INHR); #ifndef MINIMUMSHELL trp -> lineno = shlineno; #endif if (trp && isstatement(trp -> comm) && (trp -> comm) -> id == SM_STATEMENT && (tmptr = statementbody(trp)) && getstatid(tmptr) == SM_LPAREN - 1) trp = getparent(trp); tmptr = (trp -> flags & ST_NEXT) ? getparent(trp) : NULL; trp = insertstree(trp, tmptr, type); trp = skipfuncbody(trp); new = trp -> next = newstree(trp); new -> cont = cont; new -> flags = ST_NEXT; trp -> type = type; return(new); } #if !MSDOS || defined (DEP_PTY) || !defined (USEFAKEPIPE) static VOID NEAR nownstree(trp) syntaxtree *trp; { if (!trp) return; if (!(trp -> comm)) /*EMPTY*/; else if (trp -> flags & ST_NODE) nownstree((syntaxtree *)(trp -> comm)); else if (isstatement(trp -> comm)) nownstree(statementbody(trp)); trp -> flags |= ST_NOWN; nownstree(trp -> next); } #endif static int NEAR evalfiledesc(s) CONST char *s; { int i, n; i = 0; if ((n = getnum(s, &i)) < 0) return(-1); i = Xgetdtablesize(); if (n > i) n = i; return(n); } static int NEAR redmode(type) int type; { int mode; mode = O_TEXT; if (type & MD_READ) { if (type & MD_WRITE) { mode |= (O_RDWR | O_CREAT); #ifndef MINIMUMSHELL if (noclobber && !(type & MD_FORCED)) mode |= O_EXCL; #endif } else mode |= O_RDONLY; if (type & MD_APPEND) mode |= O_APPEND; } else { mode |= (O_WRONLY | O_CREAT); if (type & MD_APPEND) mode |= O_APPEND; else { mode |= O_TRUNC; #ifndef MINIMUMSHELL if (noclobber && !(type & MD_FORCED)) mode |= O_EXCL; #endif } } return(mode); } static int NEAR cancelredirect(rp) redirectlist *rp; { if (!rp) return(0); #ifdef DEP_DOSDRIVE if (rp -> fakepipe) { errno = EBADF; doperror(NULL, rp -> filename); return(-1); } #endif if (cancelredirect(rp -> next) < 0) return(-1); if ((rp -> type & MD_WITHERR) && rp -> fd != STDOUT_FILENO) { safeclose(rp -> fd); rp -> fd = STDOUT_FILENO; } if (rp -> old >= 0) safeclose(rp -> old); if (rp -> new >= 0) { if (rp -> type & MD_HEREDOC) VOID_C closepipe2(rp -> new, rp -> fd); else if (!(rp -> type & MD_FILEDESC)) safeclose(rp -> new); } #ifdef DEP_DOSDRIVE VOID_C closepseudofd(rp); #endif rp -> old = rp -> new = -1; return(0); } static VOID NEAR closeredirect(rp) redirectlist *rp; { #ifndef USEFAKEPIPE heredoc_t *hdp; #endif if (!rp) return; closeredirect(rp -> next); if (rp -> type & MD_DUPL) return; if ((rp -> type & MD_WITHERR) && rp -> fd != STDOUT_FILENO) { if (rp -> fd != STDERR_FILENO) { Xdup2(rp -> fd, STDERR_FILENO); safeclose(rp -> fd); } rp -> fd = STDOUT_FILENO; } if (rp -> old >= 0) { Xdup2(rp -> old, rp -> fd); safeclose(rp -> old); } if (rp -> new >= 0) { if (rp -> type & MD_HEREDOC) { #ifndef USEFAKEPIPE hdp = (heredoc_t *)(rp -> filename); if (hdp -> pipein >= (p_id_t)0) VOID_C waitchild(hdp -> pipein, NULL); #endif VOID_C closepipe2(rp -> new, -1); } else if (!(rp -> type & MD_FILEDESC)) safeclose(rp -> new); } #ifdef DEP_DOSDRIVE VOID_C closepseudofd(rp); #endif rp -> old = rp -> new = -1; } static heredoc_t *NEAR searchheredoc(trp, rm) syntaxtree *trp; int rm; { redirectlist *rp; heredoc_t *hdp, *hit; if (!trp) return(NULL); if (rm && (trp -> flags & ST_NOWN)) return(NULL); if (!(trp -> comm)) /*EMPTY*/; else if (trp -> flags & ST_NODE) { if ((hdp = searchheredoc((syntaxtree *)(trp -> comm), rm))) return(hdp); } else { if (isstatement(trp -> comm)) { if ((hdp = searchheredoc(statementbody(trp), rm))) return(hdp); } hit = NULL; if (!rm && !(trp -> cont & CN_HDOC)) /*EMPTY*/; else for (rp = (trp -> comm) -> redp; rp; rp = rp -> next) { if (!(rp -> type & MD_HEREDOC)) continue; if (!(hdp = (heredoc_t *)(rp -> filename))) continue; if (!rm) { if (hdp -> fd >= 0) hit = hdp; } else if (hdp -> filename) { safermtmpfile(hdp -> filename); Xfree(hdp -> filename); hdp -> filename = NULL; } } if (hit) return(hit); } if ((hdp = searchheredoc(trp -> next, rm))) return(hdp); if (!rm) trp -> cont &= ~CN_HDOC; return(NULL); } static int NEAR saveheredoc(s, trp) CONST char *s; syntaxtree *trp; { heredoc_t *hdp; char *cp; int i, len, ret; while (hasparent(trp)) trp = trp -> parent; if (!(hdp = searchheredoc(trp, 0))) return(0); cp = hdp -> buf; hdp -> buf = NULL; if (!cp) cp = Xstrdup(s); else { len = strlen(cp); if (s) { cp = Xrealloc(cp, len + strlen(s) + 1); Xstrcpy(&(cp[len]), s); } } if (cp) { if (!(hdp -> flags & HD_QUOTED)) { for (i = 0; cp[i]; i++) { if (cp[i] == PESCAPE) { if (!cp[i + 1]) break; i++; } else if (iswchar(cp, i)) i++; } if (cp[i]) { cp[i] = '\0'; if (s) { hdp -> buf = cp; return(1); } } } i = 0; if (hdp -> flags & HD_IGNORETAB) while (cp[i] == '\t') i++; if (!strcmp(&(cp[i]), hdp -> eof)) { Xfree(cp); s = cp = NULL; } } #ifdef FAKEUNINIT else i = 0; /* fake for -Wuninitialized */ #endif ret = 1; if (cp) { #ifdef FD demacroarg(&cp); #endif len = strlen(cp); cp[len++] = '\n'; len -= i; if (surewrite(hdp -> fd, &(cp[i]), len) < 0) ret = -1; Xfree(cp); } if (!s) { safeclose(hdp -> fd); hdp -> fd = -1; searchheredoc(trp, 0); } return(ret); } static int NEAR openheredoc(hdp, old) heredoc_t *hdp; int old; { char *cp, *buf; p_id_t pipein; int fd, fdin, ret; fdin = newdup(Xopen(hdp -> filename, O_BINARY | O_RDONLY, 0666)); if (fdin < 0) return(-1); if ((fd = openpipe2(&pipein, old, 1, interactive_io, mypid)) < 0) { safeclose(fdin); return(-1); } #ifdef DJGPP setmode(STDOUT_FILENO, O_TEXT); #endif if (pipein > (p_id_t)0) { #ifndef USEFAKEPIPE hdp -> pipein = pipein; #endif safeclose(fdin); return(fd); } ret = RET_SUCCESS; while ((buf = readline(fdin, '\0')) != vnullstr) { if (!buf) { VOID_C closepipe2(fd, -1); safeclose(fdin); return(-1); } if (!(hdp -> flags & HD_QUOTED) && ret == RET_SUCCESS) { cp = evalvararg(buf, EA_STRIPESCAPE | EA_NOEVALQ | EA_NOEVALDQ | EA_BACKQ, 1); if (!cp) ret = RET_FAIL; Xfree(buf); buf = cp; } if (ret == RET_SUCCESS) { Xfputs(buf, Xstdout); VOID_C fputnl(Xstdout); } Xfree(buf); } safeclose(fdin); Xfflush(Xstdout); if ((fd = reopenpipe(fd, ret)) < 0) return(-1); if (ret != RET_SUCCESS) { VOID_C closepipe2(fd, -1); return(seterrno(-1)); } return(fd); } #ifdef DEP_DOSDRIVE static int NEAR fdcopy(fdin, fdout) int fdin, fdout; { u_char ch; int n; for (;;) { if ((n = sureread(fdin, &ch, sizeof(ch))) <= 0) break; if (surewrite(fdout, &ch, sizeof(ch)) < 0) return(-1); } return(n); } static int NEAR openpseudofd(rp) redirectlist *rp; { # ifndef USEFAKEPIPE p_id_t pid; int fds[2]; # endif char pfile[MAXPATHLEN]; int fd; if (!(rp -> type & MD_RDWR) || (rp -> type & MD_RDWR) == MD_RDWR) return(-1); # ifndef USEFAKEPIPE if (pipe(fds) < 0) /*EMPTY*/; else if ((pid = makechild(0, mypid)) < (p_id_t)0) { safeclose(fds[0]); safeclose(fds[1]); return(-1); } else if (pid) { safeclose(rp -> new); if (rp -> type & MD_READ) { safeclose(fds[1]); rp -> new = newdup(fds[0]); } else { safeclose(fds[0]); rp -> new = newdup(fds[1]); } return(0); } else { if (rp -> type & MD_READ) { safeclose(fds[0]); fds[1] = newdup(fds[1]); fdcopy(rp -> new, fds[1]); safeclose(rp -> new); safeclose(fds[1]); } else { safeclose(fds[1]); fds[0] = newdup(fds[0]); fdcopy(fds[0], rp -> new); safeclose(rp -> new); safeclose(fds[0]); } prepareexit(1); Xexit(RET_SUCCESS); } # endif /* !USEFAKEPIPE */ if ((fd = newdup(mktmpfile(pfile))) < 0) return(-1); if (rp -> type & MD_WRITE) rp -> dosfd = rp -> new; else { fdcopy(rp -> new, fd); safeclose(rp -> new); safeclose(fd); fd = newdup(Xopen(pfile, O_BINARY | O_RDONLY, 0666)); if (fd < 0) { safermtmpfile(pfile); rp -> fakepipe = NULL; return(-1); } } rp -> new = fd; rp -> fakepipe = Xstrdup(pfile); return(0); } static int NEAR closepseudofd(rp) redirectlist *rp; { int fd; if (!(rp -> fakepipe)) return(0); if (rp -> dosfd >= 0 && rp -> type & MD_WRITE) { fd = Xopen(rp -> fakepipe, O_BINARY | O_RDONLY, 0666); if (fd >= 0) { fdcopy(fd, rp -> dosfd); safeclose(fd); } safeclose(rp -> dosfd); } safermtmpfile(rp -> fakepipe); Xfree(rp -> fakepipe); rp -> fakepipe = NULL; rp -> dosfd = -1; return(0); } #endif /* DEP_DOSDRIVE */ #ifdef WITHSOCKREDIR static int NEAR parsesocket(s, addrp, portp) CONST char *s; char **addrp; int *portp; { urlhost_t host; char *cp; int n, scheme; if ((n = urlparse(s, schemelist, &cp, &scheme, 0)) <= 0) return(0); if (s[n] == '/') n++; if (s[n]) { Xfree(cp); return(0); } n = urlgethost(cp, &host); Xfree(cp); if (n < 0) return(-1); if (host.user || host.pass) n = -1; switch (scheme) { case TYPE_CONNECT: if (!(host.host)) n = -1; if (host.port < 0) n = -1; break; case TYPE_ACCEPT: case TYPE_BIND: if (host.port < 0) host.port = 0; break; default: n = -1; break; } if (n < 0) { urlfreehost(&host); return(seterrno(EINVAL)); } *addrp = host.host; *portp = host.port; return(scheme); } #endif /* WITHSOCKREDIR */ static redirectlist *NEAR doredirect(rp) redirectlist *rp; { #ifdef WITHSOCKREDIR char *addr; int s, port, scheme, opt; #endif redirectlist *errp; char *tmp; int n, type; #ifdef FD rp -> type &= ~MD_REST; #endif if (rp -> next) { if ((errp = doredirect(rp -> next))) return(errp); #ifdef FD if (((rp -> next) -> type) & MD_REST) rp -> type |= MD_REST; #endif } type = rp -> type; if (!(rp -> filename)) tmp = NULL; else if (type & MD_HEREDOC) tmp = rp -> filename; else { tmp = evalvararg(rp -> filename, EA_BACKQ | EA_STRIPQLATER, 0); if (!tmp) { errno = -1; return(rp); } else if ((type & MD_FILEDESC) && tmp[0] == '-' && !tmp[1]) { Xfree(tmp); tmp = NULL; type &= ~MD_FILEDESC; } #ifdef FD else if ((n = replacearg(&tmp)) < 0) { Xfree(tmp); return(rp); } else if (n) rp -> type |= MD_REST; #endif } if (!tmp) /*EMPTY*/; else if (type & MD_HEREDOC) { if ((rp -> new = openheredoc((heredoc_t *)tmp, rp -> fd)) < 0) return(rp); } else if (type & MD_FILEDESC) { rp -> new = evalfiledesc(tmp); Xfree(tmp); if (rp -> new < 0) { errno = EBADF; return(rp); } if (isvalidfd(rp -> new) < 0) { rp -> new = -1; #ifdef BASHSTYLE /* bash treats ineffective descriptor as error */ errno = EBADF; return(rp); #else rp -> old = -1; rp -> type = 0; return(NULL); #endif } } else if (restricted && (type & MD_WRITE)) { Xfree(tmp); errno = 0; return(rp); } else { #ifdef WITHSOCKREDIR # ifdef FAKEUNINIT addr = NULL; port = -1; # endif if ((scheme = parsesocket(tmp, &addr, &port))) { if (scheme < 0) return(rp); opt = SCK_LOWDELAY; switch (scheme) { case TYPE_CONNECT: s = sockconnect(addr, port, 0, opt); break; case TYPE_ACCEPT: s = sockbind(addr, port, opt | SCK_REUSEADDR); if (s >= 0) s = sockaccept(s, opt); break; case TYPE_BIND: s = sockbind(addr, port, opt); break; default: s = seterrno(EINVAL); break; } rp -> new = s; Xfree(addr); } else #endif /* WITHSOCKREDIR */ rp -> new = Kopen(tmp, redmode(type), 0666); rp -> new = newdup(rp -> new); Xfree(tmp); if (rp -> new < 0) return(rp); #if MSDOS && !defined (LSI_C) # ifdef DJGPP if (isatty(rp -> new)) /*EMPTY*/; else # endif setmode(rp -> new, O_BINARY); #endif /* MSDOS && !LSI_C */ } #if !MSDOS if (rp -> new != STDIN_FILENO && rp -> new != STDOUT_FILENO && rp -> new != STDERR_FILENO) closeonexec(rp -> new); #endif if (isvalidfd(rp -> fd) < 0) rp -> old = -1; else if ((rp -> old = newdup(Xdup(rp -> fd))) < 0) return(rp); #if !MSDOS else if (rp -> old != STDIN_FILENO && rp -> old != STDOUT_FILENO && rp -> old != STDERR_FILENO) closeonexec(rp -> old); #endif if (rp -> new != rp -> fd) { if (rp -> new < 0) VOID_C Xclose(rp -> fd); else { #ifdef DEP_DOSDRIVE if (chkopenfd(rp -> new) == DEV_DOS) openpseudofd(rp); #endif if (Xdup2(rp -> new, rp -> fd) < 0) return(rp); } } if ((type & MD_WITHERR) && rp -> new != STDERR_FILENO && rp -> fd == STDOUT_FILENO) { if ((n = newdup(Xdup(STDERR_FILENO))) < 0 || Xdup2(rp -> new, STDERR_FILENO) < 0) { safeclose(n); return(rp); } rp -> fd = n; #if !MSDOS if (rp -> fd != STDIN_FILENO && rp -> fd != STDOUT_FILENO && rp -> fd != STDERR_FILENO) closeonexec(rp -> fd); #endif } return(NULL); } static heredoc_t *NEAR heredoc(eof, ignoretab) char *eof; int ignoretab; { char *cp, path[MAXPATHLEN]; int fd, flags; flags = (ignoretab) ? HD_IGNORETAB : 0; cp = Xstrdup(eof); if (stripquote(cp, EA_STRIPQ)) flags |= HD_QUOTED; #ifndef BASHSTYLE /* bash allows no variables as the EOF identifier */ Xfree(cp); if (!(cp = evalvararg(eof, EA_STRIPQLATER, 0))) { errno = -1; return(NULL); } #endif #ifdef FD demacroarg(&cp); #endif if ((fd = newdup(mktmpfile(path))) < 0) { Xfree(cp); return(NULL); } return(newheredoc(cp, Xstrdup(path), fd, flags)); } static int NEAR redirect(trp, from, to, type) syntaxtree *trp; int from; char *to; int type; { redirectlist *rp; char *cp; if (to && !*to) { syntaxerrno = ER_UNEXPTOK; return(-1); } if (!(type & MD_HEREDOC)) cp = Xstrdup(to); else { if (!(cp = (char *)heredoc(to, type & MD_APPEND))) { doperror(NULL, deftmpdir); return(-1); } trp -> cont |= CN_HDOC; } if (from < 0) from = (type & MD_READ) ? STDIN_FILENO : STDOUT_FILENO; if (!(trp -> comm)) trp -> comm = newcomm(); rp = newrlist(from, cp, type, (trp -> comm) -> redp); (trp -> comm) -> redp = rp; return(0); } #if !MSDOS /*ARGSUSED*/ VOID cmpmail(path, msg, mtimep) CONST char *path, *msg; time_t *mtimep; { struct stat st; if (!path || Xstat(path, &st) < 0) return; if (st.st_size > 0 && *mtimep && st.st_mtime > *mtimep) { # ifdef MINIMUMSHELL Xfputs("you have mail", Xstderr); # else kanjifputs((msg) ? msg : "you have mail", Xstderr); # endif VOID_C fputnl(Xstderr); } *mtimep = st.st_mtime; } # ifdef MINIMUMSHELL static VOID NEAR checkmail(reset) int reset; { static time_t mtime = 0; if (reset) mtime = 0; else cmpmail(getconstvar(ENVMAIL), NULL, &mtime); } # endif /* !MINIMUMSHELL */ #endif /* !MSDOS */ int identcheck(ident, delim) CONST char *ident; int delim; { int i; if (!ident || !*ident || !isidentchar(*ident)) return(0); for (i = 1; ident[i]; i++) if (!isidentchar2(ident[i])) break; return((ident[i] == delim) ? i : ((ident[i]) ? 0 : -i)); } static int NEAR searchvar(var, ident, len, c) char *CONST *var; CONST char *ident; int len, c; { int i; if (!var) return(-1); for (i = 0; var[i]; i++) if (!strnenvcmp(ident, var[i], len) && var[i][len] == c) return(i); return(-1); } static char *NEAR searchvar2(max, var, ident, len) int max; CONST char **var, *ident; int len; { int i; if (!var) return(NULL); for (i = 0; i < max; i++) { if (!var[i]) continue; if (!strnenvcmp(ident, var[i], len) && !var[i][len]) return((char *)var[i]); #ifdef FD if (!strnenvcmp(var[i], FDENV, FDESIZ) && !strnenvcmp(ident, &(var[i][FDESIZ]), len) && !var[i][FDESIZ + len]) return((char *)&(var[i][FDESIZ])); #endif } return(NULL); } static char **NEAR expandvar(var, ident, len) char **var; CONST char *ident; int len; { int i; if (searchvar(var, ident, len, '\0') >= 0) return(var); i = countvar(var); var = (char **)Xrealloc(var, (i + 2) * sizeof(char *)); var[i] = Xstrndup(ident, len); var[++i] = NULL; return(var); } static char *NEAR getvar(var, ident, len) char *CONST *var; CONST char *ident; int len; { int i; if (len < 0) len = strlen(ident); if ((i = searchvar(var, ident, len, '=')) < 0) return(NULL); return(&(var[i][len + 1])); } char *getshellvar(ident, len) CONST char *ident; int len; { return(getvar(shellvar, ident, len)); } static char **NEAR putvar(var, s, len) char **var, *s; int len; { #if MSDOS char *cp; #endif u_long size; int i, export; export = (var == exportvar); i = searchvar(var, s, len, '='); if (i >= 0) { if (export) { size = (u_long)strlen(var[i]) + 1; if (size >= exportsize) exportsize = (u_long)0; else exportsize -= size; } Xfree(var[i]); if (!s[len]) { for (; var[i + 1]; i++) var[i] = var[i + 1]; var[i] = NULL; return(var); } } else if (!s[len]) return(var); else { i = countvar(var); var = (char **)Xrealloc(var, (i + 2) * sizeof(char *)); var[i + 1] = NULL; } var[i] = s; #ifdef ENVNOCASE Xstrntoupper(s, len); #endif if (export) { exportsize += (u_long)strlen(s) + 1; #if MSDOS if (constequal(s, ENVPATH, len)) { cp = &(s[len + 1]); if (_dospath(cp)) cp += 2; for (; *cp; cp++) { if (*cp == PATHDELIM) { *cp = ';'; if (_dospath(cp + 1)) cp += 2; } # ifndef BSPATHDELIM else if (*cp == _SC_) *cp = '\\'; # endif } } #endif /* MSDOS */ } return(var); } static int NEAR checkprimal(s, len) CONST char *s; int len; { char *cp; if ((cp = searchvar2(PRIMALVARSIZ, primalvar, s, len))) { execerror(NULL, cp, ER_CANNOTUNSET, 0); return(seterrno(EPERM)); } return(0); } static int NEAR checkrestrict(s, len) CONST char *s; int len; { char *cp; if (!restricted) return(0); if ((cp = searchvar2(RESTRICTVARSIZ, restrictvar, s, len))) { execerror(NULL, cp, ER_RESTRICTED, 0); return(seterrno(EPERM)); } return(0); } static int NEAR checkronly(s, len) CONST char *s; int len; { int i; if ((i = searchvar(ronlylist, s, len, '\0')) >= 0) { execerror(NULL, ronlylist[i], ER_ISREADONLY, 0); return(seterrno(EACCES)); } return(0); } static int NEAR _putshellvar(s, len) char *s; int len; { #if !MSDOS && defined (FD) keyseq_t *keymap; CONST char *term; #endif #if (!MSDOS && (!defined (MINIMUMSHELL) || defined (FD))) \ || !defined (NOPOSIXUTIL) \ || !defined (FD) \ && (defined (DEP_URLPATH) || defined (DEP_FTPPATH) || defined (DEP_HTTPPATH)) CONST char *cp; #endif #if (!MSDOS && (!defined (MINIMUMSHELL) || defined (FD))) \ || !defined (NOPOSIXUTIL) \ || !defined (FD) \ && (defined (DEP_URLPATH) || defined (DEP_FTPPATH) || defined (DEP_HTTPPATH)) cp = &(s[len + 1]); #endif if (checkrestrict(s, len) < 0) return(-1); #ifdef BASHSTYLE /* bash distinguishes the same named function and variable */ else if (checkronly(s, len) < 0) return(-1); #else else if (unsetshfunc(s, len) < 0) return(-1); #endif #ifndef _NOUSEHASH else if (constequal(s, ENVPATH, len)) VOID_C searchhash(NULL, NULL, NULL); #endif #if !MSDOS # ifdef MINIMUMSHELL else if (constequal(s, ENVMAIL, len)) checkmail(1); # else /* !MINIMUMSHELL */ else if (!strnenvcmp(s, ENVMAIL, strsize(ENVMAIL))) { if (len == strsize(ENVMAIL)) { if (!getconstvar(ENVMAILPATH)) replacemailpath(cp, 0); } else if (constequal(s, ENVMAILPATH, len)) replacemailpath(cp, 1); else if (constequal(s, ENVMAILCHECK, len)) { if ((mailcheck = isnumeric(cp)) < 0) mailcheck = 0; } } # endif /* !MINIMUMSHELL */ # ifdef FD else if (constequal(s, ENVTERM, len)) { keymap = copykeyseq(NULL); regetterment(cp, interactive); if (dumbterm > 1 && (!shellmode || exit_status < 0)) { if (!(term = getconstvar(ENVTERM))) term = nullstr; regetterment(term, interactive); execerror(NULL, cp, ER_INVALTERMFD, 1); copykeyseq(keymap); freekeyseq(keymap); return(seterrno(EINVAL)); } freekeyseq(keymap); } # endif /* FD */ #endif /* !MSDOS */ #ifndef NOPOSIXUTIL else if (constequal(s, ENVOPTIND, len)) { if ((posixoptind = isnumeric(cp)) <= 1) posixoptind = 0; } #endif #ifndef MINIMUMSHELL else if (constequal(s, ENVLINENO, len)) shlineno = -1L; #endif #if !defined (FD) && defined (DEP_URLPATH) else if (constequal(s, "URLTIMEOUT", len)) { if ((urltimeout = isnumeric(cp)) < 0) urltimeout = 0; } else if (constequal(s, "URLOPTIONS", len)) { if ((urloptions = isnumeric(cp)) < 0) urloptions = 0; } #endif #if !defined (FD) && defined (DEP_FTPPATH) else if (constequal(s, "FTPADDRESS", len)) ftpaddress = (char *)cp; else if (constequal(s, "FTPPROXY", len)) ftpproxy = (char *)cp; else if (constequal(s, "FTPLOGFILE", len)) ftplogfile = (char *)cp; #endif #if !defined (FD) && defined (DEP_HTTPPATH) else if (constequal(s, "HTTPPROXY", len)) httpproxy = (char *)cp; else if (constequal(s, "HTTPLOGFILE", len)) httplogfile = (char *)cp; else if (constequal(s, "HTMLLOGFILE", len)) htmllogfile = (char *)cp; #endif shellvar = putvar(shellvar, s, len); #ifdef FD evalenv(s, len); #endif return(0); } int putexportvar(s, len) char *s; int len; { char *cp; if (len < 0) { if (!(cp = Xstrchr(s, '='))) return(0); len = cp - s; } if (_putshellvar(s, len) < 0) return(-1); exportlist = expandvar(exportlist, s, len); exportvar = putvar(exportvar, Xstrdup(s), len); #ifdef DEP_PTY sendparent(TE_PUTEXPORTVAR, s, len); #endif return(0); } int putshellvar(s, len) char *s; int len; { char *cp; if (autoexport) return(putexportvar(s, len)); if (len < 0) { if (!(cp = Xstrchr(s, '='))) return(0); len = cp - s; } if (_putshellvar(s, len) < 0) return(-1); if (searchvar(exportlist, s, len, '\0') >= 0) exportvar = putvar(exportvar, Xstrdup(s), len); #ifdef DEP_PTY sendparent(TE_PUTSHELLVAR, s, len); #endif return(0); } int unset(ident, len) CONST char *ident; int len; { #if !MSDOS && !defined (MINIMUMSHELL) CONST char *cp; #endif int i; if (checkprimal(ident, len) < 0 || checkrestrict(ident, len) < 0 || checkronly(ident, len) < 0) return(-1); #if !MSDOS # ifndef MINIMUMSHELL else if (!strnenvcmp(ident, ENVMAIL, strsize(ENVMAIL))) { if (len == strsize(ENVMAIL)) { if (!getconstvar(ENVMAILPATH)) checkmail(1); } else if (constequal(ident, ENVMAILPATH, len)) { cp = getconstvar(ENVMAIL); if (cp) replacemailpath(cp, 0); else checkmail(1); } } # endif /* !MINIMUMSHELL */ # ifdef FD else if (constequal(ident, ENVTERM, len)) regetterment(nullstr, interactive); # endif #endif /* !MSDOS */ #ifndef NOPOSIXUTIL else if (constequal(ident, ENVOPTIND, len)) posixoptind = 0; #endif #ifndef MINIMUMSHELL else if (constequal(ident, ENVLINENO, len)) shlineno = -1L; #endif #if !defined (FD) && defined (DEP_URLPATH) else if (constequal(ident, "URLTIMEOUT", len)) urltimeout = 0; else if (constequal(ident, "URLOPTIONS", len)) urloptions = 0; #endif #if !defined (FD) && defined (DEP_FTPPATH) else if (constequal(ident, "FTPADDRESS", len)) ftpaddress = NULL; else if (constequal(ident, "FTPPROXY", len)) ftpproxy = NULL; else if (constequal(ident, "FTPLOGFILE", len)) ftplogfile = NULL; #endif #if !defined (FD) && defined (DEP_HTTPPATH) else if (constequal(ident, "HTTPPROXY", len)) httpproxy = NULL; else if (constequal(ident, "HTTPLOGFILE", len)) httplogfile = NULL; #endif shellvar = putvar(shellvar, (char *)ident, len); exportvar = putvar(exportvar, (char *)ident, len); if ((i = searchvar(exportlist, ident, len, '\0')) >= 0) { Xfree(exportlist[i]); for (; exportlist[i + 1]; i++) exportlist[i] = exportlist[i + 1]; exportlist[i] = NULL; } #ifdef FD evalenv(ident, len); #endif #ifdef DEP_PTY sendparent(TE_UNSET, ident, len); #endif return(0); } #ifndef MINIMUMSHELL static VOID NEAR setshlineno(n) long n; { char tmp[strsize(ENVLINENO) + 1 + MAXLONGWIDTH + 1]; if (shlineno < 0L) return; shlineno = n; VOID_C Xsnprintf(tmp, sizeof(tmp), "%s=%ld", ENVLINENO, n); shellvar = putvar(shellvar, Xstrdup(tmp), strsize(ENVLINENO)); } #endif /* !MINIMUMSHELL */ static heredoc_t *NEAR duplheredoc(hdp) heredoc_t *hdp; { heredoc_t *new; if (!hdp) return(NULL); new = newheredoc(Xstrdup(hdp -> eof), Xstrdup(hdp -> filename), hdp -> fd, hdp -> flags); new -> buf = Xstrdup(hdp -> buf); return(new); } static redirectlist *NEAR duplrlist(rp) redirectlist *rp; { redirectlist *new, *next; char *filename; if (!rp) return(NULL); next = duplrlist(rp -> next); if (rp -> type & MD_HEREDOC) filename = (char *)duplheredoc((heredoc_t *)(rp -> filename)); else filename = Xstrdup(rp -> filename); new = newrlist(rp -> fd, filename, rp -> type | MD_DUPL, next); new -> new = rp -> new; new -> old = rp -> old; #ifdef DEP_DOSDRIVE new -> fakepipe = rp -> fakepipe; new -> dosfd = rp -> dosfd; #endif return(new); } #ifdef MINIMUMSHELL syntaxtree *duplstree(trp, parent) syntaxtree *trp, *parent; #else syntaxtree *duplstree(trp, parent, top) syntaxtree *trp, *parent; long top; #endif { syntaxtree *new; redirectlist *rp; command_t *comm; new = newstree(parent); new -> type = trp -> type; new -> cont = trp -> cont; new -> flags = (trp -> flags | ST_NOWN); #ifndef MINIMUMSHELL new -> lineno = trp -> lineno - top; #endif if ((comm = trp -> comm)) { if (trp -> flags & ST_NODE) new -> comm = (command_t *)duplstree2( (syntaxtree *)comm, new, top); else { new -> comm = newcomm(); (new -> comm) -> hash = comm -> hash; (new -> comm) -> argc = comm -> argc; (new -> comm) -> type = comm -> type; (new -> comm) -> id = comm -> id; if ((trp -> comm) -> argv) { if (!isstatement(new -> comm)) (new -> comm) -> argv = duplvar(comm -> argv, 0); else (new -> comm) -> argv = (char **)duplstree2((syntaxtree *) (comm -> argv), new, top); } (new -> comm) -> redp = duplrlist(comm -> redp); } } if (trp -> next) { if (!(trp -> cont & (CN_QUOT | CN_ESCAPE))) new -> next = duplstree2(trp -> next, new, top); else { rp = (redirectlist *)Xmalloc(sizeof(redirectlist)); memcpy((char *)rp, (char *)(trp -> next), sizeof(redirectlist)); rp -> filename = Xstrdup(rp -> filename); new -> next = (syntaxtree *)rp; } } return(new); } static shfunctable *NEAR duplfunc(func) shfunctable *func; { shfunctable *dupl; int i, n; if (!func) n = 0; else for (n = 0; func[n].ident; n++) /*EMPTY*/; dupl = (shfunctable *)Xmalloc((n + 1) * sizeof(shfunctable)); for (i = 0; i < n; i++) { dupl[i].ident = Xstrdup(func[i].ident); dupl[i].func = duplstree2(func[i].func, NULL, 0L); } dupl[i].ident = NULL; return(dupl); } static VOID NEAR freefunc(func) shfunctable *func; { int i; if (func) { for (i = 0; func[i].ident; i++) { Xfree(func[i].ident); freestree(func[i].func); Xfree(func[i].func); } Xfree(func); } } static int cmpfunc(vp1, vp2) CONST VOID_P vp1; CONST VOID_P vp2; { shfunctable *fp1, *fp2; fp1 = (shfunctable *)vp1; fp2 = (shfunctable *)vp2; return(strpathcmp2(fp1 -> ident, fp2 -> ident)); } static char *NEAR getifs(VOID_A) { char *ifs; return((ifs = getconstvar(ENVIFS)) ? ifs : IFS_SET); } static int getretval(VOID_A) { return(ret_status); } static p_id_t getorgpid(VOID_A) { return(orgpid); } static p_id_t getlastpid(VOID_A) { return(lastpid); } static char *getflagstr(VOID_A) { char *cp; int i, j; cp = Xmalloc(FLAGSSIZ + 1); for (i = j = 0; i < FLAGSSIZ; i++) if (*(shflaglist[i].var) && shflaglist[i].letter) cp[j++] = shflaglist[i].letter; cp[j] = '\0'; return(cp); } static int checkundefvar(cp, arg, len) CONST char *cp, *arg; int len; { char *new; if (cp || !undeferror) return(0); new = Xstrndup(arg, len); execerror(NULL, new, ER_PARAMNOTSET, 0); Xfree(new); return(-1); } static VOID safeexit(VOID_A) { if (interactive_io) return; Xexit2(RET_FAIL); } int getstatid(trp) syntaxtree *trp; { int id; if (!trp || (trp -> flags & ST_NODE) || !isstatement(trp -> comm) || (id = (trp -> comm) -> id) <= 0 || id > STATEMENTSIZ) return(-1); return(id - 1); } static int NEAR getparenttype(trp) syntaxtree *trp; { int id; if ((id = getstatid(parentstree(trp))) < 0) return(0); return(statementlist[id].type & STT_TYPE); } static int NEAR parsestatement(trpp, n, prev, type) syntaxtree **trpp; int n, prev, type; { syntaxtree *tmptr; int i; if (!(statementlist[n].prev[0])) { if ((*trpp) -> comm) return(-1); if (prev > 0) { if ((statementlist[prev - 1].type & STT_FUNC)) { #ifdef BASHSTYLE /* bash does not allow the function definition without "{ }" */ if (n != SM_LIST - 1) return(-1); #endif } else if (!(statementlist[prev - 1].type & STT_NEEDLIST)) return(-1); } *trpp = childstree(*trpp, SM_STATEMENT); } else { if (prev <= 0 || !(tmptr = parentstree(*trpp))) return(-1); for (i = 0; i < SMPREV; i++) { if (!(statementlist[n].prev[i])) continue; if (statementlist[n].prev[i] == SM_ANOTHER) return(0); if (prev == statementlist[n].prev[i]) break; } if (i >= SMPREV) return(-1); if (!(statementlist[n].type & STT_CASEEND) && (type & STT_NEEDLIST) && !isopnot(statementbody(tmptr)) && !(statementbody(tmptr) -> comm)) return(-1); *trpp = tmptr; } if (statementlist[n].type & STT_NEEDNONE) { if (!(tmptr = parentstree(*trpp))) return(-1); *trpp = tmptr; if (getstatid(tmptr = getparent(tmptr)) == SM_FUNC - 1) { if (!(tmptr = parentstree(tmptr))) return(-1); *trpp = tmptr; } } else { if (statementlist[n].prev[0]) { tmptr = (*trpp) -> next = newstree(*trpp); tmptr -> flags = ST_NEXT; *trpp = tmptr; } *trpp = childstree(*trpp, n + 1); } return(1); } static syntaxtree *NEAR _addarg(trp, arg) syntaxtree *trp; CONST char *arg; { syntaxtree *tmptr; command_t *comm; int id; if (trp -> flags & ST_NODE) return(trp); comm = trp -> comm; if (ischild(comm)) /*EMPTY*/; else if (comm) { if (isstatement(comm)) return(trp); comm -> argc++; if (arg) { comm -> argv = (char **)Xrealloc(comm -> argv, (comm -> argc + 2) * sizeof(char *)); comm -> argv[comm -> argc] = Xstrdup(arg); comm -> argv[comm -> argc + 1] = NULL; } } else if (arg) { if ((trp -> flags & ST_NEXT) && (id = getstatid(parentstree(trp))) >= 0 && !(statementlist[id].type & STT_NEEDLIST)) { syntaxerrno = ER_UNEXPTOK; return(trp); } comm = trp -> comm = newcomm(); comm -> argc = 0; comm -> argv = (char **)Xmalloc(2 * sizeof(char *)); comm -> argv[0] = Xstrdup(arg); comm -> argv[1] = NULL; } if ((id = getstatid(getparent(trp))) >= 0) switch (statementlist[id].type & STT_TYPE) { case STT_FOR: case STT_CASE: if (!comm || comm -> argc) { syntaxerrno = ER_UNEXPNL; return(trp); } comm -> argv = (char **)Xrealloc(comm -> argv, 2 * sizeof(char *)); comm -> argv[1] = NULL; comm -> argc = 1; trp -> next = newstree(trp); (trp -> next) -> flags = ST_NEXT; trp = trp -> next; break; case STT_IN: if (!comm) { syntaxerrno = ER_UNEXPNL; return(trp); } break; case STT_FUNC: if (!arg && comm) { if (!(tmptr = parentstree(trp)) || !(tmptr = parentstree(tmptr))) { syntaxerrno = ER_UNEXPNL; return(trp); } trp = tmptr; } break; default: break; } return(trp); } static int NEAR addarg(trpp, rp, tok, lenp, notok) syntaxtree **trpp; redirectlist *rp; char *tok; int *lenp, notok; { syntaxtree *tmptr; int i, n, id, type; type = rp -> type; rp -> type = 0; if (!tok) tok = rp -> filename; if ((*trpp) -> flags & ST_NODE) { syntaxerrno = ER_UNEXPTOK; return(-1); } if (!*lenp) { if (type && notok) { syntaxerrno = ER_UNEXPTOK; return(-1); } rp -> type = type; return(0); } tok[*lenp] = '\0'; *lenp = 0; if (!type) { id = getstatid(tmptr = parentstree(*trpp)); type = (id >= 0) ? statementlist[id].type : 0; if ((type & STT_NEEDIDENT) && tmptr == getparent(*trpp)) /*EMPTY*/; else if (!((*trpp) -> comm) || ischild((*trpp) -> comm)) { for (i = 0; i < STATEMENTSIZ; i++) if (!strcommcmp(tok, statementlist[i].ident)) { n = parsestatement(trpp, i, id + 1, type); if (!n) continue; else if (n > 0) return(0); syntaxerrno = ER_UNEXPTOK; return(-1); } } if (isstatement((*trpp) -> comm)) { syntaxerrno = ER_UNEXPTOK; return(-1); } *trpp = _addarg(*trpp, tok); } else if (redirect(*trpp, rp -> fd, tok, type) < 0) return(-1); return(0); } static int NEAR evalredprefix(trpp, rp, lenp) syntaxtree **trpp; redirectlist *rp; int *lenp; { int n; rp -> filename[*lenp] = '\0'; if ((n = evalfiledesc(rp -> filename)) < 0) addarg(trpp, rp, NULL, lenp, 1); else if (rp -> type) { syntaxerrno = ER_UNEXPTOK; return(-2); } *lenp = 0; return(n); } static syntaxtree *NEAR rparen(trp) syntaxtree *trp; { syntaxtree *tmptr; if ((!(trp -> comm) && !(trp -> flags & ST_NEXT)) || !(tmptr = parentstree(trp)) || !ischild(tmptr -> comm)) syntaxerrno = ER_UNEXPTOK; else { _addarg(trp, NULL); tmptr = _addarg(tmptr, NULL); tmptr -> cont |= (trp -> cont & CN_INHR); trp = tmptr; } return(trp); } static syntaxtree *NEAR semicolon(trp, rp, s, ptrp) syntaxtree *trp; redirectlist *rp; CONST char *s; int *ptrp; { char tmptok[3]; int i, id; id = getstatid(parentstree(trp)); if (s[*ptrp + 1] != ';') { if (!(trp -> comm) && !(trp -> flags & ST_NEXT) && id >= 0) { syntaxerrno = ER_UNEXPNL; return(trp); } trp = _addarg(trp, NULL); trp = linkstree(trp, OP_FG); } else { if (id != SM_RPAREN - 1) { syntaxerrno = ER_UNEXPTOK; return(trp); } if (trp -> comm) { trp = _addarg(trp, NULL); trp = linkstree(trp, OP_FG); } (*ptrp)++; i = 0; tmptok[i++] = ';'; tmptok[i++] = ';'; addarg(&trp, rp, tmptok, &i, 0); } return(trp); } static syntaxtree *NEAR ampersand(trp, rp, s, ptrp) syntaxtree *trp; redirectlist *rp; CONST char *s; int *ptrp; { switch (s[*ptrp + 1]) { case '&': trp = _addarg(trp, NULL); (*ptrp)++; trp = linkstree(trp, OP_AND); break; #ifndef MINIMUMSHELL case '>': (*ptrp)++; rp -> fd = STDOUT_FILENO; rp -> type = (MD_WRITE | MD_WITHERR); if (s[*ptrp + 1] == '>') { (*ptrp)++; rp -> type |= MD_APPEND; } else if (s[*ptrp + 1] == '|') { (*ptrp)++; rp -> type |= MD_FORCED; } break; case '|': trp = _addarg(trp, NULL); (*ptrp)++; trp = linkstree(trp, OP_NOWN); break; #endif /* !MINIMUMSHELL */ default: trp = _addarg(trp, NULL); trp = linkstree(trp, OP_BG); break; } return(trp); } static syntaxtree *NEAR vertline(trp, s, ptrp) syntaxtree *trp; CONST char *s; int *ptrp; { #ifndef MINIMUMSHELL int n; #endif trp = _addarg(trp, NULL); switch (s[*ptrp + 1]) { case '|': (*ptrp)++; trp = linkstree(trp, OP_OR); break; #ifndef MINIMUMSHELL case '&': (*ptrp)++; n = redirect(trp, STDERR_FILENO, "1", MD_WRITE | MD_FILEDESC); if (n >= 0) trp = linkstree(trp, OP_PIPE); break; #endif default: trp = linkstree(trp, OP_PIPE); break; } return(trp); } static syntaxtree *NEAR lessthan(trp, rp, s, ptrp) syntaxtree *trp; redirectlist *rp; CONST char *s; int *ptrp; { int n; rp -> type = MD_READ; n = 0; switch (s[*ptrp + 1]) { case '<': (*ptrp)++; rp -> type |= MD_HEREDOC; if (s[*ptrp + 1] == '-') { (*ptrp)++; rp -> type |= MD_APPEND; } break; #ifndef MINIMUMSHELL case '>': (*ptrp)++; rp -> type |= MD_WRITE; if (s[*ptrp + 1] == '-') n++; else if (s[*ptrp + 1] == '&') { (*ptrp)++; if (s[*ptrp + 1] == '-') n++; else rp -> type |= MD_FILEDESC; } break; #endif /* !MINIMUMSHELL */ case '&': (*ptrp)++; if (s[*ptrp + 1] == '-') n++; else rp -> type |= MD_FILEDESC; break; case '-': n++; break; default: break; } if (n) { (*ptrp)++; if (redirect(trp, rp -> fd, NULL, rp -> type) >= 0) rp -> type = 0; } return(trp); } static syntaxtree *NEAR morethan(trp, rp, s, ptrp) syntaxtree *trp; redirectlist *rp; CONST char *s; int *ptrp; { int n; rp -> type = MD_WRITE; n = 0; switch (s[*ptrp + 1]) { case '>': (*ptrp)++; rp -> type |= MD_APPEND; break; #ifndef MINIMUMSHELL case '<': if (rp -> fd < 0) rp -> fd = STDOUT_FILENO; (*ptrp)++; rp -> type |= MD_READ; if (s[*ptrp + 1] == '-') n++; else if (s[*ptrp + 1] == '&') { (*ptrp)++; if (s[*ptrp + 1] == '-') n++; else rp -> type |= MD_FILEDESC; } break; #endif /* !MINIMUMSHELL */ case '&': (*ptrp)++; if (s[*ptrp + 1] == '-') n++; else rp -> type |= MD_FILEDESC; break; case '-': n++; break; #ifndef MINIMUMSHELL case '|': (*ptrp)++; rp -> type |= MD_FORCED; break; #endif default: break; } if (n) { (*ptrp)++; if (redirect(trp, rp -> fd, NULL, rp -> type) >= 0) rp -> type = 0; } return(trp); } #if defined (BASHSTYLE) || !defined (MINIMUMSHELL) syntaxtree *startvar(trp, rp, s, ptrp, tptrp, n) syntaxtree *trp; redirectlist *rp; CONST char *s; int *ptrp, *tptrp, n; { syntaxtree *new; redirectlist *newrp; char *cp; cp = Xmalloc(*tptrp + n + 1); Xstrncpy(cp, rp -> filename, *tptrp); Xstrncpy(&(cp[*tptrp]), &(s[*ptrp]), n); *tptrp = 0; *ptrp += n - 1; new = newstree(NULL); new -> parent = trp; newrp = (redirectlist *)Xmalloc(sizeof(redirectlist)); memcpy((char *)newrp, (char *)rp, sizeof(redirectlist)); newrp -> filename = cp; newrp -> next = (redirectlist *)new; trp -> next = (syntaxtree *)newrp; trp -> flags |= ST_BUSY; rp -> type = MD_NORMAL; rp -> fd = -1; rp -> new = rp -> old = '\0'; return(new); } static syntaxtree *NEAR endvar(trp, rp, s, ptrp, tptrp, sp, n) syntaxtree *trp; redirectlist *rp; CONST char *s; int *ptrp, *tptrp; ALLOC_T *sp; int n; { syntaxtree *tmptr; char *cp; ALLOC_T size; int len; if (!(tmptr = trp -> parent) || !(tmptr -> flags & ST_BUSY) || !(tmptr -> next)) { syntaxerrno = ER_UNEXPTOK; return(trp); } trp = tmptr; tmptr = trp -> next; trp -> next = NULL; trp -> flags &= ~ST_BUSY; cp = rp -> filename; memcpy((char *)rp, (char *)tmptr, sizeof(redirectlist)); len = strlen(rp -> filename); size = c_allocsize(len + *tptrp + n + 2); if (size > *sp) cp = Xrealloc(cp, *sp = size); memmove(&(cp[len]), cp, *tptrp); memcpy(cp, rp -> filename, len); *tptrp += len; Xstrncpy(&(cp[*tptrp]), &(s[*ptrp]), n); *tptrp += n; *ptrp += n - 1; Xfree(rp -> filename); rp -> filename = cp; Xfree(rp -> next); rp -> next = NULL; Xfree(tmptr); return(trp); } static syntaxtree *NEAR addvar(trp, s, ptrp, tok, tptrp, n) syntaxtree *trp; CONST char *s; int *ptrp; CONST char *tok; int *tptrp, n; { syntaxtree *tmptr; redirectlist *rp; int len; if (!(tmptr = trp -> parent) || !(tmptr -> flags & ST_BUSY) || !(rp = (redirectlist *)(tmptr -> next))) { syntaxerrno = ER_UNEXPTOK; return(trp); } len = strlen(rp -> filename); rp -> filename = Xrealloc(rp -> filename, len + *tptrp + n + 1); Xstrncpy(&(rp -> filename[len]), tok, *tptrp); len += *tptrp; *tptrp = 0; if (n > 0) { Xstrncpy(&(rp -> filename[len]), &(s[*ptrp]), n); len += n; *ptrp += n - 1; } rp -> filename[len] = '\0'; return(trp); } #endif /* BASHSTYLE || !MINIMUMSHELL */ static syntaxtree *NEAR normaltoken(trp, rp, s, ptrp, tptrp, sp) syntaxtree *trp; redirectlist *rp; CONST char *s; int *ptrp, *tptrp; ALLOC_T *sp; { char tmptok[2]; ALLOC_T size; int i; switch (s[*ptrp]) { case '{': if (!Xstrchr(IFS_SET, s[*ptrp + 1])) { rp -> filename[(*tptrp)++] = s[*ptrp]; break; } if (addarg(&trp, rp, NULL, tptrp, 0) < 0) break; i = 0; tmptok[i++] = s[*ptrp]; addarg(&trp, rp, tmptok, &i, 0); break; case '}': rp -> filename[(*tptrp)++] = s[*ptrp]; if ((*tptrp) > 1 || getparenttype(trp) != STT_LIST) break; if (trp -> comm) { #ifdef BASHSTYLE /* bash allows the list which does not end with ";" */ trp = _addarg(trp, NULL); trp = linkstree(trp, OP_NONE); #else break; #endif } addarg(&trp, rp, NULL, tptrp, 0); break; case '(': if (hascomm(trp)) { if (rp -> type || *tptrp || (trp -> comm) -> argc) syntaxerrno = ER_UNEXPTOK; else { trp = _addarg(trp, NULL); trp = linkstree(trp, OP_NONE); i = 0; tmptok[i++] = s[*ptrp]; addarg(&trp, rp, tmptok, &i, 0); } } else if (*tptrp) { if (!*tptrp || addarg(&trp, rp, NULL, tptrp, 0) < 0) syntaxerrno = ER_UNEXPTOK; else { trp = _addarg(trp, NULL); trp = linkstree(trp, OP_NONE); i = 0; tmptok[i++] = s[*ptrp]; addarg(&trp, rp, tmptok, &i, 0); } } else if (rp -> type) syntaxerrno = ER_UNEXPTOK; #ifdef BASHSTYLE /* bash does not allow the function definition without "{ }" */ else if (getstatid(parentstree(trp)) == SM_FUNC - 1) syntaxerrno = ER_UNEXPTOK; #endif else trp = childstree(trp, SM_CHILD); break; case ')': if (getparenttype(trp) == STT_LPAREN) { if (*tptrp || trp -> comm) syntaxerrno = ER_UNEXPTOK; else { i = 0; tmptok[i++] = s[*ptrp]; addarg(&trp, rp, tmptok, &i, 0); } break; } if (addarg(&trp, rp, NULL, tptrp, 0) < 0) break; trp = rparen(trp); break; case ';': if (addarg(&trp, rp, NULL, tptrp, 1) < 0) break; trp = semicolon(trp, rp, s, ptrp); break; case '&': if (addarg(&trp, rp, NULL, tptrp, 1) < 0) break; trp = ampersand(trp, rp, s, ptrp); break; case '|': if (addarg(&trp, rp, NULL, tptrp, 1) < 0) break; trp = vertline(trp, s, ptrp); break; #ifndef MINIMUMSHELL case '!': if (*tptrp || trp -> comm) rp -> filename[(*tptrp)++] = s[*ptrp]; else if (rp -> type || (trp -> flags & ST_NODE)) { syntaxerrno = ER_UNEXPTOK; return(trp); } else trp = linkstree(trp, OP_NOT); break; #endif case '<': if ((rp -> fd = evalredprefix(&trp, rp, tptrp)) >= -1) trp = lessthan(trp, rp, s, ptrp); break; case '>': if ((rp -> fd = evalredprefix(&trp, rp, tptrp)) >= -1) trp = morethan(trp, rp, s, ptrp); break; case '\r': #ifdef BASHSTYLE /* bash treats '\r' as just a character */ if (rp -> type) syntaxerrno = ER_UNEXPNL; else rp -> filename[(*tptrp)++] = s[*ptrp]; break; #else /*FALLTHRU*/ #endif case '\n': if (addarg(&trp, rp, NULL, tptrp, 1) < 0) break; if (trp -> comm) { trp = _addarg(trp, NULL); trp = linkstree(trp, OP_FG); } else if (!(trp -> flags & ST_NEXT) && (i = getstatid(parentstree(trp)) + 1) > 0) { if (i == SM_FOR || i == SM_CASE || i == SM_IN || *tptrp) syntaxerrno = ER_UNEXPNL; } if (trp -> cont & CN_HDOC) { i = *ptrp + 1; #ifdef BASHSTYLE /* bash treats '\r' as just a character */ while (s[*ptrp + 1] && s[*ptrp + 1] != '\n') (*ptrp)++; #else while (s[*ptrp + 1] && s[*ptrp + 1] != '\r' && s[*ptrp + 1] != '\n') (*ptrp)++; #endif *tptrp = *ptrp - i + 1; size = c_allocsize(*tptrp + 2); if (size > *sp) rp -> filename = Xrealloc(rp -> filename, *sp = size); Xstrncpy(rp -> filename, &(s[i]), *tptrp); trp -> flags |= ST_HDOC; } break; case '#': if (*tptrp) rp -> filename[(*tptrp)++] = s[*ptrp]; else { #ifdef BASHSTYLE /* bash treats '\r' as just a character */ while (s[*ptrp + 1] && s[*ptrp + 1] != '\n') (*ptrp)++; #else while (s[*ptrp + 1] && s[*ptrp + 1] != '\r' && s[*ptrp + 1] != '\n') (*ptrp)++; #endif } break; default: if (!Xstrchr(IFS_SET, s[*ptrp])) rp -> filename[(*tptrp)++] = s[*ptrp]; else addarg(&trp, rp, NULL, tptrp, 0); break; } return(trp); } static syntaxtree *NEAR casetoken(trp, rp, s, ptrp, tptrp) syntaxtree *trp; redirectlist *rp; CONST char *s; int *ptrp, *tptrp; { char tmptok[2]; int i, stype; switch (s[*ptrp]) { case ')': if (!*tptrp) /*EMPTY*/; else if (addarg(&trp, rp, NULL, tptrp, 0) < 0) break; trp = _addarg(trp, NULL); trp = linkstree(trp, OP_NONE); i = 0; tmptok[i++] = s[*ptrp]; addarg(&trp, rp, tmptok, &i, 0); break; case '|': if (!*tptrp) /*EMPTY*/; else addarg(&trp, rp, NULL, tptrp, 0); break; case ';': if (addarg(&trp, rp, NULL, tptrp, 1) < 0) break; /* for "esac;" */ if ((stype = getparenttype(trp)) != STT_INCASE && stype != STT_CASEEND) trp = semicolon(trp, rp, s, ptrp); else syntaxerrno = ER_UNEXPTOK; break; case '{': case '}': case '&': case '<': case '>': syntaxerrno = ER_UNEXPTOK; break; case '(': #ifdef STRICTPOSIX if (!*tptrp && !(trp -> comm)) break; #endif syntaxerrno = ER_UNEXPTOK; break; case '\r': #ifdef BASHSTYLE /* bash treats '\r' as just a character */ syntaxerrno = ER_UNEXPNL; break; #endif case '\n': if (getparenttype(trp) == STT_INCASE && *tptrp) { syntaxerrno = ER_UNEXPNL; break; } if (addarg(&trp, rp, NULL, tptrp, 1) < 0) break; if (trp -> comm) { trp = _addarg(trp, NULL); trp = linkstree(trp, OP_FG); } else if (!(trp -> flags & ST_NEXT) && (i = getstatid(parentstree(trp)) + 1) > 0) { if (*tptrp) syntaxerrno = ER_UNEXPNL; } break; case '#': if (*tptrp) rp -> filename[(*tptrp)++] = s[*ptrp]; else { #ifdef BASHSTYLE /* bash treats '\r' as just a character */ while (s[*ptrp + 1] && s[*ptrp + 1] != '\n') (*ptrp)++; #else while (s[*ptrp + 1] && s[*ptrp + 1] != '\r' && s[*ptrp + 1] != '\n') (*ptrp)++; #endif } break; default: if (!Xstrchr(IFS_SET, s[*ptrp])) rp -> filename[(*tptrp)++] = s[*ptrp]; else if (*tptrp > 0) { addarg(&trp, rp, NULL, tptrp, 0); do { (*ptrp)++; } while (Xisblank(s[*ptrp])); /* for "esac " */ if ((stype = getparenttype(trp)) != STT_INCASE && stype != STT_CASEEND) (*ptrp)--; else if (!s[*ptrp] || s[*ptrp] == '\n') syntaxerrno = ER_UNEXPNL; else if (s[*ptrp] == ')' || s[*ptrp] == '|') (*ptrp)--; else if (s[*ptrp] == PESCAPE && (!s[*ptrp + 1] || s[*ptrp] == '\n')) (*ptrp)--; else syntaxerrno = ER_UNEXPTOK; } break; } return(trp); } #if !defined (BASHBUG) && !defined (MINIMUMSHELL) static int NEAR cmpstatement(s, id) CONST char *s; int id; { int len; if (--id < 0) return(-1); len = strlen(statementlist[id].ident); if (strncommcmp(s, statementlist[id].ident, len)) return(-1); return(len); } static syntaxtree *NEAR comsubtoken(trp, rp, s, ptrp, tptrp, sp) syntaxtree *trp; redirectlist *rp; CONST char *s; int *ptrp, *tptrp; ALLOC_T *sp; { int i, len; if (!*tptrp) { if ((len = cmpstatement(&(s[*ptrp]), SM_CASE)) >= 0 && (!s[*ptrp + len] || Xstrchr(IFS_SET, s[*ptrp + len]))) { trp = startvar(trp, rp, s, ptrp, tptrp, len); trp -> cont = CN_CASE; return(trp); } if ((trp -> cont & CN_SBST) == CN_CASE && (len = cmpstatement(&(s[*ptrp]), SM_ESAC)) >= 0 && (!s[*ptrp + len] || Xstrchr(IFS_SET, s[*ptrp + len]) || s[*ptrp + len] == ';' || s[*ptrp + len] == ')')) { trp = endvar(trp, rp, s, ptrp, tptrp, sp, len); return(trp); } if (Xstrchr(IFS_SET, s[*ptrp])) { for (len = 1; s[*ptrp + len]; len++) if (!Xstrchr(IFS_SET, s[*ptrp + len])) break; trp = addvar(trp, s, ptrp, rp -> filename, tptrp, len); return(trp); } } if (s[*ptrp] == '(') { trp = startvar(trp, rp, s, ptrp, tptrp, 1); trp -> cont = CN_COMM; } else if (s[*ptrp] == ')') { if ((trp -> cont & CN_SBST) == CN_CASE) rp -> filename[(*tptrp)++] = s[*ptrp]; else trp = endvar(trp, rp, s, ptrp, tptrp, sp, 1); } # ifdef BASHSTYLE /* bash treats '\r' as just a character */ else if (s[*ptrp] == '\n') # else else if (s[*ptrp] == '\n' || s[*ptrp] == '\r') # endif trp = addvar(trp, s, ptrp, rp -> filename, tptrp, 1); else { for (i = 0; i < DELIMLISTSIZ; i++) { len = strlen(delimlist[i].symbol); if (!strncmp(&(s[*ptrp]), delimlist[i].symbol, len)) break; } if (i >= DELIMLISTSIZ) rp -> filename[(*tptrp)++] = s[*ptrp]; else if (delimlist[i].level) trp = addvar(trp, s, ptrp, rp -> filename, tptrp, len); else { Xstrncpy(&(rp -> filename[*tptrp]), &(s[*ptrp]), len); *tptrp += len; *ptrp += len - 1; } } return(trp); } #endif /* !BASHBUG && !MINIMUMSHELL */ static syntaxtree *NEAR analyzeloop(trp, rp, s, quiet) syntaxtree *trp; redirectlist *rp; CONST char *s; int quiet; { #if !defined (BASHSTYLE) && !defined (MINIMUMSHELL) syntaxtree *tmptr; #endif char *cp; ALLOC_T size; int i, j, n, pc, stype, hdoc; if (!rp -> filename) { j = 0; rp -> filename = c_realloc(NULL, 0, &size); } else { j = strlen(rp -> filename); size = c_allocsize(j); } hdoc = 0; for (i = 0; s && s[i]; i++) { syntaxerrno = 0; rp -> filename = c_realloc(rp -> filename, j + 2, &size); #ifndef MINIMUMSHELL if (s[i] == '\n') setshlineno(shlineno + 1L); #endif if ((trp -> cont & CN_HDOC) && (trp -> flags & ST_HDOC)) { if (s[i] != '\n') { if (hdoc) { rp -> filename[j++] = s[i]; continue; } } else { rp -> filename[j] = '\0'; n = saveheredoc(rp -> filename, trp); if (n < 0) { if (!quiet) doperror(NULL, NULL); return(NULL); } hdoc = (trp -> cont & CN_HDOC); if (n > 0) { j = 0; continue; } hdoc = 0; trp -> cont &= ~CN_HDOC; } } pc = parsechar(&(s[i]), -1, '$', EA_BACKQ | EA_EOLESCAPE, #ifdef NESTINGQUOTE &(rp -> new), &(rp -> old)); #else &(rp -> new), NULL); #endif if (pc == PC_OPQUOTE || pc == PC_CLQUOTE || pc == PC_SQUOTE) rp -> filename[j++] = s[i]; #ifdef BASHSTYLE else if (pc == PC_BQUOTE) rp -> filename[j++] = s[i]; #endif else if (pc == PC_WCHAR) { rp -> filename[j++] = s[i++]; rp -> filename[j++] = s[i]; } else if (pc == PC_ESCAPE) { if (s[++i] != '\n' || rp -> new) { rp -> filename[j++] = PESCAPE; if (s[i]) rp -> filename[j++] = s[i]; else { trp -> cont |= CN_ESCAPE; break; } } } else if (pc == '$') { if (s[i + 1] == '{') { #ifdef BASHSTYLE /* bash treats any meta character in ${} as just a character */ trp = startvar(trp, rp, s, &i, &j, 2); #else /* !BASHSTYLE */ # ifndef MINIMUMSHELL if (rp -> new == '"') trp = startvar(trp, rp, s, &i, &j, 2); else # endif { rp -> filename[j++] = s[i++]; rp -> filename[j++] = s[i]; } #endif /* !BASHSTYLE */ trp -> cont = CN_VAR; } #ifndef MINIMUMSHELL else if (s[i + 1] == '(') { if (s[i + 2] != '(') { trp = startvar(trp, rp, s, &i, &j, 2); trp -> cont = CN_COMM; } else { trp = startvar(trp, rp, s, &i, &j, 3); trp -> cont = CN_EXPR; } } #endif /* !MINIMUMSHELL */ else rp -> filename[j++] = s[i]; } else if (s[i] == '}' && (trp -> cont & CN_SBST) == CN_VAR) { #ifdef BASHSTYLE /* bash treats any meta character in ${} as just a character */ trp = endvar(trp, rp, s, &i, &j, &size, 1); #else /* !BASHSTYLE */ # ifndef MINIMUMSHELL tmptr = trp -> parent; if (tmptr) tmptr = tmptr -> next; if (tmptr && ((redirectlist *)tmptr) -> new == '"') trp = endvar(trp, rp, s, &i, &j, &size, 1); else # endif { rp -> filename[j++] = s[i]; trp -> cont &= ~CN_VAR; } #endif /* !BASHSTYLE */ } #ifndef MINIMUMSHELL else if ((trp -> cont & CN_SBST) == CN_VAR) rp -> filename[j++] = s[i]; #endif #ifndef BASHSTYLE else if (pc == PC_BQUOTE) rp -> filename[j++] = s[i]; #endif else if (pc == PC_DQUOTE) rp -> filename[j++] = s[i]; #ifndef MINIMUMSHELL # ifdef BASHBUG /* bash cannot include 'case' statement within $() */ else if ((trp -> cont & CN_SBST) == CN_COMM) { if (s[i] == '(') { trp = startvar(trp, rp, s, &i, &j, 1); trp -> cont = CN_COMM; } else if (s[i] != ')') rp -> filename[j++] = s[i]; else trp = endvar(trp, rp, s, &i, &j, &size, 1); } # else else if ((trp -> cont & CN_SBST) == CN_COMM || (trp -> cont & CN_SBST) == CN_CASE) trp = comsubtoken(trp, rp, s, &i, &j, &size); # endif else if ((trp -> cont & CN_SBST) == CN_EXPR) { if (s[i] == '(') { trp = startvar(trp, rp, s, &i, &j, 2); trp -> cont = CN_COMM; } else if (s[i] != ')' || s[i + 1] != ')') rp -> filename[j++] = s[i]; else trp = endvar(trp, rp, s, &i, &j, &size, 2); } #endif /* !MINIMUMSHELL */ else if ((stype = getparenttype(trp)) == STT_INCASE || stype == STT_CASEEND) trp = casetoken(trp, rp, s, &i, &j); else { #ifndef NOALIAS n = checkalias(trp, rp -> filename, j, s[i]); if (n >= 0) { trp = analyzeloop(trp, rp, shellalias[n].comm, quiet); shellalias[n].flags &= ~AL_USED; if (!trp) return(NULL); j = strlen(rp -> filename); i--; } else #endif /* !NOALIAS */ trp = normaltoken(trp, rp, s, &i, &j, &size); } if (syntaxerrno) { if (quiet) return(NULL); if (Xstrchr(IFS_SET, s[i])) { if (j < 0) j = 0; rp -> filename[j] = '\0'; syntaxerror(rp -> filename); return(NULL); } for (j = i + 1; s[j]; j++) { if (Xstrchr(IFS_SET, s[j])) break; else if (iswchar(s, j)) j++; } cp = Xstrndup(&(s[i]), j - i); syntaxerror(cp); Xfree(cp); return(NULL); } } if (j && (trp -> cont & CN_HDOC) && (trp -> flags & ST_HDOC)) { rp -> filename[j] = '\0'; if ((n = saveheredoc(rp -> filename, trp)) < 0) { if (!quiet) doperror(NULL, NULL); return(NULL); } if (n > 0) j = 0; else trp -> cont &= ~CN_HDOC; } rp -> filename[j] = '\0'; #ifndef NOALIAS if ((n = checkalias(trp, rp -> filename, j, '\0')) >= 0) { trp = analyzeloop(trp, rp, shellalias[n].comm, quiet); shellalias[n].flags &= ~AL_USED; } #endif return(trp); } syntaxtree *analyze(s, trp, quiet) CONST char *s; syntaxtree *trp; int quiet; { syntaxtree *parent; redirectlist *rp, red; int i; syntaxerrno = 0; red.fd = -1; red.filename = NULL; red.type = MD_NORMAL; red.new = red.old = '\0'; #ifdef DEP_DOSDRIVE red.fakepipe = NULL; red.dosfd = -1; #endif red.next = NULL; if (trp -> cont & (CN_QUOT | CN_ESCAPE)) { memcpy((char *)&red, (char *)(trp -> next), sizeof(red)); Xfree(trp -> next); i = strlen(red.filename); if (i > 0) { if ((trp -> cont & CN_ESCAPE) && red.new != '\'') i--; else if (s) red.filename[i++] = '\n'; } #ifndef BASHSTYLE /* bash does not allow unclosed quote */ if (!s) { if (trp -> cont & CN_QUOT) red.filename[i++] = red.new; red.new = '\0'; } #endif red.filename[i] = '\0'; } else if ((trp -> cont & CN_HDOC)) { if ((i = saveheredoc(s, trp)) < 0) { if (!quiet) doperror(NULL, NULL); return(NULL); } else if (!i) { trp -> cont &= ~CN_HDOC; return(NULL); } return(trp); } else if (!s) return(NULL); trp -> next = NULL; trp -> cont &= CN_INHR; exectrapcomm(); if (s) { #ifndef NOALIAS for (i = 0; shellalias[i].ident; i++) shellalias[i].flags &= ~AL_USED; #endif if (!(trp = analyzeloop(trp, &red, s, quiet))) { Xfree(red.filename); return(NULL); } } i = (red.filename) ? strlen(red.filename) : 0; if (red.new) trp -> cont |= CN_QUOT; if (trp -> cont & (CN_QUOT | CN_ESCAPE)) { rp = (redirectlist *)Xmalloc(sizeof(redirectlist)); memcpy((char *)rp, (char *)&red, sizeof(red)); trp -> next = (syntaxtree *)rp; red.filename = NULL; } #if defined (BASHSTYLE) || !defined (MINIMUMSHELL) else if (trp -> cont & CN_SBST) { red.filename[i++] = '\n'; red.filename[i] = '\0'; trp = addvar(trp, NULL, NULL, red.filename, &i, 0); } #endif else if (getparenttype(trp) == STT_INCASE && (trp -> comm || i)) syntaxerrno = ER_UNEXPNL; else if (addarg(&trp, &red, NULL, &i, 1) < 0) /*EMPTY*/; else if (!(trp = _addarg(trp, NULL)) || syntaxerrno) /*EMPTY*/; else if (trp -> comm) trp = linkstree(trp, OP_FG); else if (hasparent(trp)) { #ifndef MINIMUMSHELL if (isopnot(trp -> parent)) syntaxerrno = ER_UNEXPNL; #endif if (!isopfg(trp -> parent) && !isopbg(trp -> parent) && !isopnown(trp -> parent)) trp -> cont |= CN_STAT; } if (syntaxerrno) { if (!quiet) syntaxerror(red.filename); Xfree(red.filename); return(NULL); } Xfree(red.filename); if ((parent = parentstree(trp)) && isstatement(parent -> comm)) trp -> cont |= CN_STAT; return(trp); } static syntaxtree *NEAR analyzeeof(trp) syntaxtree *trp; { while (trp && trp -> cont) { #ifdef BASHSTYLE if (trp -> cont & CN_HDOC) trp = analyze(NULL, trp, 0); #else /* bash does not allow unclosed quote */ if (trp -> cont & (CN_ESCAPE | CN_QUOT | CN_HDOC)) trp = analyze(NULL, trp, 0); /* bash does not allow the format like as "foo |" */ else if ((trp -> flags & ST_NEXT) && hasparent(trp) && isoppipe(trp -> parent)) break; #endif else { syntaxerrno = ER_UNEXPEOF; syntaxerror(nullstr); return(NULL); } } return(trp); } static syntaxtree *NEAR statementcheck(trp, id) syntaxtree *trp; int id; { if (!trp || !isstatement(trp -> comm) || (id > 0 && (trp -> comm) -> id != id) || !(trp = statementbody(trp))) { errno = EINVAL; return(NULL); } return(trp); } static int NEAR check_statement(trp) syntaxtree *trp; { syntaxtree *body; int i, id, prev; if ((trp -> comm) -> id == SM_CHILD) return(check_stree(statementbody(trp))); if ((id = getstatid(trp = statementcheck(trp, SM_STATEMENT))) < 0 || !statementlist[id].func || statementlist[id].prev[0]) { errno = EINVAL; doperror(NULL, NULL); return(-1); } for (;;) { if (statementlist[id].type & STT_NEEDLIST) { if (!(body = statementcheck(trp, 0))) { doperror(NULL, statementlist[id].ident); return(-1); } if (check_stree(body)) return(-1); } if (!(trp = trp -> next) || !(trp -> comm)) break; prev = id + 1; if ((id = getstatid(trp)) < 0) i = SMPREV; else for (i = 0; i < SMPREV; i++) { if (!(statementlist[id].prev[i])) continue; if (prev == statementlist[id].prev[i]) break; } if (i >= SMPREV) { errno = EINVAL; doperror(NULL, statementlist[id].ident); return(-1); } } return(0); } static int NEAR check_command(trp) syntaxtree *trp; { command_t *comm; char **argv, **subst; int id, type, argc, *len; comm = trp -> comm; argc = comm -> argc; argv = comm -> argv; if (argc <= 0) return(0); comm -> argv = duplvar(comm -> argv, 0); comm -> argc = getsubst(comm -> argc, comm -> argv, &subst, &len); if ((id = evalargv(comm, &type, NULL)) >= 0 && type == CT_COMMAND) id = searchhash(&(comm -> hash), comm -> argv[0], NULL); freevar(subst); Xfree(len); comm -> argc = argc; freevar(comm -> argv); comm -> argv = argv; return((id >= 0) ? 0 : -1); } static int NEAR check_stree(trp) syntaxtree *trp; { syntaxtree *tmptr; if (!trp) { errno = EINVAL; doperror(NULL, NULL); return(-1); } if (!(trp -> comm)) return(0); if (trp -> flags & ST_NODE) { if (check_stree((syntaxtree *)(trp -> comm)) < 0) return(-1); } else if (isstatement(trp -> comm)) { if (check_statement(trp) < 0) return(-1); } else if (getstatid(tmptr = statementcheck(trp -> next, SM_STATEMENT)) == SM_LPAREN - 1) { #ifndef BASHSTYLE /* bash allows any character in the function identifier */ if (identcheck((trp -> comm) -> argv[0], '\0') <= 0) { execerror(NULL, (trp -> comm) -> argv[0], ER_NOTIDENT, 0); return(-1); } #endif if (!statementcheck(tmptr -> next, 0)) { doperror(NULL, NULL); return(-1); } trp = trp -> next; } else if (check_command(trp) < 0) return(-1); return((trp -> next) ? check_stree(trp -> next) : 0); } static syntaxtree *NEAR analyzeline(command) CONST char *command; { #ifndef MINIMUMSHELL long dupshlineno; #endif syntaxtree *trp, *stree; #ifndef MINIMUMSHELL dupshlineno = shlineno; setshlineno(1L); #endif stree = newstree(NULL); trp = analyze(command, stree, 0); if (!(trp = analyzeeof(trp))) /*EMPTY*/; #ifndef _NOUSEHASH else if (hashahead && check_stree(stree) < 0) trp = NULL; #endif if (!trp) { freestree(stree); Xfree(stree); stree = NULL; } #ifndef MINIMUMSHELL setshlineno(dupshlineno); #endif return(stree); } #ifdef DEBUG static VOID NEAR Xexecve(path, argv, envp, bg) CONST char *path; char *argv[], *envp[]; int bg; #else static VOID NEAR Xexecve(path, argv, envp) CONST char *path; char *argv[], *envp[]; #endif { #ifdef DEP_PTY char *cp; int len; #endif int fd, ret; #ifdef DEP_PTY if (parentfd >= 0 && ptyterm && *ptyterm) { len = strsize(ENVTERM); cp = Xmalloc(len + strlen(ptyterm) + 2); memcpy(cp, ENVTERM, len); cp[len] = '='; Xstrcpy(&(cp[len + 1]), ptyterm); envp = putvar(envp, cp, len); } #endif /* DEP_PTY */ execve(path, argv, envp); if (errno != ENOEXEC) { if (errno == EACCES) { execerror(NULL, argv[0], ER_CANNOTEXE, 1); ret = RET_NOTEXEC; } else { doperror(NULL, argv[0]); ret = RET_FAIL; } } else if ((fd = newdup(Kopen(path, O_TEXT | O_RDONLY, 0666))) < 0) { doperror(NULL, argv[0]); ret = RET_NOTEXEC; } else { argvar = argv; sourcefile(fd, argv[0], 0); safeclose(fd); ret = ret_status; } #ifdef DEBUG if (!bg) Xexit2(ret); #endif prepareexit(1); Xexit(ret); } #if MSDOS static char *NEAR addext(path, ext) char *path; int ext; { int len; len = strlen(path); path = Xrealloc(path, len + 1 + 3 + 1); path[len++] = '.'; if (ext & CM_BATCH) Xstrcpy(&(path[len]), EXTBAT); else if (ext & CM_EXE) Xstrcpy(&(path[len]), EXTEXE); else Xstrcpy(&(path[len]), EXTCOM); return(path); } static char **NEAR replacebat(pathp, argv) char **pathp, **argv; { char *com; int i; # ifdef FD if (!(com = getenv2("FD_COMSPEC")) && !(com = getenv2("FD_SHELL"))) # else if (!(com = getconstvar(ENVCOMSPEC)) && !(com = getconstvar(ENVSHELL))) # endif # ifdef BSPATHDELIM com = "\\COMMAND.COM"; # else com = "/COMMAND.COM"; # endif i = countvar(argv); memmove((char *)(&(argv[i + 2])), (char *)(&(argv[i])), (i + 1) * sizeof(char *)); Xfree(argv[2]); argv[2] = Xstrdup(*pathp); argv[1] = Xstrdup("/C"); argv[0] = *pathp = Xstrdup(com); return(argv); } #endif /* MSDOS */ #ifdef USEFAKEPIPE static int NEAR openpipe(pidp, fdin, new) p_id_t *pidp; int fdin, new; #else static int NEAR openpipe(pidp, fdin, new, tty, ppid) p_id_t *pidp; int fdin, new, tty; p_id_t ppid; #endif { #ifndef USEFAKEPIPE p_id_t pid; int fds[2]; #endif pipelist *pl; char pfile[MAXPATHLEN]; int fd, dupl; pl = (pipelist *)Xmalloc(sizeof(pipelist)); pl -> file = NULL; pl -> fp = NULL; #ifndef USEFAKEPIPE pl -> trp = NULL; #endif pl -> fd = fdin; pl -> old = -1; #ifndef USEFAKEPIPE if (pipe(fds) < 0) { # ifdef FAKEUNINIT fd = -1; /* fake for -Wuninitialized */ # endif pid = (p_id_t)-1; } else if ((pid = makechild(tty, ppid)) < (p_id_t)0) { # ifdef FAKEUNINIT fd = -1; /* fake for -Wuninitialized */ # endif safeclose(fds[0]); safeclose(fds[1]); } else if (!pid) { if ((fd = newdup(Xdup(STDOUT_FILENO))) < 0 || fds[1] == STDOUT_FILENO || Xdup2(fds[1], STDOUT_FILENO) < 0) { prepareexit(1); Xexit(RET_NOTEXEC); } safeclose(fds[0]); safeclose(fds[1]); pl -> old = fd; } else { if (new) fd = newdup(fds[0]); else { if ((fd = newdup(Xdup(fdin))) < 0 || fds[0] == fdin || Xdup2(fds[0], fdin) < 0) { safeclose(fd); # ifndef NOJOB if (stoppedjob(pid)) /*EMPTY*/; else # endif { VOID_C kill(pid, SIGPIPE); while (!waitjob(pid, NULL, WUNTRACED)) if (interrupted) break; } pid = (p_id_t)-1; } else { # ifndef NOJOB stackjob(pid, 0, fd, NULL); # endif pl -> old = fd; } safeclose(fds[0]); } safeclose(fds[1]); } if (pid >= (p_id_t)0) { pl -> new = fd; pl -> pid = *pidp = pid; pl -> next = pipetop; pipetop = pl; return(fd); } #endif /* !USEFAKEPIPE */ if ((dupl = newdup(Xdup(STDOUT_FILENO))) < 0) { Xfree(pl); return(-1); } if ((fd = newdup(mktmpfile(pfile))) < 0 || fd == STDOUT_FILENO || Xdup2(fd, STDOUT_FILENO) < 0) { Xfree(pl); safeclose(fd); safeclose(dupl); return(-1); } safeclose(fd); if (new) pl -> fd = -1; pl -> file = Xstrdup(pfile); pl -> new = pl -> old = dupl; pl -> pid = *pidp = (p_id_t)0; pl -> next = pipetop; pipetop = pl; return(dupl); } static pipelist **NEAR searchpipe(fd) int fd; { pipelist **prevp; if (fd < 0) return(NULL); prevp = &pipetop; while (*prevp) { if (fd == (*prevp) -> new) break; prevp = &((*prevp) -> next); } if (!*prevp) return(NULL); return(prevp); } static int NEAR reopenpipe(fd, ret) int fd, ret; { pipelist *pl, **prevp; int dupl; if (!(prevp = searchpipe(fd))) return(-1); pl = *prevp; if (pl -> pid > (p_id_t)0) return(fd); if (pl -> old >= 0) { Xdup2(pl -> old, STDOUT_FILENO); safeclose(pl -> old); pl -> old = -1; } if (!(pl -> file)) { prepareexit(1); Xexit(ret); } pl -> ret = ret; if ((fd = newdup(Xopen(pl -> file, O_BINARY | O_RDONLY, 0666))) < 0) { safermtmpfile(pl -> file); Xfree(pl -> file); *prevp = pl -> next; Xfree(pl); return(-1); } if (pl -> fd >= 0) { if ((dupl = newdup(Xdup(pl -> fd))) < 0 || fd == pl -> fd || Xdup2(fd, pl -> fd) < 0) { safeclose(fd); safermtmpfile(pl -> file); Xfree(pl -> file); *prevp = pl -> next; Xfree(pl); return(-1); } safeclose(fd); fd = pl -> old = dupl; } pl -> new = fd; return(fd); } static XFILE *NEAR fdopenpipe(fd) int fd; { pipelist *pl, **prevp; XFILE *fp; if (!(prevp = searchpipe(fd))) return(NULL); pl = *prevp; if (!(fp = Xfdopen(fd, "r"))) { safeclose(fd); safermtmpfile(pl -> file); Xfree(pl -> file); *prevp = pl -> next; Xfree(pl); return(NULL); } pl -> fp = fp; return(fp); } #ifdef DJGPP int closepipe(fd, dupl) int fd, dupl; #else int closepipe(fd) int fd; #endif { #if !MSDOS && defined (NOJOB) wait_pid_t w; #endif pipelist *pl, **prevp; int ret, duperrno; if (!(prevp = searchpipe(fd))) return(-1); duperrno = errno; pl = *prevp; #ifndef USEFAKEPIPE freestree(pl -> trp); Xfree(pl -> trp); #endif #ifndef NOJOB if (pl -> pid > (p_id_t)0 && stoppedjob(pl -> pid) > 0) { errno = duperrno; return(RET_SUCCESS); } #endif if (pl -> old >= 0) { Xdup2(pl-> old, pl -> fd); safeclose(pl -> old); } if (fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO) { if (pl -> fp) safefclose(pl -> fp); else safeclose(pl -> new); } ret = RET_SUCCESS; if (pl -> file) { if (rmtmpfile(pl -> file) < 0) { #ifdef DJGPP if (errno == EACCES && dupl >= 0 && Xclose(dupl) >= 0 && rmtmpfile(pl -> file) >= 0) /*EMPTY*/; else #endif doperror(NULL, pl -> file); } Xfree(pl -> file); ret = pl -> ret; } #if !MSDOS else if (!(pl -> pid)) { prepareexit(1); Xexit(RET_SUCCESS); } else if (pl -> pid > (p_id_t)0) { # ifdef NOJOB VOID_C kill(pl -> pid, SIGPIPE); while (!(ret = waitjob(pl -> pid, &w, WUNTRACED))) if (interrupted) break; if (ret < 0) { if (errno == ECHILD) ret = errno = 0; } else if (WIFSTOPPED(w)) ret = -1; else if (WIFSIGNALED(w) && WTERMSIG(w) != SIGPIPE) ret = -1; # else /* !NOJOB */ ret = waitchild(pl -> pid, NULL); if (ret == 128 + SIGPIPE) ret = RET_SUCCESS; # endif /* !NOJOB */ } #endif /* !MSDOS */ *prevp = pl -> next; Xfree(pl); errno = duperrno; return(ret); } #ifndef _NOUSEHASH static VOID NEAR disphash(VOID_A) { hashlist *hp; char buf[7 + 1]; int i, j; Xfputs("hits cost command", Xstdout); VOID_C fputnl(Xstdout); if (hashtable) for (i = 0; i < MAXHASH; i++) for (hp = hashtable[i]; hp; hp = hp -> next) { j = Xsnprintf(buf, sizeof(buf), "%d", hp -> hits); buf[j++] = (hp -> type & CM_RECALC) ? '*' : ' '; while (j < 7) buf[j++] = ' '; buf[j] = '\0'; VOID_C Xprintf("%s %-7d %k\n", buf, hp -> cost, hp -> path); } } #endif /* !_NOUSEHASH */ char *evalbackquote(arg) CONST char *arg; { XFILE *fp; char *buf; ALLOC_T len; int duptrapok; duptrapok = trapok; trapok = -1; fp = _dopopen(arg); trapok = duptrapok; if (!fp) { if (errno) doperror(NULL, NULL); buf = NULL; ret_status = RET_NOTEXEC; } else if (!(buf = readfile(Xfileno(fp), &len))) { doperror(NULL, NULL); ret_status = RET_FATALERR; } else { #if defined (BASHSTYLE) || defined (STRICTPOSIX) /* bash & POSIX ignore any following newlines */ while (len > 0 && buf[--len] == '\n') buf[len] = '\0'; #else if (len > 0 && buf[--len] == '\n') buf[len] = '\0'; #endif ret_status = closepipe2(Xfileno(fp), -1); } return(buf); } #ifdef NOALIAS int checktype(s, idp, func) CONST char *s; int *idp, func; #else int checktype(s, idp, alias, func) CONST char *s; int *idp, alias, func; #endif { int i; if (!s || !*s) { if (idp) *idp = 0; return(CT_NONE); } else if (!strdelim(s, 1)) { #ifndef NOALIAS if (alias) { for (i = 0; shellalias[i].ident; i++) if (!strcommcmp(s, shellalias[i].ident)) { if (idp) *idp = i; return(CT_ALIAS); } } #endif #ifdef STRICTPOSIX for (i = 0; i < SHBUILTINSIZ; i++) { # ifndef MINIMUMSHELL if (shbuiltinlist[i].flags & BT_DISABLE) continue; # endif if (!(shbuiltinlist[i].flags & BT_POSIXSPECIAL)) continue; if (!strcommcmp(s, shbuiltinlist[i].ident)) { if (idp) *idp = i; return(CT_BUILTIN); } } #endif if (func) { for (i = 0; shellfunc[i].ident; i++) if (!strcommcmp(s, shellfunc[i].ident)) { if (idp) *idp = i; return(CT_FUNCTION); } } #if MSDOS if (_dospath(s) && (!s[2] || (s[2] == _SC_ && !s[3]))) { if (idp) *idp = *s; return(CT_LOGDRIVE); } #endif for (i = 0; i < SHBUILTINSIZ; i++) { #ifndef MINIMUMSHELL if (shbuiltinlist[i].flags & BT_DISABLE) continue; #endif #ifdef STRICTPOSIX if (shbuiltinlist[i].flags & BT_POSIXSPECIAL) continue; #endif if (!strcommcmp(s, shbuiltinlist[i].ident)) { if (idp) *idp = i; return(CT_BUILTIN); } } #ifdef FD if ((i = checkbuiltin(s)) >= 0) { if (idp) *idp = i; return(CT_FDORIGINAL); } if (!shellmode && (i = checkinternal(s)) >= 0) { if (idp) *idp = i; return(CT_FDINTERNAL); } #endif } if (idp) *idp = 0; return(CT_COMMAND); } #if !defined (FDSH) && !defined (_NOCOMPLETE) int completeshellvar(s, len, argc, argvp) CONST char *s; int len, argc; char ***argvp; { char *cp; int i; if (shellvar) for (i = 0; shellvar[i]; i++) { if (strnenvcmp(s, shellvar[i], len) || !(cp = Xstrchr(shellvar[i], '='))) continue; argc = addcompletion(NULL, Xstrndup(shellvar[i], cp - shellvar[i]), argc, argvp); } return(argc); } int completeshellcomm(s, len, argc, argvp) CONST char *s; int len, argc; char ***argvp; { int i; # ifndef NOALIAS for (i = 0; shellalias[i].ident; i++) { if (strncommcmp(s, shellalias[i].ident, len)) continue; argc = addcompletion(shellalias[i].ident, NULL, argc, argvp); } # endif /* !NOALIAS */ for (i = 0; shellfunc[i].ident; i++) { if (strncommcmp(s, shellfunc[i].ident, len)) continue; argc = addcompletion(shellfunc[i].ident, NULL, argc, argvp); } for (i = 0; i < SHBUILTINSIZ; i++) { # ifndef MINIMUMSHELL if (shbuiltinlist[i].flags & BT_DISABLE) continue; # endif if (strncommcmp(s, shbuiltinlist[i].ident, len)) continue; argc = addcompletion(shbuiltinlist[i].ident, NULL, argc, argvp); } # ifdef FD argc = completebuiltin(s, len, argc, argvp); if (!shellmode) argc = completeinternal(s, len, argc, argvp); # endif for (i = 0; i < STATEMENTSIZ; i++) { if (strncommcmp(s, statementlist[i].ident, len)) continue; argc = addcompletion(statementlist[i].ident, NULL, argc, argvp); } return(argc); } #endif /* !FDSH && !_NOCOMPLETE */ #ifdef BASHSTYLE static char *NEAR quotemeta(s) char *s; { char *cp, *buf; ALLOC_T ptr, len; cp = Xstrchr(s, '='); if (!cp || !strpbrk(++cp, METACHAR)) return(s); len = strlen(s) + 2; buf = Xmalloc(len + 1); ptr = cp - s; memcpy(buf, s, ptr); buf[ptr++] = '\''; while (*cp) { if (*cp != '\'') buf[ptr++] = *(cp++); else { len += 3; buf = Xrealloc(buf, len + 1); buf[ptr++] = '\''; buf[ptr++] = PESCAPE; buf[ptr++] = *(cp++); buf[ptr++] = '\''; } } buf[ptr++] = '\''; buf[ptr] = '\0'; Xfree(s); return(buf); } #endif /* BASHSTYLE */ int getsubst(argc, argv, substp, lenp) int argc; char **argv, ***substp; int **lenp; { int i, n, len; *substp = (char **)Xmalloc((argc + 1) * sizeof(char *)); *lenp = (int *)Xmalloc(argc * sizeof(int)); len = 1; for (i = n = 0; i < argc; i++) { len = (freeenviron || len > 0) ? identcheck(argv[i], '=') : 0; if (len > 0) { (*substp)[n] = argv[i]; (*lenp)[n] = len; memmove((char *)(&(argv[i])), (char *)(&(argv[i + 1])), (argc-- - i) * sizeof(char *)); n++; i--; } } (*substp)[n] = NULL; return(argc); } static int NEAR substvar(argv, flags) char **argv; int flags; { char *tmp, *arg; int i; for (i = 0; argv[i]; i++) { if (trapok >= 0) trapok = 1; tmp = evalarg(argv[i], flags); if (trapok >= 0) trapok = 0; if (!tmp) { arg = argv[i]; if (i && *arg && (flags & EA_EVALIFS)) { while (argv[i]) i++; argv = duplvar(argv, 2); argv = checkshellbuiltinargv(i, argv); freevar(argv); } execerror(NULL, arg, ER_BADSUBST, 0); return(-1); } Xfree(argv[i]); argv[i] = tmp; } return(i); } static int NEAR evalargv(comm, typep, contp) command_t *comm; int *typep, *contp; { char *tmp; int i, id, glob; if (!comm) return(-1); else if (comm -> type) { *typep = comm -> type; return(comm -> id); } if (contp && substvar(comm -> argv, EA_BACKQ | EA_EVALIFS) < 0) return(-1); if (trapok >= 0) trapok = 1; #ifdef BASHSTYLE /* bash does not use IFS as a command separator */ comm -> argc = evalifs(comm -> argc, &(comm -> argv), IFS_SET); #else comm -> argc = evalifs(comm -> argc, &(comm -> argv), getifs()); #endif if (!(comm -> argc)) { *typep = CT_NONE; id = 0; } else { stripquote(tmp = Xstrdup(comm -> argv[0]), EA_STRIPQ); *typep = checktype2(tmp, &id, 0, 1); Xfree(tmp); } #ifdef FD if (contp) { i = replaceargs(&(comm -> argc), &(comm -> argv), exportvar, (*typep == CT_COMMAND) ? 1 : 0); if (i < 0) return(-1); *contp = i; } #endif if (noglob) glob = 0; #ifdef FD else if (*typep == CT_FDINTERNAL) glob = 0; #endif else if (*typep != CT_BUILTIN) glob = 1; else if (shbuiltinlist[id].flags & BT_NOGLOB) glob = 0; else glob = 1; if (glob) { #ifdef DEP_FILECONV if (*typep == CT_FDORIGINAL) i = 0; else if (*typep != CT_BUILTIN) i = 1; else if (shbuiltinlist[id].flags & BT_NOKANJIFGET) i = 1; else i = 0; if (i) nokanjifconv++; #endif #if MSDOS comm -> argc = evalglob(comm -> argc, &(comm -> argv), (*typep == CT_COMMAND) ? 0 : EA_STRIPQ); #else comm -> argc = evalglob(comm -> argc, &(comm -> argv), EA_STRIPQ); #endif #ifdef DEP_FILECONV if (i) nokanjifconv--; #endif } else { i = 0; #if MSDOS stripquote(comm -> argv[i++], EA_STRIPQ); if (*typep == CT_COMMAND) while (i < comm -> argc) stripquote(comm -> argv[i++], 0); else #endif while (i < comm -> argc) stripquote(comm -> argv[i++], EA_STRIPQ); } if (trapok >= 0) trapok = 0; return(id); } static char *NEAR evalexternal(comm) command_t *comm; { char *path; int type; type = searchhash(&(comm -> hash), comm -> argv[0], NULL); if (type & CM_NOTFOUND) { execerror(NULL, comm -> argv[0], ER_COMNOFOUND, 1); ret_status = RET_NOTFOUND; return(NULL); } if (restricted && (type & CM_FULLPATH)) { execerror(NULL, comm -> argv[0], ER_RESTRICTED, 2); ret_status = RET_FAIL; return(NULL); } if (type & CM_FULLPATH) { #if MSDOS if (type & CM_ADDEXT) path = comm -> argv[0] = addext(comm -> argv[0], type); else #endif path = comm -> argv[0]; } else { #ifdef _NOUSEHASH path = (char *)(comm -> hash); #else ((comm -> hash) -> hits)++; path = (comm -> hash) -> path; #endif } #if MSDOS if (type & CM_BATCH) comm -> argv = replacebat(&path, comm -> argv); #endif return(path); } static VOID NEAR printindent(n, fp) int n; XFILE *fp; { while (n-- > 0) Xfputs(" ", fp); } static VOID NEAR printnewline(n, fp) int n; XFILE *fp; { if (n < 0) Xfputc(' ', fp); else { VOID_C fputnl(fp); printindent(n, fp); } } static int NEAR printredirect(rp, fp) redirectlist *rp; XFILE *fp; { heredoc_t *hdp; int ret; if (!rp) return(0); ret = printredirect(rp -> next, fp); Xfputc(' ', fp); switch (rp -> type & MD_RDWR) { case MD_READ: if (rp -> fd != STDIN_FILENO) VOID_C Xfprintf(fp, "%d", rp -> fd); Xfputc('<', fp); if (rp -> type & MD_HEREDOC) { Xfputc('<', fp); if (rp -> type & MD_APPEND) Xfputc('-', fp); } break; case MD_WRITE: if (rp -> fd != STDOUT_FILENO) VOID_C Xfprintf(fp, "%d", rp -> fd); if (rp -> type & MD_WITHERR) Xfputc('&', fp); Xfputc('>', fp); if (rp -> type & MD_APPEND) Xfputc('>', fp); #ifndef MINIMUMSHELL else if (rp -> type & MD_FORCED) Xfputc('|', fp); #endif break; case MD_RDWR: if (rp -> fd != STDOUT_FILENO) VOID_C Xfprintf(fp, "%d", rp -> fd); Xfputs("<>", fp); break; default: break; } if (!(rp -> filename)) Xfputc('-', fp); else { if (rp -> type & MD_FILEDESC) Xfputc('&', fp); else Xfputc(' ', fp); if (!(rp -> type & MD_HEREDOC)) argfputs(rp -> filename, fp); else { hdp = (heredoc_t *)(rp -> filename); #ifdef MINIMUMSHELL argfputs(hdp -> filename, fp); #else argfputs(hdp -> eof, fp); #endif ret = 1; } } return(ret); } VOID printstree(trp, indent, fp) syntaxtree *trp; int indent; XFILE *fp; #ifndef MINIMUMSHELL { redirectlist **rlist; int i; rlist = _printstree(trp, NULL, indent, fp); if (rlist) { for (i = 0; rlist[i]; i++) printheredoc(rlist[i], fp); Xfree(rlist); } } static VOID NEAR printheredoc(rp, fp) redirectlist *rp; XFILE *fp; { heredoc_t *hdp; char *buf; int fd; if (!rp) return; printheredoc(rp -> next, fp); if (!(rp -> type & MD_HEREDOC)) return; hdp = (heredoc_t *)(rp -> filename); fd = newdup(Xopen(hdp -> filename, O_BINARY | O_RDONLY, 0666)); if (fd >= 0) { VOID_C fputnl(Xstdout); while ((buf = readline(fd, '\0')) != vnullstr) { if (!buf) break; Xfputs(buf, Xstdout); VOID_C fputnl(Xstdout); Xfree(buf); } safeclose(fd); argfputs(hdp -> eof, fp); } } static redirectlist **NEAR _printstree(trp, rlist, indent, fp) syntaxtree *trp; redirectlist **rlist; int indent; XFILE *fp; #endif /* !MINIMUMSHELL */ { #ifndef MINIMUMSHELL redirectlist **rlist2; int nl; #endif syntaxtree *tmptr; int i, j, id, prev, ind2; #ifdef MINIMUMSHELL if (!trp) return; #else if (!trp) return(rlist); #endif prev = getstatid(tmptr = parentstree(trp)) + 1; #ifndef MINIMUMSHELL if (isopnot(trp)) { Xfputc('!', fp); return(_printstree(trp -> next, rlist, indent, fp)); } rlist2 = NULL; #endif if (trp -> flags & ST_NODE) #ifdef MINIMUMSHELL printstree((syntaxtree *)(trp -> comm), indent, fp); #else rlist2 = _printstree((syntaxtree *)(trp -> comm), NULL, indent, fp); #endif else if (!(trp -> comm)) { if (tmptr && !(tmptr -> next) && prev > 0) { for (i = 0; i < STATEMENTSIZ; i++) { if (!(statementlist[i].type & STT_NEEDNONE)) continue; for (j = 0; j < SMPREV; j++) { if (!(statementlist[i].prev[j])) continue; if (prev == statementlist[i].prev[j]) break; } if (j < SMPREV) break; } if (i < STATEMENTSIZ) { printnewline(indent - 1, fp); Xfputs(statementlist[i].ident, fp); } } } else { if (isstatement(trp -> comm)) { id = (trp -> comm) -> id; i = id - 1; if (id == SM_CHILD) { Xfputs("( ", fp); #ifdef MINIMUMSHELL printstree(statementbody(trp), indent, fp); #else rlist2 = _printstree(statementbody(trp), NULL, indent, fp); #endif Xfputs(" )", fp); } else if (id == SM_STATEMENT) #ifdef MINIMUMSHELL printstree(statementbody(trp), indent, fp); #else rlist2 = _printstree(statementbody(trp), NULL, indent, fp); #endif else { Xfputs(statementlist[i].ident, fp); switch (id) { case SM_THEN: case SM_ELSE: case SM_DO: case SM_RPAREN: case SM_LIST: ind2 = 1; break; case SM_INCASE: if (indent >= 0) indent++; ind2 = 0; break; case SM_CASEEND: if (trp -> next) ind2 = 0; else ind2 = -1; break; case SM_FUNC: #ifdef BASHSTYLE /* bash type pretty print */ ind2 = 0; break; #endif case SM_LPAREN: ind2 = -1; break; default: ind2 = -1; Xfputc(' ', fp); break; } tmptr = statementbody(trp); if (ind2 < 0) ind2 = indent; else { if (indent < 0) ind2 = indent; else ind2 += indent; if (tmptr && tmptr -> comm) printnewline(ind2, fp); } #ifdef MINIMUMSHELL printstree(tmptr, ind2, fp); #else rlist2 = _printstree(tmptr, NULL, ind2, fp); #endif switch (id) { case SM_IF: case SM_ELIF: case SM_WHILE: case SM_UNTIL: case SM_IN: #ifdef BASHSTYLE /* bash type pretty print */ Xfputc(' ', fp); break; #endif case SM_THEN: case SM_RPAREN: if (!(trp -> next)) break; printnewline(indent, fp); break; case SM_FOR: case SM_CASE: Xfputc(' ', fp); break; default: break; } } } else if ((trp -> comm) -> argc > 0) { argfputs((trp -> comm) -> argv[0], fp); for (i = 1; i < (trp -> comm) -> argc; i++) { Xfputc(' ', fp); if (prev == SM_INCASE || prev == SM_CASEEND) Xfputs("| ", fp); argfputs((trp -> comm) -> argv[i], fp); } } #ifdef MINIMUMSHELL printredirect((trp -> comm) -> redp, fp); #else if (printredirect((trp -> comm) -> redp, fp)) { if (!rlist) i = 0; else for (i = 0; rlist[i]; i++) /*EMPTY*/; rlist = (redirectlist **)Xrealloc(rlist, (i + 2) * sizeof(redirectlist *)); rlist[i++] = (trp -> comm) -> redp; rlist[i] = NULL; } #endif } #ifndef MINIMUMSHELL if (rlist2) { if (!rlist) i = 0; else for (i = 0; rlist[i]; i++) /*EMPTY*/; for (j = 0; rlist2[j]; j++) /*EMPTY*/; rlist = (redirectlist **)Xrealloc(rlist, (i + j + 1) * sizeof(redirectlist *)); for (j = 0; rlist2[j]; j++) rlist[i + j] = rlist2[j]; rlist[i + j] = NULL; Xfree(rlist2); } #endif for (id = 0; id < OPELISTSIZ; id++) if (trp -> type == opelist[id].op) break; if (id < OPELISTSIZ && !isopfg(trp)) VOID_C Xfprintf(fp, " %s", opelist[id].symbol); #ifndef MINIMUMSHELL if (!rlist || opelist[id].level < 4) nl = 0; else { for (i = 0; rlist[i]; i++) printheredoc(rlist[i], fp); Xfree(rlist); rlist = NULL; nl = 1; } #endif if (trp -> next && (trp -> next) -> comm) { #ifndef MINIMUMSHELL if (nl) { VOID_C fputnl(fp); printindent(indent, fp); } else #endif if (isopfg(trp)) { #ifdef BASHSTYLE /* bash type pretty print */ Xfputc(';', fp); printnewline(indent, fp); #else if (indent < 0) Xfputc(';', fp); else { VOID_C fputnl(fp); printindent(indent, fp); } #endif } else if (id < OPELISTSIZ) { #ifndef BASHSTYLE /* bash type pretty print */ if (opelist[id].level >= 4) printnewline(indent, fp); else #endif Xfputc(' ', fp); } } #ifndef MINIMUMSHELL else if (nl) /*EMPTY*/; #endif else if (isopfg(trp)) { #ifdef BASHSTYLE /* bash type pretty print */ Xfputc(';', fp); #else if (indent < 0) Xfputc(';', fp); #endif } #ifdef MINIMUMSHELL if (trp -> next) printstree(trp -> next, indent, fp); Xfflush(fp); #else if (trp -> next) rlist = _printstree(trp -> next, rlist, indent, fp); Xfflush(fp); return(rlist); #endif } static VOID NEAR printshfunc(f, fp) shfunctable *f; XFILE *fp; { #ifdef BASHSTYLE /* bash type pretty print */ VOID_C Xfprintf(fp, "%k ()\n", f -> ident); #else VOID_C Xfprintf(fp, "%k()", f -> ident); #endif if (getstatid(statementcheck(f -> func, SM_STATEMENT)) == SM_LIST - 1) printstree(f -> func, 0, fp); else { Xfputs("{\n", fp); if (f -> func) { printindent(1, fp); printstree(f -> func, 1, fp); } Xfputs("\n}", fp); } } int tinygetopt(trp, opt, nump) syntaxtree *trp; CONST char *opt; int *nump; { char **argv; int i, n, f, argc, noopt; argv = (trp -> comm) -> argv; argc = (trp -> comm) -> argc; f = '\0'; noopt = 0; if (*opt == '-') { opt++; noopt++; } for (n = 1; n < argc; n++) { if (!argv[n] || argv[n][0] != '-') break; if (argv[n][1] == '-' && !(argv[n][2])) { n++; break; } for (i = 1; argv[n][i]; i++) { if (Xstrchr(opt, argv[n][i])) /*EMPTY*/; else if (noopt) break; else { execerror(argv, argv[n], ER_BADOPTIONS, 2); return(-1); } f = argv[n][i]; } if (!f) break; } if (nump) *nump = n; return(f); } static int NEAR dochild(trp) syntaxtree *trp; { #if MSDOS # ifdef DEP_PSEUDOPATH int drv; # endif char **svar, **evar, **elist, **rlist, cwd[MAXPATHLEN]; u_long esize; int blevel, clevel; #else /* !MSDOS */ syntaxtree *body; p_id_t pid; #endif /* !MSDOS */ int ret; #if MSDOS if (!Xgetwd(cwd)) return(RET_FAIL); # ifdef DEP_PSEUDOPATH if ((drv = preparedrv(cwd, NULL, NULL)) < 0) { doperror(NULL, cwd); return(RET_FAIL); } # endif svar = shellvar; evar = exportvar; esize = exportsize; elist = exportlist; rlist = ronlylist; blevel = breaklevel; clevel = continuelevel; shellvar = duplvar(shellvar, 0); exportvar = duplvar(exportvar, 0); exportlist = duplvar(exportlist, 0); ronlylist = duplvar(ronlylist, 0); breaklevel = continuelevel = 0; childdepth++; ret = exec_stree(statementbody(trp), 0); childdepth--; freevar(shellvar); freevar(exportvar); freevar(exportlist); freevar(ronlylist); shellvar = svar; exportvar = evar; exportsize = esize; exportlist = elist; ronlylist = rlist; breaklevel = blevel; continuelevel = clevel; if (chdir3(cwd, 1) < 0) ret = RET_FAIL; # ifdef DEP_PSEUDOPATH shutdrv(drv); # endif return(ret); #else /* !MSDOS */ body = statementbody(trp); if ((pid = makechild(1, (p_id_t)-1)) < (p_id_t)0) return(-1); else if (!pid) { childdepth++; # ifndef NOJOB stackjob(mypid, 0, -1, body); # endif ret = exec_stree(body, 0); prepareexit(1); Xexit((ret >= 0) ? ret : RET_NOTEXEC); } else { # ifndef NOJOB stackjob(pid, 0, -1, body); # endif if (isopbg(trp) || isopnown(trp)) return(RET_SUCCESS); ret = waitchild(pid, trp); if (ret == RET_NOTEXEC) ret = -1; if (ret < 0) breaklevel = loopdepth; } return(ret); #endif /* !MSDOS */ } static int NEAR doif(trp) syntaxtree *trp; { syntaxtree *cond, *body; int ret; cond = statementbody(trp); if (!(body = statementcheck(trp -> next, SM_THEN))) return(-1); if ((ret = exec_stree(cond, 1)) < 0 || returnlevel) return(ret); if (interrupted) return(RET_INTR); if (ret_status == RET_SUCCESS) return(exec_stree(body, 0)); if (!(trp = (trp -> next) -> next)) return(RET_SUCCESS); body = statementbody(trp); if (interrupted) return(RET_INTR); if ((trp -> comm) -> id == SM_ELSE) return(exec_stree(body, 0)); if ((trp -> comm) -> id == SM_ELIF) return(doif(trp)); return(seterrno(EINVAL)); } static int NEAR dowhile(trp) syntaxtree *trp; { syntaxtree *cond, *body; int ret, tmp; cond = statementbody(trp); if (!(body = statementcheck(trp -> next, SM_DO))) return(-1); ret = RET_SUCCESS; loopdepth++; for (;;) { if ((tmp = exec_stree(cond, 1)) < 0 || returnlevel) { ret = tmp; break; } if (ret_status != RET_SUCCESS) break; if (interrupted) { ret = RET_INTR; break; } if ((ret = exec_stree(body, 0)) < 0 || returnlevel) break; if (interrupted) { ret = RET_INTR; break; } if (breaklevel) { breaklevel--; break; } if (continuelevel && --continuelevel) break; } loopdepth--; return(ret); } static int NEAR dountil(trp) syntaxtree *trp; { syntaxtree *cond, *body; int ret, tmp; cond = statementbody(trp); if (!(body = statementcheck(trp -> next, SM_DO))) return(-1); ret = RET_SUCCESS; loopdepth++; for (;;) { if ((tmp = exec_stree(cond, 1)) < 0 || returnlevel) { ret = tmp; break; } #ifndef BASHSTYLE /* bash ignores "break" in the "until" condition */ if (breaklevel) { breaklevel--; break; } #endif if (ret_status == RET_SUCCESS) break; if (interrupted) { ret = RET_INTR; break; } if ((ret = exec_stree(body, 0)) < 0 || returnlevel) break; if (interrupted) { ret = RET_INTR; break; } #ifdef BASHSTYLE /* bash ignores "break" in the "until" condition */ if (breaklevel) { breaklevel--; break; } #endif if (continuelevel && --continuelevel) break; } loopdepth--; return(ret); } static int NEAR dofor(trp) syntaxtree *trp; { syntaxtree *var, *body; command_t *comm; char *tmp, *ident, **argv; int i, argc, ret; var = statementbody(trp); body = statementbody(trp -> next); comm = var -> comm; ident = comm -> argv[0]; if (identcheck(ident, '\0') <= 0) { execerror(NULL, ident, ER_NOTIDENT, 0); return(RET_FAIL); } trp = trp -> next; if ((trp -> comm) -> id != SM_IN) argv = duplvar(&(argvar[1]), 0); else { if (!(comm = body -> comm)) return(seterrno(EINVAL)); trp = trp -> next; argv = (char **)Xmalloc((comm -> argc + 1) * sizeof(char *)); for (i = 0; i < comm -> argc; i++) { tmp = evalvararg(comm -> argv[i], EA_BACKQ, 0); if (!tmp) { while (--i >= 0) Xfree(argv[i]); Xfree(argv); return(RET_FAIL); } argv[i] = tmp; } argv[i] = NULL; argc = evalifs(comm -> argc, &argv, getifs()); if (!noglob) { #ifdef DEP_FILECONV nokanjifconv++; #endif argc = evalglob(argc, &argv, EA_STRIPQ); #ifdef DEP_FILECONV nokanjifconv--; #endif } else for (i = 0; i < argc; i++) stripquote(argv[i], EA_STRIPQ); #ifdef FD if (replaceargs(&argc, &argv, NULL, -1) < 0) { freevar(argv); return(-1); } #endif } if (!(body = statementcheck(trp, SM_DO))) { freevar(argv); return(-1); } ret = RET_SUCCESS; loopdepth++; for (i = 0; argv[i]; i++) { if (interrupted) { ret = RET_INTR; break; } if (setenv2(ident, argv[i], 0) < 0) break; if ((ret = exec_stree(body, 0)) < 0 || returnlevel) break; if (interrupted) { ret = RET_INTR; break; } if (breaklevel) { breaklevel--; break; } if (continuelevel && --continuelevel) break; } loopdepth--; freevar(argv); return(ret); } static int NEAR docase(trp) syntaxtree *trp; { syntaxtree *var, *body; command_t *comm; reg_ex_t *re; char *tmp, *key; int i, n, ret; var = statementbody(trp); comm = var -> comm; key = evalvararg(comm -> argv[0], EA_BACKQ | EA_STRIPQLATER, 0); if (!key) return(RET_FAIL); #ifdef FD demacroarg(&key); #endif ret = RET_SUCCESS; for (trp = trp -> next; trp; trp = (trp -> next) -> next) { if (!(trp -> next)) break; if (interrupted) { ret = RET_INTR; break; } var = statementbody(trp); if (!(body = statementcheck(trp -> next, SM_RPAREN))) { ret = -1; break; } if (!(comm = var -> comm)) break; ret = -1; for (i = 0; i < comm -> argc; i++) { tmp = evalvararg(comm -> argv[i], EA_BACKQ, 0); if (!tmp) { ret = RET_FAIL; break; } #ifdef FD demacroarg(&tmp); #endif re = regexp_init(tmp, -1); Xfree(tmp); if (!re) continue; n = regexp_exec(re, key, 0); regexp_free(re); if (n) { ret = exec_stree(body, 0); break; } if (interrupted) { ret = RET_INTR; break; } } if (ret >= 0) break; ret = RET_SUCCESS; } Xfree(key); return(ret); } static int NEAR dolist(trp) syntaxtree *trp; { return(exec_stree(statementbody(trp), 0)); } /*ARGSUSED*/ static int NEAR donull(trp) syntaxtree *trp; { return(RET_SUCCESS); } static int NEAR dobreak(trp) syntaxtree *trp; { int n; if (!loopdepth) return(RET_FAIL); else if ((trp -> comm) -> argc <= 1) breaklevel = 1; else if ((n = isnumeric((trp -> comm) -> argv[1])) < 0) { execerror((trp -> comm) -> argv, (trp -> comm) -> argv[1], ER_BADNUMBER, 0); return(RET_FAIL); } #ifndef BASHSTYLE /* bash ignores "break 0" */ else if (!n) breaklevel = -1; #endif else if (n > loopdepth) breaklevel = loopdepth; else breaklevel = n; return(RET_SUCCESS); } static int NEAR docontinue(trp) syntaxtree *trp; { int n; if (!loopdepth) return(RET_FAIL); else if ((trp -> comm) -> argc <= 1) continuelevel = 1; else if ((n = isnumeric((trp -> comm) -> argv[1])) < 0) { execerror((trp -> comm) -> argv, (trp -> comm) -> argv[1], ER_BADNUMBER, 0); return(RET_FAIL); } #ifndef BASHSTYLE /* bash ignores "break 0" */ else if (!n) continuelevel = -1; #endif else if (n > loopdepth) continuelevel = loopdepth; else continuelevel = n; return(RET_SUCCESS); } static int NEAR doreturn(trp) syntaxtree *trp; { int ret; if (!shfunclevel) { execerror((trp -> comm) -> argv, NULL, ER_CANNOTRET, 0); return(RET_FAIL); } if ((trp -> comm) -> argc <= 1) ret = ret_status; else if ((ret = isnumeric((trp -> comm) -> argv[1])) < 0) { execerror((trp -> comm) -> argv, (trp -> comm) -> argv[1], ER_BADNUMBER, 0); ret = RET_FAIL; #ifdef BASHSTYLE /* bash ignores "return -1" */ return(ret); #endif } returnlevel = shfunclevel; return(ret); } static int NEAR execpath(comm, errexit) command_t *comm; int errexit; { char *path, **evar; path = evalexternal(comm); if (!errexit && !path) return(RET_NOTFOUND); path = Xstrdup(path); evar = exportvar; exportvar = NULL; if (errexit && !path) { #ifdef DEBUG freevar(evar); #endif Xexit2(RET_FAIL); } #ifndef NOJOB if (loginshell && interactive_io) killjob(); #endif prepareexit(1); #ifdef FD prepareexitfd(0); #endif Xexecve2(path, comm -> argv, evar, 0); return(RET_NOTEXEC); } static int NEAR doexec(trp) syntaxtree *trp; { command_t *comm; comm = trp -> comm; if (cancelredirect(comm -> redp) < 0) return(RET_FAIL); if (comm -> argc >= 2) { if (restricted) { execerror(comm -> argv, comm -> argv[1], ER_RESTRICTED, 2); return(RET_FAIL); } Xfree(comm -> argv[0]); memmove((char *)(&(comm -> argv[0])), (char *)(&(comm -> argv[1])), (comm -> argc)-- * sizeof(char *)); searchheredoc(trp, 1); #ifdef BASHSTYLE /* bash ignores the unexecutable external command */ return(execpath(comm, 0)); #else return(execpath(comm, 1)); #endif } if (!isopbg(trp) && !isopnown(trp) && comm -> redp) { if (ttyio < 0) /*EMPTY*/; else if (definput == ttyio && !isatty(STDIN_FILENO)) definput = STDIN_FILENO; else if (definput == STDIN_FILENO && isatty(STDIN_FILENO)) definput = ttyio; } return(RET_SUCCESS); } #ifndef MINIMUMSHELL /*ARGSUSED*/ static int NEAR dologin(trp) syntaxtree *trp; { # if MSDOS return(RET_SUCCESS); # else /* !MSDOS */ searchheredoc(trp, 1); return(execpath(trp -> comm, 0)); # endif /* !MSDOS */ } static int NEAR dologout(trp) syntaxtree *trp; { if ((!loginshell && interactive_io) || exit_status < 0) { execerror((trp -> comm) -> argv, NULL, ER_NOTLOGINSH, 0); return(RET_FAIL); } return(doexit(trp)); } #endif /* !MINIMUMSHELL */ static int NEAR doeval(trp) syntaxtree *trp; { #ifndef MINIMUMSHELL long dupshlineno; #endif syntaxtree *stree; char *cp; int ret; if ((trp -> comm) -> argc <= 1 || !(cp = catvar(&((trp -> comm) -> argv[1]), ' '))) return(RET_SUCCESS); #ifdef BASHSTYLE /* bash displays arguments of "eval", in -v mode */ if (verboseinput) { argfputs(cp, Xstderr); VOID_C fputnl(Xstderr); } #endif #ifndef MINIMUMSHELL dupshlineno = shlineno; setshlineno(1L); #endif trp = stree = newstree(NULL); #ifndef NOJOB childpgrp = (p_id_t)-1; #endif trp = execline(cp, stree, trp, 1); execline((char *)-1, stree, trp, 1); ret = (syntaxerrno) ? RET_SYNTAXERR : ret_status; Xfree(stree); Xfree(cp); #ifndef MINIMUMSHELL setshlineno(dupshlineno); #endif return(ret); } static int NEAR doexit(trp) syntaxtree *trp; { int ret; if ((trp -> comm) -> argc <= 1) ret = ret_status; else if ((ret = isnumeric((trp -> comm) -> argv[1])) < 0) { execerror((trp -> comm) -> argv, (trp -> comm) -> argv[1], ER_BADNUMBER, 0); ret = RET_FAIL; #ifdef BASHSTYLE /* bash ignores "exit -1" */ return(ret); #endif } if (exit_status < 0) exit_status = ret; else Xexit2(ret); return(RET_SUCCESS); } static int NEAR doread(trp) syntaxtree *trp; { char *cp, *next, *buf, *ifs; int n, top, opt, ret; if ((opt = tinygetopt(trp, "N", &top)) < 0) return(RET_FAIL); for (n = top; n < (trp -> comm) -> argc; n++) { if (identcheck((trp -> comm) -> argv[n], '\0') <= 0) { execerror((trp -> comm) -> argv, (trp -> comm) -> argv[n], ER_NOTIDENT, 0); return(RET_FAIL); } } ifs = getifs(); ret = RET_SUCCESS; buf = readline(STDIN_FILENO, opt); if (buf == vnullstr) ret = RET_FAIL; else if (!buf) { if (errno != EINTR) doperror((trp -> comm) -> argv[0], NULL); ret = RET_FAIL; } else if ((trp -> comm) -> argc > top) { cp = buf; for (n = top; n < (trp -> comm) -> argc - 1; n++) { if (!*cp) next = cp; else if (!(next = strpbrk(cp, ifs))) next = cp + strlen(cp); else do { *(next++) = '\0'; } while (Xstrchr(ifs, *next)); if (setenv2((trp -> comm) -> argv[n], cp, 0) < 0) { ret = RET_FAIL; cp = NULL; break; } cp = next; } if (cp && setenv2((trp -> comm) -> argv[n], cp, 0) < 0) ret = RET_FAIL; } #ifdef BASHSTYLE /* bash set the variable REPLY without any argument */ else if (setenv2(ENVREPLY, buf, 0) < 0) ret = RET_FAIL; #endif if (buf != vnullstr) Xfree(buf); return(ret); } static int NEAR doshift(trp) syntaxtree *trp; { int i, n, ret; if ((trp -> comm) -> argc <= 1) n = 1; else if ((n = isnumeric((trp -> comm) -> argv[1])) < 0) { execerror((trp -> comm) -> argv, (trp -> comm) -> argv[1], ER_BADNUMBER, 0); return(RET_FAIL); } else if (!n) return(RET_SUCCESS); for (i = 0; i < n; i++) { if (!argvar[i + 1]) break; Xfree(argvar[i + 1]); } ret = (i >= n) ? RET_SUCCESS : RET_FAIL; n = i; for (i = 0; argvar[i + n + 1]; i++) argvar[i + 1] = argvar[i + n + 1]; argvar[i + 1] = NULL; if (ret != RET_SUCCESS) execerror((trp -> comm) -> argv, NULL, ER_CANNOTSHIFT, 0); return(ret); } static int NEAR doset(trp) syntaxtree *trp; { shfunctable *func; char **var, **argv; int i, n, argc; argc = (trp -> comm) -> argc; argv = (trp -> comm) -> argv; if (argc <= 1) { var = duplvar(shellvar, 0); i = countvar(var); if (i > 1) qsort(var, i, sizeof(char *), cmppath); for (i = 0; var[i]; i++) { #ifdef BASHSTYLE /* bash's "set" quotes the value which includes any meta chacters */ var[i] = quotemeta(var[i]); #endif kanjifputs(var[i], Xstdout); VOID_C fputnl(Xstdout); } freevar(var); func = duplfunc(shellfunc); for (i = 0; func[i].ident; i++) /*EMPTY*/; if (i > 1) qsort(func, i, sizeof(shfunctable), cmpfunc); for (i = 0; func[i].ident; i++) { printshfunc(&(func[i]), Xstdout); VOID_C fputnl(Xstdout); } freefunc(func); return(RET_SUCCESS); } if ((n = getoption(argc, argv, 0)) < 0) return(RET_FAIL); #ifdef BASHSTYLE /* bash makes -e option effective immediately */ errorexit = tmperrorexit; #endif if (n > 2) { if (argc <= 2) { for (i = 0; i < FLAGSSIZ; i++) { if (!(shflaglist[i].ident)) continue; VOID_C Xprintf("%-16.16s%s\n", shflaglist[i].ident, (*(shflaglist[i].var)) ? "on" : "off"); } } else { for (i = 0; i < FLAGSSIZ; i++) { if (!(shflaglist[i].ident)) continue; if (!strcmp(argv[2], shflaglist[i].ident)) break; } if (i >= FLAGSSIZ) { execerror(argv, argv[2], ER_BADOPTIONS, 0); return(RET_FAIL); } setshflag(i, (n <= 3) ? 1 : 0); } n = 3; } if (n >= argc) return(RET_SUCCESS); var = argvar; argvar = (char **)Xmalloc((argc - n + 2) * sizeof(char *)); argvar[0] = Xstrdup(var[0]); for (i = 1; n < argc; i++, n++) argvar[i] = Xstrdup(argv[n]); argvar[i] = NULL; freevar(var); #ifdef DEP_PTY sendparent(TE_SETVAR, &argvar, argvar); #endif return(RET_SUCCESS); } static int NEAR dounset(trp) syntaxtree *trp; { char **argv; int i, n, len, ret; argv = (trp -> comm) -> argv; ret = RET_SUCCESS; for (i = 1; i < (trp -> comm) -> argc; i++) { len = strlen(argv[i]); if (getshellvar(argv[i], len)) n = unset(argv[i], len); else n = unsetshfunc(argv[i], len); if (n < 0) { ret = RET_FAIL; ERRBREAK; } } return(ret); } #ifndef _NOUSEHASH static int NEAR dohash(trp) syntaxtree *trp; { hashlist *hp; int i, n, ret; if ((trp -> comm) -> argc <= 1) { disphash(); return(RET_SUCCESS); } if (!strcmp((trp -> comm) -> argv[1], "-r")) { VOID_C searchhash(NULL, NULL, NULL); return(RET_SUCCESS); } ret = RET_SUCCESS; for (i = 1; i < (trp -> comm) -> argc; i++) { n = searchhash(&hp, (trp -> comm) -> argv[i], NULL); if (n & CM_NOTFOUND) { execerror((trp -> comm) -> argv, (trp -> comm) -> argv[i], ER_NOTFOUND, 1); ret = RET_FAIL; ERRBREAK; } if (!(n & CM_HASH)) continue; hp -> hits = 0; } return(ret); } #endif /* !_NOUSEHASH */ static int NEAR dochdir(trp) syntaxtree *trp; { #ifdef FD int opt, dupphysical_path; #endif char *cp, *tmp, *dir, *path, *next; int n, dlen, len, size; #ifdef FD if ((opt = tinygetopt(trp, "LP", &n)) < 0) return(RET_FAIL); #else n = 1; #endif /* !FD */ if (n < (trp -> comm) -> argc) dir = (trp -> comm) -> argv[n]; else if (!(dir = getconstvar(ENVHOME))) { execerror((trp -> comm) -> argv, (trp -> comm) -> argv[0], ER_NOHOMEDIR, 0); return(RET_FAIL); } else if (!*dir) return(RET_SUCCESS); #ifdef FD dupphysical_path = physical_path; if (opt) physical_path = (opt == 'P') ? 1 : 0; #endif if (isrootdir(dir)) next = NULL; #ifdef DEP_DOSPATH else if (_dospath(dir)) next = NULL; #endif #ifdef FD # ifdef DEP_DOSDRIVE else if (dir[0] && !dir[1] && Xstrchr(".?-@", dir[0])) next = NULL; # else else if (dir[0] && !dir[1] && Xstrchr(".?-", dir[0])) next = NULL; # endif #endif /* FD */ else if ((next = getconstvar(ENVCDPATH))) { tmp = ((cp = strdelim(dir, 0))) ? Xstrndup(dir, cp - dir) : dir; if (isdotdir(tmp)) next = NULL; if (tmp != dir) Xfree(tmp); } if (!next) { if (chdir4(dir, 0, NULL) >= 0) { #ifdef FD physical_path = dupphysical_path; #endif return(RET_SUCCESS); } } else { len = strlen(dir); size = 0; path = NULL; for (cp = next; cp; cp = next) { #ifdef DEP_DOSPATH if (_dospath(cp)) next = Xstrchr(&(cp[2]), PATHDELIM); else #endif next = Xstrchr(cp, PATHDELIM); dlen = (next) ? (next++) - cp : strlen(cp); if (!dlen) tmp = NULL; else { tmp = _evalpath(cp, cp + dlen, 0); dlen = strlen(tmp); } if (dlen + len + 1 + 1 > size) { size = dlen + len + 1 + 1; path = Xrealloc(path, size); } if (tmp) { Xstrncpy(path, tmp, dlen); Xfree(tmp); dlen = strcatdelim(path) - path; } Xstrncpy(&(path[dlen]), dir, len); if (chdir4(path, 1, NULL) >= 0) { kanjifputs(path, Xstdout); VOID_C fputnl(Xstdout); Xfree(path); #ifdef FD physical_path = dupphysical_path; #endif return(RET_SUCCESS); } } Xfree(path); } execerror((trp -> comm) -> argv, dir, ER_BADDIR, 0); #ifdef FD physical_path = dupphysical_path; #endif return(RET_FAIL); } static int NEAR dopwd(trp) syntaxtree *trp; { #ifdef FD int opt; #endif char buf[MAXPATHLEN]; #ifdef FD if ((opt = tinygetopt(trp, "LP", NULL)) < 0) return(RET_FAIL); if (!((opt) ? (opt == 'P') : physical_path)) Xstrcpy(buf, fullpath); else #endif if (!Xgetwd(buf)) { execerror((trp -> comm) -> argv, NULL, ER_CANNOTSTAT, 0); return(RET_FAIL); } kanjifputs(buf, Xstdout); VOID_C fputnl(Xstdout); return(RET_SUCCESS); } static int NEAR dosource(trp) syntaxtree *trp; { #ifdef BASHSTYLE char **var, **dupargvar; #endif hashlist *hp; CONST char *fname; int n, fd; if ((trp -> comm) -> argc <= 1) return(RET_SUCCESS); fname = (trp -> comm) -> argv[1]; n = searchhash(&hp, fname, NULL); if (restricted && (n & CM_FULLPATH)) { execerror((trp -> comm) -> argv, fname, ER_RESTRICTED, 2); return(RET_FAIL); } if (n & CM_NOTFOUND) { execerror((trp -> comm) -> argv, fname, ER_NOTFOUND, 1); return(RET_FAIL); } if ((fd = newdup(Kopen(fname, O_TEXT | O_RDONLY, 0666))) < 0) { doperror((trp -> comm) -> argv[0], fname); return(RET_FAIL); } #ifdef BASHSTYLE /* bash sets positional parameters with source arguments */ if ((trp -> comm) -> argc > 2) { dupargvar = argvar; argvar = (char **)Xmalloc((trp -> comm) -> argc * sizeof(char *)); argvar[0] = Xstrdup(dupargvar[0]); for (n = 1; n < (trp -> comm) -> argc - 1; n++) argvar[n] = Xstrdup((trp -> comm) -> argv[n + 1]); argvar[n] = NULL; var = argvar; sourcefile(fd, fname, 0); safeclose(fd); if (var != argvar) freevar(dupargvar); else { freevar(argvar); argvar = dupargvar; } } else #endif /* BASHSTYLE */ { sourcefile(fd, fname, 0); safeclose(fd); } return(ret_status); } static int NEAR expandlist(varp, ident) char ***varp; CONST char *ident; { #ifndef MINIMUMSHELL char *cp; #endif int len; #ifdef MINIMUMSHELL len = identcheck(ident, '\0'); #else len = identcheck(ident, '='); #endif if (!len) { execerror(NULL, ident, ER_NOTIDENT, 0); return(-1); } #ifndef MINIMUMSHELL else if (len < 0) len = -len; else if (_putshellvar(cp = Xstrdup(ident), len) < 0) { Xfree(cp); return(-1); } #endif *varp = expandvar(*varp, ident, len); return(len); } int setexport(ident) CONST char *ident; { int i, len; if ((len = expandlist(&exportlist, ident)) < 0) return(-1); if ((i = searchvar(shellvar, ident, len, '=')) >= 0) exportvar = putvar(exportvar, Xstrdup(shellvar[i]), len); return(len); } int setronly(ident) CONST char *ident; { return(expandlist(&ronlylist, ident)); } static int NEAR doexport(trp) syntaxtree *trp; { char **argv; int i, n, ret; argv = (trp -> comm) -> argv; if ((trp -> comm) -> argc <= 1) { for (i = 0; exportlist[i]; i++) VOID_C Xprintf("export %k\n", exportlist[i]); return(RET_SUCCESS); } ret = RET_SUCCESS; for (n = 1; n < (trp -> comm) -> argc; n++) { if (setexport(argv[n]) < 0) { ret = RET_FAIL; ERRBREAK; } #ifdef DEP_PTY sendparent(TE_SETEXPORT, argv[n]); #endif } return(ret); } static int NEAR doreadonly(trp) syntaxtree *trp; { char **argv; int i, n, ret; argv = (trp -> comm) -> argv; if ((trp -> comm) -> argc <= 1) { for (i = 0; ronlylist[i]; i++) { VOID_C Xprintf("readonly %k\n", ronlylist[i]); } return(RET_SUCCESS); } ret = RET_SUCCESS; for (n = 1; n < (trp -> comm) -> argc; n++) { if (setronly(argv[n]) < 0) { ret = RET_FAIL; ERRBREAK; } #ifdef DEP_PTY sendparent(TE_SETRONLY, argv[n]); #endif } return(ret); } /*ARGSUSED*/ static int NEAR dotimes(trp) syntaxtree *trp; { time_t usrtime, systime; #ifdef USEGETRUSAGE struct rusage ru; getrusage(RUSAGE_CHILDREN, &ru); usrtime = ru.ru_utime.tv_sec; systime = ru.ru_stime.tv_sec; #else /* !USEGETRUSAGE */ # ifdef USETIMES struct tms buf; int clk; times(&buf); clk = CLKPERSEC; usrtime = buf.tms_cutime / clk; if (buf.tms_cutime % clk > clk / 2) usrtime++; systime = buf.tms_cstime / clk; if (buf.tms_cstime % clk > clk / 2) systime++; # else usrtime = systime = (time_t)0; # endif #endif /* !USEGETRUSAGE */ VOID_C Xprintf("%dm%ds %dm%ds\n", (int)(usrtime / 60), (int)(usrtime % 60), (int)(systime / 60), (int)(systime % 60)); return(RET_SUCCESS); } /*ARGSUSED*/ static int NEAR dowait(trp) syntaxtree *trp; { #if MSDOS return(RET_SUCCESS); #else /* !MSDOS */ char *s; p_id_t pid; # ifndef NOJOB int i, n; # endif if ((trp -> comm) -> argc <= 1) { # ifdef NOJOB pid = lastpid; # else for (;;) { for (n = 0; n < maxjobs; n++) { if (!(joblist[n].pids)) continue; i = joblist[n].npipe; if (!(joblist[n].stats[i])) break; } if (n >= maxjobs) return(RET_SUCCESS); VOID_C waitchild(joblist[n].pids[i], NULL); } # endif } else { s = (trp -> comm) -> argv[1]; # ifndef NOJOB if (*s == '%') { checkjob(NULL); if ((n = getjob(s)) < 0) pid = (p_id_t)-1; else { i = joblist[n].npipe; pid = joblist[n].pids[i]; } } else # endif /* !NOJOB */ if ((pid = isnumeric(s)) < (p_id_t)0) { execerror((trp -> comm) -> argv, s, ER_BADNUMBER, 0); return(RET_FAIL); } # ifndef NOJOB else { checkjob(NULL); if (!joblist || (n = searchjob(pid, &i)) < 0) { pid = (p_id_t)-1; # ifdef FAKEUNINIT n = -1; /* fake for -Wuninitialized */ # endif } } if (pid < (p_id_t)0) { execerror((trp -> comm) -> argv, s, ER_NOSUCHJOB, 2); return(RET_FAIL); } if (joblist[n].stats[i]) return(RET_SUCCESS); # endif /* !NOJOB */ } return(waitchild(pid, NULL)); #endif /* !MSDOS */ } static int NEAR doumask(trp) syntaxtree *trp; { char *s; int i, n; if ((trp -> comm) -> argc <= 1) { n = umask(022); VOID_C umask(n); #ifdef BASHSTYLE VOID_C Xprintf("%03o\n", n & 0777); #else VOID_C Xprintf("%04o\n", n & 0777); #endif } else { s = (trp -> comm) -> argv[1]; n = 0; for (i = 0; s[i] >= '0' && s[i] <= '7'; i++) n = (n << 3) + s[i] - '0'; #ifdef BASHSTYLE if (n & ~0777) { execerror((trp -> comm) -> argv, s, ER_NUMOUTRANGE, 0); return(RET_FAIL); } #else n &= 0777; #endif VOID_C umask(n); } return(RET_SUCCESS); } /*ARGSUSED*/ static int NEAR doulimit(trp) syntaxtree *trp; { #ifdef USERESOURCEH struct rlimit lim; XFILE *fp; u_long flags; int i, j, n, err, hs, res, inf; #endif #if defined (USERESOURCEH) || defined (USEULIMITH) long val; char **argv; int argc; #endif #if !defined (USERESOURCEH) && !defined (USEULIMITH) execerror((trp -> comm) -> argv, NULL, ER_BADULIMIT, 1); return(RET_FAIL); #else /* USERESOURCEH || USEULIMITH */ argc = (trp -> comm) -> argc; argv = (trp -> comm) -> argv; # ifdef USERESOURCEH flags = (u_long)0; err = hs = 0; n = 1; if (argc > 1 && argv[1][0] == '-') { for (i = 1; !err && argv[1][i]; i++) switch (argv[1][i]) { case 'a': flags = ((u_long)1 << ULIMITSIZ) - 1; break; case 'H': hs |= 1; break; case 'S': hs |= 2; break; default: for (j = 0; j < ULIMITSIZ; j++) if (argv[1][i] == ulimitlist[j].opt) break; if (j >= ULIMITSIZ) err = 1; else flags |= ((u_long)1 << j); break; } n++; } res = -1; if (!flags) for (i = 0, flags = (u_long)1; i < ULIMITSIZ; i++, flags <<= 1) { if (ulimitlist[i].res == RLIMIT_FSIZE) { res = i; break; } } else for (i = 0; i < ULIMITSIZ; i++) { if (flags & ((u_long)1 << i)) { if (res < 0) res = i; else { res = -1; break; } } } # ifdef FAKEUNINIT val = 0L; /* fake for -Wuninitialized */ # endif if (n >= argc) { # ifdef FAKEUNINIT inf = 0; /* fake for -Wuninitialized */ # endif if (!hs) hs = 2; } else { inf = 0; if (!hs) hs = (1 | 2); if (res < 0) err = 1; else if (!strcmp(argv[n], UNLIMITED)) inf = 1; else { if ((val = isnumeric(argv[n])) < 0L) { execerror(argv, argv[n], ER_BADULIMIT, 1); return(RET_FAIL); } val *= ulimitlist[res].unit; } } if (err) { # ifdef BASHSTYLE fp = Xstderr; # else fp = Xstdout; # endif VOID_C Xfprintf(fp, "usage: %k [ -HSa", argv[0]); for (j = 0; j < ULIMITSIZ; j++) Xfputc(ulimitlist[j].opt, fp); Xfputs(" ] [ limit ]", fp); VOID_C fputnl(fp); # ifdef BASHSTYLE return(RET_SYNTAXERR); # else return(RET_SUCCESS); # endif } if (n >= argc) { for (i = 0; i < ULIMITSIZ; i++) if (flags & ((u_long)1 << i)) { if (res < 0) VOID_C Xprintf("%s ", ulimitlist[i].mes); if (getrlimit(ulimitlist[i].res, &lim) < 0) { execerror(argv, NULL, ER_BADULIMIT, 1); return(RET_FAIL); } if (hs & 2) { if (lim.rlim_cur == RLIM_INFINITY) Xfputs(UNLIMITED, Xstdout); else if (lim.rlim_cur) VOID_C Xprintf("%ld", lim.rlim_cur / ulimitlist[i].unit); } if (hs & 1) { if (hs & 2) Xfputc(':', Xstdout); if (lim.rlim_max == RLIM_INFINITY) Xfputs(UNLIMITED, Xstdout); else if (lim.rlim_max) VOID_C Xprintf("%ld", lim.rlim_max / ulimitlist[i].unit); } VOID_C fputnl(Xstdout); } } else { if (getrlimit(ulimitlist[res].res, &lim) < 0) { execerror(argv, NULL, ER_BADULIMIT, 1); return(RET_FAIL); } if (hs & 1) lim.rlim_max = (inf) ? RLIM_INFINITY : val; if (hs & 2) lim.rlim_cur = (inf) ? RLIM_INFINITY : val; if (setrlimit(ulimitlist[res].res, &lim) < 0) { execerror(argv, NULL, ER_BADULIMIT, 1); return(RET_FAIL); } } # else /* !USERESOURCEH */ if (argc <= 1) { if ((val = ulimit(UL_GETFSIZE, 0L)) < 0L) { execerror(argv, NULL, ER_BADULIMIT, 1); return(RET_FAIL); } if (val == RLIM_INFINITY) Xfputs(UNLIMITED, Xstdout); else VOID_C Xprintf("%ld", val * 512L); VOID_C fputnl(Xstdout); } else { if (!strcmp(argv[1], UNLIMITED)) val = RLIM_INFINITY; else { if ((val = isnumeric(argv[1])) < 0L) { execerror(argv, argv[1], ER_BADULIMIT, 1); return(RET_FAIL); } val /= 512L; } if (ulimit(UL_SETFSIZE, val) < 0L) { execerror(argv, NULL, ER_BADULIMIT, 1); return(RET_FAIL); } } # endif /* !USERESOURCEH */ return(RET_SUCCESS); #endif /* USERESOURCEH || USEULIMITH */ } static int NEAR dotrap(trp) syntaxtree *trp; { char *comm, **argv; int i, n, sig; argv = (trp -> comm) -> argv; if ((trp -> comm) -> argc <= 1) { for (i = 0; i < NSIG; i++) { if ((trapmode[i] & TR_STAT) != TR_TRAP) continue; VOID_C Xprintf("%d: %k\n", i, trapcomm[i]); } return(RET_SUCCESS); } n = 1; comm = (isnumeric(argv[n]) < 0) ? argv[n++] : NULL; for (; n < (trp -> comm) -> argc; n++) { if ((sig = isnumeric(argv[n])) < 0) { execerror(argv, argv[n], ER_BADNUMBER, 0); return(RET_FAIL); } if (sig >= NSIG) { execerror(argv, argv[n], ER_BADTRAP, 0); return(RET_FAIL); } if (!sig) { trapmode[0] = (comm) ? TR_TRAP : 0; Xfree(trapcomm[0]); trapcomm[0] = Xstrdup(comm); continue; } for (i = 0; signallist[i].sig >= 0; i++) if (sig == signallist[i].sig) break; if (signallist[i].sig < 0 || (signallist[i].flags & TR_NOTRAP)) { execerror(argv, argv[n], ER_BADTRAP, 0); return(RET_FAIL); } signal2(sig, SIG_IGN); Xfree(trapcomm[sig]); if (!comm) { trapmode[sig] = signallist[i].flags; if (trapmode[sig] & TR_BLOCK) signal2(sig, (sigcst_t)(signallist[i].func)); else signal2(sig, oldsigfunc[sig]); trapcomm[sig] = NULL; } else { trapmode[sig] = TR_TRAP; trapcomm[sig] = Xstrdup(comm); if ((signallist[i].flags & TR_STAT) == TR_STOP) signal2(sig, SIG_DFL); else signal2(sig, (sigcst_t)(signallist[i].func)); } } return(RET_SUCCESS); } #ifndef NOJOB static int NEAR dojobs(trp) syntaxtree *trp; { return(posixjobs(trp)); } static int NEAR dofg(trp) syntaxtree *trp; { return(posixfg(trp)); } static int NEAR dobg(trp) syntaxtree *trp; { return(posixbg(trp)); } static int NEAR dodisown(trp) syntaxtree *trp; { char *s; int n; s = ((trp -> comm) -> argc > 1) ? (trp -> comm) -> argv[1] : NULL; checkjob(NULL); if ((n = getjob(s)) < 0) { execerror((trp -> comm) -> argv, (trp -> comm) -> argv[1], (n < -1) ? ER_TERMINATED : ER_NOSUCHJOB, 2); return(RET_FAIL); } freejob(n); return(RET_SUCCESS); } #endif /* !NOJOB */ int typeone(s, fp) CONST char *s; XFILE *fp; { hashlist *hp; int type, id; kanjifputs(s, fp); type = checktype2(s, &id, 1, 1); if (type == CT_BUILTIN) Xfputs(" is a shell builtin", fp); #ifdef FD else if (type == CT_FDORIGINAL) Xfputs(" is a FDclone builtin", fp); else if (type == CT_FDINTERNAL) Xfputs(" is a FDclone internal", fp); #endif #if MSDOS else if (type == CT_LOGDRIVE) Xfputs(" is a change drive command", fp); #endif else if (type == CT_FUNCTION) { Xfputs(" is a function\n", fp); printshfunc(&(shellfunc[id]), fp); } #ifndef NOALIAS else if (type == CT_ALIAS) VOID_C Xfprintf(fp, " is a aliased to `%k'", shellalias[id].comm); #endif else { type = searchhash(&hp, s, NULL); #ifdef _NOUSEHASH if (!(type & CM_FULLPATH)) s = (char *)hp; #else if (type & CM_HASH) s = hp -> path; #endif if (restricted && (type & CM_FULLPATH)) Xfputs(": restricted", fp); else if ((type & CM_NOTFOUND) || Xaccess(s, X_OK) < 0) { Xfputs(" not found", fp); VOID_C fputnl(fp); return(-1); } else VOID_C Xfprintf(fp, " is %k", s); } VOID_C fputnl(fp); return(0); } static int NEAR dotype(trp) syntaxtree *trp; { int i, ret; if ((trp -> comm) -> argc <= 1) return(RET_SUCCESS); #ifdef BASHSTYLE ret = RET_FAIL; #else ret = RET_SUCCESS; #endif for (i = 1; i < (trp -> comm) -> argc; i++) { if (typeone((trp -> comm) -> argv[i], Xstdout) >= 0) #ifdef BASHSTYLE ret = RET_SUCCESS; #else /*EMPTY*/; else ret = RET_FAIL; #endif } return(ret); } #ifdef DOSCOMMAND static int NEAR dodir(trp) syntaxtree *trp; { return(doscomdir((trp -> comm) -> argc, (trp -> comm) -> argv)); } static int NEAR domkdir(trp) syntaxtree *trp; { return(doscommkdir((trp -> comm) -> argc, (trp -> comm) -> argv)); } static int NEAR dormdir(trp) syntaxtree *trp; { return(doscomrmdir((trp -> comm) -> argc, (trp -> comm) -> argv)); } static int NEAR doerase(trp) syntaxtree *trp; { return(doscomerase((trp -> comm) -> argc, (trp -> comm) -> argv)); } static int NEAR dorename(trp) syntaxtree *trp; { return(doscomrename((trp -> comm) -> argc, (trp -> comm) -> argv)); } static int NEAR docopy(trp) syntaxtree *trp; { return(doscomcopy((trp -> comm) -> argc, (trp -> comm) -> argv)); } static int NEAR docls(trp) syntaxtree *trp; { return(doscomcls((trp -> comm) -> argc, (trp -> comm) -> argv)); } static int NEAR dodtype(trp) syntaxtree *trp; { return(doscomtype((trp -> comm) -> argc, (trp -> comm) -> argv)); } #endif /* DOSCOMMAND */ #ifndef NOALIAS static int NEAR doalias(trp) syntaxtree *trp; { return(posixalias(trp)); } static int NEAR dounalias(trp) syntaxtree *trp; { return(posixunalias(trp)); } #endif /* NOALIAS */ static int NEAR doecho(trp) syntaxtree *trp; { int i, n, opt; n = 1; if ((opt = tinygetopt(trp, "-nN", NULL)) < 0) return(RET_FAIL); if (opt) n++; for (i = n; i < (trp -> comm) -> argc; i++) { if (i > n) Xfputc(' ', Xstdout); if ((trp -> comm) -> argv[i]) argfputs((trp -> comm) -> argv[i], Xstdout); } if (opt == 'n') /*EMPTY*/; else if (opt == 'N') Xfputs("\r\n", Xstdout); else VOID_C fputnl(Xstdout); Xfflush(Xstdout); return(RET_SUCCESS); } #ifndef MINIMUMSHELL static int NEAR dokill(trp) syntaxtree *trp; { return(posixkill(trp)); } static int NEAR dotest(trp) syntaxtree *trp; { return(posixtest(trp)); } #endif /* !MINIMUMSHELL */ #ifndef NOPOSIXUTIL /*ARGSUSED*/ static int NEAR dofalse(trp) syntaxtree *trp; { return(RET_FAIL); } static int NEAR docommand(trp) syntaxtree *trp; { return(posixcommand(trp)); } static int NEAR dogetopts(trp) syntaxtree *trp; { return(posixgetopts(trp)); } /*ARGSUSED*/ static int NEAR donewgrp(trp) syntaxtree *trp; { #if MSDOS return(RET_SUCCESS); #else /* !MSDOS */ searchheredoc(trp, 1); return(execpath(trp -> comm, 0)); #endif /* !MSDOS */ } # if 0 /* exists in FD original builtin */ static int NEAR dofc(trp) syntaxtree *trp; { return(RET_SUCCESS); } # endif #endif /* NOPOSIXUTIL */ #ifndef MINIMUMSHELL static int NEAR getworkdir(path) char *path; { # ifdef FD if (underhome(&(path[1]))) path[0] = '~'; else Xstrcpy(path, fullpath); # else if (!Xgetwd(path)) { execerror(NULL, NULL, ER_CANNOTSTAT, 0); return(-1); } # endif return(0); } static int NEAR dopushd(trp) syntaxtree *trp; { char *cp, path[MAXPATHLEN]; int n; if (getworkdir(path) < 0) return(RET_FAIL); if ((trp -> comm) -> argc < 2) { if (!dirstack || !dirstack[0]) { execerror((trp -> comm) -> argv, NULL, ER_DIREMPTY, 2); return(RET_FAIL); } cp = evalpath(Xstrdup(dirstack[0]), 0); n = chdir4(cp, 1, NULL); Xfree(cp); if (n < 0) { execerror((trp -> comm) -> argv, dirstack[0], ER_BADDIR, 0); return(RET_FAIL); } Xfree(dirstack[0]); # ifdef DEP_PTY sendparent(TE_POPVAR, &dirstack); # endif } else { if (chdir4((trp -> comm) -> argv[1], 0, NULL) < 0) { execerror((trp -> comm) -> argv, (trp -> comm) -> argv[1], ER_BADDIR, 0); return(RET_FAIL); } n = countvar(dirstack); dirstack = (char **)Xrealloc(dirstack, (n + 1 + 1) * sizeof(char *)); memmove((char *)&(dirstack[1]), (char *)&(dirstack[0]), n * sizeof(char *)); dirstack[n + 1] = NULL; } dirstack[0] = Xstrdup(path); dodirs(trp); # ifdef DEP_PTY sendparent(TE_PUSHVAR, &dirstack, path); # endif return(RET_SUCCESS); } static int NEAR dopopd(trp) syntaxtree *trp; { char *cp; int n; if (!dirstack || !dirstack[0]) { execerror((trp -> comm) -> argv, NULL, ER_DIREMPTY, 2); return(RET_FAIL); } cp = evalpath(Xstrdup(dirstack[0]), 0); n = chdir4(cp, 1, NULL); Xfree(cp); if (n < 0) { execerror((trp -> comm) -> argv, dirstack[0], ER_BADDIR, 0); return(RET_FAIL); } n = countvar(dirstack); Xfree(dirstack[0]); memmove((char *)&(dirstack[0]), (char *)&(dirstack[1]), n * sizeof(char *)); dodirs(trp); # ifdef DEP_PTY sendparent(TE_POPVAR, &dirstack); # endif return(RET_SUCCESS); } /*ARGSUSED*/ static int NEAR dodirs(trp) syntaxtree *trp; { char path[MAXPATHLEN]; int i; if (getworkdir(path) < 0) return(RET_FAIL); kanjifputs(path, Xstdout); if (dirstack) for (i = 0; dirstack[i]; i++) VOID_C Xprintf(" %k", dirstack[i]); VOID_C fputnl(Xstdout); return(RET_SUCCESS); } static int NEAR doenable(trp) syntaxtree *trp; { char **argv; int i, j, n, ret; argv = (trp -> comm) -> argv; n = 1; if ((trp -> comm) -> argc > 1 && argv[n][0] == '-' && argv[n][1] == 'n' && !(argv[n][2])) n++; ret = RET_SUCCESS; if (n >= (trp -> comm) -> argc) for (j = 0; j < SHBUILTINSIZ; j++) { if (n == 1) { if (shbuiltinlist[j].flags & BT_DISABLE) continue; } else { if (!(shbuiltinlist[j].flags & BT_DISABLE)) continue; } for (i = 0; i < (trp -> comm) -> argc; i++) VOID_C Xprintf("%k ", argv[i]); VOID_C Xprintf("%k\n", shbuiltinlist[j].ident); } else for (i = n; i < (trp -> comm) -> argc; i++) { for (j = 0; j < SHBUILTINSIZ; j++) if (!strcommcmp(argv[i], shbuiltinlist[j].ident)) break; if (j >= SHBUILTINSIZ) { execerror(argv, argv[i], ER_COMNOFOUND, 1); ret = RET_FAIL; continue; } if (n == 1) shbuiltinlist[j].flags &= ~BT_DISABLE; else shbuiltinlist[j].flags |= BT_DISABLE; } return(ret); } static int NEAR dobuiltin(trp) syntaxtree *trp; { char **argv; int i, ret, argc; argc = (trp -> comm) -> argc; argv = (trp -> comm) -> argv; if (interrupted) return(RET_INTR); if (argc <= 1) return(ret_status); for (i = 0; i < SHBUILTINSIZ; i++) { if (shbuiltinlist[i].flags & BT_DISABLE) continue; if (!strcommcmp(argv[1], shbuiltinlist[i].ident)) break; } if (i >= SHBUILTINSIZ) { execerror(argv, argv[1], ER_COMNOFOUND, 1); return(RET_FAIL); } if (restricted && (shbuiltinlist[i].flags & BT_RESTRICT)) { execerror(argv, argv[1], ER_RESTRICTED, 0); return(RET_FAIL); } if (!shbuiltinlist[i].func) return(RET_FAIL); (trp -> comm) -> argc--; (trp -> comm) -> argv++; ret = (*(shbuiltinlist[i].func))(trp); (trp -> comm) -> argc = argc; (trp -> comm) -> argv = argv; return(ret); } static int NEAR doaddcr(trp) syntaxtree *trp; { CONST char *fname; char *buf; int n, fd, ret, opt; if ((opt = tinygetopt(trp, "1", &n)) < 0) return(RET_FAIL); fname = (trp -> comm) -> argv[n]; if (!fname) fd = STDIN_FILENO; else if ((fd = newdup(Kopen(fname, O_TEXT | O_RDONLY, 0666))) < 0) { doperror((trp -> comm) -> argv[0], fname); return(RET_FAIL); } ret = RET_SUCCESS; while ((buf = readline(fd, 'N')) != vnullstr) { if (!buf) { if (errno != EINTR) doperror((trp -> comm) -> argv[0], fname); ret = RET_FAIL; break; } Xfputs(buf, Xstdout); Xfree(buf); Xfputs("\r\n", Xstdout); Xfflush(Xstdout); if (opt == '1') break; } safeclose(fd); return(ret); } #endif /* !MINIMUMSHELL */ #ifdef WITHSOCKET static int NEAR doaccept(trp) syntaxtree *trp; { CONST char *cp; int s, fd; if (!(cp = (trp -> comm) -> argv[1])) s = STDIN_FILENO; else if ((s = isnumeric(cp)) < 0) { execerror((trp -> comm) -> argv, cp, ER_BADNUMBER, 0); return(RET_FAIL); } if (issocket(s) < 0) { execerror((trp -> comm) -> argv, cp, ER_NOTSOCKET, 2); return(RET_FAIL); } if ((fd = sockaccept(s, SCK_THROUGHPUT)) < 0) { doperror((trp -> comm) -> argv[0], cp); return(RET_FAIL); } s = Xdup2(fd, s); safeclose(fd); if (s < 0) { doperror((trp -> comm) -> argv[0], cp); return(RET_FAIL); } return(RET_SUCCESS); } static int NEAR dosocketinfo(trp) syntaxtree *trp; { char addr[SCK_ADDRSIZE + 1]; CONST char *cp; int n, s, opt, port; if ((opt = tinygetopt(trp, "apAP", &n)) < 0) return(RET_FAIL); if (!(cp = (trp -> comm) -> argv[n])) s = STDIN_FILENO; else if ((s = isnumeric(cp)) < 0) { execerror((trp -> comm) -> argv, cp, ER_BADNUMBER, 0); return(RET_FAIL); } if (issocket(s) < 0) { execerror((trp -> comm) -> argv, NULL, ER_NOTSOCKET, 2); return(RET_FAIL); } if (!Xisupper(opt)) { if (getsockinfo(s, addr, sizeof(addr), &port, 1) >= 0) { if (opt == 'a') VOID_C Xprintf("%s\n", addr); else if (opt == 'p') VOID_C Xprintf("%d\n", port); else VOID_C Xprintf("Remote: %s:%d\n", addr, port); } # ifdef ENOTCONN else if (errno == ENOTCONN) { if (opt) VOID_C Xprintf("%s\n", nullstr); else VOID_C Xprintf("Remote: (not connected)\n"); } # endif else { execerror((trp -> comm) -> argv, NULL, ER_INVALSOCKET, 2); return(RET_FAIL); } } if (!Xislower(opt)) { if (getsockinfo(s, addr, sizeof(addr), &port, 0) >= 0) { if (opt == 'A') VOID_C Xprintf("%s\n", addr); else if (opt == 'P') VOID_C Xprintf("%d\n", port); else VOID_C Xprintf("Local: %s:%d\n", addr, port); } else { execerror((trp -> comm) -> argv, NULL, ER_INVALSOCKET, 2); return(RET_FAIL); } } return(RET_SUCCESS); } #endif /* WITHSOCKET */ #ifdef FD static int NEAR dofd(trp) syntaxtree *trp; { int n, mode; if (!shellmode || exit_status < 0) { execerror((trp -> comm) -> argv, NULL, ER_RECURSIVEFD, 0); return(RET_FAIL); } else if (dumbterm > 1) { execerror((trp -> comm) -> argv, getconstvar(ENVTERM), ER_INVALTERMFD, 1); return(RET_FAIL); } else if (!interactive || nottyout) { execerror((trp -> comm) -> argv, NULL, ER_INVALTERMFD, 1); return(RET_FAIL); } else { n = sigvecset(1); ttyiomode(0); mode = termmode(1); shellmode = 0; main_fd(&((trp -> comm) -> argv[1]), 1); shellmode = 1; VOID_C termmode(mode); stdiomode(); VOID_C fputnl(Xstderr); sigvecset(n); } return(RET_SUCCESS); } #endif /* FD */ static int NEAR doshfunc(trp, n) syntaxtree *trp; int n; { #ifndef MINIMUMSHELL long dupshlineno; #endif char **avar; int ret; #ifndef MINIMUMSHELL dupshlineno = shlineno; #endif avar = argvar; argvar = duplvar((trp -> comm) -> argv, 0); shfunclevel++; ret = exec_stree(shellfunc[n].func, 0); if (returnlevel >= shfunclevel) returnlevel = 0; shfunclevel--; freevar(argvar); argvar = avar; #ifndef MINIMUMSHELL setshlineno(dupshlineno); #endif return(ret); } #ifndef FDSH char **getsimpleargv(trp) syntaxtree *trp; { char **argv; if ((trp -> flags & ST_NODE) || trp -> cont) return(NULL); if (!(trp -> comm) || isstatement(trp -> comm)) return(NULL); argv = (trp -> comm) -> argv; while (trp -> next) { trp = trp -> next; if ((trp -> flags & ST_NODE) || trp -> comm) return(NULL); } return(argv); } #endif /* !FDSH */ #ifdef SHOWSTREE static VOID NEAR show_stree(trp, lvl) syntaxtree *trp; int lvl; { redirectlist *rp; int i, id; if (!trp) { printindent(lvl, Xstdout); Xfputs("(null):", Xstdout); VOID_C fputnl(Xstdout); return; } if (trp -> flags & ST_NODE) { printindent(lvl, Xstdout); Xfputs("node:\n", Xstdout); show_stree((syntaxtree *)(trp -> comm), lvl + 1); } else if (!(trp -> comm)) { printindent(lvl, Xstdout); Xfputs("body: NULL", Xstdout); VOID_C fputnl(Xstdout); } else { printindent(lvl, Xstdout); if (isstatement(trp -> comm)) { id = (trp -> comm) -> id; i = id - 1; if (id == SM_CHILD) Xfputs("sub shell", Xstdout); else if ((id == SM_STATEMENT)) Xfputs("statement", Xstdout); else Xfputs(statementlist[i].ident, Xstdout); Xfputs(":\n", Xstdout); show_stree(statementbody(trp), lvl + 1); } else for (i = 0; i <= (trp -> comm) -> argc; i++) { if (!((trp -> comm) -> argv) || !((trp -> comm) -> argv[i])) Xfputs("NULL", Xstdout); else if (!i && isbuiltin(trp -> comm)) argfputs((trp -> comm) -> argv[i], Xstdout); else VOID_C Xprintf("\"%a\"", (trp -> comm) -> argv[i]); Xfputc((i < (trp -> comm) -> argc) ? ' ' : '\n', Xstdout); } for (rp = (trp -> comm) -> redp; rp; rp = rp -> next) { printindent(lvl, Xstdout); VOID_C Xprintf("redirect %d", rp -> fd); if (!(rp -> filename)) Xfputs(">-: ", Xstdout); else if (rp -> type & MD_HEREDOC) VOID_C Xprintf(">> \"%a\": ", ((heredoc_t *)(rp -> filename)) -> eof); else VOID_C Xprintf("> \"%a\": ", rp -> filename); VOID_C Xprintf("%06o\n", (int)(rp -> type)); } } if (trp -> type) { for (i = 0; i < OPELISTSIZ; i++) if (trp -> type == opelist[i].op) break; if (i < OPELISTSIZ) { printindent(lvl, Xstdout); Xfputs(opelist[i].symbol, Xstdout); VOID_C fputnl(Xstdout); } } if (trp -> next) { if (trp -> cont & (CN_QUOT | CN_ESCAPE)) { rp = (redirectlist *)(trp -> next); printindent(lvl, Xstdout); VOID_C Xprintf("continuing...\"%a\"\n", rp -> filename); } # ifndef MINIMUMSHELL else if (trp -> flags & ST_BUSY); # endif else show_stree(trp -> next, lvl); } } #endif /* SHOWSTREE */ VOID setshfunc(ident, trp) char *ident; syntaxtree *trp; { int i; for (i = 0; shellfunc[i].ident; i++) if (!strcommcmp(ident, shellfunc[i].ident)) break; if (shellfunc[i].ident) { Xfree(shellfunc[i].ident); freestree(shellfunc[i].func); Xfree(shellfunc[i].func); } else { shellfunc = (shfunctable *)Xrealloc(shellfunc, (i + 2) * sizeof(shfunctable)); shellfunc[i + 1].ident = NULL; } shellfunc[i].ident = ident; shellfunc[i].func = trp; #ifndef _NOUSEHASH if (hashahead) check_stree(trp); #endif } static int NEAR dosetshfunc(ident, trp) CONST char *ident; syntaxtree *trp; { syntaxtree *functr; char *new; int len; #ifndef BASHSTYLE /* bash allows any character in the function identifier */ if (identcheck(ident, '\0') <= 0) { execerror(NULL, ident, ER_NOTIDENT, 0); return(-1); } #endif new = Xstrdup(ident); stripquote(new, EA_STRIPQ); len = strlen(new); #ifndef BASHSTYLE /* bash distinguishes the same named function and variable */ if (unset(new, len) < 0) { Xfree(new); return(RET_FAIL); } #endif trp = trp -> next; if (!(functr = statementbody(trp))) { Xfree(new); return(RET_FAIL); } (trp -> comm) -> argv = (char **)duplstree2(functr, NULL, functr -> lineno); functr -> flags |= ST_TOP; setshfunc(new, functr); #ifdef DEP_PTY if (parentfd >= 0 && mypid == shellpid) { sendparent(TE_ADDFUNCTION, ident, functr); nownstree(functr); } #endif return(RET_SUCCESS); } int unsetshfunc(ident, len) CONST char *ident; int len; { int i; if (checkronly(ident, len) < 0) return(-1); for (i = 0; shellfunc[i].ident; i++) if (!strncommcmp(ident, shellfunc[i].ident, len) && !shellfunc[i].ident[len]) break; if (!shellfunc[i].ident) return(0); Xfree(shellfunc[i].ident); freestree(shellfunc[i].func); Xfree(shellfunc[i].func); for (; shellfunc[i + 1].ident; i++) { shellfunc[i].ident = shellfunc[i + 1].ident; shellfunc[i].func = shellfunc[i + 1].func; } shellfunc[i].ident = NULL; #ifdef DEP_PTY sendparent(TE_DELETEFUNCTION, ident, len); #endif return(0); } static int NEAR exec_statement(trp) syntaxtree *trp; { int id; if ((id = getstatid(trp = statementbody(trp))) < 0) return(seterrno(EINVAL)); return((*(statementlist[id].func))(trp)); } #if MSDOS int exec_simplecom(trp, type, id) syntaxtree *trp; int type, id; #else int exec_simplecom(trp, type, id, bg) syntaxtree *trp; int type, id, bg; #endif { #ifdef DEP_FILECONV int i; #endif #if !MSDOS p_id_t pid; #endif command_t *comm; char *path; int ret; comm = trp -> comm; #ifdef DEP_FILECONV if (defaultkcode == NOCNV || defaultkcode == DEFCODE) /*EMPTY*/; else if (type == CT_FDORIGINAL || type == CT_FDINTERNAL || (type == CT_BUILTIN && (shbuiltinlist[id].flags & BT_FILENAME))) { for (i = 1; i < comm -> argc; i++) renewkanjiconv(&(comm -> argv[i]), defaultkcode, DEFCODE, L_FNAME); } #endif if (type == CT_NONE) return(ret_status); if (type == CT_BUILTIN) { if (!shbuiltinlist[id].func) return(RET_FAIL); if (!restricted || !(shbuiltinlist[id].flags & BT_RESTRICT)) return((*(shbuiltinlist[id].func))(trp)); execerror(comm -> argv, NULL, ER_RESTRICTED, 0); return(RET_FAIL); } #ifdef FD if (type == CT_FDORIGINAL) return(execbuiltin(id, comm -> argc, comm -> argv)); if (type == CT_FDINTERNAL) { if (shellmode) return(RET_FAIL); resetsignal(0); ret = execinternal(id, comm -> argc, comm -> argv); setsignal(); return(ret); } #endif #if MSDOS if (type == CT_LOGDRIVE) { if (setcurdrv(id, 1) >= 0) return(RET_SUCCESS); execerror(comm -> argv, NULL, ER_INVALDRIVE, 2); return(RET_FAIL); } #endif if (type == CT_FUNCTION) { if (!shellfunc[id].func) return(RET_FAIL); return(doshfunc(trp, id)); } if (!(path = evalexternal(trp -> comm))) return(ret_status); #if MSDOS if ((ret = spawnve(P_WAIT, path, comm -> argv, exportvar)) < 0 && errno == ENOENT) { execerror(comm -> argv, NULL, ER_COMNOFOUND, 1); return(RET_NOTFOUND); } #else /* !MSDOS */ # ifndef BASHSTYLE /* bash does fork() all processes even in a sub shell */ if (childdepth && !(trp -> next)) bg = 1; # endif if (bg || isopbg(trp) || isopnown(trp)) { searchheredoc(trp, 1); Xexecve2(path, comm -> argv, exportvar, 1); } if ((pid = makechild(1, (p_id_t)-1)) < (p_id_t)0) return(-1); if (!pid) Xexecve2(path, comm -> argv, exportvar, 1); ret = waitchild(pid, trp); #endif /* !MSDOS */ return(ret); } static char **NEAR checkshellbuiltinargv(argc, argv) int argc; char **argv; { char *tmp; int id, type; isshellbuiltin = 0; #ifdef BASHSTYLE /* bash does not use IFS as a command separator */ argc = evalifs(argc, &argv, " \t"); #else argc = evalifs(argc, &argv, getifs()); #endif if (!argc) return(argv); stripquote(tmp = Xstrdup(argv[0]), EA_STRIPQ); type = checktype2(tmp, &id, 0, 1); Xfree(tmp); #ifdef STRICTPOSIX if (type == CT_BUILTIN && (shbuiltinlist[id].flags & BT_POSIXSPECIAL)) isshellbuiltin = 1; #else if (type != CT_NONE && type != CT_COMMAND) isshellbuiltin = 1; #endif return(argv); } static int NEAR checkshellbuiltin(trp) syntaxtree *trp; { syntaxtree *next; char **argv, **subst; int ret, *len, argc, duperrno; duperrno = errno; isshellbuiltin = 0; if (!trp || !(trp -> comm) || isstatement(trp -> comm)) return(0); next = statementcheck(trp -> next, SM_STATEMENT); if (getstatid(next) == SM_LPAREN - 1) { errno = duperrno; return(0); } argv = duplvar((trp -> comm) -> argv, 2); argc = getsubst((trp -> comm) -> argc, argv, &subst, &len); if (substvar(argv, EA_BACKQ | EA_EVALIFS) < 0) ret = -1; else { argv = checkshellbuiltinargv(argc, argv); ret = 0; } freevar(subst); Xfree(len); freevar(argv); errno = duperrno; return(ret); } #if MSDOS static int NEAR exec_command(trp, contp) syntaxtree *trp; int *contp; #else static int NEAR exec_command(trp, contp, bg) syntaxtree *trp; int *contp, bg; #endif { #ifndef _NOUSEHASH hashlist **htable; char *pathvar; #endif command_t *comm; char *ps, **argv, **subst, **svar, **evar; u_long esize; int i, ret, id, type, argc, nsubst, keepvar, *len; isshellbuiltin = execerrno = 0; comm = trp -> comm; argc = comm -> argc; argv = comm -> argv; if (interrupted) return(RET_INTR); if (argc <= 0) return(ret_status); type = 0; comm -> argv = duplvar(comm -> argv, 2); comm -> argc = getsubst(comm -> argc, comm -> argv, &subst, &len); id = evalargv(comm, &type, contp); if (id < 0 || (nsubst = substvar(subst, EA_BACKQ)) < 0) { freevar(subst); Xfree(len); comm -> argc = argc; freevar(comm -> argv); comm -> argv = argv; return(RET_FAIL); } if (nsubst > 0 && type == CT_NONE) ret_status = RET_SUCCESS; keepvar = 0; #ifdef BASHSTYLE /* bash treats the substitution before builtin as ineffective */ if (type == CT_BUILTIN) keepvar = -1; else if (type != CT_NONE) keepvar = 1; #else if (type == CT_COMMAND) keepvar = 1; /* bash treats the substitution before a function as effective */ else if (type == CT_FUNCTION) keepvar = -1; #endif #ifdef STRICTPOSIX if (type == CT_BUILTIN) { if (shbuiltinlist[id].flags & BT_POSIXSPECIAL) isshellbuiltin = 1; else keepvar = -1; } #else if (type != CT_NONE && type != CT_COMMAND) isshellbuiltin = 1; #endif if (keepvar < 0) { for (i = 0; subst[i]; i++) Xfree(subst[i]); subst[0] = NULL; keepvar = nsubst = 0; } if (keepvar) { shellvar = duplvar(svar = shellvar, 0); exportvar = duplvar(evar = exportvar, 0); esize = exportsize; #ifndef _NOUSEHASH htable = duplhash(hashtable); pathvar = getconstvar(ENVPATH); #endif } #ifdef FAKEUNINIT else { /* fake for -Wuninitialized */ svar = evar = NULL; esize = 0L; # ifndef _NOUSEHASH htable = NULL; pathvar = NULL; # endif } #endif #ifdef MINIMUMSHELL ps = PS4STR; #else /* !MINIMUMSHELL */ # ifdef FD if ((ps = getconstvar(ENVPS4))) evalprompt(&ps, ps); # else if ((ps = getconstvar(ENVPS4))) ps = evalvararg(ps, EA_BACKQ, 0); # endif #endif /* !MINIMUMSHELL */ while (nsubst--) { #ifdef FD demacroarg(&(subst[nsubst])); #endif stripquote(subst[nsubst], EA_STRIPQ); if (putshellvar(subst[nsubst], len[nsubst]) < 0) { while (nsubst >= 0) Xfree(subst[nsubst--]); Xfree(subst); Xfree(len); comm -> argc = argc; freevar(comm -> argv); comm -> argv = argv; return(RET_FAIL); } if (type == CT_COMMAND) exportvar = putvar(exportvar, Xstrdup(subst[nsubst]), len[nsubst]); if (verboseexec) { #ifdef BASHSTYLE /* bash displays "+ " with substitutions, in -x mode */ if (ps) Xfputs(ps, Xstderr); argfputs(subst[nsubst], Xstderr); #else argfputs(subst[nsubst], Xstderr); if (nsubst) Xfputc(' ', Xstderr); else #endif VOID_C fputnl(Xstderr); } } Xfree(subst); Xfree(len); if (verboseexec && comm -> argc) { if (ps) Xfputs(ps, Xstderr); argfputs(comm -> argv[0], Xstderr); for (i = 1; i < comm -> argc; i++) VOID_C Xfprintf(Xstderr, " %a", comm -> argv[i]); VOID_C fputnl(Xstderr); } #ifndef MINIMUMSHELL Xfree(ps); #endif ret = exec_simplecom2(trp, type, id, bg); Xfpurge(Xstdin); Xfflush(Xstdout); Xfflush(Xstderr); if (keepvar) { #ifndef _NOUSEHASH if (pathvar != getconstvar(ENVPATH)) { VOID_C searchhash(NULL, NULL, NULL); hashtable = htable; } else if (htable) VOID_C searchhash(htable, NULL, NULL); #endif freevar(shellvar); freevar(exportvar); shellvar = svar; exportvar = evar; exportsize = esize; } #ifdef FD if (type != CT_NONE && type != CT_FDINTERNAL && type != CT_FUNCTION) internal_status = FNC_FAIL; #endif comm -> argc = argc; freevar(comm -> argv); comm -> argv = argv; #if !MSDOS && defined (FD) if (autosavetty) savestdio(0); #endif return(ret); } #ifdef USEFAKEPIPE static int NEAR exec_process(trp) syntaxtree *trp; #else static int NEAR exec_process(trp, pipein) syntaxtree *trp; p_id_t pipein; #endif { #if !MSDOS syntaxtree *tmptr; p_id_t pid; int bg, sub; #endif #ifndef MINIMUMSHELL long dupshlineno; #endif syntaxtree *next; int cont, ret; next = statementcheck(trp -> next, SM_STATEMENT); if (getstatid(next) != SM_LPAREN - 1) { #if !MSDOS tmptr = trp; #endif next = NULL; } #if !MSDOS else tmptr = trp -> next; #endif #if !MSDOS sub = 0; # if !defined (BASHSTYLE) && !defined (USEFAKEPIPE) /* bash does not treat the end of pipeline as sub shell */ if (tmptr -> next || !(tmptr -> flags & ST_NEXT)) /*EMPTY*/; else if ((tmptr = getparent(trp)) && isoppipe(tmptr)) sub = 1; # endif if (!isstatement(trp -> comm)) /*EMPTY*/; else if ((trp -> comm) -> id == SM_CHILD) sub = 0; # if !defined (NOJOB) && defined (CHILDSTATEMENT) else if (jobok && mypid == orgpgrp) sub = 1; # endif # ifndef BASHSTYLE /* bash does not treat redirected statements as sub shell */ else if ((trp -> comm) -> redp) sub = 1; # endif if (!sub) /*EMPTY*/; else if ((pid = makechild(1, (p_id_t)-1)) < (p_id_t)0) return(-1); else if (pid) { # ifndef NOJOB stackjob(pid, 0, -1, trp); # endif return(waitchild(pid, trp)); } # ifndef NOJOB else stackjob(mypid, 0, -1, trp); # endif #endif /* !MSDOS */ if (isstatement(trp -> comm)) { if ((trp -> comm) -> id == SM_CHILD) ret = dochild(trp); else ret = exec_statement(trp); } else if (next) ret = dosetshfunc((trp -> comm) -> argv[0], next); else for (;;) { cont = 0; #ifndef MINIMUMSHELL dupshlineno = shlineno; setshlineno(trp -> lineno); #endif #if !MSDOS if (sub) bg = 1; # ifndef USEFAKEPIPE else if (!pipein) bg = 1; # endif # ifndef NOJOB else if (ttypgrp < (p_id_t)0 && !(trp -> next)) bg = 1; # endif else bg = 0; #endif /* !MSDOS */ ret = exec_command2(trp, &cont, bg); #ifndef MINIMUMSHELL setshlineno(dupshlineno); #endif if (ret < 0) break; #ifdef FD if (cont) continue; #endif break; } #if !MSDOS if (sub) { prepareexit(1); Xexit((ret >= 0) ? ret : RET_NOTEXEC); } #endif return(ret); } static int NEAR exec_stree(trp, cond) syntaxtree *trp; int cond; { #if !MSDOS p_id_t pid; #endif syntaxtree *tmptr; redirectlist *errp; p_id_t pipein; char *tmp; int ret, fd; exectrapcomm(); if (breaklevel || continuelevel) { ret_status = RET_SUCCESS; return(ret_status); } #ifndef MINIMUMSHELL if (isopnot(trp)) { trp = skipfuncbody(trp); if (!(trp -> next)) return(RET_FAIL); if ((ret = exec_stree(trp -> next, cond)) < 0) return(-1); ret_status = (ret_status != RET_SUCCESS) ? RET_SUCCESS : RET_FAIL; return(ret_status); } #endif fd = -1; #if !MSDOS if (!isopbg(trp) && !isopnown(trp)) pid = (p_id_t)-1; else if ((pid = makechild(0, (p_id_t)-1)) < (p_id_t)0) return(-1); else if (!pid) { nownstree(trp -> next); # ifndef NOJOB ttypgrp = (p_id_t)-1; if (!isopnown(trp)) stackjob(mypid, 0, -1, trp); if (jobok) /*EMPTY*/; else # endif fd = Xopen(_PATH_DEVNULL, O_BINARY | O_RDONLY, 0666); if (fd >= 0) { Xdup2(fd, STDIN_FILENO); safeclose(fd); } } else { tmptr = trp -> next; trp -> next = NULL; nownstree(trp); trp -> next = tmptr; # ifndef NOJOB childpgrp = (p_id_t)-1; if (!isopnown(trp)) { prevjob = lastjob; lastjob = stackjob(pid, 0, -1, trp); } # endif if (interactive && !nottyout) { # ifndef NOJOB if (jobok && !isopnown(trp)) { if (mypid == orgpgrp) VOID_C Xfprintf(Xstderr, "[%d] %id\n", lastjob + 1, pid); } else # endif /* !NOJOB */ VOID_C Xfprintf(Xstderr, "%id\n", pid); } lastpid = pid; trp = skipfuncbody(trp); ret_status = RET_SUCCESS; if (!(trp -> next)) return(ret_status); return(exec_stree(trp -> next, cond)); } #endif /* !MSDOS */ tmptr = skipfuncbody(trp); if (!isoppipe(tmptr)) pipein = (p_id_t)-1; else if ((fd = openpipe2(&pipein, STDIN_FILENO, 0, 1, (p_id_t)-1)) < 0) return(-1); #ifdef FD replaceargs(NULL, NULL, NULL, 0); #endif if (!(trp -> comm) || pipein > (p_id_t)0) { #ifndef NOJOB if (pipein > (p_id_t)0) stackjob(pipein, 0, fd, trp); #endif ret = ret_status; } else if (trp -> flags & ST_NODE) ret = exec_stree((syntaxtree *)(trp -> comm), cond); else if (!((trp -> comm) -> redp)) { ret = exec_process2(trp, pipein); ret_status = (ret >= 0) ? ret : RET_FAIL; } else for (;;) { if (!(errp = doredirect((trp -> comm) -> redp))) ret = exec_process2(trp, pipein); else { if (checkshellbuiltin(trp) < 0) /*EMPTY*/; else if (errno < 0) /*EMPTY*/; else if (errp -> type & MD_HEREDOC) doperror(NULL, NULL); else { if (!(errp -> filename)) tmp = Xstrdup("-"); else tmp = evalvararg(errp -> filename, EA_BACKQ | EA_STRIPQLATER, 0); if (tmp && !*tmp && *(errp -> filename)) { Xfree(tmp); tmp = Xstrdup(errp -> filename); } if (tmp) { if (errno) doperror(NULL, tmp); else execerror(NULL, tmp, ER_RESTRICTED, 2); Xfree(tmp); } } ret = RET_FAIL; } closeredirect((trp -> comm) -> redp); ret_status = (ret >= 0) ? ret : RET_FAIL; #ifdef FD if (!errp && ((trp -> comm) -> redp) -> type & MD_REST) continue; #endif break; } trp = tmptr; if (returnlevel || ret < 0) /*EMPTY*/; else if (pipein >= (p_id_t)0 && (fd = reopenpipe(fd, RET_SUCCESS)) < 0) { pipein = (p_id_t)-1; ret = -1; } else { #if !MSDOS if (!pid) { searchheredoc(trp, 1); prepareexit(1); Xexit(RET_SUCCESS); } #endif #ifndef NOJOB if (pipein > (p_id_t)0) stackjob(pipein, 0, fd, trp); #endif if (interrupted) { breaklevel = loopdepth; ret = RET_INTR; } else if (!(trp -> next)) /*EMPTY*/; else if (errorexit && !cond && isopfg(trp) && ret_status) breaklevel = loopdepth; else if (isopand(trp) && ret_status) { if (errorexit && !cond) { breaklevel = loopdepth; ret = RET_SUCCESS; } } else if (isopor(trp) && !ret_status) /*EMPTY*/; else ret = exec_stree(trp -> next, cond); } if (pipein >= (p_id_t)0) VOID_C closepipe2(fd, -1); exectrapcomm(); return(ret); } static syntaxtree *NEAR execline(command, stree, trp, noexit) CONST char *command; syntaxtree *stree, *trp; int noexit; { int ret; if (command == (char *)-1) { if (!(trp = analyzeeof(trp))) { freestree(stree); return(NULL); } } else { if (!(trp = analyze(command, trp, 0))) { freestree(stree); if (errorexit && !noexit) { Xfree(stree); Xexit2(RET_SYNTAXERR); } return(NULL); } if (trp -> cont) return(trp); } if (notexec) { ret = RET_SUCCESS; #ifdef SHOWSTREE show_stree(stree, 0); #endif } #ifndef _NOUSEHASH else if (hashahead && check_stree(stree) < 0) ret = ret_status = RET_FAIL; #endif else ret = exec_stree(stree, 0); errorexit = tmperrorexit; freestree(stree); if (ret < 0 && errno) doperror(NULL, NULL); if ((errorexit && ret && !noexit) || terminated) { Xfree(stree); Xexit2(ret); } return(NULL); } static int NEAR exec_line(command) CONST char *command; { static syntaxtree *stree = NULL; static syntaxtree *trp = NULL; int ret; if (!command) { freestree(stree); Xfree(stree); stree = trp = NULL; return(0); } setsignal(); if (verboseinput && command != (char *)-1) { argfputs(command, Xstderr); VOID_C fputnl(Xstderr); } if (!stree) trp = stree = newstree(NULL); #ifndef NOJOB childpgrp = (p_id_t)-1; #endif if ((trp = execline(command, stree, trp, 0))) ret = trp -> cont; else { Xfree(stree); stree = trp = NULL; ret = 0; } resetsignal(0); return(ret); } static int NEAR _dosystem(command) CONST char *command; { static syntaxtree *trp = NULL; int ret; if (!command) ret = 0; else if (!(trp = analyzeline(command))) ret = RET_SYNTAXERR; else { if (notexec) { ret = RET_SUCCESS; #ifdef SHOWSTREE show_stree(trp, 0); #endif } #ifndef _NOUSEHASH else if (hashahead && check_stree(trp) < 0) ret = RET_FAIL; #endif else ret = exec_stree(trp, 0); errorexit = tmperrorexit; } freestree(trp); Xfree(trp); trp = NULL; return((ret >= 0) ? ret : RET_FAIL); } #ifndef FDSH int dosystem(command) CONST char *command; { int ret; shellpid = mypid; # ifndef NOJOB orgpgrp = mypid; childpgrp = (p_id_t)-1; # endif # ifdef DEP_PTY if (!command) return(shell_loop((isshptymode()) ? 0 : 1)); # else if (!command) return(shell_loop(1)); # endif setsignal(); ret = _dosystem(command); resetsignal(0); return(ret); } #endif /* !FDSH */ static XFILE *NEAR _dopopen(command) CONST char *command; { #ifndef USEFAKEPIPE pipelist **prevp; #endif #ifdef CYGWIN struct timeval tv; #endif syntaxtree *trp; p_id_t pipein; int fd; trp = (command) ? analyzeline(command) : NULL; nottyout++; fd = openpipe2(&pipein, STDIN_FILENO, 1, 1, mypid); #ifndef USEFAKEPIPE prevp = searchpipe(fd); #endif if (fd < 0) /*EMPTY*/; else if (pipein) { #ifdef CYGWIN /* a trick for buggy terminal emulation */ tv.tv_sec = 0L; tv.tv_usec = 500000L; /* maybe enough waiting limit */ VOID_C readselect(1, &fd, NULL, &tv); #endif } else { #ifndef USEFAKEPIPE if (prevp && !((*prevp) -> file)) nownstree(trp); prevp = NULL; #endif if (!trp) ret_status = RET_SYNTAXERR; else if (!(trp -> comm)) ret_status = RET_SUCCESS; else if (notexec) { #ifdef SHOWSTREE show_stree(trp, 0); #endif pipein = (p_id_t)-1; } #ifndef _NOUSEHASH else if (hashahead && check_stree(trp) < 0) pipein = (p_id_t)-1; #endif else if (exec_stree(trp, 0) < 0) pipein = (p_id_t)-1; searchheredoc(trp, 1); if (pipein >= (p_id_t)0) fd = reopenpipe(fd, ret_status); else { VOID_C closepipe2(fd, -1); fd = -1; } } #ifndef USEFAKEPIPE if (prevp) (*prevp) -> trp = trp; else #endif { freestree(trp); Xfree(trp); } errorexit = tmperrorexit; nottyout--; return((fd >= 0) ? fdopenpipe(fd) : NULL); } #ifndef FDSH XFILE *dopopen(command) CONST char *command; { XFILE *fp; shellpid = mypid; # ifndef NOJOB orgpgrp = mypid; childpgrp = (p_id_t)-1; # endif setsignal(); fp = _dopopen(command); resetsignal(0); return(fp); } int dopclose(fp) XFILE *fp; { return(closepipe2(Xfileno(fp), -1)); } #endif /* !FDSH */ static int NEAR sourcefile(fd, fname, verbose) int fd; CONST char *fname; int verbose; { #ifndef MINIMUMSHELL long dupshlineno; #endif syntaxtree *stree, *trp; char *buf; long n; int ret, dupinteractive; dupinteractive = interactive; interactive = 0; #ifndef MINIMUMSHELL dupshlineno = shlineno; setshlineno(1L); #endif trp = stree = newstree(NULL); n = 0L; ret = errno = 0; #if !MSDOS closeonexec(fd); #endif while ((buf = readline(fd, '\0')) != vnullstr) { if (!buf) { if (errno != EINTR) doperror(NULL, fname); ret++; ret_status = RET_FAIL; break; } if (!trp) trp = stree; trp = execline(buf, stree, trp, 1); n++; if (ret_status == RET_NOTICE || syntaxerrno || execerrno) { ret++; if (verbose) VOID_C Xfprintf(Xstderr, "%k:%ld: %s\n", fname, n, buf); ret_status = RET_FAIL; } Xfree(buf); if (syntaxerrno) break; #ifndef BASHSTYLE if (execerrno) break; #endif #ifndef MINIMUMSHELL setshlineno(shlineno + 1L); #endif } execline((char *)-1, stree, trp, 1); if (syntaxerrno) ret_status = RET_SYNTAXERR; Xfree(stree); interactive = dupinteractive; #ifndef MINIMUMSHELL setshlineno(dupshlineno); #endif return(ret); } int execruncom(fname, verbose) CONST char *fname; int verbose; { #ifdef MINIMUMSHELL char *cp, path[MAXPATHLEN]; #endif lockbuf_t *lck; char *new, **dupargvar; int ret, duprestricted; setsignal(); #ifdef MINIMUMSHELL if (*fname == '~' && fname[1] == _SC_ && (cp = getconstvar(ENVHOME))) { strcatdelim2(path, cp, &(fname[2])); fname = path; } #endif new = Xstrdup(fname); #if MSDOS && !defined (BSPATHDELIM) new = adjustpname(new); #endif fname = new = evalpath(new, 0); ret = RET_SUCCESS; if (noruncom || !isrootdir(fname)) lck = NULL; else if (!(lck = lockopen(fname, O_TEXT | O_RDONLY, 0666))) { doperror(NULL, fname); ret = RET_FAIL; } else if (lck -> fd >= 0) { #ifdef FD inruncom = 1; #endif duprestricted = restricted; restricted = 0; dupargvar = argvar; argvar = (char **)Xmalloc(2 * sizeof(char *)); argvar[0] = Xstrdup(fname); argvar[1] = NULL; ret = sourcefile(lck -> fd, fname, verbose); freevar(argvar); argvar = dupargvar; restricted = duprestricted; #ifdef FD inruncom = 0; #endif } lockclose(lck); resetsignal(0); Xfree(new); return(ret); } #if MSDOS && !defined (BSPATHDELIM) static VOID NEAR adjustdelim(var) char *CONST *var; { char *cp; int i; if (!var) return; for (i = 0; var[i]; i++) { if (!(cp = Xstrchr(var[i], '='))) continue; if (searchvar2(ADJUSTVARSIZ, adjustvar, var[i], cp - var[i])) adjustpname(cp); } } #endif /* MSDOS && !BSPATHDELIM */ VOID setshellvar(envp) char *CONST *envp; { char *cp; int i, len; shellvar = duplvar(envp, 0); exportvar = duplvar(envp, 0); #if MSDOS && !defined (BSPATHDELIM) adjustdelim(shellvar); adjustdelim(exportvar); #endif exportsize = (u_long)0; for (i = 0; exportvar[i]; i++) exportsize += (u_long)strlen(exportvar[i]) + 1; exportlist = (char **)Xmalloc((i + 1) * sizeof(char *)); for (i = 0; exportvar[i]; i++) { len = ((cp = Xstrchr(exportvar[i], '='))) ? cp - exportvar[i] : strlen(exportvar[i]); exportlist[i] = Xstrndup(exportvar[i], len); } exportlist[i] = NULL; ronlylist = duplvar(NULL, 0); } int prepareterm(VOID_A) { #ifdef FD CONST char *term; #endif if (ttyio >= 0 && ttyout) return(0); if (opentty(&ttyio, &ttyout) < 0) { closetty(&ttyio, &ttyout); nottyout++; if (interactive) return(-1); } #ifndef NOJOB if (!interactive) oldttypgrp = (p_id_t)-1; else if (gettcpgrp(ttyio, &oldttypgrp) < (p_id_t)0) { closetty(&ttyio, &ttyout); if ((ttyio = newdup(Xdup(STDIN_FILENO))) < 0 || opentty(&ttyio, &ttyout) < 0) { closetty(&ttyio, &ttyout); return(-1); } } #endif /* !NOJOB */ #ifdef FD if (ttyio >= 0) inittty(0); if (!(term = getconstvar(ENVTERM))) term = nullstr; getterment(term); #endif return(0); } static VOID NEAR initrc(verbose) int verbose; { #if !defined (MINIMUMSHELL) \ || (MSDOS && defined (FD) && !defined (BSPATHDELIM)) CONST char *cp; #endif #ifdef FD execruncom(DEFRC, verbose); #else if (loginshell) { execruncom(LSH_DEFRC, verbose); execruncom(LSH_RCFILE, verbose); } #endif #ifndef MINIMUMSHELL # if !MSDOS if (getuid() != geteuid() || getgid() != getegid()) /*EMPTY*/; else # endif if ((cp = getconstvar(ENVENV))) execruncom(cp, verbose); #endif /* !MINIMUMSHELL */ #ifdef FD if (loginshell) execruncom(SH_RCFILE, verbose); else execruncom(FD_RCFILE, verbose); # ifdef DEP_PTY if (interactive) shptymode = tmpshptymode; # endif #endif /* FD */ } int initshell(argc, argv) int argc; char *CONST *argv; { #if MSDOS char *tmp; #else /* !MSDOS */ # if !defined (NOJOB) && defined (NTTYDISC) && defined (ldisc) ldiscioctl_t tty; # endif # ifndef MINIMUMSHELL char buf[MAXLONGWIDTH + 1]; # endif sigmask_t mask; #endif /* !MSDOS */ CONST char *cp, *cp2; int i, n, isstdin, tmprestricted; shellname = argv[0]; getshellname(getbasename(shellname), &loginshell, &tmprestricted); definput = STDIN_FILENO; if (!interactive && isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)) interactive = 1; orgpid = shellpid = mypid = getpid(); #ifndef NOJOB ttypgrp = mypid; if ((orgpgrp = getpgroup()) < (p_id_t)0) { doperror(NULL, NULL); return(-1); } #endif if ((n = getoption(argc, argv, 1)) < 0) return(-1); #if !defined (MINIMUMSHELL) && defined (BASHSTYLE) noclobber = 0; #endif errorexit = tmperrorexit; #ifdef DEP_PTY shptymode = tmpshptymode; #endif isstdin = forcedstdin; if (n > 2) { shellmode = 1; interactive = interactive_io; } else if (n >= argc || isstdin) isstdin = 1; else { definput = newdup(Xopen(argv[n], O_BINARY | O_RDONLY, 0666)); if (definput < 0) { VOID_C Xfprintf(Xstderr, "%k: cannot open\n", argv[n]); return(-1); } if (!interactive_io || !isatty(definput)) { interactive = 0; #if !MSDOS closeonexec(definput); #endif } else { if (Xdup2(definput, STDIN_FILENO) < 0) { VOID_C Xfprintf(Xstderr, "%k: cannot open\n", argv[n]); return(-1); } safeclose(definput); definput = STDIN_FILENO; } } interactive_io = interactive; if (prepareterm() < 0) { doperror(NULL, NULL); return(-1); } #if !MSDOS && defined (FD) if (autosavetty) savestdio(0); #endif Xsetbuf(Xstdin); Xsetlinebuf(Xstderr); Xsetlinebuf(Xstdout); #if !MSDOS Xsigemptyset(mask); Xsigblock(oldsigmask, mask); #endif /* !MSDOS */ if (ttyio >= 0 && definput == STDIN_FILENO && isatty(STDIN_FILENO)) definput = ttyio; getvarfunc = getshellvar; putvarfunc = putshellvar; getretvalfunc = getretval; getpidfunc = getorgpid; getlastpidfunc = getlastpid; getflagfunc = getflagstr; checkundeffunc = checkundefvar; exitfunc = safeexit; backquotefunc = evalbackquote; #ifndef MINIMUMSHELL posixsubstfunc = evalposixsubst; #endif shellfunc = (shfunctable *)Xmalloc(1 * sizeof(shfunctable)); shellfunc[0].ident = NULL; #ifndef NOALIAS shellalias = (shaliastable *)Xmalloc(1 * sizeof(shaliastable)); shellalias[0].ident = NULL; #endif #ifndef _NOUSEHASH VOID_C searchhash(NULL, NULL, NULL); #endif if ((!interactive || isstdin) && n < argc) { argvar = (char **)Xmalloc((argc - n + 1 + isstdin) * sizeof(char *)); for (i = 0; i < argc - n + 1; i++) argvar[i + isstdin] = Xstrdup(argv[i + n]); if (isstdin) argvar[0] = Xstrdup(argv[0]); } else { argvar = (char **)Xmalloc(2 * sizeof(char *)); argvar[0] = Xstrdup(argv[0]); argvar[1] = NULL; } #if MSDOS if (!(tmp = getconstvar(ENVPATH))) setenv2(ENVPATH, DEFPATH, 1); else for (i = 0; tmp[i]; i++) if (tmp[i] == ';') tmp[i] = PATHDELIM; #else if (!getconstvar(ENVPATH)) setenv2(ENVPATH, DEFPATH, 1); if (!getconstvar(ENVTERM)) setenv2(ENVTERM, DEFTERM, 1); #endif if (interactive) { if (getconstvar(ENVPS1)) /*EMPTY*/; #if !MSDOS else if (!getuid()) setenv2(ENVPS1, PS1ROOT, 0); #endif else setenv2(ENVPS1, PS1STR, 0); if (!getconstvar(ENVPS2)) setenv2(ENVPS2, PS2STR, 0); } else { for (i = 0; i < PRIMALVARSIZ; i++) if (!strenvcmp(primalvar[i], ENVPS1) || !strenvcmp(primalvar[i], ENVPS2)) primalvar[i] = NULL; unset(ENVPS1, strsize(ENVPS1)); unset(ENVPS2, strsize(ENVPS2)); } #ifndef MINIMUMSHELL if (!getconstvar(ENVPS4)) setenv2(ENVPS4, PS4STR, 0); setshlineno(1L); # if !MSDOS VOID_C Xsnprintf(buf, sizeof(buf), "%id", getppid()); setenv2(ENVPPID, buf, 0); # endif #endif setenv2(ENVIFS, IFS_SET, 0); if (loginshell) { #ifndef NOUID getlogininfo(&cp, &cp2); #endif if (!getconstvar(ENVHOME)) { #ifndef NOUID if (cp) /*EMPTY*/; else #endif cp = rootpath; setenv2(ENVHOME, cp, 1); } if (!getconstvar(ENVSHELL)) { #ifndef NOUID if (cp2) /*EMPTY*/; else #endif cp2 = shellname; setenv2(ENVSHELL, cp2, 1); } } #if !MSDOS && !defined (MINIMUMSHELL) # ifdef BASHSTYLE if (!getconstvar(ENVMAILCHECK)) setenv2(ENVMAILCHECK, "60", 0); # else if (!getconstvar(ENVMAILCHECK)) setenv2(ENVMAILCHECK, "600", 0); # endif if ((cp = getconstvar(ENVMAILPATH))) replacemailpath(cp, 1); else if ((cp = getconstvar(ENVMAIL))) replacemailpath(cp, 0); #endif /* !MSDOS && !MINIMUMSHELL */ #ifndef NOPOSIXUTIL setenv2(ENVOPTIND, "1", 0); #endif for (i = 0; i < NSIG; i++) { trapmode[i] = 0; trapcomm[i] = NULL; if ((oldsigfunc[i] = (sigcst_t)signal2(i, SIG_DFL)) == SIG_ERR) oldsigfunc[i] = SIG_DFL; else signal2(i, oldsigfunc[i]); } for (i = 0; signallist[i].sig >= 0; i++) trapmode[signallist[i].sig] = signallist[i].flags; #ifndef NOJOB if (!interactive || ttyio < 0) jobok = 0; else { if (!orgpgrp) { orgpgrp = mypid; if (setpgroup(0, mypid) < (p_id_t)0 || settcpgrp(ttyio, orgpgrp) < 0) { doperror(NULL, NULL); return(-1); } } VOID_C gettcpgrp(ttyio, &ttypgrp); # ifdef SIGTTIN while (ttypgrp >= (p_id_t)0 && ttypgrp != orgpgrp) { signal2(SIGTTIN, SIG_DFL); VOID_C kill(0, SIGTTIN); signal2(SIGTTIN, oldsigfunc[SIGTTIN]); VOID_C gettcpgrp(ttyio, &ttypgrp); } # endif # if defined (NTTYDISC) && defined (ldisc) if (tioctl(ttyio, REQGETD, &tty) < 0) { doperror(NULL, NULL); return(-1); } else if (ldisc(tty) != NTTYDISC && (ldisc(tty) = NTTYDISC) > 0 && tioctl(ttyio, REQSETD, &tty) < 0) { # ifdef USESGTTY doperror(NULL, NULL); return(-1); # else /* !USESGTTY */ # ifdef ENODEV if (errno == ENODEV) /*EMPTY*/; else # endif jobok = 0; # endif /* !USESGTTY */ } # endif /* NTTYDISC && ldisc */ if (orgpgrp != mypid) { orgpgrp = mypid; if (setpgroup(0, mypid) < (p_id_t)0 || (mypid != ttypgrp && gettermio(orgpgrp, 1) < 0)) { doperror(NULL, NULL); return(-1); } } if (jobok < 0) jobok = 1; } #endif /* !NOJOB */ #if !MSDOS closeonexec(ttyio); #endif if (n > 2) { #ifdef FD initenv(); # ifdef DEP_PTY if (isshptymode()) checkscreen(0, 0); # endif # ifndef _NOCUSTOMIZE saveorigenviron(); # endif #endif /* FD */ initrc(0); #ifdef FD initfd(argv); #endif if (verboseinput) { kanjifputs(argv[2], Xstderr); #ifdef BASHSTYLE /* bash displays a newline with single string command, in -v mode */ VOID_C fputnl(Xstderr); #endif Xfflush(Xstderr); } #ifdef DEP_PTY if (isshptymode()) { shellpid = (p_id_t)-1; n = ptymacro(argv[2], NULL, F_DOSYSTEM); } else #endif { setsignal(); n = _dosystem(argv[2]); resetsignal(0); } Xexit2(n); } n = 0; #ifdef BASHSTYLE /* bash changes the current directory if the variable PWD is set */ if ((cp = getconstvar(ENVPWD))) n = chdir2(cp); else #endif if (loginshell && interactive) n = chdir2(getconstvar(ENVHOME)); if (n < 0) { #ifdef FD initfd(argv); #endif Xfputs("No directory", Xstderr); VOID_C fputnl(Xstderr); Xexit2(RET_FAIL); } if (!restricted) restricted = tmprestricted; if (!restricted) { #ifdef FD cp = getenv2("FD_SHELL"); #else cp = getconstvar(ENVSHELL); #endif if (cp) getshellname(getbasename(cp), NULL, &restricted); } #ifdef FD fd_restricted = restricted; #endif return(0); } int shell_loop(pseudoexit) int pseudoexit; { char *ps, *buf; int cont; shellmode = 1; setsignal(); cont = 0; if (pseudoexit) exit_status = -1; for (;;) { if (trapok >= 0) trapok = 1; if (!interactive) buf = readline(definput, '\0'); else { #if !MSDOS checkmail(0); #endif ps = (cont) ? getconstvar(ENVPS2) : getconstvar(ENVPS1); #ifdef FD if (dumbterm > 1) { evalprompt(&buf, ps); kanjifputs(buf, Xstderr); Xfree(buf); Xfflush(Xstderr); buf = readline(definput, '\0'); } else { ttyiomode(1); buf = inputshellstr(ps, -1, NULL); stdiomode(); if (!buf) continue; } #else /* !FD */ kanjifputs(ps, Xstderr); Xfflush(Xstderr); buf = readline(definput, '\0'); #endif /* !FD */ } if (trapok >= 0) trapok = 0; if (!buf) { if (errno != EINTR) doperror(NULL, "stdin"); exec_line(NULL); break; } if (buf == vnullstr) { #ifndef MINIMUMSHELL if (interactive && ignoreeof) { if (cont) { exec_line(NULL); syntaxerrno = ER_UNEXPEOF; syntaxerror(nullstr); } else VOID_C Xfprintf(Xstderr, "Use \"%s\" to leave to the shell.\n", (loginshell) ? "logout" : "exit"); cont = 0; continue; } #endif /* !MINIMUMSHELL */ if (!cont) break; exec_line((char *)-1); cont = 0; ERRBREAK; } #ifdef DEP_FILECONV renewkanjiconv(&buf, DEFCODE, defaultkcode, L_FNAME); printf_defkanji++; #endif cont = exec_line(buf); #ifdef DEP_FILECONV printf_defkanji--; #endif Xfree(buf); if (pseudoexit && exit_status >= 0) break; #ifndef MINIMUMSHELL setshlineno(shlineno + 1L); #endif } resetsignal(0); if (exit_status >= 0) ret_status = exit_status; shellmode = 0; return(ret_status); } int main_shell(argc, argv, envp) int argc; char *CONST *argv, *CONST *envp; { shellmode = 1; setshellvar(envp); if (initshell(argc, argv) < 0) return(RET_FAIL); #ifdef FD initenv(); # if MSDOS inittty(1); # endif if (interactive) checkscreen(0, 0); # ifndef _NOCUSTOMIZE saveorigenviron(); # endif #endif /* FD */ #if defined (DEP_URLPATH) && defined (WITHNETWORK) urldrive = 1; #endif ret_status = RET_SUCCESS; initrc(!loginshell); #ifdef FD initfd(argv); #endif #ifdef DEP_PTY if (isshptymode()) { shellpid = (p_id_t)-1; ret_status = ptymacro(NULL, NULL, F_DOSYSTEM); } else #endif shell_loop(0); return(ret_status); } #ifdef FDSH int main(argc, argv, envp) int argc; char *CONST argv[], *CONST envp[]; { int ret; # ifdef DEBUG mtrace(); # endif ret = main_shell(argc, argv, envp); Xexit2(ret); return(0); } #endif /* FDSH */ #endif /* DEP_ORIGSHELL */