ash: cleanup part 8
authorDenis Vlasenko <vda.linux@googlemail.com>
Fri, 23 Feb 2007 01:05:38 +0000 (01:05 -0000)
committerDenis Vlasenko <vda.linux@googlemail.com>
Fri, 23 Feb 2007 01:05:38 +0000 (01:05 -0000)
shell/ash.c

index e061211a0701e7d0ef95a68f2eb5dc9ec670964e..94333360b96cd6bbf6bd9f203fca7e66f009c88f 100644 (file)
@@ -407,6 +407,7 @@ out2str(const char *p)
 
 
 /* ============ Parsing structures */
+
 #define NCMD 0
 #define NPIPE 1
 #define NREDIR 2
@@ -896,12 +897,7 @@ struct strlist {
 };
 
 #if ENABLE_ASH_ALIAS
-#define ALIASINUSE 1
-#define ALIASDEAD  2
 struct alias;
-static int aliascmd(int, char **);
-static int unaliascmd(int, char **);
-static void printalias(const struct alias *);
 #endif
 
 struct strpush {
@@ -1485,7 +1481,7 @@ nextopt(const char *optstring)
 }
 
 
-/* ============ Variables */
+/* ============ Shell variables */
 
 /* flags */
 #define VEXPORT         0x01    /* variable is exported */
@@ -1503,11 +1499,6 @@ nextopt(const char *optstring)
 # define VDYNAMIC        0
 #endif
 
-#if ENABLE_LOCALE_SUPPORT
-static void change_lc_all(const char *value);
-static void change_lc_ctype(const char *value);
-#endif
-
 static const char defpathvar[] = "PATH=/usr/local/bin:/usr/bin:/sbin:/bin";
 #ifdef IFS_BROKEN
 static const char defifsvar[] = "IFS= \t\n";
@@ -1516,6 +1507,27 @@ static const char defifsvar[] = "IFS= \t\n";
 static const char defifs[] = " \t\n";
 #endif
 
