mkfs_ext2: fix compile error
[oweals/busybox.git] / shell / ash.c
index 37bdc701a5490adfff1dc1821db26d9987dc0b21..481b84138dbed7da9286ca525934f34097d3fa08 100644 (file)
 #include <setjmp.h>
 #include <fnmatch.h>
 #include "math.h"
+#if ENABLE_ASH_RANDOM_SUPPORT
+# include "random.h"
+#else
+# define CLEAR_RANDOM_T(rnd) ((void)0)
+#endif
 
 #if defined SINGLE_APPLET_MAIN
 /* STANDALONE does not make sense, and won't compile */
-#undef CONFIG_FEATURE_SH_STANDALONE
-#undef ENABLE_FEATURE_SH_STANDALONE
-#undef IF_FEATURE_SH_STANDALONE
-#undef IF_NOT_FEATURE_SH_STANDALONE(...)
-#define ENABLE_FEATURE_SH_STANDALONE 0
-#define IF_FEATURE_SH_STANDALONE(...)
-#define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__
+# undef CONFIG_FEATURE_SH_STANDALONE
+# undef ENABLE_FEATURE_SH_STANDALONE
+# undef IF_FEATURE_SH_STANDALONE
+# undef IF_NOT_FEATURE_SH_STANDALONE(...)
+# define ENABLE_FEATURE_SH_STANDALONE 0
+# define IF_FEATURE_SH_STANDALONE(...)
+# define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__
 #endif
 
 #ifndef PIPE_BUF
@@ -197,9 +202,7 @@ struct globals_misc {
 
        /* Rarely referenced stuff */
 #if ENABLE_ASH_RANDOM_SUPPORT
-       /* Random number generators */
-       int32_t random_galois_LFSR; /* Galois LFSR (fast but weak). signed! */
-       uint32_t random_LCG;        /* LCG (fast but weak) */
+       random_t random_gen;
 #endif
        pid_t backgndpid;        /* pid of last background process */
        smallint job_warning;    /* user was warned about stopped jobs (can be 2, 1 or 0). */
@@ -224,8 +227,7 @@ extern struct globals_misc *const ash_ptr_to_globals_misc;
 #define gotsig      (G_misc.gotsig     )
 #define trap        (G_misc.trap       )
 #define trap_ptr    (G_misc.trap_ptr   )
-#define random_galois_LFSR (G_misc.random_galois_LFSR)
-#define random_LCG         (G_misc.random_LCG        )
+#define random_gen  (G_misc.random_gen )
 #define backgndpid  (G_misc.backgndpid )
 #define job_warning (G_misc.job_warning)
 #define INIT_G_misc() do { \
@@ -1155,6 +1157,49 @@ errmsg(int e, const char *em)
 
 /* ============ Memory allocation */
 
+#if 0
+/* I consider these wrappers nearly useless:
+ * ok, they return you to nearest exception handler, but
+ * how much memory do you leak in the process, making
+ * memory starvation worse?
+ */
+static void *
+ckrealloc(void * p, size_t nbytes)
+{
+       p = realloc(p, nbytes);
+       if (!p)
+               ash_msg_and_raise_error(bb_msg_memory_exhausted);
+       return p;
+}
+
+static void *
+ckmalloc(size_t nbytes)
+{
+       return ckrealloc(NULL, nbytes);
+}
+
+static void *
+ckzalloc(size_t nbytes)
+{
+       return memset(ckmalloc(nbytes), 0, nbytes);
+}
+
+static char *
+ckstrdup(const char *s)
+{
+       char *p = strdup(s);
+       if (!p)
+               ash_msg_and_raise_error(bb_msg_memory_exhausted);
+       return p;
+}
+#else
+/* Using bbox equivalents. They exit if out of memory */
+# define ckrealloc xrealloc
+# define ckmalloc  xmalloc
+# define ckzalloc  xzalloc
+# define ckstrdup  xstrdup
+#endif
+
 /*
  * It appears that grabstackstr() will barf with such alignments
  * because stalloc() will return a string allocated in a new stackblock.
@@ -1164,7 +1209,7 @@ enum {
        /* Most machines require the value returned from malloc to be aligned
         * in some way.  The following macro will get this right
         * on many machines.  */
-       SHELL_SIZE = sizeof(union {int i; char *cp; double d; }) - 1,
+       SHELL_SIZE = sizeof(union { int i; char *cp; double d; }) - 1,
        /* Minimum size of a block */
        MINSIZE = SHELL_ALIGN(504),
 };
