summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorstbuehler <stbuehler@152afb58-edef-0310-8abb-c4023f1b3aa9>2009-06-21 17:26:22 +0000
committerstbuehler <stbuehler@152afb58-edef-0310-8abb-c4023f1b3aa9>2009-06-21 17:26:22 +0000
commit67a45eb4d77181a4b57403e15af175f55cbf2a1d (patch)
treee3fa1cfe00ba6bb5c03a884f5553a16ce33ed488
parentb54bbd13c48e6d51b99d1ff7a4bf1c2b0c4c58e8 (diff)
downloadlighttpd-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--NEWS1
-rw-r--r--src/base.h1
-rw-r--r--src/configfile.c2
-rw-r--r--src/log.c102
-rw-r--r--src/log.h7
-rw-r--r--src/mod_rrdtool.c4
-rw-r--r--src/server.c4
7 files changed, 85 insertions, 36 deletions
diff --git a/NEWS b/NEWS
index 6603b951..0a68a014 100644
--- a/NEWS
+++ b/NEWS
@@ -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
diff --git a/src/base.h b/src/base.h
index 9e36375f..d0ca8188 100644
--- a/src/base.h
+++ b/src/base.h
@@ -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 *));
diff --git a/src/log.c b/src/log.c
index 1d121660..401ab50d 100644
--- a/src/log.c
+++ b/src/log.c
@@ -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);
diff --git a/src/log.h b/src/log.h
index 52369d8e..616e6274 100644
--- a/src/log.h
+++ b/src/log.h
@@ -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");