From fe8d1db385d1de65c0f28db4c0ee7a430b0b959f Mon Sep 17 00:00:00 2001
From: vda <vda@69ca8d6d-28ef-0310-b511-8ec308f3f277>
Date: Mon, 26 Mar 2007 17:25:33 +0000
Subject: zcip: make it work on NOMMU (+ improve NOMMU support machinery) fsck:
 fix bad English in a comment

git-svn-id: svn://busybox.net/trunk/busybox@18248 69ca8d6d-28ef-0310-b511-8ec308f3f277
---
 TODO_config_nommu          |   6 +-
 e2fsprogs/fsck.c           |   7 +--
 include/libbb.h            |   7 +++
 libbb/vfork_daemon_rexec.c |   9 ++-
 libbb/xfuncs.c             |  13 +++-
 networking/zcip.c          | 146 ++++++++++++++++++++++-----------------------
 6 files changed, 100 insertions(+), 88 deletions(-)

diff --git a/TODO_config_nommu b/TODO_config_nommu
index 74095aa9a..695ac1114 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_RESET=y
 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_WGET=y
 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 447b4d008..b70fd7088 100644
--- a/e2fsprogs/fsck.c
+++ b/e2fsprogs/fsck.c
@@ -509,12 +509,7 @@ static struct fsck_instance *wait_one(int flags)
 		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 32e099b54..67fd2af21 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -263,6 +263,13 @@ char *xrealloc_getcwd_or_warn(char *cwd);
 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 89ae9a73c..ec8b9b1d7 100644
--- a/libbb/vfork_daemon_rexec.c
+++ b/libbb/vfork_daemon_rexec.c
@@ -40,11 +40,14 @@ pid_t spawn(char **argv)
 		 * (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 14bd62a15..7f870ac8b 100644
--- a/libbb/xfuncs.c
+++ b/libbb/xfuncs.c
@@ -192,9 +192,16 @@ int wait4pid(int pid)
 {
 	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 c0cf665dd..6035b91e1 100644
--- a/networking/zcip.c
+++ b/networking/zcip.c
@@ -70,10 +70,6 @@ enum {
 #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 @@ static void arp(int fd, struct sockaddr *saddr, int op,
 }
 
 /**
- * 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 (ip) {
+		char *addr = inet_ntoa(*ip);
+		setenv("ip", addr, 1);
+		bb_info_msg("%s %s %s", argv[1], intf, addr);
+	}
 
-		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;
-		}
+	status = wait4pid(spawn(argv));
+	if (status < 0) {
+		bb_perror_msg("%s %s", argv[1], intf);
+		return -errno;
 	}
-	return 0;
-bad:
-	status = -errno;
-	bb_perror_msg("%s %s, %s", arg, intf, why);
+	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 @@ static unsigned ATTRIBUTE_ALWAYS_INLINE ms_rdelay(unsigned secs)
 /**
  * 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;
+	char *r_opt;
+	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
-	char *r_opt;
-	opt_complementary = "vv:vf"; // -v accumulates and implies -f
+	// 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 @@ int zcip_main(int argc, char *argv[])
 			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 @@ int zcip_main(int argc, char *argv[])
 
 	// 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 @@ int zcip_main(int argc, char *argv[])
 					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 @@ int zcip_main(int argc, char *argv[])
 					// 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 @@ int zcip_main(int argc, char *argv[])
 					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 @@ int zcip_main(int argc, char *argv[])
 			goto bad;
 		} // switch poll
 	}
-bad:
+ bad:
 	bb_perror_msg("%s, %s", intf, why);
 	return EXIT_FAILURE;
 }
-- 
cgit v1.2.3-55-g6feb