From ef02f82bcf667ede9790a5de6aa78459529f29e4 Mon Sep 17 00:00:00 2001 From: Eric Andersen Date: Thu, 11 Mar 2004 13:34:24 +0000 Subject: Paul Mundt, lethal at linux-sh dot org writes: Here's a follow-up replacement to the patch I sent earlier, this adjusts some of the semantics of the dynamic variable setting. Namely, dynamic vars can hook a set handler (which RANDOM uses to adjust the seed). They'll only lose their dynamic status if they're unset. I've used the same approach that bash does to come up with the random number, mostly just for consistency. For example: $ echo $RANDOM 13759 $ echo $RANDOM 20057 $ echo $RANDOM 1502 $ export RANDOM=42 $ echo $RANDOM 24179 $ echo $RANDOM 2046 $ unset RANDOM $ echo $RANDOM $ export RANDOM=42 $ echo $RANDOM 42 $ --- shell/ash.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 54 insertions(+), 14 deletions(-) (limited to 'shell/ash.c') diff --git a/shell/ash.c b/shell/ash.c index eb8706f36..8c2493ece 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -37,6 +37,8 @@ * used in busybox and size optimizations, * support locale, rewrited arith (see notes to this) * + * Modified by Paul Mundt (c) 2004 to support + * dynamic variables. */ @@ -88,7 +90,7 @@ #include #include #include - +#include #include @@ -1465,6 +1467,7 @@ static void reset(void); #define VNOFUNC 0x40 /* don't call the callback function */ #define VNOSET 0x80 /* do not set variable - just readonly test */ #define VNOSAVE 0x100 /* when text is on the heap before setvareq */ +#define VDYNAMIC 0x200 /* dynamic variable */ struct var { @@ -1474,6 +1477,9 @@ struct var { void (*func)(const char *); /* function to be called when */ /* the variable gets set/unset */ + char *(*lookup_func)(const char *); + /* function to be called when */ + /* the variable is read (if dynamic) */ }; struct localvar { @@ -1500,6 +1506,9 @@ static void change_lc_all(const char *value); static void change_lc_ctype(const char *value); #endif +static char *get_random(const char *); +static void change_random(const char *); + #define VTABSIZE 39 static const char defpathvar[] = "PATH=/usr/local/bin:/usr/bin:/sbin:/bin"; @@ -1513,30 +1522,32 @@ static const char defifs[] = " \t\n"; static struct var varinit[] = { #ifdef IFS_BROKEN - { 0, VSTRFIXED|VTEXTFIXED, defifsvar, 0 }, + { 0, VSTRFIXED|VTEXTFIXED, defifsvar, 0, 0 }, #else - { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0", 0 }, + { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0", 0, 0 }, #endif #ifdef CONFIG_ASH_MAIL - { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0", changemail }, - { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail }, + { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0", changemail, 0 }, + { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail, 0 }, #endif - { 0, VSTRFIXED|VTEXTFIXED, defpathvar, changepath }, - { 0, VSTRFIXED|VTEXTFIXED, "PS1=$ ", 0 }, - { 0, VSTRFIXED|VTEXTFIXED, "PS2=> ", 0 }, - { 0, VSTRFIXED|VTEXTFIXED, "PS4=+ ", 0 }, + { 0, VSTRFIXED|VTEXTFIXED, defpathvar, changepath, 0 }, + { 0, VSTRFIXED|VTEXTFIXED, "PS1=$ ", 0, 0 }, + { 0, VSTRFIXED|VTEXTFIXED, "PS2=> ", 0, 0 }, + { 0, VSTRFIXED|VTEXTFIXED, "PS4=+ ", 0, 0 }, #ifdef CONFIG_ASH_GETOPTS - { 0, VSTRFIXED|VTEXTFIXED, "OPTIND=1", getoptsreset }, + { 0, VSTRFIXED|VTEXTFIXED, "OPTIND=1", getoptsreset, 0 }, #endif #ifdef CONFIG_LOCALE_SUPPORT - {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL=", change_lc_all}, - {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE=", change_lc_ctype}, + {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL=", change_lc_all, 0}, + {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE=", change_lc_ctype, 0}, #endif #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY - {0, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE=", NULL}, + {0, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE=", NULL, 0}, #endif + {0, VSTRFIXED | VTEXTFIXED | VUNSET | VDYNAMIC, "RANDOM\0", + change_random, get_random}, }; #define vifs varinit[0] @@ -9019,6 +9030,22 @@ static void change_lc_ctype(const char *value) #endif +/* Roughly copied from bash.. */ +static unsigned long rseed = 1; +static char *get_random(const char *var) +{ + char buf[255]; + rseed = (rseed + getpid() + ((time_t)time((time_t *)0))); + rseed = rseed * 1103515245 + 12345; + sprintf(buf, "%d", (unsigned int)((rseed >> 16 & 32767))); + return bb_xstrdup(buf); +} + +static void change_random(const char *value) +{ + rseed = strtoul(value, (char **)NULL, 10); +} + #ifdef CONFIG_ASH_GETOPTS static int getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff) @@ -12031,9 +12058,20 @@ lookupvar(const char *name) { struct var *v; - if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) { + if ((v = *findvar(hashvar(name), name)) && !(v->flags & (VUNSET|VDYNAMIC))) { return strchrnul(v->text, '=') + 1; } + + /* + * Dynamic variables are implemented roughly the same way they are + * in bash. Namely, they're "special" so long as they aren't unset. + * As soon as they're unset, they're no longer dynamic, and dynamic + * lookup will no longer happen at that point. -- PFM. + */ + if (v && ((v->flags & VDYNAMIC))) + if (v->lookup_func) + return v->lookup_func(name); + return NULL; } @@ -12308,6 +12346,8 @@ unsetvar(const char *s) retval = 1; if (flags & VREADONLY) goto out; + if (flags & VDYNAMIC) + vp->flags &= ~VDYNAMIC; if (flags & VUNSET) goto ok; if ((flags & VSTRFIXED) == 0) { -- cgit v1.2.3