zcip: make it work on NOMMU (+ improve NOMMU support machinery)
fsck: fix bad English in a comment
diff --git a/TODO_config_nommu b/TODO_config_nommu
index 74095aa..695ac11 100644
--- a/TODO_config_nommu
+++ b/TODO_config_nommu
@@ -5,7 +5,7 @@
 #
 # Automatically generated make config: don't edit
 # Busybox version: 1.6.0.svn
-# Mon Mar 26 15:00:56 2007
+# Mon Mar 26 18:36:12 2007
 #
 CONFIG_HAVE_DOT_CONFIG=y
 
@@ -266,7 +266,7 @@
 CONFIG_RESIZE=y
 CONFIG_FEATURE_RESIZE_PRINT=y
 CONFIG_SETCONSOLE=y
-# CONFIG_FEATURE_SETCONSOLE_LONG_OPTIONS is not set
+CONFIG_FEATURE_SETCONSOLE_LONG_OPTIONS=y
 CONFIG_SETKEYCODES=y
 CONFIG_SETLOGCONS=y
 
@@ -605,7 +605,7 @@
 CONFIG_FEATURE_WGET_STATUSBAR=y
 CONFIG_FEATURE_WGET_AUTHENTICATION=y
 CONFIG_FEATURE_WGET_LONG_OPTIONS=y
-# CONFIG_ZCIP is not set
+CONFIG_ZCIP=y
 
 #
 # Process Utilities
diff --git a/e2fsprogs/fsck.c b/e2fsprogs/fsck.c
index 447b4d0..b70fd70 100644
--- a/e2fsprogs/fsck.c
+++ b/e2fsprogs/fsck.c
@@ -509,12 +509,7 @@
 		goto ret_inst;
 	}
 
