libbsd: Branch 'master' - 13 commits

Guillem Jover guillem at kemper.freedesktop.org
Mon Nov 30 15:04:57 PST 2015


 COPYING                  |   23 +
 Makefile.am              |    2 
 configure.ac             |   11 
 man/Makefile.am          |    2 
 man/arc4random.3         |  100 ++++----
 man/funopen.3            |  191 ----------------
 man/funopen.3bsd         |  191 ++++++++++++++++
 src/Makefile.am          |   28 ++
 src/arc4random.c         |  356 +++++++++++-------------------
 src/arc4random.h         |   29 ++
 src/arc4random_bsd.h     |   86 +++++++
 src/arc4random_linux.h   |   86 +++++++
 src/arc4random_openbsd.h |   61 +++++
 src/arc4random_uniform.c |   57 ++++
 src/arc4random_unix.h    |   80 ++++++
 src/chacha_private.h     |  222 +++++++++++++++++++
 src/getentropy.c         |   43 +++
 src/getentropy_aix.c     |  425 ++++++++++++++++++++++++++++++++++++
 src/getentropy_bsd.c     |   62 +++++
 src/getentropy_hpux.c    |  419 ++++++++++++++++++++++++++++++++++++
 src/getentropy_linux.c   |  547 +++++++++++++++++++++++++++++++++++++++++++++++
 src/getentropy_osx.c     |  429 ++++++++++++++++++++++++++++++++++++
 src/getentropy_solaris.c |  445 ++++++++++++++++++++++++++++++++++++++
 src/hash/sha512.h        |   51 ++++
 src/hash/sha512c.c       |  320 +++++++++++++++++++++++++++
 src/local-elf.h          |    6 
 test/.gitignore          |    2 
 test/Makefile.am         |   19 +
 test/arc4random.c        |  105 +++++++++
 test/proctitle.c         |    4 
 test/strmode.c           |   69 +++++
 31 files changed, 3997 insertions(+), 474 deletions(-)

New commits:
commit 2b030da0165ac507280a5355ba8a28c2013bf9b6
Author: Guillem Jover <guillem at hadrons.org>
Date:   Mon Nov 30 03:59:42 2015 +0100

    Release libbsd 0.8.0

diff --git a/configure.ac b/configure.ac
index f194fa9..cbdd602 100644
--- a/configure.ac
+++ b/configure.ac
@@ -12,7 +12,7 @@ m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])],
                             [AC_SUBST([AM_DEFAULT_VERBOSITY], [1])])
 
 LIBBSD_ABI_MAJOR=0
-LIBBSD_ABI_MINOR=7
+LIBBSD_ABI_MINOR=8
 LIBBSD_ABI_PATCH=0
 
 LIBBSD_ABI="$LIBBSD_ABI_MAJOR:$LIBBSD_ABI_MINOR:$LIBBSD_ABI_PATCH"
commit 330e211142e9a2ad5436ab38e3e4a8596f49cf1a
Author: Guillem Jover <guillem at hadrons.org>
Date:   Mon Nov 30 03:53:21 2015 +0100

    Update license and copyright information

diff --git a/COPYING b/COPYING
index 51a1b27..4f79ecd 100644
--- a/COPYING
+++ b/COPYING
@@ -66,7 +66,7 @@ for man/arc4random.3, man/tree.3 and man/getprogname.3.
 The rest of the licenses apply to code and/or man pages.
 
 
-    Copyright © 2004-2006, 2008-2013 Guillem Jover <guillem at hadrons.org>
+    Copyright © 2004-2006, 2008-2015 Guillem Jover <guillem at hadrons.org>
     Copyright © 2005 Hector Garcia Alvarez
     Copyright © 2005 Aurelien Jarno
     Copyright © 2006 Robert Millan
@@ -263,6 +263,9 @@ The rest of the licenses apply to code and/or man pages.
     Copyright © 2005 Pawel Jakub Dawidek <pjd at FreeBSD.org>
     All rights reserved.
 
+    Copyright © 2005 Colin Percival
+    All rights reserved.
+
     Copyright © 2007 Eric Anderson <anderson at FreeBSD.org>
     Copyright © 2007 Pawel Jakub Dawidek <pjd at FreeBSD.org>
     All rights reserved.
@@ -352,13 +355,22 @@ The rest of the licenses apply to code and/or man pages.
 
     --
 
-    Copyright © 1998, 2000 Todd C. Miller <Todd.Miller at courtesan.com>
-    Copyright © 2004 Ted Unangst
-
     Copyright © 2004 Ted Unangst and Todd Miller
     All rights reserved.
 
+    Copyright © 1996 David Mazieres <dm at uun.org>
+    Copyright © 1998, 2000, 2004-2005, 2010, 2012-2014
+        Todd C. Miller <Todd.Miller at courtesan.com>
+    Copyright © 2004 Ted Unangst
+    Copyright © 2008 Damien Miller <djm at openbsd.org>
     Copyright © 2008 Otto Moerbeek <otto at drijf.net>
+    Copyright © 2013 Markus Friedl <markus at openbsd.org>
+    Copyright © 2014 Bob Beck <beck at obtuse.com>
+    Copyright © 2014 Brent Cook <bcook at openbsd.org>
+    Copyright © 2014 Pawel Jakub Dawidek <pjd at FreeBSD.org>
+    Copyright © 2014 Theo de Raadt <deraadt at openbsd.org>
+    Copyright © 2015 Michael Felt <aixtools at gmail.com>
+    Copyright © 2015 Guillem Jover <guillem at hadrons.org>
 
     Permission to use, copy, modify, and distribute this software for any
     purpose with or without fee is hereby granted, provided that the above
@@ -374,8 +386,7 @@ The rest of the licenses apply to code and/or man pages.
 
     --
 
-    Copyright © 2000-2002, 2004-2005, 2007, 2010
-        Todd C. Miller <Todd.Miller at courtesan.com>
+    Copyright © 2000-2002, 2007 Todd C. Miller <Todd.Miller at courtesan.com>
 
     Permission to use, copy, modify, and distribute this software for any
     purpose with or without fee is hereby granted, provided that the above
commit 874a0e51d3a38596006b3ef7396e62194f467abf
Author: Guillem Jover <guillem at hadrons.org>
Date:   Wed Sep 23 19:39:47 2015 +0200

    Update arc4random module from OpenBSD and LibreSSL
    
    Rework arc4random_stir() and arc4random_addrandom() code over the new
    internal API, and documentation in the man page. Adapt the code to the
    local build system.
    
    Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=85827

diff --git a/configure.ac b/configure.ac
index 0e797ce..f194fa9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -129,7 +129,7 @@ AC_LINK_IFELSE(
 	[AC_MSG_RESULT([no])])
 
 AC_CHECK_FUNCS([clearenv dirfd fopencookie __fpurge \
-                getentropy getexecname getline \
+                getauxval getentropy getexecname getline \
                 pstat_getproc sysconf])
 AM_CONDITIONAL(HAVE_GETENTROPY, [test "x$ac_cv_func_getentropy" = "xtrue"])
 
diff --git a/man/arc4random.3 b/man/arc4random.3
index 90264ce..9602ad9 100644
--- a/man/arc4random.3
+++ b/man/arc4random.3
@@ -1,4 +1,5 @@
-.\" $OpenBSD: arc4random.3,v 1.2 1997/04/27 22:40:25 angelos Exp $
+.\" $OpenBSD: arc4random.3,v 1.34 2014/07/19 16:11:16 naddy Exp $
+.\"
 .\" Copyright 1997 Niels Provos <provos at physnet.uni-hamburg.de>
 .\" All rights reserved.
 .\"
@@ -28,9 +29,8 @@
 .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
 .\" Manual page, using -mandoc macros
-.\" $FreeBSD$
 .\"
-.Dd April 15, 1997
+.Dd $Mdocdate: July 19 2014 $
 .Dt ARC4RANDOM 3
 .Os
 .Sh NAME
@@ -56,45 +56,59 @@
 .Ft void
 .Fn arc4random_addrandom "unsigned char *dat" "int datlen"
 .Sh DESCRIPTION
+This family of functions provides higher quality data than those
+described in
+.Xr rand 3 ,
+.Xr random 3 ,
+and
+.Xr rand48 3 .
+.Pp
+Use of these functions is encouraged for almost all random number
+consumption because the other interfaces are deficient in either
+quality, portability, standardization, or availability.
+These functions can be called in almost all coding environments,
+including
+.Xr pthreads 3
+and
+.Xr chroot 2 .
+.Pp
+High quality 32-bit pseudo-random numbers are generated very quickly.
+On each call, a cryptographic pseudo-random number generator is used
+to generate a new result.
+One data pool is used for all consumers in a process, so that consumption
+under program flow can act as additional stirring.
+The subsystem is re-seeded from the kernel random number subsystem using
+.Xr getentropy 2
+on a regular basis, and also upon
+.Xr fork 2 .
+.Pp
 The
 .Fn arc4random
