"Fossies" - the Fresh Open Source Software Archive

Member "gvm-libs-11.0.1/base/logging.c" (12 May 2020, 25854 Bytes) of package /linux/misc/openvas/gvm-libs-11.0.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "logging.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 1.0-beta2_vs_1.0.0.

    1 /* Copyright (C) 2017-2019 Greenbone Networks GmbH
    2  *
    3  * SPDX-License-Identifier: GPL-2.0-or-later
    4  *
    5  * This program is free software; you can redistribute it and/or
    6  * modify it under the terms of the GNU General Public License
    7  * as published by the Free Software Foundation; either version 2
    8  * of the License, or (at your option) any later version.
    9  *
   10  * This program is distributed in the hope that it will be useful,
   11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   13  * GNU General Public License for more details.
   14  *
   15  * You should have received a copy of the GNU General Public License
   16  * along with this program; if not, write to the Free Software
   17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   18  */
   19 
   20 /**
   21  * @file
   22  * @brief Implementation of logging methods.
   23  *
   24  * This file contains all methods needed for logging. To enable logging,
   25  * methods in this file are called.
   26  *
   27  * The module reuses glib datatypes and api for memory management and logging.
   28  */
   29 
   30 #include "logging.h"
   31 
   32 #include <errno.h>  /* for errno */
   33 #include <libgen.h> /* for dirname */
   34 #include <stdio.h>  /* for fflush, fprintf, stderr */
   35 #include <stdlib.h> /* for atoi */
   36 #include <string.h> /* for strcasecmp, strlen, strerror */
   37 #define SYSLOG_NAMES
   38 #include <syslog.h> /* for LOG_INFO, facilitynames, closelog, openlog */
   39 #undef SYSLOG_NAMES
   40 #include <time.h>   /* for localtime, time, time_t */
   41 #include <unistd.h> /* for getpid */
   42 
   43 /**
   44  * @struct gvm_logging_t
   45  * @brief Logging stores the parameters loaded from a log configuration
   46  * @brief file, to be used internally by the gvm_logging module only.
   47  */
   48 typedef struct
   49 {
   50   gchar *log_domain;          ///< Affected logdomain e.g libnasl.
   51   gchar *prepend_string;      ///< Prepend this string before every message.
   52   gchar *prepend_time_format; ///< If prependstring has %t, format for strftime.
   53   gchar *log_file;            ///< Where to log to.
   54   GLogLevelFlags *default_level; ///< What severity level to use as default.
   55   GIOChannel *log_channel;       ///< Gio Channel - FD holder for logfile.
   56   gchar *syslog_facility;        ///< Syslog facility to use for syslog logging.
   57   gchar *syslog_ident;           ///< Syslog ident to use for syslog logging.
   58   gchar *prepend_separator; ///< If prependstring has %s, used this symbol as
   59                             ///< separator.
   60 } gvm_logging_t;
   61 
   62 /**
   63  * @brief Returns time as specified in time_fmt strftime format.
   64  *
   65  * @param time_fmt ptr to the string format to use. The strftime
   66  *        man page documents the conversion specification. An
   67  *        example time_fmt string is "%Y-%m-%d %H:%M:%S".
   68  *
   69  * @return NULL in case the format string is NULL. A ptr to a
   70  *         string that contains the formatted date time value.
   71  *         This value must be freed using glib's g_free.
   72  */
   73 gchar *
   74 get_time (gchar *time_fmt)
   75 {
   76   time_t now;
   77   struct tm *ts;
   78   gchar buf[80];
   79 
   80   /* Get the current time. */
   81   now = time (NULL);
   82 
   83   /* Format and print the time, "ddd yyyy-mm-dd hh:mm:ss zzz." */
   84   ts = localtime (&now);
   85   strftime (buf, sizeof (buf), time_fmt, ts);
   86 
   87   return g_strdup_printf ("%s", buf);
   88 }
   89 
   90 /**
   91  * @brief Return the integer corresponding to a log level string.
   92  *
   93  * @param level Level name or integer.
   94  *
   95  * @return Log level integer if level matches a level name, else 0.
   96  */
   97 static gint
   98 level_int_from_string (const gchar *level)
   99 {
  100   if (level && strlen (level) > 0)
  101     {
  102       if (level[0] >= '0' && level[0] <= '9')
  103         return atoi (level);
  104       if (strcasecmp (level, "critical") == 0)
  105         return G_LOG_LEVEL_CRITICAL;
  106       if (strcasecmp (level, "debug") == 0)
  107         return G_LOG_LEVEL_DEBUG;
  108       if (strcasecmp (level, "error") == 0)
  109         return G_LOG_LEVEL_ERROR;
  110       if (strcasecmp (level, "info") == 0)
  111         return G_LOG_LEVEL_INFO;
  112       if (strcasecmp (level, "message") == 0)
  113         return G_LOG_LEVEL_MESSAGE;
  114       if (strcasecmp (level, "warning") == 0)
  115         return G_LOG_LEVEL_WARNING;
  116     }
  117   return 0;
  118 }
  119 
  120 /**
  121  * @brief Return the integer corresponding to a syslog facility string.
  122  *
  123  * @param facility Facility name.
  124  *
  125  * @return Facility integer if facility matches a facility name, else
  126  * LOG_LOCAL0.
  127  */
  128 static gint
  129 facility_int_from_string (const gchar *facility)
  130 {
  131   if (facility && strlen (facility) > 0)
  132     {
  133       int i = 0;
  134       while (facilitynames[i].c_name != NULL)
  135         {
  136           if (g_ascii_strcasecmp (facility, facilitynames[i].c_name) == 0)
  137             return facilitynames[i].c_val;
  138           i++;
  139         }
  140     }
  141   return LOG_LOCAL0;
  142 }
  143 
  144 /**
  145  * @brief Loads parameters from a config file into a linked list.
  146  *
  147  * @param config_file A string containing the path to the configuration file
  148  *                   to load.
  149  *
  150  * @return NULL in case the config file could not be loaded or an error
  151  *         occurred otherwise, a singly linked list of parameter groups
  152  *         is returned.
  153  */
  154 GSList *
  155 load_log_configuration (gchar *config_file)
  156 {
  157   GKeyFile *key_file;
  158   GKeyFileFlags flags;
  159   GError *error = NULL;
  160   /* key_file *_has_* functions requires this. */
  161 
  162   // FIXME: If a g_* function that takes error fails, then free error.
  163 
  164   /* Groups found in the conf file. */
  165   gchar **groups;
  166   /* Temp variable to iterate over groups. */
  167   gchar **group;
  168 
  169   /* The link list for the structure above and it's tmp helper */
  170   GSList *log_domain_list = NULL;
  171 
  172   /* Create a new GKeyFile object and a bitwise list of flags. */
  173   key_file = g_key_file_new ();
  174   flags = G_KEY_FILE_KEEP_COMMENTS | G_KEY_FILE_KEEP_TRANSLATIONS;
  175 
  176   /* Load the GKeyFile from conf or return. */
  177   if (!g_key_file_load_from_file (key_file, config_file, flags, &error))
  178     {
  179       g_error ("%s:  %s", config_file, error->message);
  180     }
  181 
  182   /* Get all the groups available. */
  183   groups = g_key_file_get_groups (key_file, NULL);
  184 
  185   /* Point to the group head. */
  186   group = groups;
  187   /* Iterate till we get to the end of the array. */
  188   while (*group != NULL)
  189     {
  190       /* Structure to hold per group settings. */
  191       gvm_logging_t *log_domain_entry;
  192       /* Create the struct. */
  193       log_domain_entry = g_malloc (sizeof (gvm_logging_t));
  194       /* Set the logdomain. */
  195       log_domain_entry->log_domain = g_strdup (*group);
  196       /* Initialize everything else to NULL. */
  197       log_domain_entry->prepend_string = NULL;
  198       log_domain_entry->prepend_time_format = NULL;
  199       log_domain_entry->log_file = NULL;
  200       log_domain_entry->default_level = NULL;
  201       log_domain_entry->log_channel = NULL;
  202       log_domain_entry->syslog_facility = NULL;
  203       log_domain_entry->syslog_ident = NULL;
  204       log_domain_entry->prepend_separator = NULL;
  205 
  206       /* Look for the prepend string. */
  207       if (g_key_file_has_key (key_file, *group, "prepend", &error))
  208         {
  209           log_domain_entry->prepend_string =
  210             g_key_file_get_value (key_file, *group, "prepend", &error);
  211         }
  212 
  213       /* Look for the log_separator string. */
  214       if (g_key_file_has_key (key_file, *group, "separator", &error))
  215         {
  216           log_domain_entry->prepend_separator =
  217             g_key_file_get_value (key_file, *group, "separator", &error);
  218         }
  219 
  220       /* Look for the prepend time format string. */
  221       if (g_key_file_has_key (key_file, *group, "prepend_time_format", &error))
  222         {
  223           log_domain_entry->prepend_time_format = g_key_file_get_value (
  224             key_file, *group, "prepend_time_format", &error);
  225         }
  226 
  227       /* Look for the log file string. */
  228       if (g_key_file_has_key (key_file, *group, "file", &error))
  229         {
  230           log_domain_entry->log_file =
  231             g_key_file_get_value (key_file, *group, "file", &error);
  232         }
  233 
  234       /* Look for the prepend log level string. */
  235       if (g_key_file_has_key (key_file, *group, "level", &error))
  236         {
  237           gchar *level;
  238 
  239           level = g_key_file_get_value (key_file, *group, "level", &error);
  240           level = g_strchug (level);
  241           log_domain_entry->default_level = g_malloc (sizeof (gint));
  242           *log_domain_entry->default_level = level_int_from_string (level);
  243           g_free (level);
  244         }
  245 
  246       /* Look for the syslog_facility string. */
  247       if (g_key_file_has_key (key_file, *group, "syslog_facility", &error))
  248         {
  249           log_domain_entry->syslog_facility =
  250             g_key_file_get_value (key_file, *group, "syslog_facility", &error);
  251         }
  252       else
  253         log_domain_entry->syslog_facility = "local0";
  254 
  255       /* Look for the syslog_ident string. */
  256       if (g_key_file_has_key (key_file, *group, "syslog_ident", &error))
  257         {
  258           log_domain_entry->syslog_ident =
  259             g_key_file_get_value (key_file, *group, "syslog_ident", &error);
  260         }
  261       else
  262         log_domain_entry->syslog_ident = g_strdup (*group);
  263 
  264       /* Attach the struct to the list. */
  265       log_domain_list = g_slist_prepend (log_domain_list, log_domain_entry);
  266       group++;
  267     }
  268   /* Free the groups array. */
  269   g_strfreev (groups);
  270 
  271   /* Free the key file. */
  272   g_key_file_free (key_file);
  273 
  274   return log_domain_list;
  275 }
  276 
  277 /**
  278  * @brief Frees all resources loaded by the config loader.
  279  *
  280  * @param log_domain_list Head of the link list.
  281  */
  282 void
  283 free_log_configuration (GSList *log_domain_list)
  284 {
  285   GSList *log_domain_list_tmp;
  286 
  287   /* Free the struct fields then the struct and then go the next
  288    * item in the link list.
  289    */
  290 
  291   /* Go to the head of the list. */
  292   log_domain_list_tmp = log_domain_list;
  293   while (log_domain_list_tmp != NULL)
  294     {
  295       gvm_logging_t *log_domain_entry;
  296 
  297       /* Get the list data which is an gvm_logging_t struct. */
  298       log_domain_entry = log_domain_list_tmp->data;
  299 
  300       /* Free the struct contents. */
  301       g_free (log_domain_entry->log_domain);
  302       g_free (log_domain_entry->prepend_string);
  303       g_free (log_domain_entry->prepend_time_format);
  304       g_free (log_domain_entry->log_file);
  305       g_free (log_domain_entry->default_level);
  306       g_free (log_domain_entry->syslog_ident);
  307       g_free (log_domain_entry->prepend_separator);
  308 
  309       /* Drop the reference to the GIOChannel. */
  310       if (log_domain_entry->log_channel)
  311         g_io_channel_unref (log_domain_entry->log_channel);
  312 
  313       /* Free the struct. */
  314       g_free (log_domain_entry);
  315 
  316       /* Go to the next item. */
  317       log_domain_list_tmp = g_slist_next (log_domain_list_tmp);
  318     }
  319   /* Free the link list. */
  320   g_slist_free (log_domain_list);
  321 }
  322 
  323 /**
  324  * @brief Returns immediately.
  325  *
  326  * @param log_domain A string containing the message's log domain.
  327  * @param log_level  Flags defining the message's log level.
  328  * @param message    A string containing the log message.
  329  * @param gvm_log_config_list A pointer to the configuration linked list.
  330  */
  331 void
  332 gvm_log_silent (const char *log_domain, GLogLevelFlags log_level,
  333                 const char *message, gpointer gvm_log_config_list)
  334 {
  335   (void) log_domain;
  336   (void) log_level;
  337   (void) message;
  338   (void) gvm_log_config_list;
  339   return;
  340 }
  341 
  342 static GMutex *logger_mutex = NULL;
  343 
  344 /**
  345  * @brief Initialize logger_mutex mutex if it was not done before.
  346  */
  347 static void
  348 gvm_log_lock_init (void)
  349 {
  350   if (logger_mutex == NULL)
  351     {
  352       logger_mutex = g_malloc (sizeof (*logger_mutex));
  353       g_mutex_init (logger_mutex);
  354     }
  355 }
  356 
  357 /**
  358  * @brief Try to lock logger_mutex.
  359  */
  360 static void
  361 gvm_log_lock (void)
  362 {
  363   g_mutex_lock (logger_mutex);
  364 }
  365 
  366 /**
  367  * @brief Unlock logger_mutex.
  368  */
  369 static void
  370 gvm_log_unlock (void)
  371 {
  372   g_mutex_unlock (logger_mutex);
  373 }
  374 
  375 /**
  376  * @brief Creates the formatted string and outputs it to the log destination.
  377  *
  378  * @param log_domain A string containing the message's log domain.
  379  * @param log_level  Flags defining the message's log level.
  380  * @param message    A string containing the log message.
  381  * @param gvm_log_config_list A pointer to the configuration linked list.
  382  */
  383 void
  384 gvm_log_func (const char *log_domain, GLogLevelFlags log_level,
  385               const char *message, gpointer gvm_log_config_list)
  386 {
  387   gchar *prepend;
  388   gchar *prepend_buf;
  389   gchar *prepend_tmp;
  390   gchar *prepend_tmp1;
  391   gchar *tmp;
  392   gchar *tmpstr;
  393   int messagelen;
  394 
  395   /* For link list operations. */
  396   GSList *log_domain_list_tmp;
  397   gvm_logging_t *log_domain_entry = NULL;
  398 
  399   /* Channel to log through. */
  400   GIOChannel *channel;
  401   GError *error = NULL;
  402 
  403   /* The default parameters to be used. The group '*' will override
  404    * these defaults if it's found.
  405    */
  406   gchar *prepend_format = "%t %s %p - ";
  407   gchar *time_format = "%Y-%m-%d %Hh%M.%S %Z";
  408   gchar *log_separator = ":";
  409   gchar *log_file = "-";
  410   GLogLevelFlags default_level = G_LOG_LEVEL_DEBUG;
  411   channel = NULL;
  412   gchar *syslog_facility = "local0";
  413   gchar *syslog_ident = NULL;
  414 
  415   /* Initialize logger lock if not done. */
  416   gvm_log_lock_init ();
  417 
  418   /* Let's load the default configuration file directives from the
  419    * linked list. Scanning the link list twice is inefficient but
  420    * leaves the source cleaner.
  421    */
  422   if (gvm_log_config_list != NULL && log_domain != NULL)
  423     {
  424       /* Go to the head of the list. */
  425       log_domain_list_tmp = (GSList *) gvm_log_config_list;
  426 
  427       while (log_domain_list_tmp != NULL)
  428         {
  429           gvm_logging_t *entry;
  430 
  431           entry = log_domain_list_tmp->data;
  432 
  433           /* Override defaults if the current linklist group name is '*'. */
  434           if (g_ascii_strcasecmp (entry->log_domain, "*") == 0)
  435             {
  436               /* Get the list data for later use. */
  437               log_domain_entry = entry;
  438 
  439               /* Override defaults if the group items are not null. */
  440               if (log_domain_entry->prepend_string)
  441                 prepend_format = log_domain_entry->prepend_string;
  442               if (log_domain_entry->prepend_time_format)
  443                 time_format = log_domain_entry->prepend_time_format;
  444               if (log_domain_entry->log_file)
  445                 log_file = log_domain_entry->log_file;
  446               if (log_domain_entry->default_level)
  447                 default_level = *log_domain_entry->default_level;
  448               if (log_domain_entry->log_channel)
  449                 channel = log_domain_entry->log_channel;
  450               if (log_domain_entry->syslog_facility)
  451                 syslog_facility = log_domain_entry->syslog_facility;
  452               if (log_domain_entry->prepend_separator)
  453                 log_separator = log_domain_entry->prepend_separator;
  454               break;
  455             }
  456 
  457           /* Go to the next item. */
  458           log_domain_list_tmp = g_slist_next (log_domain_list_tmp);
  459         }
  460     }
  461 
  462   /* Let's load the configuration file directives if a linked list item for
  463    * the log domain group exists.
  464    */
  465   if (gvm_log_config_list != NULL && log_domain != NULL)
  466     {
  467       /* Go to the head of the list. */
  468       log_domain_list_tmp = (GSList *) gvm_log_config_list;
  469 
  470       while (log_domain_list_tmp != NULL)
  471         {
  472           gvm_logging_t *entry;
  473 
  474           entry = log_domain_list_tmp->data;
  475 
  476           /* Search for the log domain in the link list. */
  477           if (g_ascii_strcasecmp (entry->log_domain, log_domain) == 0)
  478             {
  479               /* Get the list data which is an gvm_logging_t struct. */
  480               log_domain_entry = entry;
  481 
  482               /* Get the struct contents. */
  483               prepend_format = log_domain_entry->prepend_string;
  484               time_format = log_domain_entry->prepend_time_format;
  485               log_file = log_domain_entry->log_file;
  486               if (log_domain_entry->default_level)
  487                 default_level = *log_domain_entry->default_level;
  488               channel = log_domain_entry->log_channel;
  489               syslog_facility = log_domain_entry->syslog_facility;
  490               syslog_ident = log_domain_entry->syslog_ident;
  491               if (log_domain_entry->prepend_separator)
  492                 log_separator = log_domain_entry->prepend_separator;
  493               break;
  494             }
  495 
  496           /* Go to the next item. */
  497           log_domain_list_tmp = g_slist_next (log_domain_list_tmp);
  498         }
  499     }
  500 
  501   /* If the current log entry is less severe than the specified log level,
  502    * let's exit.
  503    */
  504   if (default_level < log_level)
  505     return;
  506 
  507   /* Prepend buf is a newly allocated empty string. Makes life easier. */
  508   prepend_buf = g_strdup ("");
  509 
  510   /* Make the tmp pointer (for iteration) point to the format string. */
  511   tmp = prepend_format;
  512 
  513   while (*tmp != '\0')
  514     {
  515       /* If the current char is a % and the next one is a p, get the pid. */
  516       if ((*tmp == '%') && (*(tmp + 1) == 'p'))
  517         {
  518           /* Use g_strdup, a new string returned. Store it in a tmp var until
  519            * we free the old one. */
  520           prepend_tmp = g_strdup_printf ("%s%d", prepend_buf, (int) getpid ());
  521           /* Free the old string. */
  522           g_free (prepend_buf);
  523           /* Point the buf ptr to the new string. */
  524           prepend_buf = prepend_tmp;
  525           /* Skip over the two chars we've processed '%p'. */
  526           tmp += 2;
  527         }
  528       else if ((*tmp == '%') && (*(tmp + 1) == 't'))
  529         {
  530           /* Get time returns a newly allocated string.
  531            * Store it in a tmp var.
  532            */
  533           prepend_tmp1 = get_time (time_format);
  534           /* Use g_strdup. New string returned. Store it in a tmp var until
  535            * we free the old one.
  536            */
  537           prepend_tmp = g_strdup_printf ("%s%s", prepend_buf, prepend_tmp1);
  538           /* Free the time tmp var. */
  539           g_free (prepend_tmp1);
  540           /* Free the old string. */
  541           g_free (prepend_buf);
  542           /* Point the buf ptr to the new string. */
  543           prepend_buf = prepend_tmp;
  544           /* Skip over the two chars we've processed '%t.' */
  545           tmp += 2;
  546         }
  547       else if ((*tmp == '%') && (*(tmp + 1) == 's'))
  548         {
  549           /* Use g_strdup. New string returned. Store it in a tmp var until
  550            * we free the old one.
  551            */
  552           prepend_tmp = g_strdup_printf ("%s%s", prepend_buf, log_separator);
  553           /* Free the old string. */
  554           g_free (prepend_buf);
  555           /* Point the buf ptr to the new string. */
  556           prepend_buf = prepend_tmp;
  557           /* Skip over the two chars we've processed '%s.' */
  558           tmp += 2;
  559         }
  560       else
  561         {
  562           /* Jump to the next character. */
  563           tmp++;
  564         }
  565     }
  566 
  567   /* Step through all possible messages prefixing them with an appropriate
  568    * tag.
  569    */
  570   switch (log_level)
  571     {
  572     case G_LOG_FLAG_RECURSION:
  573       prepend = g_strdup_printf ("RECURSION%s%s", log_separator, prepend_buf);
  574       break;
  575 
  576     case G_LOG_FLAG_FATAL:
  577       prepend = g_strdup_printf ("FATAL%s%s", log_separator, prepend_buf);
  578       break;
  579 
  580     case G_LOG_LEVEL_ERROR:
  581       prepend = g_strdup_printf ("ERROR%s%s", log_separator, prepend_buf);
  582       break;
  583 
  584     case G_LOG_LEVEL_CRITICAL:
  585       prepend = g_strdup_printf ("CRITICAL%s%s", log_separator, prepend_buf);
  586       break;
  587 
  588     case G_LOG_LEVEL_WARNING:
  589       prepend = g_strdup_printf ("WARNING%s%s", log_separator, prepend_buf);
  590       break;
  591 
  592     case G_LOG_LEVEL_MESSAGE:
  593       prepend = g_strdup_printf ("MESSAGE%s%s", log_separator, prepend_buf);
  594       break;
  595 
  596     case G_LOG_LEVEL_INFO:
  597       prepend = g_strdup_printf ("   INFO%s%s", log_separator, prepend_buf);
  598       break;
  599 
  600     case G_LOG_LEVEL_DEBUG:
  601       prepend = g_strdup_printf ("  DEBUG%s%s", log_separator, prepend_buf);
  602       break;
  603 
  604     default:
  605       prepend = g_strdup_printf ("UNKNOWN%s%s", log_separator, prepend_buf);
  606       break;
  607     }
  608 
  609   /* If the current log entry is more severe than the specified log
  610    * level, print out the message.  In case MESSAGE already ends in a
  611    * LF and there is not only the LF, remove the LF to avoid empty
  612    * lines in the log.
  613    */
  614   messagelen = message ? strlen (message) : 0;
  615   if (messagelen > 1 && message[messagelen - 1] == '\n')
  616     messagelen--;
  617   tmpstr = g_strdup_printf ("%s%s%s%s %.*s\n", log_domain ? log_domain : "",
  618                             log_separator, prepend, log_separator, messagelen,
  619                             message);
  620   g_free (prepend);
  621 
  622   gvm_log_lock ();
  623   /* Output everything to stderr if logfile is "-". */
  624   if (g_ascii_strcasecmp (log_file, "-") == 0)
  625     {
  626       fprintf (stderr, "%s", tmpstr);
  627       fflush (stderr);
  628     }
  629   /* Output everything to syslog if logfile is "syslog" */
  630   else if (g_ascii_strcasecmp (log_file, "syslog") == 0)
  631     {
  632       int facility = facility_int_from_string (syslog_facility);
  633       int syslog_level = LOG_INFO;
  634 
  635       openlog (syslog_ident, LOG_CONS | LOG_PID | LOG_NDELAY, facility);
  636 
  637       switch (log_level)
  638         {
  639         case G_LOG_FLAG_FATAL:
  640           syslog_level = LOG_ALERT;
  641           break;
  642         case G_LOG_LEVEL_ERROR:
  643           syslog_level = LOG_ERR;
  644           break;
  645         case G_LOG_LEVEL_CRITICAL:
  646           syslog_level = LOG_CRIT;
  647           break;
  648         case G_LOG_LEVEL_WARNING:
  649           syslog_level = LOG_WARNING;
  650           break;
  651         case G_LOG_LEVEL_MESSAGE:
  652           syslog_level = LOG_NOTICE;
  653           break;
  654         case G_LOG_LEVEL_INFO:
  655           syslog_level = LOG_INFO;
  656           break;
  657         case G_LOG_LEVEL_DEBUG:
  658           syslog_level = LOG_DEBUG;
  659           break;
  660         default:
  661           syslog_level = LOG_INFO;
  662           break;
  663         }
  664 
  665       syslog (syslog_level, "%s", message);
  666 
  667       closelog ();
  668     }
  669   else
  670     {
  671       /* Open a channel and store it in the struct or
  672        * retrieve and use an already existing channel.
  673        */
  674       if (channel == NULL)
  675         {
  676           channel = g_io_channel_new_file (log_file, "a", &error);
  677           if (!channel)
  678             {
  679               gchar *log = g_strdup (log_file);
  680               gchar *dir = dirname (log);
  681 
  682               /* Check error. In case of the directory does not exist, it will
  683                * be handle below. In other case a message is printed to the
  684                * stderr since the channel is still not created/accessible.
  685                */
  686               if (error->code != G_FILE_ERROR_NOENT)
  687                 fprintf (stderr, "Can not open '%s' logfile: %s\n", log_file,
  688                          error->message);
  689               g_error_free (error);
  690 
  691               /* Ensure directory exists. */
  692               if (g_mkdir_with_parents (dir, 0755)) /* "rwxr-xr-x" */
  693                 {
  694                   g_warning ("Failed to create log file directory %s: %s", dir,
  695                              strerror (errno));
  696                   g_free (log);
  697                   g_free (tmpstr);
  698                   g_free (prepend_buf);
  699                   return;
  700                 }
  701               g_free (log);
  702 
  703               /* Try again. */
  704               error = NULL;
  705               channel = g_io_channel_new_file (log_file, "a", &error);
  706               if (!channel)
  707                 {
  708                   g_error ("Can not open '%s' logfile: %s", log_file,
  709                            error->message);
  710                 }
  711             }
  712 
  713           /* Store it in the struct for later use. */
  714           if (log_domain_entry != NULL)
  715             log_domain_entry->log_channel = channel;
  716         }
  717       g_io_channel_write_chars (channel, (const gchar *) tmpstr, -1, NULL,
  718                                 &error);
  719       g_io_channel_flush (channel, NULL);
  720     }
  721   gvm_log_unlock ();
  722   g_free (tmpstr);
  723   g_free (prepend_buf);
  724 }
  725 
  726 /**
  727  * @brief This function logs debug messages from gnutls.
  728  *
  729  * @param level GnuTLS log level (integer from 0 to 99 according to GnuTLS
  730  * documentation.
  731  * @param message GnuTLS log message.
  732  *
  733  * To enable GNUTLS debug messages, the environment variable @c
  734  * OPENVAS_GNUTLS_DEBUG is to be set to the desired log level as
  735  * described in the GNUTLS manual.
  736  */
  737 void
  738 log_func_for_gnutls (int level, const char *message)
  739 {
  740   g_log ("x  gnutls", G_LOG_LEVEL_INFO, "tls(%d): %s", level, message);
  741 }
  742 
  743 /**
  744  * @brief Sets up routing of logdomains to log handlers.
  745  *
  746  * Iterates over the link list and adds the groups to the handler.
  747  *
  748  * @param gvm_log_config_list A pointer to the configuration linked list.
  749  */
  750 void
  751 setup_log_handlers (GSList *gvm_log_config_list)
  752 {
  753   GSList *log_domain_list_tmp;
  754   if (gvm_log_config_list != NULL)
  755     {
  756       /* Go to the head of the list. */
  757       log_domain_list_tmp = (GSList *) gvm_log_config_list;
  758 
  759       while (log_domain_list_tmp != NULL)
  760         {
  761           gvm_logging_t *log_domain_entry;
  762 
  763           /* Get the list data which is an gvm_logging_t struct. */
  764           log_domain_entry = log_domain_list_tmp->data;
  765 
  766           GLogFunc logfunc =
  767 #if 0
  768             (!strcmp (log_domain_entry, "syslog")) ? gvm_syslog_func :
  769 #endif
  770             gvm_log_func;
  771 
  772           if (g_ascii_strcasecmp (log_domain_entry->log_domain, "*"))
  773             {
  774               g_log_set_handler (
  775                 log_domain_entry->log_domain,
  776                 (GLogLevelFlags) (G_LOG_LEVEL_DEBUG | G_LOG_LEVEL_INFO
  777                                   | G_LOG_LEVEL_MESSAGE | G_LOG_LEVEL_WARNING
  778                                   | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_ERROR
  779                                   | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION),
  780                 (GLogFunc) logfunc, gvm_log_config_list);
  781             }
  782           else
  783             {
  784               g_log_set_default_handler ((GLogFunc) logfunc,
  785                                          gvm_log_config_list);
  786             }
  787 
  788           /* Go to the next item. */
  789           log_domain_list_tmp = g_slist_next (log_domain_list_tmp);
  790         }
  791     }
  792   g_log_set_handler (
  793     "",
  794     (GLogLevelFlags) (G_LOG_LEVEL_DEBUG | G_LOG_LEVEL_INFO | G_LOG_LEVEL_MESSAGE
  795                       | G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL
  796                       | G_LOG_LEVEL_ERROR | G_LOG_FLAG_FATAL
  797                       | G_LOG_FLAG_RECURSION),
  798     (GLogFunc) gvm_log_func, gvm_log_config_list);
  799 }