[core] graceful restart with SIGUSR1 (fixes #2785)
more consistent cleanup of resources at shutdown (e.g. upon error conditions) Notes: graceful restart with SIGUSR1 - not available if chroot()ed, oneshot mode, or if idle timeout occurs - preserve process id (pid) - preserve existing listen sockets - i.e. does not close old listen sockets from prior configs (even if old listen sockets no longer in the new config) (sockets may have been bound w/ root privileges no longer available) - will fail to add listen sockets from new config if privileges lighttpd configured to drop privileges to non-root user, and new listen socket attempts to bind to low-numbered port requiring root privileges. - will fail if listen sockets in new config conflict with any previous old listen sockets - These failure modes will result in lighttpd shutting down instead of graceful restart. These failure modes are not detectable with preflight checks ('lighttpd -tt -f lighttpd.conf') because the new instance of lighttpd running the preflight check does not known config state of n prior graceful restarts, or even the config state of the currently running lighttpd server. - due to lighttpd feature of optionally managing backends (e.g. fastcgi and scgi via "bin-path"), lighttpd must wait for all child processes to exit prior to restarting. Restarting new workers while old workers (and old backends) were still running would result in failure of restarted lighttpd process to be able to bind to sockets already in use by old backends (e.g. unix "socket" path) x-ref: "graceful restart with SIGUSR1" https://redmine.lighttpd.net/issues/2785
This commit is contained in:
parent
b0c66266d9
commit
6c1e6e660e
|
@ -572,6 +572,8 @@ void connections_free(server *srv) {
|
|||
connections *conns = srv->conns;
|
||||
size_t i;
|
||||
|
||||
if (NULL == conns) return;
|
||||
|
||||
for (i = 0; i < conns->size; i++) {
|
||||
connection *con = conns->ptr[i];
|
||||
|
||||
|
@ -617,6 +619,8 @@ void connections_free(server *srv) {
|
|||
}
|
||||
|
||||
free(conns->ptr);
|
||||
free(conns);
|
||||
srv->conns = NULL;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -437,12 +437,7 @@ srv_sockets_append:
|
|||
|
||||
error_free_socket:
|
||||
if (srv_socket->fd != -1) {
|
||||
/* check if server fd are already registered */
|
||||
if (srv_socket->fde_ndx != -1) {
|
||||
fdevent_event_del(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd);
|
||||
fdevent_unregister(srv->ev, srv_socket->fd);
|
||||
}
|
||||
|
||||
network_unregister_sock(srv, srv_socket);
|
||||
close(srv_socket->fd);
|
||||
}
|
||||
buffer_free(srv_socket->srv_token);
|
||||
|
@ -457,14 +452,8 @@ int network_close(server *srv) {
|
|||
size_t i;
|
||||
for (i = 0; i < srv->srv_sockets.used; i++) {
|
||||
server_socket *srv_socket = srv->srv_sockets.ptr[i];
|
||||
|
||||
if (srv_socket->fd != -1) {
|
||||
/* check if server fd are already registered */
|
||||
if (srv_socket->fde_ndx != -1) {
|
||||
fdevent_event_del(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd);
|
||||
fdevent_unregister(srv->ev, srv_socket->fd);
|
||||
}
|
||||
|
||||
network_unregister_sock(srv, srv_socket);
|
||||
close(srv_socket->fd);
|
||||
}
|
||||
|
||||
|
@ -474,6 +463,9 @@ int network_close(server *srv) {
|
|||
}
|
||||
|
||||
free(srv->srv_sockets.ptr);
|
||||
srv->srv_sockets.ptr = NULL;
|
||||
srv->srv_sockets.used = 0;
|
||||
srv->srv_sockets.size = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -520,9 +512,17 @@ int network_init(server *srv) {
|
|||
buffer_append_string_len(b, CONST_STR_LEN(":"));
|
||||
buffer_append_int(b, srv->srvconf.port);
|
||||
|
||||
if (0 != network_server_init(srv, b, 0)) {
|
||||
buffer_free(b);
|
||||
return -1;
|
||||
/* check if we already know this socket, and if yes, don't init it */
|
||||
for (j = 0; j < srv->srv_sockets.used; j++) {
|
||||
if (buffer_is_equal(srv->srv_sockets.ptr[j]->srv_token, b)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (j == srv->srv_sockets.used) {
|
||||
if (0 != network_server_init(srv, b, 0)) {
|
||||
buffer_free(b);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
buffer_free(b);
|
||||
|
||||
|
@ -592,6 +592,12 @@ int network_init(server *srv) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
void network_unregister_sock(server *srv, server_socket *srv_socket) {
|
||||
if (-1 == srv_socket->fd || -1 == srv_socket->fde_ndx) return;
|
||||
fdevent_event_del(srv->ev, &srv_socket->fde_ndx, srv_socket->fd);
|
||||
fdevent_unregister(srv->ev, srv_socket->fd);
|
||||
}
|
||||
|
||||
int network_register_fdevents(server *srv) {
|
||||
size_t i;
|
||||
|
||||
|
|
|
@ -10,5 +10,6 @@ int network_init(server *srv);
|
|||
int network_close(server *srv);
|
||||
|
||||
int network_register_fdevents(server *srv);
|
||||
void network_unregister_sock(server *srv, server_socket *srv_socket);
|
||||
|
||||
#endif
|
||||
|
|
367
src/server.c
367
src/server.c
|
@ -23,6 +23,7 @@
|
|||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
@ -74,8 +75,11 @@
|
|||
#endif
|
||||
|
||||
static int oneshot_fd = 0;
|
||||
static volatile sig_atomic_t srv_shutdown = 0;
|
||||
static volatile int pid_fd = -1;
|
||||
static server_socket_array graceful_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_alarm = 1;
|
||||
static volatile sig_atomic_t handle_sig_hup = 0;
|
||||
static volatile sig_atomic_t forwarded_sig_hup = 0;
|
||||
|
@ -95,9 +99,19 @@ static void sigaction_handler(int sig, siginfo_t *si, void *context) {
|
|||
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) {
|
||||
srv_shutdown = 1;
|
||||
if (2 == graceful_restart)
|
||||
graceful_restart = 1;
|
||||
else
|
||||
srv_shutdown = 1;
|
||||
} else {
|
||||
graceful_shutdown = 1;
|
||||
}
|
||||
|
@ -131,10 +145,15 @@ 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;
|
||||
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: break;
|
||||
|
@ -365,9 +384,10 @@ static void server_free(server *srv) {
|
|||
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)) {
|
||||
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_error_write(srv, __FILE__, __LINE__, "sbds",
|
||||
"ftruncate failed for:",
|
||||
srv->srvconf.pid_file,
|
||||
|
@ -375,9 +395,9 @@ static void remove_pid_file(server *srv, int *pid_fd) {
|
|||
strerror(errno));
|
||||
}
|
||||
}
|
||||
if (0 <= *pid_fd) {
|
||||
close(*pid_fd);
|
||||
*pid_fd = -1;
|
||||
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)) {
|
||||
|
@ -689,6 +709,57 @@ static void show_help (void) {
|
|||
write_all(STDOUT_FILENO, b, strlen(b));
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
static int server_sockets_set_nb_cloexec (server *srv) {
|
||||
if (srv->sockets_disabled) return 0; /* lighttpd -1 (one-shot mode) */
|
||||
for (size_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->ev, srv_socket->fd)) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "ss",
|
||||
"fcntl failed:", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void server_sockets_set_event (server *srv, int event) {
|
||||
for (size_t i = 0; i < srv->srv_sockets.used; ++i) {
|
||||
server_socket *srv_socket = srv->srv_sockets.ptr[i];
|
||||
fdevent_event_set(srv->ev,&(srv_socket->fde_ndx),srv_socket->fd,event);
|
||||
}
|
||||
}
|
||||
|
||||
static void server_sockets_unregister (server *srv) {
|
||||
for (size_t i = 0; i < srv->srv_sockets.used; ++i)
|
||||
network_unregister_sock(srv, srv->srv_sockets.ptr[i]);
|
||||
}
|
||||
|
||||
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")
|
||||
*/
|
||||
for (size_t i = 0; i < srv->srv_sockets.used; ++i) {
|
||||
server_socket *srv_socket = srv->srv_sockets.ptr[i];
|
||||
if (-1 == srv_socket->fd) continue;
|
||||
network_unregister_sock(srv, srv_socket);
|
||||
close(srv_socket->fd);
|
||||
srv_socket->fd = -1;
|
||||
/* network_close() will cleanup after us */
|
||||
}
|
||||
}
|
||||
|
||||
static void server_graceful_shutdown_maint (server *srv) {
|
||||
connections *conns = srv->conns;
|
||||
for (size_t ndx = 0; ndx < conns->used; ++ndx) {
|
||||
|
@ -725,14 +796,41 @@ static void server_graceful_shutdown_maint (server *srv) {
|
|||
}
|
||||
}
|
||||
|
||||
int main (int argc, char **argv) {
|
||||
server *srv = NULL;
|
||||
static void server_graceful_state (server *srv) {
|
||||
|
||||
if (!srv_shutdown) server_graceful_shutdown_maint(srv);
|
||||
|
||||
if (!oneshot_fd) {
|
||||
if (0==srv->srv_sockets.used || -1 == srv->srv_sockets.ptr[0]->fde_ndx)
|
||||
return;
|
||||
}
|
||||
|
||||
log_error_write(srv, __FILE__, __LINE__, "s",
|
||||
"[note] graceful shutdown started");
|
||||
|
||||
/* no graceful restart if chroot()ed, if oneshot mode, or if idle timeout */
|
||||
if (!buffer_string_is_empty(srv->srvconf.changeroot)
|
||||
|| oneshot_fd || 2 == graceful_shutdown)
|
||||
graceful_restart = 0;
|
||||
|
||||
if (graceful_restart) {
|
||||
server_sockets_unregister(srv);
|
||||
if (pid_fd > 0) pid_fd = -pid_fd; /*(flag to skip removing pid file)*/
|
||||
}
|
||||
else {
|
||||
server_sockets_close(srv);
|
||||
remove_pid_file(srv);
|
||||
buffer_reset(srv->srvconf.pid_file); /*(prevent more removal attempts)*/
|
||||
}
|
||||
}
|
||||
|
||||
static int server_main (server * const srv, int argc, char **argv) {
|
||||
int print_config = 0;
|
||||
int test_config = 0;
|
||||
int i_am_root = 0;
|
||||
int o;
|
||||
int num_childs = 0;
|
||||
int pid_fd = -1, fd;
|
||||
int fd;
|
||||
size_t i;
|
||||
time_t idle_limit = 0, last_active_ts = time(NULL);
|
||||
#ifdef HAVE_SIGACTION
|
||||
|
@ -744,14 +842,7 @@ int main (int argc, char **argv) {
|
|||
#endif
|
||||
|
||||
#ifdef HAVE_GETUID
|
||||
#ifndef HAVE_ISSETUGID
|
||||
#define issetugid() (geteuid() != getuid() || getegid() != getgid())
|
||||
#endif
|
||||
i_am_root = (0 == getuid());
|
||||
if (!i_am_root && issetugid()) { /* check as early as possible in main() */
|
||||
fprintf(stderr, "Are you nuts ? Don't apply a SUID bit to this binary\n");
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* initialize globals (including file-scoped static globals) */
|
||||
|
@ -764,16 +855,10 @@ int main (int argc, char **argv) {
|
|||
chunkqueue_set_tempdirs_default_reset();
|
||||
http_auth_dumbdata_reset();
|
||||
http_vhostdb_dumbdata_reset();
|
||||
|
||||
/* for nice %b handling in strfime() */
|
||||
setlocale(LC_TIME, "C");
|
||||
|
||||
if (NULL == (srv = server_init())) {
|
||||
fprintf(stderr, "did this really happen?\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* init structs done */
|
||||
/*graceful_restart = 0;*//*(reset below to avoid further daemonizing)*/
|
||||
/*(intentionally preserved)*/
|
||||
/*memset(graceful_sockets, 0, sizeof(graceful_sockets));*/
|
||||
/*pid_fd = -1;*/
|
||||
|
||||
srv->srvconf.port = 0;
|
||||
srv->srvconf.dont_daemonize = 0;
|
||||
|
@ -785,12 +870,9 @@ int main (int argc, char **argv) {
|
|||
if (srv->config_storage) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "s",
|
||||
"Can only read one config file. Use the include command to use multiple config files.");
|
||||
|
||||
server_free(srv);
|
||||
return -1;
|
||||
}
|
||||
if (config_read(srv, optarg)) {
|
||||
server_free(srv);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
@ -803,7 +885,6 @@ int main (int argc, char **argv) {
|
|||
if (!*optarg || *endptr || timeout < 0) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "ss",
|
||||
"Invalid idle timeout value:", optarg);
|
||||
server_free(srv);
|
||||
return -1;
|
||||
}
|
||||
idle_limit = (time_t)timeout;
|
||||
|
@ -813,12 +894,11 @@ int main (int argc, char **argv) {
|
|||
case 't': ++test_config; break;
|
||||
case '1': oneshot_fd = dup(STDIN_FILENO); break;
|
||||
case 'D': srv->srvconf.dont_daemonize = 1; break;
|
||||
case 'v': show_version(); server_free(srv); return 0;
|
||||
case 'V': show_features(); server_free(srv); return 0;
|
||||
case 'h': show_help(); server_free(srv); return 0;
|
||||
case 'v': show_version(); return 0;
|
||||
case 'V': show_features(); return 0;
|
||||
case 'h': show_help(); return 0;
|
||||
default:
|
||||
show_help();
|
||||
server_free(srv);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
@ -826,8 +906,6 @@ int main (int argc, char **argv) {
|
|||
if (!srv->config_storage) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "s",
|
||||
"No configuration available. Try using -f option.");
|
||||
|
||||
server_free(srv);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -854,7 +932,6 @@ int main (int argc, char **argv) {
|
|||
}
|
||||
|
||||
if (test_config || print_config) {
|
||||
server_free(srv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -862,7 +939,6 @@ int main (int argc, char **argv) {
|
|||
if (oneshot_fd <= STDERR_FILENO) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "s",
|
||||
"Invalid fds at startup with lighttpd -1");
|
||||
server_free(srv);
|
||||
return -1;
|
||||
}
|
||||
graceful_shutdown = 1;
|
||||
|
@ -879,11 +955,14 @@ int main (int argc, char **argv) {
|
|||
/* close stdin and stdout, as they are not needed */
|
||||
openDevNull(STDIN_FILENO);
|
||||
openDevNull(STDOUT_FILENO);
|
||||
{
|
||||
struct stat st;
|
||||
if (0 != fstat(STDERR_FILENO, &st)) openDevNull(STDERR_FILENO);
|
||||
}
|
||||
|
||||
if (0 != config_set_defaults(srv)) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "s",
|
||||
"setting default values failed");
|
||||
server_free(srv);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -891,24 +970,17 @@ int main (int argc, char **argv) {
|
|||
if (buffer_string_is_empty(srv->config_storage[0]->document_root)) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "s",
|
||||
"document-root is not set\n");
|
||||
|
||||
server_free(srv);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (plugins_load(srv)) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "s",
|
||||
"loading plugins finally failed");
|
||||
|
||||
plugins_free(srv);
|
||||
server_free(srv);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* open pid file BEFORE chroot */
|
||||
if (!buffer_string_is_empty(srv->srvconf.pid_file)) {
|
||||
if (-1 == pid_fd && !buffer_string_is_empty(srv->srvconf.pid_file)) {
|
||||
if (-1 == (pid_fd = fdevent_open_cloexec(srv->srvconf.pid_file->ptr, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) {
|
||||
struct stat st;
|
||||
if (errno != EEXIST) {
|
||||
|
@ -1004,9 +1076,6 @@ int main (int argc, char **argv) {
|
|||
|
||||
/* we need root-perms for port < 1024 */
|
||||
if (0 != network_init(srv)) {
|
||||
plugins_free(srv);
|
||||
server_free(srv);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -1118,27 +1187,23 @@ int main (int argc, char **argv) {
|
|||
|
||||
if (HANDLER_GO_ON != plugins_call_init(srv)) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "s", "Initialization of plugins failed. Going down.");
|
||||
|
||||
plugins_free(srv);
|
||||
network_close(srv);
|
||||
server_free(srv);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef HAVE_FORK
|
||||
/* network is up, let's deamonize ourself */
|
||||
if (srv->srvconf.dont_daemonize == 0) {
|
||||
/* network is up, let's daemonize ourself */
|
||||
if (0 == srv->srvconf.dont_daemonize && 0 == graceful_restart) {
|
||||
parent_pipe_fd = daemonize();
|
||||
}
|
||||
#endif
|
||||
graceful_restart = 0;/*(reset here after avoiding further daemonizing)*/
|
||||
graceful_shutdown= 0;
|
||||
|
||||
|
||||
#ifdef HAVE_SIGACTION
|
||||
memset(&act, 0, sizeof(act));
|
||||
act.sa_handler = SIG_IGN;
|
||||
sigaction(SIGPIPE, &act, NULL);
|
||||
sigaction(SIGUSR1, &act, NULL);
|
||||
# if defined(SA_SIGINFO)
|
||||
last_sighup_info.si_uid = 0,
|
||||
last_sighup_info.si_pid = 0;
|
||||
|
@ -1156,6 +1221,7 @@ int main (int argc, char **argv) {
|
|||
sigaction(SIGTERM, &act, NULL);
|
||||
sigaction(SIGHUP, &act, NULL);
|
||||
sigaction(SIGALRM, &act, NULL);
|
||||
sigaction(SIGUSR1, &act, NULL);
|
||||
|
||||
/* it should be safe to restart syscalls after SIGCHLD */
|
||||
act.sa_flags |= SA_RESTART | SA_NOCLDSTOP;
|
||||
|
@ -1164,12 +1230,12 @@ int main (int argc, char **argv) {
|
|||
#elif defined(HAVE_SIGNAL)
|
||||
/* ignore the SIGPIPE from sendfile() */
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
signal(SIGUSR1, SIG_IGN);
|
||||
signal(SIGALRM, signal_handler);
|
||||
signal(SIGTERM, signal_handler);
|
||||
signal(SIGHUP, signal_handler);
|
||||
signal(SIGCHLD, signal_handler);
|
||||
signal(SIGINT, signal_handler);
|
||||
signal(SIGUSR1, signal_handler);
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -1177,34 +1243,28 @@ int main (int argc, char **argv) {
|
|||
srv->uid = getuid();
|
||||
|
||||
/* write pid file */
|
||||
if (pid_fd != -1) {
|
||||
if (pid_fd > 2) {
|
||||
buffer_copy_int(srv->tmp_buf, getpid());
|
||||
buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN("\n"));
|
||||
if (-1 == write_all(pid_fd, CONST_BUF_LEN(srv->tmp_buf))) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "ss", "Couldn't write pid file:", strerror(errno));
|
||||
close(pid_fd);
|
||||
pid_fd = -1;
|
||||
return -1;
|
||||
}
|
||||
} else if (pid_fd < -2) {
|
||||
pid_fd = -pid_fd;
|
||||
}
|
||||
|
||||
/* Close stderr ASAP in the child process to make sure that nothing
|
||||
* is being written to that fd which may not be valid anymore. */
|
||||
if (!srv->srvconf.preflight_check && -1 == log_error_open(srv)) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "s", "Opening errorlog failed. Going down.");
|
||||
|
||||
plugins_free(srv);
|
||||
network_close(srv);
|
||||
server_free(srv);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (HANDLER_GO_ON != plugins_call_set_defaults(srv)) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "s", "Configuration of plugins failed. Going down.");
|
||||
|
||||
plugins_free(srv);
|
||||
network_close(srv);
|
||||
server_free(srv);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -1244,20 +1304,12 @@ int main (int argc, char **argv) {
|
|||
}
|
||||
|
||||
if (srv->config_unsupported || srv->config_deprecated) {
|
||||
plugins_free(srv);
|
||||
network_close(srv);
|
||||
server_free(srv);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (srv->srvconf.preflight_check) {
|
||||
/*printf("Preflight OK");*//*(stdout reopened to /dev/null)*/
|
||||
plugins_free(srv);
|
||||
network_close(srv);
|
||||
server_free(srv);
|
||||
|
||||
exit(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1266,7 +1318,7 @@ int main (int argc, char **argv) {
|
|||
* notify daemonize-grandparent of successful startup
|
||||
* do this before any further forking is done (workers)
|
||||
*/
|
||||
if (srv->srvconf.dont_daemonize == 0) {
|
||||
if (0 == srv->srvconf.dont_daemonize && -1 != parent_pipe_fd) {
|
||||
if (0 > write(parent_pipe_fd, "", 1)) return -1;
|
||||
close(parent_pipe_fd);
|
||||
}
|
||||
|
@ -1338,21 +1390,30 @@ int main (int argc, char **argv) {
|
|||
/**
|
||||
* kill all children too
|
||||
*/
|
||||
if (graceful_shutdown) {
|
||||
if (graceful_shutdown || graceful_restart) {
|
||||
/* flag to ignore one SIGINT if graceful_restart */
|
||||
if (graceful_restart) graceful_restart = 2;
|
||||
kill(0, SIGINT);
|
||||
server_graceful_state(srv);
|
||||
} else if (srv_shutdown) {
|
||||
kill(0, SIGTERM);
|
||||
}
|
||||
|
||||
remove_pid_file(srv, &pid_fd);
|
||||
log_error_close(srv);
|
||||
network_close(srv);
|
||||
connections_free(srv);
|
||||
plugins_free(srv);
|
||||
server_free(srv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ignore SIGUSR1 in workers; only parent directs graceful restart */
|
||||
#ifdef HAVE_SIGACTION
|
||||
{
|
||||
struct sigaction actignore;
|
||||
memset(&actignore, 0, sizeof(actignore));
|
||||
actignore.sa_handler = SIG_IGN;
|
||||
sigaction(SIGUSR1, &actignore, NULL);
|
||||
}
|
||||
#elif defined(HAVE_SIGNAL)
|
||||
signal(SIGUSR1, SIG_IGN);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* make sure workers do not muck with pid-file
|
||||
*/
|
||||
|
@ -1385,10 +1446,6 @@ int main (int argc, char **argv) {
|
|||
*
|
||||
* */
|
||||
if (0 != network_register_fdevents(srv)) {
|
||||
plugins_free(srv);
|
||||
network_close(srv);
|
||||
server_free(srv);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -1437,13 +1494,8 @@ int main (int argc, char **argv) {
|
|||
srv->cur_fds = open("/dev/null", O_RDONLY);
|
||||
close(srv->cur_fds);
|
||||
|
||||
for (i = 0; i < srv->srv_sockets.used; i++) {
|
||||
server_socket *srv_socket = srv->srv_sockets.ptr[i];
|
||||
if (srv->sockets_disabled) continue; /* lighttpd -1 (one-shot mode) */
|
||||
if (-1 == fdevent_fcntl_set_nb_cloexec_sock(srv->ev, srv_socket->fd)) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed:", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
if (0 != server_sockets_set_nb_cloexec(srv)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (oneshot_fd && server_oneshot_init(srv, oneshot_fd)) {
|
||||
|
@ -1528,6 +1580,11 @@ int main (int argc, char **argv) {
|
|||
log_error_write(srv, __FILE__, __LINE__, "sDs", "[note] idle timeout", (int)idle_limit,
|
||||
"s exceeded, initiating graceful shutdown");
|
||||
graceful_shutdown = 2; /* value 2 indicates idle timeout */
|
||||
if (graceful_restart) {
|
||||
graceful_restart = 0;
|
||||
if (pid_fd < -2) pid_fd = -pid_fd;
|
||||
server_sockets_close(srv);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_GETLOADAVG
|
||||
|
@ -1657,54 +1714,26 @@ int main (int argc, char **argv) {
|
|||
}
|
||||
}
|
||||
|
||||
if (srv->sockets_disabled) {
|
||||
if (graceful_shutdown) {
|
||||
server_graceful_state(srv);
|
||||
srv->sockets_disabled = 1;
|
||||
} else if (srv->sockets_disabled) {
|
||||
/* our server sockets are disabled, why ? */
|
||||
|
||||
if ((srv->cur_fds + srv->want_fds < srv->max_fds * 8 / 10) && /* we have enough unused fds */
|
||||
(srv->conns->used <= srv->max_conns * 9 / 10) &&
|
||||
(0 == graceful_shutdown)) {
|
||||
for (i = 0; i < srv->srv_sockets.used; i++) {
|
||||
server_socket *srv_socket = srv->srv_sockets.ptr[i];
|
||||
fdevent_event_set(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd, FDEVENT_IN);
|
||||
}
|
||||
|
||||
(srv->conns->used <= srv->max_conns * 9 / 10)) {
|
||||
server_sockets_set_event(srv, FDEVENT_IN);
|
||||
log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets enabled again");
|
||||
|
||||
srv->sockets_disabled = 0;
|
||||
}
|
||||
} else {
|
||||
if ((srv->cur_fds + srv->want_fds > srv->max_fds * 9 / 10) || /* out of fds */
|
||||
(srv->conns->used >= srv->max_conns) || /* out of connections */
|
||||
(graceful_shutdown)) { /* graceful_shutdown */
|
||||
|
||||
(srv->conns->used >= srv->max_conns)) { /* out of connections */
|
||||
/* disable server-fds */
|
||||
server_sockets_set_event(srv, 0);
|
||||
|
||||
for (i = 0; i < srv->srv_sockets.used; i++) {
|
||||
server_socket *srv_socket = srv->srv_sockets.ptr[i];
|
||||
|
||||
if (graceful_shutdown) {
|
||||
/* we don't want this socket anymore,
|
||||
*
|
||||
* closing it right away will make it possible for
|
||||
* the next lighttpd to take over (graceful restart)
|
||||
* */
|
||||
|
||||
fdevent_event_del(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd);
|
||||
fdevent_unregister(srv->ev, srv_socket->fd);
|
||||
close(srv_socket->fd);
|
||||
srv_socket->fd = -1;
|
||||
|
||||
/* network_close() will cleanup after us */
|
||||
} else {
|
||||
fdevent_event_set(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (graceful_shutdown) {
|
||||
remove_pid_file(srv, &pid_fd);
|
||||
log_error_write(srv, __FILE__, __LINE__, "s", "[note] graceful shutdown started");
|
||||
if (!srv_shutdown) server_graceful_shutdown_maint(srv);
|
||||
} else if (srv->conns->used >= srv->max_conns) {
|
||||
if (srv->conns->used >= srv->max_conns) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets disabled, connection limit reached");
|
||||
} else {
|
||||
log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets disabled, out-of-fds");
|
||||
|
@ -1771,8 +1800,8 @@ int main (int argc, char **argv) {
|
|||
srv->joblist->used = 0;
|
||||
}
|
||||
|
||||
if (0 == graceful_shutdown) {
|
||||
remove_pid_file(srv, &pid_fd);
|
||||
if (graceful_shutdown || graceful_restart) {
|
||||
server_graceful_state(srv);
|
||||
}
|
||||
|
||||
if (2 == graceful_shutdown) { /* value 2 indicates idle timeout */
|
||||
|
@ -1791,12 +1820,52 @@ int main (int argc, char **argv) {
|
|||
#endif
|
||||
}
|
||||
|
||||
/* clean-up */
|
||||
log_error_close(srv);
|
||||
network_close(srv);
|
||||
connections_free(srv);
|
||||
plugins_free(srv);
|
||||
server_free(srv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main (int argc, char **argv) {
|
||||
int rc;
|
||||
|
||||
#ifdef HAVE_GETUID
|
||||
#ifndef HAVE_ISSETUGID
|
||||
#define issetugid() (geteuid() != getuid() || getegid() != getgid())
|
||||
#endif
|
||||
if (0 != getuid() && issetugid()) { /*check as early as possible in main()*/
|
||||
fprintf(stderr,
|
||||
"Are you nuts ? Don't apply a SUID bit to this binary\n");
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* for nice %b handling in strftime() */
|
||||
setlocale(LC_TIME, "C");
|
||||
|
||||
do {
|
||||
server * const srv = server_init();
|
||||
|
||||
if (graceful_restart) {
|
||||
server_sockets_restore(srv);
|
||||
optind = 1;
|
||||
}
|
||||
|
||||
rc = server_main(srv, argc, argv);
|
||||
|
||||
/* clean-up */
|
||||
remove_pid_file(srv);
|
||||
log_error_close(srv);
|
||||
if (graceful_restart)
|
||||
server_sockets_save(srv);
|
||||
else
|
||||
network_close(srv);
|
||||
connections_free(srv);
|
||||
plugins_free(srv);
|
||||
server_free(srv);
|
||||
|
||||
if (0 != rc || !graceful_restart) break;
|
||||
|
||||
/* wait for all children to exit before graceful restart */
|
||||
while (waitpid(-1, NULL, 0) > 0) ;
|
||||
} while (graceful_restart);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue