Apply vodz last_path_51-2
authorGlenn L McGrath <bug1@ihug.co.nz>
Fri, 23 Aug 2002 13:14:48 +0000 (13:14 -0000)
committerGlenn L McGrath <bug1@ihug.co.nz>
Fri, 23 Aug 2002 13:14:48 +0000 (13:14 -0000)
shell/ash.c

index 15ec043808e9e9ca2af2f5230ad100d62b77218f..216f1c4e95c91345b22ebc01e828791d1e14851c 100644 (file)
@@ -267,7 +267,6 @@ static void stunalloc(pointer);
 static void ungrabstackstr(char *, char *);
 static char *growstackstr(void);
 static char *makestrspace(size_t newlen);
-static char *sstrdup(const char *);
 
 /*
  * Parse trees for commands are allocated in lifo order, so we use a stack
@@ -311,7 +310,6 @@ static int stacknleft = MINSIZE;
 #define grabstackstr(p) stalloc(stackblocksize() - sstrnleft)
 
 
-
 #ifdef DEBUG
 #define TRACE(param)    trace param
 typedef union node unode;
@@ -676,37 +674,22 @@ static void out2c(int c)
 #define  ARISYNTAX   3 /* in arithmetic */
 
 static const char S_I_T[][4] = {
-                                                                               /*  0 */ {CSPCL, CIGN, CIGN, CIGN},
-                                                                               /* PEOA */
-                                                                                       /*  1 */ {CSPCL, CWORD, CWORD, CWORD},
-                                                                                       /* ' ' */
-                                                                       /*  2 */ {CNL, CNL, CNL, CNL},
-                                                                       /* \n */
-                                                                                       /*  3 */ {CWORD, CCTL, CCTL, CWORD},
-                                                                                       /* !*-/:=?[]~ */
-                                                                                                       /*  4 */ {CDQUOTE, CENDQUOTE, CWORD, CDQUOTE},
-                                                                                                       /* '"' */
-                                                                               /*  5 */ {CVAR, CVAR, CWORD, CVAR},
-                                                                               /* $ */
-                                                                                                       /*  6 */ {CSQUOTE, CWORD, CENDQUOTE, CSQUOTE},
-                                                                                                       /* "'" */
-                                                                                       /*  7 */ {CSPCL, CWORD, CWORD, CLP},
-                                                                                       /* ( */
-                                                                                       /*  8 */ {CSPCL, CWORD, CWORD, CRP},
-                                                                                       /* ) */
-                                                                                       /*  9 */ {CBACK, CBACK, CCTL, CBACK},
-                                                                                       /* \ */
-                                                                                                       /* 10 */ {CBQUOTE, CBQUOTE, CWORD, CBQUOTE},
-                                                                                                       /* ` */
-                                                                                                       /* 11 */ {CENDVAR, CENDVAR, CWORD, CENDVAR},
-                                                                                                       /* } */
+       {CSPCL, CIGN, CIGN, CIGN},      /* 0, PEOA */
+       {CSPCL, CWORD, CWORD, CWORD},   /* 1, ' ' */
+       {CNL, CNL, CNL, CNL},   /* 2, \n */
+       {CWORD, CCTL, CCTL, CWORD},     /* 3, !*-/:=?[]~ */
+       {CDQUOTE, CENDQUOTE, CWORD, CDQUOTE},   /* 4, '"' */
+       {CVAR, CVAR, CWORD, CVAR},      /* 5, $ */
+       {CSQUOTE, CWORD, CENDQUOTE, CSQUOTE},   /* 6, "'" */
+       {CSPCL, CWORD, CWORD, CLP},     /* 7, ( */
+       {CSPCL, CWORD, CWORD, CRP},     /* 8, ) */
+       {CBACK, CBACK, CCTL, CBACK},    /* 9, \ */
+       {CBQUOTE, CBQUOTE, CWORD, CBQUOTE},     /* 10, ` */
+       {CENDVAR, CENDVAR, CWORD, CENDVAR},     /* 11, } */
 #ifndef USE_SIT_FUNCTION
-                                                                                                               /* 12 */ {CENDFILE, CENDFILE, CENDFILE, CENDFILE},
-                                                                                                               /* PEOF */
-                                                                                       /* 13 */ {CWORD, CWORD, CWORD, CWORD},
-                                                                                       /* 0-9A-Za-z */
-                                                                               /* 14 */ {CCTL, CCTL, CCTL, CCTL}
-                                                                               /* CTLESC ... */
+       {CENDFILE, CENDFILE, CENDFILE, CENDFILE},       /* 12, PEOF */
+       {CWORD, CWORD, CWORD, CWORD},   /* 13, 0-9A-Za-z */
+       {CCTL, CCTL, CCTL, CCTL}        /* 14, CTLESC ... */
 #endif
 };
 
