|
|
|
#include "first.h"
|
|
|
|
|
|
|
|
#include "base.h"
|
|
|
|
#include "buffer.h"
|
|
|
|
#include "network.h"
|
|
|
|
#include "log.h"
|
|
|
|
#include "rand.h"
|
|
|
|
#include "chunk.h"
|
|
|
|
#include "http_auth.h" /* http_auth_dumbdata_reset() */
|
|
|
|
#include "http_vhostdb.h" /* http_vhostdb_dumbdata_reset() */
|
|
|
|
#include "fdevent.h"
|
|
|
|
#include "connections.h"
|
|
|
|
#include "sock_addr.h"
|
|
|
|
#include "stat_cache.h"
|
|
|
|
#include "plugin.h"
|
|
|
|
#include "network_write.h" /* network_write_show_handlers() */
|
|
|
|
#include "response.h" /* strftime_cache_reset() */
|
|
|
|
|
|
|
|
#ifdef HAVE_VERSIONSTAMP_H
|
|
|
|
# include "versionstamp.h"
|
|
|
|
#else
|
|
|
|
# define REPO_VERSION ""
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define PACKAGE_DESC PACKAGE_NAME "/" PACKAGE_VERSION REPO_VERSION
|
|
|
|
static const buffer default_server_tag = { CONST_STR_LEN(PACKAGE_DESC), 0 };
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/time.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/wait.h>
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <time.h>
|
|
|
|
#include <signal.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_LOADAVG_H
|
|
|
|
# include <sys/loadavg.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAVE_SYS_RESOURCE_H
|
|
|
|
# include <sys/resource.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAVE_SYS_PRCTL_H
|
|
|
|
# include <sys/prctl.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "sys-crypto.h"
|
|
|
|
#if defined(USE_OPENSSL_CRYPTO) \
|
|
|
|
|| defined(USE_MBEDTLS_CRYPTO) \
|
|
|
|
|| defined(USE_NSS_CRYPTO) \
|
|
|
|
|| defined(USE_GNUTLS_CRYPTO) \
|
|
|
|
|| defined(USE_WOLFTLS_CRYPTO)
|
|
|
|
#define TEXT_SSL " (ssl)"
|
|
|
|
#else
|
|
|
|
#define TEXT_SSL
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef __sgi
|
|
|
|
/* IRIX doesn't like the alarm based time() optimization */
|
|
|
|
/* #define USE_ALARM */
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static int oneshot_fd = 0;
|
|
|
|
static volatile int pid_fd = -2;
|
|
|
|
static server_socket_array graceful_sockets;
|
|
|
|
static server_socket_array inherited_sockets;
|
|
|
|
static volatile sig_atomic_t graceful_restart = 0;
|
|
|
|
static volatile sig_atomic_t graceful_shutdown = 0;
|
|
|
|
static volatile sig_atomic_t srv_shutdown = 0;
|
|
|
|
static volatile sig_atomic_t handle_sig_child = 0;
|
|
|
|
static volatile sig_atomic_t handle_sig_alarm = 1;
|
|
|
|
static volatile sig_atomic_t handle_sig_hup = 0;
|
|
|
|
static time_t idle_limit = 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 const siginfo_t empty_siginfo;
|
|
|
|
UNUSED(context);
|
|
|
|
|
|
|
|
if (!si) *(const siginfo_t **)&si = &empty_siginfo;
|
|
|
|
|
|
|
|
switch (sig) {
|
|
|
|
case SIGTERM:
|
|
|
|
srv_shutdown = 1;
|
|
|
|
last_sigterm_info = *si;
|
|
|
|
break;
|
|
|
|
case SIGUSR1:
|
|
|
|
if (!graceful_shutdown) {
|
|
|
|
graceful_restart = 1;
|
|
|
|
graceful_shutdown = 1;
|
|
|
|
last_sigterm_info = *si;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SIGINT:
|
|
|
|
if (graceful_shutdown) {
|
|
|
|
if (2 == graceful_restart)
|
|
|
|
graceful_restart = 1;
|
|
|
|
else
|
|
|
|
srv_shutdown = 1;
|
|
|
|
} else {
|
|
|
|
graceful_shutdown = 1;
|
|
|
|
}
|
|
|
|
last_sigterm_info = *si;
|
|
|
|
|
|
|
|
break;
|
|
|
|
case SIGALRM:
|
|
|
|
handle_sig_alarm = 1;
|
|
|
|
break;
|
|
|
|
case SIGHUP:
|
|
|
|
handle_sig_hup = 1;
|
|
|
|
last_sighup_info = *si;
|
|
|
|
break;
|
|
|
|
case SIGCHLD:
|
|
|
|
handle_sig_child = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#elif defined(HAVE_SIGNAL) || defined(HAVE_SIGACTION)
|
|
|
|
static void signal_handler(int sig) {
|
|
|
|
switch (sig) {
|
|
|
|
case SIGTERM: srv_shutdown = 1; break;
|
|
|
|
case SIGUSR1:
|
|
|
|
if (!graceful_shutdown) {
|
|
|
|
graceful_restart = 1;
|
|
|
|
graceful_shutdown = 1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SIGINT:
|
|
|
|
if (graceful_shutdown) {
|
|
|
|
if (2 == graceful_restart)
|
|
|
|
graceful_restart = 1;
|
|
|
|
else
|
|
|
|
srv_shutdown = 1;
|
|
|
|
} else {
|
|
|
|
graceful_shutdown = 1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SIGALRM: handle_sig_alarm = 1; break;
|
|
|
|
case SIGHUP: handle_sig_hup = 1; break;
|
|
|
|
case SIGCHLD: handle_sig_child = 1; 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);
|
|
|
|
|
|
|
|
fdevent_setfd_cloexec(pipefd[1]);
|
|
|
|
return pipefd[1];
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
__attribute_cold__
|
|
|
|
static server *server_init(void) {
|
|
|
|
server *srv = calloc(1, sizeof(*srv));
|
|
|
|
force_assert(srv);
|
|
|
|
#define CLEAN(x) \
|
|
|
|
srv->x = buffer_init();
|
|
|
|
|
|
|
|
CLEAN(tmp_buf);
|
|
|
|
#undef CLEAN
|
|
|
|
|
|
|
|
strftime_cache_reset();
|
|
|
|
|
|
|
|
li_rand_reseed();
|
|
|
|
|
|
|
|
srv->startup_ts = log_epoch_secs = time(NULL);
|
|
|
|
|
|
|
|
srv->errh = log_error_st_init();
|
|
|
|
|
|
|
|
config_init(srv);
|
|
|
|
|
|
|
|
srv->request_env = plugins_call_handle_request_env;
|
|
|
|
|
|
|
|
srv->loadavg[0] = 0.0;
|
|
|
|
srv->loadavg[1] = 0.0;
|
|
|
|
srv->loadavg[2] = 0.0;
|
|
|
|
srv->stdin_fd = -1;
|
|
|
|
|
|
|
|
return srv;
|
|
|
|
}
|
|
|
|
|
|
|
|
__attribute_cold__
|
|
|
|
static void server_free(server *srv) {
|
|
|
|
if (oneshot_fd > 0) {
|
|
|
|
close(oneshot_fd);
|
|
|
|
}
|
|
|
|
if (srv->stdin_fd >= 0) {
|
|
|
|
close(srv->stdin_fd);
|
|
|
|
}
|
|
|
|
|
|
|
|
#define CLEAN(x) \
|
|
|
|
buffer_free(srv->x);
|
|
|
|
|
|
|
|
CLEAN(tmp_buf);
|
|
|
|
|
|
|
|
#undef CLEAN
|
|
|
|
|
|
|
|
fdevent_free(srv->ev);
|
|
|
|
|
|
|
|
config_free(srv);
|
|
|
|
|
|
|
|
free(srv->joblist.ptr);
|
|
|
|
free(srv->fdwaitqueue.ptr);
|
|
|
|
|
|
|
|
stat_cache_free();
|
|
|
|
|
|
|
|
li_rand_cleanup();
|
|
|
|
chunkqueue_chunk_pool_free();
|
|
|
|
|
|
|
|
log_error_st_free(srv->errh);
|
|
|
|
free(srv);
|
|
|
|
}
|
|
|
|
|
|
|
|
__attribute_cold__
|
|
|
|
static void remove_pid_file(server *srv) {
|
|
|
|
if (pid_fd <= -2) return;
|
|
|
|
if (!buffer_string_is_empty(srv->srvconf.pid_file) && 0 <= pid_fd) {
|
|
|
|
if (0 != ftruncate(pid_fd, 0)) {
|
|
|
|
log_perror(srv->errh, __FILE__, __LINE__,
|
|
|
|
"ftruncate failed for: %s", srv->srvconf.pid_file->ptr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
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_perror(srv->errh, __FILE__, __LINE__,
|
|
|
|
"unlink failed for: %s", srv->srvconf.pid_file->ptr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
__attribute_cold__
|
|
|
|
static server_socket * server_oneshot_getsock(server *srv, sock_addr *cnt_addr) {
|
|
|
|
server_socket *srv_socket, *srv_socket_wild = NULL;
|
|
|
|
for (uint32_t i = 0; i < srv->srv_sockets.used; ++i) {
|
|
|
|
srv_socket = srv->srv_sockets.ptr[i];
|
|
|
|
if (!sock_addr_is_port_eq(&srv_socket->addr,cnt_addr)) continue;
|
|
|
|
if (sock_addr_is_addr_eq(&srv_socket->addr,cnt_addr)) return srv_socket;
|
|
|
|
|
|
|
|
if (NULL != srv_socket_wild) continue;
|
|
|
|
if (sock_addr_is_addr_wildcard(&srv_socket->addr)) {
|
|
|
|
srv_socket_wild = srv_socket;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (NULL != srv_socket_wild) {
|
|
|
|
return srv_socket_wild;
|
|
|
|
} else if (srv->srv_sockets.used) {
|
|
|
|
return srv->srv_sockets.ptr[0];
|
|
|
|
} else {
|
|
|
|
log_error(srv->errh, __FILE__, __LINE__, "no sockets configured");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
__attribute_cold__
|
|
|
|
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_perror(srv->errh, __FILE__, __LINE__, "fstat()");
|
|
|
|
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(srv->errh, __FILE__, __LINE__,
|
|
|
|
"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_perror(srv->errh, __FILE__, __LINE__, "getsockname()");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
srv_socket = server_oneshot_getsock(srv, &cnt_addr);
|
|
|
|
if (NULL == srv_socket) return 0;
|
|
|
|
|
|
|
|
#ifdef __clang_analyzer__
|
|
|
|
memset(&cnt_addr, 0, sizeof(cnt_addr));
|
|
|
|
#endif
|
|
|
|
cnt_len = sizeof(cnt_addr);
|
|
|
|
if (0 != getpeername(fd, (struct sockaddr *)&cnt_addr, &cnt_len)) {
|
|
|
|
log_perror(srv->errh, __FILE__, __LINE__, "getpeername()");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*(must set flags; fd did not pass through fdevent accept() logic)*/
|
|
|
|
if (-1 == fdevent_fcntl_set_nb_cloexec(fd)) {
|
|
|
|
log_perror(srv->errh, __FILE__, __LINE__, "fcntl()");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sock_addr_get_family(&cnt_addr) != 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(con);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
__attribute_cold__
|
|
|
|
static void show_version (void) {
|
|
|
|
char *b = PACKAGE_DESC TEXT_SSL \
|
|
|
|
" - a light and fast webserver\n"
|
|
|
|
#ifdef NONREPRODUCIBLE_BUILD
|
|
|
|
"Build-Date: " __DATE__ " " __TIME__ "\n";
|
|
|
|
#endif
|
|
|
|
;
|
|
|
|
write_all(STDOUT_FILENO, b, strlen(b));
|
|
|
|
}
|
|
|
|
|
|
|
|
__attribute_cold__
|
|
|
|
static void show_features (void) {
|
|
|
|
static const char features[] =
|
|
|
|
"\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_CRYPTO
|
|
|
|
"\t+ OpenSSL support\n"
|
|
|
|
#else
|
|
|
|
"\t- OpenSSL support\n"
|
|
|
|
#endif
|
|
|
|
#ifdef USE_MBEDTLS_CRYPTO
|
|
|
|
"\t+ mbedTLS support\n"
|
|
|
|
#else
|
|
|
|
"\t- mbedTLS support\n"
|
|
|
|
#endif
|
|
|
|
#ifdef USE_NSS_CRYPTO
|
|
|
|
"\t+ NSS crypto support\n"
|
|
|
|
#else
|
|
|
|
"\t- NSS crypto support\n"
|
|
|
|
#endif
|
|
|
|
#ifdef USE_GNUTLS_CRYPTO
|
|
|
|
"\t+ GnuTLS support\n"
|
|
|
|
#else
|
|
|
|
"\t- GnuTLS support\n"
|
|
|
|
#endif
|
|
|
|
#ifdef USE_WOLFSSL_CRYPTO
|
|
|
|
"\t+ WolfSSL support\n"
|
|
|
|
#else
|
|
|
|
"\t- WolfSSL support\n"
|
|
|
|
#endif
|
|
|
|
#ifdef USE_NETTLE_CRYPTO
|
|
|
|
"\t+ Nettle support\n"
|
|
|
|
#else
|
|
|
|
"\t- Nettle 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_PGSQL
|
|
|
|
"\t+ PgSQL support\n"
|
|
|
|
#else
|
|
|
|
"\t- PgSQL support\n"
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_DBI
|
|
|
|
"\t+ DBI support\n"
|
|
|
|
#else
|
|
|
|
"\t- DBI 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 HAVE_PAM
|
|
|
|
"\t+ PAM support\n"
|
|
|
|
#else
|
|
|
|
"\t- PAM 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
|
|
|
|
;
|
|
|
|
show_version();
|
|
|
|
printf("%s%s%s\n", fdevent_show_event_handlers(), network_write_show_handlers(), features);
|
|
|
|
}
|
|
|
|
|
|
|
|
__attribute_cold__
|
|
|
|
static void show_help (void) {
|
|
|
|
char *b = PACKAGE_DESC TEXT_SSL
|
|
|
|
#ifdef NONREPRODUCIBLE_BUILD
|
|
|
|
" ("__DATE__ " " __TIME__ ")"
|
|
|
|
#endif
|
|
|
|
" - 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"
|
|
|
|
;
|
|
|
|
write_all(STDOUT_FILENO, b, strlen(b));
|
|
|
|
}
|
|
|
|
|
|
|
|
__attribute_cold__
|
|
|
|
static void server_sockets_save (server *srv) { /* graceful_restart */
|
|
|
|
memcpy(&graceful_sockets, &srv->srv_sockets, sizeof(server_socket_array));
|
|
|
|
memset(&srv->srv_sockets, 0, sizeof(server_socket_array));
|
|
|
|
memcpy(&inherited_sockets, &srv->srv_sockets_inherited, sizeof(server_socket_array));
|
|
|
|
memset(&srv->srv_sockets_inherited, 0, sizeof(server_socket_array));
|
|
|
|
}
|
|
|
|
|
|
|
|
__attribute_cold__
|
|
|
|
static void server_sockets_restore (server *srv) { /* graceful_restart */
|
|
|
|
memcpy(&srv->srv_sockets, &graceful_sockets, sizeof(server_socket_array));
|
|
|
|
memset(&graceful_sockets, 0, sizeof(server_socket_array));
|
|
|
|
memcpy(&srv->srv_sockets_inherited, &inherited_sockets, sizeof(server_socket_array));
|
|
|
|
memset(&inherited_sockets, 0, sizeof(server_socket_array));
|
|
|
|
}
|
|
|
|
|
|
|
|
__attribute_cold__
|
|
|
|
static int server_sockets_set_nb_cloexec (server *srv) {
|
|
|
|
if (srv->sockets_disabled) return 0; /* lighttpd -1 (one-shot mode) */
|
|
|
|
for (uint32_t i = 0; i < srv->srv_sockets.used; ++i) {
|
|
|
|
server_socket *srv_socket = srv->srv_sockets.ptr[i];
|
|
|
|
if (-1 == fdevent_fcntl_set_nb_cloexec_sock(srv_socket->fd)) {
|
|
|
|
log_perror(srv->errh, __FILE__, __LINE__, "fcntl()");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
__attribute_cold__
|
|
|
|
static void server_sockets_set_event (server *srv, int event) {
|
|
|
|
for (uint32_t i = 0; i < srv->srv_sockets.used; ++i) {
|
|
|
|
server_socket *srv_socket = srv->srv_sockets.ptr[i];
|
|
|
|
fdevent_fdnode_event_set(srv->ev, srv_socket->fdn, event);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
__attribute_cold__
|
|
|
|
static void server_sockets_unregister (server *srv) {
|
|
|
|
if (2 == srv->sockets_disabled) return;
|
|
|
|
srv->sockets_disabled = 2;
|
|
|
|
for (uint32_t i = 0; i < srv->srv_sockets.used; ++i)
|
|
|
|
network_unregister_sock(srv, srv->srv_sockets.ptr[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
__attribute_cold__
|
|
|
|
static void server_sockets_close (server *srv) {
|
|
|
|
/* closing socket right away will make it possible for the next lighttpd
|
|
|
|
* to take over (old-style graceful restart), but only if backends
|
|
|
|
* (e.g. fastcgi, scgi, etc) are independent from lighttpd, rather
|
|
|
|
* than started by lighttpd via "bin-path")
|
|
|
|
*/
|
|
|
|
if (3 == srv->sockets_disabled) return;
|
|
|
|
for (uint32_t i = 0; i < srv->srv_sockets.used; ++i) {
|
|
|
|
server_socket *srv_socket = srv->srv_sockets.ptr[i];
|
|
|
|
if (-1 == srv_socket->fd) continue;
|
|
|
|
if (2 != srv->sockets_disabled) network_unregister_sock(srv,srv_socket);
|
|
|
|
close(srv_socket->fd);
|
|
|
|
srv_socket->fd = -1;
|
|
|
|
/* network_close() will cleanup after us */
|
|
|
|
}
|
|
|
|
srv->sockets_disabled = 3;
|
|