tls: code shrink
[oweals/busybox.git] / shell / ash.c
index f74bef6b1cb7a8be222c980b048ad61514670918..04e4006c89d4b0a1b6680eb6e7d1a63090c0927d 100644 (file)
 //config:      you to run the specified command or builtin,
 //config:      even when there is a function with the same name.
 //config:
+//config:config ASH_EMBEDDED_SCRIPTS
+//config:      bool "Embed scripts in the binary"
+//config:      default y
+//config:      depends on ASH || SH_IS_ASH || BASH_IS_ASH
+//config:      help
+//config:      Allow scripts to be compressed and embedded in the busybox
+//config:      binary. The scripts should be placed in the 'embed' directory
+//config:      at build time. Like applets, scripts can be run as
+//config:      'busybox SCRIPT ...' or by linking their name to the binary.
+//config:
+//config:      This also allows applets to be implemented as scripts: place
+//config:      the script in 'applets_sh' and a stub C file containing
+//config:      configuration in the appropriate subsystem directory.
+//config:
 //config:endif # ash options
 
 //applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP))
 #include <sys/times.h>
 #include <sys/utsname.h> /* for setting $HOSTNAME */
 #include "busybox.h" /* for applet_names */
+#if ENABLE_ASH_EMBEDDED_SCRIPTS
+# include "embedded_scripts.h"
+#else
+# define NUM_SCRIPTS 0
+#endif
 
 /* So far, all bash compat is controlled by one config option */
 /* Separate defines document which part of code implements what */
@@ -2405,13 +2424,12 @@ setvar(const char *name, const char *val, int flags)
        }
 
        INT_OFF;
-       nameeq = ckmalloc(namelen + vallen + 2);
+       nameeq = ckzalloc(namelen + vallen + 2);
        p = mempcpy(nameeq, name, namelen);
        if (val) {
                *p++ = '=';
-               p = mempcpy(p, val, vallen);
+               memcpy(p, val, vallen);
        }
-       *p = '\0';
        vp = setvareq(nameeq, flags | VNOSAVE);
        INT_ON;
 