+struct shparam {
+       int nparam;             /* # of positional parameters (without $0) */
+       unsigned char malloc;   /* if parameter list dynamically allocated */
+       char **p;               /* parameter list */
+#if ENABLE_ASH_GETOPTS
+       int optind;             /* next parameter to be processed by getopts */
+       int optoff;             /* used by getopts */
+#endif
+};
+
+static struct shparam shellparam;      /* $@ current positional parameters */
+
+#if ENABLE_ASH_GETOPTS
+static void
+getoptsreset(const char *value)
+{
+       shellparam.optind = number(value);
+       shellparam.optoff = -1;
+}
+#endif
+
 struct var {
        struct var *next;               /* next entry in hash list */
        int flags;                      /* flags are defined above */
@@ -1532,46 +1544,45 @@ struct localvar {
 };
 
 /* Forward decls for varinit[] */
+#if ENABLE_LOCALE_SUPPORT
+static void change_lc_all(const char *value);
+static void change_lc_ctype(const char *value);
+#endif
 #if ENABLE_ASH_MAIL
 static void chkmail(void);
 static void changemail(const char *);
 #endif
 static void changepath(const char *);
-#if ENABLE_ASH_GETOPTS
-static void getoptsreset(const char *);
-#endif
 #if ENABLE_ASH_RANDOM_SUPPORT
 static void change_random(const char *);
 #endif
 
 static struct var varinit[] = {
 #ifdef IFS_BROKEN
-       { 0,    VSTRFIXED|VTEXTFIXED,           defifsvar,      0 },
+       { NULL, VSTRFIXED|VTEXTFIXED,           defifsvar,      NULL },
 #else
-       { 0,    VSTRFIXED|VTEXTFIXED|VUNSET,    "IFS\0",        0 },
+       { NULL, VSTRFIXED|VTEXTFIXED|VUNSET,    "IFS\0",        NULL },
 #endif
-
 #if ENABLE_ASH_MAIL
-       { 0,    VSTRFIXED|VTEXTFIXED|VUNSET,    "MAIL\0",       changemail },
-       { 0,    VSTRFIXED|VTEXTFIXED|VUNSET,    "MAILPATH\0",   changemail },
+       { NULL, VSTRFIXED|VTEXTFIXED|VUNSET,    "MAIL\0",       changemail },
+       { NULL, VSTRFIXED|VTEXTFIXED|VUNSET,    "MAILPATH\0",   changemail },
 #endif
-
-       { 0,    VSTRFIXED|VTEXTFIXED,           defpathvar,     changepath },
-       { 0,    VSTRFIXED|VTEXTFIXED,           "PS1=$ ",       0          },
-       { 0,    VSTRFIXED|VTEXTFIXED,           "PS2=> ",       0          },
-       { 0,    VSTRFIXED|VTEXTFIXED,           "PS4=+ ",       0          },
+       { NULL, VSTRFIXED|VTEXTFIXED,           defpathvar,     changepath },
+       { NULL, VSTRFIXED|VTEXTFIXED,           "PS1=$ ",       NULL },
+       { NULL, VSTRFIXED|VTEXTFIXED,           "PS2=> ",       NULL },
+       { NULL, VSTRFIXED|VTEXTFIXED,           "PS4=+ ",       NULL },
 #if ENABLE_ASH_GETOPTS
-       { 0,    VSTRFIXED|VTEXTFIXED,           "OPTIND=1",     getoptsreset },
+       { NULL, VSTRFIXED|VTEXTFIXED,           "OPTIND=1",     getoptsreset },
 #endif
 #if ENABLE_ASH_RANDOM_SUPPORT
-       {0, VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random },
+       { NULL, VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random },
 #endif
 #if ENABLE_LOCALE_SUPPORT
-       {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL\0", change_lc_all },
-       {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE\0", change_lc_ctype },
+       { NULL, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL\0",    change_lc_all },
+       { NULL, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE\0",  change_lc_ctype },
 #endif
 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
-       {0, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE\0", NULL },
+       { NULL, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE\0",  NULL },
 #endif
 };
 
@@ -1611,10 +1622,6 @@ static struct var varinit[] = {
 
 #define mpathset()      ((vmpath.flags & VUNSET) == 0)
 
-static struct var **hashvar(const char *);
-
-static int loopnest;            /* current loop nesting level */
-
 /*
  * The parsefile structure pointed to by the global variable parsefile
  * contains information about the current file being read.
@@ -1627,36 +1634,13 @@ struct redirtab {
 
 static struct redirtab *redirlist;
 static int nullredirs;
-
 extern char **environ;
-
 static int preverrout_fd;   /* save fd2 before print debug if xflag is set. */
 
-struct shparam {
-       int nparam;             /* # of positional parameters (without $0) */
-       unsigned char malloc;   /* if parameter list dynamically allocated */
-       char **p;               /* parameter list */
-#if ENABLE_ASH_GETOPTS
-       int optind;             /* next parameter to be processed by getopts */
-       int optoff;             /* used by getopts */
-#endif
-};
-
-static struct shparam shellparam;      /* $@ current positional parameters */
-
 #define VTABSIZE 39
 
 static struct var *vartab[VTABSIZE];
 
-#if ENABLE_ASH_GETOPTS
-static void
-getoptsreset(const char *value)
-{
-       shellparam.optind = number(value);
-       shellparam.optoff = -1;
-}
-#endif
-
 #define is_name(c)      ((c) == '_' || isalpha((unsigned char)(c)))
 #define is_in_name(c)   ((c) == '_' || isalnum((unsigned char)(c)))
 
@@ -2397,6 +2381,7 @@ static int casematch(union node *, char *);
 static void expari(int);
 #endif
 
+
 /*      parser.h     */
 
 /* control characters in argument strings */
@@ -2452,7 +2437,6 @@ static char *parsenextc;                /* copy of parsefile->nextc */
 
 #define basebuf bb_common_bufsiz1       /* buffer for top level input file */
 
-
 static int tokpushback;                 /* last token pushed back */
 #define NEOF ((union node *)&tokpushback)
 static int parsebackquote;             /* nonzero if we are inside backquotes */
@@ -2465,7 +2449,7 @@ static struct heredoc *heredoc;
 static int quoteflag;                  /* set if (part of) last token was quoted */
 
 static void fixredir(union node *, const char *, int);
-static char *endofname(const char *);
+
 
 /*      shell.h   */
 
@@ -2478,7 +2462,6 @@ static const char dolatstr[] = { CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0' };
 
 #define xlikely(x)       __builtin_expect((x),1)
 
-
 #define TEOF 0
 #define TNL 1
 #define TREDIR 2
@@ -2610,12 +2593,6 @@ findkwd(const char *s)
        ( (((unsigned int)c) - 33 < 32) \
                         && ((0xc1ff920dUL >> (((unsigned int)c) - 33)) & 1))
 
-#define digit_val(c)    ((c) - '0')
-
-/*
- * This file was generated by the mksyntax program.
- */
-
 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE
 #define USE_SIT_FUNCTION
 #endif
@@ -3019,15 +2996,15 @@ static const char syntax_index_table[258] = {
 
 #endif  /* USE_SIT_FUNCTION */
 
-/*      alias.c      */
 
+/*      alias.c      */
 
 #define ATABSIZE 39
 
-static int     funcblocksize;          /* size of structures in function */
-static int     funcstringsize;         /* size of strings in node */
-static void   *funcblock;              /* block to allocate function from */
-static char   *funcstring;             /* block to allocate strings from */
+static int funcblocksize;          /* size of structures in function */
+static int funcstringsize;         /* size of strings in node */
+static void *funcblock;            /* block to allocate function from */
+static char *funcstring;           /* block to allocate strings from */
 
 static const short nodesize[26] = {
        SHELL_ALIGN(sizeof(struct ncmd)),
@@ -3058,14 +3035,12 @@ static const short nodesize[26] = {
        SHELL_ALIGN(sizeof(struct nnot)),
 };
 
-
 static void calcsize(union node *);
 static void sizenodelist(struct nodelist *);
 static union node *copynode(union node *);
 static struct nodelist *copynodelist(struct nodelist *);
 static char *nodeckstrdup(char *);
 
-
 static int evalskip;                   /* set if we are skipping commands */
 static int skipcount;           /* number of levels to skip */
 static int funcnest;                   /* depth of function calls */
@@ -3077,60 +3052,6 @@ static int funcnest;                   /* depth of function calls */
 #define SKIPFILE       (1 << 3)
 #define SKIPEVAL       (1 << 4)
 
-/*
- * This file was generated by the mkbuiltins program.
- */
-
-#if JOBS
-static int fg_bgcmd(int, char **);
-#endif
-static int breakcmd(int, char **);
-static int cdcmd(int, char **);
-#if ENABLE_ASH_CMDCMD
-static int commandcmd(int, char **);
-#endif
-static int dotcmd(int, char **);
-static int evalcmd(int, char **);
-#if ENABLE_ASH_BUILTIN_ECHO
-static int echocmd(int, char **);
-#endif
-#if ENABLE_ASH_BUILTIN_TEST
-static int testcmd(int, char **);
-#endif
-static int execcmd(int, char **);
-static int exitcmd(int, char **);
-static int exportcmd(int, char **);
-static int falsecmd(int, char **);
-#if ENABLE_ASH_GETOPTS
-static int getoptscmd(int, char **);
-#endif
-static int hashcmd(int, char **);
-#if !ENABLE_FEATURE_SH_EXTRA_QUIET
-static int helpcmd(int argc, char **argv);
-#endif
-#if JOBS
-static int jobscmd(int, char **);
-#endif
-#if ENABLE_ASH_MATH_SUPPORT
-static int letcmd(int, char **);
-#endif
-static int localcmd(int, char **);
-static int pwdcmd(int, char **);
-static int readcmd(int, char **);
-static int returncmd(int, char **);
-static int setcmd(int, char **);
-static int shiftcmd(int, char **);
-static int timescmd(int, char **);
-static int trapcmd(int, char **);
-static int truecmd(int, char **);
-static int typecmd(int, char **);
-static int umaskcmd(int, char **);
-static int unsetcmd(int, char **);
-static int waitcmd(int, char **);
-static int ulimitcmd(int, char **);
-#if JOBS
-static int killcmd(int, char **);
-#endif
 
 /*      exec.h    */
 
@@ -3189,30 +3110,9 @@ static unsigned long rseed;
 # endif
 #endif
 
-/* PEOF (the end of file marker) */
-
-enum {
-       INPUT_PUSH_FILE = 1,
-       INPUT_NOFILE_OK = 2,
-};
-
-/*
- * The input line number.  Input.c just defines this variable, and saves
- * and restores it when files are pushed and popped.  The user of this
- * package must set its value.
- */
-static void pungetc(void);
-static void pushstring(char *, void *);
-static void popstring(void);
-static void setinputfd(int, int);
-static void setinputstring(char *);
-static void popfile(void);
-static void popallfiles(void);
-static void closescript(void);
 
 /*      jobs.h    */
 
-
 /* Mode argument to forkshell.  Don't change FORK_FG or FORK_BG. */
 #define FORK_FG 0
 #define FORK_BG 1
@@ -3286,7 +3186,6 @@ static void readcmdfile(char *);
 
 static char *minusc;                   /* argument to -c option */
 
-
 static void optschanged(void);
 static void setparam(char **);
 static void freeparam(volatile struct shparam *);
@@ -3350,7 +3249,12 @@ static int is_safe_applet(char *name)
 }
 
 
+/* ============ Alias handling */
 #if ENABLE_ASH_ALIAS
+
+#define ALIASINUSE 1
+#define ALIASDEAD  2
+
 struct alias {
        struct alias *next;
        char *name;
@@ -3475,6 +3379,12 @@ rmaliases(void)
        INT_ON;
 }
 
+static void
+printalias(const struct alias *ap)
+{
+       out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
+}
+
 /*
  * TODO - sort output
  */
@@ -3532,25 +3442,17 @@ unaliascmd(int argc, char **argv)
 
        return i;
 }
-
-static void
-printalias(const struct alias *ap)
-{
-       out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
-}
 #endif /* ASH_ALIAS */
 
-/*      eval.c  */
 
-/*
- * Evaluate a command.
- */
+/* ============ eval.c  */
 
 /* flags in argument to evaltree */
 #define EV_EXIT 01              /* exit after evaluating tree */
 #define EV_TESTED 02            /* exit status is checked; ignore -e flag */
 #define EV_BACKCMD 04           /* command executing within back quotes */
 
+/* forward declarations - evaluation is faily recursive business... */
 static void evalloop(union node *, int);
 static void evalfor(union node *, int);
 static void evalcase(union node *, int);
@@ -3679,12 +3581,12 @@ evaltree(union node *n, int flags)
        }
 }
 
-
 #if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
 static
 #endif
 void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
 
+static int loopnest;            /* current loop nesting level */
 
 static void
 evalloop(union node *n, int flags)
@@ -3722,7 +3624,6 @@ evalloop(union node *n, int flags)
        exitstatus = status;
 }
 
-
 static void
 evalfor(union node *n, int flags)
 {
@@ -3762,7 +3663,6 @@ evalfor(union node *n, int flags)
        popstackmark(&smark);
 }
 
-
 static void
 evalcase(union node *n, int flags)
 {
@@ -3789,7 +3689,6 @@ evalcase(union node *n, int flags)
        popstackmark(&smark);
 }
 
-
 /*
  * Kick off a subshell to evaluate a tree.
  */
@@ -3822,7 +3721,6 @@ evalsubshell(union node *n, int flags)
        INT_ON;
 }
 
-
 /*
  * Compute the names of the files in a redirection list.
  */
@@ -3858,7 +3756,6 @@ expredir(union node *n)
        }
 }
 
-
 /*
  * Evaluate a pipeline.  All the processes in the pipeline are children
  * of the process creating the pipeline.  (This differs from some versions
@@ -3919,7 +3816,6 @@ evalpipe(union node *n, int flags)
        INT_ON;
 }
 
-
 #if ENABLE_ASH_CMDCMD
 static char **
 parse_command_args(char **argv, const char **path)
@@ -3955,6 +3851,57 @@ parse_command_args(char **argv, const char **path)
 }
 #endif
 
+/* Forward declarations for builtintab[] */
+#if JOBS
+static int fg_bgcmd(int, char **);
+#endif
+static int breakcmd(int, char **);
+#if ENABLE_ASH_CMDCMD
+static int commandcmd(int, char **);
+#endif
+static int dotcmd(int, char **);
+static int evalcmd(int, char **);
+#if ENABLE_ASH_BUILTIN_ECHO
+static int echocmd(int, char **);
+#endif
+#if ENABLE_ASH_BUILTIN_TEST
+static int testcmd(int, char **);
+#endif
+static int execcmd(int, char **);
+static int exitcmd(int, char **);
+static int exportcmd(int, char **);
+static int falsecmd(int, char **);
+#if ENABLE_ASH_GETOPTS
+static int getoptscmd(int, char **);
+#endif
+static int hashcmd(int, char **);
+#if !ENABLE_FEATURE_SH_EXTRA_QUIET
+static int helpcmd(int argc, char **argv);
+#endif
+#if JOBS
+static int jobscmd(int, char **);
+#endif
+#if ENABLE_ASH_MATH_SUPPORT
+static int letcmd(int, char **);
+#endif
+static int localcmd(int, char **);
+static int pwdcmd(int, char **);
+static int readcmd(int, char **);
+static int returncmd(int, char **);
+static int setcmd(int, char **);
+static int shiftcmd(int, char **);
+static int timescmd(int, char **);
+static int trapcmd(int, char **);
+static int truecmd(int, char **);
+static int typecmd(int, char **);
+static int umaskcmd(int, char **);
+static int unsetcmd(int, char **);
+static int waitcmd(int, char **);
+static int ulimitcmd(int, char **);
+#if JOBS
+static int killcmd(int, char **);
+#endif
+
 #define BUILTIN_NOSPEC  "0"
 #define BUILTIN_SPECIAL "1"
 #define BUILTIN_REGULAR "2"
@@ -4514,7 +4461,7 @@ execcmd(int argc, char **argv)
 }
 
 
-/*      exec.c    */
+/* ============ Executing commands */
 
 /*
  * When commands are first encountered, they are entered in a hash table.
@@ -4528,7 +4475,6 @@ execcmd(int argc, char **argv)
 #define CMDTABLESIZE 31         /* should be prime */
 #define ARB 1                   /* actual size determined at run time */
 
-
 struct tblentry {
        struct tblentry *next;  /* next entry in hash chain */
        union param param;      /* definition of builtin function */
@@ -4537,38 +4483,86 @@ struct tblentry {
        char cmdname[ARB];      /* name of command */
 };
 
-
 static struct tblentry *cmdtable[CMDTABLESIZE];
 static int builtinloc = -1;             /* index in path of %builtin, or -1 */
 
-
-static void tryexec(char *, char **, char **);
-static void clearcmdentry(int);
-static struct tblentry *cmdlookup(const char *, int);
-static void delete_cmd_entry(void);
-
-
-/*
- * Exec a program.  Never returns.  If you change this routine, you may
- * have to change the find_command routine as well.
- */
-#define environment() listvars(VEXPORT, VUNSET, 0)
-static void shellexec(char **, const char *, int) ATTRIBUTE_NORETURN;
 static void
-shellexec(char **argv, const char *path, int idx)
+tryexec(char *cmd, char **argv, char **envp)
 {
-       char *cmdname;
-       int e;
-       char **envp;
-       int exerrno;
+       int repeated = 0;
+       struct BB_applet *a;
+       int argc = 0;
+       char **c;
 
-       clearredir(1);
-       envp = environment();
-       if (strchr(argv[0], '/') || is_safe_applet(argv[0])
+       if (strchr(cmd, '/') == NULL
+        && (a = find_applet_by_name(cmd)) != NULL
+        && is_safe_applet(cmd)
+       ) {
+               c = argv;
+               while (*c != NULL) {
+                       c++; argc++;
+               }
+               applet_name = cmd;
+               exit(a->main(argc, argv));
+       }
 #if ENABLE_FEATURE_SH_STANDALONE_SHELL
-        || find_applet_by_name(argv[0])
+       if (find_applet_by_name(cmd) != NULL) {
+               /* re-exec ourselves with the new arguments */
+               execve(CONFIG_BUSYBOX_EXEC_PATH, argv, envp);
+               /* If they called chroot or otherwise made the binary no longer
+                * executable, fall through */
+       }
 #endif
-       ) {
+
+ repeat:
+#ifdef SYSV
+       do {
+               execve(cmd, argv, envp);
+       } while (errno == EINTR);
+#else
+       execve(cmd, argv, envp);
+#endif
+       if (repeated++) {
+               free(argv);
+       } else if (errno == ENOEXEC) {
+               char **ap;
+               char **new;
+
+               for (ap = argv; *ap; ap++)
+                       ;
+               ap = new = ckmalloc((ap - argv + 2) * sizeof(char *));
+               ap[1] = cmd;
+               *ap = cmd = (char *)DEFAULT_SHELL;
+               ap += 2;
+               argv++;
+               while ((*ap++ = *argv++))
+                       ;
+               argv = new;
+               goto repeat;
+       }
+}
+
+/*
+ * Exec a program.  Never returns.  If you change this routine, you may
+ * have to change the find_command routine as well.
+ */
+#define environment() listvars(VEXPORT, VUNSET, 0)
+static void shellexec(char **, const char *, int) ATTRIBUTE_NORETURN;
+static void
+shellexec(char **argv, const char *path, int idx)
+{
+       char *cmdname;
+       int e;
+       char **envp;
+       int exerrno;
+
+       clearredir(1);
+       envp = environment();
+       if (strchr(argv[0], '/') || is_safe_applet(argv[0])
+#if ENABLE_FEATURE_SH_STANDALONE_SHELL
+        || find_applet_by_name(argv[0])
+#endif
+       ) {
                tryexec(argv[0], argv, envp);
                e = errno;
        } else {
@@ -4602,83 +4596,128 @@ shellexec(char **argv, const char *path, int idx)
        /* NOTREACHED */
 }
 
+static void
+printentry(struct tblentry *cmdp)
+{
+       int idx;
+       const char *path;
+       char *name;
+
+       idx = cmdp->param.index;
+       path = pathval();
+       do {
+               name = padvance(&path, cmdp->cmdname);
+               stunalloc(name);
+       } while (--idx >= 0);
+       out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
+}
 
+/*
+ * Clear out command entries.  The argument specifies the first entry in
+ * PATH which has changed.
+ */
 static void
-tryexec(char *cmd, char **argv, char **envp)
+clearcmdentry(int firstchange)
 {
-       int repeated = 0;
-       struct BB_applet *a;
-       int argc = 0;
-       char **c;
+       struct tblentry **tblp;
+       struct tblentry **pp;
+       struct tblentry *cmdp;
 
-       if (strchr(cmd, '/') == NULL
-        && (a = find_applet_by_name(cmd)) != NULL
-        && is_safe_applet(cmd)
-       ) {
-               c = argv;
-               while (*c != NULL) {
-                       c++; argc++;
+       INT_OFF;
+       for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
+               pp = tblp;
+               while ((cmdp = *pp) != NULL) {
+                       if ((cmdp->cmdtype == CMDNORMAL &&
+                            cmdp->param.index >= firstchange)
+                        || (cmdp->cmdtype == CMDBUILTIN &&
+                            builtinloc >= firstchange)
+                       ) {
+                               *pp = cmdp->next;
+                               free(cmdp);
+                       } else {
+                               pp = &cmdp->next;
+                       }
                }
-               applet_name = cmd;
-               exit(a->main(argc, argv));
-       }
-#if ENABLE_FEATURE_SH_STANDALONE_SHELL
-       if (find_applet_by_name(cmd) != NULL) {
-               /* re-exec ourselves with the new arguments */
-               execve(CONFIG_BUSYBOX_EXEC_PATH, argv, envp);
-               /* If they called chroot or otherwise made the binary no longer
-                * executable, fall through */
        }
-#endif
+       INT_ON;
+}
 
- repeat:
-#ifdef SYSV
-       do {
-               execve(cmd, argv, envp);
-       } while (errno == EINTR);
-#else
-       execve(cmd, argv, envp);
-#endif
-       if (repeated++) {
-               free(argv);
-       } else if (errno == ENOEXEC) {
-               char **ap;
-               char **new;
+/*
+ * 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
+ * variable "lastcmdentry" is set to point to the address of the link
+ * pointing to the entry, so that delete_cmd_entry can delete the
+ * entry.
+ *
+ * Interrupts must be off if called with add != 0.
+ */
+static struct tblentry **lastcmdentry;
 
-               for (ap = argv; *ap; ap++)
-                       ;
-               ap = new = ckmalloc((ap - argv + 2) * sizeof(char *));
-               ap[1] = cmd;
-               *ap = cmd = (char *)DEFAULT_SHELL;
-               ap += 2;
-               argv++;
-               while ((*ap++ = *argv++))
-                       ;
-               argv = new;
-               goto repeat;
+static struct tblentry *
+cmdlookup(const char *name, int add)
+{
+       unsigned int hashval;
+       const char *p;
+       struct tblentry *cmdp;
+       struct tblentry **pp;
+
+       p = name;
+       hashval = (unsigned char)*p << 4;
+       while (*p)
+               hashval += (unsigned char)*p++;
+       hashval &= 0x7FFF;
+       pp = &cmdtable[hashval % CMDTABLESIZE];
+       for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
+               if (strcmp(cmdp->cmdname, name) == 0)
+                       break;
+               pp = &cmdp->next;
+       }
+       if (add && cmdp == NULL) {
+               cmdp = *pp = ckmalloc(sizeof(struct tblentry) - ARB
+                                       + strlen(name) + 1);
+               cmdp->next = NULL;
+               cmdp->cmdtype = CMDUNKNOWN;
+               strcpy(cmdp->cmdname, name);
        }
+       lastcmdentry = pp;
+       return cmdp;
 }
 
+/*
+ * Delete the command entry returned on the last lookup.
+ */
+static void
+delete_cmd_entry(void)
+{
+       struct tblentry *cmdp;
 
-/*** Command hashing code ***/
+       INT_OFF;
+       cmdp = *lastcmdentry;
+       *lastcmdentry = cmdp->next;
+       if (cmdp->cmdtype == CMDFUNCTION)
+               freefunc(cmdp->param.func);
+       free(cmdp);
+       INT_ON;
+}
 
+/*
+ * Add a new command entry, replacing any existing command entry for
+ * the same name - except special builtins.
+ */
 static void
-printentry(struct tblentry *cmdp)
+addcmdentry(char *name, struct cmdentry *entry)
 {
-       int idx;
-       const char *path;
-       char *name;
+       struct tblentry *cmdp;
 
-       idx = cmdp->param.index;
-       path = pathval();
-       do {
-               name = padvance(&path, cmdp->cmdname);
-               stunalloc(name);
-       } while (--idx >= 0);
-       out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
+       cmdp = cmdlookup(name, 1);
+       if (cmdp->cmdtype == CMDFUNCTION) {
+               freefunc(cmdp->param.func);
+       }
+       cmdp->cmdtype = entry->cmdtype;
+       cmdp->param = entry->u;
+       cmdp->rehash = 0;
 }
 
-
 static int
 hashcmd(int argc, char **argv)
 {
@@ -4716,7 +4755,6 @@ hashcmd(int argc, char **argv)
        return c;
 }
 
-
 /*
  * Resolve a command name.  If you change this routine, you may have to
  * change the shellexec routine as well.
@@ -4901,7 +4939,6 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
        entry->u = cmdp->param;
 }
 
-
 /*
  * Search the table of builtin commands.
  */
@@ -4917,7 +4954,6 @@ find_builtin(const char *name)
        return bp;
 }
 
-
 /*
  * Called when a cd is done.  Marks all commands so the next time they
  * are executed they will be rehashed.
@@ -4940,7 +4976,6 @@ hashcd(void)
        }
 }
 
-
 /*
  * Fix command hash table when PATH changed.
  * Called before PATH is changed.  The argument is the new value of PATH;
@@ -4986,116 +5021,6 @@ changepath(const char *newval)
 }
 
 
-/*
- * Clear out command entries.  The argument specifies the first entry in
- * PATH which has changed.
- */
-static void
-clearcmdentry(int firstchange)
-{
-       struct tblentry **tblp;
-       struct tblentry **pp;
-       struct tblentry *cmdp;
-
-       INT_OFF;
-       for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
-               pp = tblp;
-               while ((cmdp = *pp) != NULL) {
-                       if ((cmdp->cmdtype == CMDNORMAL &&
-                            cmdp->param.index >= firstchange)
-                        || (cmdp->cmdtype == CMDBUILTIN &&
-                            builtinloc >= firstchange)
-                       ) {
-                               *pp = cmdp->next;
-                               free(cmdp);
-                       } else {
-                               pp = &cmdp->next;
-                       }
-               }
-       }
-       INT_ON;
-}
-
-
-/*
- * 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
- * variable "lastcmdentry" is set to point to the address of the link
- * pointing to the entry, so that delete_cmd_entry can delete the
- * entry.
- *
- * Interrupts must be off if called with add != 0.
- */
-static struct tblentry **lastcmdentry;
-
-static struct tblentry *
-cmdlookup(const char *name, int add)
-{
-       unsigned int hashval;
-       const char *p;
-       struct tblentry *cmdp;
-       struct tblentry **pp;
-
-       p = name;
-       hashval = (unsigned char)*p << 4;
-       while (*p)
-               hashval += (unsigned char)*p++;
-       hashval &= 0x7FFF;
-       pp = &cmdtable[hashval % CMDTABLESIZE];
-       for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
-               if (strcmp(cmdp->cmdname, name) == 0)
-                       break;
-               pp = &cmdp->next;
-       }
-       if (add && cmdp == NULL) {
-               cmdp = *pp = ckmalloc(sizeof(struct tblentry) - ARB
-                                       + strlen(name) + 1);
-               cmdp->next = NULL;
-               cmdp->cmdtype = CMDUNKNOWN;
-               strcpy(cmdp->cmdname, name);
-       }
-       lastcmdentry = pp;
-       return cmdp;
-}
-
-
-/*
- * Delete the command entry returned on the last lookup.
- */
-static void
-delete_cmd_entry(void)
-{
-       struct tblentry *cmdp;
-
-       INT_OFF;
-       cmdp = *lastcmdentry;
-       *lastcmdentry = cmdp->next;
-       if (cmdp->cmdtype == CMDFUNCTION)
-               freefunc(cmdp->param.func);
-       free(cmdp);
-       INT_ON;
-}
-
-
-/*
- * Add a new command entry, replacing any existing command entry for
- * the same name - except special builtins.
- */
-static void
-addcmdentry(char *name, struct cmdentry *entry)
-{
-       struct tblentry *cmdp;
-
-       cmdp = cmdlookup(name, 1);
-       if (cmdp->cmdtype == CMDFUNCTION) {
-               freefunc(cmdp->param.func);
-       }
-       cmdp->cmdtype = entry->cmdtype;
-       cmdp->param = entry->u;
-       cmdp->rehash = 0;
-}
-
-
 /*
  * Make a copy of a parse tree.
  */
@@ -5145,6 +5070,7 @@ unsetfunc(const char *name)
                delete_cmd_entry();
 }
 
+
 /*
  * Locate and print what a word is...
  */
@@ -6804,94 +6730,45 @@ varunset(const char *end, const char *var, const char *umsg, int varflags)
 }
 
 
-/*      input.c      */
-
-/*
+/* ============ input.c
+ *
  * This implements the input routines used by the parser.
  */
-
 #define EOF_NLEFT -99           /* value of parsenleft when EOF pushed back */
 
-static void pushfile(void);
-
-/*
- * Read a character from the script, returning PEOF on end of file.
- * Nul characters in the input are silently discarded.
- */
-static int preadbuffer(void);
-#define pgetc_as_macro()   (--parsenleft >= 0? SC2INT(*parsenextc++) : preadbuffer())
+enum {
+       INPUT_PUSH_FILE = 1,
+       INPUT_NOFILE_OK = 2,
+};
 
-#if ENABLE_ASH_OPTIMIZE_FOR_SIZE
-#define pgetc_macro() pgetc()
-static int
-pgetc(void)
-{
-       return pgetc_as_macro();
-}
-#else
-#define pgetc_macro()   pgetc_as_macro()
-static int
-pgetc(void)
+static void
+popstring(void)
 {
-       return pgetc_macro();
-}
-#endif
+       struct strpush *sp = parsefile->strpush;
 
-/*
- * Same as pgetc(), but ignores PEOA.
- */
+       INT_OFF;
 #if ENABLE_ASH_ALIAS
-static int
-pgetc2(void)
-{
-       int c;
-
-       do {
-               c = pgetc_macro();
-       } while (c == PEOA);
-       return c;
-}
-#else
-static int
-pgetc2(void)
-{
-       return pgetc_macro();
-}
-#endif
-
-/*
- * Read a line from the script.
- */
-static char *
-pfgets(char *line, int len)
-{
-       char *p = line;
-       int nleft = len;
-       int c;
-
-       while (--nleft > 0) {
-               c = pgetc2();
-               if (c == PEOF) {
-                       if (p == line)
-                               return NULL;
-                       break;
-               }
-               *p++ = c;
-               if (c == '\n')
-                       break;
-       }
-       *p = '\0';
-       return line;
-}
-
-#if ENABLE_FEATURE_EDITING_VI
-#define setvimode(on) do { \
-       if (on) line_input_state->flags |= VI_MODE; \
-       else line_input_state->flags &= ~VI_MODE; \
-} while (0)
-#else
-#define setvimode(on) viflag = 0   /* forcibly keep the option off */
+       if (sp->ap) {
+               if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
+                       checkkwd |= CHKALIAS;
+               }
+               if (sp->string != sp->ap->val) {
+                       free(sp->string);
+               }
+               sp->ap->flag &= ~ALIASINUSE;
+               if (sp->ap->flag & ALIASDEAD) {
+                       unalias(sp->ap->name);
+               }
+       }
 #endif