-function uses the key stream generator employed by the
-arc4 cipher, which uses 8*8 8 bit S-Boxes.
-The S-Boxes
-can be in about
-.if t 2\u\s71700\s10\d
-.if n (2**1700)
-states.
-The
-.Fn arc4random
-function returns pseudo-random numbers in the range of 0 to
-.if t 2\u\s731\s10\d\(mi1,
-.if n (2**32)\(mi1,
-and therefore has twice the range of
-.Xr rand 3
-and
-.Xr random 3 .
+function returns a single 32-bit value.
 .Pp
+The
 .Fn arc4random_buf
 function fills the region
 .Fa buf
 of length
 .Fa nbytes
-with ARC4-derived random data.
+with random data.
 .Pp
 .Fn arc4random_uniform
-will return a uniformly distributed random number less than
+will return a single 32-bit value, uniformly distributed but less than
 .Fa upper_bound .
-.Fn arc4random_uniform
-is recommended over constructions like
+This is recommended over constructions like
 .Dq Li arc4random() % upper_bound
 as it avoids "modulo bias" when the upper bound is not a power of two.
+In the worst case, this function may consume multiple iterations
+to ensure uniformity; see the source code to understand the problem
+and solution.
 .Pp
 The
 .Fn arc4random_stir
 function reads data from
-.Pa /dev/urandom
-and uses it to permute the S-Boxes via
+.Xr getentropy 2
+and uses it to re-seed the subsystem via
 .Fn arc4random_addrandom .
 .Pp
 There is no need to call
@@ -103,26 +117,22 @@ before using
 .Fn arc4random
 functions family, since
 they automatically initialize themselves.
-.Sh EXAMPLES
-The following produces a drop-in replacement for the traditional
-.Fn rand
-and
-.Fn random
-functions using
-.Fn arc4random :
-.Pp
-.Dl "#define foo4random() (arc4random() % ((unsigned)RAND_MAX + 1))"
+.Sh RETURN VALUES
+These functions are always successful, and no return value is
+reserved to indicate an error.
 .Sh SEE ALSO
 .Xr rand 3 ,
-.Xr random 3 ,
-.Xr srandomdev 3
+.Xr rand48 3 ,
+.Xr random 3
 .Sh HISTORY
-.Pa RC4
-has been designed by RSA Data Security, Inc.
-It was posted anonymously
-to the USENET and was confirmed to be equivalent by several sources who
-had access to the original cipher.
-Since
-.Pa RC4
-used to be a trade secret, the cipher is now referred to as
-.Pa ARC4 .
+These functions first appeared in
+.Ox 2.1 .
+.Pp
+The original version of this random number generator used the
+RC4 (also known as ARC4) algorithm.
+In
+.Ox 5.5
+it was replaced with the ChaCha20 cipher, and it may be replaced
+again in the future as cryptographic techniques advance.
+A good mnemonic is
+.Dq A Replacement Call for Random .
diff --git a/src/Makefile.am b/src/Makefile.am
index bd490fd..cc2b784 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -56,7 +56,14 @@ libbsd_la_LDFLAGS = \
 	-version-number $(LIBBSD_ABI)
 libbsd_la_SOURCES = \
 	arc4random.c \
+	arc4random.h \
+	arc4random_bsd.h \
+	arc4random_linux.h \
+	arc4random_unix.h \
+	arc4random_openbsd.h \
+	arc4random_uniform.c \
 	bsd_getopt.c \
+	chacha_private.h \
 	closefrom.c \
 	dehumanize_number.c \
 	err.c \
diff --git a/src/arc4random.c b/src/arc4random.c
index fc8db6d..fb16757 100644
--- a/src/arc4random.c
+++ b/src/arc4random.c
@@ -1,6 +1,11 @@
+/*	$OpenBSD: arc4random.c,v 1.53 2015/09/10 18:53:50 bcook Exp $	*/
+
 /*
  * Copyright (c) 1996, David Mazieres <dm at uun.org>
  * Copyright (c) 2008, Damien Miller <djm at openbsd.org>
+ * Copyright (c) 2013, Markus Friedl <markus at openbsd.org>
+ * Copyright (c) 2014, Theo de Raadt <deraadt at openbsd.org>
+ * Copyright (c) 2015, Guillem Jover <guillem at hadrons.org>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -16,281 +21,192 @@
  */
 
 /*
- * Arc4 random number generator for OpenBSD.
- *
- * This code is derived from section 17.1 of Applied Cryptography,
- * second edition, which describes a stream cipher allegedly
- * compatible with RSA Labs "RC4" cipher (the actual description of
- * which is a trade secret).  The same algorithm is used as a stream
- * cipher called "arcfour" in Tatu Ylonen's ssh package.
- *
- * Here the stream cipher has been modified always to include the time
- * when initializing the state.  That makes it impossible to
- * regenerate the same random sequence twice, so this can't be used
- * for encryption, but will generate good random numbers.
- *
- * RC4 is a registered trademark of RSA Laboratories.
+ * ChaCha based random number generator for OpenBSD.
  */
 
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <sys/types.h>
-#include <sys/time.h>
-#include <stdlib.h>
 #include <fcntl.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
 #include <unistd.h>
-#include <pthread.h>
+#include <sys/types.h>
+#include <sys/time.h>
 
-struct arc4_stream {
-	uint8_t i;
-	uint8_t j;
-	uint8_t s[256];
-};
+#define KEYSTREAM_ONLY
+#include "chacha_private.h"
 
-#define	RANDOMDEV	"/dev/urandom"
-#define KEYSIZE		128
+#define minimum(a, b) ((a) < (b) ? (a) : (b))
 
-#ifdef __REENTRANT
-static pthread_mutex_t arc4random_mtx = PTHREAD_MUTEX_INITIALIZER;
-#define	THREAD_LOCK()	pthread_mutex_lock(&arc4random_mtx)
-#define	THREAD_UNLOCK()	pthread_mutex_unlock(&arc4random_mtx)
-#else
-#define	THREAD_LOCK()
-#define	THREAD_UNLOCK()
-#endif
+#if defined(__GNUC__) || defined(_MSC_VER)
+#define inline __inline
+#else				/* __GNUC__ || _MSC_VER */
+#define inline
+#endif				/* !__GNUC__ && !_MSC_VER */
+
+#define KEYSZ	32
+#define IVSZ	8
+#define BLOCKSZ	64
+#define RSBUFSZ	(16*BLOCKSZ)
+
+/* Marked MAP_INHERIT_ZERO, so zero'd out in fork children. */
+static struct _rs {
+	size_t		rs_have;	/* valid bytes at end of rs_buf */
+	size_t		rs_count;	/* bytes till reseed */
+} *rs;
 
-static struct arc4_stream rs;
-static int rs_initialized;
-static int rs_stired;
-static int arc4_count;
+/* Maybe be preserved in fork children, if _rs_allocate() decides. */
+static struct _rsx {
+	chacha_ctx	rs_chacha;	/* chacha context for random keystream */
+	u_char		rs_buf[RSBUFSZ];	/* keystream blocks */
+} *rsx;
 
-static inline uint8_t arc4_getbyte(void);
-static void arc4_stir(void);
+static inline int _rs_allocate(struct _rs **, struct _rsx **);
+static inline void _rs_forkdetect(void);
+#include "arc4random.h"
 
 static inline void
-arc4_init(void)
+_rs_init(u_char *buf, size_t n)
 {
-	int     n;
+	if (n < KEYSZ + IVSZ)
+		return;
 
-	for (n = 0; n < 256; n++)
-		rs.s[n] = n;
-	rs.i = 0;
-	rs.j = 0;
+	if (rs == NULL) {
+		if (_rs_allocate(&rs, &rsx) == -1)
+			abort();
+	}
+
+	chacha_keysetup(&rsx->rs_chacha, buf, KEYSZ * 8, 0);
+	chacha_ivsetup(&rsx->rs_chacha, buf + KEYSZ);
 }
 
 static inline void
-arc4_addrandom(u_char *dat, int datlen)
+_rs_rekey(u_char *dat, size_t datlen)
 {
-	int     n;
-	uint8_t si;
-
-	rs.i--;
-	for (n = 0; n < 256; n++) {
-		rs.i = (rs.i + 1);
-		si = rs.s[rs.i];
-		rs.j = (rs.j + si + dat[n % datlen]);
-		rs.s[rs.i] = rs.s[rs.j];
-		rs.s[rs.j] = si;
+#ifndef KEYSTREAM_ONLY
+	memset(rsx->rs_buf, 0, sizeof(rsx->rs_buf));
+#endif
+	/* fill rs_buf with the keystream */
+	chacha_encrypt_bytes(&rsx->rs_chacha, rsx->rs_buf,
+	    rsx->rs_buf, sizeof(rsx->rs_buf));
+	/* mix in optional user provided data */
+	if (dat) {
+		size_t i, m;
+
+		m = minimum(datlen, KEYSZ + IVSZ);
+		for (i = 0; i < m; i++)
+			rsx->rs_buf[i] ^= dat[i];
 	}
-	rs.j = rs.i;
+	/* immediately reinit for backtracking resistance */
+	_rs_init(rsx->rs_buf, KEYSZ + IVSZ);
+	memset(rsx->rs_buf, 0, KEYSZ + IVSZ);
+	rs->rs_have = sizeof(rsx->rs_buf) - KEYSZ - IVSZ;
 }
 
 static void
-arc4_stir(void)
+_rs_stir(void)
 {
-	int done, fd, n;
-	struct {
-		struct timeval	tv;
-		pid_t 		pid;
-		uint8_t		rnd[KEYSIZE];
-	} rdat;
-
-	fd = open(RANDOMDEV, O_RDONLY, 0);
-	done = 0;
-	if (fd >= 0) {
-		if (read(fd, &rdat, KEYSIZE) == KEYSIZE)
-			done = 1;
-		(void)close(fd);
-	} 
-	if (!done) {
-		(void)gettimeofday(&rdat.tv, NULL);
-		rdat.pid = getpid();
-		/* We'll just take whatever was on the stack too... */
-	}
-
-	arc4_addrandom((u_char *)&rdat, KEYSIZE);
+	u_char rnd[KEYSZ + IVSZ];
 
-	/*
-	 * Throw away the first N bytes of output, as suggested in the
-	 * paper "Weaknesses in the Key Scheduling Algorithm of RC4"
-	 * by Fluher, Mantin, and Shamir.  N=1024 is based on
-	 * suggestions in the paper "(Not So) Random Shuffles of RC4"
-	 * by Ilya Mironov.
-	 */
-	for (n = 0; n < 1024; n++)
-		(void) arc4_getbyte();
-	arc4_count = 1600000;
-}
+	if (getentropy(rnd, sizeof rnd) == -1)
+		_getentropy_fail();
 
-static inline uint8_t
-arc4_getbyte(void)
-{
-	uint8_t si, sj;
+	if (!rs)
+		_rs_init(rnd, sizeof(rnd));
+	else
+		_rs_rekey(rnd, sizeof(rnd));
+	explicit_bzero(rnd, sizeof(rnd));	/* discard source seed */
 
-	rs.i = (rs.i + 1);
-	si = rs.s[rs.i];
-	rs.j = (rs.j + si);
-	sj = rs.s[rs.j];
-	rs.s[rs.i] = sj;
-	rs.s[rs.j] = si;
+	/* invalidate rs_buf */
+	rs->rs_have = 0;
+	memset(rsx->rs_buf, 0, sizeof(rsx->rs_buf));
 
-	return (rs.s[(si + sj) & 0xff]);
+	rs->rs_count = 1600000;
 }
 
-static inline uint32_t
-arc4_getword(void)
+static inline void
+_rs_stir_if_needed(size_t len)
 {
-	uint32_t val;
-
-	val = arc4_getbyte() << 24;
-	val |= arc4_getbyte() << 16;
-	val |= arc4_getbyte() << 8;
-	val |= arc4_getbyte();
-
-	return (val);
+	_rs_forkdetect();
+	if (!rs || rs->rs_count <= len)
+		_rs_stir();
+	if (rs->rs_count <= len)
+		rs->rs_count = 0;
+	else
+		rs->rs_count -= len;
 }
 
-static void
-arc4_check_init(void)
+static inline void
+_rs_random_buf(void *_buf, size_t n)
 {
-	if (!rs_initialized) {
-		arc4_init();
-		rs_initialized = 1;
+	u_char *buf = (u_char *)_buf;
+	u_char *keystream;
+	size_t m;
+
+	_rs_stir_if_needed(n);
+	while (n > 0) {
+		if (rs->rs_have > 0) {
+			m = minimum(n, rs->rs_have);
+			keystream = rsx->rs_buf + sizeof(rsx->rs_buf)
+			    - rs->rs_have;
+			memcpy(buf, keystream, m);
+			memset(keystream, 0, m);
+			buf += m;
+			n -= m;
+			rs->rs_have -= m;
+		}
+		if (rs->rs_have == 0)
+			_rs_rekey(NULL, 0);
 	}
 }
 
 static inline void
-arc4_check_stir(void)
+_rs_random_u32(uint32_t *val)
 {
-	if (!rs_stired || arc4_count <= 0) {
-		arc4_stir();
-		rs_stired = 1;
-	}
+	u_char *keystream;
+
+	_rs_stir_if_needed(sizeof(*val));
+	if (rs->rs_have < sizeof(*val))
+		_rs_rekey(NULL, 0);
+	keystream = rsx->rs_buf + sizeof(rsx->rs_buf) - rs->rs_have;
+	memcpy(val, keystream, sizeof(*val));
+	memset(keystream, 0, sizeof(*val));
+	rs->rs_have -= sizeof(*val);
 }
 
 void
 arc4random_stir(void)
 {
-	THREAD_LOCK();
-	arc4_check_init();
-	arc4_stir();
-	rs_stired = 1;
-	THREAD_UNLOCK();
+	_ARC4_LOCK();
+	_rs_stir();
+	_ARC4_UNLOCK();
 }
 
 void
 arc4random_addrandom(u_char *dat, int datlen)
 {
-	THREAD_LOCK();
-	arc4_check_init();
-	arc4_check_stir();
-	arc4_addrandom(dat, datlen);
-	THREAD_UNLOCK();
+	_ARC4_LOCK();
+	_rs_stir_if_needed(datlen);
+	_rs_rekey(dat, datlen);
+	_ARC4_UNLOCK();
 }
 
 uint32_t
 arc4random(void)
 {
-	uint32_t rnd;
-
-	THREAD_LOCK();
-	arc4_check_init();
-	arc4_check_stir();
-	rnd = arc4_getword();
-	arc4_count -= 4;
-	THREAD_UNLOCK();
+	uint32_t val;
 
-	return (rnd);
+	_ARC4_LOCK();
+	_rs_random_u32(&val);
+	_ARC4_UNLOCK();
+	return val;
 }
 
 void
-arc4random_buf(void *_buf, size_t n)
-{
-	u_char *buf = (u_char *)_buf;
-
-	THREAD_LOCK();
-	arc4_check_init();
-	while (n--) {
-		arc4_check_stir();
-		buf[n] = arc4_getbyte();
-		arc4_count--;
-	}
-	THREAD_UNLOCK();
-}
-
-/*
- * Calculate a uniformly distributed random number less than upper_bound
- * avoiding "modulo bias".
- *
- * Uniformity is achieved by generating new random numbers until the one
- * returned is outside the range [0, 2**32 % upper_bound).  This
- * guarantees the selected random number will be inside
- * [2**32 % upper_bound, 2**32) which maps back to [0, upper_bound)
- * after reduction modulo upper_bound.
- */
-uint32_t
-arc4random_uniform(uint32_t upper_bound)
-{
-	uint32_t r, min;
-
-	if (upper_bound < 2)
-		return (0);
-
-#if (ULONG_MAX > 0xffffffffUL)
-	min = 0x100000000UL % upper_bound;
-#else
-	/* Calculate (2**32 % upper_bound) avoiding 64-bit math */
-	if (upper_bound > 0x80000000)
-		min = 1 + ~upper_bound;		/* 2**32 - upper_bound */
-	else {
-		/* (2**32 - (x * 2)) % x == 2**32 % x when x <= 2**31 */
-		min = ((0xffffffff - (upper_bound * 2)) + 1) % upper_bound;
-	}
-#endif
-
-	/*
-	 * This could theoretically loop forever but each retry has
-	 * p > 0.5 (worst case, usually far better) of selecting a
-	 * number inside the range we need, so it should rarely need
-	 * to re-roll.
-	 */
-	for (;;) {
-		r = arc4random();
-		if (r >= min)
-			break;
-	}
-
-	return (r % upper_bound);
-}
-
-#if 0
-/*-------- Test code for i386 --------*/
-#include <stdio.h>
-#include <machine/pctr.h>
-int
-main(int argc, char **argv)
+arc4random_buf(void *buf, size_t n)
 {
-	const int iter = 1000000;
-	int     i;
-	pctrval v;
-
-	v = rdtsc();
-	for (i = 0; i < iter; i++)
-		arc4random();
-	v = rdtsc() - v;
-	v /= iter;
-
-	printf("%qd cycles\n", v);
+	_ARC4_LOCK();
+	_rs_random_buf(buf, n);
+	_ARC4_UNLOCK();
 }
-#endif
diff --git a/src/arc4random.h b/src/arc4random.h
new file mode 100644
index 0000000..de52922
--- /dev/null
+++ b/src/arc4random.h
@@ -0,0 +1,29 @@
+#ifndef LIBBSD_ARC4RANDOM_H
+#define LIBBSD_ARC4RANDOM_H
+
+#include <sys/param.h>
+
+int
+getentropy(void *buf, size_t len);
+
+#if defined(__linux__)
+#include "arc4random_linux.h"
+#elif defined(__FreeBSD__)
+#include "arc4random_bsd.h"
+#elif defined(__NetBSD__)
+#include "arc4random_bsd.h"
+#elif defined(__OpenBSD__)
+#include "arc4random_openbsd.h"
+#elif defined(__sun)
+#include "arc4random_unix.h"
+#elif defined(__APPLE__)
+#include "arc4random_unix.h"
+#elif defined(_AIX)
+#include "arc4random_unix.h"
+#elif defined(__hpux)
+#include "arc4random_unix.h"
+#else
+#error "No arc4random hooks defined for this platform."
+#endif
+
+#endif
diff --git a/src/arc4random_bsd.h b/src/arc4random_bsd.h
new file mode 100644
index 0000000..ece2f85
--- /dev/null
+++ b/src/arc4random_bsd.h
@@ -0,0 +1,86 @@
+/*	$OpenBSD: arc4random_freebsd.h,v 1.2 2015/01/15 06:57:18 deraadt Exp $	*/
+
+/*
+ * Copyright (c) 1996, David Mazieres <dm at uun.org>
+ * Copyright (c) 2008, Damien Miller <djm at openbsd.org>
+ * Copyright (c) 2013, Markus Friedl <markus at openbsd.org>
+ * Copyright (c) 2014, Theo de Raadt <deraadt at openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Stub functions for portability.
+ */
+
+#include <sys/mman.h>
+
+#include <pthread.h>
+#include <signal.h>
+
+static pthread_mutex_t arc4random_mtx = PTHREAD_MUTEX_INITIALIZER;
+#define _ARC4_LOCK()   pthread_mutex_lock(&arc4random_mtx)
+#define _ARC4_UNLOCK() pthread_mutex_unlock(&arc4random_mtx)
+
+/*
+ * Unfortunately, pthread_atfork() is broken on FreeBSD (at least 9 and 10) if
+ * a program does not link to -lthr. Callbacks registered with pthread_atfork()
+ * appear to fail silently. So, it is not always possible to detect a PID
+ * wraparound.
+ */
+#define _ARC4_ATFORK(f) pthread_atfork(NULL, NULL, (f))
+
+static inline void
+_getentropy_fail(void)
+{
+	raise(SIGKILL);
+}
+
+static volatile sig_atomic_t _rs_forked;
+
+static inline void
+_rs_forkhandler(void)
+{
+	_rs_forked = 1;
+}
+
+static inline void
+_rs_forkdetect(void)
+{
+	static pid_t _rs_pid = 0;
+	pid_t pid = getpid();
+
+	if (_rs_pid == 0 || _rs_pid != pid || _rs_forked) {
+		_rs_pid = pid;
+		_rs_forked = 0;
+		if (rs)
+			memset(rs, 0, sizeof(*rs));
+	}
+}
+
+static inline int
+_rs_allocate(struct _rs **rsp, struct _rsx **rsxp)
+{
+	if ((*rsp = mmap(NULL, sizeof(**rsp), PROT_READ|PROT_WRITE,
+	    MAP_ANON|MAP_PRIVATE, -1, 0)) == MAP_FAILED)
+		return (-1);
+
+	if ((*rsxp = mmap(NULL, sizeof(**rsxp), PROT_READ|PROT_WRITE,
+	    MAP_ANON|MAP_PRIVATE, -1, 0)) == MAP_FAILED) {
+		munmap(*rsp, sizeof(**rsp));
+		return (-1);
+	}
+
+	_ARC4_ATFORK(_rs_forkhandler);
+	return (0);
+}
diff --git a/src/arc4random_linux.h b/src/arc4random_linux.h
new file mode 100644
index 0000000..d61a8db
--- /dev/null
+++ b/src/arc4random_linux.h
@@ -0,0 +1,86 @@
+/*	$OpenBSD: arc4random_linux.h,v 1.8 2014/08/13 06:04:10 deraadt Exp $	*/
+
+/*
+ * Copyright (c) 1996, David Mazieres <dm at uun.org>
+ * Copyright (c) 2008, Damien Miller <djm at openbsd.org>
+ * Copyright (c) 2013, Markus Friedl <markus at openbsd.org>
+ * Copyright (c) 2014, Theo de Raadt <deraadt at openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Stub functions for portability.
+ */
+
+#include <sys/mman.h>
+
+#include <pthread.h>
+#include <signal.h>
+
+static pthread_mutex_t arc4random_mtx = PTHREAD_MUTEX_INITIALIZER;
+#define _ARC4_LOCK()   pthread_mutex_lock(&arc4random_mtx)
+#define _ARC4_UNLOCK() pthread_mutex_unlock(&arc4random_mtx)
+
+#ifdef __GLIBC__
+extern void *__dso_handle;
+extern int __register_atfork(void (*)(void), void(*)(void), void (*)(void), void *);
+#define _ARC4_ATFORK(f) __register_atfork(NULL, NULL, (f), __dso_handle)
+#else
+#define _ARC4_ATFORK(f) pthread_atfork(NULL, NULL, (f))
+#endif
+
+static inline void
+_getentropy_fail(void)
+{
+	raise(SIGKILL);
+}
+
+static volatile sig_atomic_t _rs_forked;
+
+static inline void
+_rs_forkhandler(void)
+{
+	_rs_forked = 1;
+}
+
+static inline void
+_rs_forkdetect(void)
+{
+	static pid_t _rs_pid = 0;
+	pid_t pid = getpid();
+
+	if (_rs_pid == 0 || _rs_pid != pid || _rs_forked) {
+		_rs_pid = pid;
+		_rs_forked = 0;
+		if (rs)
+			memset(rs, 0, sizeof(*rs));
+	}
+}
+
+static inline int
+_rs_allocate(struct _rs **rsp, struct _rsx **rsxp)
+{
+	if ((*rsp = mmap(NULL, sizeof(**rsp), PROT_READ|PROT_WRITE,
+	    MAP_ANON|MAP_PRIVATE, -1, 0)) == MAP_FAILED)
+		return (-1);
+
+	if ((*rsxp = mmap(NULL, sizeof(**rsxp), PROT_READ|PROT_WRITE,
+	    MAP_ANON|MAP_PRIVATE, -1, 0)) == MAP_FAILED) {
+		munmap(*rsp, sizeof(**rsp));
+		return (-1);
+	}
+
+	_ARC4_ATFORK(_rs_forkhandler);
+	return (0);
+}
diff --git a/src/arc4random_openbsd.h b/src/arc4random_openbsd.h
new file mode 100644
index 0000000..9cd8b68
--- /dev/null
+++ b/src/arc4random_openbsd.h
@@ -0,0 +1,61 @@
+/*	$OpenBSD: arc4random.h,v 1.3 2014/07/20 20:51:13 bcook Exp $	*/
+
+/*
+ * Copyright (c) 1996, David Mazieres <dm at uun.org>
+ * Copyright (c) 2008, Damien Miller <djm at openbsd.org>
+ * Copyright (c) 2013, Markus Friedl <markus at openbsd.org>
+ * Copyright (c) 2014, Theo de Raadt <deraadt at openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Stub functions for portability.
+ */
+#include <sys/mman.h>
+
+#include <signal.h>
+
+#include "thread_private.h"
+
+static inline void
+_getentropy_fail(void)
+{
+	raise(SIGKILL);
+}
+
+static inline int
+_rs_allocate(struct _rs **rsp, struct _rsx **rsxp)
+{
+	struct {
+		struct _rs rs;
+		struct _rsx rsx;
+	} *p;
+
+	if ((p = mmap(NULL, sizeof(*p), PROT_READ|PROT_WRITE,
+	    MAP_ANON|MAP_PRIVATE, -1, 0)) == MAP_FAILED)
+		return (-1);
+	if (minherit(p, sizeof(*p), MAP_INHERIT_ZERO) == -1) {
+		munmap(p, sizeof(*p));
+		return (-1);
+	}
+
+	*rsp = &p->rs;
+	*rsxp = &p->rsx;
+	return (0);
+}
+
+static inline void
+_rs_forkdetect(void)
+{
+}
diff --git a/src/arc4random_uniform.c b/src/arc4random_uniform.c
new file mode 100644
index 0000000..0c89a2d
--- /dev/null
+++ b/src/arc4random_uniform.c
@@ -0,0 +1,57 @@
+/*	$OpenBSD: arc4random_uniform.c,v 1.1 2014/07/12 13:24:54 deraadt Exp $	*/
+
+/*
+ * Copyright (c) 2008, Damien Miller <djm at openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <stdlib.h>
+
+/*
+ * Calculate a uniformly distributed random number less than upper_bound
+ * avoiding "modulo bias".
+ *
+ * Uniformity is achieved by generating new random numbers until the one
+ * returned is outside the range [0, 2**32 % upper_bound).  This
+ * guarantees the selected random number will be inside
+ * [2**32 % upper_bound, 2**32) which maps back to [0, upper_bound)
+ * after reduction modulo upper_bound.
+ */
+uint32_t
+arc4random_uniform(uint32_t upper_bound)
+{
+	uint32_t r, min;
+
+	if (upper_bound < 2)
+		return 0;
+
+	/* 2**32 % x == (2**32 - x) % x */
+	min = -upper_bound % upper_bound;
+
+	/*
+	 * This could theoretically loop forever but each retry has
+	 * p > 0.5 (worst case, usually far better) of selecting a
+	 * number inside the range we need, so it should rarely need
+	 * to re-roll.
+	 */
+	for (;;) {
+		r = arc4random();
+		if (r >= min)
+			break;
+	}
+
+	return r % upper_bound;
+}
+//DEF_WEAK(arc4random_uniform);
diff --git a/src/arc4random_unix.h b/src/arc4random_unix.h
new file mode 100644
index 0000000..c200abc
--- /dev/null
+++ b/src/arc4random_unix.h
@@ -0,0 +1,80 @@
+/*	$OpenBSD: arc4random_hpux.h,v 1.1 2015/01/06 21:08:11 bcook Exp $	*/
+
+/*
+ * Copyright (c) 1996, David Mazieres <dm at uun.org>
+ * Copyright (c) 2008, Damien Miller <djm at openbsd.org>
+ * Copyright (c) 2013, Markus Friedl <markus at openbsd.org>
+ * Copyright (c) 2014, Theo de Raadt <deraadt at openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Stub functions for portability.
+ */
+
+#include <sys/mman.h>
+
+#include <pthread.h>
+#include <signal.h>
+
+static pthread_mutex_t arc4random_mtx = PTHREAD_MUTEX_INITIALIZER;
+#define _ARC4_LOCK()   pthread_mutex_lock(&arc4random_mtx)
+#define _ARC4_UNLOCK() pthread_mutex_unlock(&arc4random_mtx)
+
+#define _ARC4_ATFORK(f) pthread_atfork(NULL, NULL, (f))
+
+static inline void
+_getentropy_fail(void)
+{
+	raise(SIGKILL);
+}
+
+static volatile sig_atomic_t _rs_forked;
+
+static inline void
+_rs_forkhandler(void)
+{
+	_rs_forked = 1;
+}
+
+static inline void
+_rs_forkdetect(void)
+{
+	static pid_t _rs_pid = 0;
+	pid_t pid = getpid();
+
+	if (_rs_pid == 0 || _rs_pid != pid || _rs_forked) {
+		_rs_pid = pid;
+		_rs_forked = 0;
+		if (rs)
+			memset(rs, 0, sizeof(*rs));
+	}
+}
+
+static inline int
+_rs_allocate(struct _rs **rsp, struct _rsx **rsxp)
+{
+	if ((*rsp = mmap(NULL, sizeof(**rsp), PROT_READ|PROT_WRITE,
+	    MAP_ANON|MAP_PRIVATE, -1, 0)) == MAP_FAILED)
+		return (-1);
+
+	if ((*rsxp = mmap(NULL, sizeof(**rsxp), PROT_READ|PROT_WRITE,
+	    MAP_ANON|MAP_PRIVATE, -1, 0)) == MAP_FAILED) {
+		munmap(*rsp, sizeof(**rsp));
+		return (-1);
+	}
+
+	_ARC4_ATFORK(_rs_forkhandler);
+	return (0);
+}
diff --git a/src/chacha_private.h b/src/chacha_private.h
new file mode 100644
index 0000000..b720d93
--- /dev/null
+++ b/src/chacha_private.h
@@ -0,0 +1,222 @@
+/*
+chacha-merged.c version 20080118
+D. J. Bernstein
+Public domain.
+*/
+
+/* $OpenBSD$ */
+
+typedef unsigned char u8;
+typedef unsigned int u32;
+
+typedef struct
+{
+  u32 input[16]; /* could be compressed */
+} chacha_ctx;
+
+#define U8C(v) (v##U)
+#define U32C(v) (v##U)
+
+#define U8V(v) ((u8)(v) & U8C(0xFF))
+#define U32V(v) ((u32)(v) & U32C(0xFFFFFFFF))
+
+#define ROTL32(v, n) \
+  (U32V((v) << (n)) | ((v) >> (32 - (n))))
+
+#define U8TO32_LITTLE(p) \
+  (((u32)((p)[0])      ) | \
+   ((u32)((p)[1]) <<  8) | \
+   ((u32)((p)[2]) << 16) | \
+   ((u32)((p)[3]) << 24))
+
+#define U32TO8_LITTLE(p, v) \
+  do { \
+    (p)[0] = U8V((v)      ); \
+    (p)[1] = U8V((v) >>  8); \
+    (p)[2] = U8V((v) >> 16); \
+    (p)[3] = U8V((v) >> 24); \
+  } while (0)
+
+#define ROTATE(v,c) (ROTL32(v,c))
+#define XOR(v,w) ((v) ^ (w))
+#define PLUS(v,w) (U32V((v) + (w)))
+#define PLUSONE(v) (PLUS((v),1))
+
+#define QUARTERROUND(a,b,c,d) \
+  a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \
+  c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \
+  a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \
+  c = PLUS(c,d); b = ROTATE(XOR(b,c), 7);
+
+static const char sigma[16] = "expand 32-byte k";
+static const char tau[16] = "expand 16-byte k";
+
+static void
+chacha_keysetup(chacha_ctx *x,const u8 *k,u32 kbits,u32 ivbits)
+{
+  const char *constants;
+
+  x->input[4] = U8TO32_LITTLE(k + 0);
+  x->input[5] = U8TO32_LITTLE(k + 4);
+  x->input[6] = U8TO32_LITTLE(k + 8);
+  x->input[7] = U8TO32_LITTLE(k + 12);
+  if (kbits == 256) { /* recommended */
+    k += 16;
+    constants = sigma;
+  } else { /* kbits == 128 */
+    constants = tau;
+  }
+  x->input[8] = U8TO32_LITTLE(k + 0);
+  x->input[9] = U8TO32_LITTLE(k + 4);
+  x->input[10] = U8TO32_LITTLE(k + 8);
+  x->input[11] = U8TO32_LITTLE(k + 12);
+  x->input[0] = U8TO32_LITTLE(constants + 0);
+  x->input[1] = U8TO32_LITTLE(constants + 4);
+  x->input[2] = U8TO32_LITTLE(constants + 8);
+  x->input[3] = U8TO32_LITTLE(constants + 12);
+}
+
+static void
+chacha_ivsetup(chacha_ctx *x,const u8 *iv)
+{
+  x->input[12] = 0;
+  x->input[13] = 0;
+  x->input[14] = U8TO32_LITTLE(iv + 0);
+  x->input[15] = U8TO32_LITTLE(iv + 4);
+}
+
+static void
+chacha_encrypt_bytes(chacha_ctx *x,const u8 *m,u8 *c,u32 bytes)
+{
+  u32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
+  u32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
+  u8 *ctarget = NULL;
+  u8 tmp[64];
+  u_int i;
+
+  if (!bytes) return;
+
+  j0 = x->input[0];
+  j1 = x->input[1];
+  j2 = x->input[2];
+  j3 = x->input[3];
+  j4 = x->input[4];
+  j5 = x->input[5];
+  j6 = x->input[6];
+  j7 = x->input[7];
+  j8 = x->input[8];
+  j9 = x->input[9];
+  j10 = x->input[10];
+  j11 = x->input[11];
+  j12 = x->input[12];
+  j13 = x->input[13];
+  j14 = x->input[14];
+  j15 = x->input[15];
+
+  for (;;) {
+    if (bytes < 64) {
+      for (i = 0;i < bytes;++i) tmp[i] = m[i];
+      m = tmp;
+      ctarget = c;
+      c = tmp;
+    }
+    x0 = j0;
+    x1 = j1;
+    x2 = j2;
+    x3 = j3;
+    x4 = j4;
+    x5 = j5;
+    x6 = j6;
+    x7 = j7;
+    x8 = j8;
+    x9 = j9;
+    x10 = j10;
+    x11 = j11;
+    x12 = j12;
+    x13 = j13;
+    x14 = j14;
+    x15 = j15;
+    for (i = 20;i > 0;i -= 2) {
+      QUARTERROUND( x0, x4, x8,x12)
+      QUARTERROUND( x1, x5, x9,x13)
+      QUARTERROUND( x2, x6,x10,x14)
+      QUARTERROUND( x3, x7,x11,x15)
+      QUARTERROUND( x0, x5,x10,x15)
+      QUARTERROUND( x1, x6,x11,x12)
+      QUARTERROUND( x2, x7, x8,x13)
+      QUARTERROUND( x3, x4, x9,x14)
+    }
+    x0 = PLUS(x0,j0);
+    x1 = PLUS(x1,j1);
+    x2 = PLUS(x2,j2);
+    x3 = PLUS(x3,j3);
+    x4 = PLUS(x4,j4);
+    x5 = PLUS(x5,j5);
+    x6 = PLUS(x6,j6);
+    x7 = PLUS(x7,j7);
+    x8 = PLUS(x8,j8);
+    x9 = PLUS(x9,j9);
+    x10 = PLUS(x10,j10);
+    x11 = PLUS(x11,j11);
+    x12 = PLUS(x12,j12);
+    x13 = PLUS(x13,j13);
+    x14 = PLUS(x14,j14);
+    x15 = PLUS(x15,j15);
+
+#ifndef KEYSTREAM_ONLY
+    x0 = XOR(x0,U8TO32_LITTLE(m + 0));
+    x1 = XOR(x1,U8TO32_LITTLE(m + 4));
+    x2 = XOR(x2,U8TO32_LITTLE(m + 8));
+    x3 = XOR(x3,U8TO32_LITTLE(m + 12));
+    x4 = XOR(x4,U8TO32_LITTLE(m + 16));
+    x5 = XOR(x5,U8TO32_LITTLE(m + 20));
+    x6 = XOR(x6,U8TO32_LITTLE(m + 24));
+    x7 = XOR(x7,U8TO32_LITTLE(m + 28));
+    x8 = XOR(x8,U8TO32_LITTLE(m + 32));
+    x9 = XOR(x9,U8TO32_LITTLE(m + 36));
+    x10 = XOR(x10,U8TO32_LITTLE(m + 40));
+    x11 = XOR(x11,U8TO32_LITTLE(m + 44));
+    x12 = XOR(x12,U8TO32_LITTLE(m + 48));
+    x13 = XOR(x13,U8TO32_LITTLE(m + 52));
+    x14 = XOR(x14,U8TO32_LITTLE(m + 56));
+    x15 = XOR(x15,U8TO32_LITTLE(m + 60));
+#endif
+
+    j12 = PLUSONE(j12);
+    if (!j12) {
+      j13 = PLUSONE(j13);
+      /* stopping at 2^70 bytes per nonce is user's responsibility */
+    }
+
+    U32TO8_LITTLE(c + 0,x0);
+    U32TO8_LITTLE(c + 4,x1);
+    U32TO8_LITTLE(c + 8,x2);
+    U32TO8_LITTLE(c + 12,x3);
+    U32TO8_LITTLE(c + 16,x4);
+    U32TO8_LITTLE(c + 20,x5);
+    U32TO8_LITTLE(c + 24,x6);
+    U32TO8_LITTLE(c + 28,x7);
+    U32TO8_LITTLE(c + 32,x8);
+    U32TO8_LITTLE(c + 36,x9);
+    U32TO8_LITTLE(c + 40,x10);
+    U32TO8_LITTLE(c + 44,x11);
+    U32TO8_LITTLE(c + 48,x12);
+    U32TO8_LITTLE(c + 52,x13);
+    U32TO8_LITTLE(c + 56,x14);
+    U32TO8_LITTLE(c + 60,x15);
+
+    if (bytes <= 64) {
+      if (bytes < 64) {
+        for (i = 0;i < bytes;++i) ctarget[i] = c[i];
+      }
+      x->input[12] = j12;
+      x->input[13] = j13;
+      return;
+    }
+    bytes -= 64;
+    c += 64;
+#ifndef KEYSTREAM_ONLY
+    m += 64;
+#endif
+  }
+}
commit 9a9a8b2dba2f511c0888499726597add59ae1215
Author: Guillem Jover <guillem at hadrons.org>
Date:   Wed Sep 23 19:39:47 2015 +0200

    Add private getentropy module from OpenBSD and LibreSSL
    
    Adapt the code to the local build system.

diff --git a/configure.ac b/configure.ac
index 3b75267..0e797ce 100644
--- a/configure.ac
+++ b/configure.ac
@@ -128,8 +128,10 @@ AC_LINK_IFELSE(
 	 AC_MSG_RESULT([yes])],
 	[AC_MSG_RESULT([no])])
 
-AC_CHECK_FUNCS([clearenv dirfd fopencookie __fpurge getexecname getline \
+AC_CHECK_FUNCS([clearenv dirfd fopencookie __fpurge \
+                getentropy getexecname getline \
                 pstat_getproc sysconf])
+AM_CONDITIONAL(HAVE_GETENTROPY, [test "x$ac_cv_func_getentropy" = "xtrue"])
 
 AC_CONFIG_FILES([
 	Makefile
diff --git a/src/Makefile.am b/src/Makefile.am
index c8db76e..bd490fd 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -9,6 +9,12 @@ AM_CPPFLAGS = \
 
 libbsd_la_included_sources = \
 	hash/helper.c \
+	getentropy_aix.c \
+	getentropy_bsd.c \
+	getentropy_hpux.c \
+	getentropy_linux.c \
+	getentropy_osx.c \
+	getentropy_solaris.c \
 	$(nil)
 
 EXTRA_DIST = \
@@ -97,6 +103,12 @@ libbsd_la_SOURCES = \
 	wcslcpy.c \
 	$(nil)
 
+if !HAVE_GETENTROPY
+libbsd_la_SOURCES += \
+	getentropy.c \
+	$(nil)
+endif
+
 libbsd_ctor_a_SOURCES = \
 	setproctitle_ctor.c \
 	$(nil)
diff --git a/src/getentropy.c b/src/getentropy.c
new file mode 100644
index 0000000..f22b850
--- /dev/null
+++ b/src/getentropy.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright © 2015 Guillem Jover <guillem at hadrons.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(__linux__)
+#include "getentropy_linux.c"
+#elif defined(__FreeBSD__)
+#include "arc4random_bsd.c"
+#elif defined(__NetBSD__)
+#include "arc4random_bsd.c"
+#elif defined(__sun)
+#include "arc4random_solaris.c"
+#elif defined(__APPLE__)
+#include "arc4random_osx.c"
+#elif defined(_AIX)
+#include "arc4random_aix.c"
+#elif defined(__hpux)
+#include "arc4random_hpux.c"
+#else
+#error "No getentropy hooks defined for this platform."
+#endif
diff --git a/src/getentropy_aix.c b/src/getentropy_aix.c
new file mode 100644
index 0000000..cbd4037
--- /dev/null
+++ b/src/getentropy_aix.c
@@ -0,0 +1,425 @@
+/*	$OpenBSD: getentropy_aix.c,v 1.3 2015/08/25 17:26:43 deraadt Exp $	*/
+
+/*
+ * Copyright (c) 2015 Michael Felt <aixtools at gmail.com>
+ * Copyright (c) 2014 Theo de Raadt <deraadt at openbsd.org>
+ * Copyright (c) 2014 Bob Beck <beck at obtuse.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Emulation of getentropy(2) as documented at:
+ * http://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man2/getentropy.2
+ */
+/*
+ * -lperfstat is needed for the psuedo entropy data
+ */
+
+#include <sys/mman.h>
+#include <sys/procfs.h>
+#include <sys/protosw.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/statvfs.h>
+#include <sys/timers.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <termios.h>
+
+#include <openssl/sha.h>
+
+#include <libperfstat.h>
+
+#define REPEAT 5
+#define min(a, b) (((a) < (b)) ? (a) : (b))
+
+#define HX(a, b) \
+	do { \
+		if ((a)) \
+			HD(errno); \
+		else \
+			HD(b); \
+	} while (0)
+
+#define HR(x, l) (SHA512_Update(&ctx, (char *)(x), (l)))
+#define HD(x)	 (SHA512_Update(&ctx, (char *)&(x), sizeof (x)))
+#define HF(x)    (SHA512_Update(&ctx, (char *)&(x), sizeof (void*)))
+
+int	getentropy(void *buf, size_t len);
+
+static int gotdata(char *buf, size_t len);
+static int getentropy_urandom(void *buf, size_t len, const char *path,
+    int devfscheck);
+static int getentropy_fallback(void *buf, size_t len);
+
+int
+getentropy(void *buf, size_t len)
+{
+	int ret = -1;
+
+	if (len > 256) {
+		errno = EIO;
+		return (-1);
+	}
+
+	/*
+	 * Try to get entropy with /dev/urandom
+	 */
+	ret = getentropy_urandom(buf, len, "/dev/urandom", 0);
+	if (ret != -1)
+		return (ret);
+
+	/*
+	 * Entropy collection via /dev/urandom has failed.
+	 *
+	 * No other API exists for collecting entropy, and we have
+	 * no failsafe way to get it on AIX that is not sensitive
+	 * to resource exhaustion.
+	 *
+	 * We have very few options:
+	 *     - Even syslog_r is unsafe to call at this low level, so
+	 *	 there is no way to alert the user or program.
+	 *     - Cannot call abort() because some systems have unsafe
+	 *	 corefiles.
+	 *     - Could raise(SIGKILL) resulting in silent program termination.
+	 *     - Return EIO, to hint that arc4random's stir function
+	 *       should raise(SIGKILL)
+	 *     - Do the best under the circumstances....
+	 *
+	 * This code path exists to bring light to the issue that AIX
+	 * does not provide a failsafe API for entropy collection.
+	 *
+	 * We hope this demonstrates that AIX should consider
+	 * providing a new failsafe API which works in a chroot or
+	 * when file descriptors are exhausted.
+	 */
+#undef FAIL_INSTEAD_OF_TRYING_FALLBACK
+#ifdef FAIL_INSTEAD_OF_TRYING_FALLBACK
+	raise(SIGKILL);
+#endif
+	ret = getentropy_fallback(buf, len);
+	if (ret != -1)
+		return (ret);
+
+	errno = EIO;
+	return (ret);
+}
+
+/*
+ * Basic sanity checking; wish we could do better.
+ */
+static int
+gotdata(char *buf, size_t len)
+{
+	char	any_set = 0;
+	size_t	i;
+
+	for (i = 0; i < len; ++i)
+		any_set |= buf[i];
+	if (any_set == 0)
+		return (-1);
+	return (0);
+}
+
+static int
+getentropy_urandom(void *buf, size_t len, const char *path, int devfscheck)
+{
+	struct stat st;
+	size_t i;
+	int fd, flags;
+	int save_errno = errno;
+
+start:
+
+	flags = O_RDONLY;
+#ifdef O_NOFOLLOW
+	flags |= O_NOFOLLOW;
+#endif
+#ifdef O_CLOEXEC
+	flags |= O_CLOEXEC;
+#endif
+	fd = open(path, flags, 0);
+	if (fd == -1) {
+		if (errno == EINTR)
+			goto start;
+		goto nodevrandom;
+	}
+#ifndef O_CLOEXEC
+	fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
+#endif
+
+	/* Lightly verify that the device node looks sane */
+	if (fstat(fd, &st) == -1 || !S_ISCHR(st.st_mode)) {
+		close(fd);
+		goto nodevrandom;
+	}
+	for (i = 0; i < len; ) {
+		size_t wanted = len - i;
+		ssize_t ret = read(fd, (char *)buf + i, wanted);
+
+		if (ret == -1) {
+			if (errno == EAGAIN || errno == EINTR)
+				continue;
+			close(fd);
+			goto nodevrandom;
+		}
+		i += ret;
+	}
+	close(fd);
+	if (gotdata(buf, len) == 0) {
+		errno = save_errno;
+		return (0);		/* satisfied */
+	}
+nodevrandom:
+	errno = EIO;
+	return (-1);
+}
+
+static const int cl[] = {
+	CLOCK_REALTIME,
+#ifdef CLOCK_MONOTONIC
+	CLOCK_MONOTONIC,
+#endif
+#ifdef CLOCK_MONOTONIC_RAW
+	CLOCK_MONOTONIC_RAW,
+#endif
+#ifdef CLOCK_TAI
+	CLOCK_TAI,
+#endif
+#ifdef CLOCK_VIRTUAL
+	CLOCK_VIRTUAL,
+#endif
+#ifdef CLOCK_UPTIME
+	CLOCK_UPTIME,
+#endif
+#ifdef CLOCK_PROCESS_CPUTIME_ID
+	CLOCK_PROCESS_CPUTIME_ID,
+#endif
+#ifdef CLOCK_THREAD_CPUTIME_ID
+	CLOCK_THREAD_CPUTIME_ID,
+#endif
+};
+
+static int
+getentropy_fallback(void *buf, size_t len)
+{
+	uint8_t results[SHA512_DIGEST_LENGTH];
+	int save_errno = errno, e, pgs = sysconf(_SC_PAGESIZE), faster = 0, repeat;
+	static int cnt;
+	struct timespec ts;
+	struct timeval tv;
+	perfstat_cpu_total_t cpustats;
+#ifdef _AIX61
+	perfstat_cpu_total_wpar_t cpustats_wpar;
+#endif
+	perfstat_partition_total_t lparstats;
+	perfstat_disk_total_t diskinfo;
+	perfstat_netinterface_total_t netinfo;
+	struct rusage ru;
+	sigset_t sigset;
+	struct stat st;
+	SHA512_CTX ctx;
+	static pid_t lastpid;
+	pid_t pid;
+	size_t i, ii, m;
+	char *p;
+
+	pid = getpid();
+	if (lastpid == pid) {
+		faster = 1;
+		repeat = 2;
+	} else {
+		faster = 0;
+		lastpid = pid;
+		repeat = REPEAT;
+	}
+	for (i = 0; i < len; ) {
+		int j;
+		SHA512_Init(&ctx);
+		for (j = 0; j < repeat; j++) {
+			HX((e = gettimeofday(&tv, NULL)) == -1, tv);
+			if (e != -1) {
+				cnt += (int)tv.tv_sec;
+				cnt += (int)tv.tv_usec;
+			}
+
+			HX(perfstat_cpu_total(NULL, &cpustats,
+			    sizeof(cpustats), 1) == -1, cpustats);
+
+#ifdef _AIX61
+			HX(perfstat_cpu_total_wpar(NULL, &cpustats_wpar,
+			    sizeof(cpustats_wpar), 1) == -1, cpustats_wpar);
+#endif
+
+			HX(perfstat_partition_total(NULL, &lparstats,
+			    sizeof(lparstats), 1) == -1, lparstats);
+
+			HX(perfstat_disk_total(NULL, &diskinfo,
+			    sizeof(diskinfo), 1) == -1, diskinfo);
+
+			HX(perfstat_netinterface_total(NULL, &netinfo,
+			    sizeof(netinfo), 1) == -1, netinfo);
+
+			for (ii = 0; ii < sizeof(cl)/sizeof(cl[0]); ii++)
+				HX(clock_gettime(cl[ii], &ts) == -1, ts);
+
+			HX((pid = getpid()) == -1, pid);
+			HX((pid = getsid(pid)) == -1, pid);
+			HX((pid = getppid()) == -1, pid);
+			HX((pid = getpgid(0)) == -1, pid);
+			HX((e = getpriority(0, 0)) == -1, e);
+
+			if (!faster) {
+				ts.tv_sec = 0;
+				ts.tv_nsec = 1;
+				(void) nanosleep(&ts, NULL);
+			}
+
+			HX(sigpending(&sigset) == -1, sigset);
+			HX(sigprocmask(SIG_BLOCK, NULL, &sigset) == -1,
+			    sigset);
+
+			HF(getentropy);	/* an addr in this library */
+			HF(printf);		/* an addr in libc */
+			p = (char *)&p;
+			HD(p);		/* an addr on stack */
+			p = (char *)&errno;
+			HD(p);		/* the addr of errno */
+
+			if (i == 0) {
+				struct sockaddr_storage ss;
+				struct statvfs stvfs;
+				struct termios tios;
+				socklen_t ssl;
+				off_t off;
+
+				/*
+				 * Prime-sized mappings encourage fragmentation;
+				 * thus exposing some address entropy.
+				 */
+				struct mm {
+					size_t	npg;
+					void	*p;
+				} mm[] =	 {
+					{ 17, MAP_FAILED }, { 3, MAP_FAILED },
+					{ 11, MAP_FAILED }, { 2, MAP_FAILED },
+					{ 5, MAP_FAILED }, { 3, MAP_FAILED },
+					{ 7, MAP_FAILED }, { 1, MAP_FAILED },
+					{ 57, MAP_FAILED }, { 3, MAP_FAILED },
+					{ 131, MAP_FAILED }, { 1, MAP_FAILED },
+				};
+
+				for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) {
+					HX(mm[m].p = mmap(NULL,
+					    mm[m].npg * pgs,
+					    PROT_READ|PROT_WRITE,
+					    MAP_PRIVATE|MAP_ANON, -1,
+					    (off_t)0), mm[m].p);
+					if (mm[m].p != MAP_FAILED) {
+						size_t mo;
+
+						/* Touch some memory... */
+						p = mm[m].p;
+						mo = cnt %
+						    (mm[m].npg * pgs - 1);
+						p[mo] = 1;
+						cnt += (int)((long)(mm[m].p)
+						    / pgs);
+					}
+
+					/* Check cnts and times... */
+					for (ii = 0; ii < sizeof(cl)/sizeof(cl[0]);
+					    ii++) {
+						HX((e = clock_gettime(cl[ii],
+						    &ts)) == -1, ts);
+						if (e != -1)
+							cnt += (int)ts.tv_nsec;
+					}
+
+					HX((e = getrusage(RUSAGE_SELF,
+					    &ru)) == -1, ru);
+					if (e != -1) {
+						cnt += (int)ru.ru_utime.tv_sec;
+						cnt += (int)ru.ru_utime.tv_usec;
+					}
+				}
+
+				for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) {
+					if (mm[m].p != MAP_FAILED)
+						munmap(mm[m].p, mm[m].npg * pgs);
+					mm[m].p = MAP_FAILED;
+				}
+
+				HX(stat(".", &st) == -1, st);
+				HX(statvfs(".", &stvfs) == -1, stvfs);
+
+				HX(stat("/", &st) == -1, st);
+				HX(statvfs("/", &stvfs) == -1, stvfs);
+
+				HX((e = fstat(0, &st)) == -1, st);
+				if (e == -1) {
+					if (S_ISREG(st.st_mode) ||
+					    S_ISFIFO(st.st_mode) ||
+					    S_ISSOCK(st.st_mode)) {
+						HX(fstatvfs(0, &stvfs) == -1,
+						    stvfs);
+						HX((off = lseek(0, (off_t)0,
+						    SEEK_CUR)) < 0, off);
+					}
+					if (S_ISCHR(st.st_mode)) {
+						HX(tcgetattr(0, &tios) == -1,
+						    tios);
+					} else if (S_ISSOCK(st.st_mode)) {
+						memset(&ss, 0, sizeof ss);
+						ssl = sizeof(ss);
+						HX(getpeername(0,
+						    (void *)&ss, &ssl) == -1,
+						    ss);
+					}
+				}
+
+				HX((e = getrusage(RUSAGE_CHILDREN,
+				    &ru)) == -1, ru);
+				if (e != -1) {
+					cnt += (int)ru.ru_utime.tv_sec;
+					cnt += (int)ru.ru_utime.tv_usec;
+				}
+			} else {
+				/* Subsequent hashes absorb previous result */
+				HD(results);
+			}
+
+			HX((e = gettimeofday(&tv, NULL)) == -1, tv);
+			if (e != -1) {
+				cnt += (int)tv.tv_sec;
+				cnt += (int)tv.tv_usec;
+			}
+
+			HD(cnt);
+		}
+		SHA512_Final(results, &ctx);
+		memcpy((char *)buf + i, results, min(sizeof(results), len - i));
+		i += min(sizeof(results), len - i);
+	}
+	explicit_bzero(&ctx, sizeof ctx);
+	explicit_bzero(results, sizeof results);
+	if (gotdata(buf, len) == 0) {
+		errno = save_errno;
+		return (0);		/* satisfied */
+	}
+	errno = EIO;
+	return (-1);
+}
diff --git a/src/getentropy_bsd.c b/src/getentropy_bsd.c
new file mode 100644
index 0000000..1959984
--- /dev/null
+++ b/src/getentropy_bsd.c
@@ -0,0 +1,62 @@
+/*	$OpenBSD: getentropy_freebsd.c,v 1.1 2014/11/03 06:23:30 bcook Exp $	*/
+
+/*
+ * Copyright (c) 2014 Pawel Jakub Dawidek <pjd at FreeBSD.org>
+ * Copyright (c) 2014 Brent Cook <bcook at openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Emulation of getentropy(2) as documented at:
+ * http://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man2/getentropy.2
+ */
+
+#include <sys/types.h>
+#include <sys/sysctl.h>
+
+#include <errno.h>
+#include <stddef.h>
+
+/*
+ * Derived from lib/libc/gen/arc4random.c from FreeBSD.
+ */
+static size_t
+getentropy_sysctl(u_char *buf, size_t size)
+{
+	int mib[2];
+	size_t len, done;
+
+	mib[0] = CTL_KERN;
+	mib[1] = KERN_ARND;
+	done = 0;
+
+	do {
+		len = size;
+		if (sysctl(mib, 2, buf, &len, NULL, 0) == -1)
+			return (done);
+		done += len;
+		buf += len;
+		size -= len;
+	} while (size > 0);
+
+	return (done);
+}
+
+int
+getentropy(void *buf, size_t len)
+{
+	if (len <= 256 && getentropy_sysctl(buf, len) == len)
+		return (0);
+
+	errno = EIO;
+	return (-1);
+}
diff --git a/src/getentropy_hpux.c b/src/getentropy_hpux.c
new file mode 100644
index 0000000..45ac84b
--- /dev/null
+++ b/src/getentropy_hpux.c
@@ -0,0 +1,419 @@
+/*	$OpenBSD: getentropy_hpux.c,v 1.3 2015/08/25 17:26:43 deraadt Exp $	*/
+
+/*
+ * Copyright (c) 2014 Theo de Raadt <deraadt at openbsd.org>
+ * Copyright (c) 2014 Bob Beck <beck at obtuse.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Emulation of getentropy(2) as documented at:
+ * http://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man2/getentropy.2
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/resource.h>
+#include <sys/syscall.h>
+#include <sys/statvfs.h>
+#include <sys/socket.h>
+#include <sys/mount.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <termios.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <time.h>
+#include <openssl/sha.h>
+
+#include <sys/vfs.h>
+
+#include <sys/pstat.h>
+
+#define REPEAT 5
+#define min(a, b) (((a) < (b)) ? (a) : (b))
+
+#define HX(a, b) \
+	do { \
+		if ((a)) \
+			HD(errno); \
+		else \
+			HD(b); \
+	} while (0)
+
+#define HR(x, l) (SHA512_Update(&ctx, (char *)(x), (l)))
+#define HD(x)	 (SHA512_Update(&ctx, (char *)&(x), sizeof (x)))
+#define HF(x)    (SHA512_Update(&ctx, (char *)&(x), sizeof (void*)))
+
+int	getentropy(void *buf, size_t len);
+
+static int gotdata(char *buf, size_t len);
+static int getentropy_urandom(void *buf, size_t len, const char *path,
+    int devfscheck);
+static int getentropy_fallback(void *buf, size_t len);
+
+int
+getentropy(void *buf, size_t len)
+{
+	int ret = -1;
+
+	if (len > 256) {
+		errno = EIO;
+		return (-1);
+	}
+
+	/*
+	 * Try to get entropy with /dev/urandom
+	 */
+	ret = getentropy_urandom(buf, len, "/dev/urandom", 0);
+	if (ret != -1)
+		return (ret);
+
+	/*
+	 * Entropy collection via /dev/urandom has failed.
+	 *
+	 * No other API exists for collecting entropy, and we have
+	 * no failsafe way to get it on hpux that is not sensitive
+	 * to resource exhaustion.
+	 *
+	 * We have very few options:
+	 *     - Even syslog_r is unsafe to call at this low level, so
+	 *	 there is no way to alert the user or program.
+	 *     - Cannot call abort() because some systems have unsafe
+	 *	 corefiles.
+	 *     - Could raise(SIGKILL) resulting in silent program termination.
+	 *     - Return EIO, to hint that arc4random's stir function
+	 *       should raise(SIGKILL)
+	 *     - Do the best under the circumstances....
+	 *
+	 * This code path exists to bring light to the issue that hpux
+	 * does not provide a failsafe API for entropy collection.
+	 *
+	 * We hope this demonstrates that hpux should consider
+	 * providing a new failsafe API which works in a chroot or
+	 * when file descriptors are exhausted.
+	 */
+#undef FAIL_INSTEAD_OF_TRYING_FALLBACK
+#ifdef FAIL_INSTEAD_OF_TRYING_FALLBACK
+	raise(SIGKILL);
+#endif
+	ret = getentropy_fallback(buf, len);
+	if (ret != -1)
+		return (ret);
+
+	errno = EIO;
+	return (ret);
+}
+
+/*
+ * Basic sanity checking; wish we could do better.
+ */
+static int
+gotdata(char *buf, size_t len)
+{
+	char	any_set = 0;
+	size_t	i;
+
+	for (i = 0; i < len; ++i)
+		any_set |= buf[i];
+	if (any_set == 0)
+		return (-1);
+	return (0);
+}
+
+static int
+getentropy_urandom(void *buf, size_t len, const char *path, int devfscheck)
+{
+	struct stat st;
+	size_t i;
+	int fd, flags;
+	int save_errno = errno;
+
+start:
+
+	flags = O_RDONLY;
+#ifdef O_NOFOLLOW
+	flags |= O_NOFOLLOW;
+#endif
+#ifdef O_CLOEXEC
+	flags |= O_CLOEXEC;
+#endif
+	fd = open(path, flags, 0);
+	if (fd == -1) {
+		if (errno == EINTR)
+			goto start;
+		goto nodevrandom;
+	}
+#ifndef O_CLOEXEC
+	fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
+#endif
+
+	/* Lightly verify that the device node looks sane */
+	if (fstat(fd, &st) == -1 || !S_ISCHR(st.st_mode)) {
+		close(fd);
+		goto nodevrandom;
+	}
+	for (i = 0; i < len; ) {
+		size_t wanted = len - i;
+		ssize_t ret = read(fd, (char *)buf + i, wanted);
+
+		if (ret == -1) {
+			if (errno == EAGAIN || errno == EINTR)
+				continue;
+			close(fd);
+			goto nodevrandom;
+		}
+		i += ret;
+	}
+	close(fd);
+	if (gotdata(buf, len) == 0) {
+		errno = save_errno;
+		return (0);		/* satisfied */
+	}
+nodevrandom:
+	errno = EIO;
+	return (-1);
+}
+
+static const int cl[] = {
+	CLOCK_REALTIME,
+#ifdef CLOCK_MONOTONIC
+	CLOCK_MONOTONIC,
+#endif
+#ifdef CLOCK_MONOTONIC_RAW
+	CLOCK_MONOTONIC_RAW,
+#endif
+#ifdef CLOCK_TAI
+	CLOCK_TAI,
+#endif
+#ifdef CLOCK_VIRTUAL
+	CLOCK_VIRTUAL,
+#endif
+#ifdef CLOCK_UPTIME
+	CLOCK_UPTIME,
+#endif
+#ifdef CLOCK_PROCESS_CPUTIME_ID
+	CLOCK_PROCESS_CPUTIME_ID,
+#endif
+#ifdef CLOCK_THREAD_CPUTIME_ID
+	CLOCK_THREAD_CPUTIME_ID,
+#endif
+};
+
+static int
+getentropy_fallback(void *buf, size_t len)
+{
+	uint8_t results[SHA512_DIGEST_LENGTH];
+	int save_errno = errno, e, pgs = sysconf(_SC_PAGESIZE), faster = 0, repeat;
+	static int cnt;
+	struct timespec ts;
+	struct timeval tv;
+	struct pst_vminfo pvi;
+	struct pst_vm_status pvs;
+	struct pst_dynamic pdy;
+	struct rusage ru;
+	sigset_t sigset;
+	struct stat st;
+	SHA512_CTX ctx;
+	static pid_t lastpid;
+	pid_t pid;
+	size_t i, ii, m;
+	char *p;
+
+	pid = getpid();
+	if (lastpid == pid) {
+		faster = 1;
+		repeat = 2;
+	} else {
+		faster = 0;
+		lastpid = pid;
+		repeat = REPEAT;
+	}
+	for (i = 0; i < len; ) {
+		int j;
+		SHA512_Init(&ctx);
+		for (j = 0; j < repeat; j++) {
+			HX((e = gettimeofday(&tv, NULL)) == -1, tv);
+			if (e != -1) {
+				cnt += (int)tv.tv_sec;
+				cnt += (int)tv.tv_usec;
+			}
+
+			HX(pstat_getvminfo(&pvi, sizeof(pvi), 1, 0) != 1, pvi);
+			HX(pstat_getprocvm(&pvs, sizeof(pvs), 0, 0) != 1, pvs);
+
+			for (ii = 0; ii < sizeof(cl)/sizeof(cl[0]); ii++)
+				HX(clock_gettime(cl[ii], &ts) == -1, ts);
+
+			HX((pid = getpid()) == -1, pid);
+			HX((pid = getsid(pid)) == -1, pid);
+			HX((pid = getppid()) == -1, pid);
+			HX((pid = getpgid(0)) == -1, pid);
+			HX((e = getpriority(0, 0)) == -1, e);
+
+			if(pstat_getdynamic(&pdy, sizeof(pdy), 1, 0) != 1) {
+				HD(errno);
+			} else {
+				HD(pdy.psd_avg_1_min);
+				HD(pdy.psd_avg_5_min);
+				HD(pdy.psd_avg_15_min);
+			}
+
+			if (!faster) {
+				ts.tv_sec = 0;
+				ts.tv_nsec = 1;
+				(void) nanosleep(&ts, NULL);
+			}
+
+			HX(sigpending(&sigset) == -1, sigset);
+			HX(sigprocmask(SIG_BLOCK, NULL, &sigset) == -1,
+			    sigset);
+
+			HF(getentropy);	/* an addr in this library */
+			HF(printf);		/* an addr in libc */
+			p = (char *)&p;
+			HD(p);		/* an addr on stack */
+			p = (char *)&errno;
+			HD(p);		/* the addr of errno */
+
+			if (i == 0) {
+				struct sockaddr_storage ss;
+				struct statvfs stvfs;
+				struct termios tios;
+				socklen_t ssl;
+				off_t off;
+
+				/*
+				 * Prime-sized mappings encourage fragmentation;
+				 * thus exposing some address entropy.
+				 */
+				struct mm {
+					size_t	npg;
+					void	*p;
+				} mm[] =	 {
+					{ 17, MAP_FAILED }, { 3, MAP_FAILED },
+					{ 11, MAP_FAILED }, { 2, MAP_FAILED },
+					{ 5, MAP_FAILED }, { 3, MAP_FAILED },
+					{ 7, MAP_FAILED }, { 1, MAP_FAILED },
+					{ 57, MAP_FAILED }, { 3, MAP_FAILED },
+					{ 131, MAP_FAILED }, { 1, MAP_FAILED },
+				};
+
+				for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) {
+					HX(mm[m].p = mmap(NULL,
+					    mm[m].npg * pgs,
+					    PROT_READ|PROT_WRITE,
+					    MAP_PRIVATE|MAP_ANON, -1,
+					    (off_t)0), mm[m].p);
+					if (mm[m].p != MAP_FAILED) {
+						size_t mo;
+
+						/* Touch some memory... */
+						p = mm[m].p;
+						mo = cnt %
+						    (mm[m].npg * pgs - 1);
+						p[mo] = 1;
+						cnt += (int)((long)(mm[m].p)
+						    / pgs);
+					}
+
+					/* Check cnts and times... */
+					for (ii = 0; ii < sizeof(cl)/sizeof(cl[0]);
+					    ii++) {
+						HX((e = clock_gettime(cl[ii],
+						    &ts)) == -1, ts);
+						if (e != -1)
+							cnt += (int)ts.tv_nsec;
+					}
+
+					HX((e = getrusage(RUSAGE_SELF,
+					    &ru)) == -1, ru);
+					if (e != -1) {
+						cnt += (int)ru.ru_utime.tv_sec;
+						cnt += (int)ru.ru_utime.tv_usec;
+					}
+				}
+
+				for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) {
+					if (mm[m].p != MAP_FAILED)
+						munmap(mm[m].p, mm[m].npg * pgs);
+					mm[m].p = MAP_FAILED;
+				}
+
+				HX(stat(".", &st) == -1, st);
+				HX(statvfs(".", &stvfs) == -1, stvfs);
+
+				HX(stat("/", &st) == -1, st);
+				HX(statvfs("/", &stvfs) == -1, stvfs);
+
+				HX((e = fstat(0, &st)) == -1, st);
+				if (e == -1) {
+					if (S_ISREG(st.st_mode) ||
+					    S_ISFIFO(st.st_mode) ||
+					    S_ISSOCK(st.st_mode)) {
+						HX(fstatvfs(0, &stvfs) == -1,
+						    stvfs);
+						HX((off = lseek(0, (off_t)0,
+						    SEEK_CUR)) < 0, off);
+					}
+					if (S_ISCHR(st.st_mode)) {
+						HX(tcgetattr(0, &tios) == -1,
+						    tios);
+					} else if (S_ISSOCK(st.st_mode)) {
+						memset(&ss, 0, sizeof ss);
+						ssl = sizeof(ss);
+						HX(getpeername(0,
+						    (void *)&ss, &ssl) == -1,
+						    ss);
+					}
+				}
+
+				HX((e = getrusage(RUSAGE_CHILDREN,
+				    &ru)) == -1, ru);
+				if (e != -1) {
+					cnt += (int)ru.ru_utime.tv_sec;
+					cnt += (int)ru.ru_utime.tv_usec;
+				}
+			} else {
+				/* Subsequent hashes absorb previous result */
+				HD(results);
+			}
+
+			HX((e = gettimeofday(&tv, NULL)) == -1, tv);
+			if (e != -1) {
+				cnt += (int)tv.tv_sec;
+				cnt += (int)tv.tv_usec;
+			}
+
+			HD(cnt);
+		}
+		SHA512_Final(results, &ctx);
+		memcpy((char *)buf + i, results, min(sizeof(results), len - i));
+		i += min(sizeof(results), len - i);
+	}
+	explicit_bzero(&ctx, sizeof ctx);
+	explicit_bzero(results, sizeof results);
+	if (gotdata(buf, len) == 0) {
+		errno = save_errno;
+		return (0);		/* satisfied */
+	}
+	errno = EIO;
+	return (-1);
+}
diff --git a/src/getentropy_linux.c b/src/getentropy_linux.c
new file mode 100644
index 0000000..0a5d6b8
--- /dev/null
+++ b/src/getentropy_linux.c
@@ -0,0 +1,547 @@
+/*	$OpenBSD: getentropy_linux.c,v 1.40 2015/08/25 17:26:43 deraadt Exp $	*/
+
+/*
+ * Copyright (c) 2014 Theo de Raadt <deraadt at openbsd.org>
+ * Copyright (c) 2014 Bob Beck <beck at obtuse.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Emulation of getentropy(2) as documented at:
+ * http://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man2/getentropy.2
+ */
+
+#define	_POSIX_C_SOURCE	199309L
+#define	_GNU_SOURCE	1
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/resource.h>
+#include <sys/syscall.h>
+#ifdef SYS__sysctl
+#include <linux/sysctl.h>
+#endif
+#include <sys/statvfs.h>
+#include <sys/socket.h>
+#include <sys/mount.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <link.h>
+#include <termios.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <time.h>
+#include <openssl/sha.h>
+
+#include <linux/types.h>
+#include <linux/random.h>
+#ifdef HAVE_GETAUXVAL
+#include <sys/auxv.h>
+#endif
+#include <sys/vfs.h>
+
+#define REPEAT 5
+#define min(a, b) (((a) < (b)) ? (a) : (b))
+
+#define HX(a, b) \
+	do { \
+		if ((a)) \
+			HD(errno); \
+		else \
+			HD(b); \
+	} while (0)
+
+#define HR(x, l) (SHA512_Update(&ctx, (char *)(x), (l)))
+#define HD(x)	 (SHA512_Update(&ctx, (char *)&(x), sizeof (x)))
+#define HF(x)    (SHA512_Update(&ctx, (char *)&(x), sizeof (void*)))
+
+int	getentropy(void *buf, size_t len);
+
+static int gotdata(char *buf, size_t len);
+#ifdef SYS_getrandom
+static int getentropy_getrandom(void *buf, size_t len);
+#endif
+static int getentropy_urandom(void *buf, size_t len);
+#ifdef SYS__sysctl
+static int getentropy_sysctl(void *buf, size_t len);
+#endif
+static int getentropy_fallback(void *buf, size_t len);
+static int getentropy_phdr(struct dl_phdr_info *info, size_t size, void *data);
+
+int
+getentropy(void *buf, size_t len)
+{
+	int ret = -1;
+
+	if (len > 256) {
+		errno = EIO;
+		return (-1);
+	}
+
+#ifdef SYS_getrandom
+	/*
+	 * Try descriptor-less getrandom()
+	 */
+	ret = getentropy_getrandom(buf, len);
+	if (ret != -1)
+		return (ret);
+	if (errno != ENOSYS)
+		return (-1);
+#endif
+
+	/*
+	 * Try to get entropy with /dev/urandom
+	 *
+	 * This can fail if the process is inside a chroot or if file
+	 * descriptors are exhausted.
+	 */
+	ret = getentropy_urandom(buf, len);
+	if (ret != -1)
+		return (ret);
+
+#ifdef SYS__sysctl
+	/*
+	 * Try to use sysctl CTL_KERN, KERN_RANDOM, RANDOM_UUID.
+	 * sysctl is a failsafe API, so it guarantees a result.  This
+	 * should work inside a chroot, or when file descriptors are
+	 * exhuasted.
+	 *
+	 * However this can fail if the Linux kernel removes support
+	 * for sysctl.  Starting in 2007, there have been efforts to
+	 * deprecate the sysctl API/ABI, and push callers towards use
+	 * of the chroot-unavailable fd-using /proc mechanism --
+	 * essentially the same problems as /dev/urandom.
+	 *
+	 * Numerous setbacks have been encountered in their deprecation
+	 * schedule, so as of June 2014 the kernel ABI still exists on
+	 * most Linux architectures. The sysctl() stub in libc is missing
+	 * on some systems.  There are also reports that some kernels
+	 * spew messages to the console.
+	 */
+	ret = getentropy_sysctl(buf, len);
+	if (ret != -1)
+		return (ret);
+#endif /* SYS__sysctl */
+
+	/*
+	 * Entropy collection via /dev/urandom and sysctl have failed.
+	 *
+	 * No other API exists for collecting entropy.  See the large
+	 * comment block above.
+	 *
+	 * We have very few options:
+	 *     - Even syslog_r is unsafe to call at this low level, so
+	 *	 there is no way to alert the user or program.
+	 *     - Cannot call abort() because some systems have unsafe
+	 *	 corefiles.
+	 *     - Could raise(SIGKILL) resulting in silent program termination.
+	 *     - Return EIO, to hint that arc4random's stir function
+	 *       should raise(SIGKILL)
+	 *     - Do the best under the circumstances....
+	 *
+	 * This code path exists to bring light to the issue that Linux
+	 * does not provide a failsafe API for entropy collection.
+	 *
+	 * We hope this demonstrates that Linux should either retain their
+	 * sysctl ABI, or consider providing a new failsafe API which
+	 * works in a chroot or when file descriptors are exhausted.
+	 */
+#undef FAIL_INSTEAD_OF_TRYING_FALLBACK
+#ifdef FAIL_INSTEAD_OF_TRYING_FALLBACK
+	raise(SIGKILL);
+#endif
+	ret = getentropy_fallback(buf, len);
+	if (ret != -1)
+		return (ret);
+
+	errno = EIO;
+	return (ret);
+}
+
+/*
+ * Basic sanity checking; wish we could do better.
+ */
+static int
+gotdata(char *buf, size_t len)
+{
+	char	any_set = 0;
+	size_t	i;
+
+	for (i = 0; i < len; ++i)
+		any_set |= buf[i];
+	if (any_set == 0)
+		return (-1);
+	return (0);
+}
+
+#ifdef SYS_getrandom
+static int
+getentropy_getrandom(void *buf, size_t len)
+{
+	int pre_errno = errno;
+	int ret;
+	if (len > 256)
+		return (-1);
+	do {
+		ret = syscall(SYS_getrandom, buf, len, 0);
+	} while (ret == -1 && errno == EINTR);
+
+	if (ret != (int)len)
+		return (-1);
+	errno = pre_errno;
+	return (0);
+}
+#endif
+
+static int
+getentropy_urandom(void *buf, size_t len)
+{
+	struct stat st;
+	size_t i;
+	int fd, cnt, flags;
+	int save_errno = errno;
+
+start:
+
+	flags = O_RDONLY;
+#ifdef O_NOFOLLOW
+	flags |= O_NOFOLLOW;
+#endif
+#ifdef O_CLOEXEC
+	flags |= O_CLOEXEC;
+#endif
+	fd = open("/dev/urandom", flags, 0);
+	if (fd == -1) {
+		if (errno == EINTR)
+			goto start;
+		goto nodevrandom;
+	}
+#ifndef O_CLOEXEC
+	fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
+#endif
+
+	/* Lightly verify that the device node looks sane */
+	if (fstat(fd, &st) == -1 || !S_ISCHR(st.st_mode)) {
+		close(fd);
+		goto nodevrandom;
+	}
+	if (ioctl(fd, RNDGETENTCNT, &cnt) == -1) {
+		close(fd);
+		goto nodevrandom;
+	}
+	for (i = 0; i < len; ) {
+		size_t wanted = len - i;
+		ssize_t ret = read(fd, (char *)buf + i, wanted);
+
+		if (ret == -1) {
+			if (errno == EAGAIN || errno == EINTR)
+				continue;
+			close(fd);
+			goto nodevrandom;
+		}
+		i += ret;
+	}
+	close(fd);
+	if (gotdata(buf, len) == 0) {
+		errno = save_errno;
+		return (0);		/* satisfied */
+	}
+nodevrandom:
+	errno = EIO;
+	return (-1);
+}
+
+#ifdef SYS__sysctl
+static int
+getentropy_sysctl(void *buf, size_t len)
+{
+	static int mib[] = { CTL_KERN, KERN_RANDOM, RANDOM_UUID };
+	size_t i;
+	int save_errno = errno;
+
+	for (i = 0; i < len; ) {
+		size_t chunk = min(len - i, 16);
+
+		/* SYS__sysctl because some systems already removed sysctl() */
+		struct __sysctl_args args = {
+			.name = mib,
+			.nlen = 3,
+			.oldval = (char *)buf + i,
+			.oldlenp = &chunk,
+		};
+		if (syscall(SYS__sysctl, &args) != 0)
+			goto sysctlfailed;
+		i += chunk;
+	}
+	if (gotdata(buf, len) == 0) {
+		errno = save_errno;
+		return (0);			/* satisfied */
+	}
+sysctlfailed:
+	errno = EIO;
+	return (-1);
+}
+#endif /* SYS__sysctl */
+
+static const int cl[] = {
+	CLOCK_REALTIME,
+#ifdef CLOCK_MONOTONIC
+	CLOCK_MONOTONIC,
+#endif
+#ifdef CLOCK_MONOTONIC_RAW
+	CLOCK_MONOTONIC_RAW,
+#endif
+#ifdef CLOCK_TAI
+	CLOCK_TAI,
+#endif
+#ifdef CLOCK_VIRTUAL
+	CLOCK_VIRTUAL,
+#endif
+#ifdef CLOCK_UPTIME
+	CLOCK_UPTIME,
+#endif
+#ifdef CLOCK_PROCESS_CPUTIME_ID
+	CLOCK_PROCESS_CPUTIME_ID,
+#endif
+#ifdef CLOCK_THREAD_CPUTIME_ID
+	CLOCK_THREAD_CPUTIME_ID,
+#endif
+};
+
+static int
+getentropy_phdr(struct dl_phdr_info *info, size_t size, void *data)
+{
+	SHA512_CTX *ctx = data;
+
+	SHA512_Update(ctx, &info->dlpi_addr, sizeof (info->dlpi_addr));
+	return (0);
+}
+
+static int
+getentropy_fallback(void *buf, size_t len)
+{
+	uint8_t results[SHA512_DIGEST_LENGTH];
+	int save_errno = errno, e, pgs = getpagesize(), faster = 0, repeat;
+	static int cnt;
+	struct timespec ts;
+	struct timeval tv;
+	struct rusage ru;
+	sigset_t sigset;
+	struct stat st;
+	SHA512_CTX ctx;
+	static pid_t lastpid;
+	pid_t pid;
+	size_t i, ii, m;
+	char *p;
+
+	pid = getpid();
+	if (lastpid == pid) {
+		faster = 1;
+		repeat = 2;
+	} else {
+		faster = 0;
+		lastpid = pid;
+		repeat = REPEAT;
+	}
+	for (i = 0; i < len; ) {
+		int j;
+		SHA512_Init(&ctx);
+		for (j = 0; j < repeat; j++) {
+			HX((e = gettimeofday(&tv, NULL)) == -1, tv);
+			if (e != -1) {
+				cnt += (int)tv.tv_sec;
+				cnt += (int)tv.tv_usec;
+			}
+
+			dl_iterate_phdr(getentropy_phdr, &ctx);
+
+			for (ii = 0; ii < sizeof(cl)/sizeof(cl[0]); ii++)
+				HX(clock_gettime(cl[ii], &ts) == -1, ts);
+
+			HX((pid = getpid()) == -1, pid);
+			HX((pid = getsid(pid)) == -1, pid);
+			HX((pid = getppid()) == -1, pid);
+			HX((pid = getpgid(0)) == -1, pid);
+			HX((e = getpriority(0, 0)) == -1, e);
+
+			if (!faster) {
+				ts.tv_sec = 0;
+				ts.tv_nsec = 1;
+				(void) nanosleep(&ts, NULL);
+			}
+
+			HX(sigpending(&sigset) == -1, sigset);
+			HX(sigprocmask(SIG_BLOCK, NULL, &sigset) == -1,
+			    sigset);
+
+			HF(getentropy);	/* an addr in this library */
+			HF(printf);		/* an addr in libc */
+			p = (char *)&p;
+			HD(p);		/* an addr on stack */
+			p = (char *)&errno;
+			HD(p);		/* the addr of errno */
+
+			if (i == 0) {
+				struct sockaddr_storage ss;
+				struct statvfs stvfs;
+				struct termios tios;
+				struct statfs stfs;
+				socklen_t ssl;
+				off_t off;
+
+				/*
+				 * Prime-sized mappings encourage fragmentation;
+				 * thus exposing some address entropy.
+				 */
+				struct mm {
+					size_t	npg;
+					void	*p;
+				} mm[] =	 {
+					{ 17, MAP_FAILED }, { 3, MAP_FAILED },
+					{ 11, MAP_FAILED }, { 2, MAP_FAILED },
+					{ 5, MAP_FAILED }, { 3, MAP_FAILED },
+					{ 7, MAP_FAILED }, { 1, MAP_FAILED },
+					{ 57, MAP_FAILED }, { 3, MAP_FAILED },
+					{ 131, MAP_FAILED }, { 1, MAP_FAILED },
+				};
+
+				for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) {
+					HX(mm[m].p = mmap(NULL,
+					    mm[m].npg * pgs,
+					    PROT_READ|PROT_WRITE,
+					    MAP_PRIVATE|MAP_ANON, -1,
+					    (off_t)0), mm[m].p);
+					if (mm[m].p != MAP_FAILED) {
+						size_t mo;
+
+						/* Touch some memory... */
+						p = mm[m].p;
+						mo = cnt %
+						    (mm[m].npg * pgs - 1);
+						p[mo] = 1;
+						cnt += (int)((long)(mm[m].p)
+						    / pgs);
+					}
+
+					/* Check cnts and times... */
+					for (ii = 0; ii < sizeof(cl)/sizeof(cl[0]);
+					    ii++) {
+						HX((e = clock_gettime(cl[ii],
+						    &ts)) == -1, ts);
+						if (e != -1)
+							cnt += (int)ts.tv_nsec;
+					}
+
+					HX((e = getrusage(RUSAGE_SELF,
+					    &ru)) == -1, ru);
+					if (e != -1) {
+						cnt += (int)ru.ru_utime.tv_sec;
+						cnt += (int)ru.ru_utime.tv_usec;
+					}
+				}
+
+				for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) {
+					if (mm[m].p != MAP_FAILED)
+						munmap(mm[m].p, mm[m].npg * pgs);
+					mm[m].p = MAP_FAILED;
+				}
+
+				HX(stat(".", &st) == -1, st);
+				HX(statvfs(".", &stvfs) == -1, stvfs);
+				HX(statfs(".", &stfs) == -1, stfs);
+
+				HX(stat("/", &st) == -1, st);
+				HX(statvfs("/", &stvfs) == -1, stvfs);
+				HX(statfs("/", &stfs) == -1, stfs);
+
+				HX((e = fstat(0, &st)) == -1, st);
+				if (e == -1) {
+					if (S_ISREG(st.st_mode) ||
+					    S_ISFIFO(st.st_mode) ||
+					    S_ISSOCK(st.st_mode)) {
+						HX(fstatvfs(0, &stvfs) == -1,
+						    stvfs);
+						HX(fstatfs(0, &stfs) == -1,
+						    stfs);
+						HX((off = lseek(0, (off_t)0,
+						    SEEK_CUR)) < 0, off);
+					}
+					if (S_ISCHR(st.st_mode)) {
+						HX(tcgetattr(0, &tios) == -1,
+						    tios);
+					} else if (S_ISSOCK(st.st_mode)) {
+						memset(&ss, 0, sizeof ss);
+						ssl = sizeof(ss);
+						HX(getpeername(0,
+						    (void *)&ss, &ssl) == -1,
+						    ss);
+					}
+				}
+
+				HX((e = getrusage(RUSAGE_CHILDREN,
+				    &ru)) == -1, ru);
+				if (e != -1) {
+					cnt += (int)ru.ru_utime.tv_sec;
+					cnt += (int)ru.ru_utime.tv_usec;
+				}
+			} else {
+				/* Subsequent hashes absorb previous result */
+				HD(results);
+			}
+
+			HX((e = gettimeofday(&tv, NULL)) == -1, tv);
+			if (e != -1) {
+				cnt += (int)tv.tv_sec;
+				cnt += (int)tv.tv_usec;
+			}
+
+			HD(cnt);
+		}
+#ifdef HAVE_GETAUXVAL
+#ifdef AT_RANDOM
+		/* Not as random as you think but we take what we are given */
+		p = (char *) getauxval(AT_RANDOM);
+		if (p)
+			HR(p, 16);
+#endif
+#ifdef AT_SYSINFO_EHDR
+		p = (char *) getauxval(AT_SYSINFO_EHDR);
+		if (p)
+			HR(p, pgs);
+#endif
+#ifdef AT_BASE
+		p = (char *) getauxval(AT_BASE);
+		if (p)
+			HD(p);
+#endif
+#endif
+
+		SHA512_Final(results, &ctx);
+		memcpy((char *)buf + i, results, min(sizeof(results), len - i));
+		i += min(sizeof(results), len - i);
+	}
+	explicit_bzero(&ctx, sizeof ctx);
+	explicit_bzero(results, sizeof results);
+	if (gotdata(buf, len) == 0) {
+		errno = save_errno;
+		return (0);		/* satisfied */
+	}
+	errno = EIO;
+	return (-1);
+}
diff --git a/src/getentropy_osx.c b/src/getentropy_osx.c
new file mode 100644
index 0000000..db67c4b
--- /dev/null
+++ b/src/getentropy_osx.c
@@ -0,0 +1,429 @@
+/*	$OpenBSD: getentropy_osx.c,v 1.8 2014/07/21 20:19:47 guenther Exp $	*/
+
+/*
+ * Copyright (c) 2014 Theo de Raadt <deraadt at openbsd.org>
+ * Copyright (c) 2014 Bob Beck <beck at obtuse.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Emulation of getentropy(2) as documented at:
+ * http://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man2/getentropy.2
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/resource.h>
+#include <sys/syscall.h>
+#include <sys/sysctl.h>
+#include <sys/statvfs.h>
+#include <sys/socket.h>
+#include <sys/mount.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <termios.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <time.h>
+#include <mach/mach_time.h>
+#include <mach/mach_host.h>
+#include <mach/host_info.h>
+#include <sys/socketvar.h>
+#include <sys/vmmeter.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <netinet/udp.h>
+#include <netinet/ip_var.h>
+#include <netinet/tcp_var.h>
+#include <netinet/udp_var.h>
+#include <CommonCrypto/CommonDigest.h>
+#define SHA512_Update(a, b, c)	(CC_SHA512_Update((a), (b), (c)))
+#define SHA512_Init(xxx) (CC_SHA512_Init((xxx)))
+#define SHA512_Final(xxx, yyy) (CC_SHA512_Final((xxx), (yyy)))
+#define SHA512_CTX CC_SHA512_CTX
+#define SHA512_DIGEST_LENGTH CC_SHA512_DIGEST_LENGTH
+
+#define REPEAT 5
+#define min(a, b) (((a) < (b)) ? (a) : (b))
+
+#define HX(a, b) \
+	do { \
+		if ((a)) \
+			HD(errno); \
+		else \
+			HD(b); \
+	} while (0)
+
+#define HR(x, l) (SHA512_Update(&ctx, (char *)(x), (l)))
+#define HD(x)	 (SHA512_Update(&ctx, (char *)&(x), sizeof (x)))
+#define HF(x)    (SHA512_Update(&ctx, (char *)&(x), sizeof (void*)))
+
+int	getentropy(void *buf, size_t len);
+
+static int gotdata(char *buf, size_t len);
+static int getentropy_urandom(void *buf, size_t len);
+static int getentropy_fallback(void *buf, size_t len);
+
+int
+getentropy(void *buf, size_t len)
+{
+	int ret = -1;
+
+	if (len > 256) {
+		errno = EIO;
+		return (-1);
+	}
+
+	/*
+	 * Try to get entropy with /dev/urandom
+	 *
+	 * This can fail if the process is inside a chroot or if file
+	 * descriptors are exhausted.
+	 */
+	ret = getentropy_urandom(buf, len);
+	if (ret != -1)
+		return (ret);
+
+	/*
+	 * Entropy collection via /dev/urandom and sysctl have failed.
+	 *
+	 * No other API exists for collecting entropy, and we have
+	 * no failsafe way to get it on OSX that is not sensitive
+	 * to resource exhaustion.
+	 *
+	 * We have very few options:
+	 *     - Even syslog_r is unsafe to call at this low level, so
+	 *	 there is no way to alert the user or program.
+	 *     - Cannot call abort() because some systems have unsafe
+	 *	 corefiles.
+	 *     - Could raise(SIGKILL) resulting in silent program termination.
+	 *     - Return EIO, to hint that arc4random's stir function
+	 *       should raise(SIGKILL)
+	 *     - Do the best under the circumstances....
+	 *
+	 * This code path exists to bring light to the issue that OSX
+	 * does not provide a failsafe API for entropy collection.
+	 *
+	 * We hope this demonstrates that OSX should consider
+	 * providing a new failsafe API which works in a chroot or
+	 * when file descriptors are exhausted.
+	 */
+#undef FAIL_INSTEAD_OF_TRYING_FALLBACK
+#ifdef FAIL_INSTEAD_OF_TRYING_FALLBACK
+	raise(SIGKILL);
+#endif
+	ret = getentropy_fallback(buf, len);
+	if (ret != -1)
+		return (ret);
+
+	errno = EIO;
+	return (ret);
+}
+
+/*
+ * Basic sanity checking; wish we could do better.
+ */
+static int
+gotdata(char *buf, size_t len)
+{
+	char	any_set = 0;
+	size_t	i;
+
+	for (i = 0; i < len; ++i)
+		any_set |= buf[i];
+	if (any_set == 0)
+		return (-1);
+	return (0);
+}
+
+static int
+getentropy_urandom(void *buf, size_t len)
+{
+	struct stat st;
+	size_t i;
+	int fd, flags;
+	int save_errno = errno;
+
+start:
+
+	flags = O_RDONLY;
+#ifdef O_NOFOLLOW
+	flags |= O_NOFOLLOW;
+#endif
+#ifdef O_CLOEXEC
+	flags |= O_CLOEXEC;
+#endif
+	fd = open("/dev/urandom", flags, 0);
+	if (fd == -1) {
+		if (errno == EINTR)
+			goto start;
+		goto nodevrandom;
+	}
+#ifndef O_CLOEXEC
+	fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
+#endif
+
+	/* Lightly verify that the device node looks sane */
+	if (fstat(fd, &st) == -1 || !S_ISCHR(st.st_mode)) {
+		close(fd);
+		goto nodevrandom;
+	}
+	for (i = 0; i < len; ) {
+		size_t wanted = len - i;
+		ssize_t ret = read(fd, (char *)buf + i, wanted);
+
+		if (ret == -1) {
+			if (errno == EAGAIN || errno == EINTR)
+				continue;
+			close(fd);
+			goto nodevrandom;
+		}
+		i += ret;
+	}
+	close(fd);
+	if (gotdata(buf, len) == 0) {
+		errno = save_errno;
+		return (0);		/* satisfied */
+	}
+nodevrandom:
+	errno = EIO;
+	return (-1);
+}
+
+static int tcpmib[] = { CTL_NET, AF_INET, IPPROTO_TCP, TCPCTL_STATS };
+static int udpmib[] = { CTL_NET, AF_INET, IPPROTO_UDP, UDPCTL_STATS };
+static int ipmib[] = { CTL_NET, AF_INET, IPPROTO_IP, IPCTL_STATS };
+static int kmib[] = { CTL_KERN, KERN_USRSTACK };
+static int hwmib[] = { CTL_HW, HW_USERMEM };
+
+static int
+getentropy_fallback(void *buf, size_t len)
+{
+	uint8_t results[SHA512_DIGEST_LENGTH];
+	int save_errno = errno, e, pgs = getpagesize(), faster = 0, repeat;
+	static int cnt;
+	struct timespec ts;
+	struct timeval tv;
+	struct rusage ru;
+	sigset_t sigset;
+	struct stat st;
+	SHA512_CTX ctx;
+	static pid_t lastpid;
+	pid_t pid;
+	size_t i, ii, m;
+	char *p;
+	struct tcpstat tcpstat;
+	struct udpstat udpstat;
+	struct ipstat ipstat;
+	uint64_t mach_time;
+	unsigned int idata;
+	void *addr;
+
+	pid = getpid();
+	if (lastpid == pid) {
+		faster = 1;
+		repeat = 2;
+	} else {
+		faster = 0;
+		lastpid = pid;
+		repeat = REPEAT;
+	}
+	for (i = 0; i < len; ) {
+		int j;
+		SHA512_Init(&ctx);
+		for (j = 0; j < repeat; j++) {
+			HX((e = gettimeofday(&tv, NULL)) == -1, tv);
+			if (e != -1) {
+				cnt += (int)tv.tv_sec;
+				cnt += (int)tv.tv_usec;
+			}
+
+			mach_time = mach_absolute_time();
+			HD(mach_time);
+
+			ii = sizeof(addr);
+			HX(sysctl(kmib, sizeof(kmib) / sizeof(kmib[0]),
+			    &addr, &ii, NULL, 0) == -1, addr);
+
+			ii = sizeof(idata);
+			HX(sysctl(hwmib, sizeof(hwmib) / sizeof(hwmib[0]),
+			    &idata, &ii, NULL, 0) == -1, idata);
+
+			ii = sizeof(tcpstat);
+			HX(sysctl(tcpmib, sizeof(tcpmib) / sizeof(tcpmib[0]),
+			    &tcpstat, &ii, NULL, 0) == -1, tcpstat);
+
+			ii = sizeof(udpstat);
+			HX(sysctl(udpmib, sizeof(udpmib) / sizeof(udpmib[0]),
+			    &udpstat, &ii, NULL, 0) == -1, udpstat);
+
+			ii = sizeof(ipstat);
+			HX(sysctl(ipmib, sizeof(ipmib) / sizeof(ipmib[0]),
+			    &ipstat, &ii, NULL, 0) == -1, ipstat);
+
+			HX((pid = getpid()) == -1, pid);
+			HX((pid = getsid(pid)) == -1, pid);
+			HX((pid = getppid()) == -1, pid);
+			HX((pid = getpgid(0)) == -1, pid);
+			HX((e = getpriority(0, 0)) == -1, e);
+
+			if (!faster) {
+				ts.tv_sec = 0;
+				ts.tv_nsec = 1;
+				(void) nanosleep(&ts, NULL);
+			}
+
+			HX(sigpending(&sigset) == -1, sigset);
+			HX(sigprocmask(SIG_BLOCK, NULL, &sigset) == -1,
+			    sigset);
+
+			HF(getentropy);	/* an addr in this library */
+			HF(printf);		/* an addr in libc */
+			p = (char *)&p;
+			HD(p);		/* an addr on stack */
+			p = (char *)&errno;
+			HD(p);		/* the addr of errno */
+
+			if (i == 0) {
+				struct sockaddr_storage ss;
+				struct statvfs stvfs;
+				struct termios tios;
+				struct statfs stfs;
+				socklen_t ssl;
+				off_t off;
+
+				/*
+				 * Prime-sized mappings encourage fragmentation;
+				 * thus exposing some address entropy.
+				 */
+				struct mm {
+					size_t	npg;
+					void	*p;
+				} mm[] =	 {
+					{ 17, MAP_FAILED }, { 3, MAP_FAILED },
+					{ 11, MAP_FAILED }, { 2, MAP_FAILED },
+					{ 5, MAP_FAILED }, { 3, MAP_FAILED },
+					{ 7, MAP_FAILED }, { 1, MAP_FAILED },
+					{ 57, MAP_FAILED }, { 3, MAP_FAILED },
+					{ 131, MAP_FAILED }, { 1, MAP_FAILED },
+				};
+
+				for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) {
+					HX(mm[m].p = mmap(NULL,
+					    mm[m].npg * pgs,
+					    PROT_READ|PROT_WRITE,
+					    MAP_PRIVATE|MAP_ANON, -1,
+					    (off_t)0), mm[m].p);
+					if (mm[m].p != MAP_FAILED) {
+						size_t mo;
+
+						/* Touch some memory... */
+						p = mm[m].p;
+						mo = cnt %
+						    (mm[m].npg * pgs - 1);
+						p[mo] = 1;
+						cnt += (int)((long)(mm[m].p)
+						    / pgs);
+					}
+
+					/* Check cnts and times... */
+					mach_time = mach_absolute_time();
+					HD(mach_time);
+					cnt += (int)mach_time;
+
+					HX((e = getrusage(RUSAGE_SELF,
+					    &ru)) == -1, ru);
+					if (e != -1) {
+						cnt += (int)ru.ru_utime.tv_sec;
+						cnt += (int)ru.ru_utime.tv_usec;
+					}
+				}
+
+				for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) {
+					if (mm[m].p != MAP_FAILED)
+						munmap(mm[m].p, mm[m].npg * pgs);
+					mm[m].p = MAP_FAILED;
+				}
+
+				HX(stat(".", &st) == -1, st);
+				HX(statvfs(".", &stvfs) == -1, stvfs);
+				HX(statfs(".", &stfs) == -1, stfs);
+
+				HX(stat("/", &st) == -1, st);
+				HX(statvfs("/", &stvfs) == -1, stvfs);
+				HX(statfs("/", &stfs) == -1, stfs);
+
+				HX((e = fstat(0, &st)) == -1, st);
+				if (e == -1) {
+					if (S_ISREG(st.st_mode) ||
+					    S_ISFIFO(st.st_mode) ||
+					    S_ISSOCK(st.st_mode)) {
+						HX(fstatvfs(0, &stvfs) == -1,
+						    stvfs);
+						HX(fstatfs(0, &stfs) == -1,
+						    stfs);
+						HX((off = lseek(0, (off_t)0,
+						    SEEK_CUR)) < 0, off);
+					}
+					if (S_ISCHR(st.st_mode)) {
+						HX(tcgetattr(0, &tios) == -1,
+						    tios);
+					} else if (S_ISSOCK(st.st_mode)) {
+						memset(&ss, 0, sizeof ss);
+						ssl = sizeof(ss);
+						HX(getpeername(0,
+						    (void *)&ss, &ssl) == -1,
+						    ss);
+					}
+				}
+
+				HX((e = getrusage(RUSAGE_CHILDREN,
+				    &ru)) == -1, ru);
+				if (e != -1) {
+					cnt += (int)ru.ru_utime.tv_sec;
+					cnt += (int)ru.ru_utime.tv_usec;
+				}
+			} else {
+				/* Subsequent hashes absorb previous result */
+				HD(results);
+			}
+
+			HX((e = gettimeofday(&tv, NULL)) == -1, tv);
+			if (e != -1) {
+				cnt += (int)tv.tv_sec;
+				cnt += (int)tv.tv_usec;
+			}
+
+			HD(cnt);
+		}
+
+		SHA512_Final(results, &ctx);
+		memcpy((char *)buf + i, results, min(sizeof(results), len - i));
+		i += min(sizeof(results), len - i);
+	}
+	explicit_bzero(&ctx, sizeof ctx);
+	explicit_bzero(results, sizeof results);
+	if (gotdata(buf, len) == 0) {
+		errno = save_errno;
+		return (0);		/* satisfied */
+	}
+	errno = EIO;
+	return (-1);
+}
diff --git a/src/getentropy_solaris.c b/src/getentropy_solaris.c
new file mode 100644
index 0000000..ca787f8
--- /dev/null
+++ b/src/getentropy_solaris.c
@@ -0,0 +1,445 @@
+/*	$OpenBSD: getentropy_solaris.c,v 1.10 2015/08/25 17:26:43 deraadt Exp $	*/
+
+/*
+ * Copyright (c) 2014 Theo de Raadt <deraadt at openbsd.org>
+ * Copyright (c) 2014 Bob Beck <beck at obtuse.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Emulation of getentropy(2) as documented at:
+ * http://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man2/getentropy.2
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/resource.h>
+#include <sys/syscall.h>
+#include <sys/statvfs.h>
+#include <sys/socket.h>
+#include <sys/mount.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <link.h>
+#include <termios.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/sha2.h>
+#define SHA512_Init SHA512Init
+#define SHA512_Update SHA512Update
+#define SHA512_Final SHA512Final
+
+#include <sys/vfs.h>
+#include <sys/statfs.h>
+#include <sys/loadavg.h>
+
+#define REPEAT 5
+#define min(a, b) (((a) < (b)) ? (a) : (b))
+
+#define HX(a, b) \
+	do { \
+		if ((a)) \
+			HD(errno); \
+		else \
+			HD(b); \
+	} while (0)
+
+#define HR(x, l) (SHA512_Update(&ctx, (char *)(x), (l)))
+#define HD(x)	 (SHA512_Update(&ctx, (char *)&(x), sizeof (x)))
+#define HF(x)    (SHA512_Update(&ctx, (char *)&(x), sizeof (void*)))
+
+int	getentropy(void *buf, size_t len);
+
+static int gotdata(char *buf, size_t len);
+static int getentropy_urandom(void *buf, size_t len, const char *path,
+    int devfscheck);
+static int getentropy_fallback(void *buf, size_t len);
+static int getentropy_phdr(struct dl_phdr_info *info, size_t size, void *data);
+
+int
+getentropy(void *buf, size_t len)
+{
+	int ret = -1;
+
+	if (len > 256) {
+		errno = EIO;
+		return (-1);
+	}
+
+	/*
+	 * Try to get entropy with /dev/urandom
+	 *
+	 * Solaris provides /dev/urandom as a symbolic link to
+	 * /devices/pseudo/random at 0:urandom which is provided by
+	 * a devfs filesystem.  Best practice is to use O_NOFOLLOW,
+	 * so we must try the unpublished name directly.
+	 *
+	 * This can fail if the process is inside a chroot which lacks
+	 * the devfs mount, or if file descriptors are exhausted.
+	 */
+	ret = getentropy_urandom(buf, len,
+	    "/devices/pseudo/random at 0:urandom", 1);
+	if (ret != -1)
+		return (ret);
+
+	/*
+	 * Unfortunately, chroot spaces on Solaris are sometimes setup
+	 * with direct device node of the well-known /dev/urandom name
+	 * (perhaps to avoid dragging all of devfs into the space).
+	 *
+	 * This can fail if the process is inside a chroot or if file
+	 * descriptors are exhausted.
+	 */
+	ret = getentropy_urandom(buf, len, "/dev/urandom", 0);
+	if (ret != -1)
+		return (ret);
+
+	/*
+	 * Entropy collection via /dev/urandom has failed.
+	 *
+	 * No other API exists for collecting entropy, and we have
+	 * no failsafe way to get it on Solaris that is not sensitive
+	 * to resource exhaustion.
+	 *
+	 * We have very few options:
+	 *     - Even syslog_r is unsafe to call at this low level, so
+	 *	 there is no way to alert the user or program.
+	 *     - Cannot call abort() because some systems have unsafe
+	 *	 corefiles.
+	 *     - Could raise(SIGKILL) resulting in silent program termination.
+	 *     - Return EIO, to hint that arc4random's stir function
+	 *       should raise(SIGKILL)
+	 *     - Do the best under the circumstances....
+	 *
+	 * This code path exists to bring light to the issue that Solaris
+	 * does not provide a failsafe API for entropy collection.
+	 *
+	 * We hope this demonstrates that Solaris should consider
+	 * providing a new failsafe API which works in a chroot or
+	 * when file descriptors are exhausted.
+	 */
+#undef FAIL_INSTEAD_OF_TRYING_FALLBACK
+#ifdef FAIL_INSTEAD_OF_TRYING_FALLBACK
+	raise(SIGKILL);
+#endif
+	ret = getentropy_fallback(buf, len);
+	if (ret != -1)
+		return (ret);
+
+	errno = EIO;
+	return (ret);
+}
+
+/*
+ * Basic sanity checking; wish we could do better.
+ */
+static int
+gotdata(char *buf, size_t len)
+{
+	char	any_set = 0;
+	size_t	i;
+
+	for (i = 0; i < len; ++i)
+		any_set |= buf[i];
+	if (any_set == 0)
+		return (-1);
+	return (0);
+}
+
+static int
+getentropy_urandom(void *buf, size_t len, const char *path, int devfscheck)
+{
+	struct stat st;
+	size_t i;
+	int fd, flags;
+	int save_errno = errno;
+
+start:
+
+	flags = O_RDONLY;
+#ifdef O_NOFOLLOW
+	flags |= O_NOFOLLOW;
+#endif
+#ifdef O_CLOEXEC
+	flags |= O_CLOEXEC;
+#endif
+	fd = open(path, flags, 0);
+	if (fd == -1) {
+		if (errno == EINTR)
+			goto start;
+		goto nodevrandom;
+	}
+#ifndef O_CLOEXEC
+	fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
+#endif
+
+	/* Lightly verify that the device node looks sane */
+	if (fstat(fd, &st) == -1 || !S_ISCHR(st.st_mode) ||
+	    (devfscheck && (strcmp(st.st_fstype, "devfs") != 0))) {
+		close(fd);
+		goto nodevrandom;
+	}
+	for (i = 0; i < len; ) {
+		size_t wanted = len - i;
+		ssize_t ret = read(fd, (char *)buf + i, wanted);
+
+		if (ret == -1) {
+			if (errno == EAGAIN || errno == EINTR)
+				continue;
+			close(fd);
+			goto nodevrandom;
+		}
+		i += ret;
+	}
+	close(fd);
+	if (gotdata(buf, len) == 0) {
+		errno = save_errno;
+		return (0);		/* satisfied */
+	}
+nodevrandom:
+	errno = EIO;
+	return (-1);
+}
+
+static const int cl[] = {
+	CLOCK_REALTIME,
+#ifdef CLOCK_MONOTONIC
+	CLOCK_MONOTONIC,
+#endif
+#ifdef CLOCK_MONOTONIC_RAW
+	CLOCK_MONOTONIC_RAW,
+#endif
+#ifdef CLOCK_TAI
+	CLOCK_TAI,
+#endif
+#ifdef CLOCK_VIRTUAL
+	CLOCK_VIRTUAL,
+#endif
+#ifdef CLOCK_UPTIME
+	CLOCK_UPTIME,
+#endif
+#ifdef CLOCK_PROCESS_CPUTIME_ID
+	CLOCK_PROCESS_CPUTIME_ID,
+#endif
+#ifdef CLOCK_THREAD_CPUTIME_ID
+	CLOCK_THREAD_CPUTIME_ID,
+#endif
+};
+
+static int
+getentropy_phdr(struct dl_phdr_info *info, size_t size, void *data)
+{
+	SHA512_CTX *ctx = data;
+
+	SHA512_Update(ctx, &info->dlpi_addr, sizeof (info->dlpi_addr));
+	return (0);
+}
+
+static int
+getentropy_fallback(void *buf, size_t len)
+{
+	uint8_t results[SHA512_DIGEST_LENGTH];
+	int save_errno = errno, e, pgs = getpagesize(), faster = 0, repeat;
+	static int cnt;
+	struct timespec ts;
+	struct timeval tv;
+	double loadavg[3];
+	struct rusage ru;
+	sigset_t sigset;
+	struct stat st;
+	SHA512_CTX ctx;
+	static pid_t lastpid;
+	pid_t pid;
+	size_t i, ii, m;
+	char *p;
+
+	pid = getpid();
+	if (lastpid == pid) {
+		faster = 1;
+		repeat = 2;
+	} else {
+		faster = 0;
+		lastpid = pid;
+		repeat = REPEAT;
+	}
+	for (i = 0; i < len; ) {
+		int j;
+		SHA512_Init(&ctx);
+		for (j = 0; j < repeat; j++) {
+			HX((e = gettimeofday(&tv, NULL)) == -1, tv);
+			if (e != -1) {
+				cnt += (int)tv.tv_sec;
+				cnt += (int)tv.tv_usec;
+			}
+
+			dl_iterate_phdr(getentropy_phdr, &ctx);
+
+			for (ii = 0; ii < sizeof(cl)/sizeof(cl[0]); ii++)
+				HX(clock_gettime(cl[ii], &ts) == -1, ts);
+
+			HX((pid = getpid()) == -1, pid);
+			HX((pid = getsid(pid)) == -1, pid);
+			HX((pid = getppid()) == -1, pid);
+			HX((pid = getpgid(0)) == -1, pid);
+			HX((e = getpriority(0, 0)) == -1, e);
+			HX((getloadavg(loadavg, 3) == -1), loadavg);
+
+			if (!faster) {
+				ts.tv_sec = 0;
+				ts.tv_nsec = 1;
+				(void) nanosleep(&ts, NULL);
+			}
+
+			HX(sigpending(&sigset) == -1, sigset);
+			HX(sigprocmask(SIG_BLOCK, NULL, &sigset) == -1,
+			    sigset);
+
+			HF(getentropy);	/* an addr in this library */
+			HF(printf);		/* an addr in libc */
+			p = (char *)&p;
+			HD(p);		/* an addr on stack */
+			p = (char *)&errno;
+			HD(p);		/* the addr of errno */
+
+			if (i == 0) {
+				struct sockaddr_storage ss;
+				struct statvfs stvfs;
+				struct termios tios;
+				socklen_t ssl;
+				off_t off;
+
+				/*
+				 * Prime-sized mappings encourage fragmentation;
+				 * thus exposing some address entropy.
+				 */
+				struct mm {
+					size_t	npg;
+					void	*p;
+				} mm[] =	 {
+					{ 17, MAP_FAILED }, { 3, MAP_FAILED },
+					{ 11, MAP_FAILED }, { 2, MAP_FAILED },
+					{ 5, MAP_FAILED }, { 3, MAP_FAILED },
+					{ 7, MAP_FAILED }, { 1, MAP_FAILED },
+					{ 57, MAP_FAILED }, { 3, MAP_FAILED },
+					{ 131, MAP_FAILED }, { 1, MAP_FAILED },
+				};
+
+				for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) {
+					HX(mm[m].p = mmap(NULL,
+					    mm[m].npg * pgs,
+					    PROT_READ|PROT_WRITE,
+					    MAP_PRIVATE|MAP_ANON, -1,
+					    (off_t)0), mm[m].p);
+					if (mm[m].p != MAP_FAILED) {
+						size_t mo;
+
+						/* Touch some memory... */
+						p = mm[m].p;
+						mo = cnt %
+						    (mm[m].npg * pgs - 1);
+						p[mo] = 1;
+						cnt += (int)((long)(mm[m].p)
+						    / pgs);
+					}
+
+					/* Check cnts and times... */
+					for (ii = 0; ii < sizeof(cl)/sizeof(cl[0]);
+					    ii++) {
+						HX((e = clock_gettime(cl[ii],
+						    &ts)) == -1, ts);
+						if (e != -1)
+							cnt += (int)ts.tv_nsec;
+					}
+
+					HX((e = getrusage(RUSAGE_SELF,
+					    &ru)) == -1, ru);
+					if (e != -1) {
+						cnt += (int)ru.ru_utime.tv_sec;
+						cnt += (int)ru.ru_utime.tv_usec;
+					}
+				}
+
+				for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) {
+					if (mm[m].p != MAP_FAILED)
+						munmap(mm[m].p, mm[m].npg * pgs);
+					mm[m].p = MAP_FAILED;
+				}
+
+				HX(stat(".", &st) == -1, st);
+				HX(statvfs(".", &stvfs) == -1, stvfs);
+
+				HX(stat("/", &st) == -1, st);
+				HX(statvfs("/", &stvfs) == -1, stvfs);
+
+				HX((e = fstat(0, &st)) == -1, st);
+				if (e == -1) {
+					if (S_ISREG(st.st_mode) ||
+					    S_ISFIFO(st.st_mode) ||
+					    S_ISSOCK(st.st_mode)) {
+						HX(fstatvfs(0, &stvfs) == -1,
+						    stvfs);
+						HX((off = lseek(0, (off_t)0,
+						    SEEK_CUR)) < 0, off);
+					}
+					if (S_ISCHR(st.st_mode)) {
+						HX(tcgetattr(0, &tios) == -1,
+						    tios);
+					} else if (S_ISSOCK(st.st_mode)) {
+						memset(&ss, 0, sizeof ss);
+						ssl = sizeof(ss);
+						HX(getpeername(0,
+						    (void *)&ss, &ssl) == -1,
+						    ss);
+					}
+				}
+
+				HX((e = getrusage(RUSAGE_CHILDREN,
+				    &ru)) == -1, ru);
+				if (e != -1) {
+					cnt += (int)ru.ru_utime.tv_sec;
+					cnt += (int)ru.ru_utime.tv_usec;
+				}
+			} else {
+				/* Subsequent hashes absorb previous result */
+				HD(results);
+			}
+
+			HX((e = gettimeofday(&tv, NULL)) == -1, tv);
+			if (e != -1) {
+				cnt += (int)tv.tv_sec;
+				cnt += (int)tv.tv_usec;
+			}
+
+			HD(cnt);
+		}
+		SHA512_Final(results, &ctx);
+		memcpy((char *)buf + i, results, min(sizeof(results), len - i));
+		i += min(sizeof(results), len - i);
+	}
+	explicit_bzero(&ctx, sizeof ctx);
+	explicit_bzero(results, sizeof results);
+	if (gotdata(buf, len) == 0) {
+		errno = save_errno;
+		return (0);		/* satisfied */
+	}
+	errno = EIO;
+	return (-1);
+}
commit 5f9265f81601f591336616a4acd3bae0ece4b6fc
Author: Guillem Jover <guillem at hadrons.org>
Date:   Wed Sep 23 20:13:33 2015 +0200

    Add private SHA512 module from FreeBSD

