From 922db9aa31d3d21cbfa631ee88b7159f34319cc2 Mon Sep 17 00:00:00 2001
From: vda <vda@69ca8d6d-28ef-0310-b511-8ec308f3f277>
Date: Mon, 26 Mar 2007 13:20:04 +0000
Subject: libbb: rework NOMMU helper API so that it makes more sense and easier
 to use. Doesn't compile - need two more commits.

git-svn-id: svn://busybox.net/trunk/busybox@18241 69ca8d6d-28ef-0310-b511-8ec308f3f277
---
 libbb/vfork_daemon_rexec.c | 134 ++++++++++++++++++++++++++++++++++++++++++++-
 libbb/xfuncs.c             |  78 --------------------------
 2 files changed, 133 insertions(+), 79 deletions(-)

(limited to 'libbb')

diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c
index 3185f2d39..c59b0b6fd 100644
--- a/libbb/vfork_daemon_rexec.c
+++ b/libbb/vfork_daemon_rexec.c
@@ -18,11 +18,68 @@
 #include <paths.h>
 #include "libbb.h"
 
-#ifdef BB_NOMMU
+/* This does a fork/exec in one call, using vfork().  Returns PID of new child,
+ * -1 for failure.  Runs argv[0], searching path if that has no / in it. */
+pid_t spawn(char **argv)
+{
+	/* Compiler should not optimize stores here */
+	volatile int failed;
+	pid_t pid;
+
+	// Be nice to nommu machines.
+	failed = 0;
+	pid = vfork();
+	if (pid < 0) /* error */
+		return pid;
+	if (!pid) { /* child */
+		/* Don't use BB_EXECVP tricks here! */
+		execvp(argv[0], argv);
+
+		/* We are (maybe) sharing a stack with blocked parent,
+		 * let parent know we failed and then exit to unblock parent
+		 * (but don't run atexit() stuff, which would screw up parent.)
+		 */
+		failed = errno;
+		_exit(0);
+	}
+	/* parent */
+	/* Unfortunately, this is not reliable: vfork()
+	 * can be equivalent to fork() according to standards */
+	if (failed) {
+		errno = failed;
+		return -1;
+	}
+	return pid;
+}
+
+/* Die with an error message if we can't spawn a child process. */
+pid_t xspawn(char **argv)
+{
+	pid_t pid = spawn(argv);
+	if (pid < 0) bb_perror_msg_and_die("%s", *argv);
+	return pid;
+}
+
+
+
+#if 0 //ndef BB_NOMMU
+// Die with an error message if we can't daemonize.
+void xdaemon(int nochdir, int noclose)
+{
+	if (daemon(nochdir, noclose))
+		bb_perror_msg_and_die("daemon");
+}
+#endif
+
+#if 0 // def BB_NOMMU
 void vfork_daemon_rexec(int nochdir, int noclose, char **argv)
 {
 	int fd;
 
+	/* Maybe we are already re-execed and come here again? */
+	if (re_execed)
+		return;
+
 	setsid();
 
 	if (!nochdir)
@@ -56,3 +113,78 @@ void vfork_daemon_rexec(int nochdir, int noclose, char **argv)
 	}
 }
 #endif /* BB_NOMMU */
+
+#ifdef BB_NOMMU
+static void daemon_or_rexec(char **argv)
+{
+	pid_t pid;
+	/* Maybe we are already re-execed and come here again? */
+	if (re_execed)
+		return;
+
+	pid = vfork();
+	if (pid < 0) /* wtf? */
+		bb_perror_msg_and_die("vfork");
+	if (pid) /* parent */
+		exit(0);
+	/* child - re-exec ourself */
+	/* high-order bit of first char in argv[0] is a hidden
+	 * "we have (alrealy) re-execed, don't do it again" flag */
+	argv[0][0] |= 0x80;
+	execv(CONFIG_BUSYBOX_EXEC_PATH, argv);
+	bb_perror_msg_and_die("exec %s", CONFIG_BUSYBOX_EXEC_PATH);
+}
+#else
+static void daemon_or_rexec(void)
+{
+	pid_t pid;
+	pid = fork();
+	if (pid < 0) /* wtf? */
+		bb_perror_msg_and_die("fork");
+	if (pid) /* parent */
+		exit(0);
+	/* child */
+}
+#define daemon_or_rexec(argv) daemon_or_rexec()
+#endif
+
+
+/* Due to a #define in libbb.h on MMU systems we actually have 1 argument -
+ * char **argv "vanishes" */
+void bb_daemonize_or_rexec(int flags, char **argv)
+{
+	int fd;
+
+	fd = xopen(bb_dev_null, O_RDWR);
+
+	if (flags & DAEMON_CHDIR_ROOT)
+		xchdir("/");
+
+	if (flags & DAEMON_DEVNULL_STDIO) {
+		close(0);
+		close(1);
+		close(2);
+	}
+
+	while ((unsigned)fd < 2)
+		fd = dup(fd); /* have 0,1,2 open at least to /dev/null */
+
+	if (!(flags & DAEMON_ONLY_SANITIZE)) {
+		daemon_or_rexec(argv);
+		/* if daemonizing, make sure we detach from stdio */
+		setsid();
+		dup2(fd, 0);
+		dup2(fd, 1);
+		dup2(fd, 2);
+	}
+	if (fd > 2)
+		close(fd--);
+	if (flags & DAEMON_CLOSE_EXTRA_FDS)
+		while (fd > 2)
+			close(fd--); /* close everything after fd#2 */
+}
+
+void bb_sanitize_stdio(void)
+{
+	bb_daemonize_or_rexec(DAEMON_ONLY_SANITIZE, NULL);
+}
diff --git a/libbb/xfuncs.c b/libbb/xfuncs.c
index 1dcdbc065..14bd62a15 100644
--- a/libbb/xfuncs.c
+++ b/libbb/xfuncs.c
@@ -187,43 +187,6 @@ void xfflush_stdout(void)
 	}
 }
 
-// This does a fork/exec in one call, using vfork().  Return PID of new child,
-// -1 for failure.  Runs argv[0], searching path if that has no / in it.
-pid_t spawn(char **argv)
-{
-	/* Why static? */
-	static int failed;
-	pid_t pid;
-
-	// Be nice to nommu machines.
-	failed = 0;
-	pid = vfork();
-	if (pid < 0) return pid;
-	if (!pid) {
-		BB_EXECVP(argv[0], argv);
-
-		// We're sharing a stack with blocked parent, let parent know we failed
-		// and then exit to unblock parent (but don't run atexit() stuff, which
-		// would screw up parent.)
-
-		failed = errno;
-		_exit(0);
-	}
-	if (failed) {
-		errno = failed;
-		return -1;
-	}
-	return pid;
-}
-
-// Die with an error message if we can't spawn a child process.
-pid_t xspawn(char **argv)
-{
-	pid_t pid = spawn(argv);
-	if (pid < 0) bb_perror_msg_and_die("%s", *argv);
-	return pid;
-}
-
 // Wait for the specified child PID to exit, returning child's error return.
 int wait4pid(int pid)
 {
@@ -510,47 +473,6 @@ DIR *xopendir(const char *path)
 	return dp;
 }
 
-#ifndef BB_NOMMU
-// Die with an error message if we can't daemonize.
-void xdaemon(int nochdir, int noclose)
-{
-	if (daemon(nochdir, noclose))
-		bb_perror_msg_and_die("daemon");
-}
-#endif
-
-void bb_sanitize_stdio_maybe_daemonize(int daemonize)
-{
-	int fd;
-	/* Mega-paranoid */
-	fd = xopen(bb_dev_null, O_RDWR);
-	while ((unsigned)fd < 2)
-		fd = dup(fd); /* have 0,1,2 open at least to /dev/null */
-	if (daemonize) {
-		pid_t pid = fork();
-		if (pid < 0) /* wtf? */
-			bb_perror_msg_and_die("fork");
-		if (pid) /* parent */
-			exit(0);
-		/* child */
-		/* if daemonizing, make sure we detach from stdio */
-		setsid();
-		dup2(fd, 0);
-		dup2(fd, 1);
-		dup2(fd, 2);
-	}
-	while (fd > 2)
-		close(fd--); /* close everything after fd#2 */
-}
-void bb_sanitize_stdio(void)
-{
-	bb_sanitize_stdio_maybe_daemonize(0);
-}
-void bb_daemonize(void)
-{
-	bb_sanitize_stdio_maybe_daemonize(1);
-}
-
 // Die with an error message if we can't open a new socket.
 int xsocket(int domain, int type, int protocol)
 {
-- 
cgit v1.2.3-55-g6feb