From 1527160c69fcc4f15af0ce8a7bb447513be4d1ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20B=C3=BChler?= Date: Fri, 10 Apr 2009 10:50:51 +0000 Subject: [PATCH] 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 --- NEWS | 1 + src/base.h | 2 +- src/log.c | 102 ++++++++++++++++++++++++++++++++++++++------ src/log.h | 2 + src/mod_accesslog.c | 69 +----------------------------- src/mod_cgi.c | 10 ----- 6 files changed, 95 insertions(+), 91 deletions(-) diff --git a/NEWS b/NEWS index 1da25b8d..5ae7a4ee 100644 --- a/NEWS +++ b/NEWS @@ -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) diff --git a/src/base.h b/src/base.h index e0523147..4057ab66 100644 --- a/src/base.h +++ b/src/base.h @@ -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; diff --git a/src/log.c b/src/log.c index 8195a5f8..56cfe0c2 100644 --- a/src/log.c +++ b/src/log.c @@ -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); diff --git a/src/log.h b/src/log.h index bdd7af4d..583288b6 100644 --- a/src/log.h +++ b/src/log.h @@ -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, ...); diff --git a/src/mod_accesslog.c b/src/mod_accesslog.c index 1476a7a1..024f2e9f 100644 --- a/src/mod_accesslog.c +++ b/src/mod_accesslog.c @@ -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; diff --git a/src/mod_cgi.c b/src/mod_cgi.c index db52802d..a61ab719 100644 --- a/src/mod_cgi.c +++ b/src/mod_cgi.c @@ -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;