diff options
-rw-r--r-- | include/libbb.h | 2 | ||||
-rw-r--r-- | libbb/vfork_daemon_rexec.c | 15 | ||||
-rw-r--r-- | networking/httpd.c | 140 |
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 { | |||
587 | }; | 587 | }; |
588 | #if BB_MMU | 588 | #if BB_MMU |
589 | void forkexit_or_rexec(void); | 589 | void forkexit_or_rexec(void); |
590 | enum { re_execed = 0 }; | ||
590 | # define forkexit_or_rexec(argv) forkexit_or_rexec() | 591 | # define forkexit_or_rexec(argv) forkexit_or_rexec() |
591 | # define bb_daemonize_or_rexec(flags, argv) bb_daemonize_or_rexec(flags) | 592 | # define bb_daemonize_or_rexec(flags, argv) bb_daemonize_or_rexec(flags) |
592 | # define bb_daemonize(flags) bb_daemonize_or_rexec(flags, bogus) | 593 | # define bb_daemonize(flags) bb_daemonize_or_rexec(flags, bogus) |
593 | #else | 594 | #else |
595 | void re_exec(char **argv) ATTRIBUTE_NORETURN; | ||
594 | void forkexit_or_rexec(char **argv); | 596 | void forkexit_or_rexec(char **argv); |
595 | extern bool re_execed; | 597 | extern bool re_execed; |
596 | # define fork() BUG_fork_is_unavailable_on_nommu() | 598 | # 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) | |||
203 | } | 203 | } |
204 | 204 | ||
205 | #if !BB_MMU | 205 | #if !BB_MMU |
206 | void re_exec(char **argv) | ||
207 | { | ||
208 | /* high-order bit of first char in argv[0] is a hidden | ||
209 | * "we have (already) re-execed, don't do it again" flag */ | ||
210 | argv[0][0] |= 0x80; | ||
211 | execv(bb_busybox_exec_path, argv); | ||
212 | bb_perror_msg_and_die("exec %s", bb_busybox_exec_path); | ||
213 | } | ||
214 | |||
206 | void forkexit_or_rexec(char **argv) | 215 | void forkexit_or_rexec(char **argv) |
207 | { | 216 | { |
208 | pid_t pid; | 217 | pid_t pid; |
@@ -216,11 +225,7 @@ void forkexit_or_rexec(char **argv) | |||
216 | if (pid) /* parent */ | 225 | if (pid) /* parent */ |
217 | exit(0); | 226 | exit(0); |
218 | /* child - re-exec ourself */ | 227 | /* child - re-exec ourself */ |
219 | /* high-order bit of first char in argv[0] is a hidden | 228 | re_exec(argv); |
220 | * "we have (alrealy) re-execed, don't do it again" flag */ | ||
221 | argv[0][0] |= 0x80; | ||
222 | execv(bb_busybox_exec_path, argv); | ||
223 | bb_perror_msg_and_die("exec %s", bb_busybox_exec_path); | ||
224 | } | 229 | } |
225 | #else | 230 | #else |
226 | /* Dance around (void)...*/ | 231 | /* 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) | |||
764 | /* | 764 | /* |
765 | * Create a listen server socket on the designated port. | 765 | * Create a listen server socket on the designated port. |
766 | */ | 766 | */ |
767 | #if BB_MMU | ||
768 | static int openServer(void) | 767 | static int openServer(void) |
769 | { | 768 | { |
770 | int n = bb_strtou(bind_addr_or_port, NULL, 10); | 769 | int n = bb_strtou(bind_addr_or_port, NULL, 10); |
@@ -775,7 +774,6 @@ static int openServer(void) | |||
775 | xlisten(n, 9); | 774 | xlisten(n, 9); |
776 | return n; | 775 | return n; |
777 | } | 776 | } |
778 | #endif | ||
779 | 777 | ||
780 | /* | 778 | /* |
781 | * Log the connection closure and exit. | 779 | * Log the connection closure and exit. |
@@ -1474,8 +1472,8 @@ static void exit_on_signal(int sig) | |||
1474 | /* | 1472 | /* |
1475 | * Handle an incoming http request and exit. | 1473 | * Handle an incoming http request and exit. |
1476 | */ | 1474 | */ |
1477 | static void handle_incoming_and_exit(void) ATTRIBUTE_NORETURN; | 1475 | static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) ATTRIBUTE_NORETURN; |
1478 | static void handle_incoming_and_exit(void) | 1476 | static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) |
1479 | { | 1477 | { |
1480 | static const char request_GET[] ALIGN1 = "GET"; | 1478 | static const char request_GET[] ALIGN1 = "GET"; |
1481 | 1479 | ||
@@ -1497,6 +1495,22 @@ static void handle_incoming_and_exit(void) | |||
1497 | int credentials = -1; /* if not required this is Ok */ | 1495 | int credentials = -1; /* if not required this is Ok */ |
1498 | #endif | 1496 | #endif |
1499 | 1497 | ||
1498 | rmt_port = get_nport(&fromAddr->sa); | ||
1499 | rmt_port = ntohs(rmt_port); | ||
1500 | rmt_ip = 0; | ||
1501 | if (fromAddr->sa.sa_family == AF_INET) { | ||
1502 | rmt_ip = ntohl(fromAddr->sin.sin_addr.s_addr); | ||
1503 | } | ||
1504 | if (ENABLE_FEATURE_HTTPD_CGI || DEBUG || verbose) { | ||
1505 | rmt_ip_str = xmalloc_sockaddr2dotted(&fromAddr->sa); | ||
1506 | } | ||
1507 | if (verbose) { | ||
1508 | /* this trick makes -v logging much simpler */ | ||
1509 | applet_name = rmt_ip_str; | ||
1510 | if (verbose > 2) | ||
1511 | bb_error_msg("connected"); | ||
1512 | } | ||
1513 | |||
1500 | /* Install timeout handler */ | 1514 | /* Install timeout handler */ |
1501 | memset(&sa, 0, sizeof(sa)); | 1515 | memset(&sa, 0, sizeof(sa)); |
1502 | sa.sa_handler = exit_on_signal; | 1516 | sa.sa_handler = exit_on_signal; |
@@ -1772,13 +1786,13 @@ static void handle_incoming_and_exit(void) | |||
1772 | #endif | 1786 | #endif |
1773 | } | 1787 | } |
1774 | 1788 | ||
1775 | #if BB_MMU | ||
1776 | /* | 1789 | /* |
1777 | * The main http server function. | 1790 | * The main http server function. |
1778 | * Given an open socket, listen for new connections and farm out | 1791 | * Given a socket, listen for new connections and farm out |
1779 | * the processing as a forked process. | 1792 | * the processing as a [v]forked process. |
1780 | * Never returns. | 1793 | * Never returns. |
1781 | */ | 1794 | */ |
1795 | #if BB_MMU | ||
1782 | static void mini_httpd(int server_socket) ATTRIBUTE_NORETURN; | 1796 | static void mini_httpd(int server_socket) ATTRIBUTE_NORETURN; |
1783 | static void mini_httpd(int server_socket) | 1797 | static void mini_httpd(int server_socket) |
1784 | { | 1798 | { |
@@ -1810,22 +1824,53 @@ static void mini_httpd(int server_socket) | |||
1810 | xmove_fd(n, 0); | 1824 | xmove_fd(n, 0); |
1811 | xdup2(0, 1); | 1825 | xdup2(0, 1); |
1812 | 1826 | ||
1813 | n = get_nport(&fromAddr.sa); | 1827 | handle_incoming_and_exit(&fromAddr); |
1814 | rmt_port = ntohs(n); | 1828 | } |
1815 | rmt_ip = 0; | 1829 | /* parent, or fork failed */ |
1816 | if (fromAddr.sa.sa_family == AF_INET) { | 1830 | close(n); |
1817 | rmt_ip = ntohl(fromAddr.sin.sin_addr.s_addr); | 1831 | } /* while (1) */ |
1818 | } | 1832 | /* never reached */ |
1819 | if (ENABLE_FEATURE_HTTPD_CGI || DEBUG || verbose) { | 1833 | } |
1820 | rmt_ip_str = xmalloc_sockaddr2dotted(&fromAddr.sa); | 1834 | #else |
1821 | } | 1835 | static void mini_httpd_nommu(int server_socket, int argc, char **argv) ATTRIBUTE_NORETURN; |
1822 | if (verbose) { | 1836 | static void mini_httpd_nommu(int server_socket, int argc, char **argv) |
1823 | /* this trick makes -v logging much simpler */ | 1837 | { |
1824 | applet_name = rmt_ip_str; | 1838 | char *argv_copy[argc + 2]; |
1825 | if (verbose > 2) | 1839 | |
1826 | bb_error_msg("connected"); | 1840 | argv_copy[0] = argv[0]; |
1827 | } | 1841 | argv_copy[1] = (char*)"-i"; |
1828 | handle_incoming_and_exit(); | 1842 | memcpy(&argv_copy[2], &argv[1], argc * sizeof(argv[0])); |
1843 | |||
1844 | /* NB: it's best to not use xfuncs in this loop before vfork(). | ||
1845 | * Otherwise server may die on transient errors (temporary | ||
1846 | * out-of-memory condition, etc), which is Bad(tm). | ||
1847 | * Try to do any dangerous calls after fork. | ||
1848 | */ | ||
1849 | while (1) { | ||
1850 | int n; | ||
1851 | len_and_sockaddr fromAddr; | ||
1852 | |||
1853 | /* Wait for connections... */ | ||
1854 | fromAddr.len = LSA_SIZEOF_SA; | ||
1855 | n = accept(server_socket, &fromAddr.sa, &fromAddr.len); | ||
1856 | |||
1857 | if (n < 0) | ||
1858 | continue; | ||
1859 | /* set the KEEPALIVE option to cull dead connections */ | ||
1860 | setsockopt(n, SOL_SOCKET, SO_KEEPALIVE, &const_int_1, sizeof(const_int_1)); | ||
1861 | |||
1862 | if (vfork() == 0) { | ||
1863 | /* child */ | ||
1864 | #if ENABLE_FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP | ||
1865 | /* Do not reload config on HUP */ | ||
1866 | signal(SIGHUP, SIG_IGN); | ||
1867 | #endif | ||
1868 | close(server_socket); | ||
1869 | xmove_fd(n, 0); | ||
1870 | xdup2(0, 1); | ||
1871 | |||
1872 | /* Run a copy of ourself in inetd mode */ | ||
1873 | re_exec(argv_copy); | ||
1829 | } | 1874 | } |
1830 | /* parent, or fork failed */ | 1875 | /* parent, or fork failed */ |
1831 | close(n); | 1876 | close(n); |
@@ -1834,25 +1879,18 @@ static void mini_httpd(int server_socket) | |||
1834 | } | 1879 | } |
1835 | #endif | 1880 | #endif |
1836 | 1881 | ||
1837 | /* from inetd */ | 1882 | /* |
1883 | * Process a HTTP connection on stdin/out. | ||
1884 | * Never returns. | ||
1885 | */ | ||
1838 | static void mini_httpd_inetd(void) ATTRIBUTE_NORETURN; | 1886 | static void mini_httpd_inetd(void) ATTRIBUTE_NORETURN; |
1839 | static void mini_httpd_inetd(void) | 1887 | static void mini_httpd_inetd(void) |
1840 | { | 1888 | { |
1841 | int n; | ||
1842 | len_and_sockaddr fromAddr; | 1889 | len_and_sockaddr fromAddr; |
1843 | 1890 | ||
1844 | fromAddr.len = LSA_SIZEOF_SA; | 1891 | fromAddr.len = LSA_SIZEOF_SA; |
1845 | getpeername(0, &fromAddr.sa, &fromAddr.len); | 1892 | getpeername(0, &fromAddr.sa, &fromAddr.len); |
1846 | n = get_nport(&fromAddr.sa); | 1893 | handle_incoming_and_exit(&fromAddr); |
1847 | rmt_port = ntohs(n); | ||
1848 | rmt_ip = 0; | ||
1849 | if (fromAddr.sa.sa_family == AF_INET) { | ||
1850 | rmt_ip = ntohl(fromAddr.sin.sin_addr.s_addr); | ||
1851 | } | ||
1852 | if (ENABLE_FEATURE_HTTPD_CGI || DEBUG || verbose) { | ||
1853 | rmt_ip_str = xmalloc_sockaddr2dotted(&fromAddr.sa); | ||
1854 | } | ||
1855 | handle_incoming_and_exit(); | ||
1856 | } | 1894 | } |
1857 | 1895 | ||
1858 | #if ENABLE_FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP | 1896 | #if ENABLE_FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP |
@@ -1915,7 +1953,8 @@ int httpd_main(int argc, char **argv) | |||
1915 | #endif | 1953 | #endif |
1916 | 1954 | ||
1917 | home_httpd = xrealloc_getcwd_or_warn(NULL); | 1955 | home_httpd = xrealloc_getcwd_or_warn(NULL); |
1918 | opt_complementary = "vv"; /* counter */ | 1956 | /* -v counts, -i implies -f */ |
1957 | opt_complementary = "vv:if"; | ||
1919 | /* We do not "absolutize" path given by -h (home) opt. | 1958 | /* We do not "absolutize" path given by -h (home) opt. |
1920 | * If user gives relative path in -h, $SCRIPT_FILENAME can end up | 1959 | * If user gives relative path in -h, $SCRIPT_FILENAME can end up |
1921 | * relative too. */ | 1960 | * relative too. */ |
@@ -1934,12 +1973,12 @@ int httpd_main(int argc, char **argv) | |||
1934 | , &verbose | 1973 | , &verbose |
1935 | ); | 1974 | ); |
1936 | if (opt & OPT_DECODE_URL) { | 1975 | if (opt & OPT_DECODE_URL) { |
1937 | printf("%s", decodeString(url_for_decode, 1)); | 1976 | fputs(decodeString(url_for_decode, 1), stdout); |
1938 | return 0; | 1977 | return 0; |
1939 | } | 1978 | } |
1940 | #if ENABLE_FEATURE_HTTPD_ENCODE_URL_STR | 1979 | #if ENABLE_FEATURE_HTTPD_ENCODE_URL_STR |
1941 | if (opt & OPT_ENCODE_URL) { | 1980 | if (opt & OPT_ENCODE_URL) { |
1942 | printf("%s", encodeString(url_for_encode)); | 1981 | fputs(encodeString(url_for_encode), stdout); |
1943 | return 0; | 1982 | return 0; |
1944 | } | 1983 | } |
1945 | #endif | 1984 | #endif |
@@ -1957,9 +1996,14 @@ int httpd_main(int argc, char **argv) | |||
1957 | } | 1996 | } |
1958 | #endif | 1997 | #endif |
1959 | 1998 | ||
1999 | #if !BB_MMU | ||
2000 | if (!(opt & OPT_FOREGROUND)) { | ||
2001 | bb_daemonize_or_rexec(0, argv); /* don't change current directory */ | ||
2002 | } | ||
2003 | #endif | ||
2004 | |||
1960 | xchdir(home_httpd); | 2005 | xchdir(home_httpd); |
1961 | if (!(opt & OPT_INETD)) { | 2006 | if (!(opt & OPT_INETD)) { |
1962 | #if BB_MMU | ||
1963 | signal(SIGCHLD, SIG_IGN); | 2007 | signal(SIGCHLD, SIG_IGN); |
1964 | server_socket = openServer(); | 2008 | server_socket = openServer(); |
1965 | #if ENABLE_FEATURE_HTTPD_SETUID | 2009 | #if ENABLE_FEATURE_HTTPD_SETUID |
@@ -1973,9 +2017,6 @@ int httpd_main(int argc, char **argv) | |||
1973 | xsetuid(ugid.uid); | 2017 | xsetuid(ugid.uid); |
1974 | } | 2018 | } |
1975 | #endif | 2019 | #endif |
1976 | #else /* BB_MMU */ | ||
1977 | bb_error_msg_and_die("-i is required"); | ||
1978 | #endif | ||
1979 | } | 2020 | } |
1980 | 2021 | ||
1981 | #if ENABLE_FEATURE_HTTPD_CGI | 2022 | #if ENABLE_FEATURE_HTTPD_CGI |
@@ -1990,21 +2031,22 @@ int httpd_main(int argc, char **argv) | |||
1990 | } | 2031 | } |
1991 | #endif | 2032 | #endif |
1992 | 2033 | ||
1993 | #if BB_MMU | ||
1994 | #if ENABLE_FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP | 2034 | #if ENABLE_FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP |
1995 | sighup_handler(0); | 2035 | if (!(opt & OPT_INETD)) |
1996 | #else | 2036 | sighup_handler(0); |
1997 | parse_conf(default_path_httpd_conf, FIRST_PARSE); | 2037 | else /* do not install HUP handler in inetd mode */ |
1998 | #endif | 2038 | #endif |
2039 | parse_conf(default_path_httpd_conf, FIRST_PARSE); | ||
2040 | |||
1999 | xfunc_error_retval = 0; | 2041 | xfunc_error_retval = 0; |
2000 | if (opt & OPT_INETD) | 2042 | if (opt & OPT_INETD) |
2001 | mini_httpd_inetd(); | 2043 | mini_httpd_inetd(); |
2044 | #if BB_MMU | ||
2002 | if (!(opt & OPT_FOREGROUND)) | 2045 | if (!(opt & OPT_FOREGROUND)) |
2003 | bb_daemonize(0); /* don't change current directory */ | 2046 | bb_daemonize(0); /* don't change current directory */ |
2004 | mini_httpd(server_socket); /* never returns */ | 2047 | mini_httpd(server_socket); /* never returns */ |
2005 | #else | 2048 | #else |
2006 | xfunc_error_retval = 0; | 2049 | mini_httpd_nommu(server_socket, argc, argv); /* never returns */ |
2007 | mini_httpd_inetd(); /* never returns */ | ||
2008 | /* return 0; */ | ||
2009 | #endif | 2050 | #endif |
2051 | /* return 0; */ | ||
2010 | } | 2052 | } |