|
|
| version 1.1, 2013/10/14 10:32:47 | version 1.1.1.3, 2016/11/02 10:35:00 |
|---|---|
| Line 1 | Line 1 |
| #include "first.h" | |
| #include "base.h" | #include "base.h" |
| #include "log.h" | #include "log.h" |
| #include "array.h" | #include "array.h" |
| Line 26 | Line 28 |
| # define O_LARGEFILE 0 | # define O_LARGEFILE 0 |
| #endif | #endif |
| #ifndef HAVE_CLOCK_GETTIME | |
| #ifdef HAVE_SYS_TIME_H | |
| # include <sys/time.h> /* gettimeofday() */ | |
| #endif | |
| #endif | |
| int log_clock_gettime_realtime (struct timespec *ts) { | |
| #ifdef HAVE_CLOCK_GETTIME | |
| return clock_gettime(CLOCK_REALTIME, ts); | |
| #else | |
| /* Mac OSX does not provide clock_gettime() | |
| * e.g. defined(__APPLE__) && defined(__MACH__) */ | |
| struct timeval tv; | |
| gettimeofday(&tv, NULL); | |
| ts->tv_sec = tv.tv_sec; | |
| ts->tv_nsec = tv.tv_usec * 1000; | |
| return 0; | |
| #endif | |
| } | |
| /* retry write on EINTR or when not all data was written */ | |
| ssize_t write_all(int fd, const void* buf, size_t count) { | |
| ssize_t written = 0; | |
| while (count > 0) { | |
| ssize_t r = write(fd, buf, count); | |
| if (r < 0) { | |
| switch (errno) { | |
| case EINTR: | |
| /* try again */ | |
| break; | |
| default: | |
| /* fail - repeating probably won't help */ | |
| return -1; | |
| } | |
| } else if (0 == r) { | |
| /* really shouldn't happen... */ | |
| errno = EIO; | |
| return -1; | |
| } else { | |
| force_assert(r <= (ssize_t) count); | |
| written += r; | |
| buf = r + (char const*) buf; | |
| count -= r; | |
| } | |
| } | |
| return written; | |
| } | |
| /* Close fd and _try_ to get a /dev/null for it instead. | /* Close fd and _try_ to get a /dev/null for it instead. |
| * close() alone may trigger some bugs when a | * close() alone may trigger some bugs when a |
| * process opens another file and gets fd = STDOUT_FILENO or STDERR_FILENO | * process opens another file and gets fd = STDOUT_FILENO or STDERR_FILENO |
| Line 122 int open_logfile_or_pipe(server *srv, const char* logf | Line 174 int open_logfile_or_pipe(server *srv, const char* logf |
| return -1; | return -1; |
| } | } |
| #ifdef FD_CLOEXEC | fd_close_on_exec(fd); |
| fcntl(fd, F_SETFD, FD_CLOEXEC); | |
| #endif | |
| return fd; | return fd; |
| } | } |
| Line 154 int log_error_open(server *srv) { | Line 204 int log_error_open(server *srv) { |
| if (srv->srvconf.errorlog_use_syslog) { | if (srv->srvconf.errorlog_use_syslog) { |
| srv->errorlog_mode = ERRORLOG_SYSLOG; | srv->errorlog_mode = ERRORLOG_SYSLOG; |
| } else if (!buffer_is_empty(srv->srvconf.errorlog_file)) { | } else if (!buffer_string_is_empty(srv->srvconf.errorlog_file)) { |
| const char *logfile = srv->srvconf.errorlog_file->ptr; | const char *logfile = srv->srvconf.errorlog_file->ptr; |
| if (-1 == (srv->errorlog_fd = open_logfile_or_pipe(srv, logfile))) { | if (-1 == (srv->errorlog_fd = open_logfile_or_pipe(srv, logfile))) { |
| Line 172 int log_error_open(server *srv) { | Line 222 int log_error_open(server *srv) { |
| srv->errorlog_fd = -1; | srv->errorlog_fd = -1; |
| } | } |
| if (!buffer_is_empty(srv->srvconf.breakagelog_file)) { | if (!buffer_string_is_empty(srv->srvconf.breakagelog_file)) { |
| int breakage_fd; | int breakage_fd; |
| const char *logfile = srv->srvconf.breakagelog_file->ptr; | const char *logfile = srv->srvconf.breakagelog_file->ptr; |
| if (srv->errorlog_mode == ERRORLOG_FD) { | if (srv->errorlog_mode == ERRORLOG_FD) { |
| srv->errorlog_fd = dup(STDERR_FILENO); | srv->errorlog_fd = dup(STDERR_FILENO); |
| #ifdef FD_CLOEXEC | fd_close_on_exec(srv->errorlog_fd); |
| fcntl(srv->errorlog_fd, F_SETFD, FD_CLOEXEC); | |
| #endif | |
| } | } |
| if (-1 == (breakage_fd = open_logfile_or_pipe(srv, logfile))) { | if (-1 == (breakage_fd = open_logfile_or_pipe(srv, logfile))) { |
| Line 231 int log_error_cycle(server *srv) { | Line 279 int log_error_cycle(server *srv) { |
| /* ok, new log is open, close the old one */ | /* ok, new log is open, close the old one */ |
| close(srv->errorlog_fd); | close(srv->errorlog_fd); |
| srv->errorlog_fd = new_fd; | srv->errorlog_fd = new_fd; |
| #ifdef FD_CLOEXEC | fd_close_on_exec(srv->errorlog_fd); |
| /* close fd on exec (cgi) */ | |
| fcntl(srv->errorlog_fd, F_SETFD, FD_CLOEXEC); | |
| #endif | |
| } | } |
| } | } |
| Line 274 static void log_buffer_append_printf(buffer *out, cons | Line 319 static void log_buffer_append_printf(buffer *out, cons |
| switch(*fmt) { | switch(*fmt) { |
| case 's': /* string */ | case 's': /* string */ |
| s = va_arg(ap, char *); | s = va_arg(ap, char *); |
| buffer_append_string(out, s); | buffer_append_string_c_escaped(out, s, (NULL != s) ? strlen(s) : 0); |
| buffer_append_string_len(out, CONST_STR_LEN(" ")); | buffer_append_string_len(out, CONST_STR_LEN(" ")); |
| break; | break; |
| case 'b': /* buffer */ | case 'b': /* buffer */ |
| b = va_arg(ap, buffer *); | b = va_arg(ap, buffer *); |
| buffer_append_string_buffer(out, b); | buffer_append_string_c_escaped(out, CONST_BUF_LEN(b)); |
| buffer_append_string_len(out, CONST_STR_LEN(" ")); | buffer_append_string_len(out, CONST_STR_LEN(" ")); |
| break; | break; |
| case 'd': /* int */ | case 'd': /* int */ |
| d = va_arg(ap, int); | d = va_arg(ap, int); |
| buffer_append_long(out, d); | buffer_append_int(out, d); |
| buffer_append_string_len(out, CONST_STR_LEN(" ")); | buffer_append_string_len(out, CONST_STR_LEN(" ")); |
| break; | break; |
| case 'o': /* off_t */ | case 'o': /* off_t */ |
| o = va_arg(ap, off_t); | o = va_arg(ap, off_t); |
| buffer_append_off_t(out, o); | buffer_append_int(out, o); |
| buffer_append_string_len(out, CONST_STR_LEN(" ")); | buffer_append_string_len(out, CONST_STR_LEN(" ")); |
| break; | break; |
| case 'x': /* int (hex) */ | case 'x': /* int (hex) */ |
| d = va_arg(ap, int); | d = va_arg(ap, int); |
| buffer_append_string_len(out, CONST_STR_LEN("0x")); | buffer_append_string_len(out, CONST_STR_LEN("0x")); |
| buffer_append_long_hex(out, d); | buffer_append_uint_hex(out, d); |
| buffer_append_string_len(out, CONST_STR_LEN(" ")); | buffer_append_string_len(out, CONST_STR_LEN(" ")); |
| break; | break; |
| case 'S': /* string */ | case 'S': /* string */ |
| s = va_arg(ap, char *); | s = va_arg(ap, char *); |
| buffer_append_string(out, s); | buffer_append_string_c_escaped(out, s, (NULL != s) ? strlen(s) : 0); |
| break; | break; |
| case 'B': /* buffer */ | case 'B': /* buffer */ |
| b = va_arg(ap, buffer *); | b = va_arg(ap, buffer *); |
| buffer_append_string_buffer(out, b); | buffer_append_string_c_escaped(out, CONST_BUF_LEN(b)); |
| break; | break; |
| case 'D': /* int */ | case 'D': /* int */ |
| d = va_arg(ap, int); | d = va_arg(ap, int); |
| buffer_append_long(out, d); | buffer_append_int(out, d); |
| break; | break; |
| case 'O': /* off_t */ | case 'O': /* off_t */ |
| o = va_arg(ap, off_t); | o = va_arg(ap, off_t); |
| buffer_append_off_t(out, o); | buffer_append_int(out, o); |
| break; | break; |
| case 'X': /* int (hex) */ | case 'X': /* int (hex) */ |
| d = va_arg(ap, int); | d = va_arg(ap, int); |
| buffer_append_string_len(out, CONST_STR_LEN("0x")); | buffer_append_string_len(out, CONST_STR_LEN("0x")); |
| buffer_append_long_hex(out, d); | buffer_append_uint_hex(out, d); |
| break; | break; |
| case '(': | case '(': |
| case ')': | case ')': |
| Line 339 static int log_buffer_prepare(buffer *b, server *srv, | Line 384 static int log_buffer_prepare(buffer *b, server *srv, |
| if (-1 == srv->errorlog_fd) return -1; | if (-1 == srv->errorlog_fd) return -1; |
| /* cache the generated timestamp */ | /* cache the generated timestamp */ |
| if (srv->cur_ts != srv->last_generated_debug_ts) { | if (srv->cur_ts != srv->last_generated_debug_ts) { |
| buffer_prepare_copy(srv->ts_debug_str, 255); | buffer_string_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))); | buffer_append_strftime(srv->ts_debug_str, "%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; | srv->last_generated_debug_ts = srv->cur_ts; |
| } | } |
| buffer_copy_string_buffer(b, srv->ts_debug_str); | buffer_copy_buffer(b, srv->ts_debug_str); |
| buffer_append_string_len(b, CONST_STR_LEN(": (")); | buffer_append_string_len(b, CONST_STR_LEN(": (")); |
| break; | break; |
| case ERRORLOG_SYSLOG: | case ERRORLOG_SYSLOG: |
| Line 357 static int log_buffer_prepare(buffer *b, server *srv, | Line 401 static int log_buffer_prepare(buffer *b, server *srv, |
| buffer_append_string(b, filename); | buffer_append_string(b, filename); |
| buffer_append_string_len(b, CONST_STR_LEN(".")); | buffer_append_string_len(b, CONST_STR_LEN(".")); |
| buffer_append_long(b, line); | buffer_append_int(b, line); |
| buffer_append_string_len(b, CONST_STR_LEN(") ")); | buffer_append_string_len(b, CONST_STR_LEN(") ")); |
| return 0; | return 0; |
| Line 369 static void log_write(server *srv, buffer *b) { | Line 413 static void log_write(server *srv, buffer *b) { |
| case ERRORLOG_FILE: | case ERRORLOG_FILE: |
| case ERRORLOG_FD: | case ERRORLOG_FD: |
| buffer_append_string_len(b, CONST_STR_LEN("\n")); | buffer_append_string_len(b, CONST_STR_LEN("\n")); |
| write(srv->errorlog_fd, b->ptr, b->used - 1); | write_all(srv->errorlog_fd, CONST_BUF_LEN(b)); |
| break; | break; |
| case ERRORLOG_SYSLOG: | case ERRORLOG_SYSLOG: |
| syslog(LOG_ERR, "%s", b->ptr); | syslog(LOG_ERR, "%s", b->ptr); |
| Line 393 int log_error_write(server *srv, const char *filename, | Line 437 int log_error_write(server *srv, const char *filename, |
| int log_error_write_multiline_buffer(server *srv, const char *filename, unsigned int line, buffer *multiline, const char *fmt, ...) { | int log_error_write_multiline_buffer(server *srv, const char *filename, unsigned int line, buffer *multiline, const char *fmt, ...) { |
| va_list ap; | va_list ap; |
| size_t prefix_used; | size_t prefix_len; |
| buffer *b = srv->errorlog_buf; | buffer *b = srv->errorlog_buf; |
| char *pos, *end, *current_line; | char *pos, *end, *current_line; |
| if (multiline->used < 2) return 0; | if (buffer_string_is_empty(multiline)) return 0; |
| if (-1 == log_buffer_prepare(b, srv, filename, line)) return 0; | if (-1 == log_buffer_prepare(b, srv, filename, line)) return 0; |
| Line 405 int log_error_write_multiline_buffer(server *srv, cons | Line 449 int log_error_write_multiline_buffer(server *srv, cons |
| log_buffer_append_printf(b, fmt, ap); | log_buffer_append_printf(b, fmt, ap); |
| va_end(ap); | va_end(ap); |
| prefix_used = b->used; | prefix_len = buffer_string_length(b); |
| current_line = pos = multiline->ptr; | current_line = pos = multiline->ptr; |
| end = multiline->ptr + multiline->used; | end = multiline->ptr + buffer_string_length(multiline); |
| for ( ; pos < end ; ++pos) { | for ( ; pos <= end ; ++pos) { |
| switch (*pos) { | switch (*pos) { |
| case '\n': | case '\n': |
| case '\r': | case '\r': |
| case '\0': /* handles end of string */ | case '\0': /* handles end of string */ |
| if (current_line < pos) { | if (current_line < pos) { |
| /* truncate to prefix */ | /* truncate to prefix */ |
| b->used = prefix_used; | buffer_string_set_length(b, prefix_len); |
| b->ptr[b->used - 1] = '\0'; | |
| buffer_append_string_len(b, current_line, pos - current_line); | buffer_append_string_len(b, current_line, pos - current_line); |
| log_write(srv, b); | log_write(srv, b); |