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