Annotation of embedaddon/lighttpd/src/log.c, revision 1.1.1.3
1.1.1.3 ! misho 1: #include "first.h"
! 2:
1.1 misho 3: #include "base.h"
4: #include "log.h"
5: #include "array.h"
6:
7: #include <sys/types.h>
8:
9: #include <errno.h>
10: #include <fcntl.h>
11: #include <time.h>
12: #include <unistd.h>
13: #include <string.h>
14: #include <stdlib.h>
15:
16: #include <stdarg.h>
17: #include <stdio.h>
18:
19: #ifdef HAVE_SYSLOG_H
20: # include <syslog.h>
21: #endif
22:
23: #ifdef HAVE_VALGRIND_VALGRIND_H
24: # include <valgrind/valgrind.h>
25: #endif
26:
27: #ifndef O_LARGEFILE
28: # define O_LARGEFILE 0
29: #endif
30:
1.1.1.3 ! misho 31: #ifndef HAVE_CLOCK_GETTIME
! 32: #ifdef HAVE_SYS_TIME_H
! 33: # include <sys/time.h> /* gettimeofday() */
! 34: #endif
! 35: #endif
! 36:
! 37: int log_clock_gettime_realtime (struct timespec *ts) {
! 38: #ifdef HAVE_CLOCK_GETTIME
! 39: return clock_gettime(CLOCK_REALTIME, ts);
! 40: #else
! 41: /* Mac OSX does not provide clock_gettime()
! 42: * e.g. defined(__APPLE__) && defined(__MACH__) */
! 43: struct timeval tv;
! 44: gettimeofday(&tv, NULL);
! 45: ts->tv_sec = tv.tv_sec;
! 46: ts->tv_nsec = tv.tv_usec * 1000;
! 47: return 0;
! 48: #endif
! 49: }
! 50:
! 51: /* retry write on EINTR or when not all data was written */
! 52: ssize_t write_all(int fd, const void* buf, size_t count) {
! 53: ssize_t written = 0;
! 54:
! 55: while (count > 0) {
! 56: ssize_t r = write(fd, buf, count);
! 57: if (r < 0) {
! 58: switch (errno) {
! 59: case EINTR:
! 60: /* try again */
! 61: break;
! 62: default:
! 63: /* fail - repeating probably won't help */
! 64: return -1;
! 65: }
! 66: } else if (0 == r) {
! 67: /* really shouldn't happen... */
! 68: errno = EIO;
! 69: return -1;
! 70: } else {
! 71: force_assert(r <= (ssize_t) count);
! 72: written += r;
! 73: buf = r + (char const*) buf;
! 74: count -= r;
! 75: }
! 76: }
! 77:
! 78: return written;
! 79: }
! 80:
1.1 misho 81: /* Close fd and _try_ to get a /dev/null for it instead.
82: * close() alone may trigger some bugs when a
83: * process opens another file and gets fd = STDOUT_FILENO or STDERR_FILENO
84: * and later tries to just print on stdout/stderr
85: *
86: * Returns 0 on success and -1 on failure (fd gets closed in all cases)
87: */
88: int openDevNull(int fd) {
89: int tmpfd;
90: close(fd);
91: #if defined(__WIN32)
92: /* Cygwin should work with /dev/null */
93: tmpfd = open("nul", O_RDWR);
94: #else
95: tmpfd = open("/dev/null", O_RDWR);
96: #endif
97: if (tmpfd != -1 && tmpfd != fd) {
98: dup2(tmpfd, fd);
99: close(tmpfd);
100: }
101: return (tmpfd != -1) ? 0 : -1;
102: }
103:
104: int open_logfile_or_pipe(server *srv, const char* logfile) {
105: int fd;
106:
107: if (logfile[0] == '|') {
108: #ifdef HAVE_FORK
109: /* create write pipe and spawn process */
110:
111: int to_log_fds[2];
112:
113: if (pipe(to_log_fds)) {
114: log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed: ", strerror(errno));
115: return -1;
116: }
117:
118: /* fork, execve */
119: switch (fork()) {
120: case 0:
121: /* child */
122: close(STDIN_FILENO);
123:
124: /* dup the filehandle to STDIN */
125: if (to_log_fds[0] != STDIN_FILENO) {
126: if (STDIN_FILENO != dup2(to_log_fds[0], STDIN_FILENO)) {
127: log_error_write(srv, __FILE__, __LINE__, "ss",
128: "dup2 failed: ", strerror(errno));
129: exit(-1);
130: }
131: close(to_log_fds[0]);
132: }
133: close(to_log_fds[1]);
134:
135: #ifndef FD_CLOEXEC
136: {
137: int i;
138: /* we don't need the client socket */
139: for (i = 3; i < 256; i++) {
140: close(i);
141: }
142: }
143: #endif
144:
145: /* close old stderr */
146: openDevNull(STDERR_FILENO);
147:
148: /* exec the log-process (skip the | ) */
149: execl("/bin/sh", "sh", "-c", logfile + 1, NULL);
150: log_error_write(srv, __FILE__, __LINE__, "sss",
151: "spawning log process failed: ", strerror(errno),
152: logfile + 1);
153:
154: exit(-1);
155: break;
156: case -1:
157: /* error */
158: log_error_write(srv, __FILE__, __LINE__, "ss", "fork failed: ", strerror(errno));
159: return -1;
160: default:
161: close(to_log_fds[0]);
162: fd = to_log_fds[1];
163: break;
164: }
165:
166: #else
167: return -1;
168: #endif
169: } else if (-1 == (fd = open(logfile, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
170: log_error_write(srv, __FILE__, __LINE__, "SSSS",
171: "opening errorlog '", logfile,
172: "' failed: ", strerror(errno));
173:
174: return -1;
175: }
176:
1.1.1.2 misho 177: fd_close_on_exec(fd);
1.1 misho 178:
179: return fd;
180: }
181:
182:
183: /**
184: * open the errorlog
185: *
186: * we have 4 possibilities:
187: * - stderr (default)
188: * - syslog
189: * - logfile
190: * - pipe
191: *
192: * if the open failed, report to the user and die
193: *
194: */
195:
196: int log_error_open(server *srv) {
197: #ifdef HAVE_SYSLOG_H
198: /* perhaps someone wants to use syslog() */
199: openlog("lighttpd", LOG_CONS | LOG_PID, LOG_DAEMON);
200: #endif
201:
202: srv->errorlog_mode = ERRORLOG_FD;
203: srv->errorlog_fd = STDERR_FILENO;
204:
205: if (srv->srvconf.errorlog_use_syslog) {
206: srv->errorlog_mode = ERRORLOG_SYSLOG;
1.1.1.3 ! misho 207: } else if (!buffer_string_is_empty(srv->srvconf.errorlog_file)) {
1.1 misho 208: const char *logfile = srv->srvconf.errorlog_file->ptr;
209:
210: if (-1 == (srv->errorlog_fd = open_logfile_or_pipe(srv, logfile))) {
211: return -1;
212: }
213: srv->errorlog_mode = (logfile[0] == '|') ? ERRORLOG_PIPE : ERRORLOG_FILE;
214: }
215:
216: log_error_write(srv, __FILE__, __LINE__, "s", "server started");
217:
218: if (srv->errorlog_mode == ERRORLOG_FD && !srv->srvconf.dont_daemonize) {
219: /* We can only log to stderr in dont-daemonize mode;
220: * if we do daemonize and no errorlog file is specified, we log into /dev/null
221: */
222: srv->errorlog_fd = -1;
223: }
224:
1.1.1.3 ! misho 225: if (!buffer_string_is_empty(srv->srvconf.breakagelog_file)) {
1.1 misho 226: int breakage_fd;
227: const char *logfile = srv->srvconf.breakagelog_file->ptr;
228:
229: if (srv->errorlog_mode == ERRORLOG_FD) {
230: srv->errorlog_fd = dup(STDERR_FILENO);
1.1.1.2 misho 231: fd_close_on_exec(srv->errorlog_fd);
1.1 misho 232: }
233:
234: if (-1 == (breakage_fd = open_logfile_or_pipe(srv, logfile))) {
235: return -1;
236: }
237:
238: if (STDERR_FILENO != breakage_fd) {
239: dup2(breakage_fd, STDERR_FILENO);
240: close(breakage_fd);
241: }
242: } else if (!srv->srvconf.dont_daemonize) {
243: /* move stderr to /dev/null */
244: openDevNull(STDERR_FILENO);
245: }
246: return 0;
247: }
248:
249: /**
250: * open the errorlog
251: *
252: * if the open failed, report to the user and die
253: * if no filename is given, use syslog instead
254: *
255: */
256:
257: int log_error_cycle(server *srv) {
258: /* only cycle if the error log is a file */
259:
260: if (srv->errorlog_mode == ERRORLOG_FILE) {
261: const char *logfile = srv->srvconf.errorlog_file->ptr;
262: /* already check of opening time */
263:
264: int new_fd;
265:
266: if (-1 == (new_fd = open_logfile_or_pipe(srv, logfile))) {
267: /* write to old log */
268: log_error_write(srv, __FILE__, __LINE__, "SSSSS",
269: "cycling errorlog '", logfile,
270: "' failed: ", strerror(errno),
271: ", falling back to syslog()");
272:
273: close(srv->errorlog_fd);
274: srv->errorlog_fd = -1;
275: #ifdef HAVE_SYSLOG_H
276: srv->errorlog_mode = ERRORLOG_SYSLOG;
277: #endif
278: } else {
279: /* ok, new log is open, close the old one */
280: close(srv->errorlog_fd);
281: srv->errorlog_fd = new_fd;
1.1.1.2 misho 282: fd_close_on_exec(srv->errorlog_fd);
1.1 misho 283: }
284: }
285:
286: return 0;
287: }
288:
289: int log_error_close(server *srv) {
290: switch(srv->errorlog_mode) {
291: case ERRORLOG_PIPE:
292: case ERRORLOG_FILE:
293: case ERRORLOG_FD:
294: if (-1 != srv->errorlog_fd) {
295: /* don't close STDERR */
296: if (STDERR_FILENO != srv->errorlog_fd)
297: close(srv->errorlog_fd);
298: srv->errorlog_fd = -1;
299: }
300: break;
301: case ERRORLOG_SYSLOG:
302: #ifdef HAVE_SYSLOG_H
303: closelog();
304: #endif
305: break;
306: }
307:
308: return 0;
309: }
310:
311: /* lowercase: append space, uppercase: don't */
312: static void log_buffer_append_printf(buffer *out, const char *fmt, va_list ap) {
313: for(; *fmt; fmt++) {
314: int d;
315: char *s;
316: buffer *b;
317: off_t o;
318:
319: switch(*fmt) {
320: case 's': /* string */
321: s = va_arg(ap, char *);
1.1.1.3 ! misho 322: buffer_append_string_c_escaped(out, s, (NULL != s) ? strlen(s) : 0);
1.1 misho 323: buffer_append_string_len(out, CONST_STR_LEN(" "));
324: break;
325: case 'b': /* buffer */
326: b = va_arg(ap, buffer *);
1.1.1.3 ! misho 327: buffer_append_string_c_escaped(out, CONST_BUF_LEN(b));
1.1 misho 328: buffer_append_string_len(out, CONST_STR_LEN(" "));
329: break;
330: case 'd': /* int */
331: d = va_arg(ap, int);
1.1.1.3 ! misho 332: buffer_append_int(out, d);
1.1 misho 333: buffer_append_string_len(out, CONST_STR_LEN(" "));
334: break;
335: case 'o': /* off_t */
336: o = va_arg(ap, off_t);
1.1.1.3 ! misho 337: buffer_append_int(out, o);
1.1 misho 338: buffer_append_string_len(out, CONST_STR_LEN(" "));
339: break;
340: case 'x': /* int (hex) */
341: d = va_arg(ap, int);
342: buffer_append_string_len(out, CONST_STR_LEN("0x"));
1.1.1.3 ! misho 343: buffer_append_uint_hex(out, d);
1.1 misho 344: buffer_append_string_len(out, CONST_STR_LEN(" "));
345: break;
346: case 'S': /* string */
347: s = va_arg(ap, char *);
1.1.1.3 ! misho 348: buffer_append_string_c_escaped(out, s, (NULL != s) ? strlen(s) : 0);
1.1 misho 349: break;
350: case 'B': /* buffer */
351: b = va_arg(ap, buffer *);
1.1.1.3 ! misho 352: buffer_append_string_c_escaped(out, CONST_BUF_LEN(b));
1.1 misho 353: break;
354: case 'D': /* int */
355: d = va_arg(ap, int);
1.1.1.3 ! misho 356: buffer_append_int(out, d);
1.1 misho 357: break;
358: case 'O': /* off_t */
359: o = va_arg(ap, off_t);
1.1.1.3 ! misho 360: buffer_append_int(out, o);
1.1 misho 361: break;
362: case 'X': /* int (hex) */
363: d = va_arg(ap, int);
364: buffer_append_string_len(out, CONST_STR_LEN("0x"));
1.1.1.3 ! misho 365: buffer_append_uint_hex(out, d);
1.1 misho 366: break;
367: case '(':
368: case ')':
369: case '<':
370: case '>':
371: case ',':
372: case ' ':
373: buffer_append_string_len(out, fmt, 1);
374: break;
375: }
376: }
377: }
378:
379: static int log_buffer_prepare(buffer *b, server *srv, const char *filename, unsigned int line) {
380: switch(srv->errorlog_mode) {
381: case ERRORLOG_PIPE:
382: case ERRORLOG_FILE:
383: case ERRORLOG_FD:
384: if (-1 == srv->errorlog_fd) return -1;
385: /* cache the generated timestamp */
386: if (srv->cur_ts != srv->last_generated_debug_ts) {
1.1.1.3 ! misho 387: buffer_string_prepare_copy(srv->ts_debug_str, 255);
! 388: buffer_append_strftime(srv->ts_debug_str, "%Y-%m-%d %H:%M:%S", localtime(&(srv->cur_ts)));
1.1 misho 389:
390: srv->last_generated_debug_ts = srv->cur_ts;
391: }
392:
1.1.1.3 ! misho 393: buffer_copy_buffer(b, srv->ts_debug_str);
1.1 misho 394: buffer_append_string_len(b, CONST_STR_LEN(": ("));
395: break;
396: case ERRORLOG_SYSLOG:
397: /* syslog is generating its own timestamps */
398: buffer_copy_string_len(b, CONST_STR_LEN("("));
399: break;
400: }
401:
402: buffer_append_string(b, filename);
403: buffer_append_string_len(b, CONST_STR_LEN("."));
1.1.1.3 ! misho 404: buffer_append_int(b, line);
1.1 misho 405: buffer_append_string_len(b, CONST_STR_LEN(") "));
406:
407: return 0;
408: }
409:
410: static void log_write(server *srv, buffer *b) {
411: switch(srv->errorlog_mode) {
412: case ERRORLOG_PIPE:
413: case ERRORLOG_FILE:
414: case ERRORLOG_FD:
415: buffer_append_string_len(b, CONST_STR_LEN("\n"));
1.1.1.3 ! misho 416: write_all(srv->errorlog_fd, CONST_BUF_LEN(b));
1.1 misho 417: break;
418: case ERRORLOG_SYSLOG:
419: syslog(LOG_ERR, "%s", b->ptr);
420: break;
421: }
422: }
423:
424: int log_error_write(server *srv, const char *filename, unsigned int line, const char *fmt, ...) {
425: va_list ap;
426:
427: if (-1 == log_buffer_prepare(srv->errorlog_buf, srv, filename, line)) return 0;
428:
429: va_start(ap, fmt);
430: log_buffer_append_printf(srv->errorlog_buf, fmt, ap);
431: va_end(ap);
432:
433: log_write(srv, srv->errorlog_buf);
434:
435: return 0;
436: }
437:
438: int log_error_write_multiline_buffer(server *srv, const char *filename, unsigned int line, buffer *multiline, const char *fmt, ...) {
439: va_list ap;
1.1.1.3 ! misho 440: size_t prefix_len;
1.1 misho 441: buffer *b = srv->errorlog_buf;
442: char *pos, *end, *current_line;
443:
1.1.1.3 ! misho 444: if (buffer_string_is_empty(multiline)) return 0;
1.1 misho 445:
446: if (-1 == log_buffer_prepare(b, srv, filename, line)) return 0;
447:
448: va_start(ap, fmt);
449: log_buffer_append_printf(b, fmt, ap);
450: va_end(ap);
451:
1.1.1.3 ! misho 452: prefix_len = buffer_string_length(b);
1.1 misho 453:
454: current_line = pos = multiline->ptr;
1.1.1.3 ! misho 455: end = multiline->ptr + buffer_string_length(multiline);
1.1 misho 456:
1.1.1.3 ! misho 457: for ( ; pos <= end ; ++pos) {
1.1 misho 458: switch (*pos) {
459: case '\n':
460: case '\r':
461: case '\0': /* handles end of string */
462: if (current_line < pos) {
463: /* truncate to prefix */
1.1.1.3 ! misho 464: buffer_string_set_length(b, prefix_len);
1.1 misho 465:
466: buffer_append_string_len(b, current_line, pos - current_line);
467: log_write(srv, b);
468: }
469: current_line = pos + 1;
470: break;
471: default:
472: break;
473: }
474: }
475:
476: return 0;
477: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>