logconf.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2004-2007, 2011, 2013, 2014  Internet Systems Consortium, Inc. ("ISC")
00003  * Copyright (C) 1999-2001  Internet Software Consortium.
00004  *
00005  * Permission to use, copy, modify, and/or distribute this software for any
00006  * purpose with or without fee is hereby granted, provided that the above
00007  * copyright notice and this permission notice appear in all copies.
00008  *
00009  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
00010  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00011  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00012  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00013  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00014  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00015  * PERFORMANCE OF THIS SOFTWARE.
00016  */
00017 
00018 /* $Id: logconf.c,v 1.45 2011/03/05 23:52:29 tbox Exp $ */
00019 
00020 /*! \file */
00021 
00022 #include <config.h>
00023 
00024 #include <isc/file.h>
00025 #include <isc/offset.h>
00026 #include <isc/result.h>
00027 #include <isc/stdio.h>
00028 #include <isc/string.h>
00029 #include <isc/syslog.h>
00030 
00031 #include <isccfg/cfg.h>
00032 #include <isccfg/log.h>
00033 
00034 #include <named/log.h>
00035 #include <named/logconf.h>
00036 
00037 #define CHECK(op) \
00038         do { result = (op);                                      \
00039                if (result != ISC_R_SUCCESS) goto cleanup;        \
00040         } while (0)
00041 
00042 /*%
00043  * Set up a logging category according to the named.conf data
00044  * in 'ccat' and add it to 'logconfig'.
00045  */
00046 static isc_result_t
00047 category_fromconf(const cfg_obj_t *ccat, isc_logconfig_t *logconfig) {
00048         isc_result_t result;
00049         const char *catname;
00050         isc_logcategory_t *category;
00051         isc_logmodule_t *module;
00052         const cfg_obj_t *destinations = NULL;
00053         const cfg_listelt_t *element = NULL;
00054 
00055         catname = cfg_obj_asstring(cfg_tuple_get(ccat, "name"));
00056         category = isc_log_categorybyname(ns_g_lctx, catname);
00057         if (category == NULL) {
00058                 cfg_obj_log(ccat, ns_g_lctx, ISC_LOG_ERROR,
00059                             "unknown logging category '%s' ignored",
00060                             catname);
00061                 /*
00062                  * Allow further processing by returning success.
00063                  */
00064                 return (ISC_R_SUCCESS);
00065         }
00066 
00067         if (logconfig == NULL)
00068                 return (ISC_R_SUCCESS);
00069 
00070         module = NULL;
00071 
00072         destinations = cfg_tuple_get(ccat, "destinations");
00073         for (element = cfg_list_first(destinations);
00074              element != NULL;
00075              element = cfg_list_next(element))
00076         {
00077                 const cfg_obj_t *channel = cfg_listelt_value(element);
00078                 const char *channelname = cfg_obj_asstring(channel);
00079 
00080                 result = isc_log_usechannel(logconfig, channelname, category,
00081                                             module);
00082                 if (result != ISC_R_SUCCESS) {
00083                         isc_log_write(ns_g_lctx, CFG_LOGCATEGORY_CONFIG,
00084                                       NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
00085                                       "logging channel '%s': %s", channelname,
00086                                       isc_result_totext(result));
00087                         return (result);
00088                 }
00089         }
00090         return (ISC_R_SUCCESS);
00091 }
00092 
00093 /*%
00094  * Set up a logging channel according to the named.conf data
00095  * in 'cchan' and add it to 'logconfig'.
00096  */
00097 static isc_result_t
00098 channel_fromconf(const cfg_obj_t *channel, isc_logconfig_t *logconfig)
00099 {
00100         isc_result_t result;
00101         isc_logdestination_t dest;
00102         unsigned int type;
00103         unsigned int flags = 0;
00104         int level;
00105         const char *channelname;
00106         const cfg_obj_t *fileobj = NULL;
00107         const cfg_obj_t *syslogobj = NULL;
00108         const cfg_obj_t *nullobj = NULL;
00109         const cfg_obj_t *stderrobj = NULL;
00110         const cfg_obj_t *severity = NULL;
00111         int i;
00112 
00113         channelname = cfg_obj_asstring(cfg_map_getname(channel));
00114 
00115         (void)cfg_map_get(channel, "file", &fileobj);
00116         (void)cfg_map_get(channel, "syslog", &syslogobj);
00117         (void)cfg_map_get(channel, "null", &nullobj);
00118         (void)cfg_map_get(channel, "stderr", &stderrobj);
00119 
00120         i = 0;
00121         if (fileobj != NULL)
00122                 i++;
00123         if (syslogobj != NULL)
00124                 i++;
00125         if (nullobj != NULL)
00126                 i++;
00127         if (stderrobj != NULL)
00128                 i++;
00129 
00130         if (i != 1) {
00131                 cfg_obj_log(channel, ns_g_lctx, ISC_LOG_ERROR,
00132                               "channel '%s': exactly one of file, syslog, "
00133                               "null, and stderr must be present", channelname);
00134                 return (ISC_R_FAILURE);
00135         }
00136 
00137         type = ISC_LOG_TONULL;
00138 
00139         if (fileobj != NULL) {
00140                 const cfg_obj_t *pathobj = cfg_tuple_get(fileobj, "file");
00141                 const cfg_obj_t *sizeobj = cfg_tuple_get(fileobj, "size");
00142                 const cfg_obj_t *versionsobj =
00143                                  cfg_tuple_get(fileobj, "versions");
00144                 isc_int32_t versions = ISC_LOG_ROLLNEVER;
00145                 isc_offset_t size = 0;
00146 
00147                 type = ISC_LOG_TOFILE;
00148 
00149                 if (versionsobj != NULL && cfg_obj_isuint32(versionsobj))
00150                         versions = cfg_obj_asuint32(versionsobj);
00151                 if (versionsobj != NULL && cfg_obj_isstring(versionsobj) &&
00152                     strcasecmp(cfg_obj_asstring(versionsobj), "unlimited") == 0)
00153                         versions = ISC_LOG_ROLLINFINITE;
00154                 if (sizeobj != NULL &&
00155                     cfg_obj_isuint64(sizeobj) &&
00156                     cfg_obj_asuint64(sizeobj) < ISC_OFFSET_MAXIMUM)
00157                         size = (isc_offset_t)cfg_obj_asuint64(sizeobj);
00158                 dest.file.stream = NULL;
00159                 dest.file.name = cfg_obj_asstring(pathobj);
00160                 dest.file.versions = versions;
00161                 dest.file.maximum_size = size;
00162         } else if (syslogobj != NULL) {
00163                 int facility = LOG_DAEMON;
00164 
00165                 type = ISC_LOG_TOSYSLOG;
00166 
00167                 if (cfg_obj_isstring(syslogobj)) {
00168                         const char *facilitystr = cfg_obj_asstring(syslogobj);
00169                         (void)isc_syslog_facilityfromstring(facilitystr,
00170                                                             &facility);
00171                 }
00172                 dest.facility = facility;
00173         } else if (stderrobj != NULL) {
00174                 type = ISC_LOG_TOFILEDESC;
00175                 dest.file.stream = stderr;
00176                 dest.file.name = NULL;
00177                 dest.file.versions = ISC_LOG_ROLLNEVER;
00178                 dest.file.maximum_size = 0;
00179         }
00180 
00181         /*
00182          * Munge flags.
00183          */
00184         {
00185                 const cfg_obj_t *printcat = NULL;
00186                 const cfg_obj_t *printsev = NULL;
00187                 const cfg_obj_t *printtime = NULL;
00188                 const cfg_obj_t *buffered = NULL;
00189 
00190                 (void)cfg_map_get(channel, "print-category", &printcat);
00191                 (void)cfg_map_get(channel, "print-severity", &printsev);
00192                 (void)cfg_map_get(channel, "print-time", &printtime);
00193                 (void)cfg_map_get(channel, "buffered", &buffered);
00194 
00195                 if (printcat != NULL && cfg_obj_asboolean(printcat))
00196                         flags |= ISC_LOG_PRINTCATEGORY;
00197                 if (printtime != NULL && cfg_obj_asboolean(printtime))
00198                         flags |= ISC_LOG_PRINTTIME;
00199                 if (printsev != NULL && cfg_obj_asboolean(printsev))
00200                         flags |= ISC_LOG_PRINTLEVEL;
00201                 if (buffered != NULL && cfg_obj_asboolean(buffered))
00202                         flags |= ISC_LOG_BUFFERED;
00203         }
00204 
00205         level = ISC_LOG_INFO;
00206         if (cfg_map_get(channel, "severity", &severity) == ISC_R_SUCCESS) {
00207                 if (cfg_obj_isstring(severity)) {
00208                         const char *str = cfg_obj_asstring(severity);
00209                         if (strcasecmp(str, "critical") == 0)
00210                                 level = ISC_LOG_CRITICAL;
00211                         else if (strcasecmp(str, "error") == 0)
00212                                 level = ISC_LOG_ERROR;
00213                         else if (strcasecmp(str, "warning") == 0)
00214                                 level = ISC_LOG_WARNING;
00215                         else if (strcasecmp(str, "notice") == 0)
00216                                 level = ISC_LOG_NOTICE;
00217                         else if (strcasecmp(str, "info") == 0)
00218                                 level = ISC_LOG_INFO;
00219                         else if (strcasecmp(str, "dynamic") == 0)
00220                                 level = ISC_LOG_DYNAMIC;
00221                 } else
00222                         /* debug */
00223                         level = cfg_obj_asuint32(severity);
00224         }
00225 
00226         if (logconfig == NULL)
00227                 result = ISC_R_SUCCESS;
00228         else
00229                 result = isc_log_createchannel(logconfig, channelname,
00230                                                type, level, &dest, flags);
00231 
00232         if (result == ISC_R_SUCCESS && type == ISC_LOG_TOFILE) {
00233                 FILE *fp;
00234 
00235                 /*
00236                  * Test to make sure that file is a plain file.
00237                  * Fix defect #22771
00238                 */
00239                 result = isc_file_isplainfile(dest.file.name);
00240                 if (result == ISC_R_SUCCESS || result == ISC_R_FILENOTFOUND) {
00241                         /*
00242                          * Test that the file can be opened, since
00243                          * isc_log_open() can't effectively report
00244                          * failures when called in isc_log_doit().
00245                          */
00246                         result = isc_stdio_open(dest.file.name, "a", &fp);
00247                         if (result != ISC_R_SUCCESS) {
00248                                 if (logconfig != NULL && !ns_g_nosyslog)
00249                                         syslog(LOG_ERR,
00250                                                 "isc_stdio_open '%s' failed: "
00251                                                 "%s", dest.file.name,
00252                                                 isc_result_totext(result));
00253                                 fprintf(stderr,
00254                                         "isc_stdio_open '%s' failed: %s\n",
00255                                         dest.file.name,
00256                                         isc_result_totext(result));
00257                         } else
00258                                 (void)isc_stdio_close(fp);
00259                         goto done;
00260                 }
00261                 if (logconfig != NULL && !ns_g_nosyslog)
00262                         syslog(LOG_ERR, "isc_file_isplainfile '%s' failed: %s",
00263                                dest.file.name, isc_result_totext(result));
00264                 fprintf(stderr, "isc_file_isplainfile '%s' failed: %s\n",
00265                         dest.file.name, isc_result_totext(result));
00266         }
00267 
00268  done:
00269         return (result);
00270 }
00271 
00272 isc_result_t
00273 ns_log_configure(isc_logconfig_t *logconfig, const cfg_obj_t *logstmt) {
00274         isc_result_t result;
00275         const cfg_obj_t *channels = NULL;
00276         const cfg_obj_t *categories = NULL;
00277         const cfg_listelt_t *element;
00278         isc_boolean_t default_set = ISC_FALSE;
00279         isc_boolean_t unmatched_set = ISC_FALSE;
00280         const cfg_obj_t *catname;
00281 
00282         if (logconfig != NULL)
00283                 CHECK(ns_log_setdefaultchannels(logconfig));
00284 
00285         (void)cfg_map_get(logstmt, "channel", &channels);
00286         for (element = cfg_list_first(channels);
00287              element != NULL;
00288              element = cfg_list_next(element))
00289         {
00290                 const cfg_obj_t *channel = cfg_listelt_value(element);
00291                 CHECK(channel_fromconf(channel, logconfig));
00292         }
00293 
00294         (void)cfg_map_get(logstmt, "category", &categories);
00295         for (element = cfg_list_first(categories);
00296              element != NULL;
00297              element = cfg_list_next(element))
00298         {
00299                 const cfg_obj_t *category = cfg_listelt_value(element);
00300                 CHECK(category_fromconf(category, logconfig));
00301                 if (!default_set) {
00302                         catname = cfg_tuple_get(category, "name");
00303                         if (strcmp(cfg_obj_asstring(catname), "default") == 0)
00304                                 default_set = ISC_TRUE;
00305                 }
00306                 if (!unmatched_set) {
00307                         catname = cfg_tuple_get(category, "name");
00308                         if (strcmp(cfg_obj_asstring(catname), "unmatched") == 0)
00309                                 unmatched_set = ISC_TRUE;
00310                 }
00311         }
00312 
00313         if (logconfig != NULL && !default_set)
00314                 CHECK(ns_log_setdefaultcategory(logconfig));
00315 
00316         if (logconfig != NULL && !unmatched_set)
00317                 CHECK(ns_log_setunmatchedcategory(logconfig));
00318 
00319         return (ISC_R_SUCCESS);
00320 
00321  cleanup:
00322         return (result);
00323 }

Generated on Tue Apr 28 17:40:54 2015 by Doxygen 1.5.4 for BIND9 Internals 9.11.0pre-alpha