-	/*
-	 * gcc -Wall fails saving throw against stupidity
-	 * (inst and prev are thought to be uninitialized variables)
-	 */
-	inst = prev = NULL;
-
+	inst = prev = NULL; /* for gcc */
 	do {
 		pid = waitpid(-1, &status, flags);
 		kill_all_if_cancel_requested();
diff --git a/include/libbb.h b/include/libbb.h
index 32e099b..67fd2af 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -263,6 +263,13 @@
 char *xmalloc_readlink_or_warn(const char *path);
 char *xmalloc_realpath(const char *path);
 extern void xstat(const char *filename, struct stat *buf);
+/* Unlike waitpid, waits ONLY for one process,
+ * It's safe to pass negative 'pids' from failed [v]fork -
+ * wait4pid will return -1 and ECHILD in errno.
+ * IOW: rc = wait4pid(spawn(argv));
+ *      if (rc < 0) bb_perror_msg("%s", argv[0]);
+ *      if (rc > 0) bb_error_msg("exit code: %d", rc);
+ */
 extern int wait4pid(int pid);
 extern void xsetgid(gid_t gid);
 extern void xsetuid(uid_t uid);
diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c
index 89ae9a7..ec8b9b1 100644
--- a/libbb/vfork_daemon_rexec.c
+++ b/libbb/vfork_daemon_rexec.c
@@ -40,11 +40,14 @@
 		 * (but don't run atexit() stuff, which would screw up parent.)
 		 */
 		failed = errno;
-		_exit(0);
+		_exit(111);
 	}
 	/* parent */
-	/* Unfortunately, this is not reliable: vfork()
-	 * can be equivalent to fork() according to standards */
+	/* Unfortunately, this is not reliable: according to standards
+	 * vfork() can be equivalent to fork() and we won't see value
+	 * of 'failed'.
+	 * Interested party can wait on pid and learn exit code.
+	 * If 111 - then it (most probably) failed to exec */
 	if (failed) {
 		errno = failed;
 		return -1;
diff --git a/libbb/xfuncs.c b/libbb/xfuncs.c
index 14bd62a..7f870ac 100644
--- a/libbb/xfuncs.c
+++ b/libbb/xfuncs.c
@@ -192,9 +192,16 @@
 {
 	int status;
 
-	if (pid == -1 || waitpid(pid, &status, 0) == -1) return -1;
-	if (WIFEXITED(status)) return WEXITSTATUS(status);
-	if (WIFSIGNALED(status)) return WTERMSIG(status);
+	if (pid <= 0) {
+		errno = ECHILD;
+		return -1;
+	}
+	if (waitpid(pid, &status, 0) == -1)
+		return -1;
+	if (WIFEXITED(status))
+		return WEXITSTATUS(status);
+	if (WIFSIGNALED(status))
+		return WTERMSIG(status) + 10000;
 	return 0;
 }
 
diff --git a/networking/zcip.c b/networking/zcip.c
index c0cf665..6035b91 100644
--- a/networking/zcip.c
+++ b/networking/zcip.c
@@ -70,10 +70,6 @@
 #define VDBG(fmt,args...) \
 	do { } while (0)
 
-static unsigned opts;
-#define FOREGROUND (opts & 1)
-#define QUIT (opts & 2)
-
 /**
  * Pick a random link local IP address on 169.254/16, except that
  * the first and last 256 addresses are reserved.
@@ -128,49 +124,30 @@
 }
 
 /**
- * Run a script.
+ * Run a script. argv[2] is already NULL.
  */
-static int run(const char *script, const char *arg, const char *intf, struct in_addr *ip)
+static int run(char *argv[3], const char *intf, struct in_addr *ip)
 {
-	int pid, status;
-	const char *why;
+	int status;
 
-	if(1) { //always true: if (script != NULL)
-		VDBG("%s run %s %s\n", intf, script, arg);
-		if (ip != NULL) {
-			char *addr = inet_ntoa(*ip);
-			setenv("ip", addr, 1);
-			bb_info_msg("%s %s %s", arg, intf, addr);
-		}
+	VDBG("%s run %s %s\n", intf, argv[0], argv[1]);
 
-		pid = vfork();
-		if (pid < 0) {			// error
-			why = "vfork";
-			goto bad;
-		} else if (pid == 0) {		// child
-			execl(script, script, arg, NULL);
-			bb_perror_msg("execl");
-			_exit(EXIT_FAILURE);
-		}
-
-		if (waitpid(pid, &status, 0) <= 0) {
-			why = "waitpid";
-			goto bad;
-		}
-		if (WEXITSTATUS(status) != 0) {
-			bb_error_msg("script %s failed, exit=%d",
-				script, WEXITSTATUS(status));
-			return -errno;
-		}
+	if (ip) {
+		char *addr = inet_ntoa(*ip);
+		setenv("ip", addr, 1);
+		bb_info_msg("%s %s %s", argv[1], intf, addr);
 	}
-	return 0;
-bad:
-	status = -errno;
-	bb_perror_msg("%s %s, %s", arg, intf, why);
+
+	status = wait4pid(spawn(argv));
+	if (status < 0) {
+		bb_perror_msg("%s %s", argv[1], intf);
+		return -errno;
+	}
+	if (status != 0)
+		bb_error_msg("script %s %s failed, exitcode=%d", argv[0], argv[1], status);
 	return status;
 }
 
-
 /**
  * Return milliseconds of random delay, up to "secs" seconds.
  */
@@ -182,43 +159,58 @@
 /**
  * main program
  */
-
-/* Used to be auto variables on main() stack, but
- * most of them were zero-inited. Moving them to bss
- * is more space-efficient.
- */
-static	const struct in_addr null_ip; // = { 0 };
-static	const struct ether_addr null_addr; // = { {0, 0, 0, 0, 0, 0} };
-
-static	struct sockaddr saddr; // memset(0);
-static	struct in_addr ip; // = { 0 };
-static	struct ifreq ifr; //memset(0);
-
-static	char *intf; // = NULL;
-static	char *script; // = NULL;
-static	suseconds_t timeout; // = 0;	// milliseconds
-static	unsigned conflicts; // = 0;
-static	unsigned nprobes; // = 0;
-static	unsigned nclaims; // = 0;
-static	int ready; // = 0;
-static	int verbose; // = 0;
-static	int state = PROBE;
-
 int zcip_main(int argc, char *argv[]);
 int zcip_main(int argc, char *argv[])
 {
+	int state = PROBE;
 	struct ether_addr eth_addr;
 	const char *why;
 	int fd;
-
-	// parse commandline: prog [options] ifname script
 	char *r_opt;
-	opt_complementary = "vv:vf"; // -v accumulates and implies -f
+	unsigned opts;
+
+	/* Ugly trick, but I want these zeroed in one go */
+	struct {
+		const struct in_addr null_ip;
+		const struct ether_addr null_addr;
+		struct sockaddr saddr;
+		struct in_addr ip;
+		struct ifreq ifr;
+		char *intf;
+		char *script_av[3];
+		suseconds_t timeout; // milliseconds
+		unsigned conflicts;
+		unsigned nprobes;
+		unsigned nclaims;
+		int ready;
+		int verbose;
+	} L;
+#define null_ip   (L.null_ip  )
+#define null_addr (L.null_addr)
+#define saddr     (L.saddr    )
+#define ip        (L.ip       )
+#define ifr       (L.ifr      )
+#define intf      (L.intf     )
+#define script_av (L.script_av)
+#define timeout   (L.timeout  )
+#define conflicts (L.conflicts)
+#define nprobes   (L.nprobes  )
+#define nclaims   (L.nclaims  )
+#define ready     (L.ready    )
+#define verbose   (L.verbose  )
+
+	memset(&L, 0, sizeof(L));
+
+#define FOREGROUND (opts & 1)
+#define QUIT       (opts & 2)
+	// parse commandline: prog [options] ifname script
+	// exactly 2 args; -v accumulates and implies -f
+	opt_complementary = "=2:vv:vf";
 	opts = getopt32(argc, argv, "fqr:v", &r_opt, &verbose);
 	if (!FOREGROUND) {
 		/* Do it early, before all bb_xx_msg calls */
-		logmode = LOGMODE_SYSLOG;
 		openlog(applet_name, 0, LOG_DAEMON);
+		logmode |= LOGMODE_SYSLOG;
 	}
 	if (opts & 4) { // -r n.n.n.n
 		if (inet_aton(r_opt, &ip) == 0
@@ -227,16 +219,21 @@
 			bb_error_msg_and_die("invalid link address");
 		}
 	}
+	// On NOMMU reexec early (or else we will rerun things twice)
+#ifdef BB_NOMMU
+	if (!FOREGROUND)
+		bb_daemonize_or_rexec(DAEMON_CHDIR_ROOT, argv);
+#endif
 	argc -= optind;
 	argv += optind;
-	if (argc != 2)
-		bb_show_usage();
+
 	intf = argv[0];
-	script = argv[1];
+	script_av[0] = argv[1];
 	setenv("interface", intf, 1);
 
 	// initialize the interface (modprobe, ifup, etc)
-	if (run(script, "init", intf, NULL) < 0)
+	script_av[1] = (char*)"init";
+	if (run(script_av, intf, NULL))
 		return EXIT_FAILURE;
 
 	// initialize saddr
@@ -271,8 +268,9 @@
 
 	// daemonize now; don't delay system startup
 	if (!FOREGROUND) {
-//NOMMU
+#ifndef BB_NOMMU
 		bb_daemonize(DAEMON_CHDIR_ROOT);
+#endif
 		bb_info_msg("start, interface %s", intf);
 	}
 
@@ -375,7 +373,8 @@
 					state = MONITOR;
 					// link is ok to use earlier
 					// FIXME update filters
-					run(script, "config", intf, &ip);
+					script_av[1] = (char*)"config";
+					run(script_av, intf, &ip);
 					ready = 1;
 					conflicts = 0;
 					timeout = -1; // Never timeout in the monitor state.
@@ -429,8 +428,8 @@
 					// this shouldn't necessarily exit.
 					bb_error_msg("%s: poll error", intf);
 					if (ready) {
-						run(script, "deconfig",
-								intf, &ip);
+						script_av[1] = (char*)"deconfig";
+						run(script_av, intf, &ip);
 					}
 					return EXIT_FAILURE;
 				}
@@ -516,7 +515,8 @@
 					state = PROBE;
 					VDBG("defend conflict -- starting over\n");
 					ready = 0;
-					run(script, "deconfig", intf, &ip);
+					script_av[1] = (char*)"deconfig";
+					run(script_av, intf, &ip);
 
 					// restart the whole protocol
 					pick(&ip);
@@ -542,7 +542,7 @@
 			goto bad;
 		} // switch poll
 	}
-bad:
+ bad:
 	bb_perror_msg("%s, %s", intf, why);
 	return EXIT_FAILURE;
 }