diff --git a/src/Makefile.am b/src/Makefile.am
index 1b324aa..c8db76e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -67,6 +67,8 @@ libbsd_la_SOURCES = \
 	getpeereid.c \
 	hash/md5.c \
 	hash/md5hl.c \
+	hash/sha512.h \
+	hash/sha512c.c \
 	heapsort.c \
 	humanize_number.c \
 	inet_net_pton.c \
diff --git a/src/hash/sha512.h b/src/hash/sha512.h
new file mode 100644
index 0000000..43c5aaf
--- /dev/null
+++ b/src/hash/sha512.h
@@ -0,0 +1,51 @@
+/*-
+ * Copyright 2005 Colin Percival
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _SHA512_H_
+#define _SHA512_H_
+
+#include <sys/types.h>
+
+typedef struct SHA512Context {
+	uint64_t state[8];
+	uint64_t count[2];
+	unsigned char buf[128];
+} SHA512_CTX;
+
+__BEGIN_DECLS
+
+void	SHA512_Init(SHA512_CTX *);
+void	SHA512_Update(SHA512_CTX *, const void *, size_t);
+void	SHA512_Final(unsigned char [64], SHA512_CTX *);
+char   *SHA512_End(SHA512_CTX *, char *);
+char   *SHA512_File(const char *, char *);
+char   *SHA512_FileChunk(const char *, char *, off_t, off_t);
+char   *SHA512_Data(const void *, unsigned int, char *);
+__END_DECLS
+
+#endif /* !_SHA512_H_ */
diff --git a/src/hash/sha512c.c b/src/hash/sha512c.c
new file mode 100644
index 0000000..c2a93be
--- /dev/null
+++ b/src/hash/sha512c.c
@@ -0,0 +1,320 @@
+/*-
+ * Copyright 2005 Colin Percival
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/endian.h>
+#include <sys/types.h>
+
+#include <string.h>
+
+#include "sha512.h"
+
+#if BYTE_ORDER == BIG_ENDIAN
+
+/* Copy a vector of big-endian uint64_t into a vector of bytes */
+#define be64enc_vect(dst, src, len)	\
+	memcpy((void *)dst, (const void *)src, (size_t)len)
+
+/* Copy a vector of bytes into a vector of big-endian uint64_t */
+#define be64dec_vect(dst, src, len)	\
+	memcpy((void *)dst, (const void *)src, (size_t)len)
+
+#else /* BYTE_ORDER != BIG_ENDIAN */
+
+/*
+ * Encode a length len/4 vector of (uint64_t) into a length len vector of
+ * (unsigned char) in big-endian form.  Assumes len is a multiple of 8.
+ */
+static void
+be64enc_vect(unsigned char *dst, const uint64_t *src, size_t len)
+{
+	size_t i;
+
+	for (i = 0; i < len / 8; i++)
+		be64enc(dst + i * 8, src[i]);
+}
+
+/*
+ * Decode a big-endian length len vector of (unsigned char) into a length
+ * len/4 vector of (uint64_t).  Assumes len is a multiple of 8.
+ */
+static void
+be64dec_vect(uint64_t *dst, const unsigned char *src, size_t len)
+{
+	size_t i;
+
+	for (i = 0; i < len / 8; i++)
+		dst[i] = be64dec(src + i * 8);
+}
+
+#endif /* BYTE_ORDER != BIG_ENDIAN */
+
+/* Elementary functions used by SHA512 */
+#define Ch(x, y, z)	((x & (y ^ z)) ^ z)
+#define Maj(x, y, z)	((x & (y | z)) | (y & z))
+#define SHR(x, n)	(x >> n)
+#define ROTR(x, n)	((x >> n) | (x << (64 - n)))
+#define S0(x)		(ROTR(x, 28) ^ ROTR(x, 34) ^ ROTR(x, 39))
+#define S1(x)		(ROTR(x, 14) ^ ROTR(x, 18) ^ ROTR(x, 41))
+#define s0(x)		(ROTR(x, 1) ^ ROTR(x, 8) ^ SHR(x, 7))
+#define s1(x)		(ROTR(x, 19) ^ ROTR(x, 61) ^ SHR(x, 6))
+
+/* SHA512 round function */
+#define RND(a, b, c, d, e, f, g, h, k)			\
+	t0 = h + S1(e) + Ch(e, f, g) + k;		\
+	t1 = S0(a) + Maj(a, b, c);			\
+	d += t0;					\
+	h  = t0 + t1;
+
+/* Adjusted round function for rotating state */
+#define RNDr(S, W, i, k)			\
+	RND(S[(80 - i) % 8], S[(81 - i) % 8],	\
+	    S[(82 - i) % 8], S[(83 - i) % 8],	\
+	    S[(84 - i) % 8], S[(85 - i) % 8],	\
+	    S[(86 - i) % 8], S[(87 - i) % 8],	\
+	    W[i] + k)
+
+/*
+ * SHA512 block compression function.  The 512-bit state is transformed via
+ * the 512-bit input block to produce a new state.
+ */
+static void
+SHA512_Transform(uint64_t * state, const unsigned char block[128])
+{
+	uint64_t W[80];
+	uint64_t S[8];
+	uint64_t t0, t1;
+	int i;
+
+	/* 1. Prepare message schedule W. */
+	be64dec_vect(W, block, 128);
+	for (i = 16; i < 80; i++)
+		W[i] = s1(W[i - 2]) + W[i - 7] + s0(W[i - 15]) + W[i - 16];
+
+	/* 2. Initialize working variables. */
+	memcpy(S, state, 64);
+
+	/* 3. Mix. */
+	RNDr(S, W, 0, 0x428a2f98d728ae22ULL);
+	RNDr(S, W, 1, 0x7137449123ef65cdULL);
+	RNDr(S, W, 2, 0xb5c0fbcfec4d3b2fULL);
+	RNDr(S, W, 3, 0xe9b5dba58189dbbcULL);
+	RNDr(S, W, 4, 0x3956c25bf348b538ULL);
+	RNDr(S, W, 5, 0x59f111f1b605d019ULL);
+	RNDr(S, W, 6, 0x923f82a4af194f9bULL);
+	RNDr(S, W, 7, 0xab1c5ed5da6d8118ULL);
+	RNDr(S, W, 8, 0xd807aa98a3030242ULL);
+	RNDr(S, W, 9, 0x12835b0145706fbeULL);
+	RNDr(S, W, 10, 0x243185be4ee4b28cULL);
+	RNDr(S, W, 11, 0x550c7dc3d5ffb4e2ULL);
+	RNDr(S, W, 12, 0x72be5d74f27b896fULL);
+	RNDr(S, W, 13, 0x80deb1fe3b1696b1ULL);
+	RNDr(S, W, 14, 0x9bdc06a725c71235ULL);
+	RNDr(S, W, 15, 0xc19bf174cf692694ULL);
+	RNDr(S, W, 16, 0xe49b69c19ef14ad2ULL);
+	RNDr(S, W, 17, 0xefbe4786384f25e3ULL);
+	RNDr(S, W, 18, 0x0fc19dc68b8cd5b5ULL);
+	RNDr(S, W, 19, 0x240ca1cc77ac9c65ULL);
+	RNDr(S, W, 20, 0x2de92c6f592b0275ULL);
+	RNDr(S, W, 21, 0x4a7484aa6ea6e483ULL);
+	RNDr(S, W, 22, 0x5cb0a9dcbd41fbd4ULL);
+	RNDr(S, W, 23, 0x76f988da831153b5ULL);
+	RNDr(S, W, 24, 0x983e5152ee66dfabULL);
+	RNDr(S, W, 25, 0xa831c66d2db43210ULL);
+	RNDr(S, W, 26, 0xb00327c898fb213fULL);
+	RNDr(S, W, 27, 0xbf597fc7beef0ee4ULL);
+	RNDr(S, W, 28, 0xc6e00bf33da88fc2ULL);
+	RNDr(S, W, 29, 0xd5a79147930aa725ULL);
+	RNDr(S, W, 30, 0x06ca6351e003826fULL);
+	RNDr(S, W, 31, 0x142929670a0e6e70ULL);
+	RNDr(S, W, 32, 0x27b70a8546d22ffcULL);
+	RNDr(S, W, 33, 0x2e1b21385c26c926ULL);
+	RNDr(S, W, 34, 0x4d2c6dfc5ac42aedULL);
+	RNDr(S, W, 35, 0x53380d139d95b3dfULL);
+	RNDr(S, W, 36, 0x650a73548baf63deULL);
+	RNDr(S, W, 37, 0x766a0abb3c77b2a8ULL);
+	RNDr(S, W, 38, 0x81c2c92e47edaee6ULL);
+	RNDr(S, W, 39, 0x92722c851482353bULL);
+	RNDr(S, W, 40, 0xa2bfe8a14cf10364ULL);
+	RNDr(S, W, 41, 0xa81a664bbc423001ULL);
+	RNDr(S, W, 42, 0xc24b8b70d0f89791ULL);
+	RNDr(S, W, 43, 0xc76c51a30654be30ULL);
+	RNDr(S, W, 44, 0xd192e819d6ef5218ULL);
+	RNDr(S, W, 45, 0xd69906245565a910ULL);
+	RNDr(S, W, 46, 0xf40e35855771202aULL);
+	RNDr(S, W, 47, 0x106aa07032bbd1b8ULL);
+	RNDr(S, W, 48, 0x19a4c116b8d2d0c8ULL);
+	RNDr(S, W, 49, 0x1e376c085141ab53ULL);
+	RNDr(S, W, 50, 0x2748774cdf8eeb99ULL);
+	RNDr(S, W, 51, 0x34b0bcb5e19b48a8ULL);
+	RNDr(S, W, 52, 0x391c0cb3c5c95a63ULL);
+	RNDr(S, W, 53, 0x4ed8aa4ae3418acbULL);
+	RNDr(S, W, 54, 0x5b9cca4f7763e373ULL);
+	RNDr(S, W, 55, 0x682e6ff3d6b2b8a3ULL);
+	RNDr(S, W, 56, 0x748f82ee5defb2fcULL);
+	RNDr(S, W, 57, 0x78a5636f43172f60ULL);
+	RNDr(S, W, 58, 0x84c87814a1f0ab72ULL);
+	RNDr(S, W, 59, 0x8cc702081a6439ecULL);
+	RNDr(S, W, 60, 0x90befffa23631e28ULL);
+	RNDr(S, W, 61, 0xa4506cebde82bde9ULL);
+	RNDr(S, W, 62, 0xbef9a3f7b2c67915ULL);
+	RNDr(S, W, 63, 0xc67178f2e372532bULL);
+	RNDr(S, W, 64, 0xca273eceea26619cULL);
+	RNDr(S, W, 65, 0xd186b8c721c0c207ULL);
+	RNDr(S, W, 66, 0xeada7dd6cde0eb1eULL);
+	RNDr(S, W, 67, 0xf57d4f7fee6ed178ULL);
+	RNDr(S, W, 68, 0x06f067aa72176fbaULL);
+	RNDr(S, W, 69, 0x0a637dc5a2c898a6ULL);
+	RNDr(S, W, 70, 0x113f9804bef90daeULL);
+	RNDr(S, W, 71, 0x1b710b35131c471bULL);
+	RNDr(S, W, 72, 0x28db77f523047d84ULL);
+	RNDr(S, W, 73, 0x32caab7b40c72493ULL);
+	RNDr(S, W, 74, 0x3c9ebe0a15c9bebcULL);
+	RNDr(S, W, 75, 0x431d67c49c100d4cULL);
+	RNDr(S, W, 76, 0x4cc5d4becb3e42b6ULL);
+	RNDr(S, W, 77, 0x597f299cfc657e2aULL);
+	RNDr(S, W, 78, 0x5fcb6fab3ad6faecULL);
+	RNDr(S, W, 79, 0x6c44198c4a475817ULL);
+
+	/* 4. Mix local working variables into global state */
+	for (i = 0; i < 8; i++)
+		state[i] += S[i];
+}
+
+static unsigned char PAD[128] = {
+	0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* Add padding and terminating bit-count. */
+static void
+SHA512_Pad(SHA512_CTX * ctx)
+{
+	unsigned char len[16];
+	uint64_t r, plen;
+
+	/*
+	 * Convert length to a vector of bytes -- we do this now rather
+	 * than later because the length will change after we pad.
+	 */
+	be64enc_vect(len, ctx->count, 16);
+
+	/* Add 1--128 bytes so that the resulting length is 112 mod 128 */
+	r = (ctx->count[1] >> 3) & 0x7f;
+	plen = (r < 112) ? (112 - r) : (240 - r);
+	SHA512_Update(ctx, PAD, (size_t)plen);
+
+	/* Add the terminating bit-count */
+	SHA512_Update(ctx, len, 16);
+}
+
+/* SHA-512 initialization.  Begins a SHA-512 operation. */
+void
+SHA512_Init(SHA512_CTX * ctx)
+{
+
+	/* Zero bits processed so far */
+	ctx->count[0] = ctx->count[1] = 0;
+
+	/* Magic initialization constants */
+	ctx->state[0] = 0x6a09e667f3bcc908ULL;
+	ctx->state[1] = 0xbb67ae8584caa73bULL;
+	ctx->state[2] = 0x3c6ef372fe94f82bULL;
+	ctx->state[3] = 0xa54ff53a5f1d36f1ULL;
+	ctx->state[4] = 0x510e527fade682d1ULL;
+	ctx->state[5] = 0x9b05688c2b3e6c1fULL;
+	ctx->state[6] = 0x1f83d9abfb41bd6bULL;
+	ctx->state[7] = 0x5be0cd19137e2179ULL;
+}
+
+/* Add bytes into the hash */
+void
+SHA512_Update(SHA512_CTX * ctx, const void *in, size_t len)
+{
+	uint64_t bitlen[2];
+	uint64_t r;
+	const unsigned char *src = in;
+
+	/* Number of bytes left in the buffer from previous updates */
+	r = (ctx->count[1] >> 3) & 0x7f;
+
+	/* Convert the length into a number of bits */
+	bitlen[1] = ((uint64_t)len) << 3;
+	bitlen[0] = ((uint64_t)len) >> 61;
+
+	/* Update number of bits */
+	if ((ctx->count[1] += bitlen[1]) < bitlen[1])
+		ctx->count[0]++;
+	ctx->count[0] += bitlen[0];
+
+	/* Handle the case where we don't need to perform any transforms */
+	if (len < 128 - r) {
+		memcpy(&ctx->buf[r], src, len);
+		return;
+	}
+
+	/* Finish the current block */
+	memcpy(&ctx->buf[r], src, 128 - r);
+	SHA512_Transform(ctx->state, ctx->buf);
+	src += 128 - r;
+	len -= 128 - r;
+
+	/* Perform complete blocks */
+	while (len >= 128) {
+		SHA512_Transform(ctx->state, src);
+		src += 128;
+		len -= 128;
+	}
+
+	/* Copy left over data into buffer */
+	memcpy(ctx->buf, src, len);
+}
+
+/*
+ * SHA-512 finalization.  Pads the input data, exports the hash value,
+ * and clears the context state.
+ */
+void
+SHA512_Final(unsigned char digest[64], SHA512_CTX * ctx)
+{
+
+	/* Add padding */
+	SHA512_Pad(ctx);
+
+	/* Write the hash */
+	be64enc_vect(digest, ctx->state, 64);
+
+	/* Clear the context state */
+	memset((void *)ctx, 0, sizeof(*ctx));
+}
commit 1f77cdb40a997575fed193d1edbe16af03ea733e
Author: Marek Vasut <marex at denx.de>
Date:   Mon Nov 30 20:39:00 2015 +0100

    Add NIOS2 support to nlist()
    
    Add support for the NIOS2 soft-core CPU provided by Altera.
    
    Signed-off-by: Marek Vasut <marex at denx.de>
    Signed-off-by: Guillem Jover <guillem at hadrons.org>
    Cc: Ley Foon Tan <lftan at altera.com>
    Cc: Thomas Chou <thomas at wytron.com.tw>
    Cc: Walter Goossens <waltergoossens at home.nl>

diff --git a/src/local-elf.h b/src/local-elf.h
index 612ce12..28d4007 100644
--- a/src/local-elf.h
+++ b/src/local-elf.h
@@ -134,6 +134,12 @@
 #define ELF_TARG_DATA	ELFDATA2LSB
 #endif
 
+#elif defined(__nios2__)
+
+#define ELF_TARG_MACH	EM_ALTERA_NIOS2
+#define ELF_TARG_CLASS	ELFCLASS32
+#define ELF_TARG_DATA	ELFDATA2LSB
+
 #elif defined(__powerpc__)
 
 #define ELF_TARG_MACH	EM_PPC
commit f3b115540c7490c494a82e0b9c09a1dfa1c0f9b5
Author: Guillem Jover <guillem at hadrons.org>
Date:   Mon Nov 30 19:32:48 2015 +0100

    man: Rename funopen.3 to funopen.3bsd to avoid clash with funtools
    
    The funtools project ships a man page with the same, name. And although
    it mith probably make more sense to rename the man page there, as BSD
    systems will certainly not do so, this is the easiest and fastest way
    to avoid a file conflict.

diff --git a/man/Makefile.am b/man/Makefile.am
index f3bcd50..e4d6e4a 100644
--- a/man/Makefile.am
+++ b/man/Makefile.am
@@ -29,7 +29,7 @@ dist_man_MANS = \
 	flopen.3 \
 	fmtcheck.3 \
 	fparseln.3 \
-	funopen.3 \
+	funopen.3bsd \
 	getbsize.3 \
 	getmode.3 \
 	getpeereid.3 \
diff --git a/man/funopen.3 b/man/funopen.3
deleted file mode 100644
index 123c124..0000000
--- a/man/funopen.3
+++ /dev/null
@@ -1,191 +0,0 @@
-.\" Copyright (c) 1990, 1991, 1993
-.\"	The Regents of the University of California.  All rights reserved.
-.\"
-.\" This code is derived from software contributed to Berkeley by
-.\" Chris Torek.
-.\" Redistribution and use in source and binary forms, with or without
-.\" modification, are permitted provided that the following conditions
-.\" are met:
-.\" 1. Redistributions of source code must retain the above copyright
-.\"    notice, this list of conditions and the following disclaimer.
-.\" 2. Redistributions in binary form must reproduce the above copyright
-.\"    notice, this list of conditions and the following disclaimer in the
-.\"    documentation and/or other materials provided with the distribution.
-.\" 4. Neither the name of the University nor the names of its contributors
-.\"    may be used to endorse or promote products derived from this software
-.\"    without specific prior written permission.
-.\"
-.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
-.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
-.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-.\" SUCH DAMAGE.
-.\"
-.\"     @(#)funopen.3	8.1 (Berkeley) 6/9/93
-.\" $FreeBSD$
-.\"
-.Dd March 19, 2004
-.Dt FUNOPEN 3
-.Os
-.Sh NAME
-.Nm funopen ,
-.Nm fropen ,
-.Nm fwopen
-.Nd open a stream
-.Sh LIBRARY
-.ds str-Lb-libbsd Utility functions from BSD systems (libbsd, \-lbsd)
-.Lb libbsd
-.Sh SYNOPSIS
-.In bsd/stdio.h
-.Ft FILE *
-.Fn funopen "const void *cookie" "int (*readfn)(void *, char *, int)" "int (*writefn)(void *, const char *, int)" "off_t (*seekfn)(void *, off_t, int)" "int (*closefn)(void *)"
-.Ft FILE *
-.Fn fropen "void *cookie" "int (*readfn)(void *, char *, int)"
-.Ft FILE *
-.Fn fwopen "void *cookie" "int (*writefn)(void *, const char *, int)"
-.Sh DESCRIPTION
-The
-.Fn funopen
-function
-associates a stream with up to four
-.Dq Tn I/O No functions .
-Either
-.Fa readfn
-or
-.Fa writefn
-must be specified;
-the others can be given as an appropriately-typed
-.Dv NULL
-pointer.
-These
-.Tn I/O
-functions will be used to read, write, seek and
-close the new stream.
-.Pp
-In general, omitting a function means that any attempt to perform the
-associated operation on the resulting stream will fail.
-If the close function is omitted, closing the stream will flush
-any buffered output and then succeed.
-.Pp
-The calling conventions of
-.Fa readfn ,
-.Fa writefn ,
-.Fa seekfn
-and
-.Fa closefn
-must match those, respectively, of
-.Xr read 2 ,
-.Xr write 2 ,
-.Xr lseek 2 ,
-and
-.Xr close 2
-with the single exception that they are passed the
-.Fa cookie
-argument specified to
-.Fn funopen
-in place of the traditional file descriptor argument.
-.Pp
-Read and write
-.Tn I/O
-functions are allowed to change the underlying buffer
-on fully buffered or line buffered streams by calling
-.Xr setvbuf 3 .
-They are also not required to completely fill or empty the buffer.
-They are not, however, allowed to change streams from unbuffered to buffered
-or to change the state of the line buffering flag.
-They must also be prepared to have read or write calls occur on buffers other
-than the one most recently specified.
-.Pp
-All user
-.Tn I/O
-functions can report an error by returning \-1.
-Additionally, all of the functions should set the external variable
-.Va errno
-appropriately if an error occurs.
-.Pp
-An error on
-.Fn closefn
-does not keep the stream open.
-.Pp
-As a convenience, the include file
-.In stdio.h
-defines the macros
-.Fn fropen
-and
-.Fn fwopen
-as calls to
-.Fn funopen
-with only a read or write function specified.
-.Sh RETURN VALUES
-Upon successful completion,
-.Fn funopen
-returns a
-.Dv FILE
-pointer.
-Otherwise,
-.Dv NULL
-is returned and the global variable
-.Va errno
-is set to indicate the error.
-.Sh ERRORS
-.Bl -tag -width Er
-.It Bq Er EINVAL
-The
-.Fn funopen
-function
-was called without either a read or write function.
-The
-.Fn funopen
-function
-may also fail and set
-.Va errno
-for any of the errors
-specified for the routine
-.Xr malloc 3 .
-.El
-.Sh SEE ALSO
-.Xr fcntl 2 ,
-.Xr open 2 ,
-.Xr fclose 3 ,
-.Xr fopen 3 ,
-.Xr fseek 3 ,
-.Xr setbuf 3
-.Sh HISTORY
-The
-.Fn funopen
-functions first appeared in
-.Bx 4.4 .
-.Sh BUGS
-The
-.Fn funopen
-function
-may not be portable to systems other than
-.Bx .
-.Pp
-On
-.Fx ,
-.Ox
-and
-.Dx
-the
-.Fn funopen
-interface erroneously assumes that
-.Vt fpos_t
-is an integral type, and uses it in the
-.Fa seekfn
-hook; but because code using a
-.Fa seekfn
-hook will fail to build on systems where
-.Vt fpos_t
-is a struct, and it will need to be slightly fixed anyway, the
-implementation provided by libbsd (in the same way as
-.Nx )
-uses the correct
-.Vt off_t
-types.
diff --git a/man/funopen.3bsd b/man/funopen.3bsd
new file mode 100644
index 0000000..123c124
--- /dev/null
+++ b/man/funopen.3bsd
@@ -0,0 +1,191 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\"	The Regents of the University of California.  All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek.
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"     @(#)funopen.3	8.1 (Berkeley) 6/9/93
+.\" $FreeBSD$
+.\"
+.Dd March 19, 2004
+.Dt FUNOPEN 3
+.Os
+.Sh NAME
+.Nm funopen ,
+.Nm fropen ,
+.Nm fwopen
+.Nd open a stream
+.Sh LIBRARY
+.ds str-Lb-libbsd Utility functions from BSD systems (libbsd, \-lbsd)
+.Lb libbsd
+.Sh SYNOPSIS
+.In bsd/stdio.h
+.Ft FILE *
+.Fn funopen "const void *cookie" "int (*readfn)(void *, char *, int)" "int (*writefn)(void *, const char *, int)" "off_t (*seekfn)(void *, off_t, int)" "int (*closefn)(void *)"
+.Ft FILE *
+.Fn fropen "void *cookie" "int (*readfn)(void *, char *, int)"
+.Ft FILE *
+.Fn fwopen "void *cookie" "int (*writefn)(void *, const char *, int)"
+.Sh DESCRIPTION
+The
+.Fn funopen
+function
+associates a stream with up to four
+.Dq Tn I/O No functions .
+Either
+.Fa readfn
+or
+.Fa writefn
+must be specified;
+the others can be given as an appropriately-typed
+.Dv NULL
+pointer.
+These
+.Tn I/O
+functions will be used to read, write, seek and
+close the new stream.
+.Pp
+In general, omitting a function means that any attempt to perform the
+associated operation on the resulting stream will fail.
+If the close function is omitted, closing the stream will flush
+any buffered output and then succeed.
+.Pp
+The calling conventions of
+.Fa readfn ,
+.Fa writefn ,
+.Fa seekfn
+and
+.Fa closefn
+must match those, respectively, of
+.Xr read 2 ,
+.Xr write 2 ,
+.Xr lseek 2 ,
+and
+.Xr close 2
+with the single exception that they are passed the
+.Fa cookie
+argument specified to
+.Fn funopen
+in place of the traditional file descriptor argument.
+.Pp
+Read and write
+.Tn I/O
+functions are allowed to change the underlying buffer
+on fully buffered or line buffered streams by calling
+.Xr setvbuf 3 .
+They are also not required to completely fill or empty the buffer.
+They are not, however, allowed to change streams from unbuffered to buffered
+or to change the state of the line buffering flag.
+They must also be prepared to have read or write calls occur on buffers other
+than the one most recently specified.
+.Pp
+All user
+.Tn I/O
+functions can report an error by returning \-1.
+Additionally, all of the functions should set the external variable
+.Va errno
+appropriately if an error occurs.
+.Pp
+An error on
+.Fn closefn
+does not keep the stream open.
+.Pp
+As a convenience, the include file
+.In stdio.h
+defines the macros
+.Fn fropen
+and
+.Fn fwopen
+as calls to
+.Fn funopen
+with only a read or write function specified.
+.Sh RETURN VALUES
+Upon successful completion,
+.Fn funopen
+returns a
+.Dv FILE
+pointer.
+Otherwise,
+.Dv NULL
+is returned and the global variable
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Fn funopen
+function
+was called without either a read or write function.
+The
+.Fn funopen
+function
+may also fail and set
+.Va errno
+for any of the errors
+specified for the routine
+.Xr malloc 3 .
+.El
+.Sh SEE ALSO
+.Xr fcntl 2 ,
+.Xr open 2 ,
+.Xr fclose 3 ,
+.Xr fopen 3 ,
+.Xr fseek 3 ,
+.Xr setbuf 3
+.Sh HISTORY
+The
+.Fn funopen
+functions first appeared in
+.Bx 4.4 .
+.Sh BUGS
+The
+.Fn funopen
+function
+may not be portable to systems other than
+.Bx .
+.Pp
+On
+.Fx ,
+.Ox
+and
+.Dx
+the
+.Fn funopen
+interface erroneously assumes that
+.Vt fpos_t
+is an integral type, and uses it in the
+.Fa seekfn
+hook; but because code using a
+.Fa seekfn
+hook will fail to build on systems where
+.Vt fpos_t
+is a struct, and it will need to be slightly fixed anyway, the
+implementation provided by libbsd (in the same way as
+.Nx )
+uses the correct
+.Vt off_t
+types.
commit 877732ef4d101e9b6c789e9c00f88623761fc8c4
Author: Guillem Jover <guillem at hadrons.org>
Date:   Mon Nov 30 23:48:17 2015 +0100

    test: Check asprintf() return code

diff --git a/test/proctitle.c b/test/proctitle.c
index 5f546c7..c457dc9 100644
--- a/test/proctitle.c
+++ b/test/proctitle.c
@@ -36,6 +36,7 @@ main(int argc, char **argv, char **envp)
 	const char newtitle_base[] = "test arg1 arg2";
 	char *newtitle_full;
 	char *envvar;
+	int rc;
 
 #ifdef TEST_USE_SETPROCTITLE_INIT
 	setproctitle_init(argc, argv, envp);
@@ -44,7 +45,8 @@ main(int argc, char **argv, char **envp)
 	setproctitle("-test %s arg2", "arg1");
 	assert(strcmp(argv[0], newtitle_base) == 0);
 
-	asprintf(&newtitle_full, "%s: %s", getprogname(), newtitle_base);
+	rc = asprintf(&newtitle_full, "%s: %s", getprogname(), newtitle_base);
+	assert(rc > 0);
 	setproctitle("test %s arg2", "arg1");
 	assert(strcmp(argv[0], newtitle_full) == 0);
 	free(newtitle_full);
commit 02bccb0a0135d4aac670c804824335223872f11d
Author: Guillem Jover <guillem at hadrons.org>
Date:   Wed Sep 30 04:17:15 2015 +0200

    test: Add unit test for strmode()

diff --git a/test/.gitignore b/test/.gitignore
index 5ef2470..278391d 100644
--- a/test/.gitignore
+++ b/test/.gitignore
@@ -11,3 +11,4 @@ humanize
 overlay
 proctitle-init
 proctitle
+strmode
diff --git a/test/Makefile.am b/test/Makefile.am
index 4bc4d1a..9694338 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -21,6 +21,7 @@ check_PROGRAMS = \
 	fparseln \
 	fpurge \
 	proctitle-init \
+	strmode \
 	$(nil)
 
 if HAVE_LIBTESTU01
diff --git a/test/strmode.c b/test/strmode.c
new file mode 100644
index 0000000..2584c27
--- /dev/null
+++ b/test/strmode.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright © 2015 Guillem Jover <guillem at hadrons.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <assert.h>
+#include <string.h>
+
+int
+main(int argc, char **argv)
+{
+	char mode_str[12];
+
+	strmode(0, mode_str);
+	assert(strcmp(mode_str, "?--------- ") == 0);
+
+	strmode(0777, mode_str);
+	assert(strcmp(mode_str, "?rwxrwxrwx ") == 0);
+
+	strmode(0777 | S_IFREG, mode_str);
+	assert(strcmp(mode_str, "-rwxrwxrwx ") == 0);
+
+	strmode(0777 | S_IFREG | S_ISUID | S_ISGID | S_ISVTX, mode_str);
+	assert(strcmp(mode_str, "-rwsrwsrwt ") == 0);
+
+	strmode(0666 | S_IFREG | S_ISUID | S_ISGID | S_ISVTX, mode_str);
+	assert(strcmp(mode_str, "-rwSrwSrwT ") == 0);
+
+	strmode(0777 | S_IFLNK, mode_str);
+	assert(strcmp(mode_str, "lrwxrwxrwx ") == 0);
+
+	strmode(0777 | S_IFCHR, mode_str);
+	assert(strcmp(mode_str, "crwxrwxrwx ") == 0);
+
+	strmode(0777 | S_IFBLK, mode_str);
+	assert(strcmp(mode_str, "brwxrwxrwx ") == 0);
+
+	strmode(0777 | S_IFDIR, mode_str);
+	assert(strcmp(mode_str, "drwxrwxrwx ") == 0);
+
+	strmode(0777 | S_IFIFO, mode_str);
+	assert(strcmp(mode_str, "prwxrwxrwx ") == 0);
+
+	strmode(0777 | S_IFSOCK, mode_str);
+	assert(strcmp(mode_str, "srwxrwxrwx ") == 0);
+
+	return 0;
+}
commit 58bef83f410e8ec9201ecab671c27f56dca98f02
Author: Guillem Jover <guillem at hadrons.org>
Date:   Mon Nov 16 01:12:24 2015 +0100

    test: Add unit test for arc4random()

diff --git a/configure.ac b/configure.ac
index 97a606a..3b75267 100644
--- a/configure.ac
+++ b/configure.ac
@@ -38,6 +38,11 @@ if test "$user_CFLAGS" = unset && test "$GCC" = yes; then
 fi
 
 # Checks for libraries.
+AC_CHECK_LIB([testu01], [unif01_CreateExternGenBits],
+             [TESTU01_LIBS="-ltestu01"])
+AC_SUBST([TESTU01_LIBS])
+AM_CONDITIONAL([HAVE_LIBTESTU01],
+               [test "x$ac_cv_lib_testu01_unif01_CreateExternGenBits" = "xyes"])
 
 # Checks for header files.
 AC_CHECK_HEADERS([sys/ndir.h sys/dir.h ndir.h dirent.h])
diff --git a/test/.gitignore b/test/.gitignore
index 375be31..5ef2470 100644
--- a/test/.gitignore
+++ b/test/.gitignore
@@ -1,3 +1,4 @@
+arc4random
 bzero
 closefrom
 endian
diff --git a/test/Makefile.am b/test/Makefile.am
index d64608d..4bc4d1a 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -23,6 +23,12 @@ check_PROGRAMS = \
 	proctitle-init \
 	$(nil)
 
+if HAVE_LIBTESTU01
+arc4random_LDADD = $(LDADD) $(TESTU01_LIBS)
+
+check_PROGRAMS += arc4random
+endif
+
 if BUILD_LIBBSD_CTOR
 proctitle_LDFLAGS = \
 	-Wl,-u,libbsd_init_func \
diff --git a/test/arc4random.c b/test/arc4random.c
new file mode 100644
index 0000000..ec52af1
--- /dev/null
+++ b/test/arc4random.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright © 2015 Guillem Jover <guillem at hadrons.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include <testu01/gdef.h>
+#include <testu01/unif01.h>
+#include <testu01/swrite.h>
+#include <testu01/bbattery.h>
+
+#define TEST_OK		0
+#define TEST_SKIP	77
+#define TEST_DIE	99
+
+#define test_print(msg, ...) \
+	printf("TEST: " msg "\n", __VA_ARGS__)
+#define test_res(idx, name, pval, action) \
+	test_print("[%4d] (%s) pVal[%d] = %f -> %s", \
+	           idx, name[idx], i, pval[idx], action)
+
+static int test_failed = 0;
+
+static void
+test_battery_result(void)
+{
+	char **testNames = bbattery_TestNames;
+	double *pVal = bbattery_pVal;
+	double pSuspect = 0.001;
+
+	test_print("bbattery_NTests = %d", bbattery_NTests);
+	for (int i = 0; i < bbattery_NTests; i++) {
+		/* That test was not done: pVal = -1. */
+		if (pVal[i] < 0.0) {
+			test_res(i, testNames, pVal, "SKIP");
+			continue;
+		}
+
+		/* That test passed or failed. */
+		if ((pVal[i] >= pSuspect) &&
+		    (pVal[i] <= 1.0 - pSuspect)) {
+			test_res(i, testNames, pVal, "PASS");
+		} else {
+			test_res(i, testNames, pVal, "FAIL");
+			test_failed++;
+		}
+	}
+}
+
+int
+main(int argc, char **argv)
+{
+	unif01_Gen *gen;
+	int rc;
+
+	gen = unif01_CreateExternGenBits("arc4random", arc4random);
+
+	/* XXX: The following battery does not set pVal, so we cannot check
+	 * the results. */
+	bbattery_FIPS_140_2(gen);
+
+	/* XXX: The following battery fails one test. */
+	bbattery_pseudoDIEHARD(gen);
+	test_battery_result();
+
+	bbattery_Rabbit(gen, 33554432);
+	test_battery_result();
+
+	bbattery_SmallCrush(gen);
+	test_battery_result();
+
+	unif01_DeleteExternGenBits(gen);
+
+	if (test_failed) {
+		test_print("failed tests = %d", test_failed);
+		/* XXX: We should probably FAIL the test, but we currently
+		 * have one test always failing. */
+		rc = TEST_SKIP;
+	}
+
+	return rc;
+}
commit 6e074a2bdc8377a945533d54a0013f5c7f608809
Author: Guillem Jover <guillem at hadrons.org>
Date:   Mon Nov 30 23:00:35 2015 +0100

    build: Make git log invocation immune to local configuration

diff --git a/Makefile.am b/Makefile.am
index 8e50b1d..b839ae1 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -12,5 +12,5 @@ EXTRA_DIST = \
 dist-hook:
 	echo $(VERSION) >$(distdir)/.dist-version
 	if [ -d .git ]; then \
-	  git log --stat -C >$(distdir)/ChangeLog; \
+	  XDG_CONFIG_HOME= HOME= git log --stat -C >$(distdir)/ChangeLog; \
 	fi
commit 0871daf7b0031ca999d5c25f71a93a4560d7b042
Author: Guillem Jover <guillem at hadrons.org>
Date:   Mon Nov 30 04:12:02 2015 +0100

    build: Move hash/helper.c into new libbsd_la_included_sources
    
    Use this variable in EXTRA_DIST and libbsd_la_DEPENDENCIES.

diff --git a/src/Makefile.am b/src/Makefile.am
index 1cb04f9..1b324aa 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -7,12 +7,16 @@ AM_CPPFLAGS = \
 	-DLIBBSD_OVERLAY -DLIBBSD_DISABLE_DEPRECATED \
 	-D__REENTRANT
 
+libbsd_la_included_sources = \
+	hash/helper.c \
+	$(nil)
+
 EXTRA_DIST = \
 	libbsd.map \
 	libbsd.pc.in \
 	libbsd-ctor.pc.in \
 	libbsd-overlay.pc.in \
-	hash/helper.c \
+	$(libbsd_la_included_sources) \
 	$(nil)
 
 CLEANFILES = \
@@ -39,6 +43,7 @@ hash/md5hl.c: $(srcdir)/hash/helper.c
 	$(AM_V_GEN) sed -e 's:hashinc:md5.h:g' -e 's:HASH:MD5:g' $< > $@
 
 libbsd_la_DEPENDENCIES = \
+	$(libbsd_la_included_sources) \
 	libbsd.map
 libbsd_la_LDFLAGS = \
 	-Wl,--version-script=$(srcdir)/libbsd.map \
commit 02c33d50226360de04d5a5da997a040a5413c35f
Author: Guillem Jover <guillem at hadrons.org>
Date:   Mon Nov 30 02:48:23 2015 +0100

    build: Move proctitle_LDFLAGS inside BUILD_LIBBSD_CTOR conditional

diff --git a/test/Makefile.am b/test/Makefile.am
index 2576eeb..d64608d 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -24,6 +24,12 @@ check_PROGRAMS = \
 	$(nil)
 
 if BUILD_LIBBSD_CTOR
+proctitle_LDFLAGS = \
+	-Wl,-u,libbsd_init_func \
+	$(top_builddir)/src/libbsd-ctor.a \
+	$(top_builddir)/src/libbsd.la \
+	$(nil)
+
 check_PROGRAMS += proctitle
 endif
 
@@ -34,10 +40,4 @@ fparseln_SOURCES = test-stream.c test-stream.h fparseln.c
 proctitle_init_SOURCES = proctitle.c
 proctitle_init_CPPFLAGS = $(AM_CPPFLAGS) -DTEST_USE_SETPROCTITLE_INIT=1
 
-proctitle_LDFLAGS = \
-	-Wl,-u,libbsd_init_func \
-	$(top_builddir)/src/libbsd-ctor.a \
-	$(top_builddir)/src/libbsd.la \
-	$(nil)
-
 TESTS = $(check_PROGRAMS)


More information about the libbsd mailing list