From bb7fcb4229fd5ff583039f26ca1c06340e3f09ea Mon Sep 17 00:00:00 2001 From: Denis Vlasenko 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. --- libbb/vfork_daemon_rexec.c | 134 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 133 insertions(+), 1 deletion(-) (limited to 'libbb/vfork_daemon_rexec.c') 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 #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); +} -- cgit v1.2.3