[netfilter-cvslog] r3394 - in trunk/nfsim: core kernelenv

rusty at netfilter.org rusty at netfilter.org
Thu Dec 16 01:18:46 CET 2004


Author: rusty at netfilter.org
Date: 2004-12-16 01:18:46 +0100 (Thu, 16 Dec 2004)
New Revision: 3394

Modified:
   trunk/nfsim/core/core.c
   trunk/nfsim/core/core.h
   trunk/nfsim/core/failtest.c
   trunk/nfsim/core/tui.c
   trunk/nfsim/core/tui.h
   trunk/nfsim/kernelenv/kernelenv.c
Log:
In this episode, Rusty learns an important lesson about fork() and file
descriptors.  Somehow, this was missed or forgotten in his Unix education.
It turns out that file descriptor's current offset is shared with the child,
meaning that the parent's next read will get the contents somewhere furthur
down the file than expected.

To fix this, we don't use readline when we're doing failtest: suck the whole
file into memory where it's safe from the whim of fd offsets (I tried seeking
back in the parent, but readline seems to get confused somehow: this works).

In addition, tui_init etc. became tui_run() which does everything, which
encapsulates stopping quite nicely, too.  I took the should_i_fail() out
of call_elem_hook for the moment, as it is too slow.  Also, failpattern
no longer turns on failtest: code is clearer this way.



Modified: trunk/nfsim/core/core.c
===================================================================
--- trunk/nfsim/core/core.c	2004-12-16 00:04:40 UTC (rev 3393)
+++ trunk/nfsim/core/core.c	2004-12-16 00:18:46 UTC (rev 3394)
@@ -65,8 +65,6 @@
 
 const char *nf_hooknames[NPROTO][NF_MAX_HOOKS];
 
-static int running;
-
 /* userspace queue */
 static int queueid;
 LIST_HEAD(nfsim_queue);
@@ -124,11 +122,6 @@
 	return 0;
 }
 
