From 278bb609c79d9bc9d718fc1395bf4249f9cdd36a Mon Sep 17 00:00:00 2001
From: Alberto Bertogli <albertito@blitiri.com.ar>
Date: Mon, 15 Jun 2009 03:08:28 -0300
Subject: [PATCH 32/48] 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 +
 preload/Makefile                |   20 +++++-
 preload/{posix => run}/Makefile |   24 ++-----
 preload/run/run.c               |  129 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 154 insertions(+), 21 deletions(-)
 copy preload/{posix => run}/Makefile (53%)
 create mode 100644 preload/run/run.c

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/posix/Makefile b/preload/run/Makefile
similarity index 53%
copy from preload/posix/Makefile
copy to preload/run/Makefile
index 411f61d..7655a86 100644
--- a/preload/posix/Makefile
+++ b/preload/run/Makefile
@@ -15,43 +15,33 @@ endif
 PREFIX=/usr/local
 
 
-GEN_C = $(addsuffix .c,$(wildcard modules/*.mod))
-GEN_OBJS = $(addsuffix .o,$(wildcard modules/*.mod))
-CUSTOM_OBJS = $(patsubst %.c,%.o,$(wildcard modules/*.custom.c))
-OBJS = codegen.o $(GEN_OBJS) $(CUSTOM_OBJS)
+OBJS = run.o
 
 
 ifneq ($(V), 1)
 	NICE_CC = @echo "  CC  $@"; $(CC)
-	NICE_GEN = @echo "  GEN $@"; ./generate
 else
 	NICE_CC = $(CC)
-	NICE_GEN = ./generate
 endif
 
 
 default: all
 	
-all: fiu_posix_preload.so
-
-$(GEN_OBJS): $(GEN_C)
-
-%.mod.c: %.mod
-	$(NICE_GEN) $< $@
+all: fiu_run_preload.so
 
 .c.o:
 	$(NICE_CC) $(ALL_CFLAGS) -c $< -o $@
 
-fiu_posix_preload.so: $(OBJS)
+fiu_run_preload.so: $(OBJS)
 	$(NICE_CC) $(ALL_CFLAGS) -shared -fPIC $(OBJS) -lfiu -ldl \
-		-o fiu_posix_preload.so
+		-o fiu_run_preload.so
 
-install: fiu_posix_preload.so
+install: fiu_run_preload.so
 	install -d $(PREFIX)/lib
-	install -m 0755 fiu_posix_preload.so $(PREFIX)/lib
+	install -m 0755 fiu_run_preload.so $(PREFIX)/lib
 
 clean:
-	rm -f $(OBJS) $(GEN_OBJS:.o=.c) fiu_posix_preload.so
+	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);
+}
+
-- 
1.6.2.2.646.gb214

