make standalone httpd work on NOMMU machines

This commit is contained in:
Denis Vlasenko 2007-08-18 14:20:21 +00:00
parent 9611cb1215
commit 367960ba9a
3 changed files with 103 additions and 54 deletions

View File

@ -587,10 +587,12 @@ enum {
}; };
#if BB_MMU #if BB_MMU
void forkexit_or_rexec(void); void forkexit_or_rexec(void);
enum { re_execed = 0 };
# define forkexit_or_rexec(argv) forkexit_or_rexec() # define forkexit_or_rexec(argv) forkexit_or_rexec()
# define bb_daemonize_or_rexec(flags, argv) bb_daemonize_or_rexec(flags) # define bb_daemonize_or_rexec(flags, argv) bb_daemonize_or_rexec(flags)
# define bb_daemonize(flags) bb_daemonize_or_rexec(flags, bogus) # define bb_daemonize(flags) bb_daemonize_or_rexec(flags, bogus)
#else #else
void re_exec(char **argv) ATTRIBUTE_NORETURN;
void forkexit_or_rexec(char **argv); void forkexit_or_rexec(char **argv);
extern bool re_execed; extern bool re_execed;
# define fork() BUG_fork_is_unavailable_on_nommu() # define fork() BUG_fork_is_unavailable_on_nommu()

View File

