Annotation of embedaddon/lighttpd/src/log.c, revision 1.1.1.1
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:
125: #ifdef FD_CLOEXEC
126: fcntl(fd, F_SETFD, FD_CLOEXEC);
127: #endif
128:
129: return fd;
130: }
131:
132:
133: /**
134: * open the errorlog
135: *
136: * we have 4 possibilities:
137: * - stderr (default)
138: * - syslog
139: * - logfile
140: * - pipe
141: *
142: * if the open failed, report to the user and die
143: *
144: */
145:
146: int log_error_open(server *srv) {
147: #ifdef HAVE_SYSLOG_H
148: /* perhaps someone wants to use syslog() */
149: openlog("lighttpd", LOG_CONS | LOG_PID, LOG_DAEMON);
150: #endif
151:
152: srv->errorlog_mode = ERRORLOG_FD;
153: srv->errorlog_fd = STDERR_FILENO;
154:
155: if (srv->srvconf.errorlog_use_syslog) {
156: srv->errorlog_mode = ERRORLOG_SYSLOG;
157: } else if (!buffer_is_empty(srv->srvconf.errorlog_file)) {
158: const char *logfile = srv->srvconf.errorlog_file->ptr;
159:
160: if (-1 == (srv->errorlog_fd = open_logfile_or_pipe(srv, logfile))) {
161: return -1;
162: }
163: srv->errorlog_mode = (logfile[0] == '|') ? ERRORLOG_PIPE : ERRORLOG_FILE;
164: }
165:
166: log_error_write(srv, __FILE__, __LINE__, "s", "server started");
167:
168: if (srv->errorlog_mode == ERRORLOG_FD && !srv->srvconf.dont_daemonize) {
169: /* We can only log to stderr in dont-daemonize mode;
170: * if we do daemonize and no errorlog file is specified, we log into /dev/null
171: */
172: srv->errorlog_fd = -1;
173: }
174:
175: if (!buffer_is_empty(srv->srvconf.breakagelog_file)) {
176: int breakage_fd;
177: const char *logfile = srv->srvconf.breakagelog_file->ptr;
178:
179: if (srv->errorlog_mode == ERRORLOG_FD) {
180: srv->errorlog_fd = dup(STDERR_FILENO);
181: #ifdef FD_CLOEXEC
182: fcntl(srv->errorlog_fd, F_SETFD, FD_CLOEXEC);
183: #endif
184: }
185:
186: if (-1 == (breakage_fd = open_logfile_or_pipe(srv, logfile))) {
187: return -1;
188: }
189:
190: if (STDERR_FILENO != breakage_fd) {
191: dup2(breakage_fd, STDERR_FILENO);
192: close(breakage_fd);
193: }
194: } else if (!srv->srvconf.dont_daemonize) {
195: /* move stderr to /dev/null */
196: openDevNull(STDERR_FILENO);
197: }
198: return 0;
199: }
200:
201: /**
202: * open the errorlog
203: *
204: * if the open failed, report to the user and die
205: * if no filename is given, use syslog instead
206: *
207: */
208:
209: int log_error_cycle(server *srv) {
210: /* only cycle if the error log is a file */
211:
212: if (srv->errorlog_mode == ERRORLOG_FILE) {
213: const char *logfile = srv->srvconf.errorlog_file->ptr;
214: /* already check of opening time */
215:
216: int new_fd;
217:
218: if (-1 == (new_fd = open_logfile_or_pipe(srv, logfile))) {
219: /* write to old log */
220: log_error_write(srv, __FILE__, __LINE__, "SSSSS",
221: "cycling errorlog '", logfile,
222: "' failed: ", strerror(errno),
223: ", falling back to syslog()");
224:
225: close(srv->errorlog_fd);
226: srv->errorlog_fd = -1;
227: #ifdef HAVE_SYSLOG_H
228: srv->errorlog_mode = ERRORLOG_SYSLOG;
229: #endif
230: } else {
231: /* ok, new log is open, close the old one */
232: close(srv->errorlog_fd);
233: srv->errorlog_fd = new_fd;
234: #ifdef FD_CLOEXEC
235: /* close fd on exec (cgi) */
236: fcntl(srv->errorlog_fd, F_SETFD, FD_CLOEXEC);
237: #endif
238: }
239: }
240:
241: return 0;
242: }
243:
244: int log_error_close(server *srv) {
245: switch(srv->errorlog_mode) {
246: case ERRORLOG_PIPE:
247: case ERRORLOG_FILE:
248: case ERRORLOG_FD:
249: if (-1 != srv->errorlog_fd) {
250: /* don't close STDERR */
251: if (STDERR_FILENO != srv->errorlog_fd)
252: close(srv->errorlog_fd);
253: srv->errorlog_fd = -1;
254: }
255: break;
256: case ERRORLOG_SYSLOG:
257: #ifdef HAVE_SYSLOG_H
258: closelog();
259: #endif
260: break;
261: }
262:
263: return 0;
264: }
265:
266: /* lowercase: append space, uppercase: don't */
267: static void log_buffer_append_printf(buffer *out, const char *fmt, va_list ap) {
268: for(; *fmt; fmt++) {
269: int d;
270: char *s;
271: buffer *b;
272: off_t o;
273:
274: switch(*fmt) {
275: case 's': /* string */
276: s = va_arg(ap, char *);
277: buffer_append_string(out, s);
278: buffer_append_string_len(out, CONST_STR_LEN(" "));
279: break;
280: case 'b': /* buffer */
281: b = va_arg(ap, buffer *);
282: buffer_append_string_buffer(out, b);
283: buffer_append_string_len(out, CONST_STR_LEN(" "));
284: break;
285: case 'd': /* int */
286: d = va_arg(ap, int);
287: buffer_append_long(out, d);
288: buffer_append_string_len(out, CONST_STR_LEN(" "));
289: break;
290: case 'o': /* off_t */
291: o = va_arg(ap, off_t);
292: buffer_append_off_t(out, o);
293: buffer_append_string_len(out, CONST_STR_LEN(" "));
294: break;
295: case 'x': /* int (hex) */
296: d = va_arg(ap, int);
297: buffer_append_string_len(out, CONST_STR_LEN("0x"));
298: buffer_append_long_hex(out, d);
299: buffer_append_string_len(out, CONST_STR_LEN(" "));
300: break;
301: case 'S': /* string */
302: s = va_arg(ap, char *);
303: buffer_append_string(out, s);
304: break;
305: case 'B': /* buffer */
306: b = va_arg(ap, buffer *);
307: buffer_append_string_buffer(out, b);
308: break;
309: case 'D': /* int */
310: d = va_arg(ap, int);
311: buffer_append_long(out, d);
312: break;
313: case 'O': /* off_t */
314: o = va_arg(ap, off_t);
315: buffer_append_off_t(out, o);
316: break;
317: case 'X': /* int (hex) */
318: d = va_arg(ap, int);
319: buffer_append_string_len(out, CONST_STR_LEN("0x"));
320: buffer_append_long_hex(out, d);
321: break;
322: case '(':
323: case ')':
324: case '<':
325: case '>':
326: case ',':
327: case ' ':
328: buffer_append_string_len(out, fmt, 1);
329: break;
330: }
331: }
332: }
333:
334: static int log_buffer_prepare(buffer *b, server *srv, const char *filename, unsigned int line) {
335: switch(srv->errorlog_mode) {
336: case ERRORLOG_PIPE:
337: case ERRORLOG_FILE:
338: case ERRORLOG_FD:
339: if (-1 == srv->errorlog_fd) return -1;
340: /* cache the generated timestamp */
341: if (srv->cur_ts != srv->last_generated_debug_ts) {
342: buffer_prepare_copy(srv->ts_debug_str, 255);
343: strftime(srv->ts_debug_str->ptr, srv->ts_debug_str->size - 1, "%Y-%m-%d %H:%M:%S", localtime(&(srv->cur_ts)));
344: srv->ts_debug_str->used = strlen(srv->ts_debug_str->ptr) + 1;
345:
346: srv->last_generated_debug_ts = srv->cur_ts;
347: }
348:
349: buffer_copy_string_buffer(b, srv->ts_debug_str);
350: buffer_append_string_len(b, CONST_STR_LEN(": ("));
351: break;
352: case ERRORLOG_SYSLOG:
353: /* syslog is generating its own timestamps */
354: buffer_copy_string_len(b, CONST_STR_LEN("("));
355: break;
356: }
357:
358: buffer_append_string(b, filename);
359: buffer_append_string_len(b, CONST_STR_LEN("."));
360: buffer_append_long(b, line);
361: buffer_append_string_len(b, CONST_STR_LEN(") "));
362:
363: return 0;
364: }
365:
366: static void log_write(server *srv, buffer *b) {
367: switch(srv->errorlog_mode) {
368: case ERRORLOG_PIPE:
369: case ERRORLOG_FILE:
370: case ERRORLOG_FD:
371: buffer_append_string_len(b, CONST_STR_LEN("\n"));
372: write(srv->errorlog_fd, b->ptr, b->used - 1);
373: break;
374: case ERRORLOG_SYSLOG:
375: syslog(LOG_ERR, "%s", b->ptr);
376: break;
377: }
378: }
379:
380: int log_error_write(server *srv, const char *filename, unsigned int line, const char *fmt, ...) {
381: va_list ap;
382:
383: if (-1 == log_buffer_prepare(srv->errorlog_buf, srv, filename, line)) return 0;
384:
385: va_start(ap, fmt);
386: log_buffer_append_printf(srv->errorlog_buf, fmt, ap);
387: va_end(ap);
388:
389: log_write(srv, srv->errorlog_buf);
390:
391: return 0;
392: }
393:
394: int log_error_write_multiline_buffer(server *srv, const char *filename, unsigned int line, buffer *multiline, const char *fmt, ...) {
395: va_list ap;
396: size_t prefix_used;
397: buffer *b = srv->errorlog_buf;
398: char *pos, *end, *current_line;
399:
400: if (multiline->used < 2) return 0;
401:
402: if (-1 == log_buffer_prepare(b, srv, filename, line)) return 0;
403:
404: va_start(ap, fmt);
405: log_buffer_append_printf(b, fmt, ap);
406: va_end(ap);
407:
408: prefix_used = b->used;
409:
410: current_line = pos = multiline->ptr;
411: end = multiline->ptr + multiline->used;
412:
413: for ( ; pos < end ; ++pos) {
414: switch (*pos) {
415: case '\n':
416: case '\r':
417: case '\0': /* handles end of string */
418: if (current_line < pos) {
419: /* truncate to prefix */
420: b->used = prefix_used;
421: b->ptr[b->used - 1] = '\0';
422:
423: buffer_append_string_len(b, current_line, pos - current_line);
424: log_write(srv, b);
425: }
426: current_line = pos + 1;
427: break;
428: default:
429: break;
430: }
431: }
432:
433: return 0;
434: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>