[mod_auth] require digest uri= match original URI
[lighttpd.git] / src / log.c
blob45d22e163beed019400fcf23a070deb7d81d93f9
1 /* _XOPEN_SOURCE >= 500 for vsnprintf() */
2 #ifndef _XOPEN_SOURCE
3 #define _XOPEN_SOURCE 700
4 #endif
6 #include "first.h"
8 #include "base.h"
9 #include "log.h"
11 #include <sys/types.h>
12 #include <errno.h>
13 #include <time.h>
14 #include <string.h>
15 #include <stdarg.h>
16 #include <stdio.h> /* vsnprintf() */
17 #include <stdlib.h> /* malloc() free() */
18 #include <unistd.h>
20 #ifdef HAVE_SYSLOG_H
21 # include <syslog.h>
22 #endif
24 #ifndef HAVE_CLOCK_GETTIME
25 #ifdef HAVE_SYS_TIME_H
26 # include <sys/time.h> /* gettimeofday() */
27 #endif
28 #endif
30 int log_clock_gettime_realtime (struct timespec *ts) {
31 #ifdef HAVE_CLOCK_GETTIME
32 return clock_gettime(CLOCK_REALTIME, ts);
33 #else
34 /* Mac OSX does not provide clock_gettime()
35 * e.g. defined(__APPLE__) && defined(__MACH__) */
36 struct timeval tv;
37 gettimeofday(&tv, NULL);
38 ts->tv_sec = tv.tv_sec;
39 ts->tv_nsec = tv.tv_usec * 1000;
40 return 0;
41 #endif
44 /* retry write on EINTR or when not all data was written */
45 ssize_t write_all(int fd, const void* buf, size_t count) {
46 ssize_t written = 0;
48 while (count > 0) {
49 ssize_t r = write(fd, buf, count);
50 if (r < 0) {
51 switch (errno) {
52 case EINTR:
53 /* try again */
54 break;
55 default:
56 /* fail - repeating probably won't help */
57 return -1;
59 } else if (0 == r) {
60 /* really shouldn't happen... */
61 errno = EIO;
62 return -1;
63 } else {
64 force_assert(r <= (ssize_t) count);
65 written += r;
66 buf = r + (char const*) buf;
67 count -= r;
71 return written;
74 /* lowercase: append space, uppercase: don't */
75 static void log_buffer_append_printf(buffer *out, const char *fmt, va_list ap) {
76 for(; *fmt; fmt++) {
77 int d;
78 char *s;
79 buffer *b;
80 off_t o;
82 switch(*fmt) {
83 case 'S': /* string */
84 case 's': /* string */
85 s = va_arg(ap, char *);
86 buffer_append_string_c_escaped(out, s, (NULL != s) ? strlen(s) : 0);
87 break;
88 case 'B': /* buffer */
89 case 'b': /* buffer */
90 b = va_arg(ap, buffer *);
91 buffer_append_string_c_escaped(out, CONST_BUF_LEN(b));
92 break;
93 case 'D': /* int */
94 case 'd': /* int */
95 d = va_arg(ap, int);
96 buffer_append_int(out, d);
97 break;
98 case 'O': /* off_t */
99 case 'o': /* off_t */
100 o = va_arg(ap, off_t);
101 buffer_append_int(out, o);
102 break;
103 case 'X': /* int (hex) */
104 case 'x': /* int (hex) */
105 d = va_arg(ap, int);
106 buffer_append_string_len(out, CONST_STR_LEN("0x"));
107 buffer_append_uint_hex(out, d);
108 break;
109 case '(':
110 case ')':
111 case '<':
112 case '>':
113 case ',':
114 case ' ':
115 buffer_append_string_len(out, fmt, 1);
116 break;
119 if (*fmt >= 'a') { /* 's' 'b' 'd' 'o' 'x' */
120 buffer_append_string_len(out, CONST_STR_LEN(" "));
125 static int log_buffer_prepare(const log_error_st *errh, const char *filename, unsigned int line, buffer *b) {
126 switch(errh->errorlog_mode) {
127 case ERRORLOG_PIPE:
128 case ERRORLOG_FILE:
129 case ERRORLOG_FD:
130 if (-1 == errh->errorlog_fd) return -1;
131 /* cache the generated timestamp */
132 if (*errh->last_ts != *errh->cur_ts) {
133 *errh->last_ts = *errh->cur_ts;
134 buffer_clear(errh->tb);
135 buffer_append_strftime(errh->tb, "%Y-%m-%d %H:%M:%S", localtime(errh->cur_ts));
138 buffer_copy_buffer(b, errh->tb);
139 buffer_append_string_len(b, CONST_STR_LEN(": ("));
140 break;
141 case ERRORLOG_SYSLOG:
142 /* syslog is generating its own timestamps */
143 buffer_copy_string_len(b, CONST_STR_LEN("("));
144 break;
147 buffer_append_string(b, filename);
148 buffer_append_string_len(b, CONST_STR_LEN("."));
149 buffer_append_int(b, line);
150 buffer_append_string_len(b, CONST_STR_LEN(") "));
152 return 0;
155 static void log_write(const log_error_st *errh, buffer *b) {
156 switch(errh->errorlog_mode) {
157 case ERRORLOG_PIPE:
158 case ERRORLOG_FILE:
159 case ERRORLOG_FD:
160 buffer_append_string_len(b, CONST_STR_LEN("\n"));
161 write_all(errh->errorlog_fd, CONST_BUF_LEN(b));
162 break;
163 case ERRORLOG_SYSLOG:
164 syslog(LOG_ERR, "%s", b->ptr);
165 break;
169 int log_error_write(server *srv, const char *filename, unsigned int line, const char *fmt, ...) {
170 const log_error_st *errh = srv->errh;
171 buffer *b = errh->b;
172 if (-1 == log_buffer_prepare(errh, filename, line, b)) return 0;
174 va_list ap;
175 va_start(ap, fmt);
176 log_buffer_append_printf(b, fmt, ap);
177 va_end(ap);
179 log_write(errh, b);
181 return 0;
184 int log_error_write_multiline_buffer(server *srv, const char *filename, unsigned int line, buffer *multiline, const char *fmt, ...) {
185 const log_error_st *errh = srv->errh;
186 buffer *b = errh->b;
187 va_list ap;
188 size_t prefix_len;
189 char *pos, *end, *current_line;
191 if (buffer_string_is_empty(multiline)) return 0;
193 if (-1 == log_buffer_prepare(errh, filename, line, b)) return 0;
195 va_start(ap, fmt);
196 log_buffer_append_printf(b, fmt, ap);
197 va_end(ap);
199 prefix_len = buffer_string_length(b);
201 current_line = pos = multiline->ptr;
202 end = multiline->ptr + buffer_string_length(multiline);
204 for ( ; pos <= end ; ++pos) {
205 switch (*pos) {
206 case '\n':
207 case '\r':
208 case '\0': /* handles end of string */
209 if (current_line < pos) {
210 /* truncate to prefix */
211 buffer_string_set_length(b, prefix_len);
213 buffer_append_string_len(b, current_line, pos - current_line);
214 log_write(errh, b);
216 current_line = pos + 1;
217 break;
218 default:
219 break;
223 return 0;
227 static void
228 log_buffer_vprintf (buffer * const b,
229 const char * const fmt, va_list ap)
231 /* NOTE: log_buffer_prepare() ensures 0 != b->used */
232 /*assert(0 != b->used);*//*(only because code calcs below assume this)*/
233 /*assert(0 != b->size);*//*(errh->b should not have 0 size here)*/
234 size_t blen = buffer_string_length(b);
235 size_t bsp = buffer_string_space(b)+1;
236 char *s = b->ptr + blen;
237 size_t n;
239 va_list aptry;
240 va_copy(aptry, ap);
241 n = (size_t)vsnprintf(s, bsp, fmt, aptry);
242 va_end(aptry);
244 if (n >= bsp) {
245 buffer_string_prepare_append(b, n); /*(must re-read s after realloc)*/
246 vsnprintf((s = b->ptr + blen), buffer_string_space(b)+1, fmt, ap);
249 size_t i;
250 for (i = 0; i < n && ' ' <= s[i] && s[i] <= '~'; ++i) ;/*(ASCII isprint())*/
251 if (i == n) {
252 buffer_string_set_length(b, blen + n);
253 return; /* common case; nothing to encode */
256 /* need to encode log line
257 * copy original line fragment, append encoded line to buffer, free copy */
258 char * const src = (char *)malloc(n);
259 memcpy(src, s, n); /*(note: not '\0'-terminated)*/
260 buffer_append_string_c_escaped(b, src, n);
261 free(src);
265 static void
266 log_error_va_list_impl (const log_error_st * const errh,
267 const char * const filename,
268 const unsigned int line,
269 const char * const fmt, va_list ap,
270 const int perr)
272 const int errnum = errno;
273 buffer * const b = errh->b;
274 if (-1 == log_buffer_prepare(errh, filename, line, b)) return;
275 log_buffer_vprintf(b, fmt, ap);
276 if (perr) {
277 buffer_append_string_len(b, CONST_STR_LEN(": "));
278 buffer_append_string(b, strerror(errnum));
280 log_write(errh, b);
281 errno = errnum;
285 void
286 log_error(const log_error_st * const errh,
287 const char * const filename, const unsigned int line,
288 const char *fmt, ...)
290 va_list ap;
291 va_start(ap, fmt);
292 log_error_va_list_impl(errh, filename, line, fmt, ap, 0);
293 va_end(ap);
297 void
298 log_perror (const log_error_st * const errh,
299 const char * const filename, const unsigned int line,
300 const char * const fmt, ...)
302 va_list ap;
303 va_start(ap, fmt);
304 log_error_va_list_impl(errh, filename, line, fmt, ap, 1);
305 va_end(ap);
309 log_error_st *
310 log_error_st_init (time_t *cur_ts_ptr, time_t *last_ts_ptr)
312 log_error_st *errh = calloc(1, sizeof(log_error_st));
313 force_assert(errh);
314 errh->errorlog_fd = STDERR_FILENO;
315 errh->errorlog_mode = ERRORLOG_FD;
316 errh->b = buffer_init();
317 errh->tb = buffer_init();
318 errh->cur_ts = cur_ts_ptr;
319 errh->last_ts = last_ts_ptr;
320 return errh;
324 void
325 log_error_st_free (log_error_st *errh)
327 if (NULL == errh) return;
328 buffer_free(errh->tb);
329 buffer_free(errh->b);
330 free(errh);