libbsd: Branch 'master' - 25 commits

Guillem Jover guillem at kemper.freedesktop.org
Tue Sep 22 23:06:38 PDT 2015


 configure.ac            |    5 -
 include/bsd/err.h       |   12 ++-
 include/bsd/md5.h       |   16 ++--
 include/bsd/stdio.h     |    7 +
 include/bsd/stdlib.h    |    6 -
 include/bsd/sys/cdefs.h |   53 +++++++++++++
 include/bsd/sys/queue.h |  118 ++++++++++++++++++++++++------
 include/bsd/unistd.h    |    3 
 man/Makefile.am         |    1 
 man/arc4random.3        |    6 -
 man/fparseln.3          |    6 -
 man/mdX.3bsd            |    8 +-
 man/queue.3bsd          |  186 ++++++++++++++++++++++++++++++++++++++++++++++--
 man/reallocarray.3      |  102 ++++++++++++++++++++++++++
 src/Makefile.am         |    1 
 src/arc4random.c        |   30 +++----
 src/closefrom.c         |  149 +++++++++++++++++++++++++++-----------
 src/fgetln.c            |   10 ++
 src/fgetwln.c           |    2 
 src/fparseln.c          |   53 +++----------
 src/fpurge.c            |   20 -----
 src/hash/helper.c       |    2 
 src/hash/md5.c          |   20 ++---
 src/heapsort.c          |    6 -
 src/inet_net_pton.c     |   11 --
 src/local-link.h        |   33 ++++++++
 src/merge.c             |   21 +----
 src/nlist.c             |   25 +-----
 src/radixsort.c         |    3 
 src/reallocarray.c      |    4 -
 src/setmode.c           |    5 -
 src/stringlist.c        |    6 -
 src/strmode.c           |    4 -
 test/.gitignore         |    3 
 test/Makefile.am        |   14 ++-
 test/closefrom.c        |   53 +++++++++++++
 test/fgetln.c           |   60 +--------------
 test/fparseln.c         |   92 +++++++++++++++++++++++
 test/fpurge.c           |   48 ++++++++++++
 test/test-stream.c      |   84 +++++++++++++++++++++
 test/test-stream.h      |   37 +++++++++
 41 files changed, 1021 insertions(+), 304 deletions(-)

New commits:
commit 0982dcd98b7561269fdddaef4388da7177de7603
Author: Guillem Jover <guillem at hadrons.org>
Date:   Wed Sep 23 07:10:18 2015 +0200

    Lock the file streams in fgetln() and fparseln()
    
    The fparseln() function had the NetBSD uppercase macros stubbed out,
    so replace them with the actual stdio ones. The fgetln() function was
    missing any locking at all.

diff --git a/src/fgetln.c b/src/fgetln.c
index 5f646e4..4d1726e 100644
--- a/src/fgetln.c
+++ b/src/fgetln.c
@@ -50,6 +50,8 @@ fgetln(FILE *stream, size_t *len)
 	struct filebuf *fb;
 	ssize_t nread;
 
+	flockfile(stream);
+
 	/* Try to diminish the possibility of several fgetln() calls being
 	 * used on different streams, by using a pool of buffers per file. */
 	fb = &fb_pool[fb_pool_cur];
@@ -61,6 +63,9 @@ fgetln(FILE *stream, size_t *len)
 	fb->fp = stream;
 
 	nread = getline(&fb->buf, &fb->len, stream);