@ -203,6 +203,15 @@ int spawn_and_wait(char **argv)
} }
#if !BB_MMU #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) void forkexit_or_rexec(char **argv)
{ {
pid_t pid; pid_t pid;
@ -216,11 +225,7 @@ void forkexit_or_rexec(char **argv)
if (pid) /* parent */ if (pid) /* parent */
exit(0); exit(0);
/* child - re-exec ourself */ /* child - re-exec ourself */
/* high-order bit of first char in argv[0] is a hidden re_exec(argv);
* "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);
} }
#else #else
/* Dance around (void)...*/ /* Dance around (void)...*/

View File

@ -764,7 +764,6 @@ static void decodeBase64(char *Data)
/* /*
* Create a listen server socket on the designated port. * Create a listen server socket on the designated port.
*/ */
#if BB_MMU
static int openServer(void) static int openServer(void)
{ {
int n = bb_strtou(bind_addr_or_port, NULL, 10); int n = bb_strtou(bind_addr_or_port, NULL, 10);
@ -775,7 +774,6 @@ static int openServer(void)
xlisten(n, 9); xlisten(n, 9);
return n; return n;
} }
#endif
/* /*
* Log the connection closure and exit. * Log the connection closure and exit.
@ -1474,8 +1472,8 @@ static void exit_on_signal(int sig)
/* /*
* Handle an incoming http request and exit. * Handle an incoming http request and exit.
*/ */
static void handle_incoming_and_exit(void) ATTRIBUTE_NORETURN; static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) ATTRIBUTE_NORETURN;
static void handle_incoming_and_exit(void) static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
{ {
static const char request_GET[] ALIGN1 = "GET"; 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 */ int credentials = -1; /* if not required this is Ok */
#endif #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 */ /* Install timeout handler */
memset(&sa, 0, sizeof(sa)); memset(&sa, 0, sizeof(sa));
sa.sa_handler = exit_on_signal; sa.sa_handler = exit_on_signal;
@ -1772,13 +1786,13 @@ static void handle_incoming_and_exit(void)
#endif #endif
} }
#if BB_MMU
/* /*
* The main http server function. * The main http server function.
* Given an open socket, listen for new connections and farm out * Given a socket, listen for new connections and farm out
* the processing as a forked process. * the processing as a [v]forked process.
* Never returns. * Never returns.
*/ */
#if BB_MMU
static void mini_httpd(int server_socket) ATTRIBUTE_NORETURN; static void mini_httpd(int server_socket) ATTRIBUTE_NORETURN;
static void mini_httpd(int server_socket) static void mini_httpd(int server_socket)
{ {
@ -1810,22 +1824,53 @@ static void mini_httpd(int server_socket)
xmove_fd(n, 0); xmove_fd(n, 0);
xdup2(0, 1); xdup2(0, 1);
n = get_nport(&fromAddr.sa); handle_incoming_and_exit(&fromAddr);
rmt_port = ntohs(n); }
rmt_ip = 0; /* parent, or fork failed */
if (fromAddr.sa.sa_family == AF_INET) { close(n);
rmt_ip = ntohl(fromAddr.sin.sin_addr.s_addr); } /* while (1) */
} /* never reached */
if (ENABLE_FEATURE_HTTPD_CGI || DEBUG || verbose) { }
rmt_ip_str = xmalloc_sockaddr2dotted(&fromAddr.sa); #else
} static void mini_httpd_nommu(int server_socket, int argc, char **argv) ATTRIBUTE_NORETURN;
if (verbose) { static void mini_httpd_nommu(int server_socket, int argc, char **argv)
/* this trick makes -v logging much simpler */ {
applet_name = rmt_ip_str; char *argv_copy[argc + 2];
if (verbose > 2)
bb_error_msg("connected"); argv_copy[0] = argv[0];
} argv_copy[1] = (char*)"-i";
handle_incoming_and_exit(); 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 */ /* parent, or fork failed */
close(n); close(n);
@ -1834,25 +1879,18 @@ static void mini_httpd(int server_socket)
} }
#endif #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) ATTRIBUTE_NORETURN;
static void mini_httpd_inetd(void) static void mini_httpd_inetd(void)
{ {
int n;
len_and_sockaddr fromAddr; len_and_sockaddr fromAddr;
fromAddr.len = LSA_SIZEOF_SA; fromAddr.len = LSA_SIZEOF_SA;
getpeername(0, &fromAddr.sa, &fromAddr.len); getpeername(0, &fromAddr.sa, &fromAddr.len);
n = get_nport(&fromAddr.sa); handle_incoming_and_exit(&fromAddr);
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();
} }
#if ENABLE_FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP #if ENABLE_FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP
@ -1915,7 +1953,8 @@ int httpd_main(int argc, char **argv)
#endif #endif
home_httpd = xrealloc_getcwd_or_warn(NULL); 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. /* We do not "absolutize" path given by -h (home) opt.
* If user gives relative path in -h, $SCRIPT_FILENAME can end up * If user gives relative path in -h, $SCRIPT_FILENAME can end up
* relative too. */ * relative too. */
@ -1934,12 +1973,12 @@ int httpd_main(int argc, char **argv)
, &verbose , &verbose
); );
if (opt & OPT_DECODE_URL) { if (opt & OPT_DECODE_URL) {
printf("%s", decodeString(url_for_decode, 1)); fputs(decodeString(url_for_decode, 1), stdout);
return 0; return 0;
} }
#if ENABLE_FEATURE_HTTPD_ENCODE_URL_STR #if ENABLE_FEATURE_HTTPD_ENCODE_URL_STR
if (opt & OPT_ENCODE_URL) { if (opt & OPT_ENCODE_URL) {
printf("%s", encodeString(url_for_encode)); fputs(encodeString(url_for_encode), stdout);
return 0; return 0;
} }
#endif #endif
@ -1957,9 +1996,14 @@ int httpd_main(int argc, char **argv)
} }
#endif #endif
#if !BB_MMU
if (!(opt & OPT_FOREGROUND)) {
bb_daemonize_or_rexec(0, argv); /* don't change current directory */
}
#endif
xchdir(home_httpd); xchdir(home_httpd);
if (!(opt & OPT_INETD)) { if (!(opt & OPT_INETD)) {
#if BB_MMU
signal(SIGCHLD, SIG_IGN); signal(SIGCHLD, SIG_IGN);
server_socket = openServer(); server_socket = openServer();
#if ENABLE_FEATURE_HTTPD_SETUID #if ENABLE_FEATURE_HTTPD_SETUID
@ -1972,9 +2016,6 @@ int httpd_main(int argc, char **argv)
} }
xsetuid(ugid.uid); xsetuid(ugid.uid);
} }
#endif
#else /* BB_MMU */
bb_error_msg_and_die("-i is required");
#endif #endif
} }
@ -1990,21 +2031,22 @@ int httpd_main(int argc, char **argv)
} }
#endif #endif
#if BB_MMU
#if ENABLE_FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP #if ENABLE_FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP
sighup_handler(0); if (!(opt & OPT_INETD))
#else sighup_handler(0);
parse_conf(default_path_httpd_conf, FIRST_PARSE); else /* do not install HUP handler in inetd mode */
#endif #endif
parse_conf(default_path_httpd_conf, FIRST_PARSE);
xfunc_error_retval = 0; xfunc_error_retval = 0;
if (opt & OPT_INETD) if (opt & OPT_INETD)
mini_httpd_inetd(); mini_httpd_inetd();
#if BB_MMU
if (!(opt & OPT_FOREGROUND)) if (!(opt & OPT_FOREGROUND))
bb_daemonize(0); /* don't change current directory */ bb_daemonize(0); /* don't change current directory */
mini_httpd(server_socket); /* never returns */ mini_httpd(server_socket); /* never returns */
#else #else
xfunc_error_retval = 0; mini_httpd_nommu(server_socket, argc, argv); /* never returns */
mini_httpd_inetd(); /* never returns */
/* return 0; */
#endif #endif
/* return 0; */
} }