2016-03-19 15:14:35 +00:00
|
|
|
#include "first.h"
|
|
|
|
|
2009-10-11 14:31:42 +00:00
|
|
|
#include "base.h"
|
|
|
|
#include "log.h"
|
|
|
|
#include "array.h"
|
2005-02-20 14:27:00 +00:00
|
|
|
|
|
|
|
#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_SYSLOG_H
|
2009-10-11 14:31:42 +00:00
|
|
|
# include <syslog.h>
|
2005-02-20 14:27:00 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAVE_VALGRIND_VALGRIND_H
|
2009-10-11 14:31:42 +00:00
|
|
|
# include <valgrind/valgrind.h>
|
2005-02-20 14:27:00 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef O_LARGEFILE
|
|
|
|
# define O_LARGEFILE 0
|
|
|
|
#endif
|
|
|
|
|
2015-08-22 16:01:08 +00:00
|
|
|
/* 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;
|
|
|
|
}
|
|
|
|
|
2008-04-29 20:59:39 +00:00
|
|
|
/* 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;
|
|
|
|
}
|
|
|
|
|
2009-04-10 10:50:51 +00:00
|
|
|
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];
|
|
|
|
|
|
|
|
if (pipe(to_log_fds)) {
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed: ", strerror(errno));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* fork, execve */
|
2009-07-21 20:35:27 +00:00
|
|
|
switch (fork()) {
|
2009-04-10 10:50:51 +00:00
|
|
|
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
|
2009-06-11 09:38:54 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
/* we don't need the client socket */
|
|
|
|
for (i = 3; i < 256; i++) {
|
|
|
|
close(i);
|
|
|
|
}
|
2009-04-10 10:50:51 +00:00
|
|
|
}
|
|
|
|
#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;
|
|
|
|
}
|
|
|
|
|
2014-02-16 13:08:29 +00:00
|
|
|
fd_close_on_exec(fd);
|
2009-04-10 10:50:51 +00:00
|
|
|
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-10-04 13:26:23 +00:00
|
|
|
/**
|
2005-02-20 14:27:00 +00:00
|
|
|
* open the errorlog
|
2006-10-04 13:26:23 +00:00
|
|
|
*
|
2009-04-10 10:50:51 +00:00
|
|
|
* we have 4 possibilities:
|
2005-07-26 08:26:28 +00:00
|
|
|
* - stderr (default)
|
2006-10-04 13:26:23 +00:00
|
|
|
* - syslog
|
2005-07-26 08:26:28 +00:00
|
|
|
* - logfile
|
2009-04-10 10:50:51 +00:00
|
|
|
* - pipe
|
2006-10-04 13:26:23 +00:00
|
|
|
*
|
2005-02-20 14:27:00 +00:00
|
|
|
* if the open failed, report to the user and die
|
2006-10-04 13:26:23 +00:00
|
|
|
*
|
2005-02-20 14:27:00 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
int log_error_open(server *srv) {
|
2005-07-26 08:26:28 +00:00
|
|
|
#ifdef HAVE_SYSLOG_H
|
|
|
|
/* perhaps someone wants to use syslog() */
|
|
|
|
openlog("lighttpd", LOG_CONS | LOG_PID, LOG_DAEMON);
|
|
|
|
#endif
|
2009-06-21 17:25:39 +00:00
|
|
|
|
|
|
|
srv->errorlog_mode = ERRORLOG_FD;
|
|
|
|
srv->errorlog_fd = STDERR_FILENO;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-26 08:26:28 +00:00
|
|
|
if (srv->srvconf.errorlog_use_syslog) {
|
|
|
|
srv->errorlog_mode = ERRORLOG_SYSLOG;
|
2015-02-08 12:37:10 +00:00
|
|
|
} else if (!buffer_string_is_empty(srv->srvconf.errorlog_file)) {
|
2005-07-26 08:26:28 +00:00
|
|
|
const char *logfile = srv->srvconf.errorlog_file->ptr;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2009-04-10 10:50:51 +00:00
|
|
|
if (-1 == (srv->errorlog_fd = open_logfile_or_pipe(srv, logfile))) {
|
2005-02-20 14:27:00 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2009-04-10 10:50:51 +00:00
|
|
|
srv->errorlog_mode = (logfile[0] == '|') ? ERRORLOG_PIPE : ERRORLOG_FILE;
|
2005-02-20 14:27:00 +00:00
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
log_error_write(srv, __FILE__, __LINE__, "s", "server started");
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2009-06-21 17:25:39 +00:00
|
|
|
if (srv->errorlog_mode == ERRORLOG_FD && !srv->srvconf.dont_daemonize) {
|
2008-04-29 20:59:39 +00:00
|
|
|
/* We can only log to stderr in dont-daemonize mode;
|
|
|
|
* if we do daemonize and no errorlog file is specified, we log into /dev/null
|
|
|
|
*/
|
2009-06-21 17:25:39 +00:00
|
|
|
srv->errorlog_fd = -1;
|
2005-02-20 14:27:00 +00:00
|
|
|
}
|
2008-04-29 20:59:39 +00:00
|
|
|
|
2015-02-08 12:37:10 +00:00
|
|
|
if (!buffer_string_is_empty(srv->srvconf.breakagelog_file)) {
|
2009-06-21 17:25:39 +00:00
|
|
|
int breakage_fd;
|
|
|
|
const char *logfile = srv->srvconf.breakagelog_file->ptr;
|
|
|
|
|
|
|
|
if (srv->errorlog_mode == ERRORLOG_FD) {
|
|
|
|
srv->errorlog_fd = dup(STDERR_FILENO);
|
2014-02-16 13:08:29 +00:00
|
|
|
fd_close_on_exec(srv->errorlog_fd);
|
2009-06-21 17:25:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (-1 == (breakage_fd = open_logfile_or_pipe(srv, logfile))) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (STDERR_FILENO != breakage_fd) {
|
|
|
|
dup2(breakage_fd, STDERR_FILENO);
|
|
|
|
close(breakage_fd);
|
|
|
|
}
|
|
|
|
} else if (!srv->srvconf.dont_daemonize) {
|
|
|
|
/* move stderr to /dev/null */
|
|
|
|
openDevNull(STDERR_FILENO);
|
|
|
|
}
|
2005-02-20 14:27:00 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-10-04 13:26:23 +00:00
|
|
|
/**
|
2005-02-20 14:27:00 +00:00
|
|
|
* open the errorlog
|
2006-10-04 13:26:23 +00:00
|
|
|
*
|
2005-02-20 14:27:00 +00:00
|
|
|
* if the open failed, report to the user and die
|
|
|
|
* if no filename is given, use syslog instead
|
2006-10-04 13:26:23 +00:00
|
|
|
*
|
2005-02-20 14:27:00 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
int log_error_cycle(server *srv) {
|
2009-04-10 10:50:51 +00:00
|
|
|
/* only cycle if the error log is a file */
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-26 08:26:28 +00:00
|
|
|
if (srv->errorlog_mode == ERRORLOG_FILE) {
|
|
|
|
const char *logfile = srv->srvconf.errorlog_file->ptr;
|
2005-02-20 14:27:00 +00:00
|
|
|
/* already check of opening time */
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
int new_fd;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2009-04-10 10:50:51 +00:00
|
|
|
if (-1 == (new_fd = open_logfile_or_pipe(srv, logfile))) {
|
2005-02-20 14:27:00 +00:00
|
|
|
/* write to old log */
|
2006-10-04 13:26:23 +00:00
|
|
|
log_error_write(srv, __FILE__, __LINE__, "SSSSS",
|
2005-02-20 14:27:00 +00:00
|
|
|
"cycling errorlog '", logfile,
|
|
|
|
"' failed: ", strerror(errno),
|
|
|
|
", falling back to syslog()");
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-26 08:26:28 +00:00
|
|
|
close(srv->errorlog_fd);
|
|
|
|
srv->errorlog_fd = -1;
|
2006-10-04 13:26:23 +00:00
|
|
|
#ifdef HAVE_SYSLOG_H
|
2005-07-26 08:26:28 +00:00
|
|
|
srv->errorlog_mode = ERRORLOG_SYSLOG;
|
2005-02-20 14:27:00 +00:00
|
|
|
#endif
|
|
|
|
} else {
|
|
|
|
/* ok, new log is open, close the old one */
|
2005-07-26 08:26:28 +00:00
|
|
|
close(srv->errorlog_fd);
|
|
|
|
srv->errorlog_fd = new_fd;
|
2014-02-16 13:08:29 +00:00
|
|
|
fd_close_on_exec(srv->errorlog_fd);
|
2005-02-20 14:27:00 +00:00
|
|
|
}
|
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int log_error_close(server *srv) {
|
2005-07-26 08:26:28 +00:00
|
|
|
switch(srv->errorlog_mode) {
|
2009-04-10 10:50:51 +00:00
|
|
|
case ERRORLOG_PIPE:
|
2005-07-26 08:26:28 +00:00
|
|
|
case ERRORLOG_FILE:
|
2009-06-21 17:25:39 +00:00
|
|
|
case ERRORLOG_FD:
|
|
|
|
if (-1 != srv->errorlog_fd) {
|
|
|
|
/* don't close STDERR */
|
|
|
|
if (STDERR_FILENO != srv->errorlog_fd)
|
|
|
|
close(srv->errorlog_fd);
|
|
|
|
srv->errorlog_fd = -1;
|
|
|
|
}
|
2005-07-26 08:26:28 +00:00
|
|
|
break;
|
|
|
|
case ERRORLOG_SYSLOG:
|
2005-02-20 14:27:00 +00:00
|
|
|
#ifdef HAVE_SYSLOG_H
|
|
|
|
closelog();
|
|
|
|
#endif
|
2005-07-26 08:26:28 +00:00
|
|
|
break;
|
2005-02-20 14:27:00 +00:00
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-03-25 17:22:32 +00:00
|
|
|
/* lowercase: append space, uppercase: don't */
|
|
|
|
static void log_buffer_append_printf(buffer *out, const char *fmt, va_list ap) {
|
|
|
|
for(; *fmt; fmt++) {
|
2005-02-20 14:27:00 +00:00
|
|
|
int d;
|
|
|
|
char *s;
|
|
|
|
buffer *b;
|
|
|
|
off_t o;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
switch(*fmt) {
|
|
|
|
case 's': /* string */
|
|
|
|
s = va_arg(ap, char *);
|
2015-05-28 15:47:14 +00:00
|
|
|
buffer_append_string_c_escaped(out, s, (NULL != s) ? strlen(s) : 0);
|
2013-03-25 17:22:32 +00:00
|
|
|
buffer_append_string_len(out, CONST_STR_LEN(" "));
|
2005-02-20 14:27:00 +00:00
|
|
|
break;
|
|
|
|
case 'b': /* buffer */
|
|
|
|
b = va_arg(ap, buffer *);
|
2015-05-28 15:47:14 +00:00
|
|
|
buffer_append_string_c_escaped(out, CONST_BUF_LEN(b));
|
2013-03-25 17:22:32 +00:00
|
|
|
buffer_append_string_len(out, CONST_STR_LEN(" "));
|
2005-02-20 14:27:00 +00:00
|
|
|
break;
|
|
|
|
case 'd': /* int */
|
|
|
|
d = va_arg(ap, int);
|
2015-02-08 12:37:10 +00:00
|
|
|
buffer_append_int(out, d);
|
2013-03-25 17:22:32 +00:00
|
|
|
buffer_append_string_len(out, CONST_STR_LEN(" "));
|
2005-02-20 14:27:00 +00:00
|
|
|
break;
|
|
|
|
case 'o': /* off_t */
|
|
|
|
o = va_arg(ap, off_t);
|
2015-02-08 12:37:10 +00:00
|
|
|
buffer_append_int(out, o);
|
2013-03-25 17:22:32 +00:00
|
|
|
buffer_append_string_len(out, CONST_STR_LEN(" "));
|
2005-02-20 14:27:00 +00:00
|
|
|
break;
|
|
|
|
case 'x': /* int (hex) */
|
|
|
|
d = va_arg(ap, int);
|
2013-03-25 17:22:32 +00:00
|
|
|
buffer_append_string_len(out, CONST_STR_LEN("0x"));
|
2015-02-08 19:10:46 +00:00
|
|
|
buffer_append_uint_hex(out, d);
|
2013-03-25 17:22:32 +00:00
|
|
|
buffer_append_string_len(out, CONST_STR_LEN(" "));
|
2005-02-20 14:27:00 +00:00
|
|
|
break;
|
|
|
|
case 'S': /* string */
|
|
|
|
s = va_arg(ap, char *);
|
2015-05-28 15:47:14 +00:00
|
|
|
buffer_append_string_c_escaped(out, s, (NULL != s) ? strlen(s) : 0);
|
2005-02-20 14:27:00 +00:00
|
|
|
break;
|
|
|
|
case 'B': /* buffer */
|
|
|
|
b = va_arg(ap, buffer *);
|
2015-05-28 15:47:14 +00:00
|
|
|
buffer_append_string_c_escaped(out, CONST_BUF_LEN(b));
|
2005-02-20 14:27:00 +00:00
|
|
|
break;
|
|
|
|
case 'D': /* int */
|
|
|
|
d = va_arg(ap, int);
|
2015-02-08 12:37:10 +00:00
|
|
|
buffer_append_int(out, d);
|
2005-02-20 14:27:00 +00:00
|
|
|
break;
|
2008-08-19 16:41:42 +00:00
|
|
|
case 'O': /* off_t */
|
|
|
|
o = va_arg(ap, off_t);
|
2015-02-08 12:37:10 +00:00
|
|
|
buffer_append_int(out, o);
|
2008-08-19 16:41:42 +00:00
|
|
|
break;
|
|
|
|
case 'X': /* int (hex) */
|
|
|
|
d = va_arg(ap, int);
|
2013-03-25 17:22:32 +00:00
|
|
|
buffer_append_string_len(out, CONST_STR_LEN("0x"));
|
2015-02-08 19:10:46 +00:00
|
|
|
buffer_append_uint_hex(out, d);
|
2008-08-19 16:41:42 +00:00
|
|
|
break;
|
2005-02-20 14:27:00 +00:00
|
|
|
case '(':
|
|
|
|
case ')':
|
2006-10-04 13:26:23 +00:00
|
|
|
case '<':
|
2005-02-20 14:27:00 +00:00
|
|
|
case '>':
|
|
|
|
case ',':
|
|
|
|
case ' ':
|
2013-03-25 17:22:32 +00:00
|
|
|
buffer_append_string_len(out, fmt, 1);
|
2005-02-20 14:27:00 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2013-03-25 17:22:32 +00:00
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2013-03-25 17:22:32 +00:00
|
|
|
static int log_buffer_prepare(buffer *b, server *srv, const char *filename, unsigned int line) {
|
2005-07-26 08:26:28 +00:00
|
|
|
switch(srv->errorlog_mode) {
|
2009-04-10 10:50:51 +00:00
|
|
|
case ERRORLOG_PIPE:
|
2005-07-26 08:26:28 +00:00
|
|
|
case ERRORLOG_FILE:
|
2009-06-21 17:25:39 +00:00
|
|
|
case ERRORLOG_FD:
|
2013-03-25 17:22:32 +00:00
|
|
|
if (-1 == srv->errorlog_fd) return -1;
|
|
|
|
/* cache the generated timestamp */
|
|
|
|
if (srv->cur_ts != srv->last_generated_debug_ts) {
|
2015-02-08 19:10:39 +00:00
|
|
|
buffer_string_prepare_copy(srv->ts_debug_str, 255);
|
2015-02-08 19:10:44 +00:00
|
|
|
buffer_append_strftime(srv->ts_debug_str, "%Y-%m-%d %H:%M:%S", localtime(&(srv->cur_ts)));
|
2013-03-25 17:22:32 +00:00
|
|
|
|
|
|
|
srv->last_generated_debug_ts = srv->cur_ts;
|
|
|
|
}
|
|
|
|
|
2015-02-08 12:37:10 +00:00
|
|
|
buffer_copy_buffer(b, srv->ts_debug_str);
|
2013-03-25 17:22:32 +00:00
|
|
|
buffer_append_string_len(b, CONST_STR_LEN(": ("));
|
2005-07-26 08:26:28 +00:00
|
|
|
break;
|
|
|
|
case ERRORLOG_SYSLOG:
|
2013-03-25 17:22:32 +00:00
|
|
|
/* syslog is generating its own timestamps */
|
|
|
|
buffer_copy_string_len(b, CONST_STR_LEN("("));
|
2005-07-26 08:26:28 +00:00
|
|
|
break;
|
2005-02-20 14:27:00 +00:00
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2013-03-25 17:22:32 +00:00
|
|
|
buffer_append_string(b, filename);
|
|
|
|
buffer_append_string_len(b, CONST_STR_LEN("."));
|
2015-02-08 12:37:10 +00:00
|
|
|
buffer_append_int(b, line);
|
2013-03-25 17:22:32 +00:00
|
|
|
buffer_append_string_len(b, CONST_STR_LEN(") "));
|
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-03-25 17:22:32 +00:00
|
|
|
static void log_write(server *srv, buffer *b) {
|
|
|
|
switch(srv->errorlog_mode) {
|
|
|
|
case ERRORLOG_PIPE:
|
|
|
|
case ERRORLOG_FILE:
|
|
|
|
case ERRORLOG_FD:
|
|
|
|
buffer_append_string_len(b, CONST_STR_LEN("\n"));
|
2015-08-22 16:01:08 +00:00
|
|
|
write_all(srv->errorlog_fd, CONST_BUF_LEN(b));
|
2013-03-25 17:22:32 +00:00
|
|
|
break;
|
|
|
|
case ERRORLOG_SYSLOG:
|
|
|
|
syslog(LOG_ERR, "%s", b->ptr);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int log_error_write(server *srv, const char *filename, unsigned int line, const char *fmt, ...) {
|
|
|
|
va_list ap;
|
|
|
|
|
|
|
|
if (-1 == log_buffer_prepare(srv->errorlog_buf, srv, filename, line)) return 0;
|
|
|
|
|
|
|
|
va_start(ap, fmt);
|
|
|
|
log_buffer_append_printf(srv->errorlog_buf, fmt, ap);
|
|
|
|
va_end(ap);
|
|
|
|
|
|
|
|
log_write(srv, srv->errorlog_buf);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int log_error_write_multiline_buffer(server *srv, const char *filename, unsigned int line, buffer *multiline, const char *fmt, ...) {
|
|
|
|
va_list ap;
|
2015-02-08 19:10:44 +00:00
|
|
|
size_t prefix_len;
|
2013-03-25 17:22:32 +00:00
|
|
|
buffer *b = srv->errorlog_buf;
|
|
|
|
char *pos, *end, *current_line;
|
|
|
|
|
2015-02-08 19:10:44 +00:00
|
|
|
if (buffer_string_is_empty(multiline)) return 0;
|
2013-03-25 17:22:32 +00:00
|
|
|
|
|
|
|
if (-1 == log_buffer_prepare(b, srv, filename, line)) return 0;
|
|
|
|
|
|
|
|
va_start(ap, fmt);
|
|
|
|
log_buffer_append_printf(b, fmt, ap);
|
|
|
|
va_end(ap);
|
|
|
|
|
2015-02-08 19:10:44 +00:00
|
|
|
prefix_len = buffer_string_length(b);
|
2013-03-25 17:22:32 +00:00
|
|
|
|
|
|
|
current_line = pos = multiline->ptr;
|
2015-02-08 19:10:44 +00:00
|
|
|
end = multiline->ptr + buffer_string_length(multiline);
|
2013-03-25 17:22:32 +00:00
|
|
|
|
2015-02-08 19:10:44 +00:00
|
|
|
for ( ; pos <= end ; ++pos) {
|
2013-03-25 17:22:32 +00:00
|
|
|
switch (*pos) {
|
|
|
|
case '\n':
|
|
|
|
case '\r':
|
|
|
|
case '\0': /* handles end of string */
|
|
|
|
if (current_line < pos) {
|
|
|
|
/* truncate to prefix */
|
2015-02-08 19:10:44 +00:00
|
|
|
buffer_string_set_length(b, prefix_len);
|
2013-03-25 17:22:32 +00:00
|
|
|
|
|
|
|
buffer_append_string_len(b, current_line, pos - current_line);
|
|
|
|
log_write(srv, b);
|
|
|
|
}
|
|
|
|
current_line = pos + 1;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|