summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2007-08-18 14:20:21 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2007-08-18 14:20:21 +0000
commit367960ba9abd66865c810a4d9411741fd25a3854 (patch)
treed11c311339298c2e0bf9c09d23cdcce6a73c6a42
parent9611cb1215fa52200ca5259e3b226df34d0a8045 (diff)
make standalone httpd work on NOMMU machines
-rw-r--r--include/libbb.h2
-rw-r--r--libbb/vfork_daemon_rexec.c15
-rw-r--r--networking/httpd.c140
3 files changed, 103 insertions, 54 deletions
diff --git a/include/libbb.h b/include/libbb.h
index 651c48ba1..2519aeb98 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -587,10 +587,12 @@ enum {
};
#if BB_MMU
void forkexit_or_rexec(void);
+ enum { re_execed = 0 };
# define forkexit_or_rexec(argv) forkexit_or_rexec()
# define bb_daemonize_or_rexec(flags, argv) bb_daemonize_or_rexec(flags)
# define bb_daemonize(flags) bb_daemonize_or_rexec(flags, bogus)
#else
+ void re_exec(char **argv) ATTRIBUTE_NORETURN;
void forkexit_or_rexec(char **argv);
extern bool re_execed;
# define fork() BUG_fork_is_unavailable_on_nommu()
diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c
index f7c620996..558510bc6 100644
--- a/libbb/vfork_daemon_rexec.c
+++ b/libbb/vfork_daemon_rexec.c
@@ -203,6 +203,15 @@ int spawn_and_wait(char **argv)
}
#if !BB_MMU
+void re_exec(char **argv)
+{
+ /* high-order bit of first char in argv[0] is a hidden
+ * "we have (already) re-execed, don't do it again" flag */
+ argv[0][0] |= 0x80;
+ execv(bb_busybox_exec_path, argv);
+ bb_perror_msg_and_die("exec %s", bb_busybox_exec_path);
+}
+
void forkexit_or_rexec(char **argv)
{
pid_t pid;
@@ -216,11 +225,7 @@ void forkexit_or_rexec(char **argv)
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(bb_busybox_exec_path, argv);
- bb_perror_msg_and_die("exec %s", bb_busybox_exec_path);
+ re_exec(argv);
}
#else
/* Dance around (void)...*/
diff --git a/networking/httpd.c b/networking/httpd.c
index d68dc06e9..cd46f49ef 100644
--- a/networking/httpd.c
+++ b/networking/httpd.c
@@ -764,7 +764,6 @@ static void decodeBase64(char *Data)
/*
* Create a listen server socket on the designated port.
*/
-#if BB_MMU
static int openServer(void)
{
int n = bb_strtou(bind_addr_or_port, NULL, 10);
@@ -775,7 +774,6 @@ static int openServer(void)
xlisten(n, 9);
return n;
}
-#endif
/*
* Log the connection closure and exit.
@@ -1474,8 +1472,8 @@ static void exit_on_signal(int sig)
/*
* Handle an incoming http request and exit.
*/
-static void handle_incoming_and_exit(void) ATTRIBUTE_NORETURN;
-static void handle_incoming_and_exit(void)
+static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) ATTRIBUTE_NORETURN;
+static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
{
static const char request_GET[] ALIGN1 = "GET";
@@ -1497,6 +1495,22 @@ static void handle_incoming_and_exit(void)
int credentials = -1; /* if not required this is Ok */
#endif
+ rmt_port = get_nport(&fromAddr->sa);
+ rmt_port = ntohs(rmt_port);
+ rmt_ip = 0;
+ if (fromAddr->sa.sa_family == AF_INET) {
+ rmt_ip = ntohl(fromAddr->sin.sin_addr.s_addr);
+ }
+ if (ENABLE_FEATURE_HTTPD_CGI || DEBUG || verbose) {
+ rmt_ip_str = xmalloc_sockaddr2dotted(&fromAddr->sa);
+ }
+ if (verbose) {
+ /* this trick makes -v logging much simpler */
+ applet_name = rmt_ip_str;
+ if (verbose > 2)
+ bb_error_msg("connected");
+ }
+
/* Install timeout handler */
memset(&sa, 0, sizeof(sa));
sa.sa_handler = exit_on_signal;
@@ -1772,13 +1786,13 @@ static void handle_incoming_and_exit(void)
#endif
}
-#if BB_MMU
/*
* The main http server function.
- * Given an open socket, listen for new connections and farm out
- * the processing as a forked process.
+ * Given a socket, listen for new connections and farm out
+ * the processing as a [v]forked process.
* Never returns.
*/
+#if BB_MMU
static void mini_httpd(int server_socket) ATTRIBUTE_NORETURN;
static void mini_httpd(int server_socket)
{
@@ -1810,22 +1824,53 @@ static void mini_httpd(int server_socket)
xmove_fd(n, 0);
xdup2(0, 1);
- n = get_nport(&fromAddr.sa);
- rmt_port = ntohs(n);
- rmt_ip = 0;
- if (fromAddr.sa.sa_family == AF_INET) {
- rmt_ip = ntohl(fromAddr.sin.sin_addr.s_addr);
- }
- if (ENABLE_FEATURE_HTTPD_CGI || DEBUG || verbose) {
- rmt_ip_str = xmalloc_sockaddr2dotted(&fromAddr.sa);
- }
- if (verbose) {
- /* this trick makes -v logging much simpler */
- applet_name = rmt_ip_str;
- if (verbose > 2)
- bb_error_msg("connected");
- }
- handle_incoming_and_exit();
+ handle_incoming_and_exit(&fromAddr);
+ }
+ /* parent, or fork failed */
+ close(n);
+ } /* while (1) */
+ /* never reached */
+}
+#else
+static void mini_httpd_nommu(int server_socket, int argc, char **argv) ATTRIBUTE_NORETURN;
+static void mini_httpd_nommu(int server_socket, int argc, char **argv)
+{
+ char *argv_copy[argc + 2];
+
+ argv_copy[0] = argv[0];
+ argv_copy[1] = (char*)"-i";
+ memcpy(&argv_copy[2], &argv[1], argc * sizeof(argv[0]));
+
+ /* NB: it's best to not use xfuncs in this loop before vfork().
+ * Otherwise server may die on transient errors (temporary
+ * out-of-memory condition, etc), which is Bad(tm).
+ * Try to do any dangerous calls after fork.
+ */
+ while (1) {
+ int n;
+ len_and_sockaddr fromAddr;
+
+ /* Wait for connections... */
+ fromAddr.len = LSA_SIZEOF_SA;
+ n = accept(server_socket, &fromAddr.sa, &fromAddr.len);
+
+ if (n < 0)
+ continue;
+ /* set the KEEPALIVE option to cull dead connections */
+ setsockopt(n, SOL_SOCKET, SO_KEEPALIVE, &const_int_1, sizeof(const_int_1));
+
+ if (vfork() == 0) {
+ /* child */
+#if ENABLE_FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP
+ /* Do not reload config on HUP */
+ signal(SIGHUP, SIG_IGN);
+#endif
+ close(server_socket);
+ xmove_fd(n, 0);
+ xdup2(0, 1);
+
+ /* Run a copy of ourself in inetd mode */
+ re_exec(argv_copy);
}
/* parent, or fork failed */
close(n);
@@ -1834,25 +1879,18 @@ static void mini_httpd(int server_socket)
}
#endif
-/* from inetd */
+/*
+ * Process a HTTP connection on stdin/out.
+ * Never returns.
+ */
static void mini_httpd_inetd(void) ATTRIBUTE_NORETURN;
static void mini_httpd_inetd(void)
{
- int n;
len_and_sockaddr fromAddr;
fromAddr.len = LSA_SIZEOF_SA;
getpeername(0, &fromAddr.sa, &fromAddr.len);
- n = get_nport(&fromAddr.sa);
- rmt_port = ntohs(n);
- rmt_ip = 0;
- if (fromAddr.sa.sa_family == AF_INET) {
- rmt_ip = ntohl(fromAddr.sin.sin_addr.s_addr);
- }
- if (ENABLE_FEATURE_HTTPD_CGI || DEBUG || verbose) {
- rmt_ip_str = xmalloc_sockaddr2dotted(&fromAddr.sa);
- }
- handle_incoming_and_exit();
+ handle_incoming_and_exit(&fromAddr);
}
#if ENABLE_FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP
@@ -1915,7 +1953,8 @@ int httpd_main(int argc, char **argv)
#endif
home_httpd = xrealloc_getcwd_or_warn(NULL);
- opt_complementary = "vv"; /* counter */
+ /* -v counts, -i implies -f */
+ opt_complementary = "vv:if";
/* We do not "absolutize" path given by -h (home) opt.
* If user gives relative path in -h, $SCRIPT_FILENAME can end up
* relative too. */
@@ -1934,12 +1973,12 @@ int httpd_main(int argc, char **argv)
, &verbose
);
if (opt & OPT_DECODE_URL) {
- printf("%s", decodeString(url_for_decode, 1));
+ fputs(decodeString(url_for_decode, 1), stdout);
return 0;
}
#if ENABLE_FEATURE_HTTPD_ENCODE_URL_STR
if (opt & OPT_ENCODE_URL) {
- printf("%s", encodeString(url_for_encode));
+ fputs(encodeString(url_for_encode), stdout);
return 0;
}
#endif
@@ -1957,9 +1996,14 @@ int httpd_main(int argc, char **argv)
}
#endif
+#if !BB_MMU
+ if (!(opt & OPT_FOREGROUND)) {
+ bb_daemonize_or_rexec(0, argv); /* don't change current directory */
+ }
+#endif
+
xchdir(home_httpd);
if (!(opt & OPT_INETD)) {
-#if BB_MMU
signal(SIGCHLD, SIG_IGN);
server_socket = openServer();
#if ENABLE_FEATURE_HTTPD_SETUID
@@ -1973,9 +2017,6 @@ int httpd_main(int argc, char **argv)
xsetuid(ugid.uid);
}
#endif
-#else /* BB_MMU */
- bb_error_msg_and_die("-i is required");
-#endif
}
#if ENABLE_FEATURE_HTTPD_CGI
@@ -1990,21 +2031,22 @@ int httpd_main(int argc, char **argv)
}
#endif
-#if BB_MMU
#if ENABLE_FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP
- sighup_handler(0);
-#else
- parse_conf(default_path_httpd_conf, FIRST_PARSE);
+ if (!(opt & OPT_INETD))
+ sighup_handler(0);
+ else /* do not install HUP handler in inetd mode */
#endif
+ parse_conf(default_path_httpd_conf, FIRST_PARSE);
+
xfunc_error_retval = 0;
if (opt & OPT_INETD)
mini_httpd_inetd();
+#if BB_MMU
if (!(opt & OPT_FOREGROUND))
bb_daemonize(0); /* don't change current directory */
mini_httpd(server_socket); /* never returns */
#else
- xfunc_error_retval = 0;
- mini_httpd_inetd(); /* never returns */
- /* return 0; */
+ mini_httpd_nommu(server_socket, argc, argv); /* never returns */
#endif
+ /* return 0; */
}