summaryrefslogtreecommitdiffstats
path: root/contrib/bind9/lib/isc/log.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/bind9/lib/isc/log.c')
-rw-r--r--contrib/bind9/lib/isc/log.c1761
1 files changed, 0 insertions, 1761 deletions
diff --git a/contrib/bind9/lib/isc/log.c b/contrib/bind9/lib/isc/log.c
deleted file mode 100644
index 27c01d1..0000000
--- a/contrib/bind9/lib/isc/log.c
+++ /dev/null
@@ -1,1761 +0,0 @@
-/*
- * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC")
- * Copyright (C) 1999-2003 Internet Software Consortium.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
- * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
-
-/* $Id: log.c,v 1.84.18.8 2006/03/02 00:37:22 marka Exp $ */
-
-/*! \file
- * \author Principal Authors: DCL */
-
-#include <config.h>
-
-#include <errno.h>
-#include <stdlib.h>
-#include <limits.h>
-#include <time.h>
-
-#include <sys/types.h> /* dev_t FreeBSD 2.1 */
-
-#include <isc/dir.h>
-#include <isc/file.h>
-#include <isc/log.h>
-#include <isc/magic.h>
-#include <isc/mem.h>
-#include <isc/msgs.h>
-#include <isc/print.h>
-#include <isc/stat.h>
-#include <isc/stdio.h>
-#include <isc/string.h>
-#include <isc/time.h>
-#include <isc/util.h>
-
-#define LCTX_MAGIC ISC_MAGIC('L', 'c', 't', 'x')
-#define VALID_CONTEXT(lctx) ISC_MAGIC_VALID(lctx, LCTX_MAGIC)
-
-#define LCFG_MAGIC ISC_MAGIC('L', 'c', 'f', 'g')
-#define VALID_CONFIG(lcfg) ISC_MAGIC_VALID(lcfg, LCFG_MAGIC)
-
-/*
- * XXXDCL make dynamic?
- */
-#define LOG_BUFFER_SIZE (8 * 1024)
-
-#ifndef PATH_MAX
-#define PATH_MAX 1024 /* AIX and others don't define this. */
-#endif
-
-/*!
- * This is the structure that holds each named channel. A simple linked
- * list chains all of the channels together, so an individual channel is
- * found by doing strcmp()s with the names down the list. Their should
- * be no peformance penalty from this as it is expected that the number
- * of named channels will be no more than a dozen or so, and name lookups
- * from the head of the list are only done when isc_log_usechannel() is
- * called, which should also be very infrequent.
- */
-typedef struct isc_logchannel isc_logchannel_t;
-
-struct isc_logchannel {
- char * name;
- unsigned int type;
- int level;
- unsigned int flags;
- isc_logdestination_t destination;
- ISC_LINK(isc_logchannel_t) link;
-};
-
-/*!
- * The logchannellist structure associates categories and modules with
- * channels. First the appropriate channellist is found based on the
- * category, and then each structure in the linked list is checked for
- * a matching module. It is expected that the number of channels
- * associated with any given category will be very short, no more than
- * three or four in the more unusual cases.
- */
-typedef struct isc_logchannellist isc_logchannellist_t;
-
-struct isc_logchannellist {
- const isc_logmodule_t * module;
- isc_logchannel_t * channel;
- ISC_LINK(isc_logchannellist_t) link;
-};
-
-/*!
- * This structure is used to remember messages for pruning via
- * isc_log_[v]write1().
- */
-typedef struct isc_logmessage isc_logmessage_t;
-
-struct isc_logmessage {
- char * text;
- isc_time_t time;
- ISC_LINK(isc_logmessage_t) link;
-};
-
-/*!
- * The isc_logconfig structure is used to store the configurable information
- * about where messages are actually supposed to be sent -- the information
- * that could changed based on some configuration file, as opposed to the
- * the category/module specification of isc_log_[v]write[1] that is compiled
- * into a program, or the debug_level which is dynamic state information.
- */
-struct isc_logconfig {
- unsigned int magic;
- isc_log_t * lctx;
- ISC_LIST(isc_logchannel_t) channels;
- ISC_LIST(isc_logchannellist_t) *channellists;
- unsigned int channellist_count;
- unsigned int duplicate_interval;
- int highest_level;
- char * tag;
- isc_boolean_t dynamic;
-};
-
-/*!
- * This isc_log structure provides the context for the isc_log functions.
- * The log context locks itself in isc_log_doit, the internal backend to
- * isc_log_write. The locking is necessary both to provide exclusive access
- * to the the buffer into which the message is formatted and to guard against
- * competing threads trying to write to the same syslog resource. (On
- * some systems, such as BSD/OS, stdio is thread safe but syslog is not.)
- * Unfortunately, the lock cannot guard against a _different_ logging
- * context in the same program competing for syslog's attention. Thus
- * There Can Be Only One, but this is not enforced.
- * XXXDCL enforce it?
- *
- * Note that the category and module information is not locked.
- * This is because in the usual case, only one isc_log_t is ever created
- * in a program, and the category/module registration happens only once.
- * XXXDCL it might be wise to add more locking overall.
- */
-struct isc_log {
- /* Not locked. */
- unsigned int magic;
- isc_mem_t * mctx;
- isc_logcategory_t * categories;
- unsigned int category_count;
- isc_logmodule_t * modules;
- unsigned int module_count;
- int debug_level;
- isc_mutex_t lock;
- /* Locked by isc_log lock. */
- isc_logconfig_t * logconfig;
- char buffer[LOG_BUFFER_SIZE];
- ISC_LIST(isc_logmessage_t) messages;
-};
-
-/*!
- * Used when ISC_LOG_PRINTLEVEL is enabled for a channel.
- */
-static const char *log_level_strings[] = {
- "debug",
- "info",
- "notice",
- "warning",
- "error",
- "critical"
-};
-
-/*!
- * Used to convert ISC_LOG_* priorities into syslog priorities.
- * XXXDCL This will need modification for NT.
- */
-static const int syslog_map[] = {
- LOG_DEBUG,
- LOG_INFO,
- LOG_NOTICE,
- LOG_WARNING,
- LOG_ERR,
- LOG_CRIT
-};
-
-/*!
- * When adding new categories, a corresponding ISC_LOGCATEGORY_foo
- * definition needs to be added to <isc/log.h>.
- *
- * The default category is provided so that the internal default can
- * be overridden. Since the default is always looked up as the first
- * channellist in the log context, it must come first in isc_categories[].
- */
-LIBISC_EXTERNAL_DATA isc_logcategory_t isc_categories[] = {
- { "default", 0 }, /* "default" must come first. */
- { "general", 0 },
- { NULL, 0 }
-};
-
-/*!
- * See above comment for categories on LIBISC_EXTERNAL_DATA, and apply it to modules.
- */
-LIBISC_EXTERNAL_DATA isc_logmodule_t isc_modules[] = {
- { "socket", 0 },
- { "time", 0 },
- { "interface", 0 },
- { "timer", 0 },
- { NULL, 0 }
-};
-
-/*!
- * This essentially constant structure must be filled in at run time,
- * because its channel member is pointed to a channel that is created
- * dynamically with isc_log_createchannel.
- */
-static isc_logchannellist_t default_channel;
-
-/*!
- * libisc logs to this context.
- */
-LIBISC_EXTERNAL_DATA isc_log_t *isc_lctx = NULL;
-
-/*!
- * Forward declarations.
- */
-static isc_result_t
-assignchannel(isc_logconfig_t *lcfg, unsigned int category_id,
- const isc_logmodule_t *module, isc_logchannel_t *channel);
-
-static isc_result_t
-sync_channellist(isc_logconfig_t *lcfg);
-
-static isc_result_t
-greatest_version(isc_logchannel_t *channel, int *greatest);
-
-static isc_result_t
-roll_log(isc_logchannel_t *channel);
-
-static void
-isc_log_doit(isc_log_t *lctx, isc_logcategory_t *category,
- isc_logmodule_t *module, int level, isc_boolean_t write_once,
- isc_msgcat_t *msgcat, int msgset, int msg,
- const char *format, va_list args)
- ISC_FORMAT_PRINTF(9, 0);
-
-/*@{*/
-/*!
- * Convenience macros.
- */
-
-#define FACILITY(channel) (channel->destination.facility)
-#define FILE_NAME(channel) (channel->destination.file.name)
-#define FILE_STREAM(channel) (channel->destination.file.stream)
-#define FILE_VERSIONS(channel) (channel->destination.file.versions)
-#define FILE_MAXSIZE(channel) (channel->destination.file.maximum_size)
-#define FILE_MAXREACHED(channel) (channel->destination.file.maximum_reached)
-
-/*@}*/
-/****
- **** Public interfaces.
- ****/
-
-/*
- * Establish a new logging context, with default channels.
- */
-isc_result_t
-isc_log_create(isc_mem_t *mctx, isc_log_t **lctxp, isc_logconfig_t **lcfgp) {
- isc_log_t *lctx;
- isc_logconfig_t *lcfg = NULL;
- isc_result_t result;
-
- REQUIRE(mctx != NULL);
- REQUIRE(lctxp != NULL && *lctxp == NULL);
- REQUIRE(lcfgp == NULL || *lcfgp == NULL);
-
- lctx = isc_mem_get(mctx, sizeof(*lctx));
- if (lctx != NULL) {
- lctx->mctx = mctx;
- lctx->categories = NULL;
- lctx->category_count = 0;
- lctx->modules = NULL;
- lctx->module_count = 0;
- lctx->debug_level = 0;
-
- ISC_LIST_INIT(lctx->messages);
-
- result = isc_mutex_init(&lctx->lock);
- if (result != ISC_R_SUCCESS) {
- isc_mem_put(mctx, lctx, sizeof(*lctx));
- return (result);
- }
-
- /*
- * Normally setting the magic number is the last step done
- * in a creation function, but a valid log context is needed
- * by isc_log_registercategories and isc_logconfig_create.
- * If either fails, the lctx is destroyed and not returned
- * to the caller.
- */
- lctx->magic = LCTX_MAGIC;
-
- isc_log_registercategories(lctx, isc_categories);
- isc_log_registermodules(lctx, isc_modules);
- result = isc_logconfig_create(lctx, &lcfg);
-
- } else
- result = ISC_R_NOMEMORY;
-
- if (result == ISC_R_SUCCESS)
- result = sync_channellist(lcfg);
-
- if (result == ISC_R_SUCCESS) {
- lctx->logconfig = lcfg;
-
- *lctxp = lctx;
- if (lcfgp != NULL)
- *lcfgp = lcfg;
-
- } else {
- if (lcfg != NULL)
- isc_logconfig_destroy(&lcfg);
- if (lctx != NULL)
- isc_log_destroy(&lctx);
- }
-
- return (result);
-}
-
-isc_result_t
-isc_logconfig_create(isc_log_t *lctx, isc_logconfig_t **lcfgp) {
- isc_logconfig_t *lcfg;
- isc_logdestination_t destination;
- isc_result_t result = ISC_R_SUCCESS;
- int level = ISC_LOG_INFO;
-
- REQUIRE(lcfgp != NULL && *lcfgp == NULL);
- REQUIRE(VALID_CONTEXT(lctx));
-
- lcfg = isc_mem_get(lctx->mctx, sizeof(*lcfg));
-
- if (lcfg != NULL) {
- lcfg->lctx = lctx;
- lcfg->channellists = NULL;
- lcfg->channellist_count = 0;
- lcfg->duplicate_interval = 0;
- lcfg->highest_level = level;
- lcfg->tag = NULL;
- lcfg->dynamic = ISC_FALSE;
-
- ISC_LIST_INIT(lcfg->channels);
-
- /*
- * Normally the magic number is the last thing set in the
- * structure, but isc_log_createchannel() needs a valid
- * config. If the channel creation fails, the lcfg is not
- * returned to the caller.
- */
- lcfg->magic = LCFG_MAGIC;
-
- } else
- result = ISC_R_NOMEMORY;
-
- /*
- * Create the default channels:
- * default_syslog, default_stderr, default_debug and null.
- */
- if (result == ISC_R_SUCCESS) {
- destination.facility = LOG_DAEMON;
- result = isc_log_createchannel(lcfg, "default_syslog",
- ISC_LOG_TOSYSLOG, level,
- &destination, 0);
- }
-
- if (result == ISC_R_SUCCESS) {
- destination.file.stream = stderr;
- destination.file.name = NULL;
- destination.file.versions = ISC_LOG_ROLLNEVER;
- destination.file.maximum_size = 0;
- result = isc_log_createchannel(lcfg, "default_stderr",
- ISC_LOG_TOFILEDESC,
- level,
- &destination,
- ISC_LOG_PRINTTIME);
- }
-
- if (result == ISC_R_SUCCESS) {
- /*
- * Set the default category's channel to default_stderr,
- * which is at the head of the channels list because it was
- * just created.
- */
- default_channel.channel = ISC_LIST_HEAD(lcfg->channels);
-
- destination.file.stream = stderr;
- destination.file.name = NULL;
- destination.file.versions = ISC_LOG_ROLLNEVER;
- destination.file.maximum_size = 0;
- result = isc_log_createchannel(lcfg, "default_debug",
- ISC_LOG_TOFILEDESC,
- ISC_LOG_DYNAMIC,
- &destination,
- ISC_LOG_PRINTTIME);
- }
-
- if (result == ISC_R_SUCCESS)
- result = isc_log_createchannel(lcfg, "null",
- ISC_LOG_TONULL,
- ISC_LOG_DYNAMIC,
- NULL, 0);
-
- if (result == ISC_R_SUCCESS)
- *lcfgp = lcfg;
-
- else
- if (lcfg != NULL)
- isc_logconfig_destroy(&lcfg);
-
- return (result);
-}
-
-isc_logconfig_t *
-isc_logconfig_get(isc_log_t *lctx) {
- REQUIRE(VALID_CONTEXT(lctx));
-
- ENSURE(lctx->logconfig != NULL);
-
- return (lctx->logconfig);
-}
-
-isc_result_t
-isc_logconfig_use(isc_log_t *lctx, isc_logconfig_t *lcfg) {
- isc_logconfig_t *old_cfg;
- isc_result_t result;
-
- REQUIRE(VALID_CONTEXT(lctx));
- REQUIRE(VALID_CONFIG(lcfg));
- REQUIRE(lcfg->lctx == lctx);
-
- /*
- * Ensure that lcfg->channellist_count == lctx->category_count.
- * They won't be equal if isc_log_usechannel has not been called
- * since any call to isc_log_registercategories.
- */
- result = sync_channellist(lcfg);
- if (result != ISC_R_SUCCESS)
- return (result);
-
- LOCK(&lctx->lock);
-
- old_cfg = lctx->logconfig;
- lctx->logconfig = lcfg;
-
- UNLOCK(&lctx->lock);
-
- isc_logconfig_destroy(&old_cfg);
-
- return (ISC_R_SUCCESS);
-}
-
-void
-isc_log_destroy(isc_log_t **lctxp) {
- isc_log_t *lctx;
- isc_logconfig_t *lcfg;
- isc_mem_t *mctx;
- isc_logmessage_t *message;
-
- REQUIRE(lctxp != NULL && VALID_CONTEXT(*lctxp));
-
- lctx = *lctxp;
- mctx = lctx->mctx;
-
- if (lctx->logconfig != NULL) {
- lcfg = lctx->logconfig;
- lctx->logconfig = NULL;
- isc_logconfig_destroy(&lcfg);
- }
-
- DESTROYLOCK(&lctx->lock);
-
- while ((message = ISC_LIST_HEAD(lctx->messages)) != NULL) {
- ISC_LIST_UNLINK(lctx->messages, message, link);
-
- isc_mem_put(mctx, message,
- sizeof(*message) + strlen(message->text) + 1);
- }
-
- lctx->buffer[0] = '\0';
- lctx->debug_level = 0;
- lctx->categories = NULL;
- lctx->category_count = 0;
- lctx->modules = NULL;
- lctx->module_count = 0;
- lctx->mctx = NULL;
- lctx->magic = 0;
-
- isc_mem_put(mctx, lctx, sizeof(*lctx));
-
- *lctxp = NULL;
-}
-
-void
-isc_logconfig_destroy(isc_logconfig_t **lcfgp) {
- isc_logconfig_t *lcfg;
- isc_mem_t *mctx;
- isc_logchannel_t *channel;
- isc_logchannellist_t *item;
- char *filename;
- unsigned int i;
-
- REQUIRE(lcfgp != NULL && VALID_CONFIG(*lcfgp));
-
- lcfg = *lcfgp;
-
- /*
- * This function cannot be called with a logconfig that is in
- * use by a log context.
- */
- REQUIRE(lcfg->lctx != NULL && lcfg->lctx->logconfig != lcfg);
-
- mctx = lcfg->lctx->mctx;
-
- while ((channel = ISC_LIST_HEAD(lcfg->channels)) != NULL) {
- ISC_LIST_UNLINK(lcfg->channels, channel, link);
-
- if (channel->type == ISC_LOG_TOFILE) {
- /*
- * The filename for the channel may have ultimately
- * started its life in user-land as a const string,
- * but in isc_log_createchannel it gets copied
- * into writable memory and is not longer truly const.
- */
- DE_CONST(FILE_NAME(channel), filename);
- isc_mem_free(mctx, filename);
-
- if (FILE_STREAM(channel) != NULL)
- (void)fclose(FILE_STREAM(channel));
- }
-
- isc_mem_free(mctx, channel->name);
- isc_mem_put(mctx, channel, sizeof(*channel));
- }
-
- for (i = 0; i < lcfg->channellist_count; i++)
- while ((item = ISC_LIST_HEAD(lcfg->channellists[i])) != NULL) {
- ISC_LIST_UNLINK(lcfg->channellists[i], item, link);
- isc_mem_put(mctx, item, sizeof(*item));
- }
-
- if (lcfg->channellist_count > 0)
- isc_mem_put(mctx, lcfg->channellists,
- lcfg->channellist_count *
- sizeof(ISC_LIST(isc_logchannellist_t)));
-
- lcfg->dynamic = ISC_FALSE;
- if (lcfg->tag != NULL)
- isc_mem_free(lcfg->lctx->mctx, lcfg->tag);
- lcfg->tag = NULL;
- lcfg->highest_level = 0;
- lcfg->duplicate_interval = 0;
- lcfg->magic = 0;
-
- isc_mem_put(mctx, lcfg, sizeof(*lcfg));
-
- *lcfgp = NULL;
-}
-
-void
-isc_log_registercategories(isc_log_t *lctx, isc_logcategory_t categories[]) {
- isc_logcategory_t *catp;
-
- REQUIRE(VALID_CONTEXT(lctx));
- REQUIRE(categories != NULL && categories[0].name != NULL);
-
- /*
- * XXXDCL This somewhat sleazy situation of using the last pointer
- * in one category array to point to the next array exists because
- * this registration function returns void and I didn't want to have
- * change everything that used it by making it return an isc_result_t.
- * It would need to do that if it had to allocate memory to store
- * pointers to each array passed in.
- */
- if (lctx->categories == NULL)
- lctx->categories = categories;
-
- else {
- /*
- * Adjust the last (NULL) pointer of the already registered
- * categories to point to the incoming array.
- */
- for (catp = lctx->categories; catp->name != NULL; )
- if (catp->id == UINT_MAX)
- /*
- * The name pointer points to the next array.
- * Ick.
- */
- DE_CONST(catp->name, catp);
- else
- catp++;
-
- catp->name = (void *)categories;
- catp->id = UINT_MAX;
- }
-
- /*
- * Update the id number of the category with its new global id.
- */
- for (catp = categories; catp->name != NULL; catp++)
- catp->id = lctx->category_count++;
-}
-
-isc_logcategory_t *
-isc_log_categorybyname(isc_log_t *lctx, const char *name) {
- isc_logcategory_t *catp;
-
- REQUIRE(VALID_CONTEXT(lctx));
- REQUIRE(name != NULL);
-
- for (catp = lctx->categories; catp->name != NULL; )
- if (catp->id == UINT_MAX)
- /*
- * catp is neither modified nor returned to the
- * caller, so removing its const qualifier is ok.
- */
- DE_CONST(catp->name, catp);
- else {
- if (strcmp(catp->name, name) == 0)
- return (catp);
- catp++;
- }
-
- return (NULL);
-}
-
-void
-isc_log_registermodules(isc_log_t *lctx, isc_logmodule_t modules[]) {
- isc_logmodule_t *modp;
-
- REQUIRE(VALID_CONTEXT(lctx));
- REQUIRE(modules != NULL && modules[0].name != NULL);
-
- /*
- * XXXDCL This somewhat sleazy situation of using the last pointer
- * in one category array to point to the next array exists because
- * this registration function returns void and I didn't want to have
- * change everything that used it by making it return an isc_result_t.
- * It would need to do that if it had to allocate memory to store
- * pointers to each array passed in.
- */
- if (lctx->modules == NULL)
- lctx->modules = modules;
-
- else {
- /*
- * Adjust the last (NULL) pointer of the already registered
- * modules to point to the incoming array.
- */
- for (modp = lctx->modules; modp->name != NULL; )
- if (modp->id == UINT_MAX)
- /*
- * The name pointer points to the next array.
- * Ick.
- */
- DE_CONST(modp->name, modp);
- else
- modp++;
-
- modp->name = (void *)modules;
- modp->id = UINT_MAX;
- }
-
- /*
- * Update the id number of the module with its new global id.
- */
- for (modp = modules; modp->name != NULL; modp++)
- modp->id = lctx->module_count++;
-}
-
-isc_logmodule_t *
-isc_log_modulebyname(isc_log_t *lctx, const char *name) {
- isc_logmodule_t *modp;
-
- REQUIRE(VALID_CONTEXT(lctx));
- REQUIRE(name != NULL);
-
- for (modp = lctx->modules; modp->name != NULL; )
- if (modp->id == UINT_MAX)
- /*
- * modp is neither modified nor returned to the
- * caller, so removing its const qualifier is ok.
- */
- DE_CONST(modp->name, modp);
- else {
- if (strcmp(modp->name, name) == 0)
- return (modp);
- modp++;
- }
-
- return (NULL);
-}
-
-isc_result_t
-isc_log_createchannel(isc_logconfig_t *lcfg, const char *name,
- unsigned int type, int level,
- const isc_logdestination_t *destination,
- unsigned int flags)
-{
- isc_logchannel_t *channel;
- isc_mem_t *mctx;
-
- REQUIRE(VALID_CONFIG(lcfg));
- REQUIRE(name != NULL);
- REQUIRE(type == ISC_LOG_TOSYSLOG || type == ISC_LOG_TOFILE ||
- type == ISC_LOG_TOFILEDESC || type == ISC_LOG_TONULL);
- REQUIRE(destination != NULL || type == ISC_LOG_TONULL);
- REQUIRE(level >= ISC_LOG_CRITICAL);
- REQUIRE((flags &
- (unsigned int)~(ISC_LOG_PRINTALL | ISC_LOG_DEBUGONLY)) == 0);
-
- /* XXXDCL find duplicate names? */
-
- mctx = lcfg->lctx->mctx;
-
- channel = isc_mem_get(mctx, sizeof(*channel));
- if (channel == NULL)
- return (ISC_R_NOMEMORY);
-
- channel->name = isc_mem_strdup(mctx, name);
- if (channel->name == NULL) {
- isc_mem_put(mctx, channel, sizeof(*channel));
- return (ISC_R_NOMEMORY);
- }
-
- channel->type = type;
- channel->level = level;
- channel->flags = flags;
- ISC_LINK_INIT(channel, link);
-
- switch (type) {
- case ISC_LOG_TOSYSLOG:
- FACILITY(channel) = destination->facility;
- break;
-
- case ISC_LOG_TOFILE:
- /*
- * The file name is copied because greatest_version wants
- * to scribble on it, so it needs to be definitely in
- * writable memory.
- */
- FILE_NAME(channel) =
- isc_mem_strdup(mctx, destination->file.name);
- FILE_STREAM(channel) = NULL;
- FILE_VERSIONS(channel) = destination->file.versions;
- FILE_MAXSIZE(channel) = destination->file.maximum_size;
- FILE_MAXREACHED(channel) = ISC_FALSE;
- break;
-
- case ISC_LOG_TOFILEDESC:
- FILE_NAME(channel) = NULL;
- FILE_STREAM(channel) = destination->file.stream;
- FILE_MAXSIZE(channel) = 0;
- FILE_VERSIONS(channel) = ISC_LOG_ROLLNEVER;
- break;
-
- case ISC_LOG_TONULL:
- /* Nothing. */
- break;
-
- default:
- isc_mem_put(mctx, channel->name, strlen(channel->name) + 1);
- isc_mem_put(mctx, channel, sizeof(*channel));
- return (ISC_R_UNEXPECTED);
- }
-
- ISC_LIST_PREPEND(lcfg->channels, channel, link);
-
- /*
- * If default_stderr was redefined, make the default category
- * point to the new default_stderr.
- */
- if (strcmp(name, "default_stderr") == 0)
- default_channel.channel = channel;
-
- return (ISC_R_SUCCESS);
-}
-
-isc_result_t
-isc_log_usechannel(isc_logconfig_t *lcfg, const char *name,
- const isc_logcategory_t *category,
- const isc_logmodule_t *module)
-{
- isc_log_t *lctx;
- isc_logchannel_t *channel;
- isc_result_t result = ISC_R_SUCCESS;
- unsigned int i;
-
- REQUIRE(VALID_CONFIG(lcfg));
- REQUIRE(name != NULL);
-
- lctx = lcfg->lctx;
-
- REQUIRE(category == NULL || category->id < lctx->category_count);
- REQUIRE(module == NULL || module->id < lctx->module_count);
-
- for (channel = ISC_LIST_HEAD(lcfg->channels); channel != NULL;
- channel = ISC_LIST_NEXT(channel, link))
- if (strcmp(name, channel->name) == 0)
- break;
-
- if (channel == NULL)
- return (ISC_R_NOTFOUND);
-
- if (category != NULL)
- result = assignchannel(lcfg, category->id, module, channel);
-
- else
- /*
- * Assign to all categories. Note that this includes
- * the default channel.
- */
- for (i = 0; i < lctx->category_count; i++) {
- result = assignchannel(lcfg, i, module, channel);
- if (result != ISC_R_SUCCESS)
- break;
- }
-
- return (result);
-}
-
-void
-isc_log_write(isc_log_t *lctx, isc_logcategory_t *category,
- isc_logmodule_t *module, int level, const char *format, ...)
-{
- va_list args;
-
- /*
- * Contract checking is done in isc_log_doit().
- */
-
- va_start(args, format);
- isc_log_doit(lctx, category, module, level, ISC_FALSE,
- NULL, 0, 0, format, args);
- va_end(args);
-}
-
-void
-isc_log_vwrite(isc_log_t *lctx, isc_logcategory_t *category,
- isc_logmodule_t *module, int level,
- const char *format, va_list args)
-{
- /*
- * Contract checking is done in isc_log_doit().
- */
- isc_log_doit(lctx, category, module, level, ISC_FALSE,
- NULL, 0, 0, format, args);
-}
-
-void
-isc_log_write1(isc_log_t *lctx, isc_logcategory_t *category,
- isc_logmodule_t *module, int level, const char *format, ...)
-{
- va_list args;
-
- /*
- * Contract checking is done in isc_log_doit().
- */
-
- va_start(args, format);
- isc_log_doit(lctx, category, module, level, ISC_TRUE,
- NULL, 0, 0, format, args);
- va_end(args);
-}
-
-void
-isc_log_vwrite1(isc_log_t *lctx, isc_logcategory_t *category,
- isc_logmodule_t *module, int level,
- const char *format, va_list args)
-{
- /*
- * Contract checking is done in isc_log_doit().
- */
- isc_log_doit(lctx, category, module, level, ISC_TRUE,
- NULL, 0, 0, format, args);
-}
-
-void
-isc_log_iwrite(isc_log_t *lctx, isc_logcategory_t *category,
- isc_logmodule_t *module, int level,
- isc_msgcat_t *msgcat, int msgset, int msg,
- const char *format, ...)
-{
- va_list args;
-
- /*
- * Contract checking is done in isc_log_doit().
- */
-
- va_start(args, format);
- isc_log_doit(lctx, category, module, level, ISC_FALSE,
- msgcat, msgset, msg, format, args);
- va_end(args);
-}
-
-void
-isc_log_ivwrite(isc_log_t *lctx, isc_logcategory_t *category,
- isc_logmodule_t *module, int level,
- isc_msgcat_t *msgcat, int msgset, int msg,
- const char *format, va_list args)
-{
- /*
- * Contract checking is done in isc_log_doit().
- */
- isc_log_doit(lctx, category, module, level, ISC_FALSE,
- msgcat, msgset, msg, format, args);
-}
-
-void
-isc_log_iwrite1(isc_log_t *lctx, isc_logcategory_t *category,
- isc_logmodule_t *module, int level,
- isc_msgcat_t *msgcat, int msgset, int msg,
- const char *format, ...)
-{
- va_list args;
-
- /*
- * Contract checking is done in isc_log_doit().
- */
-
- va_start(args, format);
- isc_log_doit(lctx, category, module, level, ISC_TRUE,
- msgcat, msgset, msg, format, args);
- va_end(args);
-}
-
-void
-isc_log_ivwrite1(isc_log_t *lctx, isc_logcategory_t *category,
- isc_logmodule_t *module, int level,
- isc_msgcat_t *msgcat, int msgset, int msg,
- const char *format, va_list args)
-{
- /*
- * Contract checking is done in isc_log_doit().
- */
- isc_log_doit(lctx, category, module, level, ISC_TRUE,
- msgcat, msgset, msg, format, args);
-}
-
-void
-isc_log_setcontext(isc_log_t *lctx) {
- isc_lctx = lctx;
-}
-
-void
-isc_log_setdebuglevel(isc_log_t *lctx, unsigned int level) {
- isc_logchannel_t *channel;
-
- REQUIRE(VALID_CONTEXT(lctx));
-
- LOCK(&lctx->lock);
-
- lctx->debug_level = level;
- /*
- * Close ISC_LOG_DEBUGONLY channels if level is zero.
- */
- if (lctx->debug_level == 0)
- for (channel = ISC_LIST_HEAD(lctx->logconfig->channels);
- channel != NULL;
- channel = ISC_LIST_NEXT(channel, link))
- if (channel->type == ISC_LOG_TOFILE &&
- (channel->flags & ISC_LOG_DEBUGONLY) != 0 &&
- FILE_STREAM(channel) != NULL) {
- (void)fclose(FILE_STREAM(channel));
- FILE_STREAM(channel) = NULL;
- }
- UNLOCK(&lctx->lock);
-}
-
-unsigned int
-isc_log_getdebuglevel(isc_log_t *lctx) {
- REQUIRE(VALID_CONTEXT(lctx));
-
- return (lctx->debug_level);
-}
-
-void
-isc_log_setduplicateinterval(isc_logconfig_t *lcfg, unsigned int interval) {
- REQUIRE(VALID_CONFIG(lcfg));
-
- lcfg->duplicate_interval = interval;
-}
-
-unsigned int
-isc_log_getduplicateinterval(isc_logconfig_t *lcfg) {
- REQUIRE(VALID_CONTEXT(lcfg));
-
- return (lcfg->duplicate_interval);
-}
-
-isc_result_t
-isc_log_settag(isc_logconfig_t *lcfg, const char *tag) {
- REQUIRE(VALID_CONFIG(lcfg));
-
- if (tag != NULL && *tag != '\0') {
- if (lcfg->tag != NULL)
- isc_mem_free(lcfg->lctx->mctx, lcfg->tag);
- lcfg->tag = isc_mem_strdup(lcfg->lctx->mctx, tag);
- if (lcfg->tag == NULL)
- return (ISC_R_NOMEMORY);
-
- } else {
- if (lcfg->tag != NULL)
- isc_mem_free(lcfg->lctx->mctx, lcfg->tag);
- lcfg->tag = NULL;
- }
-
- return (ISC_R_SUCCESS);
-}
-
-char *
-isc_log_gettag(isc_logconfig_t *lcfg) {
- REQUIRE(VALID_CONFIG(lcfg));
-
- return (lcfg->tag);
-}
-
-/* XXXDCL NT -- This interface will assuredly be changing. */
-void
-isc_log_opensyslog(const char *tag, int options, int facility) {
- (void)openlog(tag, options, facility);
-}
-
-void
-isc_log_closefilelogs(isc_log_t *lctx) {
- isc_logchannel_t *channel;
-
- REQUIRE(VALID_CONTEXT(lctx));
-
- LOCK(&lctx->lock);
- for (channel = ISC_LIST_HEAD(lctx->logconfig->channels);
- channel != NULL;
- channel = ISC_LIST_NEXT(channel, link))
-
- if (channel->type == ISC_LOG_TOFILE &&
- FILE_STREAM(channel) != NULL) {
- (void)fclose(FILE_STREAM(channel));
- FILE_STREAM(channel) = NULL;
- }
- UNLOCK(&lctx->lock);
-}
-
-/****
- **** Internal functions
- ****/
-
-static isc_result_t
-assignchannel(isc_logconfig_t *lcfg, unsigned int category_id,
- const isc_logmodule_t *module, isc_logchannel_t *channel)
-{
- isc_logchannellist_t *new_item;
- isc_log_t *lctx;
- isc_result_t result;
-
- REQUIRE(VALID_CONFIG(lcfg));
-
- lctx = lcfg->lctx;
-
- REQUIRE(category_id < lctx->category_count);
- REQUIRE(module == NULL || module->id < lctx->module_count);
- REQUIRE(channel != NULL);
-
- /*
- * Ensure lcfg->channellist_count == lctx->category_count.
- */
- result = sync_channellist(lcfg);
- if (result != ISC_R_SUCCESS)
- return (result);
-
- new_item = isc_mem_get(lctx->mctx, sizeof(*new_item));
- if (new_item == NULL)
- return (ISC_R_NOMEMORY);
-
- new_item->channel = channel;
- new_item->module = module;
- ISC_LIST_INITANDPREPEND(lcfg->channellists[category_id],
- new_item, link);
-
- /*
- * Remember the highest logging level set by any channel in the
- * logging config, so isc_log_doit() can quickly return if the
- * message is too high to be logged by any channel.
- */
- if (channel->type != ISC_LOG_TONULL) {
- if (lcfg->highest_level < channel->level)
- lcfg->highest_level = channel->level;
- if (channel->level == ISC_LOG_DYNAMIC)
- lcfg->dynamic = ISC_TRUE;
- }
-
- return (ISC_R_SUCCESS);
-}
-
-/*
- * This would ideally be part of isc_log_registercategories(), except then
- * that function would have to return isc_result_t instead of void.
- */
-static isc_result_t
-sync_channellist(isc_logconfig_t *lcfg) {
- unsigned int bytes;
- isc_log_t *lctx;
- void *lists;
-
- REQUIRE(VALID_CONFIG(lcfg));
-
- lctx = lcfg->lctx;
-
- REQUIRE(lctx->category_count != 0);
-
- if (lctx->category_count == lcfg->channellist_count)
- return (ISC_R_SUCCESS);
-
- bytes = lctx->category_count * sizeof(ISC_LIST(isc_logchannellist_t));
-
- lists = isc_mem_get(lctx->mctx, bytes);
-
- if (lists == NULL)
- return (ISC_R_NOMEMORY);
-
- memset(lists, 0, bytes);
-
- if (lcfg->channellist_count != 0) {
- bytes = lcfg->channellist_count *
- sizeof(ISC_LIST(isc_logchannellist_t));
- memcpy(lists, lcfg->channellists, bytes);
- isc_mem_put(lctx->mctx, lcfg->channellists, bytes);
- }
-
- lcfg->channellists = lists;
- lcfg->channellist_count = lctx->category_count;
-
- return (ISC_R_SUCCESS);
-}
-
-static isc_result_t
-greatest_version(isc_logchannel_t *channel, int *greatestp) {
- /* XXXDCL HIGHLY NT */
- char *basename, *digit_end;
- const char *dirname;
- int version, greatest = -1;
- unsigned int basenamelen;
- isc_dir_t dir;
- isc_result_t result;
- char sep = '/';
-#ifdef _WIN32
- char *basename2;
-#endif
-
- REQUIRE(channel->type == ISC_LOG_TOFILE);
-
- /*
- * It is safe to DE_CONST the file.name because it was copied
- * with isc_mem_strdup in isc_log_createchannel.
- */
- basename = strrchr(FILE_NAME(channel), sep);
-#ifdef _WIN32
- basename2 = strrchr(FILE_NAME(channel), '\\');
- if ((basename != NULL && basename2 != NULL && basename2 > basename) ||
- (basename == NULL && basename2 != NULL)) {
- basename = basename2;
- sep = '\\';
- }
-#endif
- if (basename != NULL) {
- *basename++ = '\0';
- dirname = FILE_NAME(channel);
- } else {
- DE_CONST(FILE_NAME(channel), basename);
- dirname = ".";
- }
- basenamelen = strlen(basename);
-
- isc_dir_init(&dir);
- result = isc_dir_open(&dir, dirname);
-
- /*
- * Replace the file separator if it was taken out.
- */
- if (basename != FILE_NAME(channel))
- *(basename - 1) = sep;
-
- /*
- * Return if the directory open failed.
- */
- if (result != ISC_R_SUCCESS)
- return (result);
-
- while (isc_dir_read(&dir) == ISC_R_SUCCESS) {
- if (dir.entry.length > basenamelen &&
- strncmp(dir.entry.name, basename, basenamelen) == 0 &&
- dir.entry.name[basenamelen] == '.') {
-
- version = strtol(&dir.entry.name[basenamelen + 1],
- &digit_end, 10);
- if (*digit_end == '\0' && version > greatest)
- greatest = version;
- }
- }
- isc_dir_close(&dir);
-
- *greatestp = ++greatest;
-
- return (ISC_R_SUCCESS);
-}
-
-static isc_result_t
-roll_log(isc_logchannel_t *channel) {
- int i, n, greatest;
- char current[PATH_MAX + 1];
- char new[PATH_MAX + 1];
- const char *path;
- isc_result_t result;
-
- /*
- * Do nothing (not even excess version trimming) if ISC_LOG_ROLLNEVER
- * is specified. Apparently complete external control over the log
- * files is desired.
- */
- if (FILE_VERSIONS(channel) == ISC_LOG_ROLLNEVER)
- return (ISC_R_SUCCESS);
-
- path = FILE_NAME(channel);
-
- /*
- * Set greatest_version to the greatest existing version
- * (not the maximum requested version). This is 1 based even
- * though the file names are 0 based, so an oldest log of log.1
- * is a greatest_version of 2.
- */
- result = greatest_version(channel, &greatest);
- if (result != ISC_R_SUCCESS)
- return (result);
-
- /*
- * Now greatest should be set to the highest version number desired.
- * Since the highest number is one less than FILE_VERSIONS(channel)
- * when not doing infinite log rolling, greatest will need to be
- * decremented when it is equal to -- or greater than --
- * FILE_VERSIONS(channel). When greatest is less than
- * FILE_VERSIONS(channel), it is already suitable for use as
- * the maximum version number.
- */
-
- if (FILE_VERSIONS(channel) == ISC_LOG_ROLLINFINITE ||
- FILE_VERSIONS(channel) > greatest)
- ; /* Do nothing. */
- else
- /*
- * When greatest is >= FILE_VERSIONS(channel), it needs to
- * be reduced until it is FILE_VERSIONS(channel) - 1.
- * Remove any excess logs on the way to that value.
- */
- while (--greatest >= FILE_VERSIONS(channel)) {
- n = snprintf(current, sizeof(current), "%s.%d",
- path, greatest);
- if (n >= (int)sizeof(current) || n < 0)
- result = ISC_R_NOSPACE;
- else
- result = isc_file_remove(current);
- if (result != ISC_R_SUCCESS &&
- result != ISC_R_FILENOTFOUND)
- syslog(LOG_ERR,
- "unable to remove log file '%s.%d': %s",
- path, greatest,
- isc_result_totext(result));
- }
-
- for (i = greatest; i > 0; i--) {
- result = ISC_R_SUCCESS;
- n = snprintf(current, sizeof(current), "%s.%d", path, i - 1);
- if (n >= (int)sizeof(current) || n < 0)
- result = ISC_R_NOSPACE;
- if (result == ISC_R_SUCCESS) {
- n = snprintf(new, sizeof(new), "%s.%d", path, i);
- if (n >= (int)sizeof(new) || n < 0)
- result = ISC_R_NOSPACE;
- }
- if (result == ISC_R_SUCCESS)
- result = isc_file_rename(current, new);
- if (result != ISC_R_SUCCESS &&
- result != ISC_R_FILENOTFOUND)
- syslog(LOG_ERR,
- "unable to rename log file '%s.%d' to "
- "'%s.%d': %s", path, i - 1, path, i,
- isc_result_totext(result));
- }
-
- if (FILE_VERSIONS(channel) != 0) {
- n = snprintf(new, sizeof(new), "%s.0", path);
- if (n >= (int)sizeof(new) || n < 0)
- result = ISC_R_NOSPACE;
- else
- result = isc_file_rename(path, new);
- if (result != ISC_R_SUCCESS &&
- result != ISC_R_FILENOTFOUND)
- syslog(LOG_ERR,
- "unable to rename log file '%s' to '%s.0': %s",
- path, path, isc_result_totext(result));
- } else {
- result = isc_file_remove(path);
- if (result != ISC_R_SUCCESS &&
- result != ISC_R_FILENOTFOUND)
- syslog(LOG_ERR, "unable to remove log file '%s': %s",
- path, isc_result_totext(result));
- }
-
- return (ISC_R_SUCCESS);
-}
-
-static isc_result_t
-isc_log_open(isc_logchannel_t *channel) {
- struct stat statbuf;
- isc_boolean_t regular_file;
- isc_boolean_t roll = ISC_FALSE;
- isc_result_t result = ISC_R_SUCCESS;
- const char *path;
-
- REQUIRE(channel->type == ISC_LOG_TOFILE);
- REQUIRE(FILE_STREAM(channel) == NULL);
-
- path = FILE_NAME(channel);
-
- REQUIRE(path != NULL && *path != '\0');
-
- /*
- * Determine type of file; only regular files will be
- * version renamed, and only if the base file exists
- * and either has no size limit or has reached its size limit.
- */
- if (stat(path, &statbuf) == 0) {
- regular_file = S_ISREG(statbuf.st_mode) ? ISC_TRUE : ISC_FALSE;
- /* XXXDCL if not regular_file complain? */
- if ((FILE_MAXSIZE(channel) == 0 &&
- FILE_VERSIONS(channel) != ISC_LOG_ROLLNEVER) ||
- (FILE_MAXSIZE(channel) > 0 &&
- statbuf.st_size >= FILE_MAXSIZE(channel)))
- roll = regular_file;
- } else if (errno == ENOENT)
- regular_file = ISC_TRUE;
- else
- result = ISC_R_INVALIDFILE;
-
- /*
- * Version control.
- */
- if (result == ISC_R_SUCCESS && roll) {
- if (FILE_VERSIONS(channel) == ISC_LOG_ROLLNEVER)
- return (ISC_R_MAXSIZE);
- result = roll_log(channel);
- if (result != ISC_R_SUCCESS) {
- if ((channel->flags & ISC_LOG_OPENERR) == 0) {
- syslog(LOG_ERR,
- "isc_log_open: roll_log '%s' "
- "failed: %s",
- FILE_NAME(channel),
- isc_result_totext(result));
- channel->flags |= ISC_LOG_OPENERR;
- }
- return (result);
- }
- }
-
- result = isc_stdio_open(path, "a", &FILE_STREAM(channel));
-
- return (result);
-}
-
-isc_boolean_t
-isc_log_wouldlog(isc_log_t *lctx, int level) {
- /*
- * Try to avoid locking the mutex for messages which can't
- * possibly be logged to any channels -- primarily debugging
- * messages that the debug level is not high enough to print.
- *
- * If the level is (mathematically) less than or equal to the
- * highest_level, or if there is a dynamic channel and the level is
- * less than or equal to the debug level, the main loop must be
- * entered to see if the message should really be output.
- *
- * NOTE: this is UNLOCKED access to the logconfig. However,
- * the worst thing that can happen is that a bad decision is made
- * about returning without logging, and that's not a big concern,
- * because that's a risk anyway if the logconfig is being
- * dynamically changed.
- */
-
- if (lctx == NULL || lctx->logconfig == NULL)
- return (ISC_FALSE);
-
- return (ISC_TF(level <= lctx->logconfig->highest_level ||
- (lctx->logconfig->dynamic &&
- level <= lctx->debug_level)));
-}
-
-static void
-isc_log_doit(isc_log_t *lctx, isc_logcategory_t *category,
- isc_logmodule_t *module, int level, isc_boolean_t write_once,
- isc_msgcat_t *msgcat, int msgset, int msg,
- const char *format, va_list args)
-{
- int syslog_level;
- char time_string[64];
- char level_string[24];
- const char *iformat;
- struct stat statbuf;
- isc_boolean_t matched = ISC_FALSE;
- isc_boolean_t printtime, printtag;
- isc_boolean_t printcategory, printmodule, printlevel;
- isc_logconfig_t *lcfg;
- isc_logchannel_t *channel;
- isc_logchannellist_t *category_channels;
- isc_result_t result;
-
- REQUIRE(lctx == NULL || VALID_CONTEXT(lctx));
- REQUIRE(category != NULL);
- REQUIRE(module != NULL);
- REQUIRE(level != ISC_LOG_DYNAMIC);
- REQUIRE(format != NULL);
-
- /*
- * Programs can use libraries that use this logging code without
- * wanting to do any logging, thus the log context is allowed to
- * be non-existent.
- */
- if (lctx == NULL)
- return;
-
- REQUIRE(category->id < lctx->category_count);
- REQUIRE(module->id < lctx->module_count);
-
- if (! isc_log_wouldlog(lctx, level))
- return;
-
- if (msgcat != NULL)
- iformat = isc_msgcat_get(msgcat, msgset, msg, format);
- else
- iformat = format;
-
- time_string[0] = '\0';
- level_string[0] = '\0';
-
- LOCK(&lctx->lock);
-
- lctx->buffer[0] = '\0';
-
- lcfg = lctx->logconfig;
-
- category_channels = ISC_LIST_HEAD(lcfg->channellists[category->id]);
-
- /*
- * XXXDCL add duplicate filtering? (To not write multiple times to
- * the same source via various channels).
- */
- do {
- /*
- * If the channel list end was reached and a match was made,
- * everything is finished.
- */
- if (category_channels == NULL && matched)
- break;
-
- if (category_channels == NULL && ! matched &&
- category_channels != ISC_LIST_HEAD(lcfg->channellists[0]))
- /*
- * No category/module pair was explicitly configured.
- * Try the category named "default".
- */
- category_channels =
- ISC_LIST_HEAD(lcfg->channellists[0]);
-
- if (category_channels == NULL && ! matched)
- /*
- * No matching module was explicitly configured
- * for the category named "default". Use the internal
- * default channel.
- */
- category_channels = &default_channel;
-
- if (category_channels->module != NULL &&
- category_channels->module != module) {
- category_channels = ISC_LIST_NEXT(category_channels,
- link);
- continue;
- }
-
- matched = ISC_TRUE;
-
- channel = category_channels->channel;
- category_channels = ISC_LIST_NEXT(category_channels, link);
-
- if (((channel->flags & ISC_LOG_DEBUGONLY) != 0) &&
- lctx->debug_level == 0)
- continue;
-
- if (channel->level == ISC_LOG_DYNAMIC) {
- if (lctx->debug_level < level)
- continue;
- } else if (channel->level < level)
- continue;
-
- if ((channel->flags & ISC_LOG_PRINTTIME) != 0 &&
- time_string[0] == '\0') {
- isc_time_t isctime;
-
- TIME_NOW(&isctime);
- isc_time_formattimestamp(&isctime, time_string,
- sizeof(time_string));
- }
-
- if ((channel->flags & ISC_LOG_PRINTLEVEL) != 0 &&
- level_string[0] == '\0') {
- if (level < ISC_LOG_CRITICAL)
- snprintf(level_string, sizeof(level_string),
- isc_msgcat_get(isc_msgcat,
- ISC_MSGSET_LOG,
- ISC_MSG_LEVEL,
- "level %d: "),
- level);
- else if (level > ISC_LOG_DYNAMIC)
- snprintf(level_string, sizeof(level_string),
- "%s %d: ", log_level_strings[0],
- level);
- else
- snprintf(level_string, sizeof(level_string),
- "%s: ", log_level_strings[-level]);
- }
-
- /*
- * Only format the message once.
- */
- if (lctx->buffer[0] == '\0') {
- (void)vsnprintf(lctx->buffer, sizeof(lctx->buffer),
- iformat, args);
-
- /*
- * Check for duplicates.
- */
- if (write_once) {
- isc_logmessage_t *message, *new;
- isc_time_t oldest;
- isc_interval_t interval;
-
- isc_interval_set(&interval,
- lcfg->duplicate_interval, 0);
-
- /*
- * 'oldest' is the age of the oldest messages
- * which fall within the duplicate_interval
- * range.
- */
- TIME_NOW(&oldest);
- if (isc_time_subtract(&oldest, &interval, &oldest)
- != ISC_R_SUCCESS)
- /*
- * Can't effectively do the checking
- * without having a valid time.
- */
- message = NULL;
- else
- message =ISC_LIST_HEAD(lctx->messages);
-
- while (message != NULL) {
- if (isc_time_compare(&message->time,
- &oldest) < 0) {
- /*
- * This message is older
- * than the duplicate_interval,
- * so it should be dropped from
- * the history.
- *
- * Setting the interval to be
- * to be longer will obviously
- * not cause the expired
- * message to spring back into
- * existence.
- */
- new = ISC_LIST_NEXT(message,
- link);
-
- ISC_LIST_UNLINK(lctx->messages,
- message, link);
-
- isc_mem_put(lctx->mctx,
- message,
- sizeof(*message) + 1 +
- strlen(message->text));
-
- message = new;
- continue;
- }
-
- /*
- * This message is in the duplicate
- * filtering interval ...
- */
- if (strcmp(lctx->buffer, message->text)
- == 0) {
- /*
- * ... and it is a duplicate.
- * Unlock the mutex and
- * get the hell out of Dodge.
- */
- UNLOCK(&lctx->lock);
- return;
- }
-
- message = ISC_LIST_NEXT(message, link);
- }
-
- /*
- * It wasn't in the duplicate interval,
- * so add it to the message list.
- */
- new = isc_mem_get(lctx->mctx,
- sizeof(isc_logmessage_t) +
- strlen(lctx->buffer) + 1);
- if (new != NULL) {
- /*
- * Put the text immediately after
- * the struct. The strcpy is safe.
- */
- new->text = (char *)(new + 1);
- strcpy(new->text, lctx->buffer);
-
- TIME_NOW(&new->time);
-
- ISC_LIST_APPEND(lctx->messages,
- new, link);
- }
- }
- }
-
- printtime = ISC_TF((channel->flags & ISC_LOG_PRINTTIME)
- != 0);
- printtag = ISC_TF((channel->flags & ISC_LOG_PRINTTAG)
- != 0 && lcfg->tag != NULL);
- printcategory = ISC_TF((channel->flags & ISC_LOG_PRINTCATEGORY)
- != 0);
- printmodule = ISC_TF((channel->flags & ISC_LOG_PRINTMODULE)
- != 0);
- printlevel = ISC_TF((channel->flags & ISC_LOG_PRINTLEVEL)
- != 0);
-
- switch (channel->type) {
- case ISC_LOG_TOFILE:
- if (FILE_MAXREACHED(channel)) {
- /*
- * If the file can be rolled, OR
- * If the file no longer exists, OR
- * If the file is less than the maximum size,
- * (such as if it had been renamed and
- * a new one touched, or it was truncated
- * in place)
- * ... then close it to trigger reopening.
- */
- if (FILE_VERSIONS(channel) !=
- ISC_LOG_ROLLNEVER ||
- (stat(FILE_NAME(channel), &statbuf) != 0 &&
- errno == ENOENT) ||
- statbuf.st_size < FILE_MAXSIZE(channel)) {
- (void)fclose(FILE_STREAM(channel));
- FILE_STREAM(channel) = NULL;
- FILE_MAXREACHED(channel) = ISC_FALSE;
- } else
- /*
- * Eh, skip it.
- */
- break;
- }
-
- if (FILE_STREAM(channel) == NULL) {
- result = isc_log_open(channel);
- if (result != ISC_R_SUCCESS &&
- result != ISC_R_MAXSIZE &&
- (channel->flags & ISC_LOG_OPENERR) == 0) {
- syslog(LOG_ERR,
- "isc_log_open '%s' failed: %s",
- FILE_NAME(channel),
- isc_result_totext(result));
- channel->flags |= ISC_LOG_OPENERR;
- }
- if (result != ISC_R_SUCCESS)
- break;
- channel->flags &= ~ISC_LOG_OPENERR;
- }
- /* FALLTHROUGH */
-
- case ISC_LOG_TOFILEDESC:
- fprintf(FILE_STREAM(channel), "%s%s%s%s%s%s%s%s%s%s\n",
- printtime ? time_string : "",
- printtime ? " " : "",
- printtag ? lcfg->tag : "",
- printtag ? ": " : "",
- printcategory ? category->name : "",
- printcategory ? ": " : "",
- printmodule ? (module != NULL ? module->name
- : "no_module")
- : "",
- printmodule ? ": " : "",
- printlevel ? level_string : "",
- lctx->buffer);
-
- fflush(FILE_STREAM(channel));
-
- /*
- * If the file now exceeds its maximum size
- * threshold, note it so that it will not be logged
- * to any more.
- */
- if (FILE_MAXSIZE(channel) > 0) {
- INSIST(channel->type == ISC_LOG_TOFILE);
-
- /* XXXDCL NT fstat/fileno */
- /* XXXDCL complain if fstat fails? */
- if (fstat(fileno(FILE_STREAM(channel)),
- &statbuf) >= 0 &&
- statbuf.st_size > FILE_MAXSIZE(channel))
- FILE_MAXREACHED(channel) = ISC_TRUE;
- }
-
- break;
-
- case ISC_LOG_TOSYSLOG:
- if (level > 0)
- syslog_level = LOG_DEBUG;
- else if (level < ISC_LOG_CRITICAL)
- syslog_level = LOG_CRIT;
- else
- syslog_level = syslog_map[-level];
-
- (void)syslog(FACILITY(channel) | syslog_level,
- "%s%s%s%s%s%s%s%s%s%s",
- printtime ? time_string : "",
- printtime ? " " : "",
- printtag ? lcfg->tag : "",
- printtag ? ": " : "",
- printcategory ? category->name : "",
- printcategory ? ": " : "",
- printmodule ? (module != NULL ? module->name
- : "no_module")
- : "",
- printmodule ? ": " : "",
- printlevel ? level_string : "",
- lctx->buffer);
- break;
-
- case ISC_LOG_TONULL:
- break;
-
- }
-
- } while (1);
-
- UNLOCK(&lctx->lock);
-}
OpenPOWER on IntegriCloud