[autobuild] allow sendfile() in cross-compile (fixes #2836)
[lighttpd.git] / src / log.c
blob6a3d0a5b5308ba38ea8abec77fdd37a7c42b18b5
1 #include "first.h"
3 #include "base.h"
4 #include "log.h"
6 #include <sys/types.h>
7 #include <errno.h>
8 #include <time.h>
9 #include <string.h>
10 #include <stdarg.h>
11 #include <unistd.h>
13 #ifdef HAVE_SYSLOG_H
14 # include <syslog.h>
15 #endif
17 #ifndef HAVE_CLOCK_GETTIME
18 #ifdef HAVE_SYS_TIME_H
19 # include <sys/time.h> /* gettimeofday() */
20 #endif
21 #endif
23 int log_clock_gettime_realtime (struct timespec *ts) {
24 #ifdef HAVE_CLOCK_GETTIME
25 return clock_gettime(CLOCK_REALTIME, ts);
26 #else
27 /* Mac OSX does not provide clock_gettime()
28 * e.g. defined(__APPLE__) && defined(__MACH__) */
29 struct timeval tv;
30 gettimeofday(&tv, NULL);
31 ts->tv_sec = tv.tv_sec;
32 ts->tv_nsec = tv.tv_usec * 1000;
33 return 0;
34 #endif
37 /* retry write on EINTR or when not all data was written */
38 ssize_t write_all(int fd, const void* buf, size_t count) {
39 ssize_t written = 0;
41 while (count > 0) {
42 ssize_t r = write(fd, buf, count);
43 if (r < 0) {
44 switch (errno) {
45 case EINTR:
46 /* try again */
47 break;
48 default:
49 /* fail - repeating probably won't help */
50 return -1;
52 } else if (0 == r) {
53 /* really shouldn't happen... */
54 errno = EIO;
55 return -1;
56 } else {
57 force_assert(r <= (ssize_t) count);
58 written += r;
59 buf = r + (char const*) buf;
60 count -= r;
64 return written;
67 /* lowercase: append space, uppercase: don't */
68 static void log_buffer_append_printf(buffer *out, const char *fmt, va_list ap) {
69 for(; *fmt; fmt++) {
70 int d;
71 char *s;
72 buffer *b;
73 off_t o;
75 switch(*fmt) {
76 case 's': /* string */
77 s = va_arg(ap, char *);
78 buffer_append_string_c_escaped(out, s, (NULL != s) ? strlen(s) : 0);
79 buffer_append_string_len(out, CONST_STR_LEN(" "));
80 break;
81 case 'b': /* buffer */
82 b = va_arg(ap, buffer *);
83 buffer_append_string_c_escaped(out, CONST_BUF_LEN(b));
84 buffer_append_string_len(out, CONST_STR_LEN(" "));
85 break;
86 case 'd': /* int */
87 d = va_arg(ap, int);
88 buffer_append_int(out, d);
89 buffer_append_string_len(out, CONST_STR_LEN(" "));
90 break;
91 case 'o': /* off_t */
92 o = va_arg(ap, off_t);
93 buffer_append_int(out, o);
94 buffer_append_string_len(out, CONST_STR_LEN(" "));
95 break;
96 case 'x': /* int (hex) */
97 d = va_arg(ap, int);
98 buffer_append_string_len(out, CONST_STR_LEN("0x"));
99 buffer_append_uint_hex(out, d);
100 buffer_append_string_len(out, CONST_STR_LEN(" "));
101 break;
102 case 'S': /* string */
103 s = va_arg(ap, char *);
104 buffer_append_string_c_escaped(out, s, (NULL != s) ? strlen(s) : 0);
105 break;
106 case 'B': /* buffer */
107 b = va_arg(ap, buffer *);
108 buffer_append_string_c_escaped(out, CONST_BUF_LEN(b));
109 break;
110 case 'D': /* int */
111 d = va_arg(ap, int);
112 buffer_append_int(out, d);
113 break;
114 case 'O': /* off_t */
115 o = va_arg(ap, off_t);
116 buffer_append_int(out, o);
117 break;
118 case 'X': /* int (hex) */
119 d = va_arg(ap, int);
120 buffer_append_string_len(out, CONST_STR_LEN("0x"));
121 buffer_append_uint_hex(out, d);
122 break;
123 case '(':
124 case ')':
125 case '<':
126 case '>':
127 case ',':
128 case ' ':
129 buffer_append_string_len(out, fmt, 1);
130 break;
135 static int log_buffer_prepare(buffer *b, server *srv, const char *filename, unsigned int line) {
136 switch(srv->errorlog_mode) {
137 case ERRORLOG_PIPE:
138 case ERRORLOG_FILE:
139 case ERRORLOG_FD:
140 if (-1 == srv->errorlog_fd) return -1;
141 /* cache the generated timestamp */
142 if (srv->cur_ts != srv->last_generated_debug_ts) {
143 buffer_string_prepare_copy(srv->ts_debug_str, 255);
144 buffer_append_strftime(srv->ts_debug_str, "%Y-%m-%d %H:%M:%S", localtime(&(srv->cur_ts)));
146 srv->last_generated_debug_ts = srv->cur_ts;
149 buffer_copy_buffer(b, srv->ts_debug_str);
150 buffer_append_string_len(b, CONST_STR_LEN(": ("));
151 break;
152 case ERRORLOG_SYSLOG:
153 /* syslog is generating its own timestamps */
154 buffer_copy_string_len(b, CONST_STR_LEN("("));
155 break;
158 buffer_append_string(b, filename);
159 buffer_append_string_len(b, CONST_STR_LEN("."));
160 buffer_append_int(b, line);
161 buffer_append_string_len(b, CONST_STR_LEN(") "));
163 return 0;
166 static void log_write(server *srv, buffer *b) {
167 switch(srv->errorlog_mode) {
168 case ERRORLOG_PIPE:
169 case ERRORLOG_FILE:
170 case ERRORLOG_FD:
171 buffer_append_string_len(b, CONST_STR_LEN("\n"));
172 write_all(srv->errorlog_fd, CONST_BUF_LEN(b));
173 break;
174 case ERRORLOG_SYSLOG:
175 syslog(LOG_ERR, "%s", b->ptr);
176 break;
180 int log_error_write(server *srv, const char *filename, unsigned int line, const char *fmt, ...) {
181 va_list ap;
183 if (-1 == log_buffer_prepare(srv->errorlog_buf, srv, filename, line)) return 0;
185 va_start(ap, fmt);
186 log_buffer_append_printf(srv->errorlog_buf, fmt, ap);
187 va_end(ap);
189 log_write(srv, srv->errorlog_buf);
191 return 0;
194 int log_error_write_multiline_buffer(server *srv, const char *filename, unsigned int line, buffer *multiline, const char *fmt, ...) {
195 va_list ap;
196 size_t prefix_len;
197 buffer *b = srv->errorlog_buf;
198 char *pos, *end, *current_line;
200 if (buffer_string_is_empty(multiline)) return 0;
202 if (-1 == log_buffer_prepare(b, srv, filename, line)) return 0;
204 va_start(ap, fmt);
205 log_buffer_append_printf(b, fmt, ap);
206 va_end(ap);
208 prefix_len = buffer_string_length(b);
210 current_line = pos = multiline->ptr;
211 end = multiline->ptr + buffer_string_length(multiline);
213 for ( ; pos <= end ; ++pos) {
214 switch (*pos) {
215 case '\n':
216 case '\r':
217 case '\0': /* handles end of string */
218 if (current_line < pos) {
219 /* truncate to prefix */
220 buffer_string_set_length(b, prefix_len);
222 buffer_append_string_len(b, current_line, pos - current_line);
223 log_write(srv, b);
225 current_line = pos + 1;
226 break;
227 default:
228 break;
232 return 0;