Add support for pipe logging for server.errorlog (fixes #296)

git-svn-id: svn://svn.lighttpd.net/lighttpd/branches/lighttpd-1.4.x@2466 152afb58-edef-0310-8abb-c4023f1b3aa9
svn/tags/lighttpd-1.4.23
Stefan Bühler 2009-04-10 10:50:51 +00:00
parent a8ad0477a8
commit 1527160c69
6 changed files with 95 additions and 91 deletions

1
NEWS
View File

@ -18,6 +18,7 @@ NEWS
* Add proper SUID bit detection (fixes #416)
* Check for regular file in mod_cgi, so we don't try to start directories
* Include mmap.h from chunk.h to fix some problems with #define mmap mmap64 (fixes #1923)
* Add support for pipe logging for server.errorlog (fixes #296)
- 1.4.22 - 2009-03-07
* Fix wrong lua type for CACHE_MISS/CACHE_HIT in mod_cml (fixes #533)

View File

@ -537,7 +537,7 @@ typedef struct server {
/* the errorlog */
int errorlog_fd;
enum { ERRORLOG_STDERR, ERRORLOG_FILE, ERRORLOG_SYSLOG } errorlog_mode;
enum { ERRORLOG_STDERR, ERRORLOG_FILE, ERRORLOG_SYSLOG, ERRORLOG_PIPE } errorlog_mode;
buffer *errorlog_buf;
fdevents *ev, *ev_ins;

102
src/log.c
View File

@ -54,13 +54,94 @@ int openDevNull(int fd) {
return (tmpfd != -1) ? 0 : -1;
}
int open_logfile_or_pipe(server *srv, const char* logfile) {
int fd;
if (logfile[0] == '|') {
#ifdef HAVE_FORK
/* create write pipe and spawn process */
int to_log_fds[2];
pid_t pid;
int i;
if (pipe(to_log_fds)) {
log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed: ", strerror(errno));
return -1;
}
/* fork, execve */
switch (pid = fork()) {
case 0:
/* child */
close(STDIN_FILENO);
/* dup the filehandle to STDIN */
if (to_log_fds[0] != STDIN_FILENO) {
if (STDIN_FILENO != dup2(to_log_fds[0], STDIN_FILENO)) {
log_error_write(srv, __FILE__, __LINE__, "ss",
"dup2 failed: ", strerror(errno));
exit(-1);
}
close(to_log_fds[0]);
}
close(to_log_fds[1]);
#ifndef FD_CLOEXEC
/* we don't need the client socket */
for (i = 3; i < 256; i++) {
close(i);
}
#endif
/* close old stderr */
openDevNull(STDERR_FILENO);
/* exec the log-process (skip the | ) */
execl("/bin/sh", "sh", "-c", logfile + 1, NULL);
log_error_write(srv, __FILE__, __LINE__, "sss",
"spawning log process failed: ", strerror(errno),
logfile + 1);
exit(-1);
break;
case -1:
/* error */
log_error_write(srv, __FILE__, __LINE__, "ss", "fork failed: ", strerror(errno));
return -1;
default:
close(to_log_fds[0]);
fd = to_log_fds[1];
break;
}
#else
return -1;
#endif
} else if (-1 == (fd = open(logfile, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
log_error_write(srv, __FILE__, __LINE__, "SSSS",
"opening errorlog '", logfile,
"' failed: ", strerror(errno));
return -1;
}
#ifdef FD_CLOEXEC
fcntl(fd, F_SETFD, FD_CLOEXEC);
#endif
return fd;
}
/**
* open the errorlog
*
* we have 3 possibilities:
* we have 4 possibilities:
* - stderr (default)
* - syslog
* - logfile
* - pipe
*
* if the open failed, report to the user and die
*
@ -80,18 +161,10 @@ int log_error_open(server *srv) {
} else if (!buffer_is_empty(srv->srvconf.errorlog_file)) {
const char *logfile = srv->srvconf.errorlog_file->ptr;
if (-1 == (srv->errorlog_fd = open(logfile, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
log_error_write(srv, __FILE__, __LINE__, "SSSS",
"opening errorlog '", logfile,
"' failed: ", strerror(errno));
if (-1 == (srv->errorlog_fd = open_logfile_or_pipe(srv, logfile))) {
return -1;
}
#ifdef FD_CLOEXEC
/* close fd on exec (cgi) */
fcntl(srv->errorlog_fd, F_SETFD, FD_CLOEXEC);
#endif
srv->errorlog_mode = ERRORLOG_FILE;
srv->errorlog_mode = (logfile[0] == '|') ? ERRORLOG_PIPE : ERRORLOG_FILE;
}
log_error_write(srv, __FILE__, __LINE__, "s", "server started");
@ -122,7 +195,7 @@ int log_error_open(server *srv) {
*/
int log_error_cycle(server *srv) {
/* only cycle if we are not in syslog-mode */
/* only cycle if the error log is a file */
if (srv->errorlog_mode == ERRORLOG_FILE) {
const char *logfile = srv->srvconf.errorlog_file->ptr;
@ -130,7 +203,7 @@ int log_error_cycle(server *srv) {
int new_fd;
if (-1 == (new_fd = open(logfile, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
if (-1 == (new_fd = open_logfile_or_pipe(srv, logfile))) {
/* write to old log */
log_error_write(srv, __FILE__, __LINE__, "SSSSS",
"cycling errorlog '", logfile,
@ -158,6 +231,7 @@ int log_error_cycle(server *srv) {
int log_error_close(server *srv) {
switch(srv->errorlog_mode) {
case ERRORLOG_PIPE:
case ERRORLOG_FILE:
close(srv->errorlog_fd);
break;
@ -177,6 +251,7 @@ int log_error_write(server *srv, const char *filename, unsigned int line, const
va_list ap;
switch(srv->errorlog_mode) {
case ERRORLOG_PIPE:
case ERRORLOG_FILE:
case ERRORLOG_STDERR:
/* cache the generated timestamp */
@ -270,6 +345,7 @@ int log_error_write(server *srv, const char *filename, unsigned int line, const
va_end(ap);
switch(srv->errorlog_mode) {
case ERRORLOG_PIPE:
case ERRORLOG_FILE:
buffer_append_string_len(srv->errorlog_buf, CONST_STR_LEN("\n"));
write(srv->errorlog_fd, srv->errorlog_buf->ptr, srv->errorlog_buf->used - 1);

View File

@ -10,6 +10,8 @@ int openDevNull(int fd);
#define WP() log_error_write(srv, __FILE__, __LINE__, "");
int open_logfile_or_pipe(server *srv, const char* logfile);
int log_error_open(server *srv);
int log_error_close(server *srv);
int log_error_write(server *srv, const char *filename, unsigned int line, const char *fmt, ...);

View File

@ -475,74 +475,9 @@ SETDEFAULTS_FUNC(log_access_open) {
if (s->access_logfile->used < 2) continue;
if (s->access_logfile->ptr[0] == '|') {
#ifdef HAVE_FORK
/* create write pipe and spawn process */
int to_log_fds[2];
pid_t pid;
if (pipe(to_log_fds)) {
log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed: ", strerror(errno));
return HANDLER_ERROR;
}
/* fork, execve */
switch (pid = fork()) {
case 0:
/* child */
close(STDIN_FILENO);
dup2(to_log_fds[0], STDIN_FILENO);
close(to_log_fds[0]);
/* not needed */
close(to_log_fds[1]);
openDevNull(STDERR_FILENO);
/* we don't need the client socket */
for (i = 3; i < 256; i++) {
close(i);
}
/* exec the log-process (skip the | )
*
*/
execl("/bin/sh", "sh", "-c", s->access_logfile->ptr + 1, (char *)NULL);
log_error_write(srv, __FILE__, __LINE__, "sss",
"spawning log-process failed: ", strerror(errno),
s->access_logfile->ptr + 1);
exit(-1);
break;
case -1:
/* error */
log_error_write(srv, __FILE__, __LINE__, "ss", "fork failed: ", strerror(errno));
break;
default:
close(to_log_fds[0]);
s->log_access_fd = to_log_fds[1];
break;
}
#else
return -1;
#endif
} else if (-1 == (s->log_access_fd =
open(s->access_logfile->ptr, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
log_error_write(srv, __FILE__, __LINE__, "ssb",
"opening access-log failed:",
strerror(errno), s->access_logfile);
if (-1 == (s->log_access_fd = open_logfile_or_pipe(srv, s->access_logfile->ptr)))
return HANDLER_ERROR;
}
#ifdef FD_CLOEXEC
fcntl(s->log_access_fd, F_SETFD, FD_CLOEXEC);
#endif
}
return HANDLER_GO_ON;

View File

@ -777,16 +777,6 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer *
/* not needed */
close(to_cgi_fds[1]);
/* HACK:
* this is not nice, but it works
*
* we feed the stderr of the CGI to our errorlog, if possible
*/
if (srv->errorlog_mode == ERRORLOG_FILE) {
close(STDERR_FILENO);
dup2(srv->errorlog_fd, STDERR_FILENO);
}
/* create environment */
env.ptr = NULL;
env.size = 0;