hush: fix handling of unmatched ${name (without closing '}') -
[oweals/busybox.git] / shell / ash.c
index 1de4cb50b554e13d512be6faad9136e3df8e271e..ed46e1c0c2fc72655b2412e1095f3932e2ebb145 100644 (file)
@@ -60,6 +60,7 @@
 #if JOBS || ENABLE_ASH_READ_NCHARS
 #include <termios.h>
 #endif
+extern char **environ;
 
 #if defined(__uClinux__)
 #error "Do not even bother, ash will not run on uClinux"
@@ -155,8 +156,9 @@ static char gotsig[NSIG - 1];
 static char *arg0; /* value of $0 */
 
 
-/* ============ Interrupts / exceptions
- *
+/* ============ Interrupts / exceptions */
+
+/*
  * We enclose jmp_buf in a structure so that we can declare pointers to
  * jump locations.  The global variable handler contains the location to
  * jump to when an exception occurs, and the global variable exception
@@ -182,7 +184,7 @@ static volatile sig_atomic_t intpending;
 /* do we generate EXSIG events */
 static int exsig;
 /* last pending signal */
-static volatile sig_atomic_t pendingsigs;
+static volatile sig_atomic_t pendingsig;
 
 /*
  * Sigmode records the current value of the signal handlers for the various
@@ -238,8 +240,15 @@ static void
 raise_interrupt(void)
 {
        int i;
+       sigset_t mask;
 
        intpending = 0;
+       /* Signal is not automatically re-enabled after it is raised,
+        * do it ourself */
+       sigemptyset(&mask);
+       sigprocmask(SIG_SETMASK, &mask, 0);
+       /* pendingsig = 0; - now done in onsig() */
+
        i = EXSIG;
        if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
                if (!(rootshell && iflag)) {
@@ -299,7 +308,7 @@ force_int_on(void)
        do { \
                exsig++; \
                xbarrier(); \
-               if (pendingsigs) \
+               if (pendingsig) \
                        raise_exception(EXSIG); \
        } while (0)
 /* EXSIG is turned off by evalbltin(). */
@@ -323,11 +332,13 @@ static void
 onsig(int signo)
 {
        gotsig[signo - 1] = 1;
-       pendingsigs = signo;
+       pendingsig = signo;
 
        if (exsig || (signo == SIGINT && !trap[SIGINT])) {
-               if (!suppressint)
+               if (!suppressint) {
+                       pendingsig = 0;
                        raise_interrupt();
+               }
                intpending = 1;
        }
 }
@@ -984,9 +995,10 @@ ash_vmsg(const char *msg, va_list ap)
 {
        fprintf(stderr, "%s: ", arg0);
        if (commandname) {
-               const char *fmt = (!iflag || parsefile->fd) ?
-                                       "%s: %d: " : "%s: ";
-               fprintf(stderr, fmt, commandname, startlinno);
+               if (strcmp(arg0, commandname))
+                       fprintf(stderr, "%s: ", commandname);
+               if (!iflag || parsefile->fd)
+                       fprintf(stderr, "line %d: ", startlinno);
        }
        vfprintf(stderr, msg, ap);
        outcslow('\n', stderr);
@@ -1214,6 +1226,9 @@ popstackmark(struct stackmark *mark)
 {
        struct stack_block *sp;
 
+       if (!mark->stackp)
+               return;
+
        INT_OFF;
        markp = mark->marknext;
        while (stackp != mark->stackp) {
@@ -1517,13 +1532,13 @@ nextopt(const char *optstring)
        c = *p++;
        for (q = optstring; *q != c; ) {
                if (*q == '\0')
-                       ash_msg_and_raise_error("Illegal option -%c", c);
+                       ash_msg_and_raise_error("illegal option -%c", c);
                if (*++q == ':')
                        q++;
        }
        if (*++q == ':') {
                if (*p == '\0' && (p = *argptr++) == NULL)
-                       ash_msg_and_raise_error("No arg for -%c option", c);
+                       ash_msg_and_raise_error("no arg for -%c option", c);
                optionarg = p;
                p = NULL;
        }
@@ -1733,7 +1748,6 @@ 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. */
 
 #define VTABSIZE 39
@@ -2155,7 +2169,7 @@ putprompt(const char *s)
 {
        if (ENABLE_ASH_EXPAND_PRMT) {
                free((char*)cmdedit_prompt);
-               cmdedit_prompt = xstrdup(s);
+               cmdedit_prompt = ckstrdup(s);
                return;
        }
        cmdedit_prompt = s;
@@ -2279,7 +2293,8 @@ updatepwd(const char *dir)
                                                break;
                                }
                                break;
-                       } else if (p[1] == '\0')
+                       }
+                       if (p[1] == '\0')
                                break;
                        /* fall through */
                default:
@@ -3425,7 +3440,7 @@ static void
 xtcsetpgrp(int fd, pid_t pgrp)
 {
        if (tcsetpgrp(fd, pgrp))
-               ash_msg_and_raise_error("Cannot set tty process group (%m)");
+               ash_msg_and_raise_error("cannot set tty process group (%m)");
 }
 
 /*
@@ -3486,7 +3501,9 @@ setjobctl(int on)
                /* turning job control off */
                fd = ttyfd;
                pgrp = initialpgrp;
-               xtcsetpgrp(fd, pgrp);
+               /* was xtcsetpgrp, but this can make exiting ash
+                * with pty already deleted loop forever */
+               tcsetpgrp(fd, pgrp);
                setpgid(0, pgrp);
                setsignal(SIGTSTP);
                setsignal(SIGTTOU);
@@ -3502,91 +3519,22 @@ setjobctl(int on)
 static int
 killcmd(int argc, char **argv)
 {
-       int signo = -1;
-       int list = 0;
-       int i;
-       pid_t pid;
-       struct job *jp;
-
-       if (argc <= 1) {
- usage:
-               ash_msg_and_raise_error(
-"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
-"kill -l [exitstatus]"
-               );
-       }
-
-       if (**++argv == '-') {
-               signo = get_signum(*argv + 1);
-               if (signo < 0) {
-                       int c;
-
-                       while ((c = nextopt("ls:")) != '\0') {
-                               switch (c) {
-                               default:
-#if DEBUG
-                                       abort();
-#endif
-                               case 'l':
-                                       list = 1;
-                                       break;
-                               case 's':
-                                       signo = get_signum(optionarg);
-                                       if (signo < 0) {
-                                               ash_msg_and_raise_error(
-                                                       "invalid signal number or name: %s",
-                                                       optionarg
-                                               );
-                                       }
-                                       break;
-                               }
-                       }
-                       argv = argptr;
-               } else
-                       argv++;
-       }
-
-       if (!list && signo < 0)
-               signo = SIGTERM;
-
-       if ((signo < 0 || !*argv) ^ list) {
-               goto usage;
-       }
-
-       if (list) {
-               const char *name;
-
-               if (!*argv) {
-                       for (i = 1; i < NSIG; i++) {
-                               name = get_signame(i);
-                               if (isdigit(*name))
-                                       out1fmt(snlfmt, name);
+       if (argv[1] && strcmp(argv[1], "-l") != 0) {
+               int i = 1;
+               do {
+                       if (argv[i][0] == '%') {
+                               struct job *jp = getjob(argv[i], 0);
+                               unsigned pid = jp->ps[0].pid;
+                               /* Enough space for ' -NNN<nul>' */
+                               argv[i] = alloca(sizeof(int)*3 + 3);
+                               /* kill_main has matching code to expect
+                                * leading space. Needed to not confuse
+                                * negative pids with "kill -SIGNAL_NO" syntax */
+                               sprintf(argv[i], " -%u", pid);
                        }
-                       return 0;
-               }
-               name = get_signame(signo);
-               if (!isdigit(*name))
-                       ash_msg_and_raise_error("invalid signal number or exit status: %s", *argptr);
-               out1fmt(snlfmt, name);
-               return 0;
+               } while (argv[++i]);
        }
-
-       i = 0;
-       do {
-               if (**argv == '%') {
-                       jp = getjob(*argv, 0);
-                       pid = -jp->ps[0].pid;
-               } else {
-                       pid = **argv == '-' ?
-                               -number(*argv + 1) : number(*argv);
-               }
-               if (kill(pid, signo) != 0) {
-                       ash_msg("(%d) - %m", pid);
-                       i = 1;
-               }
-       } while (*++argv);
-
-       return i;
+       return kill_main(argc, argv);
 }
 
 static void
@@ -3625,7 +3573,8 @@ restartjob(struct job *jp, int mode)
                if (WIFSTOPPED(ps->status)) {
                        ps->status = -1;
                }
-       } while (ps++, --i);
+               ps++;
+       } while (--i);
  out:
        status = (mode == FORK_FG) ? waitforjob(jp) : 0;
        INT_ON;
@@ -4471,7 +4420,7 @@ forkchild(struct job *jp, union node *n, int mode)
                if (jp->nprocs == 0) {
                        close(0);
                        if (open(bb_dev_null, O_RDONLY) != 0)
-                               ash_msg_and_raise_error("Can't open %s", bb_dev_null);
+                               ash_msg_and_raise_error("can't open %s", bb_dev_null);
                }
        }
        if (!oldlvl && iflag) {
@@ -4532,7 +4481,7 @@ forkshell(struct job *jp, union node *n, int mode)
                TRACE(("Fork failed, errno=%d", errno));
                if (jp)
                        freejob(jp);
-               ash_msg_and_raise_error("Cannot fork");
+               ash_msg_and_raise_error("cannot fork");
        }
        if (pid == 0)
                forkchild(jp, n, mode);
@@ -4698,7 +4647,7 @@ openhere(union node *redir)
        size_t len = 0;
 
        if (pipe(pip) < 0)
-               ash_msg_and_raise_error("Pipe call failed");
+               ash_msg_and_raise_error("pipe call failed");
        if (redir->type == NHERE) {
                len = strlen(redir->nhere.doc->narg.text);
                if (len <= PIPESIZE) {
@@ -4784,9 +4733,9 @@ openredirect(union node *redir)
 
        return f;
  ecreate:
-       ash_msg_and_raise_error("cannot create %s: %s", fname, errmsg(errno, "Directory nonexistent"));
+       ash_msg_and_raise_error("cannot create %s: %s", fname, errmsg(errno, "nonexistent directory"));
  eopen:
-       ash_msg_and_raise_error("cannot open %s: %s", fname, errmsg(errno, "No such file"));
+       ash_msg_and_raise_error("cannot open %s: %s", fname, errmsg(errno, "no such file"));
 }
 
 /*
@@ -5053,8 +5002,9 @@ esclen(const char *start, const char *p)
 static char *
 _rmescapes(char *str, int flag)
 {
+       static const char qchars[] = { CTLESC, CTLQUOTEMARK, '\0' };
+
        char *p, *q, *r;
-       static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
        unsigned inquotes;
        int notescaped;
        int globbing;
@@ -5311,7 +5261,7 @@ evalbackcmd(union node *n, struct backcmd *result)
                struct job *jp;
 
                if (pipe(pip) < 0)
-                       ash_msg_and_raise_error("Pipe call failed");
+                       ash_msg_and_raise_error("pipe call failed");
                jp = makejob(n, 1);
                if (forkshell(jp, n, FORK_NOJOB) == 0) {
                        FORCE_INT_ON;
@@ -6454,40 +6404,6 @@ casematch(union node *pattern, char *val)
 
 /* ============ find_command */
 
-static int is_safe_applet(char *name)
-{
-       /* It isn't a bug to have non-existent applet here... */
-       /* ...just a waste of space... */
-       static const char safe_applets[][8] = {
-               "["
-               USE_AWK    (, "awk"    )
-               USE_CAT    (, "cat"    )
-               USE_CHMOD  (, "chmod"  )
-               USE_CHOWN  (, "chown"  )
-               USE_CP     (, "cp"     )
-               USE_CUT    (, "cut"    )
-               USE_DD     (, "dd"     )
-               USE_ECHO   (, "echo"   )
-               USE_FIND   (, "find"   )
-               USE_HEXDUMP(, "hexdump")
-               USE_LN     (, "ln"     )
-               USE_LS     (, "ls"     )
-               USE_MKDIR  (, "mkdir"  )
-               USE_RM     (, "rm"     )
-               USE_SORT   (, "sort"   )
-               USE_TEST   (, "test"   )
-               USE_TOUCH  (, "touch"  )
-               USE_XARGS  (, "xargs"  )
-       };
-       int n = sizeof(safe_applets) / sizeof(safe_applets[0]);
-       int i;
-       for (i = 0; i < n; i++)
-               if (strcmp(safe_applets[i], name) == 0)
-                       return 1;
-
-       return 0;
-}
-
 struct builtincmd {
        const char *name;
        int (*builtin)(int, char **);
@@ -6550,27 +6466,22 @@ static void
 tryexec(char *cmd, char **argv, char **envp)
 {
        int repeated = 0;
-       struct BB_applet *a;
-       int argc = 0;
-       char **c;
 
-       if (strchr(cmd, '/') == NULL
-        && (a = find_applet_by_name(cmd)) != NULL
-        && is_safe_applet(cmd)
-       ) {
-               c = argv;
-               while (*c != NULL) {
-                       c++; argc++;
+#if ENABLE_FEATURE_SH_STANDALONE
+       if (strchr(cmd, '/') == NULL) {
+               const struct bb_applet *a;
+
+               a = find_applet_by_name(cmd);
+               if (a) {
+                       if (a->noexec) {
+                               current_applet = a;
+                               run_current_applet_and_exit(argv);
+                       }
+                       /* 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 */
                }
-               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
 
@@ -6592,7 +6503,7 @@ tryexec(char *cmd, char **argv, char **envp)
                        ;
                ap = new = ckmalloc((ap - argv + 2) * sizeof(char *));
                ap[1] = cmd;
-               *ap = cmd = (char *)DEFAULT_SHELL;
+               ap[0] = cmd = (char *)DEFAULT_SHELL;
                ap += 2;
                argv++;
                while ((*ap++ = *argv++))
@@ -6618,8 +6529,8 @@ shellexec(char **argv, const char *path, int idx)
 
        clearredir(1);
        envp = environment();
-       if (strchr(argv[0], '/') || is_safe_applet(argv[0])
-#if ENABLE_FEATURE_SH_STANDALONE_SHELL
+       if (strchr(argv[0], '/')
+#if ENABLE_FEATURE_SH_STANDALONE
         || find_applet_by_name(argv[0])
 #endif
        ) {
@@ -6951,6 +6862,11 @@ tokname(int tok)
 {
        static char buf[16];
 
+//try this:
+//if (tok < TSEMI) return tokname_array[tok] + 1;
+//sprintf(buf, "\"%s\"", tokname_array[tok] + 1);
+//return buf;
+
        if (tok >= TSEMI)
                buf[0] = '"';
        sprintf(buf + (tok >= TSEMI), "%s%c",
@@ -6962,28 +6878,22 @@ tokname(int tok)
 static int
 pstrcmp(const void *a, const void *b)
 {
-       return strcmp((const char *) a, (*(const char *const *) b) + 1);
+       return strcmp((char*) a, (*(char**) b) + 1);
 }
 
 static const char *const *
 findkwd(const char *s)
 {
        return bsearch(s, tokname_array + KWDOFFSET,
-                       (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET,
-                       sizeof(const char *), pstrcmp);
+                       (sizeof(tokname_array) / sizeof(char *)) - KWDOFFSET,
+                       sizeof(char *), pstrcmp);
 }
 
 /*
  * Locate and print what a word is...
  */
-#if ENABLE_ASH_CMDCMD
 static int
 describe_command(char *command, int describe_command_verbose)
-#else
-#define describe_command_verbose 1
-static int
-describe_command(char *command)
-#endif
 {
        struct cmdentry entry;
        struct tblentry *cmdp;
@@ -7006,13 +6916,12 @@ describe_command(char *command)
        /* Then look at the aliases */
        ap = lookupalias(command, 0);
        if (ap != NULL) {
-               if (describe_command_verbose) {
-                       out1fmt(" is an alias for %s", ap->val);
-               } else {
+               if (!describe_command_verbose) {
                        out1str("alias ");
                        printalias(ap);
                        return 0;
                }
+               out1fmt(" is an alias for %s", ap->val);
                goto out;
        }
 #endif
@@ -7081,15 +6990,17 @@ describe_command(char *command)
 static int
 typecmd(int argc, char **argv)
 {
-       int i;
+       int i = 1;
        int err = 0;
+       int verbose = 1;
 
-       for (i = 1; i < argc; i++) {
-#if ENABLE_ASH_CMDCMD
-               err |= describe_command(argv[i], 1);
-#else
-               err |= describe_command(argv[i]);
-#endif
+       /* type -p ... ? (we don't bother checking for 'p') */
+       if (argv[1][0] == '-') {
+               i++;
+               verbose = 0;
+       }
+       while (i < argc) {
+               err |= describe_command(argv[i++], verbose);
        }
        return err;
 }
@@ -7434,7 +7345,7 @@ dotrap(void)
        int skip = 0;
 
        savestatus = exitstatus;
-       pendingsigs = 0;
+       pendingsig = 0;
        xbarrier();
 
        for (i = 0, q = gotsig; i < NSIG - 1; i++, q++) {
@@ -7573,7 +7484,7 @@ evaltree(union node *n, int flags)
  out:
        if ((checkexit & exitstatus))
                evalskip |= SKIPEVAL;
-       else if (pendingsigs && dotrap())
+       else if (pendingsig && dotrap())
                goto exexit;
 
        if (flags & EV_EXIT) {
@@ -7787,7 +7698,7 @@ evalpipe(union node *n, int flags)
                if (lp->next) {
                        if (pipe(pip) < 0) {
                                close(prevfd);
-                               ash_msg_and_raise_error("Pipe call failed");
+                               ash_msg_and_raise_error("pipe call failed");
                        }
                }
                if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
@@ -8045,14 +7956,46 @@ localcmd(int argc, char **argv)
        return 0;
 }
 
+static int
+falsecmd(int argc, char **argv)
+{
+       return 1;
+}
+
+static int
+truecmd(int argc, char **argv)
+{
+       return 0;
+}
+
+static int
+execcmd(int argc, char **argv)
+{
+       if (argc > 1) {
+               iflag = 0;              /* exit on error */
+               mflag = 0;
+               optschanged();
+               shellexec(argv + 1, pathval(), 0);
+       }
+       return 0;
+}
+
+/*
+ * The return command.
+ */
+static int
+returncmd(int argc, char **argv)
+{
+       /*
+        * If called outside a function, do what ksh does;
+        * skip the rest of the file.
+        */
+       evalskip = funcnest ? SKIPFUNC : SKIPFILE;
+       return argv[1] ? number(argv[1]) : exitstatus;
+}
+
 /* 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
@@ -8061,39 +8004,25 @@ static int echocmd(int, char **);
 #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 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"
@@ -8422,7 +8351,7 @@ evalcommand(union node *cmd, int flags)
                        if (i == EXINT)
                                j = SIGINT;
                        if (i == EXSIG)
-                               j = pendingsigs;
+                               j = pendingsig;
                        if (j)
                                exit_status = j + 128;
                        exitstatus = exit_status;
@@ -8505,9 +8434,10 @@ prehash(union node *n)
 }
 
 
-/*
- * Builtin commands.  Builtin commands whose functions are closely
- * tied to evaluation are implemented here.
+/* ============ Builtin commands
+ *
+ * Builtin commands whose functions are closely tied to evaluation
+ * are implemented here.
  */
 
 /*
@@ -8520,7 +8450,6 @@ prehash(union node *n)
  * be an error to break out of more loops than exist, but it isn't
  * in the standard shell so we don't make it one here.
  */
-
 static int
 breakcmd(int argc, char **argv)
 {
@@ -8531,50 +8460,12 @@ breakcmd(int argc, char **argv)
        if (n > loopnest)
                n = loopnest;
        if (n > 0) {
-               evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
+               evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
                skipcount = n;
        }
        return 0;
 }
 
-/*
- * The return command.
- */
-static int
-returncmd(int argc, char **argv)
-{
-       /*
-        * If called outside a function, do what ksh does;
-        * skip the rest of the file.
-        */
-       evalskip = funcnest ? SKIPFUNC : SKIPFILE;
-       return argv[1] ? number(argv[1]) : exitstatus;
-}
-
-static int
-falsecmd(int argc, char **argv)
-{
-       return 1;
-}
-
-static int
-truecmd(int argc, char **argv)
-{
-       return 0;
-}
-
-static int
-execcmd(int argc, char **argv)
-{
-       if (argc > 1) {
-               iflag = 0;              /* exit on error */
-               mflag = 0;
-               optschanged();
-               shellexec(argv + 1, pathval(), 0);
-       }
-       return 0;
-}
-
 
 /* ============ input.c
  *
@@ -8970,13 +8861,13 @@ setinputfile(const char *fname, int flags)
        if (fd < 0) {
                if (flags & INPUT_NOFILE_OK)
                        goto out;
-               ash_msg_and_raise_error("Can't open %s", fname);
+               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");
+                       ash_msg_and_raise_error("out of file descriptors");
                fd = fd2;
        }
        setinputfd(fd, flags & INPUT_PUSH_FILE);
@@ -9114,7 +9005,7 @@ minus_o(char *name, int val)
                                return;
                        }
                }
-               ash_msg_and_raise_error("Illegal option -o %s", name);
+               ash_msg_and_raise_error("illegal option -o %s", name);
        }
        out1str("Current option settings\n");
        for (i = 0; i < NOPTS; i++)
@@ -9132,7 +9023,7 @@ setoption(int flag, int val)
                        return;
                }
        }
-       ash_msg_and_raise_error("Illegal option -%c", flag);
+       ash_msg_and_raise_error("illegal option -%c", flag);
        /* NOTREACHED */
 }
 static void
@@ -9385,7 +9276,7 @@ getoptscmd(int argc, char **argv)
        char **optbase;
 
        if (argc < 3)
-               ash_msg_and_raise_error("Usage: getopts optstring var [arg]");
+               ash_msg_and_raise_error("usage: getopts optstring var [arg]");
        if (argc == 3) {
                optbase = shellparam.p;
                if (shellparam.optind > shellparam.nparam + 1) {
@@ -9422,7 +9313,7 @@ static void raise_error_syntax(const char *) ATTRIBUTE_NORETURN;
 static void
 raise_error_syntax(const char *msg)
 {
-       ash_msg_and_raise_error("Syntax error: %s", msg);
+       ash_msg_and_raise_error("syntax error: %s", msg);
        /* NOTREACHED */
 }
 
@@ -10876,8 +10767,7 @@ parseheredoc(void)
 
 
 /*
- * called by editline -- any expansions to the prompt
- *    should be added here.
+ * called by editline -- any expansions to the prompt should be added here.
  */
 #if ENABLE_ASH_EXPAND_PRMT
 static const char *
@@ -10900,7 +10790,6 @@ expandstr(const char *ps)
 }
 #endif
 
-
 /*
  * Execute a command or commands contained in a string.
  */
@@ -11054,7 +10943,7 @@ dotcmd(int argc, char **argv)
        int status = 0;
 
        for (sp = cmdenviron; sp; sp = sp->next)
-               setvareq(xstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
+               setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
 
        if (argc >= 2) {        /* That's what SVR2 does */
                char *fullname;
@@ -11156,19 +11045,7 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
                return;
        }
 
-#if ENABLE_FEATURE_SH_STANDALONE_SHELL
-       if (find_applet_by_name(name)) {
-               entry->cmdtype = CMDNORMAL;
-               entry->u.index = -1;
-               return;
-       }
-#endif
-
-       if (is_safe_applet(name)) {
-               entry->cmdtype = CMDNORMAL;
-               entry->u.index = -1;
-               return;
-       }
+/* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
 
        updatetbl = (path == pathval());
        if (!updatetbl) {
@@ -11207,10 +11084,24 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
 
        /* If %builtin not in path, check for builtin next */
        bcmd = find_builtin(name);
-       if (bcmd && (IS_BUILTIN_REGULAR(bcmd) || (
-               act & DO_ALTPATH ? !(act & DO_ALTBLTIN) : builtinloc <= 0
-       )))
-               goto builtin_success;
+       if (bcmd) {
+               if (IS_BUILTIN_REGULAR(bcmd))
+                       goto builtin_success;
+               if (act & DO_ALTPATH) {
+                       if (!(act & DO_ALTBLTIN))
+                               goto builtin_success;
+               } else if (builtinloc <= 0) {
+                       goto builtin_success;
+               }
+       }
+
+#if ENABLE_FEATURE_SH_STANDALONE
+       if (find_applet_by_name(name)) {
+               entry->cmdtype = CMDNORMAL;
+               entry->u.index = -1;
+               return;
+       }
+#endif
 
        /* We have to search path. */
        prev = -1;              /* where to start */
@@ -11375,13 +11266,13 @@ helpcmd(int argc, char **argv)
        out1fmt("\nBuilt-in commands:\n-------------------\n");
        for (col = 0, i = 0; i < NUMBUILTINS; i++) {
                col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
-                                         builtincmd[i].name + 1);
+                                       builtintab[i].name + 1);
                if (col > 60) {
                        out1fmt("\n");
                        col = 0;
                }
        }
-#if ENABLE_FEATURE_SH_STANDALONE_SHELL
+#if ENABLE_FEATURE_SH_STANDALONE
        for (i = 0; i < NUM_APPLETS; i++) {
                col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name);
                if (col > 60) {
@@ -11816,7 +11707,7 @@ umaskcmd(int argc, char **argv)
                } else {
                        mask = ~mask & 0777;
                        if (!bb_parse_mode(ap, &mask)) {
-                               ash_msg_and_raise_error("Illegal mode: %s", ap);
+                               ash_msg_and_raise_error("illegal mode: %s", ap);
                        }
                        umask(~mask & 0777);
                }