log.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2004-2007, 2009, 2011-2014  Internet Systems Consortium, Inc. ("ISC")
00003  * Copyright (C) 1999-2003  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$ */
00019 
00020 /*! \file
00021  * \author  Principal Authors: DCL */
00022 
00023 #include <config.h>
00024 
00025 #include <errno.h>
00026 #include <stdlib.h>
00027 #include <limits.h>
00028 #include <time.h>
00029 
00030 #include <sys/types.h>  /* dev_t FreeBSD 2.1 */
00031 
00032 #include <isc/dir.h>
00033 #include <isc/file.h>
00034 #include <isc/log.h>
00035 #include <isc/magic.h>
00036 #include <isc/mem.h>
00037 #include <isc/msgs.h>
00038 #include <isc/print.h>
00039 #include <isc/stat.h>
00040 #include <isc/stdio.h>
00041 #include <isc/string.h>
00042 #include <isc/time.h>
00043 #include <isc/util.h>
00044 
00045 #define LCTX_MAGIC              ISC_MAGIC('L', 'c', 't', 'x')
00046 #define VALID_CONTEXT(lctx)     ISC_MAGIC_VALID(lctx, LCTX_MAGIC)
00047 
00048 #define LCFG_MAGIC              ISC_MAGIC('L', 'c', 'f', 'g')
00049 #define VALID_CONFIG(lcfg)      ISC_MAGIC_VALID(lcfg, LCFG_MAGIC)
00050 
00051 /*
00052  * XXXDCL make dynamic?
00053  */
00054 #define LOG_BUFFER_SIZE (8 * 1024)
00055 
00056 #ifndef PATH_MAX
00057 #define PATH_MAX 1024   /* AIX and others don't define this. */
00058 #endif
00059 
00060 /*!
00061  * This is the structure that holds each named channel.  A simple linked
00062  * list chains all of the channels together, so an individual channel is
00063  * found by doing strcmp()s with the names down the list.  Their should
00064  * be no performance penalty from this as it is expected that the number
00065  * of named channels will be no more than a dozen or so, and name lookups
00066  * from the head of the list are only done when isc_log_usechannel() is
00067  * called, which should also be very infrequent.
00068  */
00069 typedef struct isc_logchannel isc_logchannel_t;
00070 
00071 struct isc_logchannel {
00072         char *                          name;
00073         unsigned int                    type;
00074         int                             level;
00075         unsigned int                    flags;
00076         isc_logdestination_t            destination;
00077         ISC_LINK(isc_logchannel_t)      link;
00078 };
00079 
00080 /*!
00081  * The logchannellist structure associates categories and modules with
00082  * channels.  First the appropriate channellist is found based on the
00083  * category, and then each structure in the linked list is checked for
00084  * a matching module.  It is expected that the number of channels
00085  * associated with any given category will be very short, no more than
00086  * three or four in the more unusual cases.
00087  */
00088 typedef struct isc_logchannellist isc_logchannellist_t;
00089 
00090 struct isc_logchannellist {
00091         const isc_logmodule_t *         module;
00092         isc_logchannel_t *              channel;
00093         ISC_LINK(isc_logchannellist_t)  link;
00094 };
00095 
00096 /*!
00097  * This structure is used to remember messages for pruning via
00098  * isc_log_[v]write1().
00099  */
00100 typedef struct isc_logmessage isc_logmessage_t;
00101 
00102 struct isc_logmessage {
00103         char *                          text;
00104         isc_time_t                      time;
00105         ISC_LINK(isc_logmessage_t)      link;
00106 };
00107 
00108 /*!
00109  * The isc_logconfig structure is used to store the configurable information
00110  * about where messages are actually supposed to be sent -- the information
00111  * that could changed based on some configuration file, as opposed to the
00112  * the category/module specification of isc_log_[v]write[1] that is compiled
00113  * into a program, or the debug_level which is dynamic state information.
00114  */
00115 struct isc_logconfig {
00116         unsigned int                    magic;
00117         isc_log_t *                     lctx;
00118         ISC_LIST(isc_logchannel_t)      channels;
00119         ISC_LIST(isc_logchannellist_t) *channellists;
00120         unsigned int                    channellist_count;
00121         unsigned int                    duplicate_interval;
00122         int                             highest_level;
00123         char *                          tag;
00124         isc_boolean_t                   dynamic;
00125 };
00126 
00127 /*!
00128  * This isc_log structure provides the context for the isc_log functions.
00129  * The log context locks itself in isc_log_doit, the internal backend to
00130  * isc_log_write.  The locking is necessary both to provide exclusive access
00131  * to the buffer into which the message is formatted and to guard against
00132  * competing threads trying to write to the same syslog resource.  (On
00133  * some systems, such as BSD/OS, stdio is thread safe but syslog is not.)
00134  * Unfortunately, the lock cannot guard against a _different_ logging
00135  * context in the same program competing for syslog's attention.  Thus
00136  * There Can Be Only One, but this is not enforced.
00137  * XXXDCL enforce it?
00138  *
00139  * Note that the category and module information is not locked.
00140  * This is because in the usual case, only one isc_log_t is ever created
00141  * in a program, and the category/module registration happens only once.
00142  * XXXDCL it might be wise to add more locking overall.
00143  */
00144 struct isc_log {
00145         /* Not locked. */
00146         unsigned int                    magic;
00147         isc_mem_t *                     mctx;
00148         isc_logcategory_t *             categories;
00149         unsigned int                    category_count;
00150         isc_logmodule_t *               modules;
00151         unsigned int                    module_count;
00152         int                             debug_level;
00153         isc_mutex_t                     lock;
00154         /* Locked by isc_log lock. */
00155         isc_logconfig_t *               logconfig;
00156         char                            buffer[LOG_BUFFER_SIZE];
00157         ISC_LIST(isc_logmessage_t)      messages;
00158 };
00159 
00160 /*!
00161  * Used when ISC_LOG_PRINTLEVEL is enabled for a channel.
00162  */
00163 static const char *log_level_strings[] = {
00164         "debug",
00165         "info",
00166         "notice",
00167         "warning",
00168         "error",
00169         "critical"
00170 };
00171 
00172 /*!
00173  * Used to convert ISC_LOG_* priorities into syslog priorities.
00174  * XXXDCL This will need modification for NT.
00175  */
00176 static const int syslog_map[] = {
00177         LOG_DEBUG,
00178         LOG_INFO,
00179         LOG_NOTICE,
00180         LOG_WARNING,
00181         LOG_ERR,
00182         LOG_CRIT
00183 };
00184 
00185 /*!
00186  * When adding new categories, a corresponding ISC_LOGCATEGORY_foo
00187  * definition needs to be added to <isc/log.h>.
00188  *
00189  * The default category is provided so that the internal default can
00190  * be overridden.  Since the default is always looked up as the first
00191  * channellist in the log context, it must come first in isc_categories[].
00192  */
00193 LIBISC_EXTERNAL_DATA isc_logcategory_t isc_categories[] = {
00194         { "default", 0 },       /* "default" must come first. */
00195         { "general", 0 },
00196         { NULL, 0 }
00197 };
00198 
00199 /*!
00200  * See above comment for categories on LIBISC_EXTERNAL_DATA, and apply it to modules.
00201  */
00202 LIBISC_EXTERNAL_DATA isc_logmodule_t isc_modules[] = {
00203         { "socket", 0 },
00204         { "time", 0 },
00205         { "interface", 0 },
00206         { "timer", 0 },
00207         { "file", 0 },
00208         { "other", 0 },
00209         { NULL, 0 }
00210 };
00211 
00212 /*!
00213  * This essentially constant structure must be filled in at run time,
00214  * because its channel member is pointed to a channel that is created
00215  * dynamically with isc_log_createchannel.
00216  */
00217 static isc_logchannellist_t default_channel;
00218 
00219 /*!
00220  * libisc logs to this context.
00221  */
00222 LIBISC_EXTERNAL_DATA isc_log_t *isc_lctx = NULL;
00223 
00224 /*!
00225  * Forward declarations.
00226  */
00227 static isc_result_t
00228 assignchannel(isc_logconfig_t *lcfg, unsigned int category_id,
00229               const isc_logmodule_t *module, isc_logchannel_t *channel);
00230 
00231 static isc_result_t
00232 sync_channellist(isc_logconfig_t *lcfg);
00233 
00234 static isc_result_t
00235 greatest_version(isc_logchannel_t *channel, int *greatest);
00236 
00237 static isc_result_t
00238 roll_log(isc_logchannel_t *channel);
00239 
00240 static void
00241 isc_log_doit(isc_log_t *lctx, isc_logcategory_t *category,
00242              isc_logmodule_t *module, int level, isc_boolean_t write_once,
00243              isc_msgcat_t *msgcat, int msgset, int msg,
00244              const char *format, va_list args)
00245      ISC_FORMAT_PRINTF(9, 0);
00246 
00247 /*@{*/
00248 /*!
00249  * Convenience macros.
00250  */
00251 
00252 #define FACILITY(channel)        (channel->destination.facility)
00253 #define FILE_NAME(channel)       (channel->destination.file.name)
00254 #define FILE_STREAM(channel)     (channel->destination.file.stream)
00255 #define FILE_VERSIONS(channel)   (channel->destination.file.versions)
00256 #define FILE_MAXSIZE(channel)    (channel->destination.file.maximum_size)
00257 #define FILE_MAXREACHED(channel) (channel->destination.file.maximum_reached)
00258 
00259 /*@}*/
00260 /****
00261  **** Public interfaces.
00262  ****/
00263 
00264 /*
00265  * Establish a new logging context, with default channels.
00266  */
00267 isc_result_t
00268 isc_log_create(isc_mem_t *mctx, isc_log_t **lctxp, isc_logconfig_t **lcfgp) {
00269         isc_log_t *lctx;
00270         isc_logconfig_t *lcfg = NULL;
00271         isc_result_t result;
00272 
00273         REQUIRE(mctx != NULL);
00274         REQUIRE(lctxp != NULL && *lctxp == NULL);
00275         REQUIRE(lcfgp == NULL || *lcfgp == NULL);
00276 
00277         lctx = isc_mem_get(mctx, sizeof(*lctx));
00278         if (lctx != NULL) {
00279                 lctx->mctx = NULL;
00280                 isc_mem_attach(mctx, &lctx->mctx);
00281                 lctx->categories = NULL;
00282                 lctx->category_count = 0;
00283                 lctx->modules = NULL;
00284                 lctx->module_count = 0;
00285                 lctx->debug_level = 0;
00286 
00287                 ISC_LIST_INIT(lctx->messages);
00288 
00289                 result = isc_mutex_init(&lctx->lock);
00290                 if (result != ISC_R_SUCCESS) {
00291                         isc_mem_putanddetach(&mctx, lctx, sizeof(*lctx));
00292                         return (result);
00293                 }
00294 
00295                 /*
00296                  * Normally setting the magic number is the last step done
00297                  * in a creation function, but a valid log context is needed
00298                  * by isc_log_registercategories and isc_logconfig_create.
00299                  * If either fails, the lctx is destroyed and not returned
00300                  * to the caller.
00301                  */
00302                 lctx->magic = LCTX_MAGIC;
00303 
00304                 isc_log_registercategories(lctx, isc_categories);
00305                 isc_log_registermodules(lctx, isc_modules);
00306                 result = isc_logconfig_create(lctx, &lcfg);
00307 
00308         } else
00309                 result = ISC_R_NOMEMORY;
00310 
00311         if (result == ISC_R_SUCCESS)
00312                 result = sync_channellist(lcfg);
00313 
00314         if (result == ISC_R_SUCCESS) {
00315                 lctx->logconfig = lcfg;
00316 
00317                 *lctxp = lctx;
00318                 if (lcfgp != NULL)
00319                         *lcfgp = lcfg;
00320 
00321         } else {
00322                 if (lcfg != NULL)
00323                         isc_logconfig_destroy(&lcfg);
00324                 if (lctx != NULL)
00325                         isc_log_destroy(&lctx);
00326         }
00327 
00328         return (result);
00329 }
00330 
00331 isc_result_t
00332 isc_logconfig_create(isc_log_t *lctx, isc_logconfig_t **lcfgp) {
00333         isc_logconfig_t *lcfg;
00334         isc_logdestination_t destination;
00335         isc_result_t result = ISC_R_SUCCESS;
00336         int level = ISC_LOG_INFO;
00337 
00338         REQUIRE(lcfgp != NULL && *lcfgp == NULL);
00339         REQUIRE(VALID_CONTEXT(lctx));
00340 
00341         lcfg = isc_mem_get(lctx->mctx, sizeof(*lcfg));
00342 
00343         if (lcfg != NULL) {
00344                 lcfg->lctx = lctx;
00345                 lcfg->channellists = NULL;
00346                 lcfg->channellist_count = 0;
00347                 lcfg->duplicate_interval = 0;
00348                 lcfg->highest_level = level;
00349                 lcfg->tag = NULL;
00350                 lcfg->dynamic = ISC_FALSE;
00351 
00352                 ISC_LIST_INIT(lcfg->channels);
00353 
00354                 /*
00355                  * Normally the magic number is the last thing set in the
00356                  * structure, but isc_log_createchannel() needs a valid
00357                  * config.  If the channel creation fails, the lcfg is not
00358                  * returned to the caller.
00359                  */
00360                 lcfg->magic = LCFG_MAGIC;
00361 
00362         } else
00363                 result = ISC_R_NOMEMORY;
00364 
00365         /*
00366          * Create the default channels:
00367          *      default_syslog, default_stderr, default_debug and null.
00368          */
00369         if (result == ISC_R_SUCCESS) {
00370                 destination.facility = LOG_DAEMON;
00371                 result = isc_log_createchannel(lcfg, "default_syslog",
00372                                                ISC_LOG_TOSYSLOG, level,
00373                                                &destination, 0);
00374         }
00375 
00376         if (result == ISC_R_SUCCESS) {
00377                 destination.file.stream = stderr;
00378                 destination.file.name = NULL;
00379                 destination.file.versions = ISC_LOG_ROLLNEVER;
00380                 destination.file.maximum_size = 0;
00381                 result = isc_log_createchannel(lcfg, "default_stderr",
00382                                                ISC_LOG_TOFILEDESC,
00383                                                level,
00384                                                &destination,
00385                                                ISC_LOG_PRINTTIME);
00386         }
00387 
00388         if (result == ISC_R_SUCCESS) {
00389                 /*
00390                  * Set the default category's channel to default_stderr,
00391                  * which is at the head of the channels list because it was
00392                  * just created.
00393                  */
00394                 default_channel.channel = ISC_LIST_HEAD(lcfg->channels);
00395 
00396                 destination.file.stream = stderr;
00397                 destination.file.name = NULL;
00398                 destination.file.versions = ISC_LOG_ROLLNEVER;
00399                 destination.file.maximum_size = 0;
00400                 result = isc_log_createchannel(lcfg, "default_debug",
00401                                                ISC_LOG_TOFILEDESC,
00402                                                ISC_LOG_DYNAMIC,
00403                                                &destination,
00404                                                ISC_LOG_PRINTTIME);
00405         }
00406 
00407         if (result == ISC_R_SUCCESS)
00408                 result = isc_log_createchannel(lcfg, "null",
00409                                                ISC_LOG_TONULL,
00410                                                ISC_LOG_DYNAMIC,
00411                                                NULL, 0);
00412 
00413         if (result == ISC_R_SUCCESS)
00414                 *lcfgp = lcfg;
00415 
00416         else
00417                 if (lcfg != NULL)
00418                         isc_logconfig_destroy(&lcfg);
00419 
00420         return (result);
00421 }
00422 
00423 isc_logconfig_t *
00424 isc_logconfig_get(isc_log_t *lctx) {
00425         REQUIRE(VALID_CONTEXT(lctx));
00426 
00427         ENSURE(lctx->logconfig != NULL);
00428 
00429         return (lctx->logconfig);
00430 }
00431 
00432 isc_result_t
00433 isc_logconfig_use(isc_log_t *lctx, isc_logconfig_t *lcfg) {
00434         isc_logconfig_t *old_cfg;
00435         isc_result_t result;
00436 
00437         REQUIRE(VALID_CONTEXT(lctx));
00438         REQUIRE(VALID_CONFIG(lcfg));
00439         REQUIRE(lcfg->lctx == lctx);
00440 
00441         /*
00442          * Ensure that lcfg->channellist_count == lctx->category_count.
00443          * They won't be equal if isc_log_usechannel has not been called
00444          * since any call to isc_log_registercategories.
00445          */
00446         result = sync_channellist(lcfg);
00447         if (result != ISC_R_SUCCESS)
00448                 return (result);
00449 
00450         LOCK(&lctx->lock);
00451 
00452         old_cfg = lctx->logconfig;
00453         lctx->logconfig = lcfg;
00454 
00455         UNLOCK(&lctx->lock);
00456 
00457         isc_logconfig_destroy(&old_cfg);
00458 
00459         return (ISC_R_SUCCESS);
00460 }
00461 
00462 void
00463 isc_log_destroy(isc_log_t **lctxp) {
00464         isc_log_t *lctx;
00465         isc_logconfig_t *lcfg;
00466         isc_mem_t *mctx;
00467         isc_logmessage_t *message;
00468 
00469         REQUIRE(lctxp != NULL && VALID_CONTEXT(*lctxp));
00470 
00471         lctx = *lctxp;
00472         mctx = lctx->mctx;
00473 
00474         if (lctx->logconfig != NULL) {
00475                 lcfg = lctx->logconfig;
00476                 lctx->logconfig = NULL;
00477                 isc_logconfig_destroy(&lcfg);
00478         }
00479 
00480         DESTROYLOCK(&lctx->lock);
00481 
00482         while ((message = ISC_LIST_HEAD(lctx->messages)) != NULL) {
00483                 ISC_LIST_UNLINK(lctx->messages, message, link);
00484 
00485                 isc_mem_put(mctx, message,
00486                             sizeof(*message) + strlen(message->text) + 1);
00487         }
00488 
00489         lctx->buffer[0] = '\0';
00490         lctx->debug_level = 0;
00491         lctx->categories = NULL;
00492         lctx->category_count = 0;
00493         lctx->modules = NULL;
00494         lctx->module_count = 0;
00495         lctx->mctx = NULL;
00496         lctx->magic = 0;
00497 
00498         isc_mem_putanddetach(&mctx, lctx, sizeof(*lctx));
00499 
00500         *lctxp = NULL;
00501 }
00502 
00503 void
00504 isc_logconfig_destroy(isc_logconfig_t **lcfgp) {
00505         isc_logconfig_t *lcfg;
00506         isc_mem_t *mctx;
00507         isc_logchannel_t *channel;
00508         isc_logchannellist_t *item;
00509         char *filename;
00510         unsigned int i;
00511 
00512         REQUIRE(lcfgp != NULL && VALID_CONFIG(*lcfgp));
00513 
00514         lcfg = *lcfgp;
00515 
00516         /*
00517          * This function cannot be called with a logconfig that is in
00518          * use by a log context.
00519          */
00520         REQUIRE(lcfg->lctx != NULL && lcfg->lctx->logconfig != lcfg);
00521 
00522         mctx = lcfg->lctx->mctx;
00523 
00524         while ((channel = ISC_LIST_HEAD(lcfg->channels)) != NULL) {
00525                 ISC_LIST_UNLINK(lcfg->channels, channel, link);
00526 
00527                 if (channel->type == ISC_LOG_TOFILE) {
00528                         /*
00529                          * The filename for the channel may have ultimately
00530                          * started its life in user-land as a const string,
00531                          * but in isc_log_createchannel it gets copied
00532                          * into writable memory and is not longer truly const.
00533                          */
00534                         DE_CONST(FILE_NAME(channel), filename);
00535                         isc_mem_free(mctx, filename);
00536 
00537                         if (FILE_STREAM(channel) != NULL)
00538                                 (void)fclose(FILE_STREAM(channel));
00539                 }
00540 
00541                 isc_mem_free(mctx, channel->name);
00542                 isc_mem_put(mctx, channel, sizeof(*channel));
00543         }
00544 
00545         for (i = 0; i < lcfg->channellist_count; i++)
00546                 while ((item = ISC_LIST_HEAD(lcfg->channellists[i])) != NULL) {
00547                         ISC_LIST_UNLINK(lcfg->channellists[i], item, link);
00548                         isc_mem_put(mctx, item, sizeof(*item));
00549                 }
00550 
00551         if (lcfg->channellist_count > 0)
00552                 isc_mem_put(mctx, lcfg->channellists,
00553                             lcfg->channellist_count *
00554                             sizeof(ISC_LIST(isc_logchannellist_t)));
00555 
00556         lcfg->dynamic = ISC_FALSE;
00557         if (lcfg->tag != NULL)
00558                 isc_mem_free(lcfg->lctx->mctx, lcfg->tag);
00559         lcfg->tag = NULL;
00560         lcfg->highest_level = 0;
00561         lcfg->duplicate_interval = 0;
00562         lcfg->magic = 0;
00563 
00564         isc_mem_put(mctx, lcfg, sizeof(*lcfg));
00565 
00566         *lcfgp = NULL;
00567 }
00568 
00569 void
00570 isc_log_registercategories(isc_log_t *lctx, isc_logcategory_t categories[]) {
00571         isc_logcategory_t *catp;
00572 
00573         REQUIRE(VALID_CONTEXT(lctx));
00574         REQUIRE(categories != NULL && categories[0].name != NULL);
00575 
00576         /*
00577          * XXXDCL This somewhat sleazy situation of using the last pointer
00578          * in one category array to point to the next array exists because
00579          * this registration function returns void and I didn't want to have
00580          * change everything that used it by making it return an isc_result_t.
00581          * It would need to do that if it had to allocate memory to store
00582          * pointers to each array passed in.
00583          */
00584         if (lctx->categories == NULL)
00585                 lctx->categories = categories;
00586 
00587         else {
00588                 /*
00589                  * Adjust the last (NULL) pointer of the already registered
00590                  * categories to point to the incoming array.
00591                  */
00592                 for (catp = lctx->categories; catp->name != NULL; )
00593                         if (catp->id == UINT_MAX)
00594                                 /*
00595                                  * The name pointer points to the next array.
00596                                  * Ick.
00597                                  */
00598                                 DE_CONST(catp->name, catp);
00599                         else
00600                                 catp++;
00601 
00602                 catp->name = (void *)categories;
00603                 catp->id = UINT_MAX;
00604         }
00605 
00606         /*
00607          * Update the id number of the category with its new global id.
00608          */
00609         for (catp = categories; catp->name != NULL; catp++)
00610                 catp->id = lctx->category_count++;
00611 }
00612 
00613 isc_logcategory_t *
00614 isc_log_categorybyname(isc_log_t *lctx, const char *name) {
00615         isc_logcategory_t *catp;
00616 
00617         REQUIRE(VALID_CONTEXT(lctx));
00618         REQUIRE(name != NULL);
00619 
00620         for (catp = lctx->categories; catp->name != NULL; )
00621                 if (catp->id == UINT_MAX)
00622                         /*
00623                          * catp is neither modified nor returned to the
00624                          * caller, so removing its const qualifier is ok.
00625                          */
00626                         DE_CONST(catp->name, catp);
00627                 else {
00628                         if (strcmp(catp->name, name) == 0)
00629                                 return (catp);
00630                         catp++;
00631                 }
00632 
00633         return (NULL);
00634 }
00635 
00636 void
00637 isc_log_registermodules(isc_log_t *lctx, isc_logmodule_t modules[]) {
00638         isc_logmodule_t *modp;
00639 
00640         REQUIRE(VALID_CONTEXT(lctx));
00641         REQUIRE(modules != NULL && modules[0].name != NULL);
00642 
00643         /*
00644          * XXXDCL This somewhat sleazy situation of using the last pointer
00645          * in one category array to point to the next array exists because
00646          * this registration function returns void and I didn't want to have
00647          * change everything that used it by making it return an isc_result_t.
00648          * It would need to do that if it had to allocate memory to store
00649          * pointers to each array passed in.
00650          */
00651         if (lctx->modules == NULL)
00652                 lctx->modules = modules;
00653 
00654         else {
00655                 /*
00656                  * Adjust the last (NULL) pointer of the already registered
00657                  * modules to point to the incoming array.
00658                  */
00659                 for (modp = lctx->modules; modp->name != NULL; )
00660                         if (modp->id == UINT_MAX)
00661                                 /*
00662                                  * The name pointer points to the next array.
00663                                  * Ick.
00664                                  */
00665                                 DE_CONST(modp->name, modp);
00666                         else
00667                                 modp++;
00668 
00669                 modp->name = (void *)modules;
00670                 modp->id = UINT_MAX;
00671         }
00672 
00673         /*
00674          * Update the id number of the module with its new global id.
00675          */
00676         for (modp = modules; modp->name != NULL; modp++)
00677                 modp->id = lctx->module_count++;
00678 }
00679 
00680 isc_logmodule_t *
00681 isc_log_modulebyname(isc_log_t *lctx, const char *name) {
00682         isc_logmodule_t *modp;
00683 
00684         REQUIRE(VALID_CONTEXT(lctx));
00685         REQUIRE(name != NULL);
00686 
00687         for (modp = lctx->modules; modp->name != NULL; )
00688                 if (modp->id == UINT_MAX)
00689                         /*
00690                          * modp is neither modified nor returned to the
00691                          * caller, so removing its const qualifier is ok.
00692                          */
00693                         DE_CONST(modp->name, modp);
00694                 else {
00695                         if (strcmp(modp->name, name) == 0)
00696                                 return (modp);
00697                         modp++;
00698                 }
00699 
00700         return (NULL);
00701 }
00702 
00703 isc_result_t
00704 isc_log_createchannel(isc_logconfig_t *lcfg, const char *name,
00705                       unsigned int type, int level,
00706                       const isc_logdestination_t *destination,
00707                       unsigned int flags)
00708 {
00709         isc_logchannel_t *channel;
00710         isc_mem_t *mctx;
00711         unsigned int permitted = ISC_LOG_PRINTALL | ISC_LOG_DEBUGONLY |
00712                                  ISC_LOG_BUFFERED;
00713 
00714         REQUIRE(VALID_CONFIG(lcfg));
00715         REQUIRE(name != NULL);
00716         REQUIRE(type == ISC_LOG_TOSYSLOG   || type == ISC_LOG_TOFILE ||
00717                 type == ISC_LOG_TOFILEDESC || type == ISC_LOG_TONULL);
00718         REQUIRE(destination != NULL || type == ISC_LOG_TONULL);
00719         REQUIRE(level >= ISC_LOG_CRITICAL);
00720         REQUIRE((flags & ~permitted) == 0);
00721 
00722         /* XXXDCL find duplicate names? */
00723 
00724         mctx = lcfg->lctx->mctx;
00725 
00726         channel = isc_mem_get(mctx, sizeof(*channel));
00727         if (channel == NULL)
00728                 return (ISC_R_NOMEMORY);
00729 
00730         channel->name = isc_mem_strdup(mctx, name);
00731         if (channel->name == NULL) {
00732                 isc_mem_put(mctx, channel, sizeof(*channel));
00733                 return (ISC_R_NOMEMORY);
00734         }
00735 
00736         channel->type = type;
00737         channel->level = level;
00738         channel->flags = flags;
00739         ISC_LINK_INIT(channel, link);
00740 
00741         switch (type) {
00742         case ISC_LOG_TOSYSLOG:
00743                 FACILITY(channel) = destination->facility;
00744                 break;
00745 
00746         case ISC_LOG_TOFILE:
00747                 /*
00748                  * The file name is copied because greatest_version wants
00749                  * to scribble on it, so it needs to be definitely in
00750                  * writable memory.
00751                  */
00752                 FILE_NAME(channel) =
00753                         isc_mem_strdup(mctx, destination->file.name);
00754                 FILE_STREAM(channel) = NULL;
00755                 FILE_VERSIONS(channel) = destination->file.versions;
00756                 FILE_MAXSIZE(channel) = destination->file.maximum_size;
00757                 FILE_MAXREACHED(channel) = ISC_FALSE;
00758                 break;
00759 
00760         case ISC_LOG_TOFILEDESC:
00761                 FILE_NAME(channel) = NULL;
00762                 FILE_STREAM(channel) = destination->file.stream;
00763                 FILE_MAXSIZE(channel) = 0;
00764                 FILE_VERSIONS(channel) = ISC_LOG_ROLLNEVER;
00765                 break;
00766 
00767         case ISC_LOG_TONULL:
00768                 /* Nothing. */
00769                 break;
00770 
00771         default:
00772                 isc_mem_free(mctx, channel->name);
00773                 isc_mem_put(mctx, channel, sizeof(*channel));
00774                 return (ISC_R_UNEXPECTED);
00775         }
00776 
00777         ISC_LIST_PREPEND(lcfg->channels, channel, link);
00778 
00779         /*
00780          * If default_stderr was redefined, make the default category
00781          * point to the new default_stderr.
00782          */
00783         if (strcmp(name, "default_stderr") == 0)
00784                 default_channel.channel = channel;
00785 
00786         return (ISC_R_SUCCESS);
00787 }
00788 
00789 isc_result_t
00790 isc_log_usechannel(isc_logconfig_t *lcfg, const char *name,
00791                    const isc_logcategory_t *category,
00792                    const isc_logmodule_t *module)
00793 {
00794         isc_log_t *lctx;
00795         isc_logchannel_t *channel;
00796         isc_result_t result = ISC_R_SUCCESS;
00797         unsigned int i;
00798 
00799         REQUIRE(VALID_CONFIG(lcfg));
00800         REQUIRE(name != NULL);
00801 
00802         lctx = lcfg->lctx;
00803 
00804         REQUIRE(category == NULL || category->id < lctx->category_count);
00805         REQUIRE(module == NULL || module->id < lctx->module_count);
00806 
00807         for (channel = ISC_LIST_HEAD(lcfg->channels); channel != NULL;
00808              channel = ISC_LIST_NEXT(channel, link))
00809                 if (strcmp(name, channel->name) == 0)
00810                         break;
00811 
00812         if (channel == NULL)
00813                 return (ISC_R_NOTFOUND);
00814 
00815         if (category != NULL)
00816                 result = assignchannel(lcfg, category->id, module, channel);
00817 
00818         else
00819                 /*
00820                  * Assign to all categories.  Note that this includes
00821                  * the default channel.
00822                  */
00823                 for (i = 0; i < lctx->category_count; i++) {
00824                         result = assignchannel(lcfg, i, module, channel);
00825                         if (result != ISC_R_SUCCESS)
00826                                 break;
00827                 }
00828 
00829         return (result);
00830 }
00831 
00832 void
00833 isc_log_write(isc_log_t *lctx, isc_logcategory_t *category,
00834               isc_logmodule_t *module, int level, const char *format, ...)
00835 {
00836         va_list args;
00837 
00838         /*
00839          * Contract checking is done in isc_log_doit().
00840          */
00841 
00842         va_start(args, format);
00843         isc_log_doit(lctx, category, module, level, ISC_FALSE,
00844                      NULL, 0, 0, format, args);
00845         va_end(args);
00846 }
00847 
00848 void
00849 isc_log_vwrite(isc_log_t *lctx, isc_logcategory_t *category,
00850                isc_logmodule_t *module, int level,
00851                const char *format, va_list args)
00852 {
00853         /*
00854          * Contract checking is done in isc_log_doit().
00855          */
00856         isc_log_doit(lctx, category, module, level, ISC_FALSE,
00857                      NULL, 0, 0, format, args);
00858 }
00859 
00860 void
00861 isc_log_write1(isc_log_t *lctx, isc_logcategory_t *category,
00862                isc_logmodule_t *module, int level, const char *format, ...)
00863 {
00864         va_list args;
00865 
00866         /*
00867          * Contract checking is done in isc_log_doit().
00868          */
00869 
00870         va_start(args, format);
00871         isc_log_doit(lctx, category, module, level, ISC_TRUE,
00872                      NULL, 0, 0, format, args);
00873         va_end(args);
00874 }
00875 
00876 void
00877 isc_log_vwrite1(isc_log_t *lctx, isc_logcategory_t *category,
00878                 isc_logmodule_t *module, int level,
00879                 const char *format, va_list args)
00880 {
00881         /*
00882          * Contract checking is done in isc_log_doit().
00883          */
00884         isc_log_doit(lctx, category, module, level, ISC_TRUE,
00885                      NULL, 0, 0, format, args);
00886 }
00887 
00888 void
00889 isc_log_iwrite(isc_log_t *lctx, isc_logcategory_t *category,
00890                isc_logmodule_t *module, int level,
00891                isc_msgcat_t *msgcat, int msgset, int msg,
00892                const char *format, ...)
00893 {
00894         va_list args;
00895 
00896         /*
00897          * Contract checking is done in isc_log_doit().
00898          */
00899 
00900         va_start(args, format);
00901         isc_log_doit(lctx, category, module, level, ISC_FALSE,
00902                      msgcat, msgset, msg, format, args);
00903         va_end(args);
00904 }
00905 
00906 void
00907 isc_log_ivwrite(isc_log_t *lctx, isc_logcategory_t *category,
00908                isc_logmodule_t *module, int level,
00909                isc_msgcat_t *msgcat, int msgset, int msg,
00910                const char *format, va_list args)
00911 {
00912         /*
00913          * Contract checking is done in isc_log_doit().
00914          */
00915         isc_log_doit(lctx, category, module, level, ISC_FALSE,
00916                      msgcat, msgset, msg, format, args);
00917 }
00918 
00919 void
00920 isc_log_iwrite1(isc_log_t *lctx, isc_logcategory_t *category,
00921                 isc_logmodule_t *module, int level,
00922                 isc_msgcat_t *msgcat, int msgset, int msg,
00923                 const char *format, ...)
00924 {
00925         va_list args;
00926 
00927         /*
00928          * Contract checking is done in isc_log_doit().
00929          */
00930 
00931         va_start(args, format);
00932         isc_log_doit(lctx, category, module, level, ISC_TRUE,
00933                      msgcat, msgset, msg, format, args);
00934         va_end(args);
00935 }
00936 
00937 void
00938 isc_log_ivwrite1(isc_log_t *lctx, isc_logcategory_t *category,
00939                  isc_logmodule_t *module, int level,
00940                  isc_msgcat_t *msgcat, int msgset, int msg,
00941                  const char *format, va_list args)
00942 {
00943         /*
00944          * Contract checking is done in isc_log_doit().
00945          */
00946         isc_log_doit(lctx, category, module, level, ISC_TRUE,
00947                      msgcat, msgset, msg, format, args);
00948 }
00949 
00950 void
00951 isc_log_setcontext(isc_log_t *lctx) {
00952         isc_lctx = lctx;
00953 }
00954 
00955 void
00956 isc_log_setdebuglevel(isc_log_t *lctx, unsigned int level) {
00957         isc_logchannel_t *channel;
00958 
00959         REQUIRE(VALID_CONTEXT(lctx));
00960 
00961         LOCK(&lctx->lock);
00962 
00963         lctx->debug_level = level;
00964         /*
00965          * Close ISC_LOG_DEBUGONLY channels if level is zero.
00966          */
00967         if (lctx->debug_level == 0)
00968                 for (channel = ISC_LIST_HEAD(lctx->logconfig->channels);
00969                      channel != NULL;
00970                      channel = ISC_LIST_NEXT(channel, link))
00971                         if (channel->type == ISC_LOG_TOFILE &&
00972                             (channel->flags & ISC_LOG_DEBUGONLY) != 0 &&
00973                             FILE_STREAM(channel) != NULL) {
00974                                 (void)fclose(FILE_STREAM(channel));
00975                                 FILE_STREAM(channel) = NULL;
00976                         }
00977         UNLOCK(&lctx->lock);
00978 }
00979 
00980 unsigned int
00981 isc_log_getdebuglevel(isc_log_t *lctx) {
00982         REQUIRE(VALID_CONTEXT(lctx));
00983 
00984         return (lctx->debug_level);
00985 }
00986 
00987 void
00988 isc_log_setduplicateinterval(isc_logconfig_t *lcfg, unsigned int interval) {
00989         REQUIRE(VALID_CONFIG(lcfg));
00990 
00991         lcfg->duplicate_interval = interval;
00992 }
00993 
00994 unsigned int
00995 isc_log_getduplicateinterval(isc_logconfig_t *lcfg) {
00996         REQUIRE(VALID_CONTEXT(lcfg));
00997 
00998         return (lcfg->duplicate_interval);
00999 }
01000 
01001 isc_result_t
01002 isc_log_settag(isc_logconfig_t *lcfg, const char *tag) {
01003         REQUIRE(VALID_CONFIG(lcfg));
01004 
01005         if (tag != NULL && *tag != '\0') {
01006                 if (lcfg->tag != NULL)
01007                         isc_mem_free(lcfg->lctx->mctx, lcfg->tag);
01008                 lcfg->tag = isc_mem_strdup(lcfg->lctx->mctx, tag);
01009                 if (lcfg->tag == NULL)
01010                         return (ISC_R_NOMEMORY);
01011 
01012         } else {
01013                 if (lcfg->tag != NULL)
01014                         isc_mem_free(lcfg->lctx->mctx, lcfg->tag);
01015                 lcfg->tag = NULL;
01016         }
01017 
01018         return (ISC_R_SUCCESS);
01019 }
01020 
01021 char *
01022 isc_log_gettag(isc_logconfig_t *lcfg) {
01023         REQUIRE(VALID_CONFIG(lcfg));
01024 
01025         return (lcfg->tag);
01026 }
01027 
01028 /* XXXDCL NT  -- This interface will assuredly be changing. */
01029 void
01030 isc_log_opensyslog(const char *tag, int options, int facility) {
01031         (void)openlog(tag, options, facility);
01032 }
01033 
01034 void
01035 isc_log_closefilelogs(isc_log_t *lctx) {
01036         isc_logchannel_t *channel;
01037 
01038         REQUIRE(VALID_CONTEXT(lctx));
01039 
01040         LOCK(&lctx->lock);
01041         for (channel = ISC_LIST_HEAD(lctx->logconfig->channels);
01042              channel != NULL;
01043              channel = ISC_LIST_NEXT(channel, link))
01044 
01045                 if (channel->type == ISC_LOG_TOFILE &&
01046                     FILE_STREAM(channel) != NULL) {
01047                         (void)fclose(FILE_STREAM(channel));
01048                         FILE_STREAM(channel) = NULL;
01049                 }
01050         UNLOCK(&lctx->lock);
01051 }
01052 
01053 /****
01054  **** Internal functions
01055  ****/
01056 
01057 static isc_result_t
01058 assignchannel(isc_logconfig_t *lcfg, unsigned int category_id,
01059               const isc_logmodule_t *module, isc_logchannel_t *channel)
01060 {
01061         isc_logchannellist_t *new_item;
01062         isc_log_t *lctx;
01063         isc_result_t result;
01064 
01065         REQUIRE(VALID_CONFIG(lcfg));
01066 
01067         lctx = lcfg->lctx;
01068 
01069         REQUIRE(category_id < lctx->category_count);
01070         REQUIRE(module == NULL || module->id < lctx->module_count);
01071         REQUIRE(channel != NULL);
01072 
01073         /*
01074          * Ensure lcfg->channellist_count == lctx->category_count.
01075          */
01076         result = sync_channellist(lcfg);
01077         if (result != ISC_R_SUCCESS)
01078                 return (result);
01079 
01080         new_item = isc_mem_get(lctx->mctx, sizeof(*new_item));
01081         if (new_item == NULL)
01082                 return (ISC_R_NOMEMORY);
01083 
01084         new_item->channel = channel;
01085         new_item->module = module;
01086         ISC_LIST_INITANDPREPEND(lcfg->channellists[category_id],
01087                                new_item, link);
01088 
01089         /*
01090          * Remember the highest logging level set by any channel in the
01091          * logging config, so isc_log_doit() can quickly return if the
01092          * message is too high to be logged by any channel.
01093          */
01094         if (channel->type != ISC_LOG_TONULL) {
01095                 if (lcfg->highest_level < channel->level)
01096                         lcfg->highest_level = channel->level;
01097                 if (channel->level == ISC_LOG_DYNAMIC)
01098                         lcfg->dynamic = ISC_TRUE;
01099         }
01100 
01101         return (ISC_R_SUCCESS);
01102 }
01103 
01104 /*
01105  * This would ideally be part of isc_log_registercategories(), except then
01106  * that function would have to return isc_result_t instead of void.
01107  */
01108 static isc_result_t
01109 sync_channellist(isc_logconfig_t *lcfg) {
01110         unsigned int bytes;
01111         isc_log_t *lctx;
01112         void *lists;
01113 
01114         REQUIRE(VALID_CONFIG(lcfg));
01115 
01116         lctx = lcfg->lctx;
01117 
01118         REQUIRE(lctx->category_count != 0);
01119 
01120         if (lctx->category_count == lcfg->channellist_count)
01121                 return (ISC_R_SUCCESS);
01122 
01123         bytes = lctx->category_count * sizeof(ISC_LIST(isc_logchannellist_t));
01124 
01125         lists = isc_mem_get(lctx->mctx, bytes);
01126 
01127         if (lists == NULL)
01128                 return (ISC_R_NOMEMORY);
01129 
01130         memset(lists, 0, bytes);
01131 
01132         if (lcfg->channellist_count != 0) {
01133                 bytes = lcfg->channellist_count *
01134                         sizeof(ISC_LIST(isc_logchannellist_t));
01135                 memmove(lists, lcfg->channellists, bytes);
01136                 isc_mem_put(lctx->mctx, lcfg->channellists, bytes);
01137         }
01138 
01139         lcfg->channellists = lists;
01140         lcfg->channellist_count = lctx->category_count;
01141 
01142         return (ISC_R_SUCCESS);
01143 }
01144 
01145 static isc_result_t
01146 greatest_version(isc_logchannel_t *channel, int *greatestp) {
01147         /* XXXDCL HIGHLY NT */
01148         char *basename, *digit_end;
01149         const char *dirname;
01150         int version, greatest = -1;
01151         size_t basenamelen;
01152         isc_dir_t dir;
01153         isc_result_t result;
01154         char sep = '/';
01155 #ifdef _WIN32
01156         char *basename2;
01157 #endif
01158 
01159         REQUIRE(channel->type == ISC_LOG_TOFILE);
01160 
01161         /*
01162          * It is safe to DE_CONST the file.name because it was copied
01163          * with isc_mem_strdup in isc_log_createchannel.
01164          */
01165         basename = strrchr(FILE_NAME(channel), sep);
01166 #ifdef _WIN32
01167         basename2 = strrchr(FILE_NAME(channel), '\\');
01168         if ((basename != NULL && basename2 != NULL && basename2 > basename) ||
01169             (basename == NULL && basename2 != NULL)) {
01170                 basename = basename2;
01171                 sep = '\\';
01172         }
01173 #endif
01174         if (basename != NULL) {
01175                 *basename++ = '\0';
01176                 dirname = FILE_NAME(channel);
01177         } else {
01178                 DE_CONST(FILE_NAME(channel), basename);
01179                 dirname = ".";
01180         }
01181         basenamelen = strlen(basename);
01182 
01183         isc_dir_init(&dir);
01184         result = isc_dir_open(&dir, dirname);
01185 
01186         /*
01187          * Replace the file separator if it was taken out.
01188          */
01189         if (basename != FILE_NAME(channel))
01190                 *(basename - 1) = sep;
01191 
01192         /*
01193          * Return if the directory open failed.
01194          */
01195         if (result != ISC_R_SUCCESS)
01196                 return (result);
01197 
01198         while (isc_dir_read(&dir) == ISC_R_SUCCESS) {
01199                 if (dir.entry.length > basenamelen &&
01200                     strncmp(dir.entry.name, basename, basenamelen) == 0 &&
01201                     dir.entry.name[basenamelen] == '.') {
01202 
01203                         version = strtol(&dir.entry.name[basenamelen + 1],
01204                                          &digit_end, 10);
01205                         if (*digit_end == '\0' && version > greatest)
01206                                 greatest = version;
01207                 }
01208         }
01209         isc_dir_close(&dir);
01210 
01211         *greatestp = ++greatest;
01212 
01213         return (ISC_R_SUCCESS);
01214 }
01215 
01216 static isc_result_t
01217 roll_log(isc_logchannel_t *channel) {
01218         int i, n, greatest;
01219         char current[PATH_MAX + 1];
01220         char new[PATH_MAX + 1];
01221         const char *path;
01222         isc_result_t result;
01223 
01224         /*
01225          * Do nothing (not even excess version trimming) if ISC_LOG_ROLLNEVER
01226          * is specified.  Apparently complete external control over the log
01227          * files is desired.
01228          */
01229         if (FILE_VERSIONS(channel) == ISC_LOG_ROLLNEVER)
01230                 return (ISC_R_SUCCESS);
01231 
01232         path = FILE_NAME(channel);
01233 
01234         /*
01235          * Set greatest_version to the greatest existing version
01236          * (not the maximum requested version).  This is 1 based even
01237          * though the file names are 0 based, so an oldest log of log.1
01238          * is a greatest_version of 2.
01239          */
01240         result = greatest_version(channel, &greatest);
01241         if (result != ISC_R_SUCCESS)
01242                 return (result);
01243 
01244         /*
01245          * Now greatest should be set to the highest version number desired.
01246          * Since the highest number is one less than FILE_VERSIONS(channel)
01247          * when not doing infinite log rolling, greatest will need to be
01248          * decremented when it is equal to -- or greater than --
01249          * FILE_VERSIONS(channel).  When greatest is less than
01250          * FILE_VERSIONS(channel), it is already suitable for use as
01251          * the maximum version number.
01252          */
01253 
01254         if (FILE_VERSIONS(channel) == ISC_LOG_ROLLINFINITE ||
01255             FILE_VERSIONS(channel) > greatest)
01256                 ;               /* Do nothing. */
01257         else
01258                 /*
01259                  * When greatest is >= FILE_VERSIONS(channel), it needs to
01260                  * be reduced until it is FILE_VERSIONS(channel) - 1.
01261                  * Remove any excess logs on the way to that value.
01262                  */
01263                 while (--greatest >= FILE_VERSIONS(channel)) {
01264                         n = snprintf(current, sizeof(current), "%s.%d",
01265                                      path, greatest);
01266                         if (n >= (int)sizeof(current) || n < 0)
01267                                 result = ISC_R_NOSPACE;
01268                         else
01269                                 result = isc_file_remove(current);
01270                         if (result != ISC_R_SUCCESS &&
01271                             result != ISC_R_FILENOTFOUND)
01272                                 syslog(LOG_ERR,
01273                                        "unable to remove log file '%s.%d': %s",
01274                                        path, greatest,
01275                                        isc_result_totext(result));
01276                 }
01277 
01278         for (i = greatest; i > 0; i--) {
01279                 result = ISC_R_SUCCESS;
01280                 n = snprintf(current, sizeof(current), "%s.%d", path, i - 1);
01281                 if (n >= (int)sizeof(current) || n < 0)
01282                         result = ISC_R_NOSPACE;
01283                 if (result == ISC_R_SUCCESS) {
01284                         n = snprintf(new, sizeof(new), "%s.%d", path, i);
01285                         if (n >= (int)sizeof(new) || n < 0)
01286                                 result = ISC_R_NOSPACE;
01287                 }
01288                 if (result == ISC_R_SUCCESS)
01289                         result = isc_file_rename(current, new);
01290                 if (result != ISC_R_SUCCESS &&
01291                     result != ISC_R_FILENOTFOUND)
01292                         syslog(LOG_ERR,
01293                                "unable to rename log file '%s.%d' to "
01294                                "'%s.%d': %s", path, i - 1, path, i,
01295                                isc_result_totext(result));
01296         }
01297 
01298         if (FILE_VERSIONS(channel) != 0) {
01299                 n = snprintf(new, sizeof(new), "%s.0", path);
01300                 if (n >= (int)sizeof(new) || n < 0)
01301                         result = ISC_R_NOSPACE;
01302                 else
01303                         result = isc_file_rename(path, new);
01304                 if (result != ISC_R_SUCCESS &&
01305                     result != ISC_R_FILENOTFOUND)
01306                         syslog(LOG_ERR,
01307                                "unable to rename log file '%s' to '%s.0': %s",
01308                                path, path, isc_result_totext(result));
01309         } else {
01310                 result = isc_file_remove(path);
01311                 if (result != ISC_R_SUCCESS &&
01312                     result != ISC_R_FILENOTFOUND)
01313                         syslog(LOG_ERR, "unable to remove log file '%s': %s",
01314                                path, isc_result_totext(result));
01315         }
01316 
01317         return (ISC_R_SUCCESS);
01318 }
01319 
01320 static isc_result_t
01321 isc_log_open(isc_logchannel_t *channel) {
01322         struct stat statbuf;
01323         isc_boolean_t regular_file;
01324         isc_boolean_t roll = ISC_FALSE;
01325         isc_result_t result = ISC_R_SUCCESS;
01326         const char *path;
01327 
01328         REQUIRE(channel->type == ISC_LOG_TOFILE);
01329         REQUIRE(FILE_STREAM(channel) == NULL);
01330 
01331         path = FILE_NAME(channel);
01332 
01333         REQUIRE(path != NULL && *path != '\0');
01334 
01335         /*
01336          * Determine type of file; only regular files will be
01337          * version renamed, and only if the base file exists
01338          * and either has no size limit or has reached its size limit.
01339          */
01340         if (stat(path, &statbuf) == 0) {
01341                 regular_file = S_ISREG(statbuf.st_mode) ? ISC_TRUE : ISC_FALSE;
01342                 /* XXXDCL if not regular_file complain? */
01343                 if ((FILE_MAXSIZE(channel) == 0 &&
01344                      FILE_VERSIONS(channel) != ISC_LOG_ROLLNEVER) ||
01345                     (FILE_MAXSIZE(channel) > 0 &&
01346                      statbuf.st_size >= FILE_MAXSIZE(channel)))
01347                         roll = regular_file;
01348         } else if (errno == ENOENT) {
01349                 regular_file = ISC_TRUE;
01350                 POST(regular_file);
01351         } else
01352                 result = ISC_R_INVALIDFILE;
01353 
01354         /*
01355          * Version control.
01356          */
01357         if (result == ISC_R_SUCCESS && roll) {
01358                 if (FILE_VERSIONS(channel) == ISC_LOG_ROLLNEVER)
01359                         return (ISC_R_MAXSIZE);
01360                 result = roll_log(channel);
01361                 if (result != ISC_R_SUCCESS) {
01362                         if ((channel->flags & ISC_LOG_OPENERR) == 0) {
01363                                 syslog(LOG_ERR,
01364                                        "isc_log_open: roll_log '%s' "
01365                                        "failed: %s",
01366                                        FILE_NAME(channel),
01367                                        isc_result_totext(result));
01368                                 channel->flags |= ISC_LOG_OPENERR;
01369                         }
01370                         return (result);
01371                 }
01372         }
01373 
01374         result = isc_stdio_open(path, "a", &FILE_STREAM(channel));
01375 
01376         return (result);
01377 }
01378 
01379 isc_boolean_t
01380 isc_log_wouldlog(isc_log_t *lctx, int level) {
01381         /*
01382          * Try to avoid locking the mutex for messages which can't
01383          * possibly be logged to any channels -- primarily debugging
01384          * messages that the debug level is not high enough to print.
01385          *
01386          * If the level is (mathematically) less than or equal to the
01387          * highest_level, or if there is a dynamic channel and the level is
01388          * less than or equal to the debug level, the main loop must be
01389          * entered to see if the message should really be output.
01390          *
01391          * NOTE: this is UNLOCKED access to the logconfig.  However,
01392          * the worst thing that can happen is that a bad decision is made
01393          * about returning without logging, and that's not a big concern,
01394          * because that's a risk anyway if the logconfig is being
01395          * dynamically changed.
01396          */
01397 
01398         if (lctx == NULL || lctx->logconfig == NULL)
01399                 return (ISC_FALSE);
01400 
01401         return (ISC_TF(level <= lctx->logconfig->highest_level ||
01402                        (lctx->logconfig->dynamic &&
01403                         level <= lctx->debug_level)));
01404 }
01405 
01406 static void
01407 isc_log_doit(isc_log_t *lctx, isc_logcategory_t *category,
01408              isc_logmodule_t *module, int level, isc_boolean_t write_once,
01409              isc_msgcat_t *msgcat, int msgset, int msg,
01410              const char *format, va_list args)
01411 {
01412         int syslog_level;
01413         char time_string[64];
01414         char level_string[24];
01415         const char *iformat;
01416         struct stat statbuf;
01417         isc_boolean_t matched = ISC_FALSE;
01418         isc_boolean_t printtime, printtag, printcolon;
01419         isc_boolean_t printcategory, printmodule, printlevel, buffered;
01420         isc_logconfig_t *lcfg;
01421         isc_logchannel_t *channel;
01422         isc_logchannellist_t *category_channels;
01423         isc_result_t result;
01424 
01425         REQUIRE(lctx == NULL || VALID_CONTEXT(lctx));
01426         REQUIRE(category != NULL);
01427         REQUIRE(module != NULL);
01428         REQUIRE(level != ISC_LOG_DYNAMIC);
01429         REQUIRE(format != NULL);
01430 
01431         /*
01432          * Programs can use libraries that use this logging code without
01433          * wanting to do any logging, thus the log context is allowed to
01434          * be non-existent.
01435          */
01436         if (lctx == NULL)
01437                 return;
01438 
01439         REQUIRE(category->id < lctx->category_count);
01440         REQUIRE(module->id < lctx->module_count);
01441 
01442         if (! isc_log_wouldlog(lctx, level))
01443                 return;
01444 
01445         if (msgcat != NULL)
01446                 iformat = isc_msgcat_get(msgcat, msgset, msg, format);
01447         else
01448                 iformat = format;
01449 
01450         time_string[0]  = '\0';
01451         level_string[0] = '\0';
01452 
01453         LOCK(&lctx->lock);
01454 
01455         lctx->buffer[0] = '\0';
01456 
01457         lcfg = lctx->logconfig;
01458 
01459         category_channels = ISC_LIST_HEAD(lcfg->channellists[category->id]);
01460 
01461         /*
01462          * XXXDCL add duplicate filtering? (To not write multiple times to
01463          * the same source via various channels).
01464          */
01465         do {
01466                 /*
01467                  * If the channel list end was reached and a match was made,
01468                  * everything is finished.
01469                  */
01470                 if (category_channels == NULL && matched)
01471                         break;
01472 
01473                 if (category_channels == NULL && ! matched &&
01474                     category_channels != ISC_LIST_HEAD(lcfg->channellists[0]))
01475                         /*
01476                          * No category/module pair was explicitly configured.
01477                          * Try the category named "default".
01478                          */
01479                         category_channels =
01480                                 ISC_LIST_HEAD(lcfg->channellists[0]);
01481 
01482                 if (category_channels == NULL && ! matched)
01483                         /*
01484                          * No matching module was explicitly configured
01485                          * for the category named "default".  Use the internal
01486                          * default channel.
01487                          */
01488                         category_channels = &default_channel;
01489 
01490                 if (category_channels->module != NULL &&
01491                     category_channels->module != module) {
01492                         category_channels = ISC_LIST_NEXT(category_channels,
01493                                                           link);
01494                         continue;
01495                 }
01496 
01497                 matched = ISC_TRUE;
01498 
01499                 channel = category_channels->channel;
01500                 category_channels = ISC_LIST_NEXT(category_channels, link);
01501 
01502                 if (((channel->flags & ISC_LOG_DEBUGONLY) != 0) &&
01503                     lctx->debug_level == 0)
01504                         continue;
01505 
01506                 if (channel->level == ISC_LOG_DYNAMIC) {
01507                         if (lctx->debug_level < level)
01508                                 continue;
01509                 } else if (channel->level < level)
01510                         continue;
01511 
01512                 if ((channel->flags & ISC_LOG_PRINTTIME) != 0 &&
01513                     time_string[0] == '\0') {
01514                         isc_time_t isctime;
01515 
01516                         TIME_NOW(&isctime);
01517                         isc_time_formattimestamp(&isctime, time_string,
01518                                                  sizeof(time_string));
01519                 }
01520 
01521                 if ((channel->flags & ISC_LOG_PRINTLEVEL) != 0 &&
01522                     level_string[0] == '\0') {
01523                         if (level < ISC_LOG_CRITICAL)
01524                                 snprintf(level_string, sizeof(level_string),
01525                                          isc_msgcat_get(isc_msgcat,
01526                                                         ISC_MSGSET_LOG,
01527                                                         ISC_MSG_LEVEL,
01528                                                         "level %d: "),
01529                                          level);
01530                         else if (level > ISC_LOG_DYNAMIC)
01531                                 snprintf(level_string, sizeof(level_string),
01532                                          "%s %d: ", log_level_strings[0],
01533                                          level);
01534                         else
01535                                 snprintf(level_string, sizeof(level_string),
01536                                          "%s: ", log_level_strings[-level]);
01537                 }
01538 
01539                 /*
01540                  * Only format the message once.
01541                  */
01542                 if (lctx->buffer[0] == '\0') {
01543                         (void)vsnprintf(lctx->buffer, sizeof(lctx->buffer),
01544                                         iformat, args);
01545 
01546                         /*
01547                          * Check for duplicates.
01548                          */
01549                         if (write_once) {
01550                                 isc_logmessage_t *message, *new;
01551                                 isc_time_t oldest;
01552                                 isc_interval_t interval;
01553 
01554                                 isc_interval_set(&interval,
01555                                                  lcfg->duplicate_interval, 0);
01556 
01557                                 /*
01558                                  * 'oldest' is the age of the oldest messages
01559                                  * which fall within the duplicate_interval
01560                                  * range.
01561                                  */
01562                                 TIME_NOW(&oldest);
01563                                 if (isc_time_subtract(&oldest, &interval, &oldest)
01564                                     != ISC_R_SUCCESS)
01565                                         /*
01566                                          * Can't effectively do the checking
01567                                          * without having a valid time.
01568                                          */
01569                                         message = NULL;
01570                                 else
01571                                         message =ISC_LIST_HEAD(lctx->messages);
01572 
01573                                 while (message != NULL) {
01574                                         if (isc_time_compare(&message->time,
01575                                                              &oldest) < 0) {
01576                                                 /*
01577                                                  * This message is older
01578                                                  * than the duplicate_interval,
01579                                                  * so it should be dropped from
01580                                                  * the history.
01581                                                  *
01582                                                  * Setting the interval to be
01583                                                  * to be longer will obviously
01584                                                  * not cause the expired
01585                                                  * message to spring back into
01586                                                  * existence.
01587                                                  */
01588                                                 new = ISC_LIST_NEXT(message,
01589                                                                     link);
01590 
01591                                                 ISC_LIST_UNLINK(lctx->messages,
01592                                                                 message, link);
01593 
01594                                                 isc_mem_put(lctx->mctx,
01595                                                         message,
01596                                                         sizeof(*message) + 1 +
01597                                                         strlen(message->text));
01598 
01599                                                 message = new;
01600                                                 continue;
01601                                         }
01602 
01603                                         /*
01604                                          * This message is in the duplicate
01605                                          * filtering interval ...
01606                                          */
01607                                         if (strcmp(lctx->buffer, message->text)
01608                                             == 0) {
01609                                                 /*
01610                                                  * ... and it is a duplicate.
01611                                                  * Unlock the mutex and
01612                                                  * get the hell out of Dodge.
01613                                                  */
01614                                                 UNLOCK(&lctx->lock);
01615                                                 return;
01616                                         }
01617 
01618                                         message = ISC_LIST_NEXT(message, link);
01619                                 }
01620 
01621                                 /*
01622                                  * It wasn't in the duplicate interval,
01623                                  * so add it to the message list.
01624                                  */
01625                                 new = isc_mem_get(lctx->mctx,
01626                                                   sizeof(isc_logmessage_t) +
01627                                                   strlen(lctx->buffer) + 1);
01628                                 if (new != NULL) {
01629                                         /*
01630                                          * Put the text immediately after
01631                                          * the struct.  The strcpy is safe.
01632                                          */
01633                                         new->text = (char *)(new + 1);
01634                                         strcpy(new->text, lctx->buffer);
01635 
01636                                         TIME_NOW(&new->time);
01637 
01638                                         ISC_LINK_INIT(new, link);
01639                                         ISC_LIST_APPEND(lctx->messages,
01640                                                         new, link);
01641                                 }
01642                         }
01643                 }
01644 
01645                 printtime     = ISC_TF((channel->flags & ISC_LOG_PRINTTIME)
01646                                        != 0);
01647                 printtag      = ISC_TF((channel->flags &
01648                                         (ISC_LOG_PRINTTAG|ISC_LOG_PRINTPREFIX))
01649                                        != 0 && lcfg->tag != NULL);
01650                 printcolon    = ISC_TF((channel->flags & ISC_LOG_PRINTTAG)
01651                                        != 0 && lcfg->tag != NULL);
01652                 printcategory = ISC_TF((channel->flags & ISC_LOG_PRINTCATEGORY)
01653                                        != 0);
01654                 printmodule   = ISC_TF((channel->flags & ISC_LOG_PRINTMODULE)
01655                                        != 0);
01656                 printlevel    = ISC_TF((channel->flags & ISC_LOG_PRINTLEVEL)
01657                                        != 0);
01658                 buffered      = ISC_TF((channel->flags & ISC_LOG_BUFFERED)
01659                                        != 0);
01660 
01661                 switch (channel->type) {
01662                 case ISC_LOG_TOFILE:
01663                         if (FILE_MAXREACHED(channel)) {
01664                                 /*
01665                                  * If the file can be rolled, OR
01666                                  * If the file no longer exists, OR
01667                                  * If the file is less than the maximum size,
01668                                  *    (such as if it had been renamed and
01669                                  *     a new one touched, or it was truncated
01670                                  *     in place)
01671                                  * ... then close it to trigger reopening.
01672                                  */
01673                                 if (FILE_VERSIONS(channel) !=
01674                                     ISC_LOG_ROLLNEVER ||
01675                                     (stat(FILE_NAME(channel), &statbuf) != 0 &&
01676                                      errno == ENOENT) ||
01677                                     statbuf.st_size < FILE_MAXSIZE(channel)) {
01678                                         (void)fclose(FILE_STREAM(channel));
01679                                         FILE_STREAM(channel) = NULL;
01680                                         FILE_MAXREACHED(channel) = ISC_FALSE;
01681                                 } else
01682                                         /*
01683                                          * Eh, skip it.
01684                                          */
01685                                         break;
01686                         }
01687 
01688                         if (FILE_STREAM(channel) == NULL) {
01689                                 result = isc_log_open(channel);
01690                                 if (result != ISC_R_SUCCESS &&
01691                                     result != ISC_R_MAXSIZE &&
01692                                     (channel->flags & ISC_LOG_OPENERR) == 0) {
01693                                         syslog(LOG_ERR,
01694                                                "isc_log_open '%s' failed: %s",
01695                                                FILE_NAME(channel),
01696                                                isc_result_totext(result));
01697                                         channel->flags |= ISC_LOG_OPENERR;
01698                                 }
01699                                 if (result != ISC_R_SUCCESS)
01700                                         break;
01701                                 channel->flags &= ~ISC_LOG_OPENERR;
01702                         }
01703                         /* FALLTHROUGH */
01704 
01705                 case ISC_LOG_TOFILEDESC:
01706                         fprintf(FILE_STREAM(channel),
01707                                 "%s%s%s%s%s%s%s%s%s%s\n",
01708                                 printtime     ? time_string     : "",
01709                                 printtime     ? " "             : "",
01710                                 printtag      ? lcfg->tag       : "",
01711                                 printcolon    ? ": "            : "",
01712                                 printcategory ? category->name  : "",
01713                                 printcategory ? ": "            : "",
01714                                 printmodule   ? (module != NULL ? module->name
01715                                                                 : "no_module")
01716                                                                 : "",
01717                                 printmodule   ? ": "            : "",
01718                                 printlevel    ? level_string    : "",
01719                                 lctx->buffer);
01720 
01721                         if (!buffered)
01722                                 fflush(FILE_STREAM(channel));
01723 
01724                         /*
01725                          * If the file now exceeds its maximum size
01726                          * threshold, note it so that it will not be logged
01727                          * to any more.
01728                          */
01729                         if (FILE_MAXSIZE(channel) > 0) {
01730                                 INSIST(channel->type == ISC_LOG_TOFILE);
01731 
01732                                 /* XXXDCL NT fstat/fileno */
01733                                 /* XXXDCL complain if fstat fails? */
01734                                 if (fstat(fileno(FILE_STREAM(channel)),
01735                                           &statbuf) >= 0 &&
01736                                     statbuf.st_size > FILE_MAXSIZE(channel))
01737                                         FILE_MAXREACHED(channel) = ISC_TRUE;
01738                         }
01739 
01740                         break;
01741 
01742                 case ISC_LOG_TOSYSLOG:
01743                         if (level > 0)
01744                                 syslog_level = LOG_DEBUG;
01745                         else if (level < ISC_LOG_CRITICAL)
01746                                 syslog_level = LOG_CRIT;
01747                         else
01748                                 syslog_level = syslog_map[-level];
01749 
01750                         (void)syslog(FACILITY(channel) | syslog_level,
01751                                "%s%s%s%s%s%s%s%s%s%s",
01752                                printtime     ? time_string      : "",
01753                                printtime     ? " "              : "",
01754                                printtag      ? lcfg->tag        : "",
01755                                printcolon    ? ": "             : "",
01756                                printcategory ? category->name   : "",
01757                                printcategory ? ": "             : "",
01758                                printmodule   ? (module != NULL
01759                                                  ? module->name
01760                                                  : "no_module")
01761                                                                 : "",
01762                                printmodule   ? ": "             : "",
01763                                printlevel    ? level_string     : "",
01764                                lctx->buffer);
01765                         break;
01766 
01767                 case ISC_LOG_TONULL:
01768                         break;
01769 
01770                 }
01771 
01772         } while (1);
01773 
01774         UNLOCK(&lctx->lock);
01775 }

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