git » libfiu » commit fadd14d

Initial commit

author Alberto Bertogli
2009-03-15 04:39:57 UTC
committer Alberto Bertogli
2009-03-20 22:45:32 UTC

Initial commit

Signed-off-by: Alberto Bertogli <albertito@blitiri.com.ar>

.gitignore +7 -0
LICENSE +30 -0
Makefile +30 -0
README +44 -0
bindings/python2/LICENSE +30 -0
bindings/python2/fiu.py +75 -0
bindings/python2/fiu_ll.c +191 -0
bindings/python2/setup.py +17 -0
doc/guide.rst +171 -0
libfiu/Makefile +77 -0
libfiu/fiu-control.h +59 -0
libfiu/fiu-local.h +37 -0
libfiu/fiu.c +387 -0
libfiu/fiu.h +71 -0
libfiu/libfiu.3 +170 -0
libfiu/libfiu.skel.pc +12 -0

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..e0c7c3d
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,7 @@
+bindings/python2/build
+bindings/python2/*.pyc
+bindings/python2/*.pyo
+libfiu/*.o
+libfiu/libfiu.a
+libfiu/libfiu.pc
+libfiu/libfiu.so
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..edb80f0
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+
+I don't like licenses, because I don't like having to worry about all this
+legal stuff just for a simple piece of software I don't really mind anyone
+using. But I also believe that it's important that people share and give back;
+so I'm placing this work under the following license.
+
+
+BOLA - Buena Onda License Agreement (v1.0)
+------------------------------------------
+
+This work is provided 'as-is', without any express or implied warranty. In no
+event will the authors be held liable for any damages arising from the use of
+this work.
+
+To all effects and purposes, this work is to be considered Public Domain.
+
+
+However, if you want to be "buena onda", you should:
+
+1. Not take credit for it, and give proper recognition to the authors.
+2. Share your modifications, so everybody benefits from them.
+4. Do something nice for the authors.
+5. Help someone who needs it: sign up for some volunteer work or help your
+   neighbour paint the house.
+6. Don't waste. Anything, but specially energy that comes from natural
+   non-renewable resources. Extra points if you discover or invent something
+   to replace them.
+7. Be tolerant. Everything that's good in nature comes from cooperation.
+
+
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..a05295c
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,30 @@
+
+all: default
+
+default: libfiu utils
+
+libfiu:
+	$(MAKE) -C libfiu
+
+install:
+	$(MAKE) -C libfiu install
+
+
+python2:
+	cd bindings/python2 && python setup.py build
+
+python2_install:
+	cd bindings/python2 && python setup.py install
+
+python2_clean:
+	cd bindings/python2 && rm -rf build/
+
+
+clean: python2_clean
+	$(MAKE) -C libfiu clean
+
+
+.PHONY: default all clean libfiu utils \
+	python2 python2_install python2_clean
+
+
diff --git a/README b/README
new file mode 100644
index 0000000..8ba4ef7
--- /dev/null
+++ b/README
@@ -0,0 +1,44 @@
+
+libfiu - Fault injection in userspace
+-------------------------------------
+
+libfiu is a C library for fault injection. It provides functions to mark
+"points of failure" inside your code (the "core API"), and functions to
+enable/disable the failure of those points (the "control API"). It's in the
+public domain, see the LICENSE file for more information.
+
+The core API is used inside the code wanting to perform failure injection on.
+The control API is used inside the testing code, in order to control the
+injection of failures.
+
+Python bindings are available in the "bindings" directory.
+
+
+Documentation
+-------------
+
+You can find the user guide in the "doc" directory, and a manpage in the
+"libfiu" directory. The manpage will be installed along the library.
+
+Python bindings have embedded documentation, although it's not as complete.
+
+
+Building and installing
+-----------------------
+
+Running "make" (or "gmake") should be enough for building, and "make install"
+for installing. By default it installs into /usr/local, but you can provide an
+alternative prefix by running "make PREFIX=/my/prefix install".
+
+To build the Python bindings, use "make python2"; to install them you can run
+"make python2_install".
+
+
+Where to report bugs
+--------------------
+
+If you want to report bugs, or have any questions or comments, just let me
+know at albertito@blitiri.com.ar. For more information about the library, you
+can go to http://blitiri.com.ar/p/libfiu.
+
+
diff --git a/bindings/python2/LICENSE b/bindings/python2/LICENSE
new file mode 100644
index 0000000..edb80f0
--- /dev/null
+++ b/bindings/python2/LICENSE
@@ -0,0 +1,30 @@
+
+I don't like licenses, because I don't like having to worry about all this
+legal stuff just for a simple piece of software I don't really mind anyone
+using. But I also believe that it's important that people share and give back;
+so I'm placing this work under the following license.
+
+
+BOLA - Buena Onda License Agreement (v1.0)
+------------------------------------------
+
+This work is provided 'as-is', without any express or implied warranty. In no
+event will the authors be held liable for any damages arising from the use of
+this work.
+
+To all effects and purposes, this work is to be considered Public Domain.
+
+
+However, if you want to be "buena onda", you should:
+
+1. Not take credit for it, and give proper recognition to the authors.
+2. Share your modifications, so everybody benefits from them.
+4. Do something nice for the authors.
+5. Help someone who needs it: sign up for some volunteer work or help your
+   neighbour paint the house.
+6. Don't waste. Anything, but specially energy that comes from natural
+   non-renewable resources. Extra points if you discover or invent something
+   to replace them.
+7. Be tolerant. Everything that's good in nature comes from cooperation.
+
+
diff --git a/bindings/python2/fiu.py b/bindings/python2/fiu.py
new file mode 100644
index 0000000..f4e6ece
--- /dev/null
+++ b/bindings/python2/fiu.py
@@ -0,0 +1,75 @@
+
+"""
+libfiu python wrapper
+
+This module is a wrapper for the libfiu, the fault injection C library.
+
+It provides an almost one-to-one mapping of the libfiu functions, although its
+primary use is to be able to test C code from within Python.
+
+For fault injection in Python, a native library would be more suitable.
+
+See libfiu's manpage for more detailed documentation.
+"""
+
+import fiu_ll as _ll
+
+
+def fail(name):
+	"Returns the failure status of the given point of failure."
+	return _ll.fail(name)
+
+def failinfo(name):
+	"""Returns the information associated with the last failure. Use with
+	care, can be fatal if the point of failure was not enabled via
+	Python."""
+	return _ll.failinfo()
+
+
+# To be sure failinfo doesn't dissapear from under our feet, we keep a
+# name -> failinfo table. See fiu_ll's comments for more details.
+_fi_table = {}
+
+def enable(name, failnum = 1, failinfo = None, flags = 0):
+	"Enables the given point of failure."
+	_fi_table[name] = failnum
+	r = _ll.enable(name, failnum, failinfo, flags)
+	if r != 0:
+		del _fi_table[name]
+		raise RuntimeError, r
+
+def enable_random(name, probability, failnum = 1, failinfo = None, flags = 0):
+	"Enables the given point of failure, with the given probability."
+	_fi_table[name] = failnum
+	r = _ll.enable_random(name, failnum, failinfo, flags, probability)
+	if r != 0:
+		del _fi_table[name]
+		raise RuntimeError, r
+
+def enable_external(name, cb, failnum = 1, flags = 0):
+	"""Enables the given point of failure, leaving the decision whether to
+	fail or not to the given external function, which should return 0 if
+	it is not to fail, or 1 otherwise.
+
+	The cb parameter is a Python function that takes three parameters,
+	name, failnum and flags, with the same values that we receive.
+
+	For technical limitations, enable_external() cannot take
+	failinfo."""
+	# in this case, use the table to prevent the function from
+	# dissapearing
+	_fi_table[name] = cb
+	r = _ll.enable_external(name, failnum, flags, cb)
+	if r != 0:
+		raise RuntimeError, r
+
+def disable(name):
+	"""Disables the given point of failure, undoing the actions of the
+	enable*() functions."""
+	if name in _fi_table:
+		del _fi_table[name]
+	r = _ll.disable(name)
+	if r != 0:
+		raise RuntimeError, r
+
+
diff --git a/bindings/python2/fiu_ll.c b/bindings/python2/fiu_ll.c
new file mode 100644
index 0000000..8afb439
--- /dev/null
+++ b/bindings/python2/fiu_ll.c
@@ -0,0 +1,191 @@
+
+/*
+ * Python bindings for libfiu
+ * Alberto Bertogli (albertito@blitiri.com.ar)
+ *
+ * This is the low-level module, used by the python one to construct
+ * friendlier objects.
+ */
+
+#include <Python.h>
+
+/* Unconditionally enable fiu, otherwise we get fake headers */
+#define FIU_ENABLE 1
+
+#include <fiu.h>
+#include <fiu-control.h>
+
+
+static PyObject *fail(PyObject *self, PyObject *args)
+{
+	char *name;
+	PyObject *rv, *err;
+
+	if (!PyArg_ParseTuple(args, "s:fail", &name))
+		return NULL;
+
+	rv = PyLong_FromLong(fiu_fail(name));
+	err = PyErr_Occurred();
+
+	if (rv == NULL || err != NULL) {
+		Py_XDECREF(rv);
+		return NULL;
+	}
+
+	return rv;
+}
+
+static PyObject *failinfo(PyObject *self, PyObject *args)
+{
+	if (!PyArg_ParseTuple(args, ":failinfo"))
+		return NULL;
+
+	/* We assume failinfo is a python object; but the caller must be
+	 * careful because if it's not, it can get into trouble.
+	 * Note that we DO NOT TOUCH THE RC OF THE OBJECT. It's entirely up to
+	 * the caller to make sure it's still alive. */
+	return (PyObject *) fiu_failinfo();
+}
+
+static PyObject *enable(PyObject *self, PyObject *args)
+{
+	char *name;
+	int failnum;
+	PyObject *failinfo;
+	unsigned int flags;
+
+	if (!PyArg_ParseTuple(args, "siOI:enable", &name, &failnum, &failinfo,
+				&flags))
+		return NULL;
+
+	/* See failinfo()'s comment regarding failinfo's RC */
+	return PyLong_FromLong(fiu_enable(name, failnum, failinfo, flags));
+}
+
+static PyObject *enable_random(PyObject *self, PyObject *args)
+{
+	char *name;
+	int failnum;
+	PyObject *failinfo;
+	unsigned int flags;
+	float probability;
+
+	if (!PyArg_ParseTuple(args, "siOIf:enable_random", &name, &failnum,
+				&failinfo, &flags, &probability))
+		return NULL;
+
+	/* See failinfo()'s comment regarding failinfo's RC */
+	return PyLong_FromLong(fiu_enable_random(name, failnum, failinfo,
+				flags, probability));
+}
+
+
+static int external_callback(const char *name, int *failnum, void **failinfo,
+		unsigned int *flags)
+{
+	int rv;
+	PyObject *cbrv;
+	PyObject *args;
+	PyGILState_STATE gil_state;
+
+	/* We need to protect ourselves from the following case:
+	 *  - fiu.enable_callback('x', cb)  (where cb is obviously a Python
+	 *    function)
+	 *  - Later on, call a function p1() inside a python C module, that
+	 *    runs a C function c1() inside
+	 *    Py_BEGIN_ALLOW_THREADS/Py_END_ALLOW_THREADS
+	 *  - c1() calls fiu_fail("x")
+	 *  - fiu_fail("x") calls external_callback(), and it should run cb()
+	 *  - BUT! It can't run cb(), because it's inside
+	 *    Py_BEGIN_ALLOW_THREADS/Py_END_ALLOW_THREADS so it's not safe to
+	 *    execute any Python code!
+	 *
+	 * The solution is to ensure we're safe to run Python code using
+	 * PyGILState_Ensure()/PyGILState_Release().
+	 */
+
+	gil_state = PyGILState_Ensure();
+	args = Py_BuildValue("(siI)", name, *failnum, *flags);
+	if (args == NULL) {
+		PyGILState_Release(gil_state);
+		return 0;
+	}
+
+	cbrv = PyEval_CallObject(*failinfo, args);
+	Py_DECREF(args);
+
+	if (cbrv == NULL) {
+		PyGILState_Release(gil_state);
+		return 0;
+	}
+
+	/* If PyInt_AsLong() causes an error, it will be handled by the
+	 * PyErr_Occurred() check in fail(), so we don't need to worry about
+	 * it now. */
+	rv = PyInt_AsLong(cbrv);
+	Py_DECREF(cbrv);
+
+	PyGILState_Release(gil_state);
+
+	return rv;
+}
+
+static PyObject *enable_external(PyObject *self, PyObject *args)
+{
+	char *name;
+	int failnum;
+	unsigned int flags;
+	PyObject *py_external_cb;
+
+	if (!PyArg_ParseTuple(args, "siIO:enable_random", &name, &failnum,
+				&flags, &py_external_cb))
+		return NULL;
+
+	if (!PyCallable_Check(py_external_cb)) {
+		PyErr_SetString(PyExc_TypeError, "parameter must be callable");
+		return NULL;
+	}
+
+	/* We use failinfo to store Python's callback function. It'd be nice
+	 * if we could keep both, but it's not easy without keeping state
+	 * inside the C module.
+	 *
+	 * Similar to the way failinfo is handled, we DO NOT TOUCH THE RC OF
+	 * THE EXTERNAL CALLBACK, assuming the caller will take care of making
+	 * sure it doesn't dissapear from beneath us. */
+	return PyLong_FromLong(fiu_enable_external(name, failnum,
+				py_external_cb, flags, external_callback));
+}
+
+static PyObject *disable(PyObject *self, PyObject *args)
+{
+	char *name;
+
+	if (!PyArg_ParseTuple(args, "s:fail", &name))
+		return NULL;
+
+	return PyLong_FromLong(fiu_disable(name));
+}
+
+
+static PyMethodDef fiu_functions[] = {
+	{ "fail", (PyCFunction) fail, METH_VARARGS, NULL },
+	{ "failinfo", (PyCFunction) failinfo, METH_VARARGS, NULL },
+	{ "enable", (PyCFunction) enable, METH_VARARGS, NULL },
+	{ "enable_random", (PyCFunction) enable_random, METH_VARARGS, NULL },
+	{ "enable_external", (PyCFunction) enable_external, METH_VARARGS, NULL },
+	{ "disable", (PyCFunction) disable, METH_VARARGS, NULL },
+	{ NULL }
+};
+
+PyMODINIT_FUNC initfiu_ll(void)
+{
+	PyObject *m;
+
+	m = Py_InitModule("fiu_ll", fiu_functions);
+
+	PyModule_AddIntConstant(m, "FIU_ONETIME", FIU_ONETIME);
+
+	fiu_init(0);
+}
+
diff --git a/bindings/python2/setup.py b/bindings/python2/setup.py
new file mode 100644
index 0000000..dbdc256
--- /dev/null
+++ b/bindings/python2/setup.py
@@ -0,0 +1,17 @@
+
+from distutils.core import setup, Extension
+
+fiu_ll = Extension("fiu_ll",
+		libraries = ['fiu'],
+		sources = ['fiu_ll.c'])
+
+setup(
+	name = 'fiu',
+	description = "libfiu bindings",
+	author = "Alberto Bertogli",
+	author_email = "albertito@blitiri.com.ar",
+	url = "http://blitiri.com.ar/p/libfiu",
+	py_modules = ['fiu'],
+	ext_modules = [fiu_ll]
+)
+
diff --git a/doc/guide.rst b/doc/guide.rst
new file mode 100644
index 0000000..eb2b736
--- /dev/null
+++ b/doc/guide.rst
@@ -0,0 +1,171 @@
+
+libfiu - Fault injection in userspace
+=====================================
+
+Introduction
+------------
+
+You, as a programmer, know many things can fail, and your software is often
+expected to be able to handle those failures. But how do you test your failure
+handling code, when it's not easy to make a failure appear in the first place?
+One way to do it is to perform *fault injection*.
+
+According to Wikipedia, "fault injection is a technique for improving the
+coverage of a test by introducing faults in order to test code paths, in
+particular error handling code paths, that might otherwise rarely be followed.
+It is often used with stress testing and is widely considered to be an
+important part of developing robust software".
+
+libfiu is a library that you can use to add fault injection to your code. It
+aims to be easy to use by means of a simple API, with minimal code impact and
+little runtime overhead when enabled.
+
+By minimal code impact I mean that the modifications you have to do to your
+code (and build system) in order to support libfiu should be as little
+intrusive as possible.
+
+
+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::
+
+        size_t free_space() {
+                [code to find out how much free space there is]
+                return space;
+        }
+
+        bool file_fits(FILE *fd) {
+                if (free_space() < file_size(fd)) {
+                        return false;
+                }
+                return true;
+        }
+
+As you can see, with current disk sizes, it's very, very strange that a disk
+runs out of free space. So the scenario where *free_space()* returns 0 is hard
+to test. With libfiu, you can modify that code into::
+
+        size_t free_space() {
+                fiu_return_on("no_free_space", 0);
+
+                [code to find out how much free space there is]
+                return space;
+        }
+
+        bool file_fits(FILE *fd) {
+                if (free_space() < file_size(fd)) {
+                        return false;
+                }
+                return true;
+        }
+
+There, you've just created a *point of failure* identified by the name
+"no_free_space", and said that when that point of failure is enabled, the
+function will return 0.
+
+In your testing code, you can now do this::
+
+        fiu_init();
+        fiu_enable("no_free_space", 1, NULL, 0);
+        assert(file_fits("tmpfile") == false);
+
+The first line initializes the library, and the second *enables* the point of
+failure. As the point of failure is enabled, *free_space()* will return 0, so
+you can test how your code behaves under that condition, which was otherwise
+hard to trigger.
+
+As you can see, libfiu's API has to "sides": a core API and a control API. The
+core API is used inside the code wanting to perform failure injection on. The
+control API is used inside the testing code, in order to control the injection
+of failures.
+
+In the example above, *fiu_return_on()* is a part of the core API, and
+*fiu_enable()* is a part of the control API.
+
+
+Using libfiu in your project
+----------------------------
+
+To use libfiu in your project, there are three things to consider: the build
+system, the fault injection code, and the testing code.
+
+
+The build system
+~~~~~~~~~~~~~~~~
+
+The first thing to do is to enable your build system to use libfiu. Usually,
+you do not want to make libfiu a runtime or build-time dependency, because
+it's a testing library.
+
+To that end, you should copy *fiu-local.h* into your source tree, and then
+create an option to do a *fault injection build* that #defines the constant
+*ENABLE_FIU* (usually done by adding ``-DFIU_ENABLE=1`` to your compiler
+flags) and links against libfiu (usually done by adding ``-lfiu`` to your
+linker flags).
+
+That way, normal builds will not have a single trace of fault injection code,
+but it will be easy to create a binary that does, for testing purposes.
+
+
+The fault injection code
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+Adding fault injection to your code means inserting points of failure in it,
+using the core API.
+
+First, you should ``#include "fiu-local.h"`` in the files you want to add
+points of failure to. That header allows you to avoid libfiu as a build-time
+dependency, as mentioned in the last section.
+
+Then, you to insert points of failure, you sprinkle your code with calls like
+``fiu_return_on("name", -1)``, ``fiu_exit_on("name")``, or more complex code
+using ``fiu_fail("name")``. Consult the libfiu's manpage for the details on
+the API.
+
+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
+all.
+
+
+The testing code
+~~~~~~~~~~~~~~~~
+
+Testing can be done in too many ways, so I won't get into specific details
+here. As a general approach, usually the idea with fault injection is to write
+tests similar in spirit to the one shown above: initialize the library, enable
+one or more failures using the control API, and then check if the code behaves
+as expected.
+
+Initially, all points of failure are disabled, which means your code should run
+as usual, with a very small performance impact.
+
+The points of failure can be enabled using different strategies:
+
+Unconditional (*fiu_enable()*)
+  Enables the point of failure in an unconditional way, so it always fails.
+
+Random (*fiu_enable_random()*)
+  Enables the point of failure in a non-deterministic way, which will fail with
+  the given probability.
+
+External (*fiu_enable_external()*)
+  Enables the point of failure using an external function, which will be called
+  to determine whether the point of failure should fail or not.
+
+You can also use an asterisk *at the end* of a name to enable all the points
+of failure that begin with the given name (excluding the asterisk, of course).
+
+Check libfiu's manpage for more details about the API.
+
+Using the Python bindings, you can also write and/or control your tests using
+Python.
+
+
diff --git a/libfiu/Makefile b/libfiu/Makefile
new file mode 100644
index 0000000..17c95d3
--- /dev/null
+++ b/libfiu/Makefile
@@ -0,0 +1,77 @@
+
+CFLAGS += -std=c99 -pedantic -Wall -O3
+ALL_CFLAGS = -D_XOPEN_SOURCE=500 -fPIC -DENABLE_FIU=1 $(CFLAGS)
+
+ifdef DEBUG
+ALL_CFLAGS += -g
+endif
+
+ifdef PROFILE
+ALL_CFLAGS += -g -pg -fprofile-arcs -ftest-coverage
+endif
+
+
+# prefix for installing the binaries
+PREFIX=/usr/local
+
+
+OBJS = fiu.o
+
+
+ifneq ($(V), 1)
+	NICE_CC = @echo "  CC  $@"; $(CC)
+else
+	NICE_CC = $(CC)
+endif
+
+
+default: all
+
+all: libs libfiu.pc
+
+libfiu.pc: libfiu.skel.pc
+	@echo "generating libfiu.pc"
+	@cat libfiu.skel.pc | \
+		sed 's@++PREFIX++@$(PREFIX)@g' \
+		> libfiu.pc
+
+libs: libfiu.so libfiu.a
+
+libfiu.so: fiu.h $(OBJS)
+	$(NICE_CC) $(ALL_CFLAGS) -shared -fPIC $(OBJS) -lpthread -o libfiu.so
+
+libfiu.a: fiu.h $(OBJS)
+	$(AR) cr libfiu.a $(OBJS)
+
+
+install-lib: libs libfiu.pc
+	install -d $(PREFIX)/lib
+	install -m 0755 libfiu.so $(PREFIX)/lib
+	install -m 0755 libfiu.a $(PREFIX)/lib
+	install -d $(PREFIX)/include
+	install -m 0644 fiu.h $(PREFIX)/include
+	install -m 0644 fiu-control.h $(PREFIX)/include
+	install -m 0644 fiu-local.h $(PREFIX)/include
+	install -d $(PREFIX)/lib/pkgconfig
+	install -m 644 libfiu.pc $(PREFIX)/lib/pkgconfig
+	@echo
+	@echo "Please run ldconfig to update your library cache"
+	@echo
+
+install-man:
+	install -d $(PREFIX)/man/man3
+	install -m 0644 libfiu.3 $(PREFIX)/man/man3/
+
+install: install-lib install-man
+
+
+.c.o:
+	$(NICE_CC) $(ALL_CFLAGS) -c $< -o $@
+
+clean:
+	rm -f libfiu.pc $(OBJS) libfiu.so libfiu.a
+	rm -f *.bb *.bbg *.da *.gcov *.gcda *.gcno gmon.out
+
+.PHONY: default all libs install-lib install-man install clean
+
+
diff --git a/libfiu/fiu-control.h b/libfiu/fiu-control.h
new file mode 100644
index 0000000..4a3baa5
--- /dev/null
+++ b/libfiu/fiu-control.h
@@ -0,0 +1,59 @@
+
+/*
+ * Control API for libfiu
+ */
+
+/* Flags */
+#define FIU_ONETIME 1		/* Only fail once */
+
+
+/* Enables the given point of failure. That makes it always fail.
+ *
+ * - name: point of failure name.
+ * - failnum: what will fiu_fail() return, must be != 0.
+ * - failinfo: what will fiu_failinfo() return.
+ * - flags: flags.
+ * - returns: 0 if success, < 0 otherwise.
+ * */
+int fiu_enable(const char *name, int failnum, void *failinfo,
+		unsigned int flags);
+
+
+/* Enables the given point of failure, with the given probability. That makes
+ * it fail with the given probablity.
+ *
+ * - name: point of failure name.
+ * - failnum: what will fiu_fail() return, must be != 0.
+ * - failinfo: what will fiu_failinfo() return.
+ * - flags: flags.
+ * - probability: probability a fiu_fail() call will return failnum,
+ * 	between 0 (never fail) and 1 (always fail). As a special fast case, -1
+ * 	can also be used to always fail.
+ * - returns: 0 if success, < 0 otherwise. */
+int fiu_enable_random(const char *name, int failnum, void *failinfo,
+		unsigned int flags, float probability);
+
+
+/** Type of external callback functions. They must return 0 to indicate not to
+ * fail, != 0 to indicate otherwise. Can modify failnum, failinfo and flags,
+ * in order to alter the values of the point of failure. */
+typedef int external_cb_t(const char *name, int *failnum, void **failinfo,
+		unsigned int *flags);
+
+/* Enables the given point of failure, leaving the decision whether to fail or
+ * not to the given external function.
+ *
+ * - name: point of failure name.
+ * - failnum: what will fiu_fail() return, must be != 0.
+ * - failinfo: what will fiu_failinfo() return.
+ * - flags: flags.
+ * - external_cb: function to call to determine whether fail or not. */
+int fiu_enable_external(const char *name, int failnum, void *failinfo,
+		unsigned int flags, external_cb_t *external_cb);
+
+/* Disables the given point of failure. That makes it NOT fail.
+ *
+ * - name: point of failure name.
+ * - returns: 0 if success, < 0 otherwise. */
+int fiu_disable(const char *name);
+
diff --git a/libfiu/fiu-local.h b/libfiu/fiu-local.h
new file mode 100644
index 0000000..b68327b
--- /dev/null
+++ b/libfiu/fiu-local.h
@@ -0,0 +1,37 @@
+
+/* libfiu - Fault Injection in Userspace
+ *
+ * This header, part of libfiu, is meant to be included in your project to
+ * avoid having libfiu as a mandatory build-time dependency.
+ *
+ * You can add it to your project, and #include it instead of fiu.h.
+ * The real fiu.h will be used only when FIU_ENABLE is defined.
+ *
+ * This header, as the rest of libfiu, is in the public domain.
+ *
+ * You can find more information about libfiu at
+ * http://blitiri.com.ar/p/libfiu.
+ */
+
+#ifndef _FIU_LOCAL_H
+#define _FIU_LOCAL_H
+
+/* Only define the stubs when fiu is disabled, otherwise use the real fiu.h
+ * header */
+#ifndef FIU_ENABLE
+
+#define fiu_init(flags) 0
+#define fiu_fail(name) 0
+#define fiu_failinfo() NULL
+#define fiu_do_on(name, action)
+#define fiu_exit_on(name)
+#define fiu_return_on(name, retval)
+
+#else
+
+#include <fiu.h>
+
+#endif /* FIU_ENABLE */
+
+#endif /* _FIU_LOCAL_H */
+
diff --git a/libfiu/fiu.c b/libfiu/fiu.c
new file mode 100644
index 0000000..b1f2330
--- /dev/null
+++ b/libfiu/fiu.c
@@ -0,0 +1,387 @@
+
+#include <stdlib.h>		/* malloc() and friends */
+#include <string.h>		/* strcmp() and friends */
+#include <pthread.h>		/* mutexes */
+
+/* Enable us, so we get the real prototypes from the headers */
+#define FIU_ENABLE 1
+
+#include "fiu.h"
+#include "fiu-control.h"
+
+
+/* Different methods to decide when a point of failure fails */
+enum pf_method {
+	PF_ALWAYS = 1,
+	PF_PROB,
+	PF_EXTERNAL,
+};
+
+/* Point of failure information */
+struct pf_info {
+	char *name;
+	unsigned int namelen;
+	int failnum;
+	void *failinfo;
+	unsigned int flags;
+
+	/* How to decide when this point of failure fails, and the information
+	 * needed to take the decision */
+	enum pf_method method;
+	union {
+		/* To use when method == PF_PROB */
+		float probability;
+
+		/* To use when method == PF_EXTERNAL */
+		external_cb_t *external_cb;
+
+	} minfo;
+};
+
+
+/* Array used to keep the information about the enabled points of failure.
+ * It's an array because we assume it's going to be short enough for the
+ * linear lookup not matter.
+ * In the future, if it turns out it's normal that it grows large enough, we
+ * may be interested in a more sophisticated structure like a hash table
+ * and/or a bloom filter. */
+static struct pf_info *enabled_fails = NULL;
+static struct pf_info *enabled_fails_last = NULL;
+static size_t enabled_fails_len = 0;
+static size_t enabled_fails_nfree = 0;
+static pthread_rwlock_t enabled_fails_lock;
+#define ef_rlock() do { pthread_rwlock_rdlock(&enabled_fails_lock); } while (0)
+#define ef_wlock() do { pthread_rwlock_wrlock(&enabled_fails_lock); } while (0)
+#define ef_runlock() do { pthread_rwlock_unlock(&enabled_fails_lock); } while (0)
+#define ef_wunlock() do { pthread_rwlock_unlock(&enabled_fails_lock); } while (0)
+
+/* Maximum number of free elements in enabled_fails (used to decide when to
+ * shrink). */
+#define EF_MAX_FREE 3
+
+/* How much to grow enabled_fails by each time, it's recommended that this is
+ * less than EF_MAX_FREE. */
+#define EF_GROW 2
+
+
+/* Used to keep the last failinfo via TLS */
+static pthread_key_t last_failinfo_key;
+
+/* Used to avoid re-initialization, protected by enabled_fails_lock */
+static int initialized = 0;
+
+
+/*
+ * Miscelaneous internal functions
+ */
+
+/* Disables the given pf_info, assuming it's inside enabled_fails. Must be
+ * called with enabled_fails_lock acquired. */
+static void disable_pf(struct pf_info *pf)
+{
+	/* free the name we've allocated in setup_fail() via strdup() */
+	free(pf->name);
+	pf->name = NULL;
+	pf->namelen = 0;
+	pf->failnum = 0;
+	pf->failinfo = NULL;
+	pf->flags = 0;
+}
+
+/* Return the last position where s1 and s2 match. */
+static unsigned int strlast(const char *s1, const char *s2)
+{
+	unsigned int i = 0;
+
+	while (*s1 != '\0' && *s2 != '\0' && *s1 == *s2) {
+		i++;
+		s1++;
+		s2++;
+	}
+
+	return i;
+}
+
+/* Checks if pf's name matches the one given. pf->name can be NULL. */
+static int name_matches(const struct pf_info *pf, const char *name, int exact)
+{
+	if (pf->name == NULL || name == NULL)
+		return 0;
+
+	if (exact || pf->name[pf->namelen - 1] != '*')
+		return strcmp(pf->name, name) == 0;
+
+	/* Inexact match */
+	return strlast(pf->name, name) >= pf->namelen - 1;
+}
+
+/* Shrink enabled_fails, used when it has too many free elements. Must be
+ * called with enabled_fails_lock acquired. */
+static int shrink_enabled_fails(void)
+{
+	int i;
+	size_t new_len;
+	struct pf_info *new, *pf;
+
+	new_len = enabled_fails_len - enabled_fails_nfree + EF_GROW;
+
+	new = malloc(new_len * sizeof(struct pf_info));
+	if (new == NULL)
+		return -1;
+
+	i = 0;
+	for (pf = enabled_fails; pf <= enabled_fails_last; pf++) {
+		if (pf->name == NULL)
+			continue;
+
+		memcpy(new + i, pf, sizeof(struct pf_info));
+		i++;
+	}
+
+	memset(new + i, 0, (new_len - i) * sizeof(struct pf_info));
+
+	free(enabled_fails);
+	enabled_fails = new;
+	enabled_fails_len = new_len;
+	enabled_fails_last = new + new_len - 1;
+	enabled_fails_nfree = EF_GROW;
+
+	return 0;
+}
+
+/*
+ * Core API
+ */
+
+/* Initializes the library. It should be safe to call this more than once at
+ * any time, to allow several independant libraries to use fiu at the same
+ * time without clashes. */
+int fiu_init(unsigned int flags)
+{
+	ef_wlock();
+	if (!initialized) {
+		/* first time we get called */
+		pthread_key_create(&last_failinfo_key, NULL);
+
+		enabled_fails = NULL;
+		enabled_fails_last = NULL;
+		enabled_fails_len = 0;
+		enabled_fails_nfree = 0;
+
+		initialized = 1;
+	}
+
+	ef_wunlock();
+	return 0;
+}
+
+/* Returns the failure status of the given name. Must work well even before
+ * fiu_init() is called assuming no points of failure are enabled; although it
+ * can (and does) assume fiu_init() will be called before enabling any. */
+int fiu_fail(const char *name)
+{
+	struct pf_info *pf;
+	int failnum;
+
+	ef_rlock();
+
+	if (enabled_fails == NULL) {
+		ef_runlock();
+		return 0;
+	}
+
+	for (pf = enabled_fails; pf <= enabled_fails_last; pf++) {
+		if (name_matches(pf, name, 0)) {
+			switch (pf->method) {
+			case PF_ALWAYS:
+				goto exit_fail;
+				break;
+			case PF_PROB:
+				if (pf->minfo.probability < drand48() )
+					goto exit_fail;
+				break;
+			case PF_EXTERNAL:
+				if (pf->minfo.external_cb(pf->name,
+						&(pf->failnum),
+						&(pf->failinfo),
+						&(pf->flags)))
+					goto exit_fail;
+				break;
+			default:
+				break;
+			}
+
+			break;
+		}
+	}
+
+	ef_runlock();
+	return 0;
+
+exit_fail:
+	pthread_setspecific(last_failinfo_key,
+			pf->failinfo);
+	failnum = pf->failnum;
+
+	if (pf->flags & FIU_ONETIME) {
+		disable_pf(pf);
+		enabled_fails_nfree++;
+	}
+
+	ef_runlock();
+	return failnum;
+}
+
+/* Returns the information associated with the last fail. */
+void *fiu_failinfo(void)
+{
+	return pthread_getspecific(last_failinfo_key);
+}
+
+
+/*
+ * Control API
+ */
+
+/* Sets up the given pf. For internal use only. */
+static int setup_fail(struct pf_info *pf, const char *name, int failnum,
+		void *failinfo, unsigned int flags, enum pf_method method,
+		float probability, external_cb_t *external_cb)
+{
+	pf->name = strdup(name);
+	pf->namelen = strlen(name);
+	pf->failnum = failnum;
+	pf->failinfo = failinfo;
+	pf->flags = flags;
+	pf->method = method;
+	switch (method) {
+		case PF_ALWAYS:
+			break;
+		case PF_PROB:
+			pf->minfo.probability = probability;
+			break;
+		case PF_EXTERNAL:
+			pf->minfo.external_cb = external_cb;
+			break;
+		default:
+			return -1;
+	}
+
+	if (pf->name == NULL)
+		return -1;
+	return 0;
+
+}
+
+/* Creates a new pf in the enabled_fails table. For internal use only. */
+static int insert_new_fail(const char *name, int failnum, void *failinfo,
+		unsigned int flags, enum pf_method method, float probability,
+		external_cb_t *external_cb)
+{
+	struct pf_info *pf;
+	int rv;
+	size_t prev_len;
+
+	rv = -1;
+
+	/* See if it's already there and update the data if so, or if we have
+	 * a free spot where to put it */
+	ef_wlock();
+	if (enabled_fails != NULL && enabled_fails_nfree > 0) {
+		for (pf = enabled_fails; pf <= enabled_fails_last; pf++) {
+			if (pf->name == NULL || strcmp(pf->name, name) == 0) {
+				rv = setup_fail(pf, name, failnum, failinfo,
+						flags, method, probability,
+						external_cb);
+				if (rv == 0)
+					enabled_fails_nfree--;
+
+				goto exit;
+			}
+		}
+
+		/* There should be a free slot, but couldn't find one! This
+		 * shouldn't happen */
+		rv = -1;
+		goto exit;
+	}
+
+	/* There are no free slots in enabled_fails, so we must grow it */
+	enabled_fails = realloc(enabled_fails,
+			enabled_fails_len + EF_GROW * sizeof(struct pf_info));
+	if (enabled_fails == NULL) {
+		enabled_fails_last = NULL;
+		enabled_fails_len = 0;
+		enabled_fails_nfree = 0;
+		rv = -1;
+		goto exit;
+	}
+
+	prev_len = enabled_fails_len;
+	enabled_fails_len += EF_GROW;
+	enabled_fails_nfree = EF_GROW;
+
+	memset(enabled_fails + prev_len, 0,
+			EF_GROW * sizeof(struct pf_info));
+
+	enabled_fails_last = enabled_fails + enabled_fails_len - 1;
+
+	pf = enabled_fails + prev_len;
+	rv = setup_fail(pf, name, failnum, failinfo, flags, method,
+			probability, external_cb);
+	if (rv == 0)
+		enabled_fails_nfree--;
+
+exit:
+	ef_wunlock();
+	return rv;
+}
+
+/* Makes the given name fail. */
+int fiu_enable(const char *name, int failnum, void *failinfo,
+		unsigned int flags)
+{
+	return insert_new_fail(name, failnum, failinfo, flags, PF_ALWAYS, 0,
+			NULL);
+}
+
+/* Makes the given name fail with the given probability. */
+int fiu_enable_random(const char *name, int failnum, void *failinfo,
+		unsigned int flags, float probability)
+{
+	return insert_new_fail(name, failnum, failinfo, flags, PF_PROB,
+			probability, NULL);
+}
+
+/* Makes the given name fail when the external function returns != 0. */
+int fiu_enable_external(const char *name, int failnum, void *failinfo,
+		unsigned int flags, external_cb_t *external_cb)
+{
+	return insert_new_fail(name, failnum, failinfo, flags, PF_EXTERNAL,
+			0, external_cb);
+}
+
+/* Makes the given name NOT fail. */
+int fiu_disable(const char *name)
+{
+	struct pf_info *pf;
+
+	/* just find the point of failure and mark it as free by setting its
+	 * name to NULL */
+	ef_wlock();
+	for (pf = enabled_fails; pf <= enabled_fails_last; pf++) {
+		if (name_matches(pf, name, 1)) {
+			disable_pf(pf);
+			enabled_fails_nfree++;
+			if (enabled_fails_nfree > EF_MAX_FREE)
+				shrink_enabled_fails();
+			ef_wunlock();
+			return 0;
+		}
+	}
+
+	ef_wunlock();
+	return -1;
+}
+
+
diff --git a/libfiu/fiu.h b/libfiu/fiu.h
new file mode 100644
index 0000000..e9fdf64
--- /dev/null
+++ b/libfiu/fiu.h
@@ -0,0 +1,71 @@
+
+/* libfiu - Fault Injection in Userspace
+ *
+ * This header, part of libfiu, contains the API that your project should use.
+ *
+ * If you want to avoid having libfiu as a mandatory build-time dependency,
+ * you should include fiu-stubs.h in your project, and #include it instead of
+ * this.
+ */
+
+#ifndef _FIU_H
+#define _FIU_H
+
+
+/* Controls whether the external code enables libfiu or not. */
+#ifdef FIU_ENABLE
+
+/* Initializes the library.
+ *
+ * - flags: unused.
+ * - returns: 0 if success, < 0 if error. */
+int fiu_init(unsigned int flags);
+
+/* Returns the failure status of the given point of failure.
+ *
+ * - name: point of failure name.
+ * - returns: the failure status (0 means it should not fail). */
+int fiu_fail(const char *name);
+
+/* Returns the information associated with the last failure.
+ *
+ * - returns: the information associated with the last fail, or NULL if there
+ *      isn't one. */
+void *fiu_failinfo(void);
+
+/* Performs the given action when the given point of failure fails. Mostly
+ * used in the following macros. */
+#define fiu_do_on(name, action) \
+        do { \
+                if (fiu_fail(name)) { \
+                        action; \
+                } \
+        } while (0)
+
+/* Exits the program when the given point of failure fails. */
+#define fiu_exit_on(name) fiu_do_on(name, exit(EXIT_FAILURE))
+
+/* Makes the function return the given retval when the given point of failure
+ * fails. */
+#define fiu_return_on(name, retval) fiu_do_on(name, return retval)
+
+
+/* Undefine the private defines */
+#undef _likely
+#undef _unlikely
+
+#else
+/* fiu not enabled, this should match fiu-local.h but we don't include it
+ * because it includes us assuming we're installed system-wide */
+
+#define fiu_init(flags) 0
+#define fiu_fail(name) 0
+#define fiu_failinfo() NULL
+#define fiu_do_on(name, action)
+#define fiu_exit_on(name)
+#define fiu_return_on(name, retval)
+
+#endif /* FIU_ENABLE */
+
+#endif /* _FIU_H */
+
diff --git a/libfiu/libfiu.3 b/libfiu/libfiu.3
new file mode 100644
index 0000000..1f27c9b
--- /dev/null
+++ b/libfiu/libfiu.3
@@ -0,0 +1,170 @@
+.TH libfiu 3 "17/Feb/2009"
+.SH NAME
+libfiu - Fault injection in userspace
+.SH SYNOPSYS
+.nf
+.B /* Core API */
+.B #include <fiu.h>
+.sp
+.BI "int fiu_init(unsigned int " flags ");"
+.BI "int fiu_fail(const char *" name ");"
+.BI "void *fiu_failinfo(void);"
+.BI "[void] fiu_do_on(char *" name ", " action "); [macro]"
+.BI "[void] fiu_exit_on(char *" name "); [macro]"
+.BI "[void] fiu_return_on(char *" name ", " retval "); [macro]"
+.sp
+.B /* Control API */
+.B #include <fiu-control.h>
+.sp
+.BI "int fiu_enable(const char *" name ", int " failnum ","
+.BI "		void *" failinfo ", unsigned int " flags ");"
+.BI "int fiu_enable_random(const char *" name ", int " failnum ","
+.BI "		void *" failinfo ", unsigned int " flags ", float " probability ");"
+.BI "typedef int external_cb_t(const char *" name ", int *" failnum ","
+.BI "		void **" failinfo ", unsigned int *" flags ");"
+.BI "int fiu_enable_external(const char *" name ", int " failnum ","
+.BI "		void *" failinfo ", unsigned int " flags ","
+.BI "		external_cb_t *" external_cb ");"
+.BI "int fiu_disable(const char *" name ");"
+.sp
+.fi
+.SH DESCRIPTION
+
+libfiu is a library for fault injection. It provides functions to mark "points
+of failure" inside your code (the "core API"), and functions to enable/disable
+the failure of those points (the "control API").
+
+The core API is used inside the code wanting to perform failure injection on.
+The control API is used inside the testing code, in order to control the
+injection of failures.
+
+This page is an API reference and not a complete manual, and as such does not
+go into detail about how to use the library. The library's manual can be found
+in the distribution.
+
+.SS CORE API
+
+To use the core API, you should
+.IR "#include <fiu.h>" .
+
+Because fault injection is usually a debugging/testing facility, unwanted at
+runtime, some special considerations were taken to minimize the impact of the
+core API. First of all, if
+.I FIU_ENABLE
+is not defined, then fiu.h will define empty stubs for all the core API,
+effectively disabling fault injection completely, without any runtime
+performance.
+
+Also, a special header
+.I fiu-local.h
+is shipped with libfiu. It is meant to be included in your project to avoid
+having libfiu as a mandatory build-time dependency. You can add it to your
+project, and #include it instead of
+.IR fiu.h .
+It will take care of including the real
+.I fiu.h
+only when
+.I FIU_ENABLE
+is defined. It is entirely optional, but recommended. See the library's manual
+for more details.
+
+
+.TP
+.BI "int fiu_init(" flags ")"
+Initializes the library. Ideally, you should only call this once, although it
+can cope with multiple calls. The flags parameter is currently unused and must
+be set to 0. Returns 0 on success, < 0 on error.
+
+.TP
+.BI "fiu_fail(" name ")"
+Returns the failure status of the given point of failure. 0 means it should
+not fail. By default, all points of failure do not fail; they're enabled in
+runtime using the control API.
+
+.TP
+.BI "fiu_failinfo()"
+Returns the information associated with the last failure, or NULL if there
+isn't one.
+
+.TP
+.BI "fiu_do_on(" name ", " action ") [macro]"
+This is a macro that uses
+.B fiu_fail()
+to perform the given action when the given point of failure fails. The action
+can be any valid C statement.
+
+.TP
+.BI "fiu_exit_on(" name ") [macro]"
+This is a macro that uses
+.B fiu_fail()
+to exit the process when the given point of failure fails. The process is exit
+using exit(3), which is given the status EXIT_FAILURE.
+
+.TP
+.BI "fiu_return_on(" name ", " retval ") [macro]"
+This is a macro that uses
+.B fiu_fail()
+to make the current function return the given value (whose type obviously
+depends on the return type of the function).
+
+.SS CONTROL API
+
+To use the control API, you should
+.IR "#include <fiu-control.h>" .
+
+.TP
+.BI "fiu_enable(" name ", " failnum ", " failinfo ", " flags ")"
+Enables the given point of failure.
+.I failnum
+is what
+.B fiu_fail()
+will return, and must be != 0.
+.I failinfo
+is what
+.B fiu_failinfo()
+will return when called after the given point of failure has failed.
+.I flags
+can be either 0 or
+.IR FIU_ONETIME ,
+which indicates that this point of failure should only fail once.  Returns 0 if
+success, < 0 otherwise. If the point of failure was already enabled, this
+overwrites the previous values.
+
+Successive calls to
+.B fiu_fail()
+will return
+.I failnum
+until this point of failure is disabled. If
+.I FIU_ONETIME
+was passed in the flags, this point of failure is disabled immediately after
+failing once.
+
+If the name ends with an asterisk, then it this will match all points of
+failure that begin with the given name (excluding the asterisk, of course).
+
+.TP
+.BI "fiu_enable_random(" name ", " failnum ", " failinfo ", " flags ", " probability ")"
+Enables the given point of failure, with the given probability. The rest of the
+parameters, as well as the return value, are the same as the ones in
+.BR fiu_enable() .
+
+.TP
+.BI "fiu_enable_external(" name ", " failnum ", " failinfo ", " flags ", " external_cb ")"
+Enables the given point of failure, leaving the decision whether to fail or not
+to the given external function, which should return 0 if it is not to fail, or
+1 otherwise. The rest of the parameters, as well as the return value, are the
+same as the ones in
+.BR fiu_enable() .
+
+.TP
+.BI "fiu_disable(" name ")"
+Disables the given point of failure, undoing the actions of the
+.B fiu_enable*()
+functions.
+
+.SH BUGS
+
+If you want to report bugs, or have any questions or comments, just let me
+know at albertito@blitiri.com.ar. For more information about the library, you
+can go to http://blitiri.com.ar/p/libfiu.
+
diff --git a/libfiu/libfiu.skel.pc b/libfiu/libfiu.skel.pc
new file mode 100644
index 0000000..838b4b6
--- /dev/null
+++ b/libfiu/libfiu.skel.pc
@@ -0,0 +1,12 @@
+
+prefix=++PREFIX++
+libdir=${prefix}/lib
+includedir=${prefix}/include
+
+Name: libfiu
+Description: Fault injection in userspace
+URL: http://blitiri.com.ar/p/libfiu/
+Version: 0.10
+Libs: -L${libdir} -lfiu
+Cflags: -I${includedir}
+