git » libfiu » commit 278bb60

Add a new preload library to enable failure points before a program starts

author Alberto Bertogli
2009-06-15 06:08:28 UTC
committer Alberto Bertogli
2009-06-16 15:44:58 UTC
parent ff676e1218b57d36c41df81d9b85ec3e89abd613

Add a new preload library to enable failure points before a program starts

This patch adds a new preload library which allows the user to enable
failure points and remote control (via environment variables) before a
program starts.

It can be used combined with the posix preload to simulate faults in the
standard library functions.

A shell script to make it easier to use will be added in future commits,
along more documentation.

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

.gitignore +2 -0
preload/Makefile +16 -4
preload/run/Makefile +49 -0
preload/run/run.c +129 -0

diff --git a/.gitignore b/.gitignore
index 39f12b9..fdfed27 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,4 +9,6 @@ preload/posix/*.o
 preload/posix/*.so
 preload/posix/modules/*.o
 preload/posix/modules/*.mod.c
+preload/run/*.o
+preload/run/*.so
 
diff --git a/preload/Makefile b/preload/Makefile
index 20698c7..a575d71 100644
--- a/preload/Makefile
+++ b/preload/Makefile
@@ -1,11 +1,11 @@
 
 default: all
 
-all: posix
+all: posix run
 
-install: posix_install
+install: posix_install run_install
 
-clean: posix_clean
+clean: posix_clean run_clean
 
 
 posix:
@@ -17,6 +17,18 @@ posix_clean:
 posix_install:
 	$(MAKE) -C posix/ install
 
+run:
+	$(MAKE) -C run/
 
-.PHONY: default clean install posix posix_clean posix_install
+run_clean:
+	$(MAKE) -C run/ clean
+
+run_install:
+	$(MAKE) -C run/ install
+
+
+
+.PHONY: default clean install \
+	posix posix_clean posix_install \
+	run run_clean run_install 
 
diff --git a/preload/run/Makefile b/preload/run/Makefile
new file mode 100644
index 0000000..7655a86
--- /dev/null
+++ b/preload/run/Makefile
@@ -0,0 +1,49 @@
+
+CFLAGS += -std=c99 -Wall -O3
+ALL_CFLAGS = -D_XOPEN_SOURCE=500 -fPIC -DFIU_ENABLE=1 \
+		-I. -I../../libfiu/ -L../../libfiu/ $(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 = run.o
+
+
+ifneq ($(V), 1)
+	NICE_CC = @echo "  CC  $@"; $(CC)
+else
+	NICE_CC = $(CC)
+endif
+
+
+default: all
+	
+all: fiu_run_preload.so
+
+.c.o:
+	$(NICE_CC) $(ALL_CFLAGS) -c $< -o $@
+
+fiu_run_preload.so: $(OBJS)
+	$(NICE_CC) $(ALL_CFLAGS) -shared -fPIC $(OBJS) -lfiu -ldl \
+		-o fiu_run_preload.so
+
+install: fiu_run_preload.so
+	install -d $(PREFIX)/lib
+	install -m 0755 fiu_run_preload.so $(PREFIX)/lib
+
+clean:
+	rm -f $(OBJS) fiu_run_preload.so
+	rm -f *.bb *.bbg *.da *.gcov *.gcda *.gcno gmon.out
+
+.PHONY: default install clean
+
+
diff --git a/preload/run/run.c b/preload/run/run.c
new file mode 100644
index 0000000..cf0dfa6
--- /dev/null
+++ b/preload/run/run.c
@@ -0,0 +1,129 @@
+
+#include <stdio.h>		/* printf() */
+#include <unistd.h>		/* execve() */
+#include <string.h>		/* strtok(), memset(), strncpy() */
+#include <stdlib.h>		/* atoi(), atol() */
+#include <getopt.h>		/* getopt() */
+
+#include <fiu.h>
+#include <fiu-control.h>
+
+/* Maximum size of parameters to the enable options */
+#define MAX_ENOPT 128
+
+enum fp_type {
+	FP_ALWAYS = 1,
+	FP_PROB = 2,
+};
+
+struct enable_option {
+	char buf[MAX_ENOPT];
+	enum fp_type type;
+	char *name;
+	int failnum;
+	unsigned long failinfo;
+	float probability;
+};
+
+/* Fills the enopt structure taking the values from the given string, which is
+ * assumed to be in of the form:
+ *
+ *   name,probability,failnum,failinfo
+ *
+ * All fields are optional, except for the name. On error, enopt->name will be
+ * set to NULL. Probability is in percent, -1 indicates it should always be
+ * enabled. */
+static void parse_enable(const char *s, struct enable_option *enopt)
+{
+	char *tok;
+	char *state;
+
+	enopt->name = NULL;
+	enopt->type = FP_ALWAYS;
+	enopt->failnum = 1;
+	enopt->failinfo = 0;
+	enopt->probability = 1;
+
+	memset(enopt->buf, 0, MAX_ENOPT);
+	strncpy(enopt->buf, s, MAX_ENOPT);
+
+	tok = strtok_r(enopt->buf, ",", &state);
+	if (tok == NULL)
+		return;
+	enopt->name = tok;
+
+	tok = strtok_r(NULL, ",", &state);
+	if (tok == NULL)
+		return;
+	if (atoi(tok) >= 0) {
+		enopt->type = FP_PROB;
+		enopt->probability = atof(tok) / 100.0;
+	}
+
+	tok = strtok_r(NULL, ",", &state);
+	if (tok == NULL)
+		return;
+	enopt->failnum = atoi(tok);
+
+	tok = strtok_r(NULL, ",", &state);
+	if (tok == NULL)
+		return;
+	enopt->failinfo = atol(tok);
+}
+
+/* We set the constructor with priority 300 so it runs after the other
+ * libfiu preloaders (if they're enabled), which use the 200 range */
+static void __attribute__((constructor(300))) fiu_run_init(void)
+{
+	int r;
+	struct enable_option enopt;
+	char *fiu_enable_env, *fiu_enable_s, *fiu_fifo_env;
+	char *tok, *state;
+
+	fiu_init(0);
+
+	fiu_fifo_env = getenv("FIU_CTRL_FIFO");
+	if (fiu_fifo_env != NULL && *fiu_fifo_env != '\0')
+		fiu_rc_fifo(fiu_fifo_env);
+
+	fiu_enable_env = getenv("FIU_ENABLE");
+	if (fiu_enable_env == NULL)
+		return;
+
+	/* copy fiu_enable_env to fiu_enable_s so we can strtok() it */
+	fiu_enable_s = malloc(strlen(fiu_enable_env) + 1);
+	strcpy(fiu_enable_s, fiu_enable_env);
+
+	state = NULL;
+	tok = strtok_r(fiu_enable_s, ":", &state);
+	while (tok != NULL) {
+		parse_enable(tok, &enopt);
+		if (enopt.name == NULL) {
+			fprintf(stderr, "fiu-run.so: "
+					"ignoring enable without name");
+			tok = strtok_r(NULL, ":", &state);
+			continue;
+		}
+
+		if (enopt.type == FP_ALWAYS) {
+			r = fiu_enable(enopt.name, enopt.failnum,
+					(void *) enopt.failinfo, 0);
+		} else {
+			r = fiu_enable_random(enopt.name, enopt.failnum,
+					(void *) enopt.failinfo, 0,
+					enopt.probability);
+		}
+
+		if (r < 0) {
+			fprintf(stderr, "fiu-run.so: "
+					"couldn't enable failure %s\n",
+					enopt.name);
+			continue;
+		}
+
+		tok = strtok_r(NULL, ":", &state);
+	}
+
+	free(fiu_enable_s);
+}
+