 .gitignore                             |    4 +++
 doc/guide.rst                          |    6 ++--
 doc/posix.rst                          |   16 +++++-----
 libfiu/Makefile                        |    2 +-
 libfiu/fiu.c                           |    4 +--
 libfiu/libfiu.3                        |    9 ++++++
 preload/posix/Makefile                 |   38 ++++++++++++++++++++++-----
 preload/posix/build-env.h.in           |   12 ++++++++
 preload/posix/codegen.c                |    3 +-
 preload/posix/codegen.h                |   16 ++++++++---
 preload/posix/modules/libc.mm.custom.c |    8 +++++-
 preload/posix/modules/posix.custom.c   |   11 ++++++-
 preload/posix/modules/posix.io.mod     |   45 +++++++++++++++++--------------
 preload/posix/modules/posix.mm.mod     |    8 +++++
 preload/posix/modules/posix.proc.mod   |    3 ++
 preload/run/Makefile                   |   17 ++++++++---
 16 files changed, 146 insertions(+), 56 deletions(-)

diff --git a/.gitignore b/.gitignore
index 7740f5e..24e7bb9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,6 +10,9 @@ libfiu/build-flags
 preload/posix/*.o
 preload/posix/*.so
 preload/posix/build-flags
+preload/posix/build-libcsoname
+preload/posix/build-needlibdl
+preload/posix/build-env.h
 preload/posix/function_list
 preload/posix/modules/*.o
 preload/posix/modules/*.mod.c
@@ -18,4 +21,5 @@ preload/run/*.o
 preload/run/*.so
 preload/run/fiu-run
 preload/run/build-flags
+preload/run/build-needlibdl
 
diff --git a/doc/guide.rst b/doc/guide.rst
index e4ef6fc..c401b46 100644
--- a/doc/guide.rst
+++ b/doc/guide.rst
@@ -31,8 +31,8 @@ Code overview
 Let's take a look to a small (fictitious) code sample to see what's the
 general idea behind libfiu.
 
-Let's say you have this code that check if there's enough free space to fit a
-given file::
+Let's say you have this code that checks if there's enough free space to store
+a given file::
 
         size_t free_space() {
                 [code to find out how much free space there is]
@@ -130,7 +130,7 @@ It is recommended that you use meaningful names for your points of failure, to
 be able to easily identify their purpose. You can also name them
 hierarchically (for example, using names like *"io/write"*, *"io/read"*, and
 so on), to be able to enable entire groups of points of failure (like
-*"io/\*"*,). To this end, any separator will do, the *'/'* is not special at
+*"io/\*"*). To this end, any separator will do, the *'/'* is not special at
 all.
 
 
diff --git a/doc/posix.rst b/doc/posix.rst
index eecadbf..d10ff91 100644
--- a/doc/posix.rst
+++ b/doc/posix.rst
@@ -40,15 +40,15 @@ Run it several times and you can see that sometimes it works, but sometimes it
 doesn't, reporting an error reading, which means a *read()* failed as
 expected.
 
-When fortune is run, every time fortune calls *read()* it has a 1% chance to
-fail, which selects an errno at random from the list of the ones that read()
-is allowed to return. If you want to select an specific errno, you can do it
-by passing its numerical value using the *-i* parameter.
+When fortune is run, every *read()* has a 1% chance to fail, selecting an
+*errno* at random from the list of the ones that read() is allowed to return.
+If you want to select an specific *errno*, you can do it by passing its
+numerical value using the *-i* parameter.
 
 The name of the failure points are fixed, and there is at least one for each
-function that libfiu supports injecting failures to. Not all POSIX is
-included, but most of the important pieces are, and it is easily extended. See
-below for details.
+function that libfiu supports injecting failures to. Not all POSIX functions
+are included, but most of the important pieces are, and it can be easily
+extended. See below for details.
 
 To see the list of supported functions and names, see the (automatically
 generated) *preload/posix/function_list* file that comes in the libfiu
@@ -64,7 +64,7 @@ instead of from the beginning, as *fiu-run* does.
 To that end, you can combine *fiu-run* with the second tool, called
 *fiu-ctrl*.
 
-Let's suppose you want to see what the "top" program does when it can't open
+Let's suppose we want to see what the "top" program does when it can't open
 files. First, we run it with *fiu-run*::
 
   $ fiu-run -x top
diff --git a/libfiu/Makefile b/libfiu/Makefile
index 98a0c61..ed98034 100644
--- a/libfiu/Makefile
+++ b/libfiu/Makefile
@@ -30,7 +30,7 @@ else
 	NICE_CC = $(CC)
 endif
 
-LIB_VER=0.13
+LIB_VER=0.14
 LIB_SO_VER=0
 
 
diff --git a/libfiu/fiu.c b/libfiu/fiu.c
index 2a01c91..8a849dd 100644
--- a/libfiu/fiu.c
+++ b/libfiu/fiu.c
@@ -365,11 +365,9 @@ static int insert_new_fail(const char *name, int failnum, void *failinfo,
 		external_cb_t *external_cb)
 {
 	struct pf_info *pf;
-	int rv;
+	int rv = -1;
 	size_t prev_len;
 
-	rv = -1;
-
 	rec_count++;
 
 	/* See if it's already there and update the data if so, or if we have
diff --git a/libfiu/libfiu.3 b/libfiu/libfiu.3
index ab46ae1..b7e3616 100644
--- a/libfiu/libfiu.3
+++ b/libfiu/libfiu.3
@@ -168,6 +168,15 @@ functions.
 Enables remote control over named pipes with the given basename. See the
 remote control documentation that comes with the library for more detail.
 
+.SS THREAD SAFETY
+
+The library is thread-safe. The list of enabled failure points is shared among
+all threads.
+
+Care should be taken in the user-provided functions given to
+.BR fiu_enable_external() ,
+as they can be run in parallel.
+
 .SH SEE ALSO
 .BR fiu-run (1),
 .BR fiu-ctrl (1).
diff --git a/preload/posix/Makefile b/preload/posix/Makefile
index 40ca573..b2afa58 100644
--- a/preload/posix/Makefile
+++ b/preload/posix/Makefile
@@ -1,7 +1,7 @@
 
 CFLAGS += -std=c99 -Wall -O3
 ALL_CFLAGS = -D_XOPEN_SOURCE=600 -fPIC -DFIU_ENABLE=1 \
-		-I. -I../../libfiu/ -L../../libfiu/ $(CFLAGS)
+		-I. -I../../libfiu/ $(CFLAGS)
 
 ifdef DEBUG
 ALL_CFLAGS += -g
@@ -60,14 +60,37 @@ $(OBJS): build-flags
 .c.o:
 	$(NICE_CC) $(ALL_CFLAGS) -c $< -o $@
 
-# some platforms do not have libdl, we only use it if available
-NEED_LIBDL := $(shell ld -o dlcheck.so -shared -ldl 2>/dev/null && echo -ldl; \
-	rm -f dlcheck.so)
 
-fiu_posix_preload.so: build-flags $(OBJS)
-	$(NICE_CC) $(ALL_CFLAGS) -shared -fPIC $(OBJS) -lfiu $(NEED_LIBDL) \
+# some platforms do not have libdl, we only use it if available
+build-needlibdl:
+	@$(LD) -ldl -o dlcheck.so 2>/dev/null \
+		&& echo -ldl > $@ || echo > $@
+	@rm -f dlcheck.so
+
+# libc's soname depends on the platform (most use libc.so.6, but for example
+# ia64 and alpha use libc.so.6.1), so find which one to use at build-time.
+# Please note that the argument to ldd *must* start with "./", otherwise some
+# "ldd"s won't work (for example, the one in FreeBSD 8.1).
+build-libcsoname:
+	@$(CC) -x c /dev/null -lc -shared -o build-libccheck.so
+	@ldd ./build-libccheck.so | grep libc.so | awk '{ print $$1 }' > $@
+	@rm build-libccheck.so
+	@test "`cat $@`" != "" || \
+		(echo "Error finding soname, please report"; rm $@; exit 1)
+
+build-env.h: build-env.h.in build-libcsoname
+	@echo "  GEN $@"
+	$(Q) sed "s+@@LIBC_SONAME@@+`cat build-libcsoname`+g" build-env.h.in \
+		> build-env.h
+
+
+fiu_posix_preload.so: build-flags build-env.h build-needlibdl $(OBJS)
+	$(NICE_CC) $(ALL_CFLAGS) -shared -fPIC $(OBJS) \
+		-L../../libfiu/ \
+		-lfiu `cat build-needlibdl` \
 		-o fiu_posix_preload.so
 
+
 # this should only be needed when building the function list and not the
 # preload library
 %.mod.fl: %.mod
@@ -86,7 +109,8 @@ uninstall:
 	$(RM) $(PREFIX)/lib/fiu_posix_preload.so
 
 clean:
-	rm -f $(OBJS) $(GEN_OBJS:.o=.c) $(GEN_FL) build-flags
+	rm -f $(OBJS) $(GEN_OBJS:.o=.c) $(GEN_FL)
+	rm -f build-flags build-env.h build-libcsoname build-needlibdl
 	rm -f function_list fiu_posix_preload.so
 	rm -f *.bb *.bbg *.da *.gcov *.gcda *.gcno gmon.out
 
diff --git a/preload/posix/build-env.h.in b/preload/posix/build-env.h.in
new file mode 100644
index 0000000..63c06f6
--- /dev/null
+++ b/preload/posix/build-env.h.in
@@ -0,0 +1,12 @@
+
+#ifndef _BUILD_ENV_H
+#define _BUILD_ENV_H
+
+/*
+ * Constants taken from the build environment
+ */
+
+/* libc's soname, used for dlopen()ing the C library */
+#define LIBC_SONAME "@@LIBC_SONAME@@"
+
+#endif
diff --git a/preload/posix/codegen.c b/preload/posix/codegen.c
index 71644c5..177fdcd 100644
--- a/preload/posix/codegen.c
+++ b/preload/posix/codegen.c
@@ -4,6 +4,7 @@
 #include <sys/time.h>
 #include <stdlib.h>
 #include "codegen.h"