@@ -1210,43 +1255,10 @@ extern struct globals_memstack *const ash_ptr_to_globals_memstack;
        herefd = -1; \
 } while (0)
 
+
 #define stackblock()     ((void *)g_stacknxt)
 #define stackblocksize() g_stacknleft
 
-
-static void *
-ckrealloc(void * p, size_t nbytes)
-{
-       p = realloc(p, nbytes);
-       if (!p)
-               ash_msg_and_raise_error(bb_msg_memory_exhausted);
-       return p;
-}
-
-static void *
-ckmalloc(size_t nbytes)
-{
-       return ckrealloc(NULL, nbytes);
-}
-
-static void *
-ckzalloc(size_t nbytes)
-{
-       return memset(ckmalloc(nbytes), 0, nbytes);
-}
-
-/*
- * Make a copy of a string in safe storage.
- */
-static char *
-ckstrdup(const char *s)
-{
-       char *p = strdup(s);
-       if (!p)
-               ash_msg_and_raise_error(bb_msg_memory_exhausted);
-       return p;
-}
-
 /*
  * Parse trees for commands are allocated in lifo order, so we use a stack
  * to make this more efficient, and also to avoid all sorts of exception
@@ -3272,9 +3284,6 @@ struct job {
 };
 
 static struct job *makejob(/*union node *,*/ int);
-#if !JOBS
-#define forkshell(job, node, mode) forkshell(job, mode)
-#endif
 static int forkshell(struct job *, union node *, int);
 static int waitforjob(struct job *);
 
@@ -4541,9 +4550,6 @@ clear_traps(void)
 static void closescript(void);
 
 /* Called after fork(), in child */
-#if !JOBS
-# define forkchild(jp, n, mode) forkchild(jp, mode)
-#endif
 static NOINLINE void
 forkchild(struct job *jp, union node *n, int mode)
 {
@@ -4601,9 +4607,9 @@ forkchild(struct job *jp, union node *n, int mode)
                 *
                 * Our solution: ONLY bare $(trap) or `trap` is special.
                 */
-               /* This is needed to prevent EXIT trap firing and such
-                * (trap_ptr will be freed in trapcmd()) */
+               /* Save trap handler strings for trap builtin to print */
                trap_ptr = memcpy(xmalloc(sizeof(trap)), trap, sizeof(trap));
+               /* Fall through into clearing traps */
        }
        clear_traps();
 #if JOBS
@@ -4721,10 +4727,12 @@ forkshell(struct job *jp, union node *n, int mode)
                        freejob(jp);
                ash_msg_and_raise_error("can't fork");
        }
-       if (pid == 0)
+       if (pid == 0) {
+               CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */
                forkchild(jp, n, mode);
-       else
+       } else {
                forkparent(jp, n, mode, pid);
+       }
        return pid;
 }
 
