diff options
author | Arno Töll <arno@debian.org> | 2012-11-21 23:03:34 +0100 |
---|---|---|
committer | Arno Töll <arno@debian.org> | 2012-11-21 23:03:34 +0100 |
commit | eb45c46b906e492f063f1469486190e93ff340ff (patch) | |
tree | 85d615969fa7bf8056a05b59006f77bc63e85892 /src/log.c | |
parent | 6426b37107707a1d95ffd03f68620cbda8bdb942 (diff) | |
download | lighttpd-eb45c46b906e492f063f1469486190e93ff340ff.tar.gz |
Imported Upstream version 1.4.10upstream/1.4.10
Diffstat (limited to 'src/log.c')
-rw-r--r-- | src/log.c | 256 |
1 files changed, 256 insertions, 0 deletions
diff --git a/src/log.c b/src/log.c new file mode 100644 index 0000000..402e302 --- /dev/null +++ b/src/log.c @@ -0,0 +1,256 @@ +#define _GNU_SOURCE + +#include <sys/types.h> + +#include <errno.h> +#include <fcntl.h> +#include <time.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> + +#include <stdarg.h> +#include <stdio.h> + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_SYSLOG_H +#include <syslog.h> +#endif + +#include "log.h" +#include "array.h" + +#ifdef HAVE_VALGRIND_VALGRIND_H +#include <valgrind/valgrind.h> +#endif + +#ifndef O_LARGEFILE +# define O_LARGEFILE 0 +#endif + +/** + * open the errorlog + * + * we have 3 possibilities: + * - stderr (default) + * - syslog + * - logfile + * + * if the open failed, report to the user and die + * + */ + +int log_error_open(server *srv) { + int fd; + int close_stderr = 1; + +#ifdef HAVE_SYSLOG_H + /* perhaps someone wants to use syslog() */ + openlog("lighttpd", LOG_CONS | LOG_PID, LOG_DAEMON); +#endif + srv->errorlog_mode = ERRORLOG_STDERR; + + if (srv->srvconf.errorlog_use_syslog) { + srv->errorlog_mode = ERRORLOG_SYSLOG; + } 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)); + + return -1; + } +#ifdef FD_CLOEXEC + /* close fd on exec (cgi) */ + fcntl(srv->errorlog_fd, F_SETFD, FD_CLOEXEC); +#endif + srv->errorlog_mode = ERRORLOG_FILE; + } + + log_error_write(srv, __FILE__, __LINE__, "s", "server started"); + +#ifdef HAVE_VALGRIND_VALGRIND_H + /* don't close stderr for debugging purposes if run in valgrind */ + if (RUNNING_ON_VALGRIND) close_stderr = 0; +#endif + if (srv->errorlog_mode == ERRORLOG_STDERR) close_stderr = 0; + + /* move stderr to /dev/null */ + if (close_stderr && + -1 != (fd = open("/dev/null", O_WRONLY))) { + close(STDERR_FILENO); + dup2(fd, STDERR_FILENO); + close(fd); + } + return 0; +} + +/** + * open the errorlog + * + * if the open failed, report to the user and die + * if no filename is given, use syslog instead + * + */ + +int log_error_cycle(server *srv) { + /* only cycle if we are not in syslog-mode */ + + if (srv->errorlog_mode == ERRORLOG_FILE) { + const char *logfile = srv->srvconf.errorlog_file->ptr; + /* already check of opening time */ + + int new_fd; + + if (-1 == (new_fd = open(logfile, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) { + /* write to old log */ + log_error_write(srv, __FILE__, __LINE__, "SSSSS", + "cycling errorlog '", logfile, + "' failed: ", strerror(errno), + ", falling back to syslog()"); + + close(srv->errorlog_fd); + srv->errorlog_fd = -1; +#ifdef HAVE_SYSLOG_H + srv->errorlog_mode = ERRORLOG_SYSLOG; +#endif + } else { + /* ok, new log is open, close the old one */ + close(srv->errorlog_fd); + srv->errorlog_fd = new_fd; + } + } + + log_error_write(srv, __FILE__, __LINE__, "s", "logfiles cycled"); + + return 0; +} + +int log_error_close(server *srv) { + log_error_write(srv, __FILE__, __LINE__, "s", "server stopped"); + + switch(srv->errorlog_mode) { + case ERRORLOG_FILE: + close(srv->errorlog_fd); + break; + case ERRORLOG_SYSLOG: +#ifdef HAVE_SYSLOG_H + closelog(); +#endif + break; + case ERRORLOG_STDERR: + break; + } + + return 0; +} + +int log_error_write(server *srv, const char *filename, unsigned int line, const char *fmt, ...) { + va_list ap; + + switch(srv->errorlog_mode) { + case ERRORLOG_FILE: + case ERRORLOG_STDERR: + /* cache the generated timestamp */ + if (srv->cur_ts != srv->last_generated_debug_ts) { + buffer_prepare_copy(srv->ts_debug_str, 255); + strftime(srv->ts_debug_str->ptr, srv->ts_debug_str->size - 1, "%Y-%m-%d %H:%M:%S", localtime(&(srv->cur_ts))); + srv->ts_debug_str->used = strlen(srv->ts_debug_str->ptr) + 1; + + srv->last_generated_debug_ts = srv->cur_ts; + } + + buffer_copy_string_buffer(srv->errorlog_buf, srv->ts_debug_str); + BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, ": ("); + break; + case ERRORLOG_SYSLOG: + /* syslog is generating its own timestamps */ + BUFFER_COPY_STRING_CONST(srv->errorlog_buf, "("); + break; + } + + buffer_append_string(srv->errorlog_buf, filename); + BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, "."); + buffer_append_long(srv->errorlog_buf, line); + BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, ") "); + + + for(va_start(ap, fmt); *fmt; fmt++) { + int d; + char *s; + buffer *b; + off_t o; + + switch(*fmt) { + case 's': /* string */ + s = va_arg(ap, char *); + buffer_append_string(srv->errorlog_buf, s); + BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, " "); + break; + case 'b': /* buffer */ + b = va_arg(ap, buffer *); + buffer_append_string_buffer(srv->errorlog_buf, b); + BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, " "); + break; + case 'd': /* int */ + d = va_arg(ap, int); + buffer_append_long(srv->errorlog_buf, d); + BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, " "); + break; + case 'o': /* off_t */ + o = va_arg(ap, off_t); + buffer_append_off_t(srv->errorlog_buf, o); + BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, " "); + break; + case 'x': /* int (hex) */ + d = va_arg(ap, int); + BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, "0x"); + buffer_append_long_hex(srv->errorlog_buf, d); + BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, " "); + break; + case 'S': /* string */ + s = va_arg(ap, char *); + buffer_append_string(srv->errorlog_buf, s); + break; + case 'B': /* buffer */ + b = va_arg(ap, buffer *); + buffer_append_string_buffer(srv->errorlog_buf, b); + break; + case 'D': /* int */ + d = va_arg(ap, int); + buffer_append_long(srv->errorlog_buf, d); + break; + case '(': + case ')': + case '<': + case '>': + case ',': + case ' ': + buffer_append_string_len(srv->errorlog_buf, fmt, 1); + break; + } + } + va_end(ap); + + switch(srv->errorlog_mode) { + case ERRORLOG_FILE: + BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, "\n"); + write(srv->errorlog_fd, srv->errorlog_buf->ptr, srv->errorlog_buf->used - 1); + break; + case ERRORLOG_STDERR: + BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, "\n"); + write(STDERR_FILENO, srv->errorlog_buf->ptr, srv->errorlog_buf->used - 1); + break; + case ERRORLOG_SYSLOG: + syslog(LOG_ERR, "%s", srv->errorlog_buf->ptr); + break; + } + + return 0; +} + |