+       parsenextc = sp->prevstring;
+       parsenleft = sp->prevnleft;
+/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
+       parsefile->strpush = sp->prev;
+       if (sp != &(parsefile->basestrpush))
+               free(sp);
+       INT_ON;
+}
 
 static int
 preadfd(void)
@@ -7024,6 +6901,72 @@ preadbuffer(void)
        return SC2INT(*parsenextc++);
 }
 
+
+#define pgetc_as_macro()   (--parsenleft >= 0? SC2INT(*parsenextc++) : preadbuffer())
+
+#if ENABLE_ASH_OPTIMIZE_FOR_SIZE
+#define pgetc_macro() pgetc()
+static int
+pgetc(void)
+{
+       return pgetc_as_macro();
+}
+#else
+#define pgetc_macro()   pgetc_as_macro()
+static int
+pgetc(void)
+{
+       return pgetc_macro();
+}
+#endif
+
+/*
+ * Same as pgetc(), but ignores PEOA.
+ */
+#if ENABLE_ASH_ALIAS
+static int
+pgetc2(void)
+{
+       int c;
+
+       do {
+               c = pgetc_macro();
+       } while (c == PEOA);
+       return c;
+}
+#else
+static int
+pgetc2(void)
+{
+       return pgetc_macro();
+}
+#endif
+
+/*
+ * Read a line from the script.
+ */
+static char *
+pfgets(char *line, int len)
+{
+       char *p = line;
+       int nleft = len;
+       int c;
+
+       while (--nleft > 0) {
+               c = pgetc2();
+               if (c == PEOF) {
+                       if (p == line)
+                               return NULL;
+                       break;
+               }
+               *p++ = c;
+               if (c == '\n')
+                       break;
+       }
+       *p = '\0';
+       return line;
+}
+
 /*
  * Undo the last call to pgetc.  Only one character may be pushed back.
  * PEOF may be pushed back.
@@ -7068,103 +7011,6 @@ pushstring(char *s, void *ap)
        INT_ON;
 }
 
-static void
-popstring(void)
-{
-       struct strpush *sp = parsefile->strpush;
-
-       INT_OFF;
-#if ENABLE_ASH_ALIAS
-       if (sp->ap) {
-               if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
-                       checkkwd |= CHKALIAS;
-               }
-               if (sp->string != sp->ap->val) {
-                       free(sp->string);
-               }
-               sp->ap->flag &= ~ALIASINUSE;
-               if (sp->ap->flag & ALIASDEAD) {
-                       unalias(sp->ap->name);
-               }
-       }
-#endif
-       parsenextc = sp->prevstring;
-       parsenleft = sp->prevnleft;
-/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
-       parsefile->strpush = sp->prev;
-       if (sp != &(parsefile->basestrpush))
-               free(sp);
-       INT_ON;
-}
-
-
-/*
- * Set the input to take input from a file.  If push is set, push the
- * old input onto the stack first.
- */
-static int
-setinputfile(const char *fname, int flags)
-{
-       int fd;
-       int fd2;
-
-       INT_OFF;
-       fd = open(fname, O_RDONLY);
-       if (fd < 0) {
-               if (flags & INPUT_NOFILE_OK)
-                       goto out;
-               ash_msg_and_raise_error("Can't open %s", fname);
-       }
-       if (fd < 10) {
-               fd2 = copyfd(fd, 10);
-               close(fd);
-               if (fd2 < 0)
-                       ash_msg_and_raise_error("Out of file descriptors");
-               fd = fd2;
-       }
-       setinputfd(fd, flags & INPUT_PUSH_FILE);
- out:
-       INT_ON;
-       return fd;
-}
-
-
-/*
- * Like setinputfile, but takes an open file descriptor.  Call this with
- * interrupts off.
- */
-static void
-setinputfd(int fd, int push)
-{
-       (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
-       if (push) {
-               pushfile();
-               parsefile->buf = 0;
-       }
-       parsefile->fd = fd;
-       if (parsefile->buf == NULL)
-               parsefile->buf = ckmalloc(IBUFSIZ);
-       parselleft = parsenleft = 0;
-       plinno = 1;
-}
-
-
-/*
- * Like setinputfile, but takes input from a string.
- */
-static void
-setinputstring(char *string)
-{
-       INT_OFF;
-       pushfile();
-       parsenextc = string;
-       parsenleft = strlen(string);
-       parsefile->buf = NULL;
-       plinno = 1;
-       INT_ON;
-}
-
-
 /*
  * To handle the "." command, a stack of input files is used.  Pushfile
  * adds a new entry to the stack and popfile restores the previous level.
@@ -7186,7 +7032,6 @@ pushfile(void)
        parsefile = pf;
 }
 
-
 static void
 popfile(void)
 {
@@ -7208,7 +7053,6 @@ popfile(void)
        INT_ON;
 }
 
-
 /*
  * Return to top level.
  */
@@ -7219,7 +7063,6 @@ popallfiles(void)
                popfile();
 }
 
