diff --git a/check.t b/check.t index 0ed21d1..9fa6fff 100644 --- a/check.t +++ b/check.t @@ -1,4 +1,4 @@ -# $MirOS: src/bin/mksh/check.t,v 1.332 2009/10/15 16:36:25 tg Exp $ +# $MirOS: src/bin/mksh/check.t,v 1.333 2009/10/17 21:16:01 tg Exp $ # $OpenBSD: bksl-nl.t,v 1.2 2001/01/28 23:04:56 niklas Exp $ # $OpenBSD: history.t,v 1.5 2001/01/28 23:04:56 niklas Exp $ # $OpenBSD: read.t,v 1.3 2003/03/10 03:48:16 david Exp $ @@ -25,7 +25,7 @@ # http://www.research.att.com/~gsf/public/ifs.sh expected-stdout: - @(#)MIRBSD KSH R39 2009/10/15 + @(#)MIRBSD KSH R39 2009/10/17 description: Check version of shell. stdin: diff --git a/jobs.c b/jobs.c index b7c526a..2977421 100644 --- a/jobs.c +++ b/jobs.c @@ -22,7 +22,7 @@ #include "sh.h" -__RCSID("$MirOS: src/bin/mksh/jobs.c,v 1.61 2009/09/26 03:39:59 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/jobs.c,v 1.62 2009/10/17 21:16:02 tg Exp $"); #if HAVE_KILLPG #define mksh_killpg killpg @@ -339,15 +339,18 @@ exchild(struct op *t, int flags, volatile int *xerrok, /* used if XPCLOSE or XCCLOSE */ int close_fd) { - static Proc *last_proc; /* for pipelines */ + static Proc *last_proc; /* for pipelines */ - int i; - sigset_t omask; - Proc *p; - Job *j; - int rv = 0; - int forksleep; - int ischild; + int i, rv = 0, forksleep; + sigset_t omask; + Proc *p; + Job *j; + struct { +#if !HAVE_ARC4RANDOM + pid_t thepid; +#endif + unsigned char ischild; + } pi; if (flags & XEXEC) /* Clear XFORK|XPCLOSE|XCCLOSE|XCOPROC|XPIPEO|XPIPEI|XXCOM|XBGND @@ -410,15 +413,17 @@ exchild(struct op *t, int flags, sigprocmask(SIG_SETMASK, &omask, NULL); errorf("cannot fork - try again"); } - ischild = i == 0; - if (ischild) - p->pid = procpid = getpid(); - else - p->pid = i; +#if !HAVE_ARC4RANDOM + pi.thepid = +#endif + p->pid = (pi.ischild = i == 0) ? (procpid = getpid()) : i; #if !HAVE_ARC4RANDOM - /* ensure next child gets a (slightly) different $RANDOM sequence */ - change_random(((unsigned long)p->pid << 1) | (ischild ? 1 : 0)); + /* + * ensure next child gets a (slightly) different $RANDOM sequence + * from its parent process and other child processes + */ + change_random(&pi, sizeof(pi)); #endif #ifndef MKSH_UNEMPLOYED @@ -440,10 +445,10 @@ exchild(struct op *t, int flags, #endif /* used to close pipe input fd */ - if (close_fd >= 0 && (((flags & XPCLOSE) && !ischild) || - ((flags & XCCLOSE) && ischild))) + if (close_fd >= 0 && (((flags & XPCLOSE) && !pi.ischild) || + ((flags & XCCLOSE) && pi.ischild))) close(close_fd); - if (ischild) { /* child */ + if (pi.ischild) { /* child */ /* Do this before restoring signal */ if (flags & XCOPROC) coproc_cleanup(false); diff --git a/main.c b/main.c index d190f39..4e725cb 100644 --- a/main.c +++ b/main.c @@ -33,7 +33,7 @@ #include #endif -__RCSID("$MirOS: src/bin/mksh/main.c,v 1.152 2009/10/02 18:08:34 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/main.c,v 1.153 2009/10/17 21:16:02 tg Exp $"); extern char **environ; @@ -93,7 +93,6 @@ main(int argc, const char *argv[]) struct block *l; unsigned char restricted, errexit; const char **wp; - pid_t ppid; struct tbl *vp; struct stat s_stdin; #if !defined(_PATH_DEFPATH) && defined(_CS_PATH) @@ -104,11 +103,10 @@ main(int argc, const char *argv[]) kshpid = procpid = getpid(); ksheuid = geteuid(); kshpgrp = getpgrp(); - ppid = getppid(); + kshppid = getppid(); #if !HAVE_ARC4RANDOM - change_random((unsigned long)time(NULL)); - change_random(((unsigned long)ksheuid << 16) | kshpid); + change_random(&kshstate_, sizeof(kshstate_)); #endif /* make sure argv[] is sane */ @@ -267,15 +265,6 @@ main(int argc, const char *argv[]) setint(global("COLUMNS"), 0); setint(global("LINES"), 0); setint(global("OPTIND"), 1); - vp = global("RANDOM"); -#if HAVE_ARC4RANDOM - Flag(FARC4RANDOM) = 1; - /* avoid calling setspec */ - vp->flag |= ISSET | INT_U; -#else - vp->flag |= INT_U; - setint(vp, (mksh_ari_t)((unsigned long)kshname + 33 * ppid)); -#endif safe_prompt = ksheuid ? "$ " : "# "; vp = global("PS1"); @@ -286,10 +275,15 @@ main(int argc, const char *argv[]) setstr(vp, safe_prompt, KSH_RETURN_ERROR); setint((vp = global("PGRP")), (mksh_uari_t)kshpgrp); vp->flag |= INT_U; - setint((vp = global("PPID")), (mksh_uari_t)ppid); + setint((vp = global("PPID")), (mksh_uari_t)kshppid); + vp->flag |= INT_U; + setint((vp = global("RANDOM")), (mksh_uari_t)hash(kshname)); vp->flag |= INT_U; setint((vp = global("USER_ID")), (mksh_uari_t)ksheuid); vp->flag |= INT_U; +#if HAVE_ARC4RANDOM + Flag(FARC4RANDOM) = 1; /* initialised */ +#endif /* Set this before parsing arguments */ #if HAVE_SETRESUGID @@ -1261,11 +1255,10 @@ static struct tbl *ktscan(struct table *, const char *, uint32_t, /* Bob Jenkins' one-at-a-time hash */ uint32_t -hash(const char *cp) +oaathash_full(register const uint8_t *bp) { register uint32_t h = 0; register uint8_t c; - register const uint8_t *bp = (const uint8_t *)cp; while ((c = *bp++)) { h += c; diff --git a/mksh.1 b/mksh.1 index 5924dad..0932af3 100644 --- a/mksh.1 +++ b/mksh.1 @@ -1,4 +1,4 @@ -.\" $MirOS: src/bin/mksh/mksh.1,v 1.194 2009/10/10 21:17:30 tg Exp $ +.\" $MirOS: src/bin/mksh/mksh.1,v 1.195 2009/10/17 21:16:03 tg Exp $ .\" $OpenBSD: ksh.1,v 1.129 2009/05/28 06:09:06 jmc Exp $ .\"- .\" Copyright © 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 @@ -48,7 +48,7 @@ .el .xD \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 .. .\"- -.Dd $Mdocdate: October 10 2009 $ +.Dd $Mdocdate: October 17 2009 $ .Dt MKSH 1 .Os MirBSD .Sh NAME @@ -1810,7 +1810,7 @@ is referenced, it is assigned a 15-bit pseudo-random number, i.e. between 0 and 32767, first, which is taken from .Xr arc4random 3 if available, -.Xr rand 3 +a Linear Congruential PRNG otherwise. .It Ev REPLY Default parameter for the @@ -5736,10 +5736,8 @@ Privileged shell profile. .Xr arc4random 3 , .Xr getopt 3 , .Xr nl_langinfo 3 , -.Xr rand 3 , .Xr setlocale 3 , .Xr signal 3 , -.Xr srand 3 , .Xr system 3 , .Xr tty 4 , .Xr shells 5 , diff --git a/sh.h b/sh.h index 593944a..d84c4d8 100644 --- a/sh.h +++ b/sh.h @@ -134,9 +134,9 @@ #endif #ifdef EXTERN -__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.355 2009/10/15 16:36:27 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.356 2009/10/17 21:16:04 tg Exp $"); #endif -#define MKSH_VERSION "R39 2009/10/15" +#define MKSH_VERSION "R39 2009/10/17" #ifndef MKSH_INCLUDES_ONLY @@ -348,13 +348,25 @@ typedef uint32_t mksh_uari_t; #define PATH_MAX 1024 /* pathname size */ #endif -EXTERN const char *kshname; /* $0 */ -EXTERN pid_t kshpid; /* $$, shell pid */ -EXTERN pid_t procpid; /* pid of executing process */ -EXTERN pid_t kshpgrp; /* process group of shell */ -EXTERN uid_t ksheuid; /* effective uid of shell */ -EXTERN int exstat; /* exit status */ -EXTERN int subst_exstat; /* exit status of last $(..)/`..` */ +EXTERN struct { + const char *kshname_; /* $0 */ + pid_t kshpid_; /* $$, shell PID */ + pid_t procpid_; /* PID of executing process */ + pid_t kshpgrp_; /* process group of shell */ + uid_t ksheuid_; /* effective UID of shell */ + pid_t kshppid_; /* PID of parent of shell */ + int exstat_; /* exit status */ + int subst_exstat_; /* exit status of last $(..)/`..` */ +} kshstate_; +#define kshname kshstate_.kshname_ +#define kshpid kshstate_.kshpid_ +#define procpid kshstate_.procpid_ +#define kshpgrp kshstate_.kshpgrp_ +#define ksheuid kshstate_.ksheuid_ +#define kshppid kshstate_.kshppid_ +#define exstat kshstate_.exstat_ +#define subst_exstat kshstate_.subst_exstat_ + EXTERN const char *safe_prompt; /* safe prompt if PS1 substitution fails */ EXTERN const char initvsn[] I__("KSH_VERSION=@(#)MIRBSD KSH " MKSH_VERSION); #define KSH_VERSION (initvsn + /* "KSH_VERSION=@(#)" */ 16) @@ -735,8 +747,8 @@ EXTERN size_t current_wd_size; */ #define MIN_COLS (2 + MIN_EDIT_SPACE + 3) #define MIN_LINS 3 -EXTERN int x_cols I__(80); /* tty columns */ -EXTERN int x_lins I__(-1); /* tty lines */ +EXTERN mksh_ari_t x_cols I__(80); /* tty columns */ +EXTERN mksh_ari_t x_lins I__(-1); /* tty lines */ /* These to avoid bracket matching problems */ #define OPAREN '(' @@ -1505,7 +1517,8 @@ void coproc_write_close(int); int coproc_getfd(int, const char **); void coproc_cleanup(int); struct temp *maketemp(Area *, Temp_type, struct temp **); -uint32_t hash(const char *); +#define hash(s) oaathash_full((const uint8_t *)(s)) +uint32_t oaathash_full(register const uint8_t *); uint32_t hashmem(const void *, size_t); void ktinit(struct table *, Area *, size_t); struct tbl *ktsearch(struct table *, const char *, uint32_t); @@ -1601,7 +1614,7 @@ int is_wdvarname(const char *, int); int is_wdvarassign(const char *); char **makenv(void); #if !HAVE_ARC4RANDOM -void change_random(unsigned long); +void change_random(const void *, size_t); #endif void change_winsz(void); int array_ref_len(const char *); diff --git a/var.c b/var.c index 8bd4075..5be9c39 100644 --- a/var.c +++ b/var.c @@ -22,7 +22,7 @@ #include "sh.h" -__RCSID("$MirOS: src/bin/mksh/var.c,v 1.94 2009/09/27 10:31:06 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/var.c,v 1.95 2009/10/17 21:16:05 tg Exp $"); /* * Variables @@ -46,11 +46,11 @@ static int getint(struct tbl *, mksh_ari_t *, bool); static mksh_ari_t intval(struct tbl *); static struct tbl *arraysearch(struct tbl *, uint32_t); static const char *array_index_calc(const char *, bool *, uint32_t *); -static int rnd_get(void); -#if HAVE_ARC4RANDOM -static void rnd_set(unsigned long); -#else -#define rnd_set change_random +#if !HAVE_ARC4RANDOM +static uint32_t oaathash_update(register uint32_t, register const uint8_t *, + register size_t); + +static uint32_t lcg_seed = 5381; #endif uint8_t set_refflag = 0; @@ -972,58 +972,45 @@ makenv(void) return ((char **)XPclose(denv)); } -#if HAVE_ARC4RANDOM -static int -rnd_get(void) +#if !HAVE_ARC4RANDOM +static uint32_t +oaathash_update(register uint32_t h, register const uint8_t *cp, + register size_t n) { - return (arc4random() & 0x7FFF); -} - -static void -rnd_set(unsigned long newval) -{ -#if HAVE_ARC4RANDOM_PUSHB - if (Flag(FARC4RANDOM)) - /* initialisation, environment import, etc. already done */ - arc4random_pushb(&newval, sizeof(newval)); - else - /* during start-up phase or somesuch */ -#endif - arc4random_addrandom((void *)&newval, sizeof(newval)); -} -#else -static int -rnd_get(void) -{ - return (rand() & 0x7FFF); -} - -/* - * Called after a fork to bump the random number generator. - * Done to ensure children will not get the same random number sequence - * as the parent processes. - * Also called as rnd_set - mksh R40+ no longer has the traditional - * repeatability of randomness sequences, state is always retained. - */ -void -change_random(unsigned long newval) -{ - register unsigned int h; - - h = rand(); - while (newval) { - h += (newval & 0xFF); + while (n--) { + h += *cp++; h += h << 10; h ^= h >> 6; - newval >>= 8; } + return (h); +} + +void +change_random(const void *vp, size_t n) +{ + register uint32_t h; + struct { + const void *sp, *bp, *dp; + size_t dsz; + struct timeval tv; + uint32_t s; + } i; + + i.dp = vp; + i.dsz = n; + i.s = lcg_seed; + i.bp = &lcg_seed; + i.sp = &i; + gettimeofday(&i.tv, NULL); + h = oaathash_update(oaathash_update(1, (void *)&i, sizeof(i)), vp, n); + + /* oaathash_finalise */ h += h << 3; h ^= h >> 11; h += h << 15; - /* pass all of it, in case RAND_MAX is large */ - srand(h); + lcg_seed = h; } #endif @@ -1058,82 +1045,84 @@ static int user_lineno; /* what user set $LINENO to */ static void getspec(struct tbl *vp) { - int i; + register mksh_ari_t i; + int st; - switch ((i = special(vp->name))) { + switch ((st = special(vp->name))) { case V_SECONDS: - vp->flag &= ~SPECIAL; - /* On start up the value of SECONDS is used before seconds - * has been set - don't do anything in this case + /* + * On start up the value of SECONDS is used before + * it has been set - don't do anything in this case * (see initcoms[] in main.c). */ if (vp->flag & ISSET) { struct timeval tv; gettimeofday(&tv, NULL); - setint(vp, tv.tv_sec - seconds); - } - vp->flag |= SPECIAL; + i = tv.tv_sec - seconds; + } else + return; break; case V_RANDOM: - vp->flag &= ~SPECIAL; - setint(vp, rnd_get()); - vp->flag |= SPECIAL; +#if HAVE_ARC4RANDOM + i = arc4random() & 0x7FFF; +#else + /* + * this is the same Linear Congruential PRNG as Borland + * C/C++ allegedly uses in its built-in rand() function + */ + i = ((lcg_seed = 22695477 * lcg_seed + 1) >> 16) & 0x7FFF; +#endif break; case V_HISTSIZE: - vp->flag &= ~SPECIAL; - setint(vp, (mksh_ari_t)histsize); - vp->flag |= SPECIAL; + i = histsize; break; case V_OPTIND: - vp->flag &= ~SPECIAL; - setint(vp, (mksh_ari_t)user_opt.uoptind); - vp->flag |= SPECIAL; + i = user_opt.uoptind; break; case V_LINENO: - vp->flag &= ~SPECIAL; - setint(vp, (mksh_ari_t)current_lineno + user_lineno); - vp->flag |= SPECIAL; + i = current_lineno + user_lineno; break; case V_COLUMNS: case V_LINES: - /* Do NOT export COLUMNS/LINES. Many applications + /* + * Do NOT export COLUMNS/LINES. Many applications * check COLUMNS/LINES before checking ws.ws_col/row, * so if the app is started with C/L in the environ * and the window is then resized, the app won't * see the change cause the environ doesn't change. */ - vp->flag &= ~SPECIAL; change_winsz(); - setint(vp, i == V_COLUMNS ? x_cols : x_lins); - vp->flag |= SPECIAL; + i = st == V_COLUMNS ? x_cols : x_lins; break; + default: + /* do nothing, do not touch vp at all */ + return; } + vp->flag &= ~SPECIAL; + setint(vp, i); + vp->flag |= SPECIAL; } static void setspec(struct tbl *vp) { - int i; + mksh_ari_t i; char *s; + int st; - switch (special(vp->name)) { + switch ((st = special(vp->name))) { case V_PATH: if (path) afree(path, APERM); s = str_val(vp); strdupx(path, s, APERM); flushcom(1); /* clear tracked aliases */ - break; + return; case V_IFS: setctypes(s = str_val(vp), C_IFS); ifs0 = *s; - break; - case V_OPTIND: - vp->flag &= ~SPECIAL; - getopts_reset((int)intval(vp)); - vp->flag |= SPECIAL; - break; + return; case V_TMPDIR: if (tmpdir) { afree(tmpdir, APERM); @@ -1151,54 +1140,84 @@ setspec(struct tbl *vp) strdupx(tmpdir, s, APERM); } break; - case V_HISTSIZE: - vp->flag &= ~SPECIAL; - sethistsize((int)intval(vp)); - vp->flag |= SPECIAL; - break; #if HAVE_PERSISTENT_HISTORY case V_HISTFILE: sethistfile(str_val(vp)); break; #endif - case V_COLUMNS: - vp->flag &= ~SPECIAL; - if ((i = intval(vp)) >= MIN_COLS) - x_cols = i; - vp->flag |= SPECIAL; - break; - case V_LINES: - vp->flag &= ~SPECIAL; - if ((i = intval(vp)) >= MIN_LINS) - x_lins = i; - vp->flag |= SPECIAL; - break; - case V_RANDOM: - vp->flag &= ~SPECIAL; - rnd_set(intval(vp)); - vp->flag |= SPECIAL; - break; - case V_SECONDS: - vp->flag &= ~SPECIAL; - { - struct timeval tv; - - gettimeofday(&tv, NULL); - seconds = tv.tv_sec - intval(vp); - } - vp->flag |= SPECIAL; - break; case V_TMOUT: /* AT&T ksh seems to do this (only listen if integer) */ if (vp->flag & INTEGER) ksh_tmout = vp->val.i >= 0 ? vp->val.i : 0; break; + + /* common sub-cases */ + case V_OPTIND: + case V_HISTSIZE: + case V_COLUMNS: + case V_LINES: + case V_RANDOM: + case V_SECONDS: case V_LINENO: vp->flag &= ~SPECIAL; - /* The -1 is because line numbering starts at 1. */ - user_lineno = (unsigned int)intval(vp) - current_lineno - 1; + i = intval(vp); vp->flag |= SPECIAL; break; + default: + /* do nothing, do not touch vp at all */ + return; + } + + /* process the singular parts of the common cases */ + + switch (st) { + case V_OPTIND: + getopts_reset((int)i); + break; + case V_HISTSIZE: + sethistsize((int)i); + break; + case V_COLUMNS: + if (i >= MIN_COLS) + x_cols = i; + break; + case V_LINES: + if (i >= MIN_LINS) + x_lins = i; + break; + case V_RANDOM: +#if HAVE_ARC4RANDOM +#if HAVE_ARC4RANDOM_PUSHB + if (Flag(FARC4RANDOM)) + /* + * things like initialisation, environment import, + * etc. are already done + */ + arc4random_pushb(&i, sizeof(i)); + else + /* during start-up phase or somesuch */ +#endif /* HAVE_ARC4RANDOM_PUSHB */ + arc4random_addrandom((void *)&i, sizeof(i)); +#else /* !HAVE_ARC4RANDOM */ + /* + * mksh R40+ no longer has the traditional repeatability + * of $RANDOM sequences, but always retains state + */ + change_random(&i, sizeof(i)); +#endif /* !HAVE_ARC4RANDOM */ + break; + case V_SECONDS: + { + struct timeval tv; + + gettimeofday(&tv, NULL); + seconds = tv.tv_sec - i; + } + break; + case V_LINENO: + /* The -1 is because line numbering starts at 1. */ + user_lineno = (unsigned int)i - current_lineno - 1; + break; } }