[core] restart piped loggers if they exit (fixes #1393)
x-ref: "access log pipe writer should restart child process if it exits" https://redmine.lighttpd.net/issues/1393
This commit is contained in:
parent
167cdc846c
commit
adeec956c3
146
src/fdevent.c
146
src/fdevent.c
|
@ -6,6 +6,7 @@
|
|||
#include "log.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include "sys-socket.h"
|
||||
|
||||
#include <unistd.h>
|
||||
|
@ -13,6 +14,7 @@
|
|||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
|
||||
#ifdef SOCK_CLOEXEC
|
||||
static int use_sock_cloexec;
|
||||
|
@ -538,10 +540,24 @@ pid_t fdevent_fork_execve(const char *name, char *argv[], char *envp[], int fdin
|
|||
}
|
||||
|
||||
|
||||
static int fdevent_open_logger_pipe(const char *logger) {
|
||||
/* create write pipe and spawn process */
|
||||
typedef struct fdevent_cmd_pipe {
|
||||
pid_t pid;
|
||||
int fds[2];
|
||||
const char *cmd;
|
||||
time_t start;
|
||||
} fdevent_cmd_pipe;
|
||||
|
||||
typedef struct fdevent_cmd_pipes {
|
||||
fdevent_cmd_pipe *ptr;
|
||||
size_t used;
|
||||
size_t size;
|
||||
} fdevent_cmd_pipes;
|
||||
|
||||
static fdevent_cmd_pipes cmd_pipes;
|
||||
|
||||
|
||||
static pid_t fdevent_open_logger_pipe_spawn(const char *logger, int rfd) {
|
||||
char *args[4];
|
||||
int to_log_fds[2];
|
||||
int devnull = fdevent_open_devnull();
|
||||
pid_t pid;
|
||||
|
||||
|
@ -549,31 +565,129 @@ static int fdevent_open_logger_pipe(const char *logger) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (pipe(to_log_fds)) {
|
||||
close(devnull);
|
||||
return -1;
|
||||
}
|
||||
fdevent_setfd_cloexec(to_log_fds[0]);
|
||||
fdevent_setfd_cloexec(to_log_fds[1]);
|
||||
|
||||
*(const char **)&args[0] = "/bin/sh";
|
||||
*(const char **)&args[1] = "-c";
|
||||
*(const char **)&args[2] = logger;
|
||||
args[3] = NULL;
|
||||
|
||||
pid = fdevent_fork_execve(args[0], args, NULL, to_log_fds[0], devnull, devnull, -1);
|
||||
pid = fdevent_fork_execve(args[0], args, NULL, rfd, devnull, devnull, -1);
|
||||
|
||||
if (pid > 0) {
|
||||
/*(future: save pipe fds, pid, and command line to restart if child exits)*/
|
||||
close(devnull);
|
||||
close(to_log_fds[0]);
|
||||
return to_log_fds[1];
|
||||
}
|
||||
else {
|
||||
int errnum = errno;
|
||||
close(devnull);
|
||||
close(to_log_fds[0]);
|
||||
close(to_log_fds[1]);
|
||||
errno = errnum;
|
||||
}
|
||||
return pid;
|
||||
}
|
||||
|
||||
|
||||
static void fdevent_waitpid_logger_pipe(fdevent_cmd_pipe *fcp, time_t ts) {
|
||||
pid_t pid = fcp->pid;
|
||||
if (pid > 0) {
|
||||
switch (waitpid(pid, NULL, WNOHANG)) {
|
||||
case 0: return;
|
||||
case -1: if (errno == EINTR) return; /* fall through */
|
||||
default: break;
|
||||
}
|
||||
fcp->pid = -1;
|
||||
}
|
||||
if (fcp->start + 5 < ts) { /* limit restart to once every 5 sec */
|
||||
/* restart child process using existing pipe fds */
|
||||
fcp->start = ts;
|
||||
fcp->pid = fdevent_open_logger_pipe_spawn(fcp->cmd, fcp->fds[0]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void fdevent_waitpid_logger_pipes(time_t ts) {
|
||||
for (size_t i = 0; i < cmd_pipes.used; ++i) {
|
||||
fdevent_waitpid_logger_pipe(cmd_pipes.ptr+i, ts);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int fdevent_reaped_logger_pipe(pid_t pid) {
|
||||
for (size_t i = 0; i < cmd_pipes.used; ++i) {
|
||||
fdevent_cmd_pipe *fcp = cmd_pipes.ptr+i;
|
||||
if (fcp->pid == pid) {
|
||||
time_t ts = time(NULL);
|
||||
if (fcp->start + 5 < ts) { /* limit restart to once every 5 sec */
|
||||
fcp->start = ts;
|
||||
fcp->pid = fdevent_open_logger_pipe_spawn(fcp->cmd,fcp->fds[0]);
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
fcp->pid = -1;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void fdevent_close_logger_pipes(void) {
|
||||
for (size_t i = 0; i < cmd_pipes.used; ++i) {
|
||||
fdevent_cmd_pipe *fcp = cmd_pipes.ptr+i;
|
||||
close(fcp->fds[0]);
|
||||
if (fcp->fds[1] != STDERR_FILENO) close(fcp->fds[1]);
|
||||
}
|
||||
free(cmd_pipes.ptr);
|
||||
cmd_pipes.ptr = NULL;
|
||||
cmd_pipes.used = 0;
|
||||
cmd_pipes.size = 0;
|
||||
}
|
||||
|
||||
|
||||
void fdevent_breakagelog_logger_pipe(int fd) {
|
||||
for (size_t i = 0; i < cmd_pipes.used; ++i) {
|
||||
fdevent_cmd_pipe *fcp = cmd_pipes.ptr+i;
|
||||
if (fcp->fds[1] != fd) continue;
|
||||
fcp->fds[1] = STDERR_FILENO;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void fdevent_init_logger_pipe(const char *cmd, int fds[2], pid_t pid) {
|
||||
fdevent_cmd_pipe *fcp;
|
||||
if (cmd_pipes.used == cmd_pipes.size) {
|
||||
cmd_pipes.size += 4;
|
||||
cmd_pipes.ptr =
|
||||
realloc(cmd_pipes.ptr, cmd_pipes.size * sizeof(fdevent_cmd_pipe));
|
||||
force_assert(cmd_pipes.ptr);
|
||||
}
|
||||
fcp = cmd_pipes.ptr + cmd_pipes.used++;
|
||||
fcp->cmd = cmd; /* note: cmd must persist in memory (or else copy here) */
|
||||
fcp->fds[0] = fds[0];
|
||||
fcp->fds[1] = fds[1];
|
||||
fcp->pid = pid;
|
||||
fcp->start = time(NULL);
|
||||
}
|
||||
|
||||
|
||||
static int fdevent_open_logger_pipe(const char *logger) {
|
||||
int fds[2];
|
||||
pid_t pid;
|
||||
if (pipe(fds)) {
|
||||
return -1;
|
||||
}
|
||||
fdevent_setfd_cloexec(fds[0]);
|
||||
fdevent_setfd_cloexec(fds[1]);
|
||||
|
||||
pid = fdevent_open_logger_pipe_spawn(logger, fds[0]);
|
||||
|
||||
if (pid > 0) {
|
||||
fdevent_init_logger_pipe(logger, fds, pid);
|
||||
return fds[1];
|
||||
}
|
||||
else {
|
||||
int errnum = errno;
|
||||
close(fds[0]);
|
||||
close(fds[1]);
|
||||
errno = errnum;
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -225,6 +225,10 @@ int fdevent_set_stdin_stdout_stderr(int fdin, int fdout, int fderr);
|
|||
pid_t fdevent_fork_execve(const char *name, char *argv[], char *envp[], int fdin, int fdout, int fderr, int dfd);
|
||||
int fdevent_open_logger(const char *logger);
|
||||
int fdevent_cycle_logger(const char *logger, int *curfd);
|
||||
int fdevent_reaped_logger_pipe(pid_t pid);
|
||||
void fdevent_waitpid_logger_pipes(time_t ts);
|
||||
void fdevent_close_logger_pipes(void);
|
||||
void fdevent_breakagelog_logger_pipe(int fd);
|
||||
|
||||
int fdevent_select_init(fdevents *ev);
|
||||
int fdevent_poll_init(fdevents *ev);
|
||||
|
|
|
@ -445,7 +445,11 @@ FREE_FUNC(mod_accesslog_free) {
|
|||
}
|
||||
}
|
||||
|
||||
if (s->log_access_fd != -1) close(s->log_access_fd);
|
||||
if (s->log_access_fd != -1) {
|
||||
if (buffer_string_is_empty(s->access_logfile) || *s->access_logfile->ptr != '|') {
|
||||
close(s->log_access_fd);
|
||||
} /*(else piped loggers closed in fdevent_close_logger_pipes())*/
|
||||
}
|
||||
|
||||
buffer_free(s->ts_accesslog_str);
|
||||
buffer_free(s->access_logbuffer);
|
||||
|
|
19
src/server.c
19
src/server.c
|
@ -843,6 +843,8 @@ static int log_error_open(server *srv) {
|
|||
"' failed: ", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (*logfile == '|') fdevent_breakagelog_logger_pipe(errfd);
|
||||
}
|
||||
else if (!srv->srvconf.dont_daemonize) {
|
||||
/* move STDERR_FILENO to /dev/null */
|
||||
|
@ -900,8 +902,11 @@ static int log_error_close(server *srv) {
|
|||
case ERRORLOG_FD:
|
||||
if (-1 != srv->errorlog_fd) {
|
||||
/* don't close STDERR */
|
||||
if (STDERR_FILENO != srv->errorlog_fd)
|
||||
/* fdevent_close_logger_pipes() closes ERRORLOG_PIPE */
|
||||
if (STDERR_FILENO != srv->errorlog_fd
|
||||
&& srv->errorlog_mode != ERRORLOG_PIPE) {
|
||||
close(srv->errorlog_fd);
|
||||
}
|
||||
srv->errorlog_fd = -1;
|
||||
}
|
||||
break;
|
||||
|
@ -1598,6 +1603,11 @@ static int server_main (server * const srv, int argc, char **argv) {
|
|||
int status;
|
||||
|
||||
if (-1 != (pid = wait(&status))) {
|
||||
switch (fdevent_reaped_logger_pipe(pid)) {
|
||||
default: break;
|
||||
case -1: alarm(5); /* fall through */
|
||||
case 1: continue;
|
||||
}
|
||||
/**
|
||||
* check if one of our workers went away
|
||||
*/
|
||||
|
@ -1630,6 +1640,10 @@ static int server_main (server * const srv, int argc, char **argv) {
|
|||
kill(0, SIGHUP);
|
||||
}
|
||||
}
|
||||
if (handle_sig_alarm) {
|
||||
handle_sig_alarm = 0;
|
||||
fdevent_waitpid_logger_pipes(time(NULL));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -1844,6 +1858,8 @@ static int server_main (server * const srv, int argc, char **argv) {
|
|||
for (i = 0; i < srv->config_context->used; ++i) {
|
||||
srv->config_storage[i]->global_bytes_per_second_cnt = 0;
|
||||
}
|
||||
/* check piped-loggers and restart, unless shutting down */
|
||||
if (!graceful_shutdown && !srv_shutdown && 0 == srv->srvconf.max_worker) fdevent_waitpid_logger_pipes(min_ts);
|
||||
/* if graceful_shutdown, accelerate cleanup of recently completed request/responses */
|
||||
if (graceful_shutdown && !srv_shutdown) server_graceful_shutdown_maint(srv);
|
||||
/**
|
||||
|
@ -2095,6 +2111,7 @@ int main (int argc, char **argv) {
|
|||
/* clean-up */
|
||||
remove_pid_file(srv);
|
||||
log_error_close(srv);
|
||||
fdevent_close_logger_pipes();
|
||||
if (graceful_restart)
|
||||
server_sockets_save(srv);
|
||||
else
|
||||
|
|
Loading…
Reference in New Issue