LCOV - code coverage report
Current view: top level - fuzz - errlog.c (source / functions) Hit Total Coverage
Test: trace.lcov_info_final Lines: 173 300 57.7 %
Date: 2021-02-22 04:51:02 Functions: 11 17 64.7 %

          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             : */

Generated by: LCOV version 1.14