+
+	funlockfile(stream);
+
 	/* Note: the getdelim/getline API ensures nread != 0. */
 	if (nread == -1) {
 		*len = 0;
diff --git a/src/fparseln.c b/src/fparseln.c
index 959df11..effb849 100644
--- a/src/fparseln.c
+++ b/src/fparseln.c
@@ -35,8 +35,6 @@ __RCSID("$NetBSD: fparseln.c,v 1.10 2009/10/21 01:07:45 snj Exp $");
 #include <string.h>
 #include <stdlib.h>
 
-#define FLOCKFILE(fp)
-#define FUNLOCKFILE(fp)
 #define _DIAGASSERT(t)
 
 static int isescaped(const char *, const char *, int);
@@ -104,7 +102,7 @@ fparseln(FILE *fp, size_t *size, size_t *lineno, const char str[3], int flags)
 	 */
 	nl  = '\n';
 
-	FLOCKFILE(fp);
+	flockfile(fp);
 
 	while (cnt) {
 		cnt = 0;
@@ -151,7 +149,7 @@ fparseln(FILE *fp, size_t *size, size_t *lineno, const char str[3], int flags)
 		}
 
 		if ((cp = realloc(buf, len + s + 1)) == NULL) {
-			FUNLOCKFILE(fp);
+			funlockfile(fp);
 			free(buf);
 			free(ptr);
 			return NULL;
@@ -163,7 +161,7 @@ fparseln(FILE *fp, size_t *size, size_t *lineno, const char str[3], int flags)
 		buf[len] = '\0';
 	}
 
-	FUNLOCKFILE(fp);
+	funlockfile(fp);
 	free(ptr);
 
 	if ((flags & FPARSELN_UNESCALL) != 0 && esc && buf != NULL &&
commit ee26e59e727c51fcf4e01d4d4cab3b697bb6b31d
Author: Guillem Jover <guillem at hadrons.org>
Date:   Wed Sep 23 05:50:52 2015 +0200

    Mark functions handling format strings with __printflike

diff --git a/include/bsd/err.h b/include/bsd/err.h
index fcaaa85..b465c1b 100644
--- a/include/bsd/err.h
+++ b/include/bsd/err.h
@@ -39,10 +39,14 @@
 #include <stdarg.h>
 
 __BEGIN_DECLS
-extern void warnc (int code, const char *format, ...);
-extern void vwarnc (int code, const char *format, va_list ap);
-extern void errc (int status, int code, const char *format, ...);
-extern void verrc (int status, int code, const char *format, va_list ap);
+void warnc(int code, const char *format, ...)
+	__printflike(2, 3);
+void vwarnc(int code, const char *format, va_list ap)
+	__printflike(2, 0);
+void errc(int status, int code, const char *format, ...)
+	__printflike(3, 4);
+void verrc(int status, int code, const char *format, va_list ap)
+	__printflike(3, 0);
 __END_DECLS
 
 #endif
diff --git a/include/bsd/unistd.h b/include/bsd/unistd.h
index 5dfa605..78a4525 100644
--- a/include/bsd/unistd.h
+++ b/include/bsd/unistd.h
@@ -60,7 +60,8 @@ void closefrom(int lowfd);
 #define initsetproctitle(c, a, e) setproctitle_init((c), (a), (e))
 
 void setproctitle_init(int argc, char *argv[], char *envp[]);
-void setproctitle(const char *fmt, ...);
+void setproctitle(const char *fmt, ...)
+	__printflike(1, 2);
 
 int getpeereid(int s, uid_t *euid, gid_t *egid);
 __END_DECLS
commit 151bc71d64845a1798561e66fa62ee0d62f4a03c
Author: Guillem Jover <guillem at hadrons.org>
Date:   Tue Sep 22 16:22:56 2015 +0200

    Add compile and link-time deprecation warnings for fgetln()
    
    Although the current implementation in libbsd is probably one of the
    safest ones around, it still poses some problems when used with many
    file streams. This function has now a replacement, that is both more
    standard and portable. Ask users to switch to getline(3) instead.

diff --git a/include/bsd/stdio.h b/include/bsd/stdio.h
index e1f8fc3..7697425 100644
--- a/include/bsd/stdio.h
+++ b/include/bsd/stdio.h
@@ -44,7 +44,12 @@
 __BEGIN_DECLS
 const char *fmtcheck(const char *, const char *);
 
-char *fgetln(FILE *fp, size_t *lenp);
+/* XXX: The function requires cooperation from the system libc to store the
+ * line buffer in the FILE struct itself. */
+char *fgetln(FILE *fp, size_t *lenp)
+	__attribute__((deprecated("This functions cannot be safely ported, "
+	                          "use getline(3) instead, as it is supported "
+	                          "by GNU and POSIX.1-2008.")));
 
 /*
  * Note: We diverge from the FreeBSD, OpenBSD and DragonFlyBSD declarations,
diff --git a/src/fgetln.c b/src/fgetln.c
index 6de804b..5f646e4 100644
--- a/src/fgetln.c
+++ b/src/fgetln.c
@@ -30,6 +30,8 @@
 #include <sys/types.h>
 #include <string.h>
 
+#include "local-link.h"
+
 #ifdef HAVE_GETLINE
 struct filebuf {
 	FILE *fp;
@@ -68,6 +70,9 @@ fgetln(FILE *stream, size_t *len)
 		return fb->buf;
 	}
 }
+libbsd_link_warning(fgetln,
+                    "This functions cannot be safely ported, use getline(3) "
+                    "instead, as it is supported by GNU and POSIX.1-2008.")
 #else
 #error "Function fgetln() needs to be ported."
 #endif
diff --git a/test/Makefile.am b/test/Makefile.am
index 9086128..6d675e3 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -27,6 +27,7 @@ check_PROGRAMS += proctitle
 endif
 
 fgetln_SOURCES = test-stream.c test-stream.h fgetln.c
+fgetln_CFLAGS = -Wno-deprecated-declarations
 fparseln_SOURCES = test-stream.c test-stream.h fparseln.c
 
 proctitle_init_SOURCES = proctitle.c
commit 41ff37bbccea236d67b0d54c97477741a6f13dab
Author: Guillem Jover <guillem at hadrons.org>
Date:   Tue Sep 22 16:21:12 2015 +0200

    build: Add support for linker warnings

diff --git a/src/Makefile.am b/src/Makefile.am
index 3f3a0f6..de1fe34 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -65,6 +65,7 @@ libbsd_la_SOURCES = \
 	humanize_number.c \
 	inet_net_pton.c \
 	local-elf.h \
+	local-link.h \
 	merge.c \
 	nlist.c \
 	pidfile.c \
diff --git a/src/local-link.h b/src/local-link.h
new file mode 100644
index 0000000..d518dcf
--- /dev/null
+++ b/src/local-link.h
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+#ifndef LIBBSD_LOCAL_LINK_H
+#define LIBBSD_LOCAL_LINK_H
+
+#define libbsd_link_warning(symbol, msg) \
+	static const char libbsd_emit_link_warning_##symbol[] \
+		__attribute__((used,section(".gnu.warning." #symbol))) = msg;
+#endif
commit 53d989a223f4d5ab789b8813451263528536f927
Author: Guillem Jover <guillem at hadrons.org>
Date:   Sat Dec 13 21:28:36 2014 +0100

    Switch fparseln() implementation from fgetln() to getline()

diff --git a/man/fparseln.3 b/man/fparseln.3
index 1c215ac..9170417 100644
--- a/man/fparseln.3
+++ b/man/fparseln.3
@@ -126,9 +126,9 @@ is returned.
 The
 .Fn fparseln
 function uses internally
-.Xr fgetln 3 ,
+.Xr getline 3 ,
 so all error conditions that apply to
-.Xr fgetln 3 ,
+.Xr getline 3 ,
 apply to
 .Fn fparseln .
 In addition
@@ -141,7 +141,7 @@ and return
 .Dv NULL
 if it runs out of memory.
 .Sh SEE ALSO
-.Xr fgetln 3
+.Xr getline 3
 .Sh HISTORY
 The
 .Fn fparseln
diff --git a/src/fparseln.c b/src/fparseln.c
index 8fbf75c..959df11 100644
--- a/src/fparseln.c
+++ b/src/fparseln.c
@@ -77,7 +77,8 @@ fparseln(FILE *fp, size_t *size, size_t *lineno, const char str[3], int flags)
 {
 	static const char dstr[3] = { '\\', '\\', '#' };
 
-	size_t	s, len;
+	ssize_t	s;
+	size_t len, ptrlen;
 	char   *buf;
 	char   *ptr, *cp;
 	int	cnt;
@@ -87,6 +88,8 @@ fparseln(FILE *fp, size_t *size, size_t *lineno, const char str[3], int flags)
 
 	len = 0;
 	buf = NULL;
+	ptrlen = 0;
+	ptr = NULL;
 	cnt = 1;
 
 	if (str == NULL)
@@ -97,7 +100,7 @@ fparseln(FILE *fp, size_t *size, size_t *lineno, const char str[3], int flags)
 	com = str[2];
 	/*
 	 * XXX: it would be cool to be able to specify the newline character,
-	 * but unfortunately, fgetln does not let us
+	 * getdelim(3) does let us, but supporting it would diverge from BSDs.
 	 */
 	nl  = '\n';
 
@@ -109,7 +112,8 @@ fparseln(FILE *fp, size_t *size, size_t *lineno, const char str[3], int flags)
 		if (lineno)
 			(*lineno)++;
 
-		if ((ptr = fgetln(fp, &s)) == NULL)
+		s = getline(&ptr, &ptrlen, fp);
+		if (s < 0)
 			break;
 
 		if (s && com) {		/* Check and eliminate comments */
@@ -149,6 +153,7 @@ fparseln(FILE *fp, size_t *size, size_t *lineno, const char str[3], int flags)
 		if ((cp = realloc(buf, len + s + 1)) == NULL) {
 			FUNLOCKFILE(fp);
 			free(buf);
+			free(ptr);
 			return NULL;
 		}
 		buf = cp;
@@ -159,6 +164,7 @@ fparseln(FILE *fp, size_t *size, size_t *lineno, const char str[3], int flags)
 	}
 
 	FUNLOCKFILE(fp);
+	free(ptr);
 
 	if ((flags & FPARSELN_UNESCALL) != 0 && esc && buf != NULL &&
 	    strchr(buf, esc) != NULL) {
commit f50b197ea597e6517ffeb9666b469b227ea88387
Author: Guillem Jover <guillem at hadrons.org>
Date:   Tue Sep 22 22:30:17 2015 +0200

    test: Add fparseln() unit test

diff --git a/src/fparseln.c b/src/fparseln.c
index 0796b66..8fbf75c 100644
--- a/src/fparseln.c
+++ b/src/fparseln.c
@@ -195,36 +195,3 @@ fparseln(FILE *fp, size_t *size, size_t *lineno, const char str[3], int flags)
 		*size = len;
 	return buf;
 }
-
-#ifdef TEST
-
-int main(int, char **);
-
-int
-main(int argc, char **argv)
-{
-	char   *ptr;
-	size_t	size, line;
-
-	line = 0;
-	while ((ptr = fparseln(stdin, &size, &line, NULL,
-	    FPARSELN_UNESCALL)) != NULL)
-		printf("line %d (%d) |%s|\n", line, size, ptr);
-	return 0;
-}
-
-/*
-
-# This is a test
-line 1
-line 2 \
-line 3 # Comment
-line 4 \# Not comment \\\\
-
-# And a comment \
-line 5 \\\
-line 6
-
-*/
-
-#endif /* TEST */
diff --git a/test/.gitignore b/test/.gitignore
index ab051cc..e80dcb5 100644
--- a/test/.gitignore
+++ b/test/.gitignore
@@ -2,6 +2,7 @@ closefrom
 endian
 fgetln
 funopen
+fparseln
 fpurge
 headers
 humanize
diff --git a/test/Makefile.am b/test/Makefile.am
index b92aeeb..9086128 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -17,6 +17,7 @@ check_PROGRAMS = \
 	humanize \
 	fgetln \
 	funopen \
+	fparseln \
 	fpurge \
 	proctitle-init \
 	$(nil)
@@ -26,6 +27,7 @@ check_PROGRAMS += proctitle
 endif
 
 fgetln_SOURCES = test-stream.c test-stream.h fgetln.c
+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
diff --git a/test/fparseln.c b/test/fparseln.c
new file mode 100644
index 0000000..daff6bd
--- /dev/null
+++ b/test/fparseln.c
@@ -0,0 +1,92 @@
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "test-stream.h"
+
+#define TEST_LINES 9
+static const char *data_test[] = {
+	"# This is a test\n",
+	"line 1\n",
+	"line 2 \\\n",
+	"line 3 # Comment\n",
+	"line 4 \\# Not comment \\\\\\\\\n",
+	"\n",
+	"# And a comment \\\n",
+	"line 5 \\\\\\\n",
+	"line 6 w/ escape sequences \\b, \\t, \\\\t",
+};
+
+#define EXPECT_LINES 5
+static size_t lineno_expect[] = { 2, 4, 5, 6, 9 };
+
+static const char *data_parse[] = {
+	"line 1",
+	"line 2 line 3 ",
+	"line 4 \\# Not comment \\\\\\\\",
+	"",
+	"line 5 \\\\line 6 w/ escape sequences \\b, \\t, \\\\t",
+};
+static const char *data_escape[] = {
+	"line 1",
+	"line 2 line 3 ",
+	"line 4 # Not comment \\\\",
+	"",
+	"line 5 \\line 6 w/ escape sequences b, t, \\t",
+};
+
+static void
+test_fparseln(const char **data_expect, int flags)
+{
+	FILE *fp;
+	size_t i, len, lineno = 0;
+
+	fp = pipe_feed("%s", (const void **)data_test, TEST_LINES);
+	for (i = 0; i < EXPECT_LINES; i++) {
+		char *str = fparseln(fp, &len, &lineno, NULL, flags);
+
+		assert(str);
+		assert(lineno == lineno_expect[i]);
+		assert(strcmp(str, data_expect[i]) == 0);
+
+		free(str);
+	}
+	assert(fparseln(fp, &len, NULL, NULL, 0) == NULL);
+	pipe_close(fp);
+}
+
+int
+main(int argc, char **argv)
+{
+	test_fparseln(data_parse, 0);
+	test_fparseln(data_escape, FPARSELN_UNESCALL);
+
+	return 0;
+}
commit 54f153414a00b2de606f1aeaf9d76f8792e062f6
Author: Guillem Jover <guillem at hadrons.org>
Date:   Tue Sep 22 20:56:15 2015 +0200

    test: Refactor stream testing functions into a new module

diff --git a/test/Makefile.am b/test/Makefile.am
index 0f5ff4e..b92aeeb 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -25,6 +25,8 @@ if BUILD_LIBBSD_CTOR
 check_PROGRAMS += proctitle
 endif
 
+fgetln_SOURCES = test-stream.c test-stream.h fgetln.c
+
 proctitle_init_SOURCES = proctitle.c
 proctitle_init_CPPFLAGS = $(AM_CPPFLAGS) -DTEST_USE_SETPROCTITLE_INIT=1
 
diff --git a/test/fgetln.c b/test/fgetln.c
index d3814d8..7d1e9dc 100644
--- a/test/fgetln.c
+++ b/test/fgetln.c
@@ -24,15 +24,15 @@
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include <sys/wait.h>
 #include <assert.h>
-#include <unistd.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <locale.h>
 #include <wchar.h>
 
+#include "test-stream.h"
+
 #define skip(msg) \
 	do { \
 		printf("skip: %s\n", (msg)); \
@@ -67,58 +67,6 @@ struct file {
 	int got_len;
 };
 
-static FILE *
-pipe_feed(const char *fmt, const void **buf, int buf_nmemb)
-{
-	FILE *fp;
-	int rc;
-	int pipefd[2];
-	pid_t pid;
-
-	rc = pipe(pipefd);
-	assert(rc >= 0);
-
-	pid = fork();
-	assert(pid >= 0);
-
-	if (pid == 0) {
-		int line;
-
-		/* Child writes data to pipe. */
-		rc = close(pipefd[0]);
-		assert(rc >= 0);
-
-		fp = fdopen(pipefd[1], "w");
-		assert(fp);
-
-		for (line = 0; line < buf_nmemb; line++) {
-			rc = fprintf(fp, fmt, buf[line]);
-			assert(rc >= 0);
-		}
-
-		rc = fclose(fp);
-		assert(rc >= 0);
-
-		_exit(0);
-	} else {
-		/* Parent gets a FILE and reads from it. */
-		rc = close(pipefd[1]);
-		assert(rc >= 0);
-
-		fp = fdopen(pipefd[0], "r");
-		assert(fp);
-
-		return fp;
-	}
-}
-
-static void
-pipe_close(FILE *fp)
-{
-	fclose(fp);
-	wait(NULL);
-}
-
 static void
 test_fgetln_single(void)
 {
diff --git a/test/test-stream.c b/test/test-stream.c
new file mode 100644
index 0000000..849f419
--- /dev/null
+++ b/test/test-stream.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright © 2013 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 <sys/wait.h>
+#include <assert.h>
+#include <unistd.h>
+#include <stdio.h>
+
+#include "test-stream.h"
+
+FILE *
+pipe_feed(const char *fmt, const void **buf, int buf_nmemb)
+{
+	FILE *fp;
+	int rc;
+	int pipefd[2];
+	pid_t pid;
+
+	rc = pipe(pipefd);
+	assert(rc >= 0);
+
+	pid = fork();
+	assert(pid >= 0);
+
+	if (pid == 0) {
+		int line;
+
+		/* Child writes data to pipe. */
+		rc = close(pipefd[0]);
+		assert(rc >= 0);
+
+		fp = fdopen(pipefd[1], "w");
+		assert(fp);
+
+		for (line = 0; line < buf_nmemb; line++) {
+			rc = fprintf(fp, fmt, buf[line]);
+			assert(rc >= 0);
+		}
+
+		rc = fclose(fp);
+		assert(rc >= 0);
+
+		_exit(0);
+	} else {
+		/* Parent gets a FILE and reads from it. */
+		rc = close(pipefd[1]);
+		assert(rc >= 0);
+
+		fp = fdopen(pipefd[0], "r");
+		assert(fp);
+
+		return fp;
+	}
+}
+
+void
+pipe_close(FILE *fp)
+{
+	fclose(fp);
+	wait(NULL);
+}
diff --git a/test/test-stream.h b/test/test-stream.h
new file mode 100644
index 0000000..cee4e60
--- /dev/null
+++ b/test/test-stream.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright © 2013 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.
+ */
+
+#ifndef LIBBSD_TEST_STREAM
+#define LIBBSD_TEST_STREAM
+
+#include <stdio.h>
+
+FILE *
+pipe_feed(const char *fmt, const void **buf, int buf_nmemb);
+void
+pipe_close(FILE *fp);
+
+#endif
commit 9688ab26b921e372cc296d4d1b0d48cbcf6a96c5
Author: Brent Cook <bcook at openbsd.org>
Date:   Sat Dec 13 08:55:59 2014 +0100

    Avoid left shift overflow in reallocarray
    
    Some 64-bit platforms (e.g. Windows 64) have a 32-bit long. So, shifting
    1UL 32-bits to the left causes an overflow. This replaces the constant
    1UL with (size_t)1 so that we get the correct constant size for the
    platform.
    
    Import from OpenBSD.
    
    Signed-off-by: Guillem Jover <guillem at hadrons.org>

diff --git a/src/reallocarray.c b/src/reallocarray.c
index 7accd99..68baca2 100644
--- a/src/reallocarray.c
+++ b/src/reallocarray.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: reallocarray.c,v 1.1 2014/05/08 21:43:49 deraadt Exp $	*/
+/*	$OpenBSD: reallocarray.c,v 1.2 2014/12/08 03:45:00 bcook Exp $	*/
 /*
  * Copyright (c) 2008 Otto Moerbeek <otto at drijf.net>
  *
@@ -24,7 +24,7 @@
  * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX
  * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW
  */
-#define MUL_NO_OVERFLOW	(1UL << (sizeof(size_t) * 4))
+#define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4))
 
 void *
 reallocarray(void *optr, size_t nmemb, size_t size)
commit 025b44800e97f61c31b9979cc61a7b443feda05e
Author: Guillem Jover <guillem at hadrons.org>
Date:   Tue Nov 4 05:34:46 2014 +0100

    Make mergesort setup() static

diff --git a/src/merge.c b/src/merge.c
index 470352a..c82594c 100644
--- a/src/merge.c
+++ b/src/merge.c
@@ -255,7 +255,7 @@ COPY:	    			b = t;
  * when THRESHOLD/2 pairs compare with same sense.  (Only used when NATURAL
  * is defined.  Otherwise simple pairwise merging is used.)
  */
-void
+static void
 setup(u_char *list1, u_char *list2, size_t n, size_t size,
 	int (*cmp)(const void *, const void *))
 {
commit a6a101effacbdf88b5879af2f63b7e5dbc4a05b9
Author: Guillem Jover <guillem at hadrons.org>
Date:   Tue Nov 4 05:33:26 2014 +0100

    Use ANSI C prototypes

diff --git a/src/heapsort.c b/src/heapsort.c
index 7e345c7..72dbcbc 100644
--- a/src/heapsort.c
+++ b/src/heapsort.c
@@ -130,10 +130,8 @@
  * only advantage over quicksort is that it requires little additional memory.
  */
 int
-heapsort(vbase, nmemb, size, compar)
-	void *vbase;
-	size_t nmemb, size;
-	int (*compar)(const void *, const void *);
+heapsort(void *vbase, size_t nmemb, size_t size,
+	int (*compar)(const void *, const void *))
 {
 	size_t cnt, i, j, l;
 	char tmp, *tmp1, *tmp2;
diff --git a/src/inet_net_pton.c b/src/inet_net_pton.c
index 8d33156..28c55ba 100644
--- a/src/inet_net_pton.c
+++ b/src/inet_net_pton.c
@@ -55,11 +55,7 @@ static int	inet_net_pton_ipv4(const char *src, u_char *dst, size_t size);
  *	Paul Vixie (ISC), June 1996
  */
 int
-inet_net_pton(af, src, dst, size)
-	int af;
-	const char *src;
-	void *dst;
-	size_t size;
+inet_net_pton(int af, const char *src, void *dst, size_t size)
 {
 	switch (af) {
 	case AF_INET:
@@ -87,10 +83,7 @@ inet_net_pton(af, src, dst, size)
  *	Paul Vixie (ISC), June 1996
  */
 static int
-inet_net_pton_ipv4(src, dst, size)
-	const char *src;
-	u_char *dst;
-	size_t size;
+inet_net_pton_ipv4(const char *src, u_char *dst, size_t size)
 {
 	static const char
 		xdigits[] = "0123456789abcdef",
diff --git a/src/merge.c b/src/merge.c
index e1078e7..470352a 100644
--- a/src/merge.c
+++ b/src/merge.c
@@ -95,11 +95,8 @@ static void insertionsort(u_char *, size_t, size_t,
  * Arguments are as for qsort.
  */
 int
-mergesort(base, nmemb, size, cmp)
-	void *base;
-	size_t nmemb;
-	size_t size;
-	int (*cmp)(const void *, const void *);
+mergesort(void *base, size_t nmemb, size_t size,
+	int (*cmp)(const void *, const void *))
 {
 	size_t i;
 	int sense;
@@ -259,10 +256,8 @@ COPY:	    			b = t;
  * is defined.  Otherwise simple pairwise merging is used.)
  */
 void
-setup(list1, list2, n, size, cmp)
-	size_t n, size;
-	int (*cmp)(const void *, const void *);
-	u_char *list1, *list2;
+setup(u_char *list1, u_char *list2, size_t n, size_t size,
+	int (*cmp)(const void *, const void *))
 {
 	int i, length, size2, tmp, sense;
 	u_char *f1, *f2, *s, *l2, *last, *p2;
@@ -333,10 +328,8 @@ setup(list1, list2, n, size, cmp)
  * last 4 elements.
  */
 static void
-insertionsort(a, n, size, cmp)
-	u_char *a;
-	size_t n, size;
-	int (*cmp)(const void *, const void *);
+insertionsort(u_char *a, size_t n, size_t size,
+	int (*cmp)(const void *, const void *))
 {
 	u_char *ai, *s, *t, *u, tmp;
 	int i;
diff --git a/src/nlist.c b/src/nlist.c
index 6c9be51..3f2c0f8 100644
--- a/src/nlist.c
+++ b/src/nlist.c
@@ -70,9 +70,7 @@ static int __elf_fdnlist(int, struct nlist *);
 int __fdnlist(int, struct nlist *);
 
 int
-nlist(name, list)
-	const char *name;
-	struct nlist *list;
+nlist(const char *name, struct nlist *list)
 {
 	int fd, n;
 
@@ -96,9 +94,7 @@ static struct nlist_handlers {
 };
 
 int
-__fdnlist(fd, list)
-	int fd;
-	struct nlist *list;
+__fdnlist(int fd, struct nlist *list)
 {
 	size_t i;
 	int n = -1;
@@ -115,9 +111,7 @@ __fdnlist(fd, list)
 
 #ifdef _NLIST_DO_AOUT
 static int
-__aout_fdnlist(fd, list)
-	int fd;
-	struct nlist *list;
+__aout_fdnlist(int fd, struct nlist *list)
 {
 	struct nlist *p, *symtab;
 	caddr_t strtab, a_out_mmap;
@@ -220,8 +214,7 @@ static void elf_sym_to_nlist(struct nlist *, Elf_Sym *, Elf_Shdr *, int);
  * as such its use should be restricted.
  */
 static int
-__elf_is_okay__(ehdr)
-	Elf_Ehdr *ehdr;
+__elf_is_okay__(Elf_Ehdr *ehdr)
 {
 	int retval = 0;
 	/*
@@ -244,9 +237,7 @@ __elf_is_okay__(ehdr)
 }
 
 static int
-__elf_fdnlist(fd, list)
-	int fd;
-	struct nlist *list;
+__elf_fdnlist(int fd, struct nlist *list)
 {
 	struct nlist *p;
 	Elf_Off symoff = 0, symstroff = 0;
@@ -386,11 +377,7 @@ __elf_fdnlist(fd, list)
  * n_value and n_type members.
  */
 static void
-elf_sym_to_nlist(nl, s, shdr, shnum)
-	struct nlist *nl;
-	Elf_Sym *s;
-	Elf_Shdr *shdr;
-	int shnum;
+elf_sym_to_nlist(struct nlist *nl, Elf_Sym *s, Elf_Shdr *shdr, int shnum)
 {
 	nl->n_value = s->st_value;
 
diff --git a/src/strmode.c b/src/strmode.c
index 97136e6..8d825ae 100644
--- a/src/strmode.c
+++ b/src/strmode.c
@@ -37,9 +37,7 @@ static char sccsid[] = "@(#)strmode.c	8.3 (Berkeley) 8/15/94";
 #include <string.h>
 
 void
-strmode(mode, p)
-	mode_t mode;
-	char *p;
+strmode(mode_t mode, char *p)
 {
 	 /* print type */
 	switch (mode & S_IFMT) {
commit 32388fe59f526a150058b58a8bc22785e4b6b4cc
Author: Guillem Jover <guillem at hadrons.org>
Date:   Mon Nov 3 23:21:52 2014 +0100

    Use reallocarray() instead of malloc() or realloc()

diff --git a/src/fgetwln.c b/src/fgetwln.c
index 2473932..9ee0776 100644
--- a/src/fgetwln.c
+++ b/src/fgetwln.c
@@ -68,7 +68,7 @@ fgetwln(FILE *stream, size_t *lenp)
 			else
 				fb->len = FILEWBUF_INIT_LEN;
 
-			wp = realloc(fb->wbuf, fb->len * sizeof(wchar_t));
+			wp = reallocarray(fb->wbuf, fb->len, sizeof(wchar_t));
 			if (wp == NULL) {
 				wused = 0;
 				break;
diff --git a/src/radixsort.c b/src/radixsort.c
index b9746fc..1473925 100644
--- a/src/radixsort.c
+++ b/src/radixsort.c
@@ -118,7 +118,8 @@ sradixsort(const u_char **a, int n, const u_char *tab, u_int endch)
 	if (n < THRESHOLD)
 		simplesort(a, n, 0, tr, endch);
 	else {
-		if ((ta = malloc(n * sizeof(a))) == NULL)
+		ta = reallocarray(NULL, n, sizeof(a));
+		if (ta == NULL)
 			return (-1);
 		r_sort_b(a, ta, n, 0, tr, endch);
 		free(ta);
diff --git a/src/setmode.c b/src/setmode.c
index c3c9a8b..cdc2179 100644
--- a/src/setmode.c
+++ b/src/setmode.c
@@ -154,7 +154,7 @@ common:			if (set->cmd2 & CMD2_CLR) {
 	if (set >= endset) {						\
 		BITCMD *newset;						\
 		setlen += SET_LEN_INCR;					\
-		newset = realloc(saveset, sizeof(BITCMD) * setlen);	\
+		newset = reallocarray(saveset, setlen, sizeof(BITCMD));	\
 		if (newset == NULL)					\
 			goto out;					\
 		set = newset + (set - saveset);				\
@@ -197,7 +197,8 @@ setmode(const char *p)
 
 	setlen = SET_LEN + 2;
 
-	if ((set = malloc((u_int)(sizeof(BITCMD) * setlen))) == NULL)
+	set = reallocarray(NULL, setlen, sizeof(BITCMD));
+	if (set == NULL)
 		return (NULL);
 	saveset = set;
 	endset = set + (setlen - 2);
diff --git a/src/stringlist.c b/src/stringlist.c
index ce1b2ce..6e5e488 100644
--- a/src/stringlist.c
+++ b/src/stringlist.c
@@ -67,7 +67,7 @@ sl_init(void)
 
 	sl->sl_cur = 0;
 	sl->sl_max = _SL_CHUNKSIZE;
-	sl->sl_str = malloc(sl->sl_max * sizeof(char *));
+	sl->sl_str = reallocarray(NULL, sl->sl_max, sizeof(char *));
 	if (sl->sl_str == NULL) {
 		free(sl);
 		sl = NULL;
@@ -88,8 +88,8 @@ sl_add(StringList *sl, char *name)
 	if (sl->sl_cur == sl->sl_max - 1) {
 		char	**new;
 
-		new = realloc(sl->sl_str,
-		    (sl->sl_max + _SL_CHUNKSIZE) * sizeof(char *));
+		new = reallocarray(sl->sl_str,
+		    (sl->sl_max + _SL_CHUNKSIZE), sizeof(char *));
 		if (new == NULL)
 			return -1;
 		sl->sl_max += _SL_CHUNKSIZE;
diff --git a/test/fgetln.c b/test/fgetln.c
index 83d120c..d3814d8 100644
--- a/test/fgetln.c
+++ b/test/fgetln.c
@@ -149,7 +149,7 @@ test_fgetln_multi(void)
 		str = strdup("A\n");
 		str[0] += i;
 
-		files[i].lines = malloc(sizeof(char *) * LINE_COUNT);
+		files[i].lines = reallocarray(NULL, LINE_COUNT, sizeof(char *));
 		files[i].lines[0] = str;
 		files[i].lines[1] = str;
 		files[i].fp = pipe_feed("%s", files[i].lines, LINE_COUNT);
@@ -211,7 +211,7 @@ test_fgetwln_multi(void)
 		wstr = wcsdup(L"A\n");
 		wstr[0] += i;
 
-		files[i].lines = malloc(sizeof(char *) * LINE_COUNT);
+		files[i].lines = reallocarray(NULL, LINE_COUNT, sizeof(char *));
 		files[i].lines[0] = wstr;
 		files[i].lines[1] = wstr;
 		files[i].fp = pipe_feed("%ls", files[i].lines, LINE_COUNT);
commit 30e328cbf14d03fc9f6569e93e0dac41526264d8
Author: Guillem Jover <guillem at hadrons.org>
Date:   Mon Nov 3 00:43:27 2014 +0100

    Do not close file descriptors while scanning the /proc filesystem
    
    Closing file descriptors changes the content of the fd directories in
    the /proc filesystem, which means readdir() might get very confused.
    
    Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=85663

diff --git a/src/closefrom.c b/src/closefrom.c
index 27aa26f..b6d9834 100644
--- a/src/closefrom.c
+++ b/src/closefrom.c
@@ -129,6 +129,10 @@ closefrom_procfs(int lowfd)
 	const char *path;
 	DIR *dirp;
 	struct dirent *dent;
+	int *fd_array = NULL;
+	int fd_array_used = 0;
+	int fd_array_size = 0;
+	int i;
 
 	/* Use /proc/self/fd (or /dev/fd on FreeBSD) if it exists. */
 # if defined(__FreeBSD__) || defined(__APPLE__)
@@ -145,10 +149,30 @@ closefrom_procfs(int lowfd)
 		int fd;
 
 		fd = strtonum(dent->d_name, lowfd, INT_MAX, &errstr);
-		if (errstr == NULL && fd != dirfd(dirp))
-			closefrom_close(fd);
+		if (errstr != NULL || fd == dirfd(dirp))
+			continue;
+
+		if (fd_array_used >= fd_array_size) {
+			int *ptr;
+
+			if (fd_array_size > 0)
+				fd_array_size *= 2;
+			else
+				fd_array_size = 32;
+
+			ptr = reallocarray(fd_array, fd_array_size, sizeof(int));
+			if (ptr == NULL)
+				break;
+			fd_array = ptr;
+		}
+
+		fd_array[fd_array_used++] = fd;
 	}
 
+	for (i = 0; i < fd_array_used; i++)
+		closefrom_close(fd_array[i]);
+
+	free(fd_array);
 	(void)closedir(dirp);
 
 	return 0;
commit 4cc43915f22c282ded2a9c3875ad7865fcb91fa5
Author: Guillem Jover <guillem at hadrons.org>
Date:   Sun Nov 2 23:58:23 2014 +0100

    Move procfs based implementation into a new closefrom_procfs() function

diff --git a/src/closefrom.c b/src/closefrom.c
index 03e84d8..27aa26f 100644
--- a/src/closefrom.c
+++ b/src/closefrom.c
@@ -123,11 +123,12 @@ closefrom(int lowfd)
 	}
 }
 #elif defined(HAVE_DIRFD)
-void
-closefrom(int lowfd)
+static int
+closefrom_procfs(int lowfd)
 {
 	const char *path;
 	DIR *dirp;
+	struct dirent *dent;
 
 	/* Use /proc/self/fd (or /dev/fd on FreeBSD) if it exists. */
 # if defined(__FreeBSD__) || defined(__APPLE__)
@@ -135,19 +136,30 @@ closefrom(int lowfd)
 # else
 	path = "/proc/self/fd";
 # endif
-	if ((dirp = opendir(path)) != NULL) {
-		struct dirent *dent;
-
-		while ((dent = readdir(dirp)) != NULL) {
-			const char *errstr;
-			int fd;
-
-			fd = strtonum(dent->d_name, lowfd, INT_MAX, &errstr);
-			if (errstr == NULL && fd != dirfd(dirp))
-				closefrom_close(fd);
-		}
-		(void)closedir(dirp);
-	} else
-		closefrom_fallback(lowfd);
+	dirp = opendir(path);
+	if (dirp == NULL)
+		return -1;
+
+	while ((dent = readdir(dirp)) != NULL) {
+		const char *errstr;
+		int fd;
+
+		fd = strtonum(dent->d_name, lowfd, INT_MAX, &errstr);
+		if (errstr == NULL && fd != dirfd(dirp))
+			closefrom_close(fd);
+	}
+
+	(void)closedir(dirp);
+
+	return 0;
+}
+
+void
+closefrom(int lowfd)
+{
+	if (closefrom_procfs(lowfd) == 0)
+		return;
+
+	closefrom_fallback(lowfd);
 }
 #endif /* HAVE_FCNTL_CLOSEM */
commit 34df1426653e79d170de399dfadc5b2709f85815
Author: Guillem Jover <guillem at hadrons.org>
Date:   Wed Nov 5 20:01:53 2014 +0100

    Refactor file descriptor closure into a new closefrom_close()

diff --git a/src/closefrom.c b/src/closefrom.c
index 423a004..03e84d8 100644
--- a/src/closefrom.c
+++ b/src/closefrom.c
@@ -60,6 +60,17 @@
 # define closefrom	closefrom_fallback
 #endif
 
+static inline void
+closefrom_close(int fd)
+{
+#ifdef __APPLE__
+	/* Avoid potential libdispatch crash when we close its fds. */
+	(void)fcntl(fd, F_SETFD, FD_CLOEXEC);
+#else
+	(void)close(fd);
+#endif
+}
+
 /*
  * Close all file descriptors greater than or equal to lowfd.
  * This is the expensive (fallback) method.
@@ -82,14 +93,8 @@ closefrom_fallback(int lowfd)
 	if (maxfd < 0)
 		maxfd = OPEN_MAX;
 
-	for (fd = lowfd; fd < maxfd; fd++) {
-#ifdef __APPLE__
-		/* Avoid potential libdispatch crash when we close its fds. */
-		(void)fcntl((int)fd, F_SETFD, FD_CLOEXEC);
-#else
-		(void)close((int)fd);
-#endif
-	}
+	for (fd = lowfd; fd < maxfd; fd++)
+		closefrom_close(fd);
 }
 
 /*
@@ -138,15 +143,8 @@ closefrom(int lowfd)
 			int fd;
 
 			fd = strtonum(dent->d_name, lowfd, INT_MAX, &errstr);
-			if (errstr == NULL && fd != dirfd(dirp)) {
-# ifdef __APPLE__
-				/* Avoid potential libdispatch crash when we
-				 * close its fds. */
-				(void)fcntl(fd, F_SETFD, FD_CLOEXEC);
-# else
-				(void)close(fd);
-# endif
-			}
+			if (errstr == NULL && fd != dirfd(dirp))
+				closefrom_close(fd);
 		}
 		(void)closedir(dirp);
 	} else
commit 3881c4fc68c7257ed22e1a25804039db5c9a0c95
Author: Guillem Jover <guillem at hadrons.org>
Date:   Sun Nov 2 00:23:00 2014 +0100

    Update closefrom() function
    
    Import from sudo. Adapt the build system to detect the required features.

diff --git a/configure.ac b/configure.ac
index 14bf306..97a606a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -40,7 +40,7 @@ fi
 # Checks for libraries.
 
 # Checks for header files.
-AC_CHECK_HEADERS([sys/ndir.h sys/dir.h dir.h dirent.h])
+AC_CHECK_HEADERS([sys/ndir.h sys/dir.h ndir.h dirent.h])
 
 # Checks for typedefs, structures, and compiler characteristics.
 AC_TYPE_UID_T
@@ -123,7 +123,8 @@ AC_LINK_IFELSE(
 	 AC_MSG_RESULT([yes])],
 	[AC_MSG_RESULT([no])])
 
-AC_CHECK_FUNCS([clearenv dirfd fopencookie __fpurge getexecname getline sysconf])
+AC_CHECK_FUNCS([clearenv dirfd fopencookie __fpurge getexecname getline \
+                pstat_getproc sysconf])
 
 AC_CONFIG_FILES([
 	Makefile
diff --git a/src/closefrom.c b/src/closefrom.c
index b7e2ad5..423a004 100644
--- a/src/closefrom.c
+++ b/src/closefrom.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004-2005, 2007, 2010
+ * Copyright (c) 2004-2005, 2007, 2010, 2012-2014
  *	Todd C. Miller <Todd.Miller at courtesan.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
@@ -18,7 +18,6 @@
 #include <config.h>
 
 #include <sys/types.h>
-#include <sys/param.h>
 #include <unistd.h>
 #include <stdio.h>
 #ifdef STDC_HEADERS
@@ -30,20 +29,26 @@
 # endif
 #endif /* STDC_HEADERS */
 #include <fcntl.h>
-#ifdef HAVE_DIRENT_H
-# include <dirent.h>
-# define NAMLEN(dirent) strlen((dirent)->d_name)
+#include <limits.h>
+#ifdef HAVE_PSTAT_GETPROC
+# include <sys/param.h>
+# include <sys/pstat.h>
 #else
-# define dirent direct
-# define NAMLEN(dirent) (dirent)->d_namlen
-# ifdef HAVE_SYS_NDIR_H
-#  include <sys/ndir.h>
-# endif
-# ifdef HAVE_SYS_DIR_H
-#  include <sys/dir.h>
-# endif
-# ifdef HAVE_NDIR_H
-#  include <ndir.h>
+# ifdef HAVE_DIRENT_H
+#  include <dirent.h>
+#  define NAMLEN(dirent) strlen((dirent)->d_name)
+# else
+#  define dirent direct
+#  define NAMLEN(dirent) (dirent)->d_namlen
+#  ifdef HAVE_SYS_NDIR_H
+#   include <sys/ndir.h>
+#  endif
+#  ifdef HAVE_SYS_DIR_H
+#   include <sys/dir.h>
+#  endif
+#  ifdef HAVE_NDIR_H
+#   include <ndir.h>
+#  endif
 # endif
 #endif
 
@@ -51,15 +56,13 @@
 # define OPEN_MAX 256
 #endif
 
-#ifndef HAVE_FCNTL_CLOSEM
-# ifndef HAVE_DIRFD
-#   define closefrom_fallback	closefrom
-# endif
+#if defined(HAVE_FCNTL_CLOSEM) && !defined(HAVE_DIRFD)
+# define closefrom	closefrom_fallback
 #endif
 
 /*
  * Close all file descriptors greater than or equal to lowfd.
- * This is the expensive (ballback) method.
+ * This is the expensive (fallback) method.
  */
 void
 closefrom_fallback(int lowfd)
@@ -79,44 +82,74 @@ closefrom_fallback(int lowfd)
 	if (maxfd < 0)
 		maxfd = OPEN_MAX;
 
-	for (fd = lowfd; fd < maxfd; fd++)
+	for (fd = lowfd; fd < maxfd; fd++) {
+#ifdef __APPLE__
+		/* Avoid potential libdispatch crash when we close its fds. */
+		(void)fcntl((int)fd, F_SETFD, FD_CLOEXEC);
+#else
 		(void)close((int)fd);
+#endif
+	}
 }
 
 /*
  * Close all file descriptors greater than or equal to lowfd.
  * We try the fast way first, falling back on the slow method.
  */
-#ifdef HAVE_FCNTL_CLOSEM
+#if defined(HAVE_FCNTL_CLOSEM)
 void
 closefrom(int lowfd)
 {
 	if (fcntl(lowfd, F_CLOSEM, 0) == -1)
 		closefrom_fallback(lowfd);
 }
-#else
-# ifdef HAVE_DIRFD
+#elif defined(HAVE_PSTAT_GETPROC)
+void
+closefrom(int lowfd)
+{
+	struct pst_status pstat;
+	int fd;
+
+	if (pstat_getproc(&pstat, sizeof(pstat), 0, getpid()) != -1) {
+		for (fd = lowfd; fd <= pstat.pst_highestfd; fd++)
+			(void)close(fd);
+	} else {
+		closefrom_fallback(lowfd);
+	}
+}
+#elif defined(HAVE_DIRFD)
 void
 closefrom(int lowfd)
 {
-	struct dirent *dent;
+	const char *path;
 	DIR *dirp;
-	char *endp;
-	long fd;
 
-	/* Use /proc/self/fd directory if it exists. */
-	dirp = opendir("/proc/self/fd");
-	if (dirp != NULL) {
+	/* Use /proc/self/fd (or /dev/fd on FreeBSD) if it exists. */
+# if defined(__FreeBSD__) || defined(__APPLE__)
+	path = "/dev/fd";
+# else
+	path = "/proc/self/fd";
+# endif
+	if ((dirp = opendir(path)) != NULL) {
+		struct dirent *dent;
+
 		while ((dent = readdir(dirp)) != NULL) {
-			fd = strtol(dent->d_name, &endp, 10);
-			if (dent->d_name != endp && *endp == '\0' &&
-			    fd >= 0 && fd < INT_MAX && fd >= lowfd &&
-			    fd != dirfd(dirp))
-				(void)close((int)fd);
+			const char *errstr;
+			int fd;
+
+			fd = strtonum(dent->d_name, lowfd, INT_MAX, &errstr);
+			if (errstr == NULL && fd != dirfd(dirp)) {
+# ifdef __APPLE__
+				/* Avoid potential libdispatch crash when we
+				 * close its fds. */
+				(void)fcntl(fd, F_SETFD, FD_CLOEXEC);
+# else
+				(void)close(fd);
+# endif
+			}
 		}
 		(void)closedir(dirp);
 	} else
 		closefrom_fallback(lowfd);
 }
-#endif /* HAVE_DIRFD */
 #endif /* HAVE_FCNTL_CLOSEM */
commit 3a3d87d7301794bd4950bb583dfa590981b842e2
Author: Guillem Jover <guillem at hadrons.org>
Date:   Wed Sep 23 04:40:21 2015 +0200

    test: Add closefrom() unit test

diff --git a/test/.gitignore b/test/.gitignore
index 1a67d6d..ab051cc 100644
--- a/test/.gitignore
+++ b/test/.gitignore
@@ -1,3 +1,4 @@
+closefrom
 endian
 fgetln
 funopen
diff --git a/test/Makefile.am b/test/Makefile.am
index 4a5bad2..0f5ff4e 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -12,6 +12,7 @@ LDADD = $(top_builddir)/src/libbsd.la
 check_PROGRAMS = \
 	headers \
 	overlay \
+	closefrom \
 	endian \
 	humanize \
 	fgetln \
diff --git a/test/closefrom.c b/test/closefrom.c
new file mode 100644
index 0000000..b5e7e92
--- /dev/null
+++ b/test/closefrom.c
@@ -0,0 +1,53 @@
+/*
+ * 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 <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+
+int
+main()
+{
+	int i;
+	int fd;
+
+	fd = open("/dev/null", O_RDONLY);
+
+	for (i = 4; i < 1024; i *= 2)
+		assert(dup2(fd, i) == i);
+
+	if (fd < 4)
+		close(fd);
+	closefrom(4);
+
+	for (i = 4; i < 1024; i++)
+		assert(fcntl(i, F_GETFL) == -1 && errno == EBADF);
+	assert(fcntl(fd, F_GETFL) == -1 && errno == EBADF);
+
+	return 0;
+}
commit d62f7d8facf087b5e93508067ec228864fe76990
Author: Guillem Jover <guillem at hadrons.org>
Date:   Sat Nov 1 00:55:55 2014 +0100

    test: Add test case for fpurge(NULL)

diff --git a/test/fpurge.c b/test/fpurge.c
index 8f2e996..03f107f 100644
--- a/test/fpurge.c
+++ b/test/fpurge.c
@@ -32,6 +32,9 @@ main()
 	static FILE fp_bad;
 	FILE *fp;
 
+	if (fpurge(NULL) == 0)
+		return 1;
+
 	if (fpurge(&fp_bad) == 0)
 		return 1;
 
commit cfb4d462a9be19c1dfd5e7793ea267a0bb111a11
Author: Guillem Jover <guillem at hadrons.org>
Date:   Sat Nov 1 00:54:09 2014 +0100

    test: Move and activate fpurge() test case from module to a dedicated file

diff --git a/src/fpurge.c b/src/fpurge.c
index e31b84a..462535a 100644
--- a/src/fpurge.c
+++ b/src/fpurge.c
@@ -44,23 +44,3 @@ fpurge(FILE *fp)
 #else
 #error "Function fpurge() needs to be ported."
 #endif
-
-#ifdef TEST
-int
-main()
-{
-	static FILE fp_bad;
-	FILE *fp;
-
-	if (fpurge(&fp_bad) == 0)
-		return 1;
-
-	fp = fopen("/dev/zero", "r");
-	if (fpurge(fp) < 0)
-		return 1;
-
-	fclose(fp);
-
-	return 0;
-}
-#endif
diff --git a/test/.gitignore b/test/.gitignore
index e351ab1..1a67d6d 100644
--- a/test/.gitignore
+++ b/test/.gitignore
@@ -1,6 +1,7 @@
 endian
 fgetln
 funopen
+fpurge
 headers
 humanize
 overlay
diff --git a/test/Makefile.am b/test/Makefile.am
index eb32e85..4a5bad2 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -16,6 +16,7 @@ check_PROGRAMS = \
 	humanize \
 	fgetln \
 	funopen \
+	fpurge \
 	proctitle-init \
 	$(nil)
 
diff --git a/test/fpurge.c b/test/fpurge.c
new file mode 100644
index 0000000..8f2e996
--- /dev/null
+++ b/test/fpurge.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright © 2011 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 <stdio.h>
+
+int
+main()
+{
+	static FILE fp_bad;
+	FILE *fp;
+
+	if (fpurge(&fp_bad) == 0)
+		return 1;
+
+	fp = fopen("/dev/zero", "r");
+	if (fpurge(fp) < 0)
+		return 1;
+
+	fclose(fp);
+
+	return 0;
+}
commit 205827a2dd16e5a14628631eea926f9da9b672a7
Author: Guillem Jover <guillem at hadrons.org>
Date:   Sat Nov 1 00:52:42 2014 +0100

    build: Centralize testsuite LDADD setting in a single variable

diff --git a/test/Makefile.am b/test/Makefile.am
index c6e2daa..eb32e85 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -7,6 +7,8 @@ AM_CPPFLAGS = \
 	-DLIBBSD_OVERLAY -DLIBBSD_DISABLE_DEPRECATED \
 	-D__REENTRANT
 
+LDADD = $(top_builddir)/src/libbsd.la
+
 check_PROGRAMS = \
 	headers \
 	overlay \
@@ -21,12 +23,9 @@ if BUILD_LIBBSD_CTOR
 check_PROGRAMS += proctitle
 endif
 
-humanize_LDFLAGS = $(top_builddir)/src/libbsd.la
-fgetln_LDFLAGS = $(top_builddir)/src/libbsd.la
-funopen_LDFLAGS = $(top_builddir)/src/libbsd.la
 proctitle_init_SOURCES = proctitle.c
 proctitle_init_CPPFLAGS = $(AM_CPPFLAGS) -DTEST_USE_SETPROCTITLE_INIT=1
-proctitle_init_LDFLAGS = $(top_builddir)/src/libbsd.la
+
 proctitle_LDFLAGS = \
 	-Wl,-u,libbsd_init_func \
 	$(top_builddir)/src/libbsd-ctor.a \
commit c7e01e9884a2478360a2629aea5583eaf7be0ea2
Author: Guillem Jover <guillem at hadrons.org>
Date:   Sat Nov 1 00:22:28 2014 +0100

    Sync queue(3) from FreeBSD
    
    Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=85147

diff --git a/include/bsd/sys/queue.h b/include/bsd/sys/queue.h
index f1f35c8..55bd494 100644
--- a/include/bsd/sys/queue.h
+++ b/include/bsd/sys/queue.h
@@ -65,7 +65,7 @@
  * so that an arbitrary element can be removed without a need to
  * traverse the list. New elements can be added to the list before
  * or after an existing element or at the head of the list. A list
- * may only be traversed in the forward direction.
+ * may be traversed in either direction.
  *
  * A tail queue is headed by a pair of pointers, one to the head of the
  * list and the other to the tail of the list. The elements are doubly
@@ -85,12 +85,16 @@
  * _EMPTY			+	+	+	+
  * _FIRST			+	+	+	+
  * _NEXT			+	+	+	+
- * _PREV			-	-	-	+
+ * _PREV			-	+	-	+
  * _LAST			-	-	+	+
  * _FOREACH			+	+	+	+
+ * _FOREACH_FROM		+	+	+	+
  * _FOREACH_SAFE		+	+	+	+
+ * _FOREACH_FROM_SAFE		+	+	+	+
  * _FOREACH_REVERSE		-	-	-	+
+ * _FOREACH_REVERSE_FROM	-	-	-	+
  * _FOREACH_REVERSE_SAFE	-	-	-	+
+ * _FOREACH_REVERSE_FROM_SAFE	-	-	-	+
  * _INSERT_HEAD			+	+	+	+
  * _INSERT_BEFORE		-	+	-	+
  * _INSERT_AFTER		+	+	+	+
@@ -99,19 +103,22 @@
  * _REMOVE_AFTER		+	-	+	-
  * _REMOVE_HEAD			+	-	+	-
  * _REMOVE			+	+	+	+
+ * _SWAP			+	+	+	+
  *
  */
 #ifdef QUEUE_MACRO_DEBUG
 /* Store the last 2 places the queue element or head was altered */
 struct qm_trace {
-	char * lastfile;
-	int lastline;
-	char * prevfile;
-	int prevline;
+	unsigned long	 lastline;
+	unsigned long	 prevline;
+	const char	*lastfile;
+	const char	*prevfile;
 };
 
 #define	TRACEBUF	struct qm_trace trace;
+#define	TRACEBUF_INITIALIZER	{ __FILE__, __LINE__, NULL, 0 } ,
 #define	TRASHIT(x)	do {(x) = (void *)-1;} while (0)
+#define	QMD_SAVELINK(name, link)	void **name = (void *)&(link)
 
 #define	QMD_TRACE_HEAD(head) do {					\
 	(head)->trace.prevline = (head)->trace.lastline;		\
@@ -130,7 +137,9 @@ struct qm_trace {
 #else
 #define	QMD_TRACE_ELEM(elem)
 #define	QMD_TRACE_HEAD(head)
+#define	QMD_SAVELINK(name, link)
 #define	TRACEBUF
+#define	TRACEBUF_INITIALIZER
 #define	TRASHIT(x)
 #endif	/* QUEUE_MACRO_DEBUG */
 
@@ -162,11 +171,21 @@ struct {								\
 	    (var);							\
 	    (var) = SLIST_NEXT((var), field))
 
+#define	SLIST_FOREACH_FROM(var, head, field)				\
+	for ((var) = ((var) ? (var) : SLIST_FIRST((head)));		\
+	    (var);							\
+	    (var) = SLIST_NEXT((var), field))
+
 #define	SLIST_FOREACH_SAFE(var, head, field, tvar)			\
 	for ((var) = SLIST_FIRST((head));				\
 	    (var) && ((tvar) = SLIST_NEXT((var), field), 1);		\
 	    (var) = (tvar))
 
+#define	SLIST_FOREACH_FROM_SAFE(var, head, field, tvar)			\
+	for ((var) = ((var) ? (var) : SLIST_FIRST((head)));		\
+	    (var) && ((tvar) = SLIST_NEXT((var), field), 1);		\
+	    (var) = (tvar))
+
 #define	SLIST_FOREACH_PREVPTR(var, varp, head, field)			\
 	for ((varp) = &SLIST_FIRST((head));				\
 	    ((var) = *(varp)) != NULL;					\
@@ -189,6 +208,7 @@ struct {								\
 #define	SLIST_NEXT(elm, field)	((elm)->field.sle_next)
 
 #define	SLIST_REMOVE(head, elm, type, field) do {			\
+	QMD_SAVELINK(oldnext, (elm)->field.sle_next);			\
 	if (SLIST_FIRST((head)) == (elm)) {				\
 		SLIST_REMOVE_HEAD((head), field);			\
 	}								\
@@ -198,7 +218,7 @@ struct {								\
 			curelm = SLIST_NEXT(curelm, field);		\
 		SLIST_REMOVE_AFTER(curelm, field);			\
 	}								\
-	TRASHIT((elm)->field.sle_next);					\
+	TRASHIT(*oldnext);						\
 } while (0)
 
 #define SLIST_REMOVE_AFTER(elm, field) do {				\
@@ -210,6 +230,12 @@ struct {								\
 	SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field);	\
 } while (0)
 
+#define SLIST_SWAP(head1, head2, type) do {				\
+	struct type *swap_first = SLIST_FIRST(head1);			\
+	SLIST_FIRST(head1) = SLIST_FIRST(head2);			\
+	SLIST_FIRST(head2) = swap_first;				\
+} while (0)
+
 /*
  * Singly-linked Tail queue declarations.
  */
@@ -247,12 +273,21 @@ struct {								\
 	   (var);							\
 	   (var) = STAILQ_NEXT((var), field))
 
+#define	STAILQ_FOREACH_FROM(var, head, field)				\
+	for ((var) = ((var) ? (var) : STAILQ_FIRST((head)));		\
+	   (var);							\
+	   (var) = STAILQ_NEXT((var), field))
 
 #define	STAILQ_FOREACH_SAFE(var, head, field, tvar)			\
 	for ((var) = STAILQ_FIRST((head));				\
 	    (var) && ((tvar) = STAILQ_NEXT((var), field), 1);		\
 	    (var) = (tvar))
 
+#define	STAILQ_FOREACH_FROM_SAFE(var, head, field, tvar)		\
+	for ((var) = ((var) ? (var) : STAILQ_FIRST((head)));		\
+	    (var) && ((tvar) = STAILQ_NEXT((var), field), 1);		\
+	    (var) = (tvar))
+
 #define	STAILQ_INIT(head) do {						\
 	STAILQ_FIRST((head)) = NULL;					\
 	(head)->stqh_last = &STAILQ_FIRST((head));			\
@@ -277,14 +312,13 @@ struct {								\
 } while (0)
 
 #define	STAILQ_LAST(head, type, field)					\
-	(STAILQ_EMPTY((head)) ?						\
-		NULL :							\
-	        ((struct type *)(void *)				\
-		((char *)((head)->stqh_last) - __offsetof(struct type, field))))
+	(STAILQ_EMPTY((head)) ? NULL :					\
+	    __containerof((head)->stqh_last, struct type, field.stqe_next))
 
 #define	STAILQ_NEXT(elm, field)	((elm)->field.stqe_next)
 
 #define	STAILQ_REMOVE(head, elm, type, field) do {			\
+	QMD_SAVELINK(oldnext, (elm)->field.stqe_next);			\
 	if (STAILQ_FIRST((head)) == (elm)) {				\
 		STAILQ_REMOVE_HEAD((head), field);			\
 	}								\
@@ -294,13 +328,7 @@ struct {								\
 			curelm = STAILQ_NEXT(curelm, field);		\
 		STAILQ_REMOVE_AFTER(head, curelm, field);		\
 	}								\
-	TRASHIT((elm)->field.stqe_next);				\
-} while (0)
-
-#define	STAILQ_REMOVE_HEAD(head, field) do {				\
-	if ((STAILQ_FIRST((head)) =					\
-	     STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL)		\
-		(head)->stqh_last = &STAILQ_FIRST((head));		\
+	TRASHIT(*oldnext);						\
 } while (0)
 
 #define STAILQ_REMOVE_AFTER(head, elm, field) do {			\
@@ -309,6 +337,12 @@ struct {								\
 		(head)->stqh_last = &STAILQ_NEXT((elm), field);		\
 } while (0)
 
+#define	STAILQ_REMOVE_HEAD(head, field) do {				\
+	if ((STAILQ_FIRST((head)) =					\
+	     STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL)		\
+		(head)->stqh_last = &STAILQ_FIRST((head));		\
+} while (0)
+
 #define STAILQ_SWAP(head1, head2, type) do {				\
 	struct type *swap_first = STAILQ_FIRST(head1);			\
 	struct type **swap_last = (head1)->stqh_last;			\
@@ -378,11 +412,21 @@ struct {								\
 	    (var);							\
 	    (var) = LIST_NEXT((var), field))
 
+#define	LIST_FOREACH_FROM(var, head, field)				\
+	for ((var) = ((var) ? (var) : LIST_FIRST((head)));		\
+	    (var);							\
+	    (var) = LIST_NEXT((var), field))
+
 #define	LIST_FOREACH_SAFE(var, head, field, tvar)			\
 	for ((var) = LIST_FIRST((head));				\
 	    (var) && ((tvar) = LIST_NEXT((var), field), 1);		\
 	    (var) = (tvar))
 
+#define	LIST_FOREACH_FROM_SAFE(var, head, field, tvar)			\
+	for ((var) = ((var) ? (var) : LIST_FIRST((head)));		\
+	    (var) && ((tvar) = LIST_NEXT((var), field), 1);		\
+	    (var) = (tvar))
+
 #define	LIST_INIT(head) do {						\
 	LIST_FIRST((head)) = NULL;					\
 } while (0)
@@ -414,15 +458,21 @@ struct {								\
 
 #define	LIST_NEXT(elm, field)	((elm)->field.le_next)
 
+#define	LIST_PREV(elm, head, type, field)				\
+	((elm)->field.le_prev == &LIST_FIRST((head)) ? NULL :		\
+	    __containerof((elm)->field.le_prev, struct type, field.le_next))
+
 #define	LIST_REMOVE(elm, field) do {					\
+	QMD_SAVELINK(oldnext, (elm)->field.le_next);			\
+	QMD_SAVELINK(oldprev, (elm)->field.le_prev);			\
 	QMD_LIST_CHECK_NEXT(elm, field);				\
 	QMD_LIST_CHECK_PREV(elm, field);				\
 	if (LIST_NEXT((elm), field) != NULL)				\
 		LIST_NEXT((elm), field)->field.le_prev = 		\
 		    (elm)->field.le_prev;				\
 	*(elm)->field.le_prev = LIST_NEXT((elm), field);		\
-	TRASHIT((elm)->field.le_next);					\
-	TRASHIT((elm)->field.le_prev);					\
+	TRASHIT(*oldnext);						\
+	TRASHIT(*oldprev);						\
 } while (0)
 
 #define LIST_SWAP(head1, head2, type, field) do {			\
@@ -446,7 +496,7 @@ struct name {								\
 }
 
 #define	TAILQ_HEAD_INITIALIZER(head)					\
-	{ NULL, &(head).tqh_first }
+	{ NULL, &(head).tqh_first, TRACEBUF_INITIALIZER }
 
 #define	TAILQ_ENTRY(type)						\
 struct {								\
@@ -509,21 +559,41 @@ struct {								\
 	    (var);							\
 	    (var) = TAILQ_NEXT((var), field))
 
+#define	TAILQ_FOREACH_FROM(var, head, field)				\
+	for ((var) = ((var) ? (var) : TAILQ_FIRST((head)));		\
+	    (var);							\
+	    (var) = TAILQ_NEXT((var), field))
+
 #define	TAILQ_FOREACH_SAFE(var, head, field, tvar)			\
 	for ((var) = TAILQ_FIRST((head));				\
 	    (var) && ((tvar) = TAILQ_NEXT((var), field), 1);		\
 	    (var) = (tvar))
 
+#define	TAILQ_FOREACH_FROM_SAFE(var, head, field, tvar)			\
+	for ((var) = ((var) ? (var) : TAILQ_FIRST((head)));		\
+	    (var) && ((tvar) = TAILQ_NEXT((var), field), 1);		\
+	    (var) = (tvar))
+
 #define	TAILQ_FOREACH_REVERSE(var, head, headname, field)		\
 	for ((var) = TAILQ_LAST((head), headname);			\
 	    (var);							\
 	    (var) = TAILQ_PREV((var), headname, field))
 
+#define	TAILQ_FOREACH_REVERSE_FROM(var, head, headname, field)		\
+	for ((var) = ((var) ? (var) : TAILQ_LAST((head), headname));	\
+	    (var);							\
+	    (var) = TAILQ_PREV((var), headname, field))
+
 #define	TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar)	\
 	for ((var) = TAILQ_LAST((head), headname);			\
 	    (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1);	\
 	    (var) = (tvar))
 
+#define	TAILQ_FOREACH_REVERSE_FROM_SAFE(var, head, headname, field, tvar) \
+	for ((var) = ((var) ? (var) : TAILQ_LAST((head), headname));	\
+	    (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1);	\
+	    (var) = (tvar))
+
 #define	TAILQ_INIT(head) do {						\
 	TAILQ_FIRST((head)) = NULL;					\
 	(head)->tqh_last = &TAILQ_FIRST((head));			\
@@ -587,6 +657,8 @@ struct {								\
 	(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
 
 #define	TAILQ_REMOVE(head, elm, field) do {				\
+	QMD_SAVELINK(oldnext, (elm)->field.tqe_next);			\
+	QMD_SAVELINK(oldprev, (elm)->field.tqe_prev);			\
 	QMD_TAILQ_CHECK_NEXT(elm, field);				\
 	QMD_TAILQ_CHECK_PREV(elm, field);				\
 	if ((TAILQ_NEXT((elm), field)) != NULL)				\
@@ -597,8 +669,8 @@ struct {								\
 		QMD_TRACE_HEAD(head);					\
 	}								\
 	*(elm)->field.tqe_prev = TAILQ_NEXT((elm), field);		\
-	TRASHIT((elm)->field.tqe_next);					\
-	TRASHIT((elm)->field.tqe_prev);					\
+	TRASHIT(*oldnext);						\
+	TRASHIT(*oldprev);						\
 	QMD_TRACE_ELEM(&(elm)->field);					\
 } while (0)
 
diff --git a/man/queue.3bsd b/man/queue.3bsd
index fc861e7..62623b7 100644
--- a/man/queue.3bsd
+++ b/man/queue.3bsd
@@ -9,7 +9,7 @@
 .\" 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
+.\" 3. 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.
 .\"
@@ -28,15 +28,17 @@
 .\"	@(#)queue.3	8.2 (Berkeley) 1/24/94
 .\" $FreeBSD$
 .\"
-.Dd May 13, 2011
-.Dt QUEUE 3bsd
+.Dd June 17, 2013
+.Dt QUEUE 3
 .Os
 .Sh NAME
 .Nm SLIST_EMPTY ,
 .Nm SLIST_ENTRY ,
 .Nm SLIST_FIRST ,
 .Nm SLIST_FOREACH ,
+.Nm SLIST_FOREACH_FROM ,
 .Nm SLIST_FOREACH_SAFE ,
+.Nm SLIST_FOREACH_FROM_SAFE ,
 .Nm SLIST_HEAD ,
 .Nm SLIST_HEAD_INITIALIZER ,
 .Nm SLIST_INIT ,
@@ -52,7 +54,9 @@
 .Nm STAILQ_ENTRY ,
 .Nm STAILQ_FIRST ,
 .Nm STAILQ_FOREACH ,
+.Nm STAILQ_FOREACH_FROM ,
 .Nm STAILQ_FOREACH_SAFE ,
+.Nm STAILQ_FOREACH_FROM_SAFE ,
 .Nm STAILQ_HEAD ,
 .Nm STAILQ_HEAD_INITIALIZER ,
 .Nm STAILQ_INIT ,
@@ -69,7 +73,9 @@
 .Nm LIST_ENTRY ,
 .Nm LIST_FIRST ,
 .Nm LIST_FOREACH ,
+.Nm LIST_FOREACH_FROM ,
 .Nm LIST_FOREACH_SAFE ,
+.Nm LIST_FOREACH_FROM_SAFE ,
 .Nm LIST_HEAD ,
 .Nm LIST_HEAD_INITIALIZER ,
 .Nm LIST_INIT ,
@@ -77,6 +83,7 @@
 .Nm LIST_INSERT_BEFORE ,
 .Nm LIST_INSERT_HEAD ,
 .Nm LIST_NEXT ,
+.Nm LIST_PREV ,
 .Nm LIST_REMOVE ,
 .Nm LIST_SWAP ,
 .Nm TAILQ_CONCAT ,
@@ -84,9 +91,13 @@
 .Nm TAILQ_ENTRY ,
 .Nm TAILQ_FIRST ,
 .Nm TAILQ_FOREACH ,
+.Nm TAILQ_FOREACH_FROM ,
 .Nm TAILQ_FOREACH_SAFE ,
+.Nm TAILQ_FOREACH_FROM_SAFE ,
 .Nm TAILQ_FOREACH_REVERSE ,
+.Nm TAILQ_FOREACH_REVERSE_FROM ,
 .Nm TAILQ_FOREACH_REVERSE_SAFE ,
+.Nm TAILQ_FOREACH_REVERSE_FROM_SAFE ,
 .Nm TAILQ_HEAD ,
 .Nm TAILQ_HEAD_INITIALIZER ,
 .Nm TAILQ_INIT ,
@@ -108,7 +119,9 @@ lists and tail queues
 .Fn SLIST_ENTRY "TYPE"
 .Fn SLIST_FIRST "SLIST_HEAD *head"
 .Fn SLIST_FOREACH "TYPE *var" "SLIST_HEAD *head" "SLIST_ENTRY NAME"
+.Fn SLIST_FOREACH_FROM "TYPE *var" "SLIST_HEAD *head" "SLIST_ENTRY NAME"
 .Fn SLIST_FOREACH_SAFE "TYPE *var" "SLIST_HEAD *head" "SLIST_ENTRY NAME" "TYPE *temp_var"
+.Fn SLIST_FOREACH_FROM_SAFE "TYPE *var" "SLIST_HEAD *head" "SLIST_ENTRY NAME" "TYPE *temp_var"
 .Fn SLIST_HEAD "HEADNAME" "TYPE"
 .Fn SLIST_HEAD_INITIALIZER "SLIST_HEAD head"
 .Fn SLIST_INIT "SLIST_HEAD *head"
@@ -125,7 +138,9 @@ lists and tail queues
 .Fn STAILQ_ENTRY "TYPE"
 .Fn STAILQ_FIRST "STAILQ_HEAD *head"
 .Fn STAILQ_FOREACH "TYPE *var" "STAILQ_HEAD *head" "STAILQ_ENTRY NAME"
+.Fn STAILQ_FOREACH_FROM "TYPE *var" "STAILQ_HEAD *head" "STAILQ_ENTRY NAME"
 .Fn STAILQ_FOREACH_SAFE "TYPE *var" "STAILQ_HEAD *head" "STAILQ_ENTRY NAME" "TYPE *temp_var"
+.Fn STAILQ_FOREACH_FROM_SAFE "TYPE *var" "STAILQ_HEAD *head" "STAILQ_ENTRY NAME" "TYPE *temp_var"
 .Fn STAILQ_HEAD "HEADNAME" "TYPE"
 .Fn STAILQ_HEAD_INITIALIZER "STAILQ_HEAD head"
 .Fn STAILQ_INIT "STAILQ_HEAD *head"
@@ -143,7 +158,9 @@ lists and tail queues
 .Fn LIST_ENTRY "TYPE"
 .Fn LIST_FIRST "LIST_HEAD *head"
 .Fn LIST_FOREACH "TYPE *var" "LIST_HEAD *head" "LIST_ENTRY NAME"
+.Fn LIST_FOREACH_FROM "TYPE *var" "LIST_HEAD *head" "LIST_ENTRY NAME"
 .Fn LIST_FOREACH_SAFE "TYPE *var" "LIST_HEAD *head" "LIST_ENTRY NAME" "TYPE *temp_var"
+.Fn LIST_FOREACH_FROM_SAFE "TYPE *var" "LIST_HEAD *head" "LIST_ENTRY NAME" "TYPE *temp_var"
 .Fn LIST_HEAD "HEADNAME" "TYPE"
 .Fn LIST_HEAD_INITIALIZER "LIST_HEAD head"
 .Fn LIST_INIT "LIST_HEAD *head"
@@ -151,6 +168,7 @@ lists and tail queues
 .Fn LIST_INSERT_BEFORE "TYPE *listelm" "TYPE *elm" "LIST_ENTRY NAME"
 .Fn LIST_INSERT_HEAD "LIST_HEAD *head" "TYPE *elm" "LIST_ENTRY NAME"
 .Fn LIST_NEXT "TYPE *elm" "LIST_ENTRY NAME"
+.Fn LIST_PREV "TYPE *elm" "LIST_HEAD *head" "TYPE" "LIST_ENTRY NAME"
 .Fn LIST_REMOVE "TYPE *elm" "LIST_ENTRY NAME"
 .Fn LIST_SWAP "LIST_HEAD *head1" "LIST_HEAD *head2" "TYPE" "LIST_ENTRY NAME"
 .\"
@@ -159,9 +177,13 @@ lists and tail queues
 .Fn TAILQ_ENTRY "TYPE"
 .Fn TAILQ_FIRST "TAILQ_HEAD *head"
 .Fn TAILQ_FOREACH "TYPE *var" "TAILQ_HEAD *head" "TAILQ_ENTRY NAME"
+.Fn TAILQ_FOREACH_FROM "TYPE *var" "TAILQ_HEAD *head" "TAILQ_ENTRY NAME"
 .Fn TAILQ_FOREACH_SAFE "TYPE *var" "TAILQ_HEAD *head" "TAILQ_ENTRY NAME" "TYPE *temp_var"
+.Fn TAILQ_FOREACH_FROM_SAFE "TYPE *var" "TAILQ_HEAD *head" "TAILQ_ENTRY NAME" "TYPE *temp_var"
 .Fn TAILQ_FOREACH_REVERSE "TYPE *var" "TAILQ_HEAD *head" "HEADNAME" "TAILQ_ENTRY NAME"
+.Fn TAILQ_FOREACH_REVERSE_FROM "TYPE *var" "TAILQ_HEAD *head" "HEADNAME" "TAILQ_ENTRY NAME"
 .Fn TAILQ_FOREACH_REVERSE_SAFE "TYPE *var" "TAILQ_HEAD *head" "HEADNAME" "TAILQ_ENTRY NAME" "TYPE *temp_var"
+.Fn TAILQ_FOREACH_REVERSE_FROM_SAFE "TYPE *var" "TAILQ_HEAD *head" "HEADNAME" "TAILQ_ENTRY NAME" "TYPE *temp_var"
 .Fn TAILQ_HEAD "HEADNAME" "TYPE"
 .Fn TAILQ_HEAD_INITIALIZER "TAILQ_HEAD head"
 .Fn TAILQ_INIT "TAILQ_HEAD *head"
@@ -244,8 +266,18 @@ Code size and execution time of operations (except for removal) is about
 twice that of the singly-linked data-structures.
 .El
 .Pp
-Linked lists are the simplest of the doubly linked data structures and support
-only the above functionality over singly-linked lists.
+Linked lists are the simplest of the doubly linked data structures.
+They add the following functionality over the above:
+.Bl -enum -compact -offset indent
+.It
+They may be traversed backwards.
+.El
+However:
+.Bl -enum -compact -offset indent
+.It
+To traverse backwards, an entry to begin the traversal and the list in
+which it is contained must be specified.
+.El
 .Pp
 Tail queues add the following functionality:
 .Bl -enum -compact -offset indent
@@ -349,6 +381,19 @@ turn to
 .Fa var .
 .Pp
 The macro
+.Nm SLIST_FOREACH_FROM
+behaves identically to
+.Nm SLIST_FOREACH
+when
+.Fa var
+is NULL, else it treats
+.Fa var
+as a previously found SLIST element and begins the loop at
+.Fa var
+instead of the first element in the SLIST referenced by
+.Fa head .
+.Pp
+The macro
 .Nm SLIST_FOREACH_SAFE
 traverses the list referenced by
 .Fa head
@@ -363,6 +408,19 @@ as well as free it from within the loop safely without interfering with the
 traversal.
 .Pp
 The macro
+.Nm SLIST_FOREACH_FROM_SAFE
+behaves identically to
+.Nm SLIST_FOREACH_SAFE
+when
+.Fa var
+is NULL, else it treats
+.Fa var
+as a previously found SLIST element and begins the loop at
+.Fa var
+instead of the first element in the SLIST referenced by
+.Fa head .
+.Pp
+The macro
 .Nm SLIST_INIT
 initializes the list referenced by
 .Fa head .
@@ -388,7 +446,8 @@ The macro
 .Nm SLIST_REMOVE_AFTER
 removes the element after
 .Fa elm
-from the list. Unlike
+from the list.
+Unlike
 .Fa SLIST_REMOVE ,
 this macro does not traverse the entire list.
 .Pp
@@ -528,6 +587,19 @@ in turn to
 .Fa var .
 .Pp
 The macro
+.Nm STAILQ_FOREACH_FROM
+behaves identically to
+.Nm STAILQ_FOREACH
+when
+.Fa var
+is NULL, else it treats
+.Fa var
+as a previously found STAILQ element and begins the loop at
+.Fa var
+instead of the first element in the STAILQ referenced by
+.Fa head .
+.Pp
+The macro
 .Nm STAILQ_FOREACH_SAFE
 traverses the tail queue referenced by
 .Fa head
@@ -542,6 +614,19 @@ as well as free it from within the loop safely without interfering with the
 traversal.
 .Pp
 The macro
+.Nm STAILQ_FOREACH_FROM_SAFE
+behaves identically to
+.Nm STAILQ_FOREACH_SAFE
+when
+.Fa var
+is NULL, else it treats
+.Fa var
+as a previously found STAILQ element and begins the loop at
+.Fa var
+instead of the first element in the STAILQ referenced by
+.Fa head .
+.Pp
+The macro
 .Nm STAILQ_INIT
 initializes the tail queue referenced by
 .Fa head .
@@ -579,7 +664,8 @@ The macro
 .Nm STAILQ_REMOVE_AFTER
 removes the element after
 .Fa elm
-from the tail queue. Unlike
+from the tail queue.
+Unlike
 .Fa STAILQ_REMOVE ,
 this macro does not traverse the entire tail queue.
 .Pp
@@ -717,6 +803,19 @@ in the forward direction, assigning each element in turn to
 .Fa var .
 .Pp
 The macro
+.Nm LIST_FOREACH_FROM
+behaves identically to
+.Nm LIST_FOREACH
+when
+.Fa var
+is NULL, else it treats
+.Fa var
+as a previously found LIST element and begins the loop at
+.Fa var
+instead of the first element in the LIST referenced by
+.Fa head .
+.Pp
+The macro
 .Nm LIST_FOREACH_SAFE
 traverses the list referenced by
 .Fa head
@@ -730,6 +829,19 @@ as well as free it from within the loop safely without interfering with the
 traversal.
 .Pp
 The macro
+.Nm LIST_FOREACH_FROM_SAFE
+behaves identically to
+.Nm LIST_FOREACH_SAFE
+when
+.Fa var
+is NULL, else it treats
+.Fa var
+as a previously found LIST element and begins the loop at
+.Fa var
+instead of the first element in the LIST referenced by
+.Fa head .
+.Pp
+The macro
 .Nm LIST_INIT
 initializes the list referenced by
 .Fa head .
@@ -759,6 +871,14 @@ The macro
 returns the next element in the list, or NULL if this is the last.
 .Pp
 The macro
+.Nm LIST_PREV
+returns the previous element in the list, or NULL if this is the first.
+List
+.Fa head
+must contain element
+.Fa elm .
+.Pp
+The macro
 .Nm LIST_REMOVE
 removes the element
 .Fa elm
@@ -894,12 +1014,38 @@ is set to
 if the loop completes normally, or if there were no elements.
 .Pp
 The macro
+.Nm TAILQ_FOREACH_FROM
+behaves identically to
+.Nm TAILQ_FOREACH
+when
+.Fa var
+is NULL, else it treats
+.Fa var
+as a previously found TAILQ element and begins the loop at
+.Fa var
+instead of the first element in the TAILQ referenced by
+.Fa head .
+.Pp
+The macro
 .Nm TAILQ_FOREACH_REVERSE
 traverses the tail queue referenced by
 .Fa head
 in the reverse direction, assigning each element in turn to
 .Fa var .
 .Pp
+The macro
+.Nm TAILQ_FOREACH_REVERSE_FROM
+behaves identically to
+.Nm TAILQ_FOREACH_REVERSE
+when
+.Fa var
+is NULL, else it treats
+.Fa var
+as a previously found TAILQ element and begins the reverse loop at
+.Fa var
+instead of the last element in the TAILQ referenced by
+.Fa head .
+.Pp
 The macros
 .Nm TAILQ_FOREACH_SAFE
 and
@@ -919,6 +1065,32 @@ as well as free it from within the loop safely without interfering with the
 traversal.
 .Pp
 The macro
+.Nm TAILQ_FOREACH_FROM_SAFE
+behaves identically to
+.Nm TAILQ_FOREACH_SAFE
+when
+.Fa var
+is NULL, else it treats
+.Fa var
+as a previously found TAILQ element and begins the loop at
+.Fa var
+instead of the first element in the TAILQ referenced by
+.Fa head .
+.Pp
+The macro
+.Nm TAILQ_FOREACH_REVERSE_FROM_SAFE
+behaves identically to
+.Nm TAILQ_FOREACH_REVERSE_SAFE
+when
+.Fa var
+is NULL, else it treats
+.Fa var
+as a previously found TAILQ element and begins the reverse loop at
+.Fa var
+instead of the last element in the TAILQ referenced by
+.Fa head .
+.Pp
+The macro
 .Nm TAILQ_INIT
 initializes the tail queue referenced by
 .Fa head .
commit 326711448308c4197923d75f40ae02162f152ce8
Author: Guillem Jover <guillem at hadrons.org>
Date:   Sat Nov 1 00:21:30 2014 +0100

    Add __offsetof, __rangeof and __containerof to sys/cdefs.h
    
    Import and adapt from FreeBSD.

diff --git a/include/bsd/sys/cdefs.h b/include/bsd/sys/cdefs.h
index c1567be..4b1063a 100644
--- a/include/bsd/sys/cdefs.h
+++ b/include/bsd/sys/cdefs.h
@@ -114,6 +114,47 @@
 # define __bounded__(x, y, z)
 #endif
 
+/*
+ * We define this here since <stddef.h>, <sys/queue.h>, and <sys/types.h>
+ * require it.
+ */
+#ifndef __offsetof
+# if LIBBSD_GCC_VERSION >= 0x0401
+#  define __offsetof(type, field)	__builtin_offsetof(type, field)
+# else
+#  ifndef __cplusplus
+#   define __offsetof(type, field) \
+           ((__size_t)(__uintptr_t)((const volatile void *)&((type *)0)->field))
+#  else
+#   define __offsetof(type, field) \
+	(__offsetof__ (reinterpret_cast <__size_t> \
+	               (&reinterpret_cast <const volatile char &> \
+	                (static_cast<type *> (0)->field))))
+#  endif
+# endif
+#endif
+
+#define __rangeof(type, start, end) \
+        (__offsetof(type, end) - __offsetof(type, start))
+
+/*
+ * Given the pointer x to the member m of the struct s, return
+ * a pointer to the containing structure.  When using GCC, we first
+ * assign pointer x to a local variable, to check that its type is
+ * compatible with member m.
+ */
+#ifndef __containerof
+# if LIBBSD_GCC_VERSION >= 0x0301
+#  define __containerof(x, s, m) ({ \
+	const volatile __typeof(((s *)0)->m) *__x = (x); \
+	__DEQUALIFY(s *, (const volatile char *)__x - __offsetof(s, m)); \
+})
+# else
+#  define __containerof(x, s, m) \
+          __DEQUALIFY(s *, (const volatile char *)(x) - __offsetof(s, m))
+# endif
+#endif
+
 #ifndef __RCSID
 # define __RCSID(x)
 #endif
commit 0e4e3ab2698a29a329beb5b85b9da5d425e296a6
Author: Guillem Jover <guillem at hadrons.org>
Date:   Sat Nov 1 00:20:23 2014 +0100

    Add __DECONST, __DEVOLATILE and __DEQUALIFY macros to sys/cdefs.h
    
    Import from FreeBSD.

diff --git a/include/bsd/sys/cdefs.h b/include/bsd/sys/cdefs.h
index c08d68d..c1567be 100644
--- a/include/bsd/sys/cdefs.h
+++ b/include/bsd/sys/cdefs.h
@@ -138,4 +138,16 @@
 # define __COPYRIGHT(x)
 #endif
 
+#ifndef __DECONST
+#define __DECONST(type, var)	((type)(__uintptr_t)(const void *)(var))
+#endif
+
+#ifndef __DEVOLATILE
+#define __DEVOLATILE(type, var)	((type)(__uintptr_t)(volatile void *)(var))
+#endif
+
+#ifndef __DEQUALIFY
+#define __DEQUALIFY(type, var)	((type)(__uintptr_t)(const volatile void *)(var))
+#endif
+
 #endif
commit a6fe103c1b4ff4ae8d78840ed964dc632ccd4d7c
Author: Guillem Jover <guillem at hadrons.org>
Date:   Fri Oct 31 17:29:54 2014 +0100

    Add new man page for reallocarray(3)
    
    Import man page from OpenBSD.
    
    Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=85622

diff --git a/man/Makefile.am b/man/Makefile.am
index 4e57553..1456ef7 100644
--- a/man/Makefile.am
+++ b/man/Makefile.am
@@ -42,6 +42,7 @@ dist_man_MANS = \
 	queue.3bsd \
 	radixsort.3 \
 	readpassphrase.3 \
+	reallocarray.3 \
 	reallocf.3 \
 	setmode.3 \
 	setproctitle.3 \
diff --git a/man/reallocarray.3 b/man/reallocarray.3
new file mode 100644
index 0000000..71a047e
--- /dev/null
+++ b/man/reallocarray.3
@@ -0,0 +1,102 @@
+.\"
+.\" Copyright (c) 1980, 1991, 1993
+.\"	The Regents of the University of California.  All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the American National Standards Committee X3, on Information
+.\" Processing Systems.
+.\"
+.\" 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. 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.
+.\"
+.\"	$OpenBSD: malloc.3,v 1.78 2014/05/01 18:41:59 jmc Exp $
+.\"
+.Dd $Mdocdate: May 1 2014 $
+.Dt MALLOC 3
+.Os
+.Sh NAME
+.Nm reallocarray
+.Nd memory allocation and deallocation
+.Sh LIBRARY
+.ds str-Lb-libbsd Utility functions from BSD systems (libbsd, \-lbsd)
+.Lb libbsd
+.Sh SYNOPSIS
+.In bsd/stdlib.h
+.Ft void *
+.Fn reallocarray "void *ptr" "size_t nmemb" "size_t size"
+.Sh DESCRIPTION
+.Pp
+When using
+.Fn malloc
+be careful to avoid the following idiom:
+.Bd -literal -offset indent
+if ((p = malloc(num * size)) == NULL)
+	err(1, "malloc");
+.Ed
+.Pp
+The multiplication may lead to an integer overflow, which can
+be avoided using the extension
+.Fn reallocarray ,
+as follows:
+.Bd -literal -offset indent
+if ((p = reallocarray(NULL, num, size)) == NULL)
+	err(1, "malloc");
+.Ed
+.Pp
+Alternatively
+.Fn calloc
+is a more portable solution which comes with the cost of clearing memory.
+.Pp
+If
+.Fn malloc
+must be used, be sure to test for overflow:
+.Bd -literal -offset indent
+if (size && num > SIZE_MAX / size) {
+	errno = ENOMEM;
+	err(1, "overflow");
+}
+.Ed
+.Pp
+The use of
+.Fn reallocarray
+or
+.Fn calloc
+is strongly encouraged when allocating multiple sized objects
+in order to avoid possible integer overflows.
+.Sh RETURN VALUES
+The
+.Fn reallocarray
+function returns a pointer to the allocated space if successful; otherwise,
+a null pointer is returned and
+.Va errno
+is set to
+.Er ENOMEM .
+.Sh SEE ALSO
+.Xr malloc 3 ,
+.Xr calloc 3 ,
+.Xr alloca 3
+.Sh HISTORY
+.Fn reallocarray
+appeared in
+.Ox 5.6 .
commit 02b55488c5ed1067f7b4d4139806a60919bb2e78
Author: Guillem Jover <guillem at hadrons.org>
Date:   Tue Aug 12 12:32:34 2014 +0200

    Use stdint integer types instead of BSD legacy ones

diff --git a/include/bsd/md5.h b/include/bsd/md5.h
index 3599640..56c3cd6 100644
--- a/include/bsd/md5.h
+++ b/include/bsd/md5.h
@@ -15,26 +15,28 @@
 #ifndef _MD5_H_
 #define _MD5_H_
 
+#include <stdint.h>
+
 #define	MD5_BLOCK_LENGTH		64
 #define	MD5_DIGEST_LENGTH		16
 #define	MD5_DIGEST_STRING_LENGTH	(MD5_DIGEST_LENGTH * 2 + 1)
 
 typedef struct MD5Context {
-	u_int32_t state[4];			/* state */
-	u_int64_t count;			/* number of bits, mod 2^64 */
-	u_int8_t buffer[MD5_BLOCK_LENGTH];	/* input buffer */
+	uint32_t state[4];			/* state */
+	uint64_t count;				/* number of bits, mod 2^64 */
+	uint8_t buffer[MD5_BLOCK_LENGTH];	/* input buffer */
 } MD5_CTX;
 
 #include <sys/cdefs.h>
 
 __BEGIN_DECLS
 void	 MD5Init(MD5_CTX *);
-void	 MD5Update(MD5_CTX *, const u_int8_t *, size_t)
+void	 MD5Update(MD5_CTX *, const uint8_t *, size_t)
 		__attribute__((__bounded__(__string__,2,3)));
 void	 MD5Pad(MD5_CTX *);
-void	 MD5Final(u_int8_t [MD5_DIGEST_LENGTH], MD5_CTX *)
+void	 MD5Final(uint8_t [MD5_DIGEST_LENGTH], MD5_CTX *)
 		__attribute__((__bounded__(__minbytes__,1,MD5_DIGEST_LENGTH)));
-void	 MD5Transform(u_int32_t [4], const u_int8_t [MD5_BLOCK_LENGTH])
+void	 MD5Transform(uint32_t [4], const uint8_t [MD5_BLOCK_LENGTH])
 		__attribute__((__bounded__(__minbytes__,1,4)))
 		__attribute__((__bounded__(__minbytes__,2,MD5_BLOCK_LENGTH)));
 char	*MD5End(MD5_CTX *, char *)
@@ -43,7 +45,7 @@ char	*MD5File(const char *, char *)
 		__attribute__((__bounded__(__minbytes__,2,MD5_DIGEST_STRING_LENGTH)));
 char	*MD5FileChunk(const char *, char *, off_t, off_t)
 		__attribute__((__bounded__(__minbytes__,2,MD5_DIGEST_STRING_LENGTH)));
-char	*MD5Data(const u_int8_t *, size_t, char *)
+char	*MD5Data(const uint8_t *, size_t, char *)
 		__attribute__((__bounded__(__string__,1,2)))
 		__attribute__((__bounded__(__minbytes__,3,MD5_DIGEST_STRING_LENGTH)));
 __END_DECLS
diff --git a/include/bsd/stdlib.h b/include/bsd/stdlib.h
index 0fcb454..0604cad 100644
--- a/include/bsd/stdlib.h
+++ b/include/bsd/stdlib.h
@@ -47,11 +47,11 @@
 #include <stdint.h>
 
 __BEGIN_DECLS
-u_int32_t arc4random(void);
+uint32_t arc4random(void);
 void arc4random_stir(void);
 void arc4random_addrandom(u_char *dat, int datlen);
 void arc4random_buf(void *_buf, size_t n);
-u_int32_t arc4random_uniform(u_int32_t upper_bound);
+uint32_t arc4random_uniform(uint32_t upper_bound);
 
 int dehumanize_number(const char *str, int64_t *size);
 
diff --git a/man/arc4random.3 b/man/arc4random.3
index eda74af..90264ce 100644
--- a/man/arc4random.3
+++ b/man/arc4random.3
@@ -45,12 +45,12 @@
 .Lb libbsd
 .Sh SYNOPSIS
 .In bsd/stdlib.h
-.Ft u_int32_t
+.Ft uint32_t
 .Fn arc4random "void"
 .Ft void
 .Fn arc4random_buf "void *buf" "size_t nbytes"
-.Ft u_int32_t
-.Fn arc4random_uniform "u_int32_t upper_bound"
+.Ft uint32_t
+.Fn arc4random_uniform "uint32_t upper_bound"
 .Ft void
 .Fn arc4random_stir "void"
 .Ft void
diff --git a/man/mdX.3bsd b/man/mdX.3bsd
index 8e1b64a..095a269 100644
--- a/man/mdX.3bsd
+++ b/man/mdX.3bsd
@@ -32,13 +32,13 @@
 .Ft void
 .Fn MDXInit "MDX_CTX *context"
 .Ft void
-.Fn MDXUpdate "MDX_CTX *context" "const u_int8_t *data" "size_t len"
+.Fn MDXUpdate "MDX_CTX *context" "const uint8_t *data" "size_t len"
 .Ft void
 .Fn MDXPad "MDX_CTX *context"
 .Ft void
-.Fn MDXFinal "u_int8_t digest[MDX_DIGEST_LENGTH]" "MDX_CTX *context"
+.Fn MDXFinal "uint8_t digest[MDX_DIGEST_LENGTH]" "MDX_CTX *context"
 .Ft void
-.Fn MDXTransform "u_int32_t state[4]" "u_int8_t block[MDX_BLOCK_LENGTH]"
+.Fn MDXTransform "uint32_t state[4]" "uint8_t block[MDX_BLOCK_LENGTH]"
 .Ft "char *"
 .Fn MDXEnd "MDX_CTX *context" "char *buf"
 .Ft "char *"
@@ -46,7 +46,7 @@
 .Ft "char *"
 .Fn MDXFileChunk "const char *filename" "char *buf" "off_t offset" "off_t length"
 .Ft "char *"
-.Fn MDXData "const u_int8_t *data" "size_t len" "char *buf"
+.Fn MDXData "const uint8_t *data" "size_t len" "char *buf"
 .Sh DESCRIPTION
 The MDX functions calculate a 128-bit cryptographic checksum (digest)
 for any number of input bytes.
diff --git a/src/arc4random.c b/src/arc4random.c
index 20fce09..fc8db6d 100644
--- a/src/arc4random.c
+++ b/src/arc4random.c
@@ -43,9 +43,9 @@ __FBSDID("$FreeBSD$");
 #include <pthread.h>
 
 struct arc4_stream {
-	u_int8_t i;
-	u_int8_t j;
-	u_int8_t s[256];
+	uint8_t i;
+	uint8_t j;
+	uint8_t s[256];
 };
 
 #define	RANDOMDEV	"/dev/urandom"
@@ -65,7 +65,7 @@ static int rs_initialized;
 static int rs_stired;
 static int arc4_count;
 
-static inline u_int8_t arc4_getbyte(void);
+static inline uint8_t arc4_getbyte(void);
 static void arc4_stir(void);
 
 static inline void
@@ -83,7 +83,7 @@ static inline void
 arc4_addrandom(u_char *dat, int datlen)
 {
 	int     n;
-	u_int8_t si;
+	uint8_t si;
 
 	rs.i--;
 	for (n = 0; n < 256; n++) {
@@ -103,7 +103,7 @@ arc4_stir(void)
 	struct {
 		struct timeval	tv;
 		pid_t 		pid;
-		u_int8_t 	rnd[KEYSIZE];
+		uint8_t		rnd[KEYSIZE];
 	} rdat;
 
 	fd = open(RANDOMDEV, O_RDONLY, 0);
@@ -133,10 +133,10 @@ arc4_stir(void)
 	arc4_count = 1600000;
 }
 
-static inline u_int8_t
+static inline uint8_t
 arc4_getbyte(void)
 {
-	u_int8_t si, sj;
+	uint8_t si, sj;
 
 	rs.i = (rs.i + 1);
 	si = rs.s[rs.i];
@@ -148,10 +148,10 @@ arc4_getbyte(void)
 	return (rs.s[(si + sj) & 0xff]);
 }
 
-static inline u_int32_t
+static inline uint32_t
 arc4_getword(void)
 {
-	u_int32_t val;
+	uint32_t val;
 
 	val = arc4_getbyte() << 24;
 	val |= arc4_getbyte() << 16;
@@ -199,10 +199,10 @@ arc4random_addrandom(u_char *dat, int datlen)
 	THREAD_UNLOCK();
 }
 
-u_int32_t
+uint32_t
 arc4random(void)
 {
-	u_int32_t rnd;
+	uint32_t rnd;
 
 	THREAD_LOCK();
 	arc4_check_init();
@@ -239,10 +239,10 @@ arc4random_buf(void *_buf, size_t n)
  * [2**32 % upper_bound, 2**32) which maps back to [0, upper_bound)
  * after reduction modulo upper_bound.
  */
-u_int32_t
-arc4random_uniform(u_int32_t upper_bound)
+uint32_t
+arc4random_uniform(uint32_t upper_bound)
 {
-	u_int32_t r, min;
+	uint32_t r, min;
 
 	if (upper_bound < 2)
 		return (0);
diff --git a/src/hash/helper.c b/src/hash/helper.c
index fe3f3e7..06af189 100644
--- a/src/hash/helper.c
+++ b/src/hash/helper.c
@@ -27,7 +27,7 @@ char *
 HASHEnd(HASH_CTX *ctx, char *buf)
 {
 	int i;
-	u_int8_t digest[HASH_DIGEST_LENGTH];
+	uint8_t digest[HASH_DIGEST_LENGTH];
 #ifdef HASH_DIGEST_UPPERCASE
 	static const char hex[] = "0123456789ABCDEF";
 #else
diff --git a/src/hash/md5.c b/src/hash/md5.c
index e60bbd9..7e9672e 100644
--- a/src/hash/md5.c
+++ b/src/hash/md5.c
@@ -37,7 +37,7 @@
 	(cp)[1] = (value) >> 8;						\
 	(cp)[0] = (value); } while (0)
 
-static u_int8_t PADDING[MD5_BLOCK_LENGTH] = {
+static uint8_t PADDING[MD5_BLOCK_LENGTH] = {
 	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
@@ -71,7 +71,7 @@ MD5Update(MD5_CTX *ctx, const unsigned char *input, size_t len)
 	need = MD5_BLOCK_LENGTH - have;
 
 	/* Update bitcount */
-	ctx->count += (u_int64_t)len << 3;
+	ctx->count += (uint64_t)len << 3;
 
 	if (len >= need) {
 		if (have != 0) {
@@ -102,7 +102,7 @@ MD5Update(MD5_CTX *ctx, const unsigned char *input, size_t len)
 void
 MD5Pad(MD5_CTX *ctx)
 {
-	u_int8_t count[8];
+	uint8_t count[8];
 	size_t padlen;
 
 	/* Convert count to 8 bytes in little endian order. */
@@ -152,19 +152,19 @@ MD5Final(unsigned char digest[MD5_DIGEST_LENGTH], MD5_CTX *ctx)
  * the data and converts bytes into longwords for this routine.
  */
 void
-MD5Transform(u_int32_t state[4], const u_int8_t block[MD5_BLOCK_LENGTH])
+MD5Transform(uint32_t state[4], const uint8_t block[MD5_BLOCK_LENGTH])
 {
-	u_int32_t a, b, c, d, in[MD5_BLOCK_LENGTH / 4];
+	uint32_t a, b, c, d, in[MD5_BLOCK_LENGTH / 4];
 
 #if BYTE_ORDER == LITTLE_ENDIAN
 	memcpy(in, block, sizeof(in));
 #else
 	for (a = 0; a < MD5_BLOCK_LENGTH / 4; a++) {
-		in[a] = (u_int32_t)(
-		    (u_int32_t)(block[a * 4 + 0]) |
-		    (u_int32_t)(block[a * 4 + 1]) <<  8 |
-		    (u_int32_t)(block[a * 4 + 2]) << 16 |
-		    (u_int32_t)(block[a * 4 + 3]) << 24);
+		in[a] = (uint32_t)(
+		    (uint32_t)(block[a * 4 + 0]) |
+		    (uint32_t)(block[a * 4 + 1]) <<  8 |
+		    (uint32_t)(block[a * 4 + 2]) << 16 |
+		    (uint32_t)(block[a * 4 + 3]) << 24);
 	}
 #endif
 
commit 6378351169696f9d446de93a3efd75b4b061fecc
Author: Callum Davies <calrogman at gmail.com>
Date:   Sun Aug 10 12:34:44 2014 +0100

    Fix arc4random() and arc4random_stir() prototypes
    
    These two functions accept no arguments.  The prototypes should reflect
    this.  This change lets the compiler warn about certain (admittedly
    silly) mistakes.
    
    Signed-off-by: Guillem Jover <guillem at hadrons.org>

diff --git a/include/bsd/stdlib.h b/include/bsd/stdlib.h
index 22a6dc8..0fcb454 100644
--- a/include/bsd/stdlib.h
+++ b/include/bsd/stdlib.h
@@ -47,8 +47,8 @@
 #include <stdint.h>
 
 __BEGIN_DECLS
-u_int32_t arc4random();
-void arc4random_stir();
+u_int32_t arc4random(void);
+void arc4random_stir(void);
 void arc4random_addrandom(u_char *dat, int datlen);
 void arc4random_buf(void *_buf, size_t n);
 u_int32_t arc4random_uniform(u_int32_t upper_bound);


More information about the libbsd mailing list