further optimise and simplify the handling of $RANDOM, reads and writes

to it are now either arc4random or rand/srand, but srand retains the old
state; set +o arc4random is no longer possible, but if it's there we use
arc4random(3), if not, we use rand(3) for $RANDOM reads; optimise special
variable handling too and fix a few consts and other minor things
This commit is contained in:
tg 2009-09-26 03:40:03 +00:00
parent b50b43e3bf
commit a59d14b565
10 changed files with 158 additions and 242 deletions

View File

@ -1,4 +1,4 @@
# $MirOS: src/bin/mksh/check.t,v 1.310 2009/09/24 17:15:29 tg Exp $ # $MirOS: src/bin/mksh/check.t,v 1.311 2009/09/26 03:39:57 tg Exp $
# $OpenBSD: bksl-nl.t,v 1.2 2001/01/28 23:04:56 niklas 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: 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 $ # $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 # http://www.research.att.com/~gsf/public/ifs.sh
expected-stdout: expected-stdout:
@(#)MIRBSD KSH R39 2009/09/24 @(#)MIRBSD KSH R39 2009/09/25
description: description:
Check version of shell. Check version of shell.
stdin: stdin:
@ -4042,8 +4042,8 @@ description:
isn't exec-ed isn't exec-ed
stdin: stdin:
sortprog=$(whence -p sort) || sortprog=cat sortprog=$(whence -p sort) || sortprog=cat
env | $sortprog >bar1 env | $sortprog | grep -v '^RANDOM=' >bar1
FOO=bar exec; env | $sortprog >bar2 FOO=bar exec; env | $sortprog | grep -v '^RANDOM=' >bar2
cmp -s bar1 bar2 cmp -s bar1 bar2
--- ---
name: xxx-what-do-you-call-this-1 name: xxx-what-do-you-call-this-1

View File

@ -25,7 +25,7 @@
#include "sh.h" #include "sh.h"
__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.134 2009/09/23 18:04:56 tg Exp $"); __RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.135 2009/09/26 03:39:58 tg Exp $");
#if HAVE_KILLPG #if HAVE_KILLPG
/* /*
@ -94,7 +94,7 @@ const struct builtin mkshbuiltins[] = {
#endif #endif
{"pwd", c_pwd}, {"pwd", c_pwd},
{"*=readonly", c_typeset}, {"*=readonly", c_typeset},
{"=typeset", c_typeset}, {T__typeset, c_typeset},
{"+unalias", c_unalias}, {"+unalias", c_unalias},
{"whence", c_whence}, {"whence", c_whence},
#ifndef MKSH_UNEMPLOYED #ifndef MKSH_UNEMPLOYED

6
jobs.c
View File

@ -22,7 +22,7 @@
#include "sh.h" #include "sh.h"
__RCSID("$MirOS: src/bin/mksh/jobs.c,v 1.60 2009/09/20 16:40:55 tg Exp $"); __RCSID("$MirOS: src/bin/mksh/jobs.c,v 1.61 2009/09/26 03:39:59 tg Exp $");
#if HAVE_KILLPG #if HAVE_KILLPG
#define mksh_killpg killpg #define mksh_killpg killpg
@ -416,8 +416,8 @@ exchild(struct op *t, int flags,
else else
p->pid = i; p->pid = i;
#if !HAVE_ARC4RANDOM || !defined(MKSH_SMALL) #if !HAVE_ARC4RANDOM
/* Ensure next child gets a (slightly) different $RANDOM sequence */ /* ensure next child gets a (slightly) different $RANDOM sequence */
change_random(((unsigned long)p->pid << 1) | (ischild ? 1 : 0)); change_random(((unsigned long)p->pid << 1) | (ischild ? 1 : 0));
#endif #endif

84
main.c
View File

@ -33,7 +33,7 @@
#include <locale.h> #include <locale.h>
#endif #endif
__RCSID("$MirOS: src/bin/mksh/main.c,v 1.148 2009/09/26 01:08:27 tg Exp $"); __RCSID("$MirOS: src/bin/mksh/main.c,v 1.149 2009/09/26 03:40:00 tg Exp $");
extern char **environ; extern char **environ;
@ -47,17 +47,17 @@ static void remove_temps(struct temp *);
static const char initifs[] = "IFS= \t\n"; static const char initifs[] = "IFS= \t\n";
static const char initsubs[] = "${PS2=> } ${PS3=#? } ${PS4=+ }"; static const char initsubs[] =
"${PS2=> } ${PS3=#? } ${PS4=+ } ${SECONDS=0} ${TMOUT=0}";
static const char *initcoms[] = { static const char *initcoms[] = {
"typeset", "-r", initvsn, NULL, T_typeset, "-r", initvsn, NULL,
"typeset", "-x", "SHELL", "PATH", "HOME", NULL, T_typeset, "-x", "HOME", "PATH", "RANDOM", "SHELL", NULL,
"typeset", "-i10", "COLUMNS=0", "LINES=0", "OPTIND=1", NULL, T_typeset, "-i10", "COLUMNS", "LINES", "OPTIND", "PGRP", "PPID",
"typeset", "-Ui10", "PGRP", "PPID", "RANDOM", "USER_ID", NULL, "RANDOM", "SECONDS", "TMOUT", "USER_ID", NULL,
"eval", "typeset -i10 SECONDS=\"${SECONDS-0}\" TMOUT=\"${TMOUT-0}\"",
NULL,
"alias", "integer=typeset -i", "local=typeset", NULL,
"alias", "alias",
"integer=typeset -i",
T_local_typeset,
"hash=alias -t", /* not "alias -t --": hash -r needs to work */ "hash=alias -t", /* not "alias -t --": hash -r needs to work */
"type=whence -v", "type=whence -v",
#ifndef MKSH_UNEMPLOYED #ifndef MKSH_UNEMPLOYED
@ -101,8 +101,14 @@ main(int argc, const char *argv[])
char *cp; char *cp;
#endif #endif
kshpid = procpid = getpid();
ksheuid = geteuid();
kshpgrp = getpgrp();
ppid = getppid();
#if !HAVE_ARC4RANDOM #if !HAVE_ARC4RANDOM
change_random((unsigned long)time(NULL) * getpid()); change_random((unsigned long)time(NULL));
change_random(((unsigned long)ksheuid << 16) | kshpid);
#endif #endif
/* make sure argv[] is sane */ /* make sure argv[] is sane */
@ -204,13 +210,14 @@ main(int argc, const char *argv[])
#endif #endif
#ifdef MKSH_BINSHREDUCED #ifdef MKSH_BINSHREDUCED
/* Set FPOSIX if we're called as -sh or /bin/sh or so */ /* set FPOSIX if we're called as -sh or /bin/sh or so */
{ {
const char *cc; const char *cc;
cc = kshname; cc = kshname;
i = 0; argi = 0; i = 0; argi = 0;
while (cc[i] != '\0') while (cc[i] != '\0')
/* the following line matches '-' and '/' ;-) */
if ((cc[i++] | 2) == '/') if ((cc[i++] | 2) == '/')
argi = i; argi = i;
if (((cc[argi] | 0x20) == 's') && ((cc[argi + 1] | 0x20) == 'h')) if (((cc[argi] | 0x20) == 's') && ((cc[argi + 1] | 0x20) == 'h'))
@ -223,7 +230,6 @@ main(int argc, const char *argv[])
for (wp = (const char **)environ; *wp != NULL; wp++) for (wp = (const char **)environ; *wp != NULL; wp++)
typeset(*wp, IMPORT | EXPORT, 0, 0, 0); typeset(*wp, IMPORT | EXPORT, 0, 0, 0);
kshpid = procpid = getpid();
typeset(initifs, 0, 0, 0, 0); /* for security */ typeset(initifs, 0, 0, 0, 0); /* for security */
/* assign default shell variable values */ /* assign default shell variable values */
@ -252,31 +258,38 @@ main(int argc, const char *argv[])
/* setstr can't fail here */ /* setstr can't fail here */
setstr(pwd_v, current_wd, KSH_RETURN_ERROR); setstr(pwd_v, current_wd, KSH_RETURN_ERROR);
} }
ppid = getppid();
#if !HAVE_ARC4RANDOM || !defined(MKSH_SMALL)
change_random(((unsigned long)kshname) ^
((unsigned long)time(NULL) * kshpid * ppid));
#endif
#if HAVE_ARC4RANDOM
Flag(FARC4RANDOM) = 2; /* use arc4random(3) until $RANDOM is written */
#endif
for (wp = initcoms; *wp != NULL; wp++) { for (wp = initcoms; *wp != NULL; wp++) {
shcomexec(wp); shcomexec(wp);
while (*wp != NULL) while (*wp != NULL)
wp++; wp++;
} }
setint(global("COLUMNS"), 0);
setint(global("LINES"), 0);
setint(global("OPTIND"), 1);
vp = global("RANDOM");
#if HAVE_ARC4RANDOM
/* avoid calling setspec */
Flag(FARC4RANDOM) = 1;
vp->flag |= ISSET | INT_U;
#else
vp->flag |= INT_U;
setint(vp, (mksh_ari_t)((unsigned long)kshname + 33 * ppid));
#endif
safe_prompt = (ksheuid = geteuid()) ? "$ " : "# "; safe_prompt = ksheuid ? "$ " : "# ";
vp = global("PS1"); vp = global("PS1");
/* Set PS1 if unset or we are root and prompt doesn't contain a # */ /* Set PS1 if unset or we are root and prompt doesn't contain a # */
if (!(vp->flag & ISSET) || if (!(vp->flag & ISSET) ||
(!ksheuid && !strchr(str_val(vp), '#'))) (!ksheuid && !strchr(str_val(vp), '#')))
/* setstr can't fail here */ /* setstr can't fail here */
setstr(vp, safe_prompt, KSH_RETURN_ERROR); setstr(vp, safe_prompt, KSH_RETURN_ERROR);
setint(global("PGRP"), (mksh_uari_t)(kshpgrp = getpgrp())); setint((vp = global("PGRP")), (mksh_uari_t)kshpgrp);
setint(global("PPID"), (mksh_uari_t)ppid); vp->flag |= INT_U;
setint(global("USER_ID"), (mksh_uari_t)ksheuid); setint((vp = global("PPID")), (mksh_uari_t)ppid);
vp->flag |= INT_U;
setint((vp = global("USER_ID")), (mksh_uari_t)ksheuid);
vp->flag |= INT_U;
/* Set this before parsing arguments */ /* Set this before parsing arguments */
#if HAVE_SETRESUGID #if HAVE_SETRESUGID
@ -408,7 +421,7 @@ main(int argc, const char *argv[])
if (restricted) { if (restricted) {
static const char *restr_com[] = { static const char *restr_com[] = {
"typeset", "-r", "PATH", T_typeset, "-r", "PATH",
"ENV", "SHELL", "ENV", "SHELL",
NULL NULL
}; };
@ -1263,27 +1276,6 @@ hash(const char *cp)
return (h); return (h);
} }
#if !HAVE_ARC4RANDOM || !defined(MKSH_SMALL)
uint32_t
hashmem(const void *cp, size_t len)
{
register uint32_t h = 0;
register const uint8_t *bp = (const uint8_t *)cp;
while (len--) {
h += *bp++;
h += h << 10;
h ^= h >> 6;
}
h += h << 3;
h ^= h >> 11;
h += h << 15;
return (h);
}
#endif
static void static void
texpand(struct table *tp, size_t nsize) texpand(struct table *tp, size_t nsize)
{ {

26
mksh.1
View File

@ -1,4 +1,4 @@
.\" $MirOS: src/bin/mksh/mksh.1,v 1.191 2009/09/20 17:23:51 tg Exp $ .\" $MirOS: src/bin/mksh/mksh.1,v 1.192 2009/09/26 03:40:00 tg Exp $
.\" $OpenBSD: ksh.1,v 1.129 2009/05/28 06:09:06 jmc Exp $ .\" $OpenBSD: ksh.1,v 1.129 2009/05/28 06:09:06 jmc Exp $
.\"- .\"-
.\" Copyright © 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 .\" Copyright © 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
@ -48,7 +48,7 @@
.el .xD \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 .el .xD \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8
.. ..
.\"- .\"-
.Dd $Mdocdate: September 20 2009 $ .Dd $Mdocdate: September 26 2009 $
.Dt MKSH 1 .Dt MKSH 1
.Os MirBSD .Os MirBSD
.Sh NAME .Sh NAME
@ -1807,10 +1807,11 @@ if the shell doesn't know where it is.
Every time Every time
.Ev RANDOM .Ev RANDOM
is referenced, it is assigned a 15-bit pseudo-random number, i.e. between is referenced, it is assigned a 15-bit pseudo-random number, i.e. between
0 and 32767, first. 0 and 32767, first, which is taken from
See the description of .Xr arc4random 3
.Ic set \-o Ic arc4random if available,
below for details. .Xr rand 3
otherwise.
.It Ev REPLY .It Ev REPLY
Default parameter for the Default parameter for the
.Ic read .Ic read
@ -3735,17 +3736,10 @@ Print commands and parameter assignments when they are executed, preceded by
the value of the value of
.Ev PS4 . .Ev PS4 .
.It Ic arc4random .It Ic arc4random
Use If this shell option, which cannot be unset, exists,
.Xr arc4random 3 .Xr arc4random 3
high-quality random numbers for the value of is used for the value of
.Ev RANDOM .Ev RANDOM .
if set (to either 1 or 2), or a semi-predictable sequence from
.Xr rand 3
if unset.
Setting this flag will change its value to 1; the default value is 2,
which means it automatically switches to 0 if
.Ev RANDOM
is written to.
.It Ic bgnice .It Ic bgnice
Background jobs are run with lower priority. Background jobs are run with lower priority.
.It Ic braceexpand .It Ic braceexpand

26
sh.h
View File

@ -134,9 +134,9 @@
#endif #endif
#ifdef EXTERN #ifdef EXTERN
__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.348 2009/09/24 17:15:32 tg Exp $"); __RCSID("$MirOS: src/bin/mksh/sh.h,v 1.349 2009/09/26 03:40:01 tg Exp $");
#endif #endif
#define MKSH_VERSION "R39 2009/09/24" #define MKSH_VERSION "R39 2009/09/25"
#ifndef MKSH_INCLUDES_ONLY #ifndef MKSH_INCLUDES_ONLY
@ -569,6 +569,9 @@ EXTERN char null[] I__("");
EXTERN const char r_fc_e_[] I__("r=fc -e -"); EXTERN const char r_fc_e_[] I__("r=fc -e -");
#define fc_e_ (r_fc_e_ + 2) /* "fc -e -" */ #define fc_e_ (r_fc_e_ + 2) /* "fc -e -" */
#define fc_e_n 7 /* strlen(fc_e_) */ #define fc_e_n 7 /* strlen(fc_e_) */
EXTERN const char T_local_typeset[] I__("local=typeset");
#define T__typeset (T_local_typeset + 5) /* "=typeset" */
#define T_typeset (T_local_typeset + 6) /* "typeset" */
enum temp_type { enum temp_type {
TT_HEREDOC_EXP, /* expanded heredoc */ TT_HEREDOC_EXP, /* expanded heredoc */
@ -963,21 +966,6 @@ struct builtin {
extern const struct builtin mkshbuiltins[]; extern const struct builtin mkshbuiltins[];
/* var spec values */
#define V_NONE 0
#define V_COLUMNS 1
#define V_HISTFILE 2
#define V_HISTSIZE 3
#define V_IFS 4
#define V_LINENO 5
#define V_LINES 6
#define V_OPTIND 7
#define V_PATH 8
#define V_RANDOM 9
#define V_SECONDS 10
#define V_TMOUT 11
#define V_TMPDIR 12
/* values for set_prompt() */ /* values for set_prompt() */
#define PS1 0 /* command */ #define PS1 0 /* command */
#define PS2 1 /* command continuation */ #define PS2 1 /* command continuation */
@ -1601,11 +1589,9 @@ void initvar(void);
struct tbl *global(const char *); struct tbl *global(const char *);
struct tbl *local(const char *, bool); struct tbl *local(const char *, bool);
char *str_val(struct tbl *); char *str_val(struct tbl *);
mksh_ari_t intval(struct tbl *);
int setstr(struct tbl *, const char *, int); int setstr(struct tbl *, const char *, int);
struct tbl *setint_v(struct tbl *, struct tbl *, bool); struct tbl *setint_v(struct tbl *, struct tbl *, bool);
void setint(struct tbl *, mksh_ari_t); void setint(struct tbl *, mksh_ari_t);
int getint(struct tbl *, mksh_ari_t *, bool);
struct tbl *typeset(const char *, Tflag, Tflag, int, int); struct tbl *typeset(const char *, Tflag, Tflag, int, int);
void unset(struct tbl *, int); void unset(struct tbl *, int);
const char *skip_varname(const char *, int); const char *skip_varname(const char *, int);
@ -1613,7 +1599,7 @@ const char *skip_wdvarname(const char *, int);
int is_wdvarname(const char *, int); int is_wdvarname(const char *, int);
int is_wdvarassign(const char *); int is_wdvarassign(const char *);
char **makenv(void); char **makenv(void);
#if !HAVE_ARC4RANDOM || !defined(MKSH_SMALL) #if !HAVE_ARC4RANDOM
void change_random(unsigned long); void change_random(unsigned long);
#endif #endif
void change_winsz(void); void change_winsz(void);

View File

@ -1,5 +1,5 @@
#if defined(SHFLAGS_DEFNS) #if defined(SHFLAGS_DEFNS)
__RCSID("$MirOS: src/bin/mksh/sh_flags.h,v 1.2 2009/09/24 17:15:33 tg Exp $"); __RCSID("$MirOS: src/bin/mksh/sh_flags.h,v 1.3 2009/09/26 03:40:02 tg Exp $");
#define FN(sname,cname,ochar,flags) /* nothing */ #define FN(sname,cname,ochar,flags) /* nothing */
#elif defined(SHFLAGS_ENUMS) #elif defined(SHFLAGS_ENUMS)
#define FN(sname,cname,ochar,flags) cname, #define FN(sname,cname,ochar,flags) cname,
@ -22,9 +22,8 @@ __RCSID("$MirOS: src/bin/mksh/sh_flags.h,v 1.2 2009/09/24 17:15:33 tg Exp $");
F0("allexport", FEXPORT, 'a', OF_ANY) F0("allexport", FEXPORT, 'a', OF_ANY)
#if HAVE_ARC4RANDOM #if HAVE_ARC4RANDOM
/* ./. for $RANDOM (non-standard), use the following function scheme: */ /* ./. backwards compat: available if arc4random(3) is used for $RANDOM */
/* 0:rand(3) 1:arc4random(3) 2:switch from 1 to 0 on write */ FN("arc4random", FARC4RANDOM, 0, OF_INTERNAL)
FN("arc4random", FARC4RANDOM, 0, OF_ANY)
#endif #endif
#if HAVE_NICE #if HAVE_NICE

4
syn.c
View File

@ -22,7 +22,7 @@
#include "sh.h" #include "sh.h"
__RCSID("$MirOS: src/bin/mksh/syn.c,v 1.43 2009/09/23 18:04:58 tg Exp $"); __RCSID("$MirOS: src/bin/mksh/syn.c,v 1.44 2009/09/26 03:40:02 tg Exp $");
struct nesting_state { struct nesting_state {
int start_token; /* token than began nesting (eg, FOR) */ int start_token; /* token than began nesting (eg, FOR) */
@ -877,7 +877,7 @@ assign_command(char *s)
return ((strcmp(s, "alias") == 0) || return ((strcmp(s, "alias") == 0) ||
(strcmp(s, "export") == 0) || (strcmp(s, "export") == 0) ||
(strcmp(s, "readonly") == 0) || (strcmp(s, "readonly") == 0) ||
(strcmp(s, "typeset") == 0)); (strcmp(s, T_typeset) == 0));
} }
/* Check if we are in the middle of reading an alias */ /* Check if we are in the middle of reading an alias */

190
var.c
View File

@ -22,7 +22,7 @@
#include "sh.h" #include "sh.h"
__RCSID("$MirOS: src/bin/mksh/var.c,v 1.91 2009/09/23 18:22:38 tg Exp $"); __RCSID("$MirOS: src/bin/mksh/var.c,v 1.92 2009/09/26 03:40:02 tg Exp $");
/* /*
* Variables * Variables
@ -42,10 +42,16 @@ static void unspecial(const char *);
static void getspec(struct tbl *); static void getspec(struct tbl *);
static void setspec(struct tbl *); static void setspec(struct tbl *);
static void unsetspec(struct tbl *); static void unsetspec(struct tbl *);
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 struct tbl *arraysearch(struct tbl *, uint32_t);
static const char *array_index_calc(const char *, bool *, uint32_t *); static const char *array_index_calc(const char *, bool *, uint32_t *);
static int rnd_get(void); static int rnd_get(void);
#if HAVE_ARC4RANDOM
static void rnd_set(unsigned long); static void rnd_set(unsigned long);
#else
#define rnd_set change_random
#endif
uint8_t set_refflag = 0; uint8_t set_refflag = 0;
@ -101,38 +107,33 @@ popblock(void)
} }
/* called by main() to initialise variable data structures */ /* called by main() to initialise variable data structures */
#define VARSPEC_DEFNS
#include "var_spec.h"
enum var_specs {
#define VARSPEC_ENUMS
#include "var_spec.h"
V_MAX
};
static const char * const initvar_names[] = {
#define VARSPEC_ITEMS
#include "var_spec.h"
};
void void
initvar(void) initvar(void)
{ {
static const struct { int i = 0;
const char *name;
int v;
} names[] = {
{ "COLUMNS", V_COLUMNS },
#if HAVE_PERSISTENT_HISTORY
{ "HISTFILE", V_HISTFILE },
#endif
{ "HISTSIZE", V_HISTSIZE },
{ "IFS", V_IFS },
{ "LINENO", V_LINENO },
{ "LINES", V_LINES },
{ "OPTIND", V_OPTIND },
{ "PATH", V_PATH },
{ "RANDOM", V_RANDOM },
{ "SECONDS", V_SECONDS },
{ "TMOUT", V_TMOUT },
{ "TMPDIR", V_TMPDIR },
{ NULL, 0 }
};
int i;
struct tbl *tp; struct tbl *tp;
ktinit(&specials, APERM, ktinit(&specials, APERM,
/* must be 80% of 2^n (currently 12 specials) */ 16); /* must be 80% of 2^n (currently 12 specials) */ 16);
for (i = 0; names[i].name; i++) { while (i < V_MAX - 1) {
tp = ktenter(&specials, names[i].name, hash(names[i].name)); tp = ktenter(&specials, initvar_names[i],
hash(initvar_names[i]));
tp->flag = DEFINED|ISSET; tp->flag = DEFINED|ISSET;
tp->type = names[i].v; tp->type = ++i;
} }
} }
@ -384,7 +385,7 @@ str_val(struct tbl *vp)
} }
/* get variable integer value, with error checking */ /* get variable integer value, with error checking */
mksh_ari_t static mksh_ari_t
intval(struct tbl *vp) intval(struct tbl *vp)
{ {
mksh_ari_t num; mksh_ari_t num;
@ -461,7 +462,7 @@ setint(struct tbl *vq, mksh_ari_t n)
setspec(vq); setspec(vq);
} }
int static int
getint(struct tbl *vp, mksh_ari_t *nump, bool arith) getint(struct tbl *vp, mksh_ari_t *nump, bool arith)
{ {
char *s; char *s;
@ -964,150 +965,55 @@ makenv(void)
return ((char **)XPclose(denv)); return ((char **)XPclose(denv));
} }
/* #if HAVE_ARC4RANDOM
* Get us a random number, either from rand(3) or arc4random(3), with
* the latter being preferred. If Flag(FARC4RANDOM) is 0, we use rand(3),
* otherwise arc4random(3). We have static caches to make change_random
* and writes to $RANDOM a cheap operation.
*/
#if HAVE_ARC4RANDOM && !defined(MKSH_SMALL)
static uint32_t rnd_cache[2];
static unsigned char rnd_lastflag = 2;
#if HAVE_ARC4RANDOM_PUSHB
static bool rnd_wpush = false;
#define rnd_mix(v,w) rnd_cmix(v,w)
#else
#define rnd_mix(v,w) rnd_cmix(v)
#endif
static void rnd_mix(unsigned long, bool);
static void
rnd_mix(unsigned long newval, bool wantpush)
{
struct {
union {
int rval;
uint32_t arval;
} v0;
uint32_t v1;
uint32_t v2;
unsigned long v3;
#if HAVE_ARC4RANDOM_PUSHB
bool neededpush;
bool wantingpush;
#endif
} v;
#if HAVE_ARC4RANDOM_PUSHB
v.neededpush = rnd_wpush;
v.wantingpush = wantpush;
rnd_wpush = v.neededpush || v.wantingpush;
#endif
v.v0.rval = rand();
v.v1 = rnd_cache[0];
v.v2 = rnd_cache[1];
v.v3 = newval;
rnd_cache[0] = hashmem(&v, sizeof(v));
v.v0.arval = arc4random();
rnd_cache[1] = hashmem(&v, sizeof(v));
}
#endif
static int static int
rnd_get(void) rnd_get(void)
{ {
#if HAVE_ARC4RANDOM && defined(MKSH_SMALL)
return (arc4random() & 0x7FFF); return (arc4random() & 0x7FFF);
#else
#if HAVE_ARC4RANDOM
#if HAVE_ARC4RANDOM_PUSHB
uint32_t rv = 0;
#endif
if (Flag(FARC4RANDOM) != rnd_lastflag) {
if (Flag(FARC4RANDOM) == 0)
/* transition to 0 by set: srand */
srand(arc4random() & 0x7FFF);
else if (rnd_lastflag == 0)
/* transition from 0: addrandom */
rnd_mix(rand(), true);
rnd_lastflag = Flag(FARC4RANDOM);
}
if (Flag(FARC4RANDOM)) {
if (rnd_cache[0] || rnd_cache[1]) {
#if HAVE_ARC4RANDOM_PUSHB
if (rnd_wpush) {
rv = arc4random_pushb(rnd_cache,
sizeof(rnd_cache));
rnd_wpush = false;
} else
#endif
arc4random_addrandom((void *)rnd_cache,
sizeof(rnd_cache));
}
rnd_cache[0] = rnd_cache[1] = 0;
return ((
#if HAVE_ARC4RANDOM_PUSHB
rv ? rv :
#endif
arc4random()) & 0x7FFF);
}
#endif
return (rand() & 0x7FFF);
#endif
} }
static void static void
rnd_set(unsigned long newval) rnd_set(unsigned long newval)
{ {
#if HAVE_ARC4RANDOM && defined(MKSH_SMALL)
#if HAVE_ARC4RANDOM_PUSHB #if HAVE_ARC4RANDOM_PUSHB
arc4random_pushb(&newval, sizeof(newval)); arc4random_pushb(&newval, sizeof(newval));
#else #else
arc4random_addrandom((void *)&newval, sizeof(newval)); arc4random_addrandom((void *)&newval, sizeof(newval));
#endif #endif
}
#else #else
#if HAVE_ARC4RANDOM static int
rnd_mix(newval, true); rnd_get(void)
if (Flag(FARC4RANDOM) == 1) {
return; return (rand() & 0x7FFF);
if (Flag(FARC4RANDOM) == 2)
Flag(FARC4RANDOM) = 0;
/* transition to 0 by write: only srand */
rnd_lastflag = 0;
#endif
srand(newval & 0x7FFF);
#endif
} }
#if !HAVE_ARC4RANDOM || !defined(MKSH_SMALL)
/* /*
* Called after a fork to bump the random number generator. * Called after a fork to bump the random number generator.
* Done to ensure children will not get the same random number sequence * Done to ensure children will not get the same random number sequence
* as the parent processes. * 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 void
change_random(unsigned long newval) change_random(unsigned long newval)
{ {
int rval = 0; register unsigned int h;
#if HAVE_ARC4RANDOM h = rand();
if (Flag(FARC4RANDOM)) { while (newval) {
rnd_mix(newval, false); h += (newval & 0xFF);
return; h += h << 10;
h ^= h >> 6;
newval >>= 8;
} }
#endif
rval += newval & 0x7FFF; h += h << 3;
newval >>= 15; h ^= h >> 11;
rval += newval & 0x7FFF; h += h << 15;
newval >>= 15;
rval += newval + rand();
rval = (rval & 0x7FFF) ^ (rval >> 15);
srand(rval); /* pass all of it, in case RAND_MAX is large */
srand(h);
} }
#endif #endif

39
var_spec.h Normal file
View File

@ -0,0 +1,39 @@
#if defined(VARSPEC_DEFNS)
__RCSID("$MirOS: src/bin/mksh/var_spec.h,v 1.1 2009/09/26 03:40:03 tg Exp $");
#define FN(name) /* nothing */
#elif defined(VARSPEC_ENUMS)
#define FN(name) V_##name,
#define F0(name) V_##name = 0,
#elif defined(VARSPEC_ITEMS)
#define F0(name) /* nothing */
#define FN(name) #name,
#endif
#ifndef F0
#define F0 FN
#endif
/* 0 is always V_NONE */
F0(NONE)
/* 1 and up are special variables */
FN(COLUMNS)
#if HAVE_PERSISTENT_HISTORY
FN(HISTFILE)
#endif
FN(HISTSIZE)
FN(IFS)
FN(LINENO)
FN(LINES)
FN(OPTIND)
FN(PATH)
FN(RANDOM)
FN(SECONDS)
FN(TMOUT)
FN(TMPDIR)
#undef FN
#undef F0
#undef VARSPEC_DEFNS
#undef VARSPEC_ENUMS
#undef VARSPEC_ITEMS