diff options
author | stbuehler <stbuehler@152afb58-edef-0310-8abb-c4023f1b3aa9> | 2009-06-21 17:26:22 +0000 |
---|---|---|
committer | stbuehler <stbuehler@152afb58-edef-0310-8abb-c4023f1b3aa9> | 2009-06-21 17:26:22 +0000 |
commit | 67a45eb4d77181a4b57403e15af175f55cbf2a1d (patch) | |
tree | e3fa1cfe00ba6bb5c03a884f5553a16ce33ed488 | |
parent | b54bbd13c48e6d51b99d1ff7a4bf1c2b0c4c58e8 (diff) | |
download | lighttpd-67a45eb4d77181a4b57403e15af175f55cbf2a1d.tar.gz |
Add server.breakagelog, a "special" stderr (fixes #1863)
* The breakage-log simply replaces stderr (the old stderr is moved away if needed for errorlog),
and stderr isn't closed after forking.
It defaults to stderr if started with -n (no daemonize), otherwise it defaults to /dev/null.
It is _not_ reopened in log_error_cycle, as there may be many long running childs which have it
still open anyway. Use a pipe-logger with cycle-support if you need it.
git-svn-id: svn://svn.lighttpd.net/lighttpd/trunk@2552 152afb58-edef-0310-8abb-c4023f1b3aa9
-rw-r--r-- | NEWS | 1 | ||||
-rw-r--r-- | src/base.h | 1 | ||||
-rw-r--r-- | src/configfile.c | 2 | ||||
-rw-r--r-- | src/log.c | 102 | ||||
-rw-r--r-- | src/log.h | 7 | ||||
-rw-r--r-- | src/mod_rrdtool.c | 4 | ||||
-rw-r--r-- | src/server.c | 4 |
7 files changed, 85 insertions, 36 deletions
@@ -123,6 +123,7 @@ NEWS * Fix race condition with joblist thread condition/mutex (thx peto, fixes #1823) * Fix segfault if there is no mimetype for the error documents * Use unsigned int for secdownload.timeout (fixes #1966) + * Add server.breakagelog, a "special" stderr (fixes #1863) - 1.5.0-r19.. - * -F option added for spawn-fcgi @@ -551,6 +551,7 @@ typedef struct { buffer *errorlog_file; unsigned short errorlog_use_syslog; + buffer *breakagelog_file; unsigned short max_stat_threads; unsigned short max_read_threads; diff --git a/src/configfile.c b/src/configfile.c index 82b4ec63..d4b5ac31 100644 --- a/src/configfile.c +++ b/src/configfile.c @@ -102,6 +102,7 @@ static int config_insert(server *srv) { { "etag.use-inode", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 54 */ { "etag.use-mtime", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 55 */ { "etag.use-size", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 56 */ + { "server.breakagelog", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 57 */ { "server.host", "use server.bind instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET }, { "server.docroot", "use server.document-root instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET }, @@ -149,6 +150,7 @@ static int config_insert(server *srv) { cv[49].destination = &(srv->srvconf.max_read_threads); cv[51].destination = &(srv->srvconf.log_timing); + cv[57].destination = srv->srvconf.breakagelog_file; srv->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *)); @@ -41,6 +41,29 @@ # define O_LARGEFILE 0 #endif +/* Close fd and _try_ to get a /dev/null for it instead. + * close() alone may trigger some bugs when a + * process opens another file and gets fd = STDOUT_FILENO or STDERR_FILENO + * and later tries to just print on stdout/stderr + * + * Returns 0 on success and -1 on failure (fd gets closed in all cases) + */ +int openDevNull(int fd) { + int tmpfd; + close(fd); +#if defined(__WIN32) + /* Cygwin should work with /dev/null */ + tmpfd = open("nul", O_RDWR); +#else + tmpfd = open("/dev/null", O_RDWR); +#endif + if (tmpfd != -1 && tmpfd != fd) { + dup2(tmpfd, fd); + close(tmpfd); + } + return (tmpfd != -1) ? 0 : -1; +} + /** * open the errorlog * @@ -60,7 +83,7 @@ typedef struct { /* the errorlog */ int fd; - enum { ERRORLOG_STDERR, ERRORLOG_FILE, ERRORLOG_SYSLOG } mode; + enum { ERRORLOG_FILE, ERRORLOG_FD, ERRORLOG_SYSLOG } mode; buffer *buf; time_t cached_ts; @@ -75,8 +98,8 @@ void log_init(void) { err = calloc(1, sizeof(*err)); - err->fd = -1; - err->mode = ERRORLOG_STDERR; + err->fd = STDERR_FILENO; + err->mode = ERRORLOG_FD; err->buf = buffer_init(); err->cached_ts_str = buffer_init(); @@ -90,15 +113,18 @@ void log_free(void) { switch(err->mode) { case ERRORLOG_FILE: - close(err->fd); + case ERRORLOG_FD: + if (-1 != err->fd) { + if (STDERR_FILENO != err->fd) + close(err->fd); + err->fd = -1; + } break; case ERRORLOG_SYSLOG: #ifdef HAVE_SYSLOG_H closelog(); #endif break; - case ERRORLOG_STDERR: - break; } buffer_free(err->buf); @@ -109,17 +135,15 @@ void log_free(void) { myconfig = NULL; } -int log_error_open(buffer *file, int use_syslog) { - int fd; - int close_stderr = 1; - +int log_error_open(buffer *file, buffer *breakage_file, int use_syslog, int dont_daemonize) { errorlog *err = myconfig; #ifdef HAVE_SYSLOG_H /* perhaps someone wants to use syslog() */ openlog("lighttpd", LOG_CONS | LOG_PID, LOG_DAEMON); #endif - err->mode = ERRORLOG_STDERR; + err->mode = ERRORLOG_FD; + err->fd = STDERR_FILENO; if (use_syslog) { err->mode = ERRORLOG_SYSLOG; @@ -141,17 +165,39 @@ int log_error_open(buffer *file, int use_syslog) { TRACE("%s", "server started"); - /* don't close stderr for debugging purposes if run in valgrind */ - if (RUNNING_ON_VALGRIND) close_stderr = 0; - if (err->mode == ERRORLOG_STDERR) close_stderr = 0; + if (err->mode == ERRORLOG_FD && !dont_daemonize) { + /* We can only log to stderr in dont-daemonize mode */ + err->fd = -1; + } + + if (!buffer_is_empty(breakage_file)) { + int breakage_fd; + + if (err->mode == ERRORLOG_FD) { + err->fd = dup(STDERR_FILENO); +#ifdef FD_CLOEXEC + fcntl(err->fd, F_SETFD, FD_CLOEXEC); +#endif + } + + if (-1 == (breakage_fd = open(breakage_file->ptr, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) { + log_error_write(NULL, __FILE__, __LINE__, "SBSS", + "opening breakagelog '", breakage_file, + "' failed: ", strerror(errno)); + + return -1; + } - /* move stderr to /dev/null */ - if (close_stderr && - -1 != (fd = open("/dev/null", O_WRONLY))) { - close(STDERR_FILENO); - dup2(fd, STDERR_FILENO); - close(fd); + if (STDERR_FILENO != breakage_fd) { + dup2(breakage_fd, STDERR_FILENO); + close(breakage_fd); + } + } else if (!dont_daemonize) { + /* move stderr to /dev/null */ + openDevNull(STDERR_FILENO); } + + return 0; } @@ -206,7 +252,8 @@ int log_error_write(void *srv, const char *filename, unsigned int line, const ch switch(err->mode) { case ERRORLOG_FILE: - case ERRORLOG_STDERR: + case ERRORLOG_FD: + if (-1 == err->fd) return 0; /* cache the generated timestamp */ t = time(NULL); @@ -290,13 +337,10 @@ int log_error_write(void *srv, const char *filename, unsigned int line, const ch switch(err->mode) { case ERRORLOG_FILE: + case ERRORLOG_FD: buffer_append_string_len(err->buf, CONST_STR_LEN("\n")); write(err->fd, err->buf->ptr, err->buf->used - 1); break; - case ERRORLOG_STDERR: - buffer_append_string_len(err->buf, CONST_STR_LEN("\n")); - write(STDERR_FILENO, err->buf->ptr, err->buf->used - 1); - break; #ifdef HAVE_SYSLOG_H case ERRORLOG_SYSLOG: syslog(LOG_ERR, "%s", err->buf->ptr); @@ -320,7 +364,8 @@ int log_trace(const char *fmt, ...) { switch(err->mode) { case ERRORLOG_FILE: - case ERRORLOG_STDERR: + case ERRORLOG_FD: + if (-1 == err->fd) return 0; /* cache the generated timestamp */ t = time(NULL); @@ -384,13 +429,10 @@ int log_trace(const char *fmt, ...) { /* write b */ switch(err->mode) { case ERRORLOG_FILE: + case ERRORLOG_FD: buffer_append_string_len(b, CONST_STR_LEN("\n")); write(err->fd, b->ptr, b->used - 1); break; - case ERRORLOG_STDERR: - buffer_append_string_len(b, CONST_STR_LEN("\n")); - write(STDERR_FILENO, b->ptr, b->used - 1); - break; #ifdef HAVE_SYSLOG_H case ERRORLOG_SYSLOG: syslog(LOG_ERR, "%s", b->ptr); @@ -4,10 +4,15 @@ #include "valgrind/valgrind.h" #include "buffer.h" +/* Close fd and _try_ to get a /dev/null for it instead. + * Returns 0 on success and -1 on failure (fd gets closed in all cases) + */ +LI_API int openDevNull(int fd); + LI_API void log_init(void); LI_API void log_free(void); -LI_API int log_error_open(buffer *file, int use_syslog); +LI_API int log_error_open(buffer* file, buffer* breakage_file, int use_syslog, int dont_daemonize); LI_API int log_error_close(); LI_API int log_error_write(void *srv, const char *filename, unsigned int line, const char *fmt, ...); LI_API int log_error_cycle(); diff --git a/src/mod_rrdtool.c b/src/mod_rrdtool.c index e70473ca..f7e4fad1 100644 --- a/src/mod_rrdtool.c +++ b/src/mod_rrdtool.c @@ -129,21 +129,17 @@ static int mod_rrd_create_pipe(server *srv, plugin_data *p) { char *dash = "-"; /* move stdout to from_rrdtool_fd[1] */ - close(STDOUT_FILENO); dup2(from_rrdtool_fds[1], STDOUT_FILENO); close(from_rrdtool_fds[1]); /* not needed */ close(from_rrdtool_fds[0]); /* move the stdin to to_rrdtool_fd[0] */ - close(STDIN_FILENO); dup2(to_rrdtool_fds[0], STDIN_FILENO); close(to_rrdtool_fds[0]); /* not needed */ close(to_rrdtool_fds[1]); - close(STDERR_FILENO); - /* set up args */ argc = 3; args = malloc(sizeof(*args) * argc); diff --git a/src/server.c b/src/server.c index 1756fdc3..5090c9ce 100644 --- a/src/server.c +++ b/src/server.c @@ -203,6 +203,7 @@ static server *server_init(void) { CLEAN(cond_check_buf); CLEAN(srvconf.errorlog_file); + CLEAN(srvconf.breakagelog_file); CLEAN(srvconf.groupname); CLEAN(srvconf.username); CLEAN(srvconf.changeroot); @@ -297,6 +298,7 @@ static void server_free(server *srv) { CLEAN(cond_check_buf); CLEAN(srvconf.errorlog_file); + CLEAN(srvconf.breakagelog_file); CLEAN(srvconf.groupname); CLEAN(srvconf.username); CLEAN(srvconf.changeroot); @@ -1536,7 +1538,7 @@ int main (int argc, char **argv, char **envp) { return -1; } - if (-1 == log_error_open(srv->srvconf.errorlog_file, srv->srvconf.errorlog_use_syslog)) { + if (-1 == log_error_open(srv->srvconf.errorlog_file, srv->srvconf.breakagelog_file, srv->srvconf.errorlog_use_syslog, srv->srvconf.dont_daemonize)) { log_error_write(srv, __FILE__, __LINE__, "s", "opening errorlog failed, dying"); |