@@ -766,16 +749,16 @@ static const char syntax_index_table[258] = {
        /*   0  -130 PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
        /*   1  -129 PEOA */ CSPCL_CIGN_CIGN_CIGN,
        /*   2  -128 0xff */ CWORD_CWORD_CWORD_CWORD,
-                                                                                               /*   3  -127      */ CCTL_CCTL_CCTL_CCTL,
-                                                                                               /* CTLQUOTEMARK */
+       /*   3  -127      */ CCTL_CCTL_CCTL_CCTL,
+       /* CTLQUOTEMARK */
        /*   4  -126      */ CCTL_CCTL_CCTL_CCTL,
        /*   5  -125      */ CCTL_CCTL_CCTL_CCTL,
        /*   6  -124      */ CCTL_CCTL_CCTL_CCTL,
        /*   7  -123      */ CCTL_CCTL_CCTL_CCTL,
        /*   8  -122      */ CCTL_CCTL_CCTL_CCTL,
        /*   9  -121      */ CCTL_CCTL_CCTL_CCTL,
-                                                                                               /*  10  -120      */ CCTL_CCTL_CCTL_CCTL,
-                                                                                               /* CTLESC */
+       /*  10  -120      */ CCTL_CCTL_CCTL_CCTL,
+       /* CTLESC */
        /*  11  -119      */ CWORD_CWORD_CWORD_CWORD,
        /*  12  -118      */ CWORD_CWORD_CWORD_CWORD,
        /*  13  -117      */ CWORD_CWORD_CWORD_CWORD,
@@ -1107,15 +1090,9 @@ static void onsig(int);
 static void dotrap(void);
 static int decode_signal(const char *, int);
 
-static void shprocvar(void);
-static void deletefuncs(void);
 static void setparam(char **);
 static void freeparam(volatile struct shparam *);
 
-static void find_command(const char *, struct cmdentry *, int, const char *);
-
-static inline void hashcd(void);
-
 /* reasons for skipping commands (see comment on breakcmd routine) */
 #define SKIPBREAK       1
 #define SKIPCONT        2
@@ -1583,7 +1560,7 @@ static void setpwd(const char *, int);
 struct builtincmd {
        const char *name;
        int (*const builtinfunc) (int, char **);
-       /* unsigned flags; */
+       //unsigned flags;
 };
 
 
@@ -1660,7 +1637,7 @@ static struct builtincmd *EXECCMD;
 static struct builtincmd *EVALCMD;
 
 /* states */
-#define CONFIG_ASH_JOB_CONTROLTOPPED 1 /* all procs are stopped */
+#define JOBSTOPPED 1   /* all procs are stopped */
 #define JOBDONE 2              /* all procs are completed */
 
 /*
@@ -1708,7 +1685,6 @@ static int initialpgrp;   /* pgrp of shell on invocation */
 static int curjob;             /* current job */
 static int jobctl;
 #endif
-static int intreceived;
 
 static struct job *makejob(const union node *, int);
 static int forkshell(struct job *, const union node *, int);
@@ -1768,6 +1744,28 @@ static int cdcmd(int argc, char **argv)
 }
 
 
+/*
+ * Update curdir (the name of the current directory) in response to a
+ * cd command.  We also call hashcd to let the routines in exec.c know
+ * that the current directory has changed.
+ */
+
+static void hashcd(void);
+
+static inline void updatepwd(const char *dir)
+{
+       hashcd();                       /* update command hash table */
+
+       /*
+        * If our argument is NULL, we don't know the current directory
+        */
+       if (dir == NULL || curdir == nullstr) {
+               setpwd(0, 1);
+       } else {
+               setpwd(dir, 1);
+       }
+}
+
 /*
  * Actually do the chdir.  In an interactive shell, print the
  * directory name if "print" is nonzero.
@@ -1781,18 +1779,7 @@ static int docd(char *dest, int print)
                INTON;
                return -1;
        }
-       hashcd();
-       /*
-        * Update curdir (the name of the current directory) in response to a
-        * cd command.  We also call hashcd to let the routines in exec.c know
-        * that the current directory has changed.
-        */
-       /* If dest is NULL, we don't know the current directory */
-       if (dest == NULL || curdir == nullstr)
-               setpwd(0, 1);
-       else
-               setpwd(dest, 1);
-
+       updatepwd(dest);
        INTON;
        if (print && iflag)
                puts(curdir);