-
 /*
  * Close the file(s) that the shell is reading commands from.  Called
  * after a fork is done.
@@ -7234,6 +7077,71 @@ closescript(void)
        }
 }
 
+/*
+ * Like setinputfile, but takes an open file descriptor.  Call this with
+ * interrupts off.
+ */
+static void
+setinputfd(int fd, int push)
+{
+       fcntl(fd, F_SETFD, FD_CLOEXEC);
+       if (push) {
+               pushfile();
+               parsefile->buf = 0;
+       }
+       parsefile->fd = fd;
+       if (parsefile->buf == NULL)
+               parsefile->buf = ckmalloc(IBUFSIZ);
+       parselleft = parsenleft = 0;
+       plinno = 1;
+}
+
+/*
+ * Set the input to take input from a file.  If push is set, push the
+ * old input onto the stack first.
+ */
+static int
+setinputfile(const char *fname, int flags)
+{
+       int fd;
+       int fd2;
+
+       INT_OFF;
+       fd = open(fname, O_RDONLY);
+       if (fd < 0) {
+               if (flags & INPUT_NOFILE_OK)
+                       goto out;
+               ash_msg_and_raise_error("Can't open %s", fname);
+       }
+       if (fd < 10) {
+               fd2 = copyfd(fd, 10);
+               close(fd);
+               if (fd2 < 0)
+                       ash_msg_and_raise_error("Out of file descriptors");
+               fd = fd2;
+       }
+       setinputfd(fd, flags & INPUT_PUSH_FILE);
+ out:
+       INT_ON;
+       return fd;
+}
+
+/*
+ * Like setinputfile, but takes input from a string.
+ */
+static void
+setinputstring(char *string)
+{
+       INT_OFF;
+       pushfile();
+       parsenextc = string;
+       parsenleft = strlen(string);
+       parsefile->buf = NULL;
+       plinno = 1;
+       INT_ON;
+}
+
+
 /*      jobs.c    */
 
 /* mode flags for set_curjob */
@@ -8903,6 +8811,15 @@ nodeckstrdup(char *s)
 }
 
 
+#if ENABLE_FEATURE_EDITING_VI
+#define setvimode(on) do { \
+       if (on) line_input_state->flags |= VI_MODE; \
+       else line_input_state->flags &= ~VI_MODE; \
+} while (0)
+#else
+#define setvimode(on) viflag = 0   /* forcibly keep the option off */
+#endif
+
 static void
 optschanged(void)
 {
@@ -9495,7 +9412,7 @@ fixredir(union node *n, const char *text, int err)
                n->ndup.vname = NULL;
 
        if (isdigit(text[0]) && text[1] == '\0')
-               n->ndup.dupfd = digit_val(text[0]);
+               n->ndup.dupfd = text[0] - '0';
        else if (LONE_DASH(text))
                n->ndup.dupfd = -1;
        else {
@@ -10160,7 +10077,7 @@ parseredir: {
                }
        }
        if (fd != '\0')
-               np->nfile.fd = digit_val(fd);
+               np->nfile.fd = fd - '0';
        redirnode = np;
        goto parseredir_return;
 }