lighttpd 1.4.x https://www.lighttpd.net/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1852 lines
46 KiB

#include "first.h"
#include "server.h"
#include "buffer.h"
#include "network.h"
#include "log.h"
#include "keyvalue.h"
#include "rand.h"
#include "response.h"
#include "request.h"
#include "chunk.h"
#include "http_chunk.h"
#include "fdevent.h"
#include "connections.h"
#include "stat_cache.h"
#include "plugin.h"
#include "joblist.h"
#include "network_backends.h"
#include "version.h"
#include <sys/types.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
#include <signal.h>
#include <assert.h>
#include <locale.h>
#include <stdio.h>
#ifdef HAVE_GETOPT_H
# include <getopt.h>
#endif
#ifdef HAVE_VALGRIND_VALGRIND_H
# include <valgrind/valgrind.h>
#endif
#ifdef HAVE_SYS_WAIT_H
# include <sys/wait.h>
#endif
#ifdef HAVE_PWD_H
# include <grp.h>
# include <pwd.h>
#endif
#ifdef HAVE_SYS_RESOURCE_H
# include <sys/resource.h>
#endif
#ifdef HAVE_SYS_PRCTL_H
# include <sys/prctl.h>
#endif
#ifdef USE_OPENSSL
# include <openssl/err.h>
#endif
#ifndef __sgi
/* IRIX doesn't like the alarm based time() optimization */
/* #define USE_ALARM */
#endif
#ifdef HAVE_GETUID
# ifndef HAVE_ISSETUGID
static int l_issetugid(void) {
return (geteuid() != getuid() || getegid() != getgid());
}
# define issetugid l_issetugid
# endif
#endif
static int oneshot_fd = 0;
static volatile sig_atomic_t srv_shutdown = 0;
static volatile sig_atomic_t graceful_shutdown = 0;
static volatile sig_atomic_t handle_sig_alarm = 1;
static volatile sig_atomic_t handle_sig_hup = 0;
static volatile sig_atomic_t forwarded_sig_hup = 0;
#if defined(HAVE_SIGACTION) && defined(SA_SIGINFO)
static volatile siginfo_t last_sigterm_info;
static volatile siginfo_t last_sighup_info;
static void sigaction_handler(int sig, siginfo_t *si, void *context) {
static siginfo_t empty_siginfo;
UNUSED(context);
if (!si) si = &empty_siginfo;
switch (sig) {
case SIGTERM:
srv_shutdown = 1;
last_sigterm_info = *si;
break;
case SIGINT:
if (graceful_shutdown) {
srv_shutdown = 1;
} else {
graceful_shutdown = 1;
}
last_sigterm_info = *si;
break;
case SIGALRM:
handle_sig_alarm = 1;
break;
case SIGHUP:
/**
* we send the SIGHUP to all procs in the process-group
* this includes ourself
*
* make sure we only send it once and don't create a
* infinite loop
*/
if (!forwarded_sig_hup) {
handle_sig_hup = 1;
last_sighup_info = *si;
} else {
forwarded_sig_hup = 0;
}
break;
case SIGCHLD:
break;
}
}
#elif defined(HAVE_SIGNAL) || defined(HAVE_SIGACTION)
static void signal_handler(int sig) {
switch (sig) {
case SIGTERM: srv_shutdown = 1; break;
case SIGINT:
if (graceful_shutdown) srv_shutdown = 1;
else graceful_shutdown = 1;
break;
case SIGALRM: handle_sig_alarm = 1; break;
case SIGHUP: handle_sig_hup = 1; break;
case SIGCHLD: break;
}
}
#endif
#ifdef HAVE_FORK
static int daemonize(void) {
int pipefd[2];
pid_t pid;
#ifdef SIGTTOU
signal(SIGTTOU, SIG_IGN);
#endif
#ifdef SIGTTIN
signal(SIGTTIN, SIG_IGN);
#endif
#ifdef SIGTSTP
signal(SIGTSTP, SIG_IGN);
#endif
if (pipe(pipefd) < 0) exit(-1);
if (0 > (pid = fork())) exit(-1);
if (0 < pid) {
char buf;
ssize_t bytes;
close(pipefd[1]);
/* parent waits for grandchild to be ready */
do {
bytes = read(pipefd[0], &buf, sizeof(buf));
} while (bytes < 0 && EINTR == errno);
close(pipefd[0]);
if (bytes <= 0) {
/* closed fd (without writing) == failure in grandchild */
fputs("daemonized server failed to start; check error log for details\n", stderr);
exit(-1);
}
exit(0);
}
close(pipefd[0]);
if (-1 == setsid()) exit(0);
signal(SIGHUP, SIG_IGN);
if (0 != fork()) exit(0);
if (0 != chdir("/")) exit(0);
fd_close_on_exec(pipefd[1]);
return pipefd[1];
}
#endif
static server *server_init(void) {
int i;
server *srv = calloc(1, sizeof(*srv));
force_assert(srv);
#define CLEAN(x) \
srv->x = buffer_init();
CLEAN(response_header);
CLEAN(parse_full_path);
CLEAN(ts_debug_str);
CLEAN(ts_date_str);
CLEAN(errorlog_buf);
CLEAN(response_range);
CLEAN(tmp_buf);
srv->empty_string = buffer_init_string("");
CLEAN(cond_check_buf);
CLEAN(srvconf.errorlog_file);
CLEAN(srvconf.breakagelog_file);
CLEAN(srvconf.groupname);
CLEAN(srvconf.username);
CLEAN(srvconf.changeroot);
CLEAN(srvconf.bindhost);
CLEAN(srvconf.event_handler);
CLEAN(srvconf.pid_file);
CLEAN(tmp_chunk_len);
#undef CLEAN
#define CLEAN(x) \
srv->x = array_init();
CLEAN(config_context);
CLEAN(config_touched);
CLEAN(status);
#undef CLEAN
for (i = 0; i < FILE_CACHE_MAX; i++) {
srv->mtime_cache[i].mtime = (time_t)-1;
srv->mtime_cache[i].str = buffer_init();
}
li_rand_reseed();
li_rand_bytes((unsigned char *)srv->entropy, (int)sizeof(srv->entropy));
srv->cur_ts = time(NULL);
srv->startup_ts = srv->cur_ts;
srv->conns = calloc(1, sizeof(*srv->conns));
force_assert(srv->conns);
srv->joblist = calloc(1, sizeof(*srv->joblist));
force_assert(srv->joblist);
srv->fdwaitqueue = calloc(1, sizeof(*srv->fdwaitqueue));
force_assert(srv->fdwaitqueue);
srv->srvconf.modules = array_init();
srv->srvconf.modules_dir = buffer_init_string(LIBRARY_DIR);
srv->srvconf.network_backend = buffer_init();
srv->srvconf.upload_tempdirs = array_init();
srv->srvconf.reject_expect_100_with_417 = 1;
srv->srvconf.xattr_name = buffer_init_string("Content-Type");
[config] opts for http header parsing strictness (fixes #551, fixes #1086, fixes #1184, fixes #2143, #2258, #2281, fixes #946, fixes #1330, fixes #602, #1016) server.http-parseopt-header-strict = &#34;enable&#34; server.http-parseopt-host-strict = &#34;enable&#34; (implies host-normalize) server.http-parseopt-host-normalize = &#34;disable&#34; defaults retain current behavior, which is strict header parsing and strict host parsing, with enhancement to normalize IPv4 address and port number strings. For lighttpd tests, these need to be enabled (and are by default) For marginally faster HTTP header parsing for benchmarks, disable these. To allow - underscores in hostname - hypen (&#39;-&#39;) at beginning of hostname - all-numeric TLDs server.http-parseopt-host-strict = &#34;disable&#34; x-ref: &#34;lighttpd doesn&#39;t allow underscores in host names&#34; https://redmine.lighttpd.net/issues/551 &#34;hyphen in hostname&#34; https://redmine.lighttpd.net/issues/1086 &#34;a numeric tld&#34; https://redmine.lighttpd.net/issues/1184 &#34;Numeric tld&#39;s&#34; https://redmine.lighttpd.net/issues/2143 &#34;Bad Request&#34; https://redmine.lighttpd.net/issues/2258 &#34;400 Bad Request when using Numeric TLDs&#34; https://redmine.lighttpd.net/issues/2281 To allow a variety of numerical formats to be converted to IP addresses server.http-parseopt-host-strict = &#34;disable&#34; server.http-parseopt-host-normalize = &#34;enable&#34; x-ref: &#34;URL encoding leads to &#34;400 - Bad Request&#34;&#34; https://redmine.lighttpd.net/issues/946 &#34;400 Bad Request when using IP&#39;s numeric value (&#34;ip2long()&#34;)&#34; https://redmine.lighttpd.net/issues/1330 To allow most 8-bit and 7-bit chars in headers server.http-parseopt-header-strict = &#34;disable&#34; (not recommended) x-ref: &#34;Russian letters not alowed?&#34; https://redmine.lighttpd.net/issues/602 &#34;header Content-Disposition with russian &#39;?&#39; (CP1251, ascii code 255) causes error&#34; https://redmine.lighttpd.net/issues/1016
5 years ago
srv->srvconf.http_header_strict = 1;
srv->srvconf.http_host_strict = 1; /*(implies http_host_normalize)*/
srv->srvconf.http_host_normalize = 0;
srv->srvconf.high_precision_timestamps = 0;
srv->srvconf.max_request_field_size = 8192;
srv->srvconf.loadavg[0] = 0.0;
srv->srvconf.loadavg[1] = 0.0;
srv->srvconf.loadavg[2] = 0.0;
/* use syslog */
srv->errorlog_fd = STDERR_FILENO;
srv->errorlog_mode = ERRORLOG_FD;
srv->split_vals = array_init();
return srv;
}
static void server_free(server *srv) {
size_t i;
for (i = 0; i < FILE_CACHE_MAX; i++) {
buffer_free(srv->mtime_cache[i].str);
}
if (oneshot_fd > 0) {
close(oneshot_fd);
}
#define CLEAN(x) \
buffer_free(srv->x);
CLEAN(response_header);
CLEAN(parse_full_path);
CLEAN(ts_debug_str);
CLEAN(ts_date_str);
CLEAN(errorlog_buf);
CLEAN(response_range);
CLEAN(tmp_buf);
CLEAN(empty_string);
CLEAN(cond_check_buf);
CLEAN(srvconf.errorlog_file);
CLEAN(srvconf.breakagelog_file);
CLEAN(srvconf.groupname);
CLEAN(srvconf.username);
CLEAN(srvconf.changeroot);
CLEAN(srvconf.bindhost);
CLEAN(srvconf.event_handler);
CLEAN(srvconf.pid_file);
CLEAN(srvconf.modules_dir);
CLEAN(srvconf.network_backend);
CLEAN(srvconf.xattr_name);
CLEAN(tmp_chunk_len);
#undef CLEAN
#if 0
fdevent_unregister(srv->ev, srv->fd);
#endif
fdevent_free(srv->ev);
free(srv->conns);
if (srv->config_storage) {
for (i = 0; i < srv->config_context->used; i++) {
specific_config *s = srv->config_storage[i];
if (!s) continue;
buffer_free(s->document_root);
buffer_free(s->server_name);
buffer_free(s->server_tag);
buffer_free(s->ssl_pemfile);
buffer_free(s->ssl_ca_file);
buffer_free(s->ssl_cipher_list);
buffer_free(s->ssl_dh_file);
buffer_free(s->ssl_ec_curve);
buffer_free(s->error_handler);
[core] server.error-handler new directive for error pages (fixes #2702) server.error-handler preserves HTTP status error code when error page is static, and allows dynamic handlers to change HTTP status code when error page is provided by dynamic handler. server.error-handler intercepts all HTTP status codes &gt;= 400 except when the content is generated by a dynamic handler (cgi, ssi, fastcgi, scgi, proxy, lua). The request method is unconditionally changed to GET for the request to service the error handler, and the original request method is later restored (for logging purposes). request body from the original request, if present, is discarded. server.error-handler is somewhat similar to server.error-handler-404, but server.error-handler-404 is now deprecated, intercepts only 404 and 403 HTTP status codes, and returns 200 OK for static error pages, a source of confusion for some admins. On the other hand, the new server.error-handler, when set, will intercept all HTTP status error codes &gt;= 400. server.error-handler takes precedence over server.error-handler-404 when both are set. NOTE: a major difference between server.error-handler and the now-deprecated server.error-handler-404 is that the values of the non-standard CGI environment variables REQUEST_URI and REDIRECT_URI have been swapped. Since REDIRECT_STATUS is the original HTTP status code, REDIRECT_URI is now the original request, and REQUEST_URI is the current request (e.g. the URI/URL to the error handler). The prior behavior -- which reversed REQUEST_URI and REDIRECT_URI values from those described above -- is preserved for server.error-handler-404. Additionally, REDIRECT_STATUS is now available to mod_magnet, which continues to have access to request.uri and request.orig_uri. See further discussion at https://redmine.lighttpd.net/issues/2702 and https://redmine.lighttpd.net/issues/1828 github: closes #36
6 years ago
buffer_free(s->error_handler_404);
buffer_free(s->errorfile_prefix);
array_free(s->mimetypes);
buffer_free(s->ssl_verifyclient_username);
#ifdef USE_OPENSSL
SSL_CTX_free(s->ssl_ctx);
EVP_PKEY_free(s->ssl_pemfile_pkey);
X509_free(s->ssl_pemfile_x509);
if (NULL != s->ssl_ca_file_cert_names) sk_X509_NAME_pop_free(s->ssl_ca_file_cert_names, X509_NAME_free);
#endif
free(s);
}
free(srv->config_storage);
srv->config_storage = NULL;
}
#define CLEAN(x) \
array_free(srv->x);
CLEAN(config_context);
CLEAN(config_touched);
CLEAN(status);
CLEAN(srvconf.upload_tempdirs);
#undef CLEAN
joblist_free(srv, srv->joblist);
fdwaitqueue_free(srv, srv->fdwaitqueue);
if (srv->stat_cache) {
stat_cache_free(srv->stat_cache);
}
array_free(srv->srvconf.modules);
array_free(srv->split_vals);
#ifdef USE_OPENSSL
if (srv->ssl_is_init) {
CRYPTO_cleanup_all_ex_data();
ERR_free_strings();
#if OPENSSL_VERSION_NUMBER >= 0x10100000L \
&& !defined(LIBRESSL_VERSION_NUMBER)
/*(OpenSSL libraries handle thread init and deinit)
* https://github.com/openssl/openssl/pull/1048 */
#elif OPENSSL_VERSION_NUMBER >= 0x10000000L
ERR_remove_thread_state(NULL);
#else
ERR_remove_state(0);
#endif
EVP_cleanup();
}
#endif
li_rand_cleanup();
free(srv);
}
static void remove_pid_file(server *srv, int *pid_fd) {
if (!buffer_string_is_empty(srv->srvconf.pid_file) && 0 <= *pid_fd) {
if (0 != ftruncate(*pid_fd, 0)) {
log_error_write(srv, __FILE__, __LINE__, "sbds",
"ftruncate failed for:",
srv->srvconf.pid_file,
errno,
strerror(errno));
}
}
if (0 <= *pid_fd) {
close(*pid_fd);
*pid_fd = -1;
}
if (!buffer_string_is_empty(srv->srvconf.pid_file) &&
buffer_string_is_empty(srv->srvconf.changeroot)) {
if (0 != unlink(srv->srvconf.pid_file->ptr)) {
if (errno != EACCES && errno != EPERM) {
log_error_write(srv, __FILE__, __LINE__, "sbds",
"unlink failed for:",
srv->srvconf.pid_file,
errno,
strerror(errno));
}
}
}
}
static server_socket * server_oneshot_getsock(server *srv, sock_addr *cnt_addr) {
server_socket *srv_socket, *srv_socket_wild = NULL;
size_t i;
for (i = 0; i < srv->srv_sockets.used; ++i) {
srv_socket = srv->srv_sockets.ptr[i];
if (cnt_addr->plain.sa_family != srv_socket->addr.plain.sa_family) continue;
switch (cnt_addr->plain.sa_family) {
case AF_INET:
if (srv_socket->addr.ipv4.sin_port != cnt_addr->ipv4.sin_port) continue;
if (srv_socket->addr.ipv4.sin_addr.s_addr == cnt_addr->ipv4.sin_addr.s_addr) {
return srv_socket;
}
if (srv_socket->addr.ipv4.sin_addr.s_addr == htonl(INADDR_ANY)) {
srv_socket_wild = srv_socket;
}
continue;
#ifdef HAVE_IPV6
case AF_INET6:
if (srv_socket->addr.ipv6.sin6_port != cnt_addr->ipv6.sin6_port) continue;
if (0 == memcmp(&srv_socket->addr.ipv6.sin6_addr, &cnt_addr->ipv6.sin6_addr, sizeof(struct in6_addr))) {
return srv_socket;
}
if (0 == memcmp(&srv_socket->addr.ipv6.sin6_addr, &in6addr_any, sizeof(struct in6_addr))) {
srv_socket_wild = srv_socket;
}
continue;
#endif
#ifdef HAVE_SYS_UN_H
case AF_UNIX:
if (0 == strcmp(srv_socket->addr.un.sun_path, cnt_addr->un.sun_path)) {
return srv_socket;
}
continue;
#endif
default: continue;
}
}
if (NULL != srv_socket_wild) {
return srv_socket_wild;
} else if (srv->srv_sockets.used) {
return srv->srv_sockets.ptr[0];
} else {
log_error_write(srv, __FILE__, __LINE__, "s", "no sockets configured");
return NULL;
}
}
static int server_oneshot_init(server *srv, int fd) {
/* Note: does not work with netcat due to requirement that fd be socket.
* STDOUT_FILENO was not saved earlier in startup, and that is to where
* netcat expects output to be sent. Since lighttpd expects connections
* to be sockets, con->fd is where output is sent; separate fds are not
* stored for input and output, but netcat has different fds for stdin
* and * stdout. To support netcat, would additionally need to avoid
* S_ISSOCK(), getsockname(), and getpeername() below, reconstructing
* addresses from environment variables:
* NCAT_LOCAL_ADDR NCAT_LOCAL_PORT
* NCAT_REMOTE_ADDR NCAT_REMOTE_PORT
* NCAT_PROTO
*/
connection *con;
server_socket *srv_socket;
sock_addr cnt_addr;
socklen_t cnt_len;
struct stat st;
if (0 != fstat(fd, &st)) {
log_error_write(srv, __FILE__, __LINE__, "ss", "fstat:", strerror(errno));
return 0;
}
if (!S_ISSOCK(st.st_mode)) {
/* require that fd is a socket
* (modules might expect STDIN_FILENO and STDOUT_FILENO opened to /dev/null) */
log_error_write(srv, __FILE__, __LINE__, "s", "lighttpd -1 stdin is not a socket");
return 0;
}
cnt_len = sizeof(cnt_addr);
if (0 != getsockname(fd, (struct sockaddr *)&cnt_addr, &cnt_len)) {
log_error_write(srv, __FILE__, __LINE__, "ss", "getsockname:", strerror(errno));
return 0;
}
srv_socket = server_oneshot_getsock(srv, &cnt_addr);
if (NULL == srv_socket) return 0;
cnt_len = sizeof(cnt_addr);
if (0 != getpeername(fd, (struct sockaddr *)&cnt_addr, &cnt_len)) {
log_error_write(srv, __FILE__, __LINE__, "ss", "getpeername:", strerror(errno));
return 0;
}
if (cnt_addr.plain.sa_family != AF_UNIX) {
network_accept_tcp_nagle_disable(fd);
}
con = connection_accepted(srv, srv_socket, &cnt_addr, fd);
if (NULL == con) return 0;
connection_state_machine(srv, con);
return 1;
}
static void show_version (void) {
#ifdef USE_OPENSSL
# define TEXT_SSL " (ssl)"
#else
# define TEXT_SSL
#endif
char *b = PACKAGE_DESC TEXT_SSL \
" - a light and fast webserver\n" \
"Build-Date: " __DATE__ " " __TIME__ "\n";
;
#undef TEXT_SSL
write_all(STDOUT_FILENO, b, strlen(b));
}
static void show_features (void) {
const char features[] = ""
#ifdef USE_SELECT
"\t+ select (generic)\n"
#else
"\t- select (generic)\n"
#endif
#ifdef USE_POLL
"\t+ poll (Unix)\n"
#else
"\t- poll (Unix)\n"
#endif
#ifdef USE_LINUX_SIGIO
"\t+ rt-signals (Linux 2.4+)\n"
#else
"\t- rt-signals (Linux 2.4+)\n"
#endif
#ifdef USE_LINUX_EPOLL
"\t+ epoll (Linux 2.6)\n"
#else
"\t- epoll (Linux 2.6)\n"
#endif
#ifdef USE_SOLARIS_DEVPOLL
"\t+ /dev/poll (Solaris)\n"
#else
"\t- /dev/poll (Solaris)\n"
#endif
#ifdef USE_SOLARIS_PORT
"\t+ eventports (Solaris)\n"
#else
"\t- eventports (Solaris)\n"
#endif
#ifdef USE_FREEBSD_KQUEUE
"\t+ kqueue (FreeBSD)\n"
#else
"\t- kqueue (FreeBSD)\n"
#endif
#ifdef USE_LIBEV
"\t+ libev (generic)\n"
#else
"\t- libev (generic)\n"
#endif
"\nNetwork handler:\n\n"
#if defined USE_LINUX_SENDFILE
"\t+ linux-sendfile\n"
#else
"\t- linux-sendfile\n"
#endif
#if defined USE_FREEBSD_SENDFILE
"\t+ freebsd-sendfile\n"
#else
"\t- freebsd-sendfile\n"
#endif
#if defined USE_DARWIN_SENDFILE
"\t+ darwin-sendfile\n"
#else
"\t- darwin-sendfile\n"
#endif
#if defined USE_SOLARIS_SENDFILEV
"\t+ solaris-sendfilev\n"
#else
"\t- solaris-sendfilev\n"
#endif
#if defined USE_WRITEV
"\t+ writev\n"
#else
"\t- writev\n"
#endif
"\t+ write\n"
#ifdef USE_MMAP
"\t+ mmap support\n"
#else
"\t- mmap support\n"
#endif
"\nFeatures:\n\n"
#ifdef HAVE_IPV6
"\t+ IPv6 support\n"
#else
"\t- IPv6 support\n"
#endif
#if defined HAVE_ZLIB_H && defined HAVE_LIBZ
"\t+ zlib support\n"
#else
"\t- zlib support\n"
#endif
#if defined HAVE_BZLIB_H && defined HAVE_LIBBZ2
"\t+ bzip2 support\n"
#else
"\t- bzip2 support\n"
#endif
#if defined(HAVE_CRYPT) || defined(HAVE_CRYPT_R) || defined(HAVE_LIBCRYPT)
"\t+ crypt support\n"
#else
"\t- crypt support\n"
#endif
#ifdef USE_OPENSSL
"\t+ SSL Support\n"
#else
"\t- SSL Support\n"
#endif
#ifdef HAVE_LIBPCRE
"\t+ PCRE support\n"
#else
"\t- PCRE support\n"
#endif
#ifdef HAVE_MYSQL
"\t+ MySQL support\n"
#else
"\t- MySQL support\n"
#endif
#ifdef HAVE_KRB5
"\t+ Kerberos support\n"
#else
"\t- Kerberos support\n"
#endif
#if defined(HAVE_LDAP_H) && defined(HAVE_LBER_H) && defined(HAVE_LIBLDAP) && defined(HAVE_LIBLBER)
"\t+ LDAP support\n"
#else
"\t- LDAP support\n"
#endif
#ifdef USE_MEMCACHED
"\t+ memcached support\n"
#else
"\t- memcached support\n"
#endif
#ifdef HAVE_FAM_H
"\t+ FAM support\n"
#else
"\t- FAM support\n"
#endif
#ifdef HAVE_LUA_H
"\t+ LUA support\n"
#else
"\t- LUA support\n"
#endif
#ifdef HAVE_LIBXML_H
"\t+ xml support\n"
#else
"\t- xml support\n"
#endif
#ifdef HAVE_SQLITE3_H
"\t+ SQLite support\n"
#else
"\t- SQLite support\n"
#endif
#ifdef HAVE_GDBM_H
"\t+ GDBM support\n"
#else
"\t- GDBM support\n"
#endif
"\n";
show_version();
printf("\nEvent Handlers:\n\n%s", features);
}
static void show_help (void) {
#ifdef USE_OPENSSL
# define TEXT_SSL " (ssl)"
#else
# define TEXT_SSL
#endif
char *b = PACKAGE_DESC TEXT_SSL " ("__DATE__ " " __TIME__ ")" \
" - a light and fast webserver\n" \
"usage:\n" \
" -f <name> filename of the config-file\n" \
" -m <name> module directory (default: "LIBRARY_DIR")\n" \
" -i <secs> graceful shutdown after <secs> of inactivity\n" \
" -1 process single (one) request on stdin socket, then exit\n" \
" -p print the parsed config-file in internal form, and exit\n" \
" -t test config-file syntax, then exit\n" \
" -tt test config-file syntax, load and init modules, then exit\n" \
" -D don't go to background (default: go to background)\n" \
" -v show version\n" \
" -V show compile-time features\n" \
" -h show this help\n" \
"\n"
;
#undef TEXT_SSL
#undef TEXT_IPV6
write_all(STDOUT_FILENO, b, strlen(b));
}
int main (int argc, char **argv) {
server *srv = NULL;
int print_config = 0;
int test_config = 0;
int i_am_root;
int o;
int num_childs = 0;
int pid_fd = -1, fd;
size_t i;
time_t idle_limit = 0, last_active_ts = time(NULL);
#ifdef HAVE_SIGACTION
struct sigaction act;
#endif
#ifdef HAVE_GETRLIMIT
struct rlimit rlim;
#endif
#ifdef HAVE_FORK
int parent_pipe_fd = -1;
#endif
#ifdef USE_ALARM
struct itimerval interval;
interval.it_interval.tv_sec = 1;
interval.it_interval.tv_usec = 0;
interval.it_value.tv_sec = 1;