@@ -1863,6 +1850,7 @@ struct jmploc {
 #define EXERROR 1              /* a generic error */
 #define EXSHELLPROC 2  /* execute a shell procedure */
 #define EXEXEC 3               /* command execution failed */
+#define EXREDIR 4              /* redirection error */
 
 static struct jmploc *handler;
 static int exception;
@@ -1911,12 +1899,11 @@ static void onint(void)
        intpending = 0;
        sigemptyset(&mysigset);
        sigprocmask(SIG_SETMASK, &mysigset, NULL);
-       if (rootshell && iflag)
-               exraise(EXINT);
-       else {
+       if (!(rootshell && iflag)) {
                signal(SIGINT, SIG_DFL);
                raise(SIGINT);
        }
+       exraise(EXINT);
        /* NOTREACHED */
 }
 
@@ -2101,6 +2088,7 @@ static int oexitstatus;   /* saved exit status */
 
 static void evalsubshell(const union node *, int);
 static void expredir(union node *);
+static void prehash(union node *);
 static void eprintlist(struct strlist *);
 
 static union node *parsecmd(int);
@@ -2218,6 +2206,7 @@ static inline void evalloop(const union node *n, int flags)
 
        loopnest++;
        status = 0;
+       flags &= EV_TESTED;
        for (;;) {
                evaltree(n->nbinary.ch1, EV_TESTED);
                if (evalskip) {
@@ -2236,7 +2225,7 @@ static inline void evalloop(const union node *n, int flags)
                        if (exitstatus == 0)
                                break;
                }
-               evaltree(n->nbinary.ch2, flags & EV_TESTED);
+               evaltree(n->nbinary.ch2, flags);
                status = exitstatus;
                if (evalskip)
                        goto skipping;
@@ -2264,9 +2253,10 @@ static void evalfor(const union node *n, int flags)
 
        exitstatus = 0;
        loopnest++;
+       flags &= EV_TESTED;
        for (sp = arglist.list; sp; sp = sp->next) {
                setvar(n->nfor.var, sp->text, 0);
-               evaltree(n->nfor.body, flags & EV_TESTED);
+               evaltree(n->nfor.body, flags);
                if (evalskip) {
                        if (evalskip == SKIPCONT && --skipcount <= 0) {
                                evalskip = 0;
@@ -2314,7 +2304,7 @@ static inline void evalcase(const union node *n, int flags)
  * of all the rest.)
  */
 
-static inline void evalpipe(union node *n)
+static inline void evalpipe(union node *n, int flags)
 {
        struct job *jp;
        struct nodelist *lp;
@@ -2326,24 +2316,12 @@ static inline void evalpipe(union node *n)
        pipelen = 0;
        for (lp = n->npipe.cmdlist; lp; lp = lp->next)
                pipelen++;
+       flags |= EV_EXIT;
        INTOFF;
        jp = makejob(n, pipelen);
        prevfd = -1;
        for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
-               /*
-                * Search for a command.  This is called before we fork so that the
-                * location of the command will be available in the parent as well as
-                * the child.  The check for "goodname" is an overly conservative
-                * check that the name will not be subject to expansion.
-                */
-
-               struct cmdentry entry;
-               union node *lpn = lp->n;
-
-               if (lpn->type == NCMD && lpn->ncmd.args
-                       && goodname(lpn->ncmd.args->narg.text))
-                       find_command(lpn->ncmd.args->narg.text, &entry, 0, pathval());
-
+               prehash(lp->n);
                pip[1] = -1;
                if (lp->next) {
                        if (pipe(pip) < 0) {
@@ -2353,40 +2331,33 @@ static inline void evalpipe(union node *n)
                }
                if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
                        INTON;
+                       if (pip[1] >= 0) {
+                               close(pip[0]);
+                       }
                        if (prevfd > 0) {
-                               close(0);
-                               dup_as_newfd(prevfd, 0);
+                               dup2(prevfd, 0);
                                close(prevfd);
-                               if (pip[0] == 0) {
-                                       pip[0] = -1;
-                               }
                        }
-                       if (pip[1] >= 0) {
-                               if (pip[0] >= 0) {
-                                       close(pip[0]);
-                               }
-                               if (pip[1] != 1) {
-                                       close(1);
-                                       dup_as_newfd(pip[1], 1);
-                                       close(pip[1]);
-                               }
+                       if (pip[1] > 1) {
+                               dup2(pip[1], 1);
+                               close(pip[1]);
                        }
-                       evaltree(lp->n, EV_EXIT);
+                       evaltree(lp->n, flags);
                }
                if (prevfd >= 0)
                        close(prevfd);
                prevfd = pip[0];
                close(pip[1]);
        }
-       INTON;
        if (n->npipe.backgnd == 0) {
-               INTOFF;
                exitstatus = waitforjob(jp);
                TRACE(("evalpipe:  job done exit status %d\n", exitstatus));
-               INTON;
        }
+       INTON;
 }
 
+static void find_command(const char *, struct cmdentry *, int, const char *);
+
 static int isassignment(const char *word)
 {
        if (!is_name(*word)) {
@@ -2418,7 +2389,7 @@ static void evalcommand(union node *cmd, int flags)
        volatile int e;
        char *lastarg;
        const char *path;
-       const struct builtincmd *firstbltin;
+       int spclbltin;
        struct jmploc *volatile savehandler;
        struct jmploc jmploc;
 
@@ -2428,6 +2399,7 @@ static void evalcommand(union node *cmd, int flags)
        (void) &argc;
        (void) &lastarg;
        (void) &flags;
+       (void) &spclbltin;
 #endif
 
        /* First expand the arguments. */
@@ -2442,23 +2414,9 @@ static void evalcommand(union node *cmd, int flags)
        for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
                expandarg(argp, &varlist, EXP_VARTILDE);
        }
-       for (argp = cmd->ncmd.args; argp && !arglist.list; argp = argp->narg.next) {
+       for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
                expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
        }
-       if (argp) {
-               struct builtincmd *bcmd;
-               int pseudovarflag;
-
-               bcmd = find_builtin(arglist.list->text);
-               pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
-               for (; argp; argp = argp->narg.next) {
-                       if (pseudovarflag && isassignment(argp->narg.text)) {
-                               expandarg(argp, &arglist, EXP_VARTILDE);
-                               continue;
-                       }
-                       expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
-               }
-       }
        *arglist.lastp = NULL;
        *varlist.lastp = NULL;
        expredir(cmd->ncmd.redirect);
@@ -2488,7 +2446,8 @@ static void evalcommand(union node *cmd, int flags)
        /* Now locate the command. */
        if (argc == 0) {
                cmdentry.cmdtype = CMDBUILTIN;
-               firstbltin = cmdentry.u.cmd = BLTINCMD;
+               cmdentry.u.cmd = BLTINCMD;
+               spclbltin = 1;
        } else {
                const char *oldpath;
                int findflag = DO_ERR;
@@ -2505,7 +2464,7 @@ static void evalcommand(union node *cmd, int flags)
                        }
                oldpath = path;
                oldfindflag = findflag;
-               firstbltin = 0;
+               spclbltin = -1;
                for (;;) {
                        find_command(argv[0], &cmdentry, findflag, path);
                        if (cmdentry.cmdtype == CMDUNKNOWN) {   /* command not found */
@@ -2516,8 +2475,8 @@ static void evalcommand(union node *cmd, int flags)
                        if (cmdentry.cmdtype != CMDBUILTIN) {
                                break;
                        }
-                       if (!firstbltin) {
-                               firstbltin = cmdentry.u.cmd;
+                       if (spclbltin < 0) {
+                               spclbltin = !!(IS_BUILTIN_SPECIAL(cmdentry.u.cmd)) * 2;
                        }
                        if (cmdentry.u.cmd == BLTINCMD) {
                                for (;;) {
@@ -2567,13 +2526,17 @@ static void evalcommand(union node *cmd, int flags)
 
        /* Fork off a child process if necessary. */
        if (cmd->ncmd.backgnd
-               || (cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0)
+               || (cmdentry.cmdtype == CMDNORMAL && (!(flags & EV_EXIT) || trap[0]))
                ) {
+               INTOFF;
                jp = makejob(cmd, 1);
                mode = cmd->ncmd.backgnd;
                if (forkshell(jp, cmd, mode) != 0)
                        goto parent;    /* at end of routine */
+               FORCEINTON;
                flags |= EV_EXIT;
+       } else {
+               flags &= ~EV_EXIT;
        }
 
        /* This is the child process if a fork occurred. */
@@ -2584,7 +2547,6 @@ static void evalcommand(union node *cmd, int flags)
                trargs(argv);
 #endif
                exitstatus = oexitstatus;
-               redirect(cmd->ncmd.redirect, REDIR_PUSH);
                saveparam = shellparam;
                shellparam.malloc = 0;
                shellparam.nparam = argc - 1;
@@ -2594,15 +2556,14 @@ static void evalcommand(union node *cmd, int flags)
                localvars = NULL;
                INTON;
                if (setjmp(jmploc.loc)) {
-                       if (exception == EXSHELLPROC) {
-                               freeparam((volatile struct shparam *)
-                                                 &saveparam);
-                       } else {
-                               saveparam.optind = shellparam.optind;
-                               saveparam.optoff = shellparam.optoff;
-                               freeparam(&shellparam);
-                               shellparam = saveparam;
+                       if (exception == EXREDIR) {
+                               exitstatus = 2;
+                               goto funcdone;
                        }
+                       saveparam.optind = shellparam.optind;
+                       saveparam.optoff = shellparam.optoff;
+                       freeparam(&shellparam);
+                       shellparam = saveparam;
                        poplocalvars();
                        localvars = savelocalvars;
                        handler = savehandler;
@@ -2610,11 +2571,12 @@ static void evalcommand(union node *cmd, int flags)
                }
                savehandler = handler;
                handler = &jmploc;
-               for (sp = varlist.list; sp; sp = sp->next)
-                       mklocal(sp->text);
+               redirect(cmd->ncmd.redirect, REDIR_PUSH);
+               listsetvar(varlist.list);
                funcnest++;
                evaltree(cmdentry.u.func, flags & EV_TESTED);
                funcnest--;
+         funcdone:
                INTOFF;
                poplocalvars();
                localvars = savelocalvars;
@@ -2629,17 +2591,16 @@ static void evalcommand(union node *cmd, int flags)
                        evalskip = 0;
                        skipcount = 0;
                }
-               if (flags & EV_EXIT)
-                       exitshell(exitstatus);
        } else if (cmdentry.cmdtype == CMDBUILTIN) {
+               int redir;
+
 #ifdef DEBUG
                trputs("builtin command:  ");
                trargs(argv);
 #endif
-               mode = (cmdentry.u.cmd == EXECCMD) ? 0 : REDIR_PUSH;
-               redirect(cmd->ncmd.redirect, mode);
+               redir = (cmdentry.u.cmd == EXECCMD) ? 0 : REDIR_PUSH;
                savecmdname = commandname;
-               if (IS_BUILTIN_SPECIAL(firstbltin)) {
+               if (spclbltin) {
                        listsetvar(varlist.list);
                } else {
                        cmdenviron = varlist.list;
@@ -2652,6 +2613,7 @@ static void evalcommand(union node *cmd, int flags)
                }
                savehandler = handler;
                handler = &jmploc;
+               redirect(cmd->ncmd.redirect, redir);
                commandname = argv[0];
                argptr = argv + 1;
                optptr = NULL;  /* initialize nextopt */
@@ -2659,18 +2621,13 @@ static void evalcommand(union node *cmd, int flags)
                flushall();
          cmddone:
                cmdenviron = NULL;
-               if (e != EXSHELLPROC) {
-                       commandname = savecmdname;
-                       if (flags & EV_EXIT)
-                               exitshell(exitstatus);
-               }
+               commandname = savecmdname;
                handler = savehandler;
                if (e != -1) {
-                       if ((e != EXERROR && e != EXEXEC)
-                               || cmdentry.u.cmd == BLTINCMD
-                               || cmdentry.u.cmd == DOTCMD
-                               || cmdentry.u.cmd == EVALCMD || cmdentry.u.cmd == EXECCMD)
-                               exraise(e);
+                       if (e == EXINT || spclbltin & 2) {
+                               if (e == EXREDIR)
+                                       exraise(e);
+                       }
                        FORCEINTON;
                }
                if (cmdentry.u.cmd != EXECCMD)
@@ -2687,14 +2644,15 @@ static void evalcommand(union node *cmd, int flags)
                envp = environment();
                shellexec(argv, envp, path, cmdentry.u.index);
        }
+       if (flags & EV_EXIT)
+               exitshell(exitstatus);
        goto out;
 
   parent:                              /* parent process gets here (if we forked) */
        if (mode == 0) {        /* argument to fork */
-               INTOFF;
                exitstatus = waitforjob(jp);
-               INTON;
        }
+       INTON;
 
   out:
        if (lastarg)
@@ -2790,7 +2748,7 @@ static void evaltree(union node *n, int flags)
                break;
 
        case NPIPE:
-               evalpipe(n);
+               evalpipe(n, flags);
                checkexit = 1;
                break;
        case NCMD:
@@ -2818,22 +2776,27 @@ static void evaltree(union node *n, int flags)
 
 static void evalsubshell(const union node *n, int flags)
 {
-       struct job *jp;
+       struct job *jp = 0;
        int backgnd = (n->type == NBACKGND);
 
        expredir(n->nredir.redirect);
+       if (!backgnd && flags & EV_EXIT && !trap[0])
+               goto nofork;
+       INTOFF;
        jp = makejob(n, 1);
        if (forkshell(jp, n, backgnd) == 0) {
+               INTON;
+               flags |= EV_EXIT;
                if (backgnd)
                        flags &= ~EV_TESTED;
+         nofork:
                redirect(n->nredir.redirect, 0);
-               evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */
+               evaltree(n->nredir.n, flags);   /* never returns */
        }
        if (!backgnd) {
-               INTOFF;
                exitstatus = waitforjob(jp);
-               INTON;
        }
+       INTON;
 }
 
 /*
@@ -2923,6 +2886,22 @@ static void evalbackcmd(union node *n, struct backcmd *result)
  * Execute a simple command.
  */
 
+/*
+ * Search for a command.  This is called before we fork so that the
+ * location of the command will be available in the parent as well as
+ * the child.  The check for "goodname" is an overly conservative
+ * check that the name will not be subject to expansion.
+ */
+
+static void prehash(union node *n)
+{
+       struct cmdentry entry;
+
+       if (n->type == NCMD && n->ncmd.args)
+               if (goodname(n->ncmd.args->narg.text))
+                       find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
+}
+
 
 /*
  * Builtin commands.  Builtin commands whose functions are closely
@@ -3132,65 +3111,6 @@ static void clear_traps(void)
 }
 
 
-static void initshellproc(void)
-{
-
-#ifdef CONFIG_ASH_ALIAS
-       /* from alias.c: */
-       {
-               rmaliases();
-       }
-#endif
-       /* from eval.c: */
-       {
-               exitstatus = 0;
-       }
-
-       /* from exec.c: */
-       {
-               deletefuncs();
-       }
-
-       /* from jobs.c: */
-       {
-               backgndpid = -1;
-#ifdef CONFIG_ASH_JOB_CONTROL
-               jobctl = 0;
-#endif
-       }
-
-       /* from options.c: */
-       {
-               int i;
-
-               for (i = 0; i < NOPTS; i++)
-                       optent_val(i) = 0;
-               optschanged();
-
-       }
-
-       /* from redir.c: */
-       {
-               clearredir();
-       }
-
-       /* from trap.c: */
-       {
-               char *sm;
-
-               clear_traps();
-               for (sm = sigmode; sm < sigmode + NSIG - 1; sm++) {
-                       if (*sm == S_IGN)
-                               *sm = S_HARD_IGN;
-               }
-       }
-
-       /* from var.c: */
-       {
-               shprocvar();
-       }
-}
-
 static int preadbuffer(void);
 static void pushfile(void);
 
@@ -3326,7 +3246,7 @@ static void setinputfile(const char *fname, int push)
 
 static void tryexec(char *cmd, char **argv, char **envp)
 {
-       int e;
+       int repeated = 0;
 
 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
        char *name = cmd;
@@ -3344,17 +3264,21 @@ static void tryexec(char *cmd, char **argv, char **envp)
                optind = 1;
        run_applet_by_name(name, argc_l, argv);
 #endif
+  repeat:
        execve(cmd, argv, envp);
-       e = errno;
-       if (e == ENOEXEC) {
-               INTOFF;
-               initshellproc();
-               setinputfile(cmd, 0);
-               commandname = arg0 = xstrdup(argv[0]);
-               setparam(argv + 1);
-               exraise(EXSHELLPROC);
+       if (repeated++) {
+               free(argv);
+       } else if (errno == ENOEXEC) {
+               char **ap;
+               char **new;
+
+               for (ap = argv; *ap; ap++);
+               ap = new = xmalloc((ap - argv + 2) * sizeof(char *));
+               *ap++ = cmd = "/bin/sh";
+               while ((*ap++ = *argv++));
+               argv = new;
+               goto repeat;
        }
-       errno = e;
 }
 
 static char *commandtext(const union node *);
@@ -3430,7 +3354,6 @@ static const char *const *findkwd(const char *s)
 
 /*** Command hashing code ***/
 
-
 static int hashcmd(int argc, char **argv)
 {
        struct tblentry **pp;
@@ -3766,17 +3689,12 @@ find_command(const char *name, struct cmdentry *entry, int act,
  * Search the table of builtin commands.
  */
 
-static int bstrcmp(const void *name, const void *b)
-{
-       return strcmp((const char *) name, (*(const char *const *) b) + 1);
-}
-
 static struct builtincmd *find_builtin(const char *name)
 {
        struct builtincmd *bp;
 
        bp = bsearch(name, builtincmds, NUMBUILTINS, sizeof(struct builtincmd),
-                                bstrcmp);
+                                pstrcmp);
        return bp;
 }
 
@@ -3786,7 +3704,7 @@ static struct builtincmd *find_builtin(const char *name)
  * are executed they will be rehashed.
  */
 
-static inline void hashcd(void)
+static void hashcd(void)
 {
        struct tblentry **pp;
        struct tblentry *cmdp;
@@ -3852,34 +3770,6 @@ static void clearcmdentry(int firstchange)
 }
 
 
-/*
- * Delete all functions.
- */
-
-static void deletefuncs(void)
-{
-       struct tblentry **tblp;
-       struct tblentry **pp;
-       struct tblentry *cmdp;
-
-       INTOFF;
-       for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
-               pp = tblp;
-               while ((cmdp = *pp) != NULL) {
-                       if (cmdp->cmdtype == CMDFUNCTION) {
-                               *pp = cmdp->next;
-                               free(cmdp->param.func);
-                               free(cmdp);
-                       } else {
-                               pp = &cmdp->next;
-                       }
-               }
-       }
-       INTON;
-}
-
-
-
 /*
  * Locate a command in the command hash table.  If "add" is nonzero,
  * add the command to the table if it is not already present.  The
@@ -3926,7 +3816,7 @@ static struct tblentry *cmdlookup(const char *name, int add)
  * Delete the command entry returned on the last lookup.
  */
 
-static void delete_cmd_entry()
+static void delete_cmd_entry(void)
 {
        struct tblentry *cmdp;
 
@@ -4117,7 +4007,7 @@ static void expbackq(union node *, int, int);
 static int subevalvar(char *, char *, int, int, int, int, int);
 static int varisset(char *, int);
 static void strtodest(const char *, int, int);
-static inline void varvalue(char *, int, int);
+static void varvalue(char *, int, int);
 static void recordregion(int, int, int);
 static void removerecordregions(int);
 static void ifsbreakup(char *, struct arglist *);
@@ -4127,7 +4017,7 @@ static void expandmeta(struct strlist *, int);
 #if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
 #define preglob(p) _rmescapes((p), RMESCAPE_ALLOC | RMESCAPE_GLOB)
 #if !defined(GLOB_BROKEN)
-static inline void addglob(const glob_t *);
+static void addglob(const glob_t *);
 #endif
 #endif
 #if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
@@ -4431,7 +4321,6 @@ static void argstr(char *p, int flag)
                        STPUTC(c, expdest);
                }
        }
-       return;
 }
 
 static char *exptilde(char *p, int flag)
@@ -4573,7 +4462,6 @@ static void expari(int flag)
                        error("syntax error: \"%s\"\n", p + 2);
        }
        snprintf(p, 12, "%d", result);
-
        while (*p++);
 
        if (quoted == 0)
@@ -4857,7 +4745,7 @@ static void strtodest(const char *p, int syntax, int quotes)
  * Add the value of a specialized variable to the stack string.
  */
 
-static inline void varvalue(char *name, int quoted, int flags)
+static void varvalue(char *name, int quoted, int flags)
 {
        int num;
        char *p;
@@ -5059,9 +4947,10 @@ static void ifsfree(void)
 static void addfname(const char *name)
 {
        struct strlist *sp;
+       size_t len = strlen(name) + 1;
 
        sp = (struct strlist *) stalloc(sizeof *sp);
-       sp->text = sstrdup(name);
+       sp->text = memcpy(stalloc(len), name, len);
        *exparg.lastp = sp;
        exparg.lastp = &sp->next;
 }
@@ -5113,7 +5002,7 @@ static void expandmeta(struct strlist *str, int flag)
  * Add the result of glob(3) to the list.
  */
 
-static inline void addglob(const glob_t * pglob)
+static void addglob(const glob_t * pglob)
 {
        char **p = pglob->gl_pathv;
 
@@ -5704,8 +5593,7 @@ static void reset(void)
 
        /* from input.c: */
        {
-               if (exception != EXSHELLPROC)
-                       parselleft = parsenleft = 0;    /* clear input buffer */
+               parselleft = parsenleft = 0;    /* clear input buffer */
                popallfiles();
        }
 
@@ -6014,7 +5902,6 @@ static void restartjob(struct job *);
 static void freejob(struct job *);
 static struct job *getjob(const char *);
 static int dowait(int, struct job *);
-static void waitonint(int);
 
 
 /*
@@ -6045,20 +5932,12 @@ static void dupredirect(const union node *, int, int fd1dup);
 
 static void setjobctl(int enable)
 {
-#ifdef OLD_TTY_DRIVER
-       int ldisc;
-#endif
-
        if (enable == jobctl || rootshell == 0)
                return;
        if (enable) {
                do {                    /* while we are in the background */
-#ifdef OLD_TTY_DRIVER
-                       if (ioctl(2, TIOCGPGRP, (char *) &initialpgrp) < 0) {
-#else
                        initialpgrp = tcgetpgrp(2);
                        if (initialpgrp < 0) {
-#endif
                                out2str("sh: can't access tty; job control turned off\n");
                                mflag = 0;
                                return;
@@ -6070,30 +5949,14 @@ static void setjobctl(int enable)
                                continue;
                        }
                } while (0);
-#ifdef OLD_TTY_DRIVER
-               if (ioctl(2, TIOCGETD, (char *) &ldisc) < 0 || ldisc != NTTYDISC) {
-                       out2str
-                               ("sh: need new tty driver to run job control; job control turned off\n");
-                       mflag = 0;
-                       return;
-               }
-#endif
                setsignal(SIGTSTP);
                setsignal(SIGTTOU);
                setsignal(SIGTTIN);
                setpgid(0, rootpid);
-#ifdef OLD_TTY_DRIVER
-               ioctl(2, TIOCSPGRP, (char *) &rootpid);
-#else
                tcsetpgrp(2, rootpid);
-#endif
        } else {                        /* turning job control off */
                setpgid(0, initialpgrp);
-#ifdef OLD_TTY_DRIVER
-               ioctl(2, TIOCSPGRP, (char *) &initialpgrp);
-#else
                tcsetpgrp(2, initialpgrp);
-#endif
                setsignal(SIGTSTP);
                setsignal(SIGTTOU);
                setsignal(SIGTTIN);
@@ -6196,11 +6059,7 @@ static int fgcmd(int argc, char **argv)
        if (jp->jobctl == 0)
                error("job not created under job control");
        pgrp = jp->ps[0].pid;
-#ifdef OLD_TTY_DRIVER
        ioctl(2, TIOCSPGRP, (char *) &pgrp);
-#else
-       tcsetpgrp(2, pgrp);
-#endif
        restartjob(jp);
        status = waitforjob(jp);
        return status;
@@ -6566,13 +6425,8 @@ static int forkshell(struct job *jp, const union node *n, int mode)
                        setpgid(0, pgrp);
                        if (mode == FORK_FG) {
                                /*** this causes superfluous TIOCSPGRPS ***/
-#ifdef OLD_TTY_DRIVER
-                               if (ioctl(2, TIOCSPGRP, (char *) &pgrp) < 0)
-                                       error("TIOCSPGRP failed, errno=%d", errno);
-#else
                                if (tcsetpgrp(2, pgrp) < 0)
                                        error("tcsetpgrp failed, errno=%d", errno);
-#endif
                        }
                        setsignal(SIGTSTP);
                        setsignal(SIGTTOU);
@@ -6651,43 +6505,18 @@ static int waitforjob(struct job *jp)
 #endif
        int status;
        int st;
-       struct sigaction act, oact;
 
        INTOFF;
-       intreceived = 0;
-#ifdef CONFIG_ASH_JOB_CONTROL
-       if (!jobctl) {
-#else
-       if (!iflag) {
-#endif
-               sigaction(SIGINT, 0, &act);
-               act.sa_handler = waitonint;
-               sigaction(SIGINT, &act, &oact);
-       }
        TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1));
        while (jp->state == 0) {
                dowait(1, jp);
        }
-#ifdef CONFIG_ASH_JOB_CONTROL
-       if (!jobctl) {
-#else
-       if (!iflag) {
-#endif
-               sigaction(SIGINT, &oact, 0);
-               if (intreceived)
-                       kill(getpid(), SIGINT);
-       }
 #ifdef CONFIG_ASH_JOB_CONTROL
        if (jp->jobctl) {
-#ifdef OLD_TTY_DRIVER
-               if (ioctl(2, TIOCSPGRP, (char *) &mypgrp) < 0)
-                       error("TIOCSPGRP failed, errno=%d\n", errno);
-#else
                if (tcsetpgrp(2, mypgrp) < 0)
                        error("tcsetpgrp failed, errno=%d\n", errno);
-#endif
        }
-       if (jp->state == CONFIG_ASH_JOB_CONTROLTOPPED)
+       if (jp->state == JOBSTOPPED)
                curjob = jp - jobtab + 1;
 #endif
        status = jp->ps[jp->nprocs - 1].status;
@@ -6804,7 +6633,7 @@ static int dowait(int block, struct job *job)
                                        done = 0;
                        }
                        if (stopped) {  /* stopped or done */
-                               int state = done ? JOBDONE : CONFIG_ASH_JOB_CONTROLTOPPED;
+                               int state = done ? JOBDONE : JOBSTOPPED;
 
                                if (jp->state != state) {
                                        TRACE(("Job %d: changing state from %d to %d\n",
@@ -6873,7 +6702,7 @@ static int stoppedjobs(void)
        for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
                if (jp->used == 0)
                        continue;
-               if (jp->state == CONFIG_ASH_JOB_CONTROLTOPPED) {
+               if (jp->state == JOBSTOPPED) {
                        out2str("You have stopped jobs.\n");
                        job_warning = 2;
                        return (1);
@@ -7301,11 +7130,6 @@ static char *commandtext(const union node *n)
 }
 
 
-static void waitonint(int sig)
-{
-       intreceived = 1;
-}
-
 #ifdef CONFIG_ASH_MAIL
 
 /*
@@ -7493,7 +7317,7 @@ int ash_main(int argc, char **argv)
                        SIGPIPE
                };
 
-#define SIGSSIZE ((sizeof(sigs)/sizeof(sigs[0])) - 1)  /* trailing nul */
+#define SIGSSIZE ((sizeof(sigs)/sizeof(sigs[0])))
                int i;
 
                for (i = 0; i < SIGSSIZE; i++)
@@ -8342,18 +8166,6 @@ static char *single_quote(const char *s)
        return grabstackstr(p);
 }
 
-/*
- * Like strdup but works with the ash stack.
- */
-
-static char *sstrdup(const char *p)
-{
-       size_t len = strlen(p) + 1;
-
-       return memcpy(stalloc(len), p, len);
-}
-
-
 /*
  * Routine for dealing with parsed shell commands.
  */
@@ -8361,7 +8173,7 @@ static char *sstrdup(const char *p)
 
 static void sizenodelist(const struct nodelist *);
 static struct nodelist *copynodelist(const struct nodelist *);
-static char *nodexstrdup(const char *);
+static char *nodesavestr(const char *);
 
 #define CALCSIZE_TABLE
 #define COPYNODE_TABLE
@@ -8502,7 +8314,7 @@ static union node *copynode(const union node *n)
                if (!(*p & NODE_MBRMASK)) {     /* standard node */
                        *((union node **) nn) = copynode(*((const union node **) no));
                } else if ((*p & NODE_MBRMASK) == NODE_CHARPTR) {       /* string */
-                       *((const char **) nn) = nodexstrdup(*((const char **) no));
+                       *((const char **) nn) = nodesavestr(*((const char **) no));
                } else if (*p & NODE_NODELIST) {        /* nodelist */
                        *((struct nodelist **) nn)
                                = copynodelist(*((const struct nodelist **) no));
@@ -8552,7 +8364,7 @@ static union node *copynode(const union node *n)
                new->nif.test = copynode(n->nif.test);
                break;
        case NFOR:
-               new->nfor.var = nodexstrdup(n->nfor.var);
+               new->nfor.var = nodesavestr(n->nfor.var);
                new->nfor.body = copynode(n->nfor.body);
                new->nfor.args = copynode(n->nfor.args);
                break;
@@ -8568,7 +8380,7 @@ static union node *copynode(const union node *n)
        case NDEFUN:
        case NARG:
                new->narg.backquote = copynodelist(n->narg.backquote);
-               new->narg.text = nodexstrdup(n->narg.text);
+               new->narg.text = nodesavestr(n->narg.text);
                new->narg.next = copynode(n->narg.next);
                break;
        case NTO:
@@ -8731,7 +8543,7 @@ static struct nodelist *copynodelist(const struct nodelist *lp)
 }
 
 
-static char *nodexstrdup(const char *s)
+static char *nodesavestr(const char *s)
 {
        const char *p = s;
        char *q = funcstring;
@@ -8866,7 +8678,7 @@ static void options(int cmdline)
                                minus_o(*argptr, val);
                                if (*argptr)
                                        argptr++;
-                       } else if (cmdline && (c == '-')) {     /* long options */
+                       } else if (cmdline && (c == '-')) {     // long options
                                if (strcmp(p, "login") == 0)
                                        isloginsh = 1;
                                break;
@@ -11013,12 +10825,14 @@ static void redirect(union node *redir, int flags)
 {
        union node *n;
        struct redirtab *sv = NULL;
-       int i = EMPTY;
+       int i;
        int fd;
        int newfd;
        int try;
        int fd1dup = flags & REDIR_BACKQ;;      /* stdout `cmd` redir to pipe */
 
+       TRACE(("redirect(%s) called\n",
+                  flags & REDIR_PUSH ? "REDIR_PUSH" : "NO_REDIR_PUSH"));
        if (flags & REDIR_PUSH) {
                sv = xmalloc(sizeof(struct redirtab));
                for (i = 0; i < 10; i++)
@@ -11167,6 +10981,7 @@ static int dup_as_newfd(int from, int to)
 /*
  * Debugging stuff.
  */
+
 static void shtree(union node *, int, char *, FILE *);
 static void shcmd(union node *, FILE *);
 static void sharg(union node *, FILE *);
@@ -11174,13 +10989,13 @@ static void indent(int, char *, FILE *);
 static void trstring(char *);
 
 
-static void showtree(n)
-       unode *n;
+#if 0
+static void showtree(node * n)
 {
        trputs("showtree called\n");
        shtree(n, 1, NULL, stdout);
 }
-
+#endif
 
 static void shtree(union node *n, int ind, char *pfx, FILE * fp)
 {
@@ -11231,7 +11046,6 @@ static void shtree(union node *n, int ind, char *pfx, FILE * fp)
 }
 
 
-
 static void shcmd(union node *cmd, FILE * fp)
 {
        union node *np;
@@ -11306,6 +11120,7 @@ static void shcmd(union node *cmd, FILE * fp)
        }
 }
 
+
 static void sharg(union node *arg, FILE * fp)
 {
        char *p;
@@ -11401,7 +11216,6 @@ static void indent(int amount, char *pfx, FILE * fp)
        }
 }
 
-
 FILE *tracefile;
 
 #if DEBUG == 2
@@ -11610,10 +11424,6 @@ static int trapcmd(int argc, char **argv)
 }
 
 
-
-
-
-
 /*
  * Set the signal handler for the specified signal.  The routine figures
  * out what it should be set to.
@@ -11819,7 +11629,7 @@ static void initvar()
         * PS1 depends on uid
         */
        if ((vps1.flags & VEXPORT) == 0) {
-               vpp = hashvar("PS1=$");
+               vpp = hashvar("PS1=$ ");
                vps1.next = *vpp;
                *vpp = &vps1;
                vps1.text = xstrdup(geteuid()? "PS1=$ " : "PS1=# ");
@@ -12012,39 +11822,6 @@ static char **environment()
 }
 
 
-/*
- * Called when a shell procedure is invoked to clear out nonexported
- * variables.  It is also necessary to reallocate variables of with
- * VSTACK set since these are currently allocated on the stack.
- */
-
-static void shprocvar(void)
-{
-       struct var **vpp;
-       struct var *vp, **prev;
-
-       for (vpp = vartab; vpp < vartab + VTABSIZE; vpp++) {
-               for (prev = vpp; (vp = *prev) != NULL;) {
-                       if ((vp->flags & VEXPORT) == 0) {
-                               *prev = vp->next;
-                               if ((vp->flags & VTEXTFIXED) == 0)
-                                       free(vp->text);
-                               if ((vp->flags & VSTRFIXED) == 0)
-                                       free(vp);
-                       } else {
-                               if (vp->flags & VSTACK) {
-                                       vp->text = xstrdup(vp->text);
-                                       vp->flags &= ~VSTACK;
-                               }
-                               prev = &vp->next;
-                       }
-               }
-       }
-       initvar();
-}
-
-
-
 /*
  * Command to list all variables which are set.  Currently this command
  * is invoked from the set command when the set command is called without
@@ -12335,7 +12112,6 @@ static struct var **findvar(struct var **vpp, const char *name)
 /*
  * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
  * This file contains code for the times builtin.
- * $Id: ash.c,v 1.57 2002/08/22 18:30:15 bug1 Exp $
  */
 static int timescmd(int argc, char **argv)
 {