+#include "build-env.h"
 
 /* Dynamically load libc */
 void *_fiu_libc;
@@ -30,7 +31,7 @@ void constructor_attr(200) _fiu_init(void)
 	if (initialized)
 		goto exit;
 
-	_fiu_libc = dlopen("libc.so.6", RTLD_NOW);
+	_fiu_libc = dlopen(LIBC_SONAME, RTLD_NOW);
 	if (_fiu_libc == NULL) {
 		fprintf(stderr, "Error loading libc: %s\n", dlerror());
 		exit(1);
diff --git a/preload/posix/codegen.h b/preload/posix/codegen.h
index 6a3444e..0999159 100644
--- a/preload/posix/codegen.h
+++ b/preload/posix/codegen.h
@@ -13,11 +13,17 @@ void _fiu_init(void);
 /* Recursion counter, per-thread */
 extern int __thread _fiu_called;
 
-/* GCC >= 4.3 supports constructor priorities only on some platforms. Since we
- * don't rely on them, but use them for clarity purposes, use a macro so
- * libfiu builds on systems where they're not supported. */
-#if (defined __linux__) && (defined __GNUC__) \
-	&& __GNUC__ >= 4 && __GNUC_MINOR__ >= 3
+/* Some compilers support constructor priorities. Since we don't rely on them,
+ * but use them for clarity purposes, use a macro so libfiu builds on systems
+ * where they're not supported.
+ * Compilers that are known to support constructor priorities:
+ *  - GCC >= 4.3 on Linux
+ *  - clang as of 2010-03-14
+ */
+#if \
+	( (defined __GNUC__) \
+		&& __GNUC__ >= 4 && __GNUC_MINOR__ >= 3 ) \
+	|| (defined __clang__)
   #define constructor_attr(prio) __attribute__((constructor(prio)))
 #else
   #define NO_CONSTRUCTOR_PRIORITIES 1
diff --git a/preload/posix/modules/libc.mm.custom.c b/preload/posix/modules/libc.mm.custom.c
index 9878ea3..4ed23e7 100644
--- a/preload/posix/modules/libc.mm.custom.c
+++ b/preload/posix/modules/libc.mm.custom.c
@@ -8,7 +8,13 @@
  * We use __malloc_hook, the glibc-specific interface, so this is glibc-only.
  */
 
-#include <features.h>
+/* We need to include features.h, which in turns defines __GLIBC__. However,
+ * features.h is glibc-specific and does not exist on other platforms, so we
+ * can't include it directly or the file won't build.
+ * Instead, we have to resort to this ugly trick of including limits.h, which
+ * is standard and we know glibc's implementation includes features.h.
+ */
+#include <limits.h>
 
 #ifndef __GLIBC__
   #warning "Not using glibc, so no malloc() wrappers will be available"
diff --git a/preload/posix/modules/posix.custom.c b/preload/posix/modules/posix.custom.c
index 5caff6f..1c709cd 100644
--- a/preload/posix/modules/posix.custom.c
+++ b/preload/posix/modules/posix.custom.c
@@ -37,12 +37,19 @@ int open(const char *pathname, int flags, ...)
 
 	/* Differences from the generated code begin here */
 
-	int mode;
+	mode_t mode;
 	va_list l;
 
 	if (flags & O_CREAT) {
 		va_start(l, flags);
-		mode = va_arg(l, mode_t);
+
+		/* va_arg() can only take fully promoted types, and mode_t
+		 * sometimes is smaller than an int, so we should always pass
+		 * int to it, and not mode_t. Not doing so would may result in
+		 * a compile-time warning and run-time error. We asume that it
+		 * is never bigger than an int, which holds in practise. */
+		mode = va_arg(l, int);
+
 		va_end(l);
 	} else {
 		/* set it to 0, it's ignored anyway */
diff --git a/preload/posix/modules/posix.io.mod b/preload/posix/modules/posix.io.mod
index dd9bb2d..4d31077 100644
--- a/preload/posix/modules/posix.io.mod
+++ b/preload/posix/modules/posix.io.mod
@@ -111,26 +111,31 @@ int rename(const char *oldpath, const char *newpath);
 		ENOENT ENOMEM ENOSPC ENOTDIR ENOTEMPTY EPERM EROFS EXDEV
 
 
-fiu name base: posix/io/stat/
-
-include: <sys/types.h>
-include: <sys/stat.h>
-include: <unistd.h>
-
-int stat(const char *path, struct stat *buf);
-	on error: -1
-	valid errnos: EACCES EBADF EFAULT ELOOP ENAMETOOLONG ENOENT ENOMEM \
-		ENOTDIR EOVERFLOW
-
-int fstat(int fd, struct stat *buf);
-	on error: -1
-	valid errnos: EACCES EBADF EFAULT ELOOP ENAMETOOLONG ENOENT ENOMEM \
-		ENOTDIR EOVERFLOW
-
-int lstat(const char *path, struct stat *buf);
-	on error: -1
-	valid errnos: EACCES EBADF EFAULT ELOOP ENAMETOOLONG ENOENT ENOMEM \
-		ENOTDIR EOVERFLOW
+# NOTE: These are disabled because the stat family function is usually defined
+# within one of the standard headers, which (besides being ugly) makes
+# overriding them this way much harder. The definitions below are commented
+# out for reference and testing purposes.
+#
+#fiu name base: posix/io/stat/
+#
+#include: <sys/types.h>
+#include: <sys/stat.h>
+#include: <unistd.h>
+#
+#int stat(const char *path, struct stat *buf);
+#	on error: -1
+#	valid errnos: EACCES EBADF EFAULT ELOOP ENAMETOOLONG ENOENT ENOMEM \
+#		ENOTDIR EOVERFLOW
+#
+#int fstat(int fd, struct stat *buf);
+#	on error: -1
+#	valid errnos: EACCES EBADF EFAULT ELOOP ENAMETOOLONG ENOENT ENOMEM \
+#		ENOTDIR EOVERFLOW
+#
+#int lstat(const char *path, struct stat *buf);
+#	on error: -1
+#	valid errnos: EACCES EBADF EFAULT ELOOP ENAMETOOLONG ENOENT ENOMEM \
+#		ENOTDIR EOVERFLOW
 
 
 fiu name base: posix/io/net/
diff --git a/preload/posix/modules/posix.mm.mod b/preload/posix/modules/posix.mm.mod
index 443f816..6d96a93 100644
--- a/preload/posix/modules/posix.mm.mod
+++ b/preload/posix/modules/posix.mm.mod
@@ -24,9 +24,17 @@ int msync(void *addr, size_t length, int flags);
 	on error: -1
 	valid errnos: EBUSY EINVAL ENOMEM
 
+# glibc's mprotect() does not use const in the first argument, as the standard
+# says it should
+v: #ifdef __GLIBC__
 int mprotect(void *addr, size_t len, int prot);
 	on error: -1
 	valid errnos: EACCES EINVAL ENOMEM
+v: #else
+int mprotect(const void *addr, size_t len, int prot);
+	on error: -1
+	valid errnos: EACCES EINVAL ENOMEM
+v: #endif
 
 int madvise(void *addr, size_t length, int advice);
 	on error: -1
diff --git a/preload/posix/modules/posix.proc.mod b/preload/posix/modules/posix.proc.mod
index 1054513..2db8802 100644
--- a/preload/posix/modules/posix.proc.mod
+++ b/preload/posix/modules/posix.proc.mod
@@ -19,9 +19,12 @@ pid_t waitpid(pid_t pid, int *status, int options);
 	on error: -1
 	valid errnos: ECHILD EINTR EINVAL
 
+# FreeBSD does not have waitid()
+v: #ifndef __FreeBSD__
 int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);
 	on error: -1
 	valid errnos: ECHILD EINTR EINVAL
+v: #endif
 
 int kill(pid_t pid, int sig);
 	on error: -1
diff --git a/preload/run/Makefile b/preload/run/Makefile
index bd4fca3..c0d864c 100644
--- a/preload/run/Makefile
+++ b/preload/run/Makefile
@@ -1,7 +1,7 @@
 
 CFLAGS += -std=c99 -Wall -O3
 ALL_CFLAGS = -D_XOPEN_SOURCE=600 -fPIC -DFIU_ENABLE=1 \
-		-I. -I../../libfiu/ -L../../libfiu/ $(CFLAGS)
+		-I. -I../../libfiu/ $(CFLAGS)
 
 ifdef DEBUG
 ALL_CFLAGS += -g
@@ -49,14 +49,21 @@ $(OBJS): build-flags
 .c.o:
 	$(NICE_CC) $(ALL_CFLAGS) -c $< -o $@
 
+
 # some platforms do not have libdl, we only use it if available
-NEED_LIBDL := $(shell ld -o dlcheck.so -shared -ldl 2>/dev/null && echo -ldl; \
-	rm -f dlcheck.so)
+build-needlibdl:
+	@$(LD) -ldl -o dlcheck.so 2>/dev/null \
+		&& echo -ldl > $@ || echo > $@
+	@rm -f dlcheck.so
+
 
-fiu_run_preload.so: build-flags $(OBJS)
-	$(NICE_CC) $(ALL_CFLAGS) -shared -fPIC $(OBJS) -lfiu $(NEED_LIBDL) \
+fiu_run_preload.so: build-flags build-needlibdl $(OBJS)
+	$(NICE_CC) $(ALL_CFLAGS) -shared -fPIC $(OBJS) \
+		-L../../libfiu/ \
+		-lfiu `cat build-needlibdl` \
 		-o fiu_run_preload.so
 
+
 fiu-run: build-flags fiu-run.in
 	cat fiu-run.in | sed "s+@@PLIBPATH@@+$(PLIBPATH)+g" > fiu-run
 	chmod +x fiu-run
