Line data Source code
1 : /*********************************************************************
2 : *
3 : * File : $Source: /cvsroot/ijbswa/current/errlog.c,v $
4 : *
5 : * Purpose : Log errors to a designated destination in an elegant,
6 : * printf-like fashion.
7 : *
8 : * Copyright : Written by and Copyright (C) 2001-2014 the
9 : * Privoxy team. https://www.privoxy.org/
10 : *
11 : * Based on the Internet Junkbuster originally written
12 : * by and Copyright (C) 1997 Anonymous Coders and
13 : * Junkbusters Corporation. http://www.junkbusters.com
14 : *
15 : * This program is free software; you can redistribute it
16 : * and/or modify it under the terms of the GNU General
17 : * Public License as published by the Free Software
18 : * Foundation; either version 2 of the License, or (at
19 : * your option) any later version.
20 : *
21 : * This program is distributed in the hope that it will
22 : * be useful, but WITHOUT ANY WARRANTY; without even the
23 : * implied warranty of MERCHANTABILITY or FITNESS FOR A
24 : * PARTICULAR PURPOSE. See the GNU General Public
25 : * License for more details.
26 : *
27 : * The GNU General Public License should be included with
28 : * this file. If not, you can view it at
29 : * http://www.gnu.org/copyleft/gpl.html
30 : * or write to the Free Software Foundation, Inc., 59
31 : * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
32 : *
33 : *********************************************************************/
34 :
35 :
36 : #include <stdlib.h>
37 : #include <stdio.h>
38 : #include <stdarg.h>
39 : #include <string.h>
40 : #include <ctype.h>
41 :
42 : #include "config.h"
43 : #include "miscutil.h"
44 :
45 : /* For gettimeofday() */
46 : #include <sys/time.h>
47 :
48 : #if !defined(_WIN32)
49 : #include <unistd.h>
50 : #endif /* !defined(_WIN32) */
51 :
52 : #include <errno.h>
53 : #include <assert.h>
54 :
55 : #ifdef _WIN32
56 : #ifndef STRICT
57 : #define STRICT
58 : #endif
59 : #include <windows.h>
60 : #ifndef _WIN_CONSOLE
61 : #include "w32log.h"
62 : #endif /* ndef _WIN_CONSOLE */
63 : #endif /* def _WIN32 */
64 : #ifdef _MSC_VER
65 : #define inline __inline
66 : #endif /* def _MSC_VER */
67 :
68 : #include "errlog.h"
69 : #include "project.h"
70 : #include "jcc.h"
71 : #ifdef FEATURE_EXTERNAL_FILTERS
72 : #include "jbsockets.h"
73 : #endif
74 :
75 : /*
76 : * LOG_LEVEL_FATAL cannot be turned off. (There are
77 : * some exceptional situations where we need to get a
78 : * message to the user).
79 : */
80 : #define LOG_LEVEL_MINIMUM LOG_LEVEL_FATAL
81 :
82 : /* where to log (default: stderr) */
83 : static FILE *logfp = NULL;
84 :
85 : /* logging detail level. XXX: stupid name. */
86 : static int debug = (LOG_LEVEL_FATAL | LOG_LEVEL_ERROR);
87 :
88 : /* static functions */
89 : static void fatal_error(const char * error_message);
90 : #ifdef _WIN32
91 : static char *w32_socket_strerr(int errcode, char *tmp_buf);
92 : #endif
93 :
94 : #ifdef MUTEX_LOCKS_AVAILABLE
95 3979424 : static void lock_logfile(void)
96 : {
97 3979424 : privoxy_mutex_lock(&log_mutex);
98 3979424 : }
99 3979424 : static void unlock_logfile(void)
100 : {
101 3979424 : privoxy_mutex_unlock(&log_mutex);
102 3979424 : }
103 0 : static void lock_loginit(void)
104 : {
105 0 : privoxy_mutex_lock(&log_init_mutex);
106 0 : }
107 0 : static void unlock_loginit(void)
108 : {
109 0 : privoxy_mutex_unlock(&log_init_mutex);
110 0 : }
111 : #else /* ! MUTEX_LOCKS_AVAILABLE */
112 : /*
113 : * FIXME we need a cross-platform locking mechanism.
114 : * The locking/unlocking functions below should be
115 : * fleshed out for non-pthread implementations.
116 : */
117 : static void lock_logfile() {}
118 : static void unlock_logfile() {}
119 : static void lock_loginit() {}
120 : static void unlock_loginit() {}
121 : #endif
122 :
123 : /*********************************************************************
124 : *
125 : * Function : fatal_error
126 : *
127 : * Description : Displays a fatal error to standard error (or, on
128 : * a WIN32 GUI, to a dialog box), and exits Privoxy
129 : * with status code 1.
130 : *
131 : * Parameters :
132 : * 1 : error_message = The error message to display.
133 : *
134 : * Returns : Does not return.
135 : *
136 : *********************************************************************/
137 0 : static void fatal_error(const char *error_message)
138 : {
139 0 : if (logfp != NULL)
140 : {
141 0 : fputs(error_message, logfp);
142 : }
143 :
144 : #if defined(_WIN32) && !defined(_WIN_CONSOLE)
145 : {
146 : /* Skip timestamp and thread id for the message box. */
147 : const char *box_message = strstr(error_message, "Fatal error");
148 : if (NULL == box_message)
149 : {
150 : /* Shouldn't happen but ... */
151 : box_message = error_message;
152 : }
153 : MessageBox(g_hwndLogFrame, box_message, "Privoxy Error",
154 : MB_OK | MB_ICONERROR | MB_TASKMODAL | MB_SETFOREGROUND | MB_TOPMOST);
155 :
156 : /* Cleanup - remove taskbar icon etc. */
157 : TermLogWindow();
158 : }
159 : #endif /* defined(_WIN32) && !defined(_WIN_CONSOLE) */
160 :
161 : #if defined(unix)
162 0 : if (pidfile)
163 : {
164 0 : unlink(pidfile);
165 : }
166 : #endif /* unix */
167 :
168 0 : exit(1);
169 : }
170 :
171 :
172 : /*********************************************************************
173 : *
174 : * Function : show_version
175 : *
176 : * Description : Logs the Privoxy version and the program name.
177 : *
178 : * Parameters :
179 : * 1 : prog_name = The program name.
180 : *
181 : * Returns : Nothing.
182 : *
183 : *********************************************************************/
184 3098 : void show_version(const char *prog_name)
185 : {
186 3098 : log_error(LOG_LEVEL_INFO, "Privoxy version " VERSION);
187 3098 : if (prog_name != NULL)
188 : {
189 3098 : log_error(LOG_LEVEL_INFO, "Program name: %s", prog_name);
190 : }
191 3098 : }
192 :
193 :
194 : /*********************************************************************
195 : *
196 : * Function : init_log_module
197 : *
198 : * Description : Initializes the logging module to log to stderr.
199 : * Can only be called while stderr hasn't been closed
200 : * yet and is only supposed to be called once.
201 : *
202 : * Parameters :
203 : * 1 : prog_name = The program name.
204 : *
205 : * Returns : Nothing.
206 : *
207 : *********************************************************************/
208 3098 : void init_log_module(void)
209 : {
210 3098 : lock_logfile();
211 3098 : logfp = stderr;
212 3098 : unlock_logfile();
213 3098 : set_debug_level(debug);
214 3098 : }
215 :
216 :
217 : /*********************************************************************
218 : *
219 : * Function : set_debug_level
220 : *
221 : * Description : Sets the debug level to the provided value
222 : * plus LOG_LEVEL_MINIMUM.
223 : *
224 : * XXX: we should only use the LOG_LEVEL_MINIMUM
225 : * until the first time the configuration file has
226 : * been parsed.
227 : *
228 : * Parameters : 1: debug_level = The debug level to set.
229 : *
230 : * Returns : Nothing.
231 : *
232 : *********************************************************************/
233 12392 : void set_debug_level(int debug_level)
234 : {
235 : #ifdef FUZZ
236 12392 : if (LOG_LEVEL_STFU == debug_level)
237 : {
238 0 : debug = LOG_LEVEL_STFU;
239 : }
240 12392 : if (LOG_LEVEL_STFU == debug)
241 : {
242 0 : return;
243 : }
244 : #endif
245 :
246 12392 : debug = debug_level | LOG_LEVEL_MINIMUM;
247 : }
248 :
249 :
250 : /*********************************************************************
251 : *
252 : * Function : debug_level_is_enabled
253 : *
254 : * Description : Checks if a certain debug level is enabled.
255 : *
256 : * Parameters : 1: debug_level = The debug level to check.
257 : *
258 : * Returns : Nothing.
259 : *
260 : *********************************************************************/
261 35226 : int debug_level_is_enabled(int debug_level)
262 : {
263 35226 : return (0 != (debug & debug_level));
264 : }
265 :
266 :
267 : /*********************************************************************
268 : *
269 : * Function : disable_logging
270 : *
271 : * Description : Disables logging.
272 : *
273 : * Parameters : None.
274 : *
275 : * Returns : Nothing.
276 : *
277 : *********************************************************************/
278 0 : void disable_logging(void)
279 : {
280 0 : if (logfp != NULL)
281 : {
282 0 : log_error(LOG_LEVEL_INFO,
283 : "No logfile configured. Please enable it before reporting any problems.");
284 0 : lock_logfile();
285 0 : fclose(logfp);
286 0 : logfp = NULL;
287 0 : unlock_logfile();
288 : }
289 0 : }
290 :
291 :
292 : /*********************************************************************
293 : *
294 : * Function : init_error_log
295 : *
296 : * Description : Initializes the logging module to log to a file.
297 : *
298 : * XXX: should be renamed.
299 : *
300 : * Parameters :
301 : * 1 : prog_name = The program name.
302 : * 2 : logfname = The logfile to (re)open.
303 : *
304 : * Returns : N/A
305 : *
306 : *********************************************************************/
307 0 : void init_error_log(const char *prog_name, const char *logfname)
308 : {
309 : FILE *fp;
310 :
311 0 : assert(NULL != logfname);
312 :
313 0 : lock_loginit();
314 :
315 0 : if ((logfp != NULL) && (logfp != stderr))
316 : {
317 0 : log_error(LOG_LEVEL_INFO, "(Re-)Opening logfile \'%s\'", logfname);
318 : }
319 :
320 : /* set the designated log file */
321 0 : fp = fopen(logfname, "a");
322 0 : if ((NULL == fp) && (logfp != NULL))
323 : {
324 : /*
325 : * Some platforms (like OS/2 (XXX: no longer supported)) don't
326 : * allow us to open the same file twice, therefore we give it
327 : * another shot after closing the old file descriptor first.
328 : *
329 : * We don't do it right away because it prevents us
330 : * from logging the "can't open logfile" message to
331 : * the old logfile.
332 : *
333 : * XXX: this is a lame workaround and once the next
334 : * release is out we should stop bothering reopening
335 : * the logfile unless we have to.
336 : *
337 : * Currently we reopen it every time the config file
338 : * has been reloaded, but actually we only have to
339 : * reopen it if the file name changed or if the
340 : * configuration reload was caused by a SIGHUP.
341 : */
342 0 : log_error(LOG_LEVEL_INFO, "Failed to reopen logfile: \'%s\'. "
343 : "Retrying after closing the old file descriptor first. If that "
344 : "doesn't work, Privoxy will exit without being able to log a message.",
345 : logfname);
346 0 : lock_logfile();
347 0 : fclose(logfp);
348 0 : logfp = NULL;
349 0 : unlock_logfile();
350 0 : fp = fopen(logfname, "a");
351 : }
352 :
353 0 : if (NULL == fp)
354 : {
355 0 : log_error(LOG_LEVEL_FATAL, "init_error_log(): can't open logfile: \'%s\'", logfname);
356 : }
357 :
358 : #ifdef FEATURE_EXTERNAL_FILTERS
359 0 : mark_socket_for_close_on_execute(3);
360 : #endif
361 :
362 : /* set logging to be completely unbuffered */
363 0 : setbuf(fp, NULL);
364 :
365 0 : lock_logfile();
366 0 : if (logfp != NULL)
367 : {
368 0 : fclose(logfp);
369 : }
370 : #ifdef unix
371 0 : if (daemon_mode && (logfp == stderr))
372 : {
373 0 : if (dup2(1, 2) == -1)
374 : {
375 : /*
376 : * We only use fatal_error() to clear the pid
377 : * file and to exit. Given that stderr has just
378 : * been closed, the user will not see the error
379 : * message.
380 : */
381 0 : fatal_error("Failed to reserve fd 2.");
382 : }
383 : }
384 : #endif
385 0 : logfp = fp;
386 0 : unlock_logfile();
387 :
388 0 : show_version(prog_name);
389 :
390 0 : unlock_loginit();
391 :
392 0 : } /* init_error_log */
393 :
394 :
395 : /*********************************************************************
396 : *
397 : * Function : get_thread_id
398 : *
399 : * Description : Returns a number that is different for each thread.
400 : *
401 : * XXX: Should be moved elsewhere (miscutil.c?)
402 : *
403 : * Parameters : None
404 : *
405 : * Returns : thread_id
406 : *
407 : *********************************************************************/
408 3976326 : static long get_thread_id(void)
409 : {
410 : long this_thread;
411 :
412 : /* FIXME get current thread id */
413 : #ifdef FEATURE_PTHREAD
414 3976326 : this_thread = (long)pthread_self();
415 : #ifdef __MACH__
416 : /*
417 : * Mac OSX (and perhaps other Mach instances) doesn't have a unique
418 : * value at the lowest order 4 bytes of pthread_self()'s return value, a pthread_t,
419 : * so trim the three lowest-order bytes from the value (16^3).
420 : */
421 : this_thread = this_thread / 4096;
422 : #endif /* def __MACH__ */
423 : #elif defined(_WIN32)
424 : this_thread = GetCurrentThreadId();
425 : #else
426 : /* Forking instead of threading. */
427 : this_thread = 1;
428 : #endif /* def FEATURE_PTHREAD */
429 :
430 3976326 : return this_thread;
431 : }
432 :
433 :
434 : /*********************************************************************
435 : *
436 : * Function : get_log_timestamp
437 : *
438 : * Description : Generates the time stamp for the log message prefix.
439 : *
440 : * Parameters :
441 : * 1 : buffer = Storage buffer
442 : * 2 : buffer_size = Size of storage buffer
443 : *
444 : * Returns : Number of written characters or 0 for error.
445 : *
446 : *********************************************************************/
447 3976326 : static size_t get_log_timestamp(char *buffer, size_t buffer_size)
448 : {
449 : size_t length;
450 : time_t now;
451 : struct tm tm_now;
452 : struct timeval tv_now; /* XXX: stupid name */
453 : long msecs;
454 3976326 : int msecs_length = 0;
455 :
456 3976326 : gettimeofday(&tv_now, NULL);
457 3976326 : msecs = tv_now.tv_usec / 1000;
458 3976326 : now = tv_now.tv_sec;
459 :
460 : #ifdef HAVE_LOCALTIME_R
461 3976326 : tm_now = *localtime_r(&now, &tm_now);
462 : #elif defined(MUTEX_LOCKS_AVAILABLE)
463 : privoxy_mutex_lock(&localtime_mutex);
464 : tm_now = *localtime(&now);
465 : privoxy_mutex_unlock(&localtime_mutex);
466 : #else
467 : tm_now = *localtime(&now);
468 : #endif
469 :
470 3976326 : length = strftime(buffer, buffer_size, "%Y-%m-%d %H:%M:%S", &tm_now);
471 3976326 : if (length > (size_t)0)
472 : {
473 3976326 : msecs_length = snprintf(buffer+length, buffer_size - length, ".%.3ld", msecs);
474 : }
475 3976326 : if (msecs_length > 0)
476 : {
477 3976326 : length += (size_t)msecs_length;
478 : }
479 : else
480 : {
481 0 : length = 0;
482 : }
483 :
484 3976326 : return length;
485 : }
486 :
487 :
488 : /*********************************************************************
489 : *
490 : * Function : get_clf_timestamp
491 : *
492 : * Description : Generates a Common Log Format time string.
493 : *
494 : * Parameters :
495 : * 1 : buffer = Storage buffer
496 : * 2 : buffer_size = Size of storage buffer
497 : *
498 : * Returns : Number of written characters or 0 for error.
499 : *
500 : *********************************************************************/
501 0 : static size_t get_clf_timestamp(char *buffer, size_t buffer_size)
502 : {
503 : /*
504 : * Complex because not all OSs have tm_gmtoff or
505 : * the %z field in strftime()
506 : */
507 : time_t now;
508 : struct tm *tm_now;
509 : struct tm gmt;
510 : #ifdef HAVE_LOCALTIME_R
511 : struct tm dummy;
512 : #endif
513 : int days, hrs, mins;
514 : size_t length;
515 0 : int tz_length = 0;
516 :
517 0 : time (&now);
518 0 : gmt = *privoxy_gmtime_r(&now, &gmt);
519 : #ifdef HAVE_LOCALTIME_R
520 0 : tm_now = localtime_r(&now, &dummy);
521 : #elif defined(MUTEX_LOCKS_AVAILABLE)
522 : privoxy_mutex_lock(&localtime_mutex);
523 : tm_now = localtime(&now);
524 : #else
525 : tm_now = localtime(&now);
526 : #endif
527 0 : days = tm_now->tm_yday - gmt.tm_yday;
528 0 : hrs = ((days < -1 ? 24 : 1 < days ? -24 : days * 24) + tm_now->tm_hour - gmt.tm_hour);
529 0 : mins = hrs * 60 + tm_now->tm_min - gmt.tm_min;
530 :
531 0 : length = strftime(buffer, buffer_size, "%d/%b/%Y:%H:%M:%S ", tm_now);
532 : #if !defined(HAVE_LOCALTIME_R) && defined(MUTEX_LOCKS_AVAILABLE)
533 : privoxy_mutex_unlock(&localtime_mutex);
534 : #endif
535 :
536 0 : if (length > (size_t)0)
537 : {
538 0 : tz_length = snprintf(buffer+length, buffer_size-length,
539 0 : "%+03d%02d", mins / 60, abs(mins) % 60);
540 : }
541 0 : if (tz_length > 0)
542 : {
543 0 : length += (size_t)tz_length;
544 : }
545 : else
546 : {
547 0 : length = 0;
548 : }
549 :
550 0 : return length;
551 : }
552 :
553 :
554 : /*********************************************************************
555 : *
556 : * Function : get_log_level_string
557 : *
558 : * Description : Translates a numerical loglevel into a string.
559 : *
560 : * Parameters :
561 : * 1 : loglevel = LOG_LEVEL_FOO
562 : *
563 : * Returns : Log level string.
564 : *
565 : *********************************************************************/
566 3976326 : static const char *get_log_level_string(int loglevel)
567 : {
568 3976326 : char *log_level_string = NULL;
569 :
570 3976326 : assert(0 < loglevel);
571 :
572 3976326 : switch (loglevel)
573 : {
574 13158 : case LOG_LEVEL_ERROR:
575 13158 : log_level_string = "Error";
576 13158 : break;
577 0 : case LOG_LEVEL_FATAL:
578 0 : log_level_string = "Fatal error";
579 0 : break;
580 0 : case LOG_LEVEL_REQUEST:
581 0 : log_level_string = "Request";
582 0 : break;
583 153428 : case LOG_LEVEL_CONNECT:
584 153428 : log_level_string = "Connect";
585 153428 : break;
586 0 : case LOG_LEVEL_TAGGING:
587 0 : log_level_string = "Tagging";
588 0 : break;
589 68778 : case LOG_LEVEL_WRITING:
590 68778 : log_level_string = "Writing";
591 68778 : break;
592 53457 : case LOG_LEVEL_RECEIVED:
593 53457 : log_level_string = "Received";
594 53457 : break;
595 893932 : case LOG_LEVEL_HEADER:
596 893932 : log_level_string = "Header";
597 893932 : break;
598 20016 : case LOG_LEVEL_INFO:
599 20016 : log_level_string = "Info";
600 20016 : break;
601 2737765 : case LOG_LEVEL_RE_FILTER:
602 2737765 : log_level_string = "Re-Filter";
603 2737765 : break;
604 : #ifdef FEATURE_FORCE_LOAD
605 0 : case LOG_LEVEL_FORCE:
606 0 : log_level_string = "Force";
607 0 : break;
608 : #endif /* def FEATURE_FORCE_LOAD */
609 0 : case LOG_LEVEL_REDIRECTS:
610 0 : log_level_string = "Redirect";
611 0 : break;
612 566 : case LOG_LEVEL_DEANIMATE:
613 566 : log_level_string = "Gif-Deanimate";
614 566 : break;
615 0 : case LOG_LEVEL_CRUNCH:
616 0 : log_level_string = "Crunch";
617 0 : break;
618 0 : case LOG_LEVEL_CGI:
619 0 : log_level_string = "CGI";
620 0 : break;
621 35226 : case LOG_LEVEL_ACTIONS:
622 35226 : log_level_string = "Actions";
623 35226 : break;
624 0 : default:
625 0 : log_level_string = "Unknown log level";
626 0 : break;
627 : }
628 3976326 : assert(NULL != log_level_string);
629 :
630 3976326 : return log_level_string;
631 : }
632 :
633 :
634 : #define LOG_BUFFER_SIZE BUFFER_SIZE
635 : /*********************************************************************
636 : *
637 : * Function : log_error
638 : *
639 : * Description : This is the error-reporting and logging function.
640 : *
641 : * Parameters :
642 : * 1 : loglevel = the type of message to be logged
643 : * 2 : fmt = the main string we want logged, printf-like
644 : * 3 : ... = arguments to be inserted in fmt (printf-like).
645 : *
646 : * Returns : N/A
647 : *
648 : *********************************************************************/
649 5239083 : void log_error(int loglevel, const char *fmt, ...)
650 : {
651 : va_list ap;
652 : char outbuf[LOG_BUFFER_SIZE+1];
653 : char tempbuf[LOG_BUFFER_SIZE];
654 5239083 : size_t length = 0;
655 5239083 : const char * src = fmt;
656 : long thread_id;
657 : char timestamp[30];
658 5239083 : const size_t log_buffer_size = LOG_BUFFER_SIZE;
659 :
660 : #if defined(_WIN32) && !defined(_WIN_CONSOLE)
661 : /*
662 : * Irrespective of debug setting, a GET/POST/CONNECT makes
663 : * the taskbar icon animate. (There is an option to disable
664 : * this but checking that is handled inside LogShowActivity()).
665 : */
666 : if ((loglevel == LOG_LEVEL_REQUEST) || (loglevel == LOG_LEVEL_CRUNCH))
667 : {
668 : LogShowActivity();
669 : }
670 : #endif /* defined(_WIN32) && !defined(_WIN_CONSOLE) */
671 :
672 : /*
673 : * verify that the loglevel applies to current
674 : * settings and that logging is enabled.
675 : * Bail out otherwise.
676 : */
677 5239083 : if ((0 == (loglevel & debug))
678 : #ifndef _WIN32
679 3976326 : || (logfp == NULL)
680 : #endif
681 : )
682 : {
683 : #ifdef FUZZ
684 1262757 : if (debug == LOG_LEVEL_STFU)
685 : {
686 0 : if (loglevel == LOG_LEVEL_FATAL)
687 : {
688 0 : exit(1);
689 : }
690 1262757 : return;
691 : }
692 : #endif
693 1262757 : if (loglevel == LOG_LEVEL_FATAL)
694 : {
695 0 : fatal_error("Fatal error. You're not supposed to"
696 : "see this message. Please file a bug report.");
697 : }
698 1262757 : return;
699 : }
700 :
701 3976326 : thread_id = get_thread_id();
702 3976326 : get_log_timestamp(timestamp, sizeof(timestamp));
703 :
704 : /*
705 : * Memsetting the whole buffer to zero (in theory)
706 : * makes things easier later on.
707 : */
708 3976326 : memset(outbuf, 0, sizeof(outbuf));
709 :
710 : /* Add prefix for everything but Common Log Format messages */
711 3976326 : if (loglevel != LOG_LEVEL_CLF)
712 : {
713 3976326 : length = (size_t)snprintf(outbuf, log_buffer_size, "%s %08lx %s: ",
714 : timestamp, thread_id, get_log_level_string(loglevel));
715 : }
716 :
717 : /* get ready to scan var. args. */
718 3976326 : va_start(ap, fmt);
719 :
720 : /* build formatted message from fmt and var-args */
721 127930662 : while ((*src) && (length < log_buffer_size-2))
722 : {
723 123963114 : const char *sval = NULL; /* %N string */
724 : int ival; /* %N string length or an error code */
725 : unsigned uval; /* %u value */
726 : long lval; /* %l value */
727 : unsigned long ulval; /* %ul value */
728 : char ch;
729 123963114 : const char *format_string = tempbuf;
730 :
731 123963114 : ch = *src++;
732 123963114 : if (ch != '%')
733 : {
734 115738631 : outbuf[length++] = ch;
735 : /*
736 : * XXX: Only necessary on platforms where multiple threads
737 : * can write to the buffer at the same time because we
738 : * don't support mutexes.
739 : * XXX: Are there any such platforms left now that OS/2 is gone?
740 : */
741 115738631 : outbuf[length] = '\0';
742 115738631 : continue;
743 : }
744 8224483 : outbuf[length] = '\0';
745 8224483 : ch = *src++;
746 8224483 : switch (ch) {
747 0 : case '%':
748 0 : tempbuf[0] = '%';
749 0 : tempbuf[1] = '\0';
750 0 : break;
751 1530665 : case 'd':
752 1530665 : ival = va_arg(ap, int);
753 1530665 : snprintf(tempbuf, sizeof(tempbuf), "%d", ival);
754 1530665 : break;
755 64099 : case 'u':
756 64099 : uval = va_arg(ap, unsigned);
757 64099 : snprintf(tempbuf, sizeof(tempbuf), "%u", uval);
758 64099 : break;
759 2639912 : case 'l':
760 : /* this is a modifier that must be followed by u, lu, or d */
761 2639912 : ch = *src++;
762 2639912 : if (ch == 'd')
763 : {
764 25577 : lval = va_arg(ap, long);
765 25577 : snprintf(tempbuf, sizeof(tempbuf), "%ld", lval);
766 : }
767 2614335 : else if (ch == 'u')
768 : {
769 2603538 : ulval = va_arg(ap, unsigned long);
770 2603538 : snprintf(tempbuf, sizeof(tempbuf), "%lu", ulval);
771 : }
772 10797 : else if ((ch == 'l') && (*src == 'u'))
773 10797 : {
774 10797 : unsigned long long lluval = va_arg(ap, unsigned long long);
775 10797 : snprintf(tempbuf, sizeof(tempbuf), "%llu", lluval);
776 10797 : src++;
777 : }
778 : else
779 : {
780 0 : snprintf(tempbuf, sizeof(tempbuf), "Bad format string: \"%s\"", fmt);
781 0 : loglevel = LOG_LEVEL_FATAL;
782 : }
783 2639912 : break;
784 615 : case 'c':
785 : /*
786 : * Note that char parameters are converted to int, so we need to
787 : * pass "int" to va_arg. (See K&R, 2nd ed, section A7.3.2, page 202)
788 : */
789 615 : tempbuf[0] = (char) va_arg(ap, int);
790 615 : tempbuf[1] = '\0';
791 615 : break;
792 3866610 : case 's':
793 3866610 : format_string = va_arg(ap, char *);
794 3866610 : if (format_string == NULL)
795 : {
796 0 : format_string = "[null]";
797 : }
798 3866610 : break;
799 122235 : case 'N':
800 : /*
801 : * Non-standard: Print a counted unterminated string,
802 : * replacing unprintable bytes with their hex value.
803 : * Takes 2 parameters: int length, const char * string.
804 : */
805 122235 : ival = va_arg(ap, int);
806 122235 : assert(ival >= 0);
807 122235 : sval = va_arg(ap, char *);
808 122235 : assert(sval != NULL);
809 :
810 106963985 : while ((ival-- > 0) && (length < log_buffer_size - 6))
811 : {
812 106841750 : if (isprint((int)*sval) && (*sval != '\\'))
813 : {
814 100281478 : outbuf[length++] = *sval;
815 100281478 : outbuf[length] = '\0';
816 : }
817 : else
818 : {
819 6560272 : int ret = snprintf(outbuf + length,
820 6560272 : log_buffer_size - length - 2, "\\x%.2x", (unsigned char)*sval);
821 6560272 : assert(ret == 4);
822 6560272 : length += 4;
823 : }
824 106841750 : sval++;
825 : }
826 : /*
827 : * XXX: In case of printable characters at the end of
828 : * the %N string, we're not using the whole buffer.
829 : */
830 122235 : format_string = (length < log_buffer_size - 6) ? "" : "[too long]";
831 122235 : break;
832 347 : case 'E':
833 : /* Non-standard: Print error code from errno */
834 : #ifdef _WIN32
835 : ival = WSAGetLastError();
836 : format_string = w32_socket_strerr(ival, tempbuf);
837 : #else /* ifndef _WIN32 */
838 347 : ival = errno;
839 : #ifdef HAVE_STRERROR
840 347 : format_string = strerror(ival);
841 : #else /* ifndef HAVE_STRERROR */
842 : format_string = NULL;
843 : #endif /* ndef HAVE_STRERROR */
844 347 : if (sval == NULL)
845 : {
846 347 : snprintf(tempbuf, sizeof(tempbuf), "(errno = %d)", ival);
847 : }
848 : #endif /* ndef _WIN32 */
849 347 : break;
850 0 : case 'T':
851 : /* Non-standard: Print a Common Log File timestamp */
852 0 : get_clf_timestamp(tempbuf, sizeof(tempbuf));
853 0 : break;
854 0 : default:
855 0 : snprintf(tempbuf, sizeof(tempbuf), "Bad format string: \"%s\"", fmt);
856 0 : loglevel = LOG_LEVEL_FATAL;
857 0 : break;
858 : }
859 :
860 8224483 : assert(length < log_buffer_size);
861 8224483 : length += strlcpy(outbuf + length, format_string, log_buffer_size - length);
862 :
863 8224483 : if (length >= log_buffer_size-2)
864 : {
865 : static const char warning[] = "... [too long, truncated]";
866 :
867 8778 : length = log_buffer_size - sizeof(warning) - 1;
868 8778 : length += strlcpy(outbuf + length, warning, log_buffer_size - length);
869 8778 : assert(length < log_buffer_size);
870 :
871 8778 : break;
872 : }
873 : }
874 :
875 : /* done with var. args */
876 3976326 : va_end(ap);
877 :
878 3976326 : assert(length < log_buffer_size);
879 3976326 : length += strlcpy(outbuf + length, "\n", log_buffer_size - length);
880 :
881 : /* Some sanity checks */
882 3976326 : if ((length >= log_buffer_size)
883 3976326 : || (outbuf[log_buffer_size-1] != '\0')
884 3976326 : || (outbuf[log_buffer_size] != '\0')
885 : )
886 : {
887 : /* Repeat as assertions */
888 0 : assert(length < log_buffer_size);
889 0 : assert(outbuf[log_buffer_size-1] == '\0');
890 : /*
891 : * outbuf's real size is log_buffer_size+1,
892 : * so while this looks like an off-by-one,
893 : * we're only checking our paranoia byte.
894 : */
895 0 : assert(outbuf[log_buffer_size] == '\0');
896 :
897 0 : snprintf(outbuf, log_buffer_size,
898 : "%s %08lx Fatal error: log_error()'s sanity checks failed."
899 : "length: %d. Exiting.",
900 : timestamp, thread_id, (int)length);
901 0 : loglevel = LOG_LEVEL_FATAL;
902 : }
903 :
904 : #ifndef _WIN32
905 : /*
906 : * On Windows this is acceptable in case
907 : * we are logging to the GUI window only.
908 : */
909 3976326 : assert(NULL != logfp);
910 : #endif
911 :
912 3976326 : lock_logfile();
913 :
914 3976326 : if (loglevel == LOG_LEVEL_FATAL)
915 : {
916 0 : fatal_error(outbuf);
917 : /* Never get here */
918 : }
919 3976326 : if (logfp != NULL)
920 : {
921 3976326 : fputs(outbuf, logfp);
922 : }
923 :
924 : #if defined(_WIN32) && !defined(_WIN_CONSOLE)
925 : /* Write to display */
926 : LogPutString(outbuf);
927 : #endif /* defined(_WIN32) && !defined(_WIN_CONSOLE) */
928 :
929 3976326 : unlock_logfile();
930 :
931 : }
932 :
933 :
934 : /*********************************************************************
935 : *
936 : * Function : jb_err_to_string
937 : *
938 : * Description : Translates JB_ERR_FOO codes into strings.
939 : *
940 : * Parameters :
941 : * 1 : jb_error = a valid jb_err code
942 : *
943 : * Returns : A string with the jb_err translation
944 : *
945 : *********************************************************************/
946 542 : const char *jb_err_to_string(jb_err jb_error)
947 : {
948 542 : switch (jb_error)
949 : {
950 0 : case JB_ERR_OK:
951 0 : return "Success, no error";
952 0 : case JB_ERR_MEMORY:
953 0 : return "Out of memory";
954 0 : case JB_ERR_CGI_PARAMS:
955 0 : return "Missing or corrupt CGI parameters";
956 0 : case JB_ERR_FILE:
957 0 : return "Error opening, reading or writing a file";
958 542 : case JB_ERR_PARSE:
959 542 : return "Parse error";
960 0 : case JB_ERR_MODIFIED:
961 0 : return "File has been modified outside of the CGI actions editor.";
962 0 : case JB_ERR_COMPRESS:
963 0 : return "(De)compression failure";
964 : }
965 0 : assert(0);
966 : return "Internal error";
967 : }
968 :
969 : #ifdef _WIN32
970 : /*********************************************************************
971 : *
972 : * Function : w32_socket_strerr
973 : *
974 : * Description : Translate the return value from WSAGetLastError()
975 : * into a string.
976 : *
977 : * Parameters :
978 : * 1 : errcode = The return value from WSAGetLastError().
979 : * 2 : tmp_buf = A temporary buffer that might be used to
980 : * store the string.
981 : *
982 : * Returns : String representing the error code. This may be
983 : * a global string constant or a string stored in
984 : * tmp_buf.
985 : *
986 : *********************************************************************/
987 : static char *w32_socket_strerr(int errcode, char *tmp_buf)
988 : {
989 : #define TEXT_FOR_ERROR(code,text) \
990 : if (errcode == code) \
991 : { \
992 : return #code " - " text; \
993 : }
994 :
995 : TEXT_FOR_ERROR(WSAEACCES, "Permission denied")
996 : TEXT_FOR_ERROR(WSAEADDRINUSE, "Address already in use.")
997 : TEXT_FOR_ERROR(WSAEADDRNOTAVAIL, "Cannot assign requested address.");
998 : TEXT_FOR_ERROR(WSAEAFNOSUPPORT, "Address family not supported by protocol family.");
999 : TEXT_FOR_ERROR(WSAEALREADY, "Operation already in progress.");
1000 : TEXT_FOR_ERROR(WSAECONNABORTED, "Software caused connection abort.");
1001 : TEXT_FOR_ERROR(WSAECONNREFUSED, "Connection refused.");
1002 : TEXT_FOR_ERROR(WSAECONNRESET, "Connection reset by peer.");
1003 : TEXT_FOR_ERROR(WSAEDESTADDRREQ, "Destination address required.");
1004 : TEXT_FOR_ERROR(WSAEFAULT, "Bad address.");
1005 : TEXT_FOR_ERROR(WSAEHOSTDOWN, "Host is down.");
1006 : TEXT_FOR_ERROR(WSAEHOSTUNREACH, "No route to host.");
1007 : TEXT_FOR_ERROR(WSAEINPROGRESS, "Operation now in progress.");
1008 : TEXT_FOR_ERROR(WSAEINTR, "Interrupted function call.");
1009 : TEXT_FOR_ERROR(WSAEINVAL, "Invalid argument.");
1010 : TEXT_FOR_ERROR(WSAEISCONN, "Socket is already connected.");
1011 : TEXT_FOR_ERROR(WSAEMFILE, "Too many open sockets.");
1012 : TEXT_FOR_ERROR(WSAEMSGSIZE, "Message too long.");
1013 : TEXT_FOR_ERROR(WSAENETDOWN, "Network is down.");
1014 : TEXT_FOR_ERROR(WSAENETRESET, "Network dropped connection on reset.");
1015 : TEXT_FOR_ERROR(WSAENETUNREACH, "Network is unreachable.");
1016 : TEXT_FOR_ERROR(WSAENOBUFS, "No buffer space available.");
1017 : TEXT_FOR_ERROR(WSAENOPROTOOPT, "Bad protocol option.");
1018 : TEXT_FOR_ERROR(WSAENOTCONN, "Socket is not connected.");
1019 : TEXT_FOR_ERROR(WSAENOTSOCK, "Socket operation on non-socket.");
1020 : TEXT_FOR_ERROR(WSAEOPNOTSUPP, "Operation not supported.");
1021 : TEXT_FOR_ERROR(WSAEPFNOSUPPORT, "Protocol family not supported.");
1022 : TEXT_FOR_ERROR(WSAEPROCLIM, "Too many processes.");
1023 : TEXT_FOR_ERROR(WSAEPROTONOSUPPORT, "Protocol not supported.");
1024 : TEXT_FOR_ERROR(WSAEPROTOTYPE, "Protocol wrong type for socket.");
1025 : TEXT_FOR_ERROR(WSAESHUTDOWN, "Cannot send after socket shutdown.");
1026 : TEXT_FOR_ERROR(WSAESOCKTNOSUPPORT, "Socket type not supported.");
1027 : TEXT_FOR_ERROR(WSAETIMEDOUT, "Connection timed out.");
1028 : TEXT_FOR_ERROR(WSAEWOULDBLOCK, "Resource temporarily unavailable.");
1029 : TEXT_FOR_ERROR(WSAHOST_NOT_FOUND, "Host not found.");
1030 : TEXT_FOR_ERROR(WSANOTINITIALISED, "Successful WSAStartup not yet performed.");
1031 : TEXT_FOR_ERROR(WSANO_DATA, "Valid name, no data record of requested type.");
1032 : TEXT_FOR_ERROR(WSANO_RECOVERY, "This is a non-recoverable error.");
1033 : TEXT_FOR_ERROR(WSASYSNOTREADY, "Network subsystem is unavailable.");
1034 : TEXT_FOR_ERROR(WSATRY_AGAIN, "Non-authoritative host not found.");
1035 : TEXT_FOR_ERROR(WSAVERNOTSUPPORTED, "WINSOCK.DLL version out of range.");
1036 : TEXT_FOR_ERROR(WSAEDISCON, "Graceful shutdown in progress.");
1037 : /*
1038 : * The following error codes are documented in the Microsoft WinSock
1039 : * reference guide, but don't actually exist.
1040 : *
1041 : * TEXT_FOR_ERROR(WSA_INVALID_HANDLE, "Specified event object handle is invalid.");
1042 : * TEXT_FOR_ERROR(WSA_INVALID_PARAMETER, "One or more parameters are invalid.");
1043 : * TEXT_FOR_ERROR(WSAINVALIDPROCTABLE, "Invalid procedure table from service provider.");
1044 : * TEXT_FOR_ERROR(WSAINVALIDPROVIDER, "Invalid service provider version number.");
1045 : * TEXT_FOR_ERROR(WSA_IO_PENDING, "Overlapped operations will complete later.");
1046 : * TEXT_FOR_ERROR(WSA_IO_INCOMPLETE, "Overlapped I/O event object not in signaled state.");
1047 : * TEXT_FOR_ERROR(WSA_NOT_ENOUGH_MEMORY, "Insufficient memory available.");
1048 : * TEXT_FOR_ERROR(WSAPROVIDERFAILEDINIT, "Unable to initialize a service provider.");
1049 : * TEXT_FOR_ERROR(WSASYSCALLFAILURE, "System call failure.");
1050 : * TEXT_FOR_ERROR(WSA_OPERATION_ABORTED, "Overlapped operation aborted.");
1051 : */
1052 :
1053 : sprintf(tmp_buf, "(error number %d)", errcode);
1054 : return tmp_buf;
1055 : }
1056 : #endif /* def _WIN32 */
1057 :
1058 :
1059 : /*
1060 : Local Variables:
1061 : tab-width: 3
1062 : end:
1063 : */
|