-void stop()
-{
-	running = 0;
-}
-
 /* We want logging for every hook */
 unsigned int call_elem_hook(struct nf_hook_ops *ops,
 			    unsigned int hooknum,
@@ -139,9 +132,6 @@
 {
 	unsigned int ret;
 
-	if (should_i_fail(__func__))
-		return NF_DROP;
-
 	ret = ops->hook(hooknum, skb, in, out, okfn);
 	nfsim_log(LOG_HOOK, "hook:%s %s %s%s",
 		   nf_hooknames[PF_INET][hooknum], ops->owner->name,
@@ -182,7 +172,7 @@
 
 int main(int argc, char **argv)
 {
-	int failtest = 0, load_modules = 1;
+	bool failtest = false, load_modules = true;
 	char c;
 	char *p;
 	char *failpattern = NULL;
@@ -199,7 +189,7 @@
 			tui_abort_on_fail = 1;
 			break;
 		case 'N':
-			load_modules = 0;
+			load_modules = false;
 			break;
 		case 'V':
 			printf("nfsim version %s\nkernel version %s\n",
@@ -208,11 +198,10 @@
 			exit(EXIT_SUCCESS);
 			break;
 		case 1:
-			failtest = 1;
+			failtest = true;
 			break;
 		case 2:
 			failpattern = optarg;
-			failtest = 1;
 			break;
 		default:
 			fprintf(stderr, "Unknown argument %c\n", c);
@@ -228,6 +217,9 @@
 		close(input);
 	}
 
+	if (failtest && isatty(STDIN_FILENO))
+		barf("Not clever enough to use --failtest interactively");
+
 	/* Hack to make users' lives easier: set LD_LIBRARY_PATH for
 	 * fakesockopt.so, based on where we are. */
 	p = strrchr(argv[0], '/');
@@ -267,24 +259,13 @@
 	
 	nfsim_log(LOG_UI, "initialisation done");
 
-	if (failtest)
-		set_failtest(failpattern);
-
-	running = 1;
-
+	set_failtest(failtest, failpattern);
+	
 	message_init();
-	tui_init();
 
-	while (running) {
-		wait_for_message(STDIN_FILENO);
-		tui_userinput(STDIN_FILENO);
-	}
+	tui_run(!failtest, STDIN_FILENO);
 
-	if (!tui_quiet)
-		printf("\n");
-
 	message_cleanup();
-	tui_cleanup(STDIN_FILENO);
 	unload_all_modules();
 	check_allocations();
 

Modified: trunk/nfsim/core/core.h
===================================================================
--- trunk/nfsim/core/core.h	2004-12-16 00:04:40 UTC (rev 3393)
+++ trunk/nfsim/core/core.h	2004-12-16 00:18:46 UTC (rev 3394)
@@ -208,8 +208,6 @@
 
 #include <ipv4/ipv4.h>
 
-void stop(void);
-
 static inline int complete_read(int fd, char *buf, int len)
 {
 	int ret = 0;
@@ -264,7 +262,7 @@
 
 /* For failtest to test malloc etc failures. */
 bool should_i_fail(const char *func);
-void set_failtest(const char *pattern);
+void set_failtest(bool failtest, const char *initial_failpattern);
 
 enum exitcodes
 {

Modified: trunk/nfsim/core/failtest.c
===================================================================
--- trunk/nfsim/core/failtest.c	2004-12-16 00:04:40 UTC (rev 3393)
+++ trunk/nfsim/core/failtest.c	2004-12-16 00:18:46 UTC (rev 3394)
@@ -22,10 +22,11 @@
 #include <log.h>
 #include <kernelenv.h>
 #include <utils.h>
+#include <tui.h>
 #include <sys/types.h>
 #include <sys/wait.h>
 
-static bool failtest_on = false;
+static bool failtest = false;
 bool suppress_failtest;
 
 /* Failures pattern so far. */
@@ -78,7 +79,6 @@
 		return false;
 	case 0:
 		failpattern = NULL;
-		failtest_on = 0;
 		return false;
 	default:
 		barf("Failpattern '%c' failed to pattern",
@@ -92,18 +92,18 @@
 	pid_t child;
 	int status;
 
-	if (!failtest_on || suppress_failtest)
-		return false;
-
 	if (failpattern)
 		return do_failpattern(func);
 
+	if (!failtest || suppress_failtest)
+		return false;
+
 	child = fork();
 	if (child == -1)
 		barf_perror("fork failed for failtest!");
 
 	/* The child actually fails.  The script will screw up at this
-	 * point, but keep going to get as much code coverage as possible. */
+	 * point, but should not crash. */
 	if (child == 0) {
 		faillist = talloc_asprintf_append(faillist, "[%s]F", func);
 		return true;
@@ -128,8 +128,8 @@
 	exit(EXIT_SILENT);
 }
 
-void set_failtest(const char *initial_failpattern)
+void set_failtest(bool ft, const char *initial_failpattern)
 {
-	failtest_on = true;
+	failtest = ft;
 	failpattern = initial_failpattern;
 }

Modified: trunk/nfsim/core/tui.c
===================================================================
--- trunk/nfsim/core/tui.c	2004-12-16 00:04:40 UTC (rev 3393)
+++ trunk/nfsim/core/tui.c	2004-12-16 00:18:46 UTC (rev 3394)
@@ -35,9 +35,8 @@
 int tui_abort_on_fail;
 int tui_quiet;
 static int linenum = 1;
+static bool stop;
 
-static void process_line(char *line);
-
 struct command {
 	struct	list_head list;
 	char	name[TUI_MAX_CMD_LEN+1];
@@ -56,7 +55,7 @@
 
 static bool tui_exit(int argc, char **argv)
 {
-	stop();
+	stop = true;
 	return true;
 }
 
@@ -171,17 +170,6 @@
  */
 }
 
-void tui_init(void)
-{
-	rl_callback_handler_install(tui_quiet ? "" : "> ", process_line);
-
-	tui_register_command("exit", tui_exit, tui_exit_help);
-	tui_register_command("quit", tui_exit, tui_exit_help);
-	tui_register_command("q", tui_exit, tui_exit_help);
-	tui_register_command("test", tui_argtest, NULL);
-	tui_register_command("help", tui_help, tui_help_help);
-}
-
 void script_fail(const char *fmt, ...)
 {
 	char *str;
@@ -202,22 +190,16 @@
 	exit(EXIT_SCRIPTFAIL);
 }
 
-void process_line(char *line)
+static void process_line(char *line)
 {
 	int argc, prevspace;
 	char *argv[TUI_MAX_ARGS+1], quotemode;
 	struct command *cmd;
 
-	if (!line) {
-		stop();
-		return;
-	}
-
 	prevspace = 1;
 	quotemode = 0;
 	argc = 0;
 
-	add_history(line);
 	if (tui_echo_commands)
 		printf("%u:%s\n", linenum, line);
 
@@ -258,17 +240,56 @@
 	return;
 }
 
-int tui_userinput(int fd)
+static void readline_process_line(char *line)
 {
-	rl_callback_read_char();
-	return 1;
+	if (!line) {
+		stop = true;
+		return;
+	}
+
+	add_history(line);
+	process_line(line);
 }
 
-void tui_cleanup(int fd)
+static void run_whole_file(int fd)
 {
-	rl_callback_handler_remove();
+	char *file, *p;
+	unsigned long size, len;
+
+	file = grab_file(fd, &size);
+	if (!file)
+		barf_perror("Grabbing file");
+
+	for (p = file; p < file + size; p += len+1) {
+		len = strcspn(p, "\n");
+		p[len] = '\0';
+		process_line(p);
+	}
 }
 
+void tui_run(bool interactive, int fd)
+{
+	tui_register_command("exit", tui_exit, tui_exit_help);
+	tui_register_command("quit", tui_exit, tui_exit_help);
+	tui_register_command("q", tui_exit, tui_exit_help);
+	tui_register_command("test", tui_argtest, NULL);
+	tui_register_command("help", tui_help, tui_help_help);
+
+	if (interactive) {
+		stop = false;
+		rl_callback_handler_install(tui_quiet ? "" : "> ",
+					    readline_process_line);
+		while (!stop) {
+			wait_for_message(fd);
+			rl_callback_read_char();
+		}
+		rl_callback_handler_remove();
+		if (!tui_quiet)
+			printf("\n");
+	} else
+		run_whole_file(fd);
+}
+
 int tui_register_pre_post_hook(void (*pre)(const char *),
 			       void (*post)(const char *))
 {

Modified: trunk/nfsim/core/tui.h
===================================================================
--- trunk/nfsim/core/tui.h	2004-12-16 00:04:40 UTC (rev 3393)
+++ trunk/nfsim/core/tui.h	2004-12-16 00:18:46 UTC (rev 3394)
@@ -27,11 +27,6 @@
 #define TUI_MAX_CMD_LEN		1024
 #define TUI_MAX_ARGS		128
 
-void tui_init(void);
-void tui_cleanup(int fd);
-
-int tui_userinput(int fd);
-
 int tui_register_command(const char *command,
 			 bool (*handler)(int argc, char **argv),
 			 void (*helpfn)(int argc, char **argv));
@@ -39,6 +34,8 @@
 int tui_register_pre_post_hook(void (*pre)(const char *),
 			       void (*post)(const char *));
 
+void tui_run(bool interactive, int fd);
+
 /* Is this a valid command?  Sanity check for expect. */
 bool tui_is_command(const char *name);
 

Modified: trunk/nfsim/kernelenv/kernelenv.c
===================================================================
--- trunk/nfsim/kernelenv/kernelenv.c	2004-12-16 00:04:40 UTC (rev 3393)
+++ trunk/nfsim/kernelenv/kernelenv.c	2004-12-16 00:18:46 UTC (rev 3394)
@@ -21,6 +21,7 @@
 
 #include <kernelenv.h>
 #include "utils.h"
+#include "tui.h"
 
 /* Root of talloc trees for different allocators */
 void *__skb_ctx, *__vmalloc_ctx, *__kmalloc_ctx, *__kmalloc_atomic_ctx, *__kmem_cache_ctx;
@@ -361,6 +362,7 @@
 
 /* timer */
 LIST_HEAD(__timers);
+LIST_HEAD(__running_timers);
 
 void __init_timer(struct timer_list * timer, struct module *owner,
 	const char *function)
@@ -382,17 +384,44 @@
 	timer->inuse = 1;
 }
 
-int del_timer(struct timer_list *timer)
+int __del_timer(struct timer_list *timer, const char *location)
 {
 	if (!timer->inuse)
 		return 0;
 
+	if (should_i_fail_once(location)) {
+		/* Pretend it's running now. */
+		list_del(&timer->entry);
+		list_add(&timer->entry, &__running_timers);
+		return 0;
+	}
+
 	list_del(&timer->entry);
 	timer->inuse = 0;
 
 	return 1;
 }
 
+static void do_running_timers(const char *cmd)
+{
+	struct timer_list *t, *next;
+	list_for_each_entry_safe(t, next, &__running_timers, entry) {
+		t->function(t->data);
+		list_del(&t->entry);
+	}
+}
+
+void schedule(void)
+{
+	do_running_timers("schedule()");
+}
+
+static void setup_running_timers(void)
+{
+	tui_register_pre_post_hook(NULL, do_running_timers);
+}
+init_call(setup_running_timers);
+
 int timer_pending(const struct timer_list * timer)
 {
 	/* straightforward at present - timers are guaranteed to




More information about the netfilter-cvslog mailing list