#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
/* 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). */
#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 { \
/* ============ 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.
/* 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),
};
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
};
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 *);
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)
{
*
* 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
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;
}
/*
* 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;
return -1;
numvar:
len = cvtnum(num);
- break;
+ goto check_1char_name;
case '-':
expdest = makestrspace(NOPTS, expdest);
for (i = NOPTS - 1; i >= 0; i--) {
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)
#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)),
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;
}
}
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
badsub:
raise_error_syntax("bad substitution");
}
+ if (c != '}' && subtype == VSLENGTH)
+ goto badsub;
STPUTC('=', out);
flags = 0;
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;
}
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;
continue;
set = *argptr ? 1 : 0;
+ val = 0;
if (set) {
char *p = *argptr;
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;
}
/* from var.c: */
{
char **envp;
- char ppid[sizeof(int)*3 + 2];
const char *p;
struct stat st1, st2;
}
}
- sprintf(ppid, "%u", (unsigned) getppid());
- setvar("PPID", ppid, 0);
+ setvar("PPID", utoa(getppid()), 0);
p = lookupvar("PWD");
if (p)
#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);
}
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)