@@ -6236,9 +6254,7 @@ memtodest(const char *p, size_t len, int syntax, int quotes)
                        if (quotes & QUOTES_ESC) {
                                int n = SIT(c, syntax);
                                if (n == CCTL
-                                || (((quotes & EXP_FULL) || syntax != BASESYNTAX)
-                                    && n == CBACK
-                                   )
+                                || (syntax != BASESYNTAX && n == CBACK)
                                ) {
                                        USTPUTC(CTLESC, q);
                                }
@@ -7639,7 +7655,7 @@ expmeta(exp_t *exp, char *name, unsigned name_len, unsigned expdir_len)
                                }
                        }
                } else {
-                       if (*p == '\\')
+                       if (*p == '\\' && p[1])
                                esc++;
                        if (p[esc] == '/') {
                                if (metaflag)
@@ -7653,7 +7669,7 @@ expmeta(exp_t *exp, char *name, unsigned name_len, unsigned expdir_len)
                        return;
                p = name;
                do {
-                       if (*p == '\\')
+                       if (*p == '\\' && p[1])
                                p++;
                        *enddir++ = *p;
                } while (*p++);
@@ -7665,7 +7681,7 @@ expmeta(exp_t *exp, char *name, unsigned name_len, unsigned expdir_len)
        if (name < start) {
                p = name;
                do {
-                       if (*p == '\\')
+                       if (*p == '\\' && p[1])
                                p++;
                        *enddir++ = *p++;
                } while (p < start);
@@ -8026,6 +8042,7 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, c
 #else
        execve(cmd, argv, envp);
 #endif
+
        if (cmd != bb_busybox_exec_path && errno == ENOEXEC) {
                /* Run "cmd" as a shell script:
                 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
@@ -8098,15 +8115,15 @@ static void shellexec(char *prog, char **argv, const char *path, int idx)
 
        /* Map to POSIX errors */
        switch (e) {
-       case EACCES:
+       default:
                exerrno = 126;
                break;
+       case ELOOP:
+       case ENAMETOOLONG:
        case ENOENT:
+       case ENOTDIR:
                exerrno = 127;
                break;
-       default:
-               exerrno = 2;
-               break;
        }
        exitstatus = exerrno;
        TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
@@ -9942,6 +9959,7 @@ find_builtin(const char *name)
 /*
  * Execute a simple command.
  */
+static void unwindfiles(struct parsefile *stop);
 static int
 isassignment(const char *p)
 {
@@ -9964,6 +9982,7 @@ evalcommand(union node *cmd, int flags)
                "\0\0", bltincmd /* why three NULs? */
        };
        struct localvar_list *localvar_stop;
+       struct parsefile *file_stop;
        struct redirtab *redir_stop;
        struct stackmark smark;
        union node *argp;
@@ -9989,6 +10008,7 @@ evalcommand(union node *cmd, int flags)
        TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
        setstackmark(&smark);
        localvar_stop = pushlocalvars();
+       file_stop = g_parsefile;
        back_exitstatus = 0;
 
        cmdentry.cmdtype = CMDBUILTIN;
@@ -10260,6 +10280,7 @@ evalcommand(union node *cmd, int flags)
        if (cmd->ncmd.redirect)
                popredir(/*drop:*/ cmd_is_exec);
        unwindredir(redir_stop);
+       unwindfiles(file_stop);
        unwindlocalvars(localvar_stop);
        if (lastarg) {
                /* dsl: I think this is intended to be used to support
@@ -10782,14 +10803,20 @@ popfile(void)
        INT_ON;
 }
 
+static void
+unwindfiles(struct parsefile *stop)
+{
+       while (g_parsefile != stop)
+               popfile();
+}
+
 /*
  * Return to top level.
  */
 static void
 popallfiles(void)
 {
-       while (g_parsefile != &basepf)
-               popfile();
+       unwindfiles(&basepf);
 }
 
 /*
@@ -12431,7 +12458,7 @@ parsesub: {
                                STPUTC(c, out);
                                c = pgetc_eatbnl();
                        } while (isdigit(c));
-               } else {
+               } else if (c != '}') {
                        /* $[{[#]]<specialchar>[}] */
                        int cc = c;
 
@@ -12457,7 +12484,8 @@ parsesub: {
                        }
 
                        USTPUTC(cc, out);
-               }
+               } else
+                       goto badsub;
 
                if (c != '}' && subtype == VSLENGTH) {
                        /* ${#VAR didn't end with } */
@@ -12933,6 +12961,7 @@ parseheredoc(void)
        heredoclist = NULL;
 
        while (here) {
+               tokpushback = 0;
                setprompt_if(needprompt, 2);
                readtoken1(pgetc(), here->here->type == NHERE ? SQSYNTAX : DQSYNTAX,
                                here->eofmark, here->striptabs);
@@ -14013,12 +14042,16 @@ procargs(char **argv)
 
        xargv = argv;
        login_sh = xargv[0] && xargv[0][0] == '-';
+#if NUM_SCRIPTS > 0
+       if (minusc)
+               goto setarg0;
+#endif
        arg0 = xargv[0];
        /* if (xargv[0]) - mmm, this is always true! */
                xargv++;
+       argptr = xargv;
        for (i = 0; i < NOPTS; i++)
                optlist[i] = 2;
-       argptr = xargv;
        if (options(/*cmdline:*/ 1, &login_sh)) {
                /* it already printed err message */
                raise_exception(EXERROR);
@@ -14120,7 +14153,12 @@ extern int etext();
  * is used to figure out how far we had gotten.
  */
 int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+#if NUM_SCRIPTS > 0
+int ash_main(int argc, char **argv)
+#else
 int ash_main(int argc UNUSED_PARAM, char **argv)
+#endif
+/* note: 'argc' is used only if embedded scripts are enabled */
 {
        volatile smallint state;
        struct jmploc jmploc;
@@ -14174,6 +14212,12 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
 
        init();
        setstackmark(&smark);
+
+#if NUM_SCRIPTS > 0
+       if (argc < 0)
+               /* Non-NULL minusc tells procargs that an embedded script is being run */
+               minusc = get_script_content(-argc - 1);
+#endif
        login_sh = procargs(argv);
 #if DEBUG
        TRACE(("Shell args: "));