@@ -6371,8 +6379,18 @@ subevalvar(char *p, char *str, int strloc, int subtype,
 
 /*
  * Add the value of a specialized variable to the stack string.
- */
-static ssize_t
+ * name parameter (examples):
+ * ash -c 'echo $1'      name:'1='
+ * ash -c 'echo $qwe'    name:'qwe='
+ * ash -c 'echo $$'      name:'$='
+ * ash -c 'echo ${$}'    name:'$='
+ * ash -c 'echo ${$##q}' name:'$=q'
+ * ash -c 'echo ${#$}'   name:'$='
+ * note: examples with bad shell syntax:
+ * ash -c 'echo ${#$1}'  name:'$=1'
+ * ash -c 'echo ${#1#}'  name:'1=#'
+ */
+static NOINLINE ssize_t
 varvalue(char *name, int varflags, int flags, struct strlist *var_str_list)
 {
        int num;
@@ -6407,7 +6425,7 @@ varvalue(char *name, int varflags, int flags, struct strlist *var_str_list)
                        return -1;
  numvar:
                len = cvtnum(num);
-               break;
+               goto check_1char_name;
        case '-':
                expdest = makestrspace(NOPTS, expdest);
                for (i = NOPTS - 1; i >= 0; i--) {
@@ -6416,6 +6434,12 @@ varvalue(char *name, int varflags, int flags, struct strlist *var_str_list)
                                len++;
                        }
                }
+ check_1char_name:
+#if 0
+               /* handles cases similar to ${#$1} */
+               if (name[2] != '\0')
+                       raise_error_syntax("bad substitution");
+#endif
                break;
        case '@':
                if (sep)
@@ -7761,7 +7785,7 @@ static char *funcstring;        /* block to allocate strings from */
 #define EV_TESTED  02           /* exit status is checked; ignore -e flag */
 #define EV_BACKCMD 04           /* command executing within back quotes */
 
-static const short nodesize[N_NUMBER] = {
+static const uint8_t nodesize[N_NUMBER] = {
        [NCMD     ] = SHELL_ALIGN(sizeof(struct ncmd)),
        [NPIPE    ] = SHELL_ALIGN(sizeof(struct npipe)),
        [NREDIR   ] = SHELL_ALIGN(sizeof(struct nredir)),
@@ -8539,12 +8563,13 @@ setinteractive(int on)
                static smallint did_banner;
 
                if (!did_banner) {
-                       out1fmt(
-                               "\n\n"
-                               "%s built-in shell (ash)\n"
+                       /* note: ash and hush share this string */
+                       out1fmt("\n\n%s %s\n"
                                "Enter 'help' for a list of built-in commands."
                                "\n\n",
-                               bb_banner);
+                               bb_banner,
+                               "built-in shell (ash)"
+                       );
                        did_banner = 1;
                }
        }
@@ -10058,34 +10083,18 @@ setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
 static void FAST_FUNC
 change_random(const char *value)
 {
-       /* Galois LFSR parameter */
-       /* Taps at 32 31 29 1: */
-       enum { MASK = 0x8000000b };
-       /* Another example - taps at 32 31 30 10: */
-       /* MASK = 0x00400007 */
+       uint32_t t;
 
        if (value == NULL) {
                /* "get", generate */
-               uint32_t t;
-
-               /* LCG has period of 2^32 and alternating lowest bit */
-               random_LCG = 1664525 * random_LCG + 1013904223;
-               /* Galois LFSR has period of 2^32-1 = 3 * 5 * 17 * 257 * 65537 */
-               t = (random_galois_LFSR << 1);
-               if (random_galois_LFSR < 0) /* if we just shifted 1 out of msb... */
-                       t ^= MASK;
-               random_galois_LFSR = t;
-               /* Both are weak, combining them gives better randomness
-                * and ~2^64 period. & 0x7fff is probably bash compat
-                * for $RANDOM range. Combining with subtraction is
-                * just for fun. + and ^ would work equally well. */
-               t = (t - random_LCG) & 0x7fff;
+               t = next_random(&random_gen);
                /* set without recursion */
                setvar(vrandom.text, utoa(t), VNOFUNC);
                vrandom.flags &= ~VNOFUNC;
        } else {
                /* set/reset */
-               random_galois_LFSR = random_LCG = strtoul(value, NULL, 10);
+               t = strtoul(value, NULL, 10);
+               INIT_RANDOM_T(&random_gen, (t ? t : 1), t);
        }
 }
 #endif
@@ -11274,6 +11283,8 @@ parsesub: {
  badsub:
                        raise_error_syntax("bad substitution");
                }
+               if (c != '}' && subtype == VSLENGTH)
+                       goto badsub;
 
                STPUTC('=', out);
                flags = 0;
@@ -12267,18 +12278,25 @@ trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
                for (signo = 0; signo < NSIG; signo++) {
                        char *tr = trap_ptr[signo];
                        if (tr) {
-                               out1fmt("trap -- %s %s%s\n",
+                               /* note: bash adds "SIG", but only if invoked
+                                * as "bash". If called as "sh", or if set -o posix,
+                                * then it prints short signal names.
+                                * We are printing short names: */
+                               out1fmt("trap -- %s %s\n",
                                                single_quote(tr),
-                                               (signo == 0 ? "" : "SIG"),
                                                get_signame(signo));
-                               if (trap_ptr != trap)
-                                       free(tr);
+               /* trap_ptr != trap only if we are in special-cased `trap` code.
+                * In this case, we will exit very soon, no need to free(). */
+                               /* if (trap_ptr != trap && tp[0]) */
+                               /*      free(tr); */
                        }
                }
+               /*
                if (trap_ptr != trap) {
                        free(trap_ptr);
                        trap_ptr = trap;
                }
+               */
                return 0;
        }
 
@@ -12901,8 +12919,7 @@ printlim(enum limtype how, const struct rlimit *limit,
 static int FAST_FUNC
 ulimitcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
 {
-       int c;
-       rlim_t val = 0;
+       rlim_t val;
        enum limtype how = SOFT | HARD;
        const struct limits *l;
        int set, all = 0;
@@ -12963,6 +12980,7 @@ ulimitcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
                continue;
 
        set = *argptr ? 1 : 0;
+       val = 0;
        if (set) {
                char *p = *argptr;
 
@@ -12971,15 +12989,13 @@ ulimitcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
                if (strncmp(p, "unlimited\n", 9) == 0)
                        val = RLIM_INFINITY;
                else {
-                       val = (rlim_t) 0;
-
-                       while ((c = *p++) >= '0' && c <= '9') {
-                               val = (val * 10) + (long)(c - '0');
-                               // val is actually 'unsigned long int' and can't get < 0
-                               if (val < (rlim_t) 0)
-                                       break;
-                       }
-                       if (c)
+                       if (sizeof(val) == sizeof(int))
+                               val = bb_strtou(p, NULL, 10);
+                       else if (sizeof(val) == sizeof(long))
+                               val = bb_strtoul(p, NULL, 10);
+                       else
+                               val = bb_strtoull(p, NULL, 10);
+                       if (errno)
                                ash_msg_and_raise_error("bad number");
                        val <<= l->factor_shift;
                }
@@ -13059,7 +13075,6 @@ init(void)
        /* from var.c: */
        {
                char **envp;
-               char ppid[sizeof(int)*3 + 2];
                const char *p;
                struct stat st1, st2;
 
@@ -13070,8 +13085,7 @@ init(void)
                        }
                }
 
-               sprintf(ppid, "%u", (unsigned) getppid());
-               setvar("PPID", ppid, 0);
+               setvar("PPID", utoa(getppid()), 0);
 
                p = lookupvar("PWD");
                if (p)
@@ -13252,11 +13266,6 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
 #endif
        rootpid = getpid();
 
-#if ENABLE_ASH_RANDOM_SUPPORT
-       /* Can use monotonic_ns() for better randomness but for now it is
-        * not used anywhere else in busybox... so avoid bloat */
-       random_galois_LFSR = random_LCG = rootpid + monotonic_us();
-#endif
        init();
        setstackmark(&smark);
        procargs(argv);
@@ -13310,7 +13319,7 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
        }
 
        if (sflag || minusc == NULL) {
-#if ENABLE_FEATURE_EDITING_SAVEHISTORY
+#if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
                if (iflag) {
                        const char *hp = lookupvar("HISTFILE");
                        if (hp)