23 #ifdef HAVE_VALGRIND_VALGRIND_H
24 # include <valgrind/valgrind.h>
28 # define O_LARGEFILE 0
31 /* retry write on EINTR or when not all data was written */
32 ssize_t
write_all(int fd
, const void* buf
, size_t count
) {
36 ssize_t r
= write(fd
, buf
, count
);
43 /* fail - repeating probably won't help */
47 /* really shouldn't happen... */
51 force_assert(r
<= (ssize_t
) count
);
53 buf
= r
+ (char const*) buf
;
61 /* Close fd and _try_ to get a /dev/null for it instead.
62 * close() alone may trigger some bugs when a
63 * process opens another file and gets fd = STDOUT_FILENO or STDERR_FILENO
64 * and later tries to just print on stdout/stderr
66 * Returns 0 on success and -1 on failure (fd gets closed in all cases)
68 int openDevNull(int fd
) {
72 /* Cygwin should work with /dev/null */
73 tmpfd
= open("nul", O_RDWR
);
75 tmpfd
= open("/dev/null", O_RDWR
);
77 if (tmpfd
!= -1 && tmpfd
!= fd
) {
81 return (tmpfd
!= -1) ? 0 : -1;
84 int open_logfile_or_pipe(server
*srv
, const char* logfile
) {
87 if (logfile
[0] == '|') {
89 /* create write pipe and spawn process */
93 if (pipe(to_log_fds
)) {
94 log_error_write(srv
, __FILE__
, __LINE__
, "ss", "pipe failed: ", strerror(errno
));
104 /* dup the filehandle to STDIN */
105 if (to_log_fds
[0] != STDIN_FILENO
) {
106 if (STDIN_FILENO
!= dup2(to_log_fds
[0], STDIN_FILENO
)) {
107 log_error_write(srv
, __FILE__
, __LINE__
, "ss",
108 "dup2 failed: ", strerror(errno
));
111 close(to_log_fds
[0]);
113 close(to_log_fds
[1]);
118 /* we don't need the client socket */
119 for (i
= 3; i
< 256; i
++) {
125 /* close old stderr */
126 openDevNull(STDERR_FILENO
);
128 /* exec the log-process (skip the | ) */
129 execl("/bin/sh", "sh", "-c", logfile
+ 1, NULL
);
130 log_error_write(srv
, __FILE__
, __LINE__
, "sss",
131 "spawning log process failed: ", strerror(errno
),
138 log_error_write(srv
, __FILE__
, __LINE__
, "ss", "fork failed: ", strerror(errno
));
141 close(to_log_fds
[0]);
149 } else if (-1 == (fd
= open(logfile
, O_APPEND
| O_WRONLY
| O_CREAT
| O_LARGEFILE
, 0644))) {
150 log_error_write(srv
, __FILE__
, __LINE__
, "SSSS",
151 "opening errorlog '", logfile
,
152 "' failed: ", strerror(errno
));
157 fd_close_on_exec(fd
);
166 * we have 4 possibilities:
172 * if the open failed, report to the user and die
176 int log_error_open(server
*srv
) {
178 /* perhaps someone wants to use syslog() */
179 openlog("lighttpd", LOG_CONS
| LOG_PID
, LOG_DAEMON
);
182 srv
->errorlog_mode
= ERRORLOG_FD
;
183 srv
->errorlog_fd
= STDERR_FILENO
;
185 if (srv
->srvconf
.errorlog_use_syslog
) {
186 srv
->errorlog_mode
= ERRORLOG_SYSLOG
;
187 } else if (!buffer_string_is_empty(srv
->srvconf
.errorlog_file
)) {
188 const char *logfile
= srv
->srvconf
.errorlog_file
->ptr
;
190 if (-1 == (srv
->errorlog_fd
= open_logfile_or_pipe(srv
, logfile
))) {
193 srv
->errorlog_mode
= (logfile
[0] == '|') ? ERRORLOG_PIPE
: ERRORLOG_FILE
;
196 log_error_write(srv
, __FILE__
, __LINE__
, "s", "server started");
198 if (srv
->errorlog_mode
== ERRORLOG_FD
&& !srv
->srvconf
.dont_daemonize
) {
199 /* We can only log to stderr in dont-daemonize mode;
200 * if we do daemonize and no errorlog file is specified, we log into /dev/null
202 srv
->errorlog_fd
= -1;
205 if (!buffer_string_is_empty(srv
->srvconf
.breakagelog_file
)) {
207 const char *logfile
= srv
->srvconf
.breakagelog_file
->ptr
;
209 if (srv
->errorlog_mode
== ERRORLOG_FD
) {
210 srv
->errorlog_fd
= dup(STDERR_FILENO
);
211 fd_close_on_exec(srv
->errorlog_fd
);
214 if (-1 == (breakage_fd
= open_logfile_or_pipe(srv
, logfile
))) {
218 if (STDERR_FILENO
!= breakage_fd
) {
219 dup2(breakage_fd
, STDERR_FILENO
);
222 } else if (!srv
->srvconf
.dont_daemonize
) {
223 /* move stderr to /dev/null */
224 openDevNull(STDERR_FILENO
);
232 * if the open failed, report to the user and die
233 * if no filename is given, use syslog instead
237 int log_error_cycle(server
*srv
) {
238 /* only cycle if the error log is a file */
240 if (srv
->errorlog_mode
== ERRORLOG_FILE
) {
241 const char *logfile
= srv
->srvconf
.errorlog_file
->ptr
;
242 /* already check of opening time */
246 if (-1 == (new_fd
= open_logfile_or_pipe(srv
, logfile
))) {
247 /* write to old log */
248 log_error_write(srv
, __FILE__
, __LINE__
, "SSSSS",
249 "cycling errorlog '", logfile
,
250 "' failed: ", strerror(errno
),
251 ", falling back to syslog()");
253 close(srv
->errorlog_fd
);
254 srv
->errorlog_fd
= -1;
256 srv
->errorlog_mode
= ERRORLOG_SYSLOG
;
259 /* ok, new log is open, close the old one */
260 close(srv
->errorlog_fd
);
261 srv
->errorlog_fd
= new_fd
;
262 fd_close_on_exec(srv
->errorlog_fd
);
269 int log_error_close(server
*srv
) {
270 switch(srv
->errorlog_mode
) {
274 if (-1 != srv
->errorlog_fd
) {
275 /* don't close STDERR */
276 if (STDERR_FILENO
!= srv
->errorlog_fd
)
277 close(srv
->errorlog_fd
);
278 srv
->errorlog_fd
= -1;
281 case ERRORLOG_SYSLOG
:
291 /* lowercase: append space, uppercase: don't */
292 static void log_buffer_append_printf(buffer
*out
, const char *fmt
, va_list ap
) {
300 case 's': /* string */
301 s
= va_arg(ap
, char *);
302 buffer_append_string_c_escaped(out
, s
, (NULL
!= s
) ? strlen(s
) : 0);
303 buffer_append_string_len(out
, CONST_STR_LEN(" "));
305 case 'b': /* buffer */
306 b
= va_arg(ap
, buffer
*);
307 buffer_append_string_c_escaped(out
, CONST_BUF_LEN(b
));
308 buffer_append_string_len(out
, CONST_STR_LEN(" "));
312 buffer_append_int(out
, d
);
313 buffer_append_string_len(out
, CONST_STR_LEN(" "));
315 case 'o': /* off_t */
316 o
= va_arg(ap
, off_t
);
317 buffer_append_int(out
, o
);
318 buffer_append_string_len(out
, CONST_STR_LEN(" "));
320 case 'x': /* int (hex) */
322 buffer_append_string_len(out
, CONST_STR_LEN("0x"));
323 buffer_append_uint_hex(out
, d
);
324 buffer_append_string_len(out
, CONST_STR_LEN(" "));
326 case 'S': /* string */
327 s
= va_arg(ap
, char *);
328 buffer_append_string_c_escaped(out
, s
, (NULL
!= s
) ? strlen(s
) : 0);
330 case 'B': /* buffer */
331 b
= va_arg(ap
, buffer
*);
332 buffer_append_string_c_escaped(out
, CONST_BUF_LEN(b
));
336 buffer_append_int(out
, d
);
338 case 'O': /* off_t */
339 o
= va_arg(ap
, off_t
);
340 buffer_append_int(out
, o
);
342 case 'X': /* int (hex) */
344 buffer_append_string_len(out
, CONST_STR_LEN("0x"));
345 buffer_append_uint_hex(out
, d
);
353 buffer_append_string_len(out
, fmt
, 1);
359 static int log_buffer_prepare(buffer
*b
, server
*srv
, const char *filename
, unsigned int line
) {
360 switch(srv
->errorlog_mode
) {
364 if (-1 == srv
->errorlog_fd
) return -1;
365 /* cache the generated timestamp */
366 if (srv
->cur_ts
!= srv
->last_generated_debug_ts
) {
367 buffer_string_prepare_copy(srv
->ts_debug_str
, 255);
368 buffer_append_strftime(srv
->ts_debug_str
, "%Y-%m-%d %H:%M:%S", localtime(&(srv
->cur_ts
)));
370 srv
->last_generated_debug_ts
= srv
->cur_ts
;
373 buffer_copy_buffer(b
, srv
->ts_debug_str
);
374 buffer_append_string_len(b
, CONST_STR_LEN(": ("));
376 case ERRORLOG_SYSLOG
:
377 /* syslog is generating its own timestamps */
378 buffer_copy_string_len(b
, CONST_STR_LEN("("));
382 buffer_append_string(b
, filename
);
383 buffer_append_string_len(b
, CONST_STR_LEN("."));
384 buffer_append_int(b
, line
);
385 buffer_append_string_len(b
, CONST_STR_LEN(") "));
390 static void log_write(server
*srv
, buffer
*b
) {
391 switch(srv
->errorlog_mode
) {
395 buffer_append_string_len(b
, CONST_STR_LEN("\n"));
396 write_all(srv
->errorlog_fd
, CONST_BUF_LEN(b
));
398 case ERRORLOG_SYSLOG
:
399 syslog(LOG_ERR
, "%s", b
->ptr
);
404 int log_error_write(server
*srv
, const char *filename
, unsigned int line
, const char *fmt
, ...) {
407 if (-1 == log_buffer_prepare(srv
->errorlog_buf
, srv
, filename
, line
)) return 0;
410 log_buffer_append_printf(srv
->errorlog_buf
, fmt
, ap
);
413 log_write(srv
, srv
->errorlog_buf
);
418 int log_error_write_multiline_buffer(server
*srv
, const char *filename
, unsigned int line
, buffer
*multiline
, const char *fmt
, ...) {
421 buffer
*b
= srv
->errorlog_buf
;
422 char *pos
, *end
, *current_line
;
424 if (buffer_string_is_empty(multiline
)) return 0;
426 if (-1 == log_buffer_prepare(b
, srv
, filename
, line
)) return 0;
429 log_buffer_append_printf(b
, fmt
, ap
);
432 prefix_len
= buffer_string_length(b
);
434 current_line
= pos
= multiline
->ptr
;
435 end
= multiline
->ptr
+ buffer_string_length(multiline
);
437 for ( ; pos
<= end
; ++pos
) {
441 case '\0': /* handles end of string */
442 if (current_line
< pos
) {
443 /* truncate to prefix */
444 buffer_string_set_length(b
, prefix_len
);
446 buffer_append_string_len(b
, current_line
, pos
- current_line
);
449 current_line
= pos
+ 1;