mirror of
https://github.com/lcn2/calc.git
synced 2025-08-19 01:13:27 +03:00
Updated COPYING file to indicate that these files are now covered under "The Unlicense" (see https://unlicense.org): sha1.c sha1.h cal/dotest.cal cal/screen.cal Updated help/credit to match the above changes to COPYING. Updated CONTRIB-CODE and calc.man to refer to using GitHub pull requests for contributing to calc (instead of using Email). Updated BUGS and calc.man to refer to using GitHub issues for reporting calc bugs (instead of using Email). Updated QUESTIONS and calc.man to refer to using GitHub issues for asking calc questions (instead of using Email). Fixed Makefile.local command example to refer to overriding the Makefile variable DEBUG (instead of CDEBUG). Fixed all make chk ASAN warnings under macOS 13.2.1 when calc is compiled with the following uncommented lines in Makefile.local: DEBUG:= -O0 -g CFLAGS+= -fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined LDFLAGS+= -fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined CALC_ENV+= ASAN_OPTIONS=detect_stack_use_after_return=1 Improved how pointers to functions are declared for the builtins array in func.c to avoid function declarations without a prototype that is now deprecated in C. Improved how pointers to functions are declared for the opcodes array in opcodes.c to avoid function declarations without a prototype Replaced use of egrep with grep -E in Makefiles. Fixed cases where variables were set but not used in symbol.c, calc.c, and the main function in func.c as used by funclist.c. Added rule name to "DO NOT EDIT -- generated by the Makefile" lines in constructed files. Test if <sys/vfs.h> exists and set HAVE_SYS_VFS_H accordingly in have_sys_vfs.h. Added HAVE_SYS_VFS_H to allow one to force this value. Test if <sys/param.h> exists and set HAVE_SYS_PARAM_H accordingly in have_sys_param.h. Added HAVE_SYS_PARAM_H to allow one to force this value. Test if <sys/mount.h> exists and set HAVE_SYS_MOUNT_H accordingly in have_sys_mount.h. Added HAVE_SYS_MOUNT_H to allow one to force this value. Test if the system as the statfs() system call and set HAVE_STATFS accordingly in have_statfs.h. Added HAVE_STATFS to allow one to force this value. The pseudo_seed() function will also try to call statfs() if possible and permitted by the HAVE_STATFS value.
804 lines
26 KiB
C
804 lines
26 KiB
C
/*
|
|
* seed - produce pseudo-random seeds
|
|
*
|
|
* Copyright (C) 1999-2007,2021 Landon Curt Noll
|
|
*
|
|
* Calc is open software; you can redistribute it and/or modify it under
|
|
* the terms of the version 2.1 of the GNU Lesser General Public License
|
|
* as published by the Free Software Foundation.
|
|
*
|
|
* Calc is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
|
|
* Public License for more details.
|
|
*
|
|
* A copy of version 2.1 of the GNU Lesser General Public License is
|
|
* distributed with calc under the filename COPYING-LGPL. You should have
|
|
* received a copy with calc; if not, write to Free Software Foundation, Inc.
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
* Under source code control: 1999/10/03 10:06:53
|
|
* File existed as early as: 1999
|
|
*
|
|
* chongo <was here> /\oo/\ http://www.isthe.com/chongo/
|
|
* Share and enjoy! :-) http://www.isthe.com/chongo/tech/comp/calc/
|
|
*/
|
|
|
|
/*
|
|
* Generate a quasi-random seed based on system and process information.
|
|
*
|
|
* NOTE: This is not a good source of chaotic data. The LavaRnd
|
|
* system does a much better job of that. See:
|
|
*
|
|
* http://www.LavaRnd.org/
|
|
*/
|
|
|
|
|
|
#include <stdio.h>
|
|
#include <errno.h>
|
|
|
|
#include "have_stdlib.h"
|
|
#if defined(HAVE_STDLIB_H)
|
|
#include <stdlib.h>
|
|
#endif
|
|
|
|
#include "have_unistd.h"
|
|
#if defined(HAVE_UNISTD_H)
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
#if defined(_WIN32) || defined(_WIN64)
|
|
# include <process.h>
|
|
# define pid_t int
|
|
#endif
|
|
|
|
/*
|
|
* PORTING NOTE:
|
|
* These includes are used by pseudo_seed(). If for some
|
|
* reason some of these include files are missing or damaged
|
|
* on your system, feel free to remove them (and the related
|
|
* calls inside pseudo_seed()), add or replace them. The
|
|
* pseudo_seed() function just needs to gather a bunch of
|
|
* information about the process and system state so the
|
|
* loss or inclusion of a few other calls should not hurt
|
|
* that much.
|
|
*/
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include "have_times.h"
|
|
|
|
#if defined(HAVE_TIME_H)
|
|
#include <time.h>
|
|
#endif /* HAVE_TIME_H */
|
|
|
|
#if defined(HAVE_SYS_TIME_H)
|
|
#include <sys/time.h>
|
|
#endif /* HAVE_SYS_TIME_H */
|
|
|
|
#if defined(HAVE_SYS_TIMES_H)
|
|
#include <sys/times.h>
|
|
#endif /* HAVE_SYS_TIMES_H */
|
|
|
|
#if !defined(_WIN32) && !defined(_WIN64)
|
|
# include <sys/resource.h>
|
|
#endif
|
|
|
|
#if defined(HAVE_STDLIB_H)
|
|
# include <stdlib.h>
|
|
/* NOTE: RANDOM_CNT should remain 32 to circular shift 31-bit returns */
|
|
# define RANDOM_CNT (32) /* random() call repeat and circular shift */
|
|
# define INITSTATE_SIZE (256) /* initstate pool size */
|
|
#endif /* HAVE_STDLIB_H */
|
|
|
|
#include <setjmp.h>
|
|
#include "alloc.h"
|
|
#include "qmath.h"
|
|
#include "longbits.h"
|
|
#include "have_ustat.h"
|
|
#include "have_getsid.h"
|
|
#include "have_getpgid.h"
|
|
#include "have_gettime.h"
|
|
#include "have_getprid.h"
|
|
#include "have_urandom.h"
|
|
#include "have_rusage.h"
|
|
#include "have_uid_t.h"
|
|
#include "have_environ.h"
|
|
#include "have_arc4random.h"
|
|
|
|
#if defined(HAVE_USTAT)
|
|
# include <ustat.h>
|
|
#endif /* HAVE_USTAT */
|
|
|
|
#if defined(HAVE_URANDOM)
|
|
# include <fcntl.h>
|
|
# define DEV_URANDOM "/dev/urandom"
|
|
# define DEV_URANDOM_POOL (16)
|
|
#endif /* HAVE_URANDOM */
|
|
|
|
#include "have_sys_vfs.h"
|
|
#if defined(HAVE_SYS_VFS_H)
|
|
# include <sys/vfs.h>
|
|
#endif /* HAVE_SYS_VFS_H */
|
|
|
|
#include "have_sys_param.h"
|
|
#if defined(HAVE_SYS_PARAM_H)
|
|
# include <sys/param.h>
|
|
#endif /* HAVE_SYS_PARAM_H */
|
|
|
|
#include "have_sys_mount.h"
|
|
#if defined(HAVE_SYS_MOUNT_H)
|
|
# include <sys/mount.h>
|
|
#endif /* HAVE_SYS_MOUNT_H */
|
|
|
|
#include "have_statfs.h"
|
|
|
|
#include "banned.h" /* include after system header <> includes */
|
|
|
|
|
|
/*
|
|
* 64 bit hash value
|
|
*/
|
|
#if defined(HAVE_B64)
|
|
typedef USB64 hash64;
|
|
static hash64 prev_hash64 = 0; /* previous pseudo_seed() return or 0 */
|
|
#else
|
|
struct s_hash64 {
|
|
USB32 w32[2];
|
|
};
|
|
typedef struct s_hash64 hash64;
|
|
static hash64 prev_hash64 = { 0, 0 }; /* previous pseudo_seed() return or 0 */
|
|
#endif
|
|
|
|
#if defined(HAVE_ENVIRON)
|
|
extern char **environ; /* user environment */
|
|
#endif /* HAVE_ENVIRON */
|
|
|
|
#if defined(HAVE_ARC4RANDOM)
|
|
#define ARC4_BUFLEN (16)
|
|
static char arc4_buf[ARC4_BUFLEN];
|
|
#endif /* HAVE_ARC4RANDOM */
|
|
|
|
|
|
/*
|
|
* call counter - number of times pseudo_seed() as been called
|
|
*/
|
|
static FULL call_count = 0;
|
|
|
|
|
|
/*
|
|
* 64-bit initial basis - Based on the 64-bit FNV basis value
|
|
*
|
|
* We start the hash at a non-zero value at the beginning so that
|
|
* hashing blocks of data with all 0 bits do not map onto the same
|
|
* 0 hash value. The virgin value that we use below is the hash value
|
|
* that we would get from following 32 ASCII characters:
|
|
*
|
|
* chongo <Landon Curt Noll> /\../\
|
|
*
|
|
* Note that the \'s above are not back-slashing escape characters.
|
|
* They are literal ASCII backslash 0x5c characters.
|
|
*
|
|
* The effect of this virgin initial value is the same as starting
|
|
* with 0 and pre-pending those 32 characters onto the data being
|
|
* hashed.
|
|
*
|
|
* Yes, even with this non-zero virgin value there is a set of data
|
|
* that will result in a zero hash value. Worse, appending some
|
|
* mount of zero value bytes will continue to produce a zero hash value.
|
|
* But that would happen with any initial value so long as the hash
|
|
* was the hash `inverse' of the virgin prefix string.
|
|
*
|
|
* But then again for any hash function, there exists sets of data
|
|
* which that the hash of every member is the same value. That is
|
|
* life with mapping functions. All we do here is to prevent sets
|
|
* whose members consist of 0 or more bytes of 0's from being such
|
|
* an awkward set.
|
|
*
|
|
* And yes, someone can figure out what the magic 'inverse' of the
|
|
* 32 ASCII character are ... but this hash function is NOT intended
|
|
* to be a cryptographic hash function, just a fast and reasonably
|
|
* good hash function.
|
|
*/
|
|
#if defined(HAVE_B64)
|
|
# define PRIVATE_64_BASIS ((hash64)(0xcbf29ce484222325ULL))
|
|
#else
|
|
# define PRIVATE_64_BASIS_0 ((USB32)0x2325)
|
|
# define PRIVATE_64_BASIS_1 ((USB32)0x8422)
|
|
# define PRIVATE_64_BASIS_2 ((USB32)0x9ce4)
|
|
# define PRIVATE_64_BASIS_3 ((USB32)0xcbf2)
|
|
#endif
|
|
|
|
|
|
/*
|
|
* initial_private_hash64 - initial basis of Fowler/Noll/Vo-1 64 bit hash
|
|
*/
|
|
S_FUNC hash64
|
|
initial_private_hash64(void)
|
|
{
|
|
hash64 hval; /* current hash value */
|
|
#if defined(HAVE_B64)
|
|
hval = PRIVATE_64_BASIS;
|
|
#else /* HAVE_B64 */
|
|
USB32 val[4]; /* hash value in base 2^16 */
|
|
|
|
/* hash each octet of the buffer */
|
|
val[0] = PRIVATE_64_BASIS_0;
|
|
val[1] = PRIVATE_64_BASIS_1;
|
|
val[2] = PRIVATE_64_BASIS_2;
|
|
val[3] = PRIVATE_64_BASIS_3;
|
|
|
|
/* convert to hash64 */
|
|
/* hval.w32[1] = 0xffff&(val[3]<<16)+val[2]; */
|
|
hval.w32[1] = (val[3]<<16) + val[2];
|
|
hval.w32[0] = (val[1]<<16) + val[0];
|
|
#endif /* HAVE_B64 */
|
|
|
|
/* return our initial hash value */
|
|
return hval;
|
|
}
|
|
|
|
|
|
/*
|
|
* private_hash64_buf - perform a Fowler/Noll/Vo-1 64 bit hash
|
|
*
|
|
* FNV-1 - Fowler/Noll/Vo-1 64 bit hash
|
|
*
|
|
* The basis of this hash algorithm was taken from an idea sent
|
|
* as reviewer comments to the IEEE POSIX P1003.2 committee by:
|
|
*
|
|
* Phong Vo (http://www.research.att.com/info/kpv/)
|
|
* Glenn Fowler (http://www.research.att.com/~gsf/)
|
|
*
|
|
* In a subsequent ballot round:
|
|
*
|
|
* Landon Curt Noll (http://www.isthe.com/chongo/)
|
|
*
|
|
* improved on their algorithm. Some people tried this hash
|
|
* and found that it worked rather well. In an Email message
|
|
* to Landon, they named it ``Fowler/Noll/Vo'' or the FNV hash.
|
|
*
|
|
* FNV hashes are designed to be fast while maintaining a low
|
|
* collision rate. The FNV speed allows one to quickly hash lots
|
|
* of data while maintaining a reasonable collision rate. See:
|
|
*
|
|
* http://www.isthe.com/chongo/tech/comp/fnv/
|
|
*
|
|
* for more details as well as other forms of the FNV hash.
|
|
*
|
|
* NOTE: For general hash functions, we recommend using the
|
|
* FNV-1a hash function. The use of FNV-1 is kept
|
|
* for backwards compatibility purposes and because
|
|
* the use of FNV-1 in this special purpose, suffices.
|
|
*
|
|
* input:
|
|
* buf - start of buffer to hash
|
|
* len - length of buffer in octets
|
|
* hval - the hash value to modify
|
|
*
|
|
* returns:
|
|
* 64 bit hash as a static hash64 structure
|
|
*/
|
|
S_FUNC hash64
|
|
private_hash64_buf(hash64 hval, char *buf, unsigned len)
|
|
{
|
|
#if !defined(HAVE_B64)
|
|
USB32 val[4]; /* hash value in base 2^16 */
|
|
USB32 tmp[4]; /* tmp 64 bit value */
|
|
#endif /* HAVE_B64 */
|
|
char *buf_end = buf+len; /* beyond end of hash area */
|
|
|
|
#if defined(HAVE_B64)
|
|
|
|
/* hash each octet of the buffer */
|
|
for (; buf < buf_end; ++buf) {
|
|
|
|
/* multiply by 1099511628211ULL mod 2^64 using 64 bit longs */
|
|
hval *= (hash64)1099511628211ULL;
|
|
|
|
/* xor the bottom with the current octet */
|
|
hval ^= (hash64)(*buf);
|
|
}
|
|
|
|
#else /* HAVE_B64 */
|
|
|
|
/* load val array from hval argument */
|
|
val[0] = hval.w32[0] & 0xffff;
|
|
val[1] = (hval.w32[0]>>16) & 0xffff;
|
|
val[2] = hval.w32[1] & 0xffff;
|
|
val[3] = (hval.w32[1]>>16) & 0xffff;
|
|
|
|
for (; buf < buf_end; ++buf) {
|
|
|
|
/*
|
|
* multiply by 1099511628211 mod 2^64 using 32 bit longs
|
|
*
|
|
* Using 1099511628211, we have the following digits base 2^16:
|
|
*
|
|
* 0x0 0x100 0x0 0x1b3
|
|
*/
|
|
/* multiply by the lowest order digit base 2^16 */
|
|
tmp[0] = val[0] * 0x1b3;
|
|
tmp[1] = val[1] * 0x1b3;
|
|
tmp[1] = val[2] * 0x1b3;
|
|
tmp[3] = val[3] * 0x1b3;
|
|
/* multiply by the other non-zero digit */
|
|
tmp[2] += val[0] << 8; /* tmp[2] += val[0] * 0x100 */
|
|
tmp[3] += val[1] << 8; /* tmp[1] += val[1] * 0x100 */
|
|
/* propagate carries */
|
|
tmp[1] += (tmp[0] >> 16);
|
|
val[0] = tmp[0] & 0xffff;
|
|
tmp[2] += (tmp[1] >> 16);
|
|
val[1] = tmp[1] & 0xffff;
|
|
val[3] = tmp[3] + (tmp[2] >> 16);
|
|
val[2] = tmp[2] & 0xffff;
|
|
/*
|
|
* Doing a val[3] &= 0xffff; is not really needed since it simply
|
|
* removes multiples of 2^64. We can discard these excess bits
|
|
* outside of the loop when we convert to hash64.
|
|
*/
|
|
|
|
/* xor the bottom with the current octet */
|
|
val[0] ^= (USB32)(*buf);
|
|
}
|
|
|
|
/* convert to hash64 */
|
|
/* hval.w32[1] = 0xffff&(val[3]<<16)+val[2]; */
|
|
hval.w32[1] = (val[3]<<16) + val[2];
|
|
hval.w32[0] = (val[1]<<16) + val[0];
|
|
|
|
#endif /* HAVE_B64 */
|
|
|
|
/* return our hash value */
|
|
return hval;
|
|
}
|
|
|
|
|
|
/*
|
|
* pseudo_seed - seed the generator with a quasi-random seed
|
|
*
|
|
* Generate a quasi-random seed based on system and process information.
|
|
*
|
|
* NOTE: This is not a good source of chaotic data. The LavaRnd
|
|
* system does a much better job of that. See:
|
|
*
|
|
* http://www.LavaRnd.org/
|
|
*
|
|
* PORTING NOTE:
|
|
* If when porting this code to your system and something
|
|
* won't compile, just remove that line or replace it with
|
|
* some other system call. We don't have to have every call
|
|
* operating below. We only want to hash the resulting data.
|
|
*
|
|
* returns:
|
|
* a pseudo-seed as a NUMBER over the range [0, 2^64)
|
|
*/
|
|
NUMBER *
|
|
pseudo_seed(void)
|
|
{
|
|
/*
|
|
* sdata - data used for quasi-random seed
|
|
*/
|
|
struct {
|
|
#if defined(HAVE_GETTIME)
|
|
# if defined(CLOCK_REALTIME)
|
|
struct timespec realtime; /* POSIX realtime clock */
|
|
# endif
|
|
#endif
|
|
#if defined(HAVE_GETPRID)
|
|
prid_t getprid; /* project ID */
|
|
#endif
|
|
#if defined(HAVE_URANDOM)
|
|
int urandom_fd; /* open descriptor for /dev/urandom */
|
|
int urandom_ret; /* read() of /dev/random */
|
|
char urandom_pool[DEV_URANDOM_POOL]; /* /dev/urandom data pool */
|
|
#endif
|
|
#if defined(HAVE_SYS_TIME_H)
|
|
struct timeval tp; /* time of day */
|
|
#endif
|
|
pid_t getpid; /* process ID */
|
|
#if !defined(_WIN32) && !defined(_WIN64)
|
|
pid_t getppid; /* parent process ID */
|
|
#endif
|
|
#if defined(HAVE_UID_T)
|
|
uid_t getuid; /* real user ID */
|
|
uid_t geteuid; /* effective user ID */
|
|
gid_t getgid; /* real group ID */
|
|
gid_t getegid; /* effective group ID */
|
|
#endif
|
|
struct stat stat_dot; /* stat of "." */
|
|
struct stat stat_dotdot; /* stat of ".." */
|
|
struct stat stat_tmp; /* stat of "/tmp" */
|
|
struct stat stat_root; /* stat of "/" */
|
|
struct stat stat_tty; /* stat of "/dev/tty" */
|
|
struct stat stat_console; /* stat of "/dev/console" */
|
|
struct stat fstat_stdin; /* stat of stdin */
|
|
struct stat fstat_stdout; /* stat of stdout */
|
|
struct stat fstat_stderr; /* stat of stderr */
|
|
struct stat stat_zero; /* stat of "/dev/zero" */
|
|
struct stat stat_null; /* stat of "/dev/null" */
|
|
struct stat stat_sh; /* stat of "/bin/sh" */
|
|
struct stat stat_ls; /* stat of "/bin/ls" */
|
|
/* stat of "/var/log/system.log" */
|
|
struct stat stat_system;
|
|
/* stat of "/var/log/messages" */
|
|
struct stat stat_messages;
|
|
#if defined(HAVE_USTAT)
|
|
struct ustat ustat_dot; /* usage stat of "." */
|
|
struct ustat ustat_dotdot; /* usage stat of ".." */
|
|
struct ustat ustat_tmp; /* usage stat of "/tmp" */
|
|
struct ustat ustat_root; /* usage stat of "/" */
|
|
struct ustat ustat_tty; /* usage stat of "/dev/tty" */
|
|
struct ustat ustat_console; /* usage stat of "/dev/console" */
|
|
struct ustat ustat_stdin; /* usage stat of stdin */
|
|
struct ustat ustat_stdout; /* usage stat of stdout */
|
|
struct ustat ustat_stderr; /* usage stat of stderr */
|
|
struct ustat ustat_zero; /* usage stat of "/dev/zero" */
|
|
struct ustat ustat_null; /* usage stat of "/dev/null" */
|
|
struct ustat ustat_sh; /* usage stat of "/bin/sh" */
|
|
struct ustat ustat_ls; /* usage stat of "/bin/ls" */
|
|
/* usage stat of "/var/log/system.log" */
|
|
struct ustat ustat_system;
|
|
/* usage stat of "/var/log/messages" */
|
|
struct ustat ustat_messages;
|
|
#endif
|
|
#if defined(HAVE_STATFS)
|
|
struct statfs statfs_dot; /* filesystem stat of "." */
|
|
struct statfs statfs_dotdot; /* filesystem stat of ".." */
|
|
struct statfs statfs_tmp; /* filesystem stat of "/tmp" */
|
|
struct statfs statfs_root; /* filesystem stat of "/" */
|
|
struct statfs statfs_tty; /* filesystem stat of "/dev/tty" */
|
|
struct statfs statfs_console; /* filesystem stat of "/dev/console" */
|
|
struct statfs statfs_stdin; /* filesystem stat of stdin */
|
|
struct statfs statfs_stdout; /* filesystem stat of stdout */
|
|
struct statfs statfs_stderr; /* filesystem stat of stderr */
|
|
struct statfs statfs_zero; /* filesystem stat of "/dev/zero" */
|
|
struct statfs statfs_null; /* filesystem stat of "/dev/null" */
|
|
struct statfs statfs_sh; /* filesystem stat of "/bin/sh" */
|
|
struct statfs statfs_ls; /* filesystem stat of "/bin/ls" */
|
|
/* filesystem stat of "/var/log/system.log" */
|
|
struct statfs statfs_system;
|
|
/* filesystem stat of "/var/log/messages" */
|
|
struct statfs statfs_messages;
|
|
#endif
|
|
#if defined(HAVE_GETSID)
|
|
pid_t getsid; /* session ID */
|
|
#endif
|
|
#if defined(HAVE_GETPGID)
|
|
pid_t getpgid; /* process group ID */
|
|
#endif
|
|
#if defined(HAVE_GETRUSAGE)
|
|
struct rusage rusage; /* resource utilization */
|
|
struct rusage rusage_child; /* resource utilization of children */
|
|
#endif
|
|
#if defined(HAVE_SYS_TIME_H)
|
|
struct timeval tp2; /* time of day again */
|
|
struct tms times; /* process times */
|
|
struct timeval times_dot[2]; /* access & mod files of "." */
|
|
struct timeval times_dotdot[2]; /* access & mod files of ".." */
|
|
struct timeval times_tmp[2]; /* access & mod files of "/tmp" */
|
|
struct timeval times_root[2]; /* access & mod files of "/" */
|
|
struct timeval times_tty[2]; /* access & mod files of "/dev/tty" */
|
|
/* access & mod files of "/dev/console" */
|
|
struct timeval times_console[2];
|
|
struct timeval times_stdin[2]; /* access & mod files of "/dev/stdin" */
|
|
/* access & mod files of "/dev/stdout" */
|
|
struct timeval times_stdout[2];
|
|
/* access & mod files of "/dev/stderr" */
|
|
struct timeval times_stderr[2];
|
|
struct timeval times_zero[2]; /* access & mod files of "/dev/zero" */
|
|
struct timeval times_null[2]; /* access & mod files of "/dev/null" */
|
|
struct timeval times_sh[2]; /* access & mod files of "/bin/sh" */
|
|
struct timeval times_ls[2]; /* access & mod files of "/bin/ls" */
|
|
/* access & mod files of "/var/log/system.log" */
|
|
struct timeval times_system[2];
|
|
/* access & mod files of "/var/log/messages" */
|
|
struct timeval times_messages[2];
|
|
#endif
|
|
time_t time; /* local time */
|
|
size_t size; /* size of this data structure */
|
|
hash64 prev_hash64_copy; /* copy if the previous hash value */
|
|
FULL call_count_copy; /* call count of this funcation */
|
|
jmp_buf env; /* setjmp() context */
|
|
#if defined(HAVE_ENVIRON)
|
|
char **environ_copy; /* copy of extern char **environ */
|
|
#endif /* HAVE_ENVIRON */
|
|
char *sdata_p; /* address of this structure */
|
|
} sdata;
|
|
|
|
/**/
|
|
|
|
#if defined(HAVE_STDLIB_H)
|
|
unsigned long tmp; /* temp holder of 31-bit random() */
|
|
unsigned past_hash; /* prev hash or xor-folded prev hash */
|
|
long random_before[RANDOM_CNT]; /* random() pre initstate() */
|
|
char *initstate_ret; /* return from initstate() call */
|
|
char initstate_tbl[INITSTATE_SIZE]; /* initstate pool */
|
|
long random_after[RANDOM_CNT]; /* random() post initstate() */
|
|
char *setstate_ret; /* return from setstate() call */
|
|
int j;
|
|
#endif /* HAVE_STDLIB_H */
|
|
#if defined(HAVE_ENVIRON)
|
|
int i;
|
|
size_t envlen; /* length of an environment variable */
|
|
#endif
|
|
hash64 hash_val; /* fnv64 hash of sdata */
|
|
ZVALUE hash; /* hash_val as a ZVALUE */
|
|
NUMBER *ret; /* return seed as a NUMBER */
|
|
|
|
/*
|
|
* initialize the Fowler/Noll/Vo-1 64 bit hash
|
|
*/
|
|
hash_val = initial_private_hash64();
|
|
|
|
/*
|
|
* pick up process/system information
|
|
*
|
|
* NOTE:
|
|
* We do NOT care (that much) if these calls fail. We only
|
|
* need to hash any results that might be store in the sdata structure.
|
|
*/
|
|
memset(&sdata, 0, sizeof(sdata)); /* zeroize sdata */
|
|
#if defined(HAVE_GETTIME)
|
|
# if defined(CLOCK_REALTIME)
|
|
(void) clock_gettime(CLOCK_REALTIME, &sdata.realtime);
|
|
# endif
|
|
#endif
|
|
#if defined(HAVE_GETPRID)
|
|
sdata.getprid = getprid();
|
|
#endif
|
|
#if defined(HAVE_URANDOM)
|
|
sdata.urandom_fd = open(DEV_URANDOM, O_NONBLOCK|O_RDONLY);
|
|
if (sdata.urandom_fd >= 0) {
|
|
sdata.urandom_ret = read(sdata.urandom_fd,
|
|
&sdata.urandom_pool, DEV_URANDOM_POOL);
|
|
close(sdata.urandom_fd);
|
|
} else {
|
|
memset(&sdata.urandom_pool, EOF, DEV_URANDOM_POOL);
|
|
sdata.urandom_ret = EOF;
|
|
}
|
|
#endif /* HAVE_URANDOM */
|
|
#if defined(HAVE_SYS_TIME_H)
|
|
(void) gettimeofday(&sdata.tp, NULL);
|
|
#endif
|
|
sdata.getpid = getpid();
|
|
#if !defined(_WIN32) && !defined(_WIN64)
|
|
sdata.getppid = getppid();
|
|
#endif
|
|
#if defined(HAVE_UID_T)
|
|
sdata.getuid = getuid();
|
|
sdata.geteuid = geteuid();
|
|
sdata.getgid = getgid();
|
|
sdata.getegid = getegid();
|
|
#endif
|
|
(void) stat(".", &sdata.stat_dot);
|
|
(void) stat("..", &sdata.stat_dotdot);
|
|
(void) stat("/tmp", &sdata.stat_tmp);
|
|
(void) stat("/", &sdata.stat_root);
|
|
(void) stat("/dev/tty", &sdata.stat_tty);
|
|
(void) stat("/dev/console", &sdata.stat_console);
|
|
(void) fstat(0, &sdata.fstat_stdin);
|
|
(void) fstat(1, &sdata.fstat_stdout);
|
|
(void) fstat(2, &sdata.fstat_stderr);
|
|
(void) stat("/dev/zero", &sdata.stat_zero);
|
|
(void) stat("/dev/null", &sdata.stat_null);
|
|
(void) stat("/bin/sh", &sdata.stat_sh);
|
|
(void) stat("/bin/ls", &sdata.stat_ls);
|
|
(void) stat("/var/log/system.log", &sdata.stat_system);
|
|
(void) stat("/var/log/messages", &sdata.stat_messages);
|
|
#if defined(HAVE_USTAT)
|
|
(void) ustat(sdata.stat_dotdot.st_dev, &sdata.ustat_dotdot);
|
|
(void) ustat(sdata.stat_dot.st_dev, &sdata.ustat_dot);
|
|
(void) ustat(sdata.stat_tmp.st_dev, &sdata.ustat_tmp);
|
|
(void) ustat(sdata.stat_root.st_dev, &sdata.ustat_root);
|
|
(void) ustat(sdata.stat_tty.st_dev, &sdata.ustat_tty);
|
|
(void) ustat(sdata.stat_console.st_dev, &sdata.ustat_console);
|
|
(void) ustat(sdata.fstat_stdin.st_dev, &sdata.ustat_stdin);
|
|
(void) ustat(sdata.fstat_stdout.st_dev, &sdata.ustat_stdout);
|
|
(void) ustat(sdata.fstat_stderr.st_dev, &sdata.ustat_stderr);
|
|
(void) ustat(sdata.stat_zero.st_dev, &sdata.ustat_zero);
|
|
(void) ustat(sdata.stat_null.st_dev, &sdata.ustat_null);
|
|
(void) ustat(sdata.stat_sh.st_dev, &sdata.ustat_sh);
|
|
(void) ustat(sdata.stat_ls.st_dev, &sdata.ustat_ls);
|
|
(void) ustat(sdata.stat_system.st_dev, &sdata.ustat_system);
|
|
(void) ustat(sdata.stat_messages.st_dev, &sdata.ustat_messages);
|
|
#endif
|
|
#if defined(HAVE_STATFS)
|
|
(void) statfs("..", &sdata.statfs_dot);
|
|
(void) statfs(".", &sdata.statfs_dotdot);
|
|
(void) statfs("/tmp", &sdata.statfs_tmp);
|
|
(void) statfs("/", &sdata.statfs_root);
|
|
(void) statfs("/dev/tty", &sdata.statfs_tty);
|
|
(void) statfs("/dev/console", &sdata.statfs_console);
|
|
(void) statfs(".dev/stdin", &sdata.statfs_stdin);
|
|
(void) statfs("/dev/stdout", &sdata.statfs_stdout);
|
|
(void) statfs("/dev/stderr", &sdata.statfs_stderr);
|
|
(void) statfs("/dev/zero", &sdata.statfs_zero);
|
|
(void) statfs("/dev/null", &sdata.statfs_null);
|
|
(void) statfs("/bin/sh", &sdata.statfs_sh);
|
|
(void) statfs("/dev/ls", &sdata.statfs_ls);
|
|
(void) statfs("/var/log/system.log", &sdata.statfs_system);
|
|
(void) statfs("/var/log/messages", &sdata.statfs_messages);
|
|
#endif
|
|
#if defined(HAVE_GETSID)
|
|
sdata.getsid = getsid((pid_t)0);
|
|
#endif
|
|
#if defined(HAVE_GETPGID)
|
|
sdata.getpgid = getpgid((pid_t)0);
|
|
#endif
|
|
#if defined(HAVE_GETRUSAGE)
|
|
(void) getrusage(RUSAGE_SELF, &sdata.rusage);
|
|
(void) getrusage(RUSAGE_CHILDREN, &sdata.rusage_child);
|
|
#endif
|
|
#if defined(HAVE_SYS_TIME_H)
|
|
(void) gettimeofday(&sdata.tp2, NULL);
|
|
(void) times(&sdata.times);
|
|
(void) utimes(".", sdata.times_dot);
|
|
(void) utimes("..", sdata.times_dotdot);
|
|
(void) utimes("/tmp", sdata.times_tmp);
|
|
(void) utimes("/", sdata.times_root);
|
|
(void) utimes("/dev/tty", sdata.times_tty);
|
|
(void) utimes("/dev/console", sdata.times_console);
|
|
(void) utimes("/dev/stdin", sdata.times_stdin);
|
|
(void) utimes("/dev/stdout", sdata.times_stdout);
|
|
(void) utimes("/dev/stderr", sdata.times_stderr);
|
|
(void) utimes("/dev/zero", sdata.times_zero);
|
|
(void) utimes("/dev/null", sdata.times_null);
|
|
(void) utimes("/bin/sh", sdata.times_sh);
|
|
(void) utimes("/bin/ls", sdata.times_ls);
|
|
(void) utimes("/var/log/system.log", sdata.times_system);
|
|
(void) utimes("/var/log/messages", sdata.times_messages);
|
|
#endif
|
|
sdata.time = time(NULL);
|
|
sdata.size = sizeof(sdata);
|
|
sdata.prev_hash64_copy = prev_hash64; /* load previous hash */
|
|
sdata.call_count_copy = ++call_count; /* update call count */
|
|
#if defined(HAVE_ENVIRON)
|
|
sdata.environ_copy = environ;
|
|
#endif /* HAVE_ENVIRON */
|
|
sdata.sdata_p = (char *)&sdata;
|
|
|
|
/*
|
|
* seed the generator with the above sdata
|
|
*/
|
|
hash_val = private_hash64_buf(hash_val, (char *)&sdata, sizeof(sdata));
|
|
|
|
#if defined(HAVE_ENVIRON)
|
|
/*
|
|
* mix in each envinment variable
|
|
*/
|
|
for (i=0; environ[i] != NULL; ++i) {
|
|
|
|
/* obtain length of this next environment variable string */
|
|
envlen = strlen(environ[i]);
|
|
|
|
/* hash any non-zero length environment variable string */
|
|
if (envlen > 0) {
|
|
hash_val = private_hash64_buf(hash_val, environ[i], envlen);
|
|
}
|
|
}
|
|
#endif /* HAVE_ENVIRON */
|
|
|
|
#if defined(HAVE_STDLIB_H)
|
|
/*
|
|
* mix in data from 31-bit random() and friends
|
|
*
|
|
* While random() returns only 31 bit values, seeded by 32 bits,
|
|
* we use it twice: once seeded by time of day, count, prev hash
|
|
* and once seeded by FNV hash of sdata. Both seeds are somewhat
|
|
* independent of each other, so we get the effect of 64 bits of seed.
|
|
*
|
|
* The 2nd seede uses the larger 256 byte state table to help
|
|
* differentiate the random() returns from the 1st seed.
|
|
*
|
|
* Because random() returns a 31-bit number, we call it 32 times
|
|
* and circular shift around the results within a 32 bit word
|
|
* to mix where the missing bit, low order and high order bits land.
|
|
*/
|
|
|
|
/* form the xor-fold of the previous hash */
|
|
#if defined(HAVE_B64)
|
|
past_hash = (unsigned)(((prev_hash64 >> 32)&0xffffffff) ^
|
|
(prev_hash64 & 0xffffffff));
|
|
#else /* HAVE_B64 */
|
|
pash_hash = (unsigned)(prev_hash64.w32[0] ^ prev_hash64.w32[1]);
|
|
#endif /* HAVE_B64 */
|
|
|
|
/* classic 31-bit random seeded with time of day, count, prev hash */
|
|
srandom((unsigned)(sdata.time) ^ (unsigned)call_count ^ past_hash);
|
|
for (j=0; j < RANDOM_CNT; ++j) {
|
|
tmp = random(); /* 31-bit value */
|
|
/* we 32-bit circular shift to spread 31-bit returns around */
|
|
random_before[j] = (tmp << j) | (tmp >> (RANDOM_CNT-j));
|
|
}
|
|
|
|
/* init with large random state with 32-bit xor fold FNV hash of sdata */
|
|
#if defined(HAVE_B64)
|
|
initstate_ret = initstate((unsigned)(((hash_val >> 32)&0xffffffff) ^
|
|
(hash_val & 0xffffffff)),
|
|
initstate_tbl,
|
|
INITSTATE_SIZE);
|
|
#else /* HAVE_B64 */
|
|
initstate_ret = initstate((unsigned)(hash_val.w32[0] ^ hash_val.w32[1]),
|
|
initstate_tbl,
|
|
INITSTATE_SIZE);
|
|
#endif /* HAVE_B64 */
|
|
|
|
/* use 31-bit random some more with the new random state */
|
|
for (j=0; j < RANDOM_CNT; ++j) {
|
|
tmp = random(); /* 31-bit value */
|
|
/* we 32-bit circular shift to spread 31-bit returns around */
|
|
random_after[j] = (tmp << j) | (tmp >> (RANDOM_CNT-j));
|
|
}
|
|
|
|
/* restore standard table sized previous state */
|
|
setstate_ret = setstate(initstate_ret);
|
|
|
|
/*
|
|
* hash all the data from random() and friends
|
|
*/
|
|
hash_val = private_hash64_buf(hash_val,
|
|
(char *)random_before,
|
|
sizeof(random_before));
|
|
hash_val = private_hash64_buf(hash_val,
|
|
(char *)initstate_ret,
|
|
sizeof(initstate_ret));
|
|
hash_val = private_hash64_buf(hash_val,
|
|
(char *)initstate_tbl,
|
|
sizeof(initstate_tbl));
|
|
hash_val = private_hash64_buf(hash_val,
|
|
(char *)random_after,
|
|
sizeof(random_after));
|
|
hash_val = private_hash64_buf(hash_val,
|
|
(char *)setstate_ret,
|
|
sizeof(setstate_ret));
|
|
#endif /* HAVE_STDLIB_H */
|
|
|
|
#if defined(HAVE_ARC4RANDOM)
|
|
/*
|
|
* hash from a cryptographic pseudo-random number generator
|
|
*/
|
|
arc4random_buf(arc4_buf, ARC4_BUFLEN);
|
|
hash_val = private_hash64_buf(hash_val,
|
|
(char *)arc4_buf,
|
|
ARC4_BUFLEN);
|
|
#endif /* HAVE_ARC4RANDOM */
|
|
|
|
/*
|
|
* load the hash data into the ZVALUE
|
|
*
|
|
* We do not care about byte-order, nor Endian issues, we just
|
|
* want to load in data. We round up to the next HALF in size
|
|
* just in case hash_val is not a HALF multiple in length.
|
|
*/
|
|
hash.len = (sizeof(hash_val)+sizeof(HALF)-1) / sizeof(HALF);
|
|
hash.v = alloc(hash.len);
|
|
memset(hash.v, 0, hash.len*sizeof(HALF)); /* paranoia */
|
|
hash.sign = 0;
|
|
memcpy((void *)hash.v, (void *)&hash_val, sizeof(hash_val));
|
|
|
|
/*
|
|
* Force the hash as ZVALUE to be at most, 64 bits long.
|
|
* It is almost certainly the case that the hash as ZVALUE
|
|
* is at most 64 bits in length: this code guarantees it.
|
|
*
|
|
* BTW: One can safely assume that 64 is an integer multiple of BASEB:
|
|
* likely 4, 2, or 1 times BASEB.
|
|
*/
|
|
if (hash.len > 64/BASEB) {
|
|
hash.len = 64/BASEB;
|
|
}
|
|
ztrim(&hash);
|
|
|
|
/*
|
|
* save hash value for next call
|
|
*/
|
|
prev_hash64 = hash_val;
|
|
|
|
/*
|
|
* return a number
|
|
*/
|
|
ret = qalloc();
|
|
ret->num = hash;
|
|
return ret;
|
|
}
|