1135446Strhodes/* 2262706Serwin * Copyright (C) 2004-2007, 2009, 2011-2014 Internet Systems Consortium, Inc. ("ISC") 3135446Strhodes * Copyright (C) 1999-2003 Internet Software Consortium. 4135446Strhodes * 5193149Sdougb * Permission to use, copy, modify, and/or distribute this software for any 6135446Strhodes * purpose with or without fee is hereby granted, provided that the above 7135446Strhodes * copyright notice and this permission notice appear in all copies. 8135446Strhodes * 9135446Strhodes * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10135446Strhodes * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11135446Strhodes * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12135446Strhodes * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13135446Strhodes * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14135446Strhodes * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15135446Strhodes * PERFORMANCE OF THIS SOFTWARE. 16135446Strhodes */ 17135446Strhodes 18234010Sdougb/* $Id$ */ 19135446Strhodes 20170222Sdougb/*! \file 21170222Sdougb * \author Principal Authors: DCL */ 22135446Strhodes 23135446Strhodes#include <config.h> 24135446Strhodes 25135446Strhodes#include <errno.h> 26135446Strhodes#include <stdlib.h> 27135446Strhodes#include <limits.h> 28135446Strhodes#include <time.h> 29135446Strhodes 30135446Strhodes#include <sys/types.h> /* dev_t FreeBSD 2.1 */ 31135446Strhodes 32135446Strhodes#include <isc/dir.h> 33135446Strhodes#include <isc/file.h> 34135446Strhodes#include <isc/log.h> 35135446Strhodes#include <isc/magic.h> 36135446Strhodes#include <isc/mem.h> 37135446Strhodes#include <isc/msgs.h> 38135446Strhodes#include <isc/print.h> 39135446Strhodes#include <isc/stat.h> 40135446Strhodes#include <isc/stdio.h> 41135446Strhodes#include <isc/string.h> 42135446Strhodes#include <isc/time.h> 43135446Strhodes#include <isc/util.h> 44135446Strhodes 45135446Strhodes#define LCTX_MAGIC ISC_MAGIC('L', 'c', 't', 'x') 46135446Strhodes#define VALID_CONTEXT(lctx) ISC_MAGIC_VALID(lctx, LCTX_MAGIC) 47135446Strhodes 48135446Strhodes#define LCFG_MAGIC ISC_MAGIC('L', 'c', 'f', 'g') 49135446Strhodes#define VALID_CONFIG(lcfg) ISC_MAGIC_VALID(lcfg, LCFG_MAGIC) 50135446Strhodes 51135446Strhodes/* 52135446Strhodes * XXXDCL make dynamic? 53135446Strhodes */ 54135446Strhodes#define LOG_BUFFER_SIZE (8 * 1024) 55135446Strhodes 56135446Strhodes#ifndef PATH_MAX 57135446Strhodes#define PATH_MAX 1024 /* AIX and others don't define this. */ 58135446Strhodes#endif 59135446Strhodes 60170222Sdougb/*! 61135446Strhodes * This is the structure that holds each named channel. A simple linked 62135446Strhodes * list chains all of the channels together, so an individual channel is 63135446Strhodes * found by doing strcmp()s with the names down the list. Their should 64193149Sdougb * be no performance penalty from this as it is expected that the number 65135446Strhodes * of named channels will be no more than a dozen or so, and name lookups 66135446Strhodes * from the head of the list are only done when isc_log_usechannel() is 67135446Strhodes * called, which should also be very infrequent. 68135446Strhodes */ 69135446Strhodestypedef struct isc_logchannel isc_logchannel_t; 70135446Strhodes 71135446Strhodesstruct isc_logchannel { 72135446Strhodes char * name; 73135446Strhodes unsigned int type; 74135446Strhodes int level; 75135446Strhodes unsigned int flags; 76135446Strhodes isc_logdestination_t destination; 77135446Strhodes ISC_LINK(isc_logchannel_t) link; 78135446Strhodes}; 79135446Strhodes 80170222Sdougb/*! 81135446Strhodes * The logchannellist structure associates categories and modules with 82135446Strhodes * channels. First the appropriate channellist is found based on the 83135446Strhodes * category, and then each structure in the linked list is checked for 84135446Strhodes * a matching module. It is expected that the number of channels 85135446Strhodes * associated with any given category will be very short, no more than 86135446Strhodes * three or four in the more unusual cases. 87135446Strhodes */ 88135446Strhodestypedef struct isc_logchannellist isc_logchannellist_t; 89135446Strhodes 90135446Strhodesstruct isc_logchannellist { 91135446Strhodes const isc_logmodule_t * module; 92135446Strhodes isc_logchannel_t * channel; 93135446Strhodes ISC_LINK(isc_logchannellist_t) link; 94135446Strhodes}; 95135446Strhodes 96170222Sdougb/*! 97135446Strhodes * This structure is used to remember messages for pruning via 98135446Strhodes * isc_log_[v]write1(). 99135446Strhodes */ 100135446Strhodestypedef struct isc_logmessage isc_logmessage_t; 101135446Strhodes 102135446Strhodesstruct isc_logmessage { 103135446Strhodes char * text; 104135446Strhodes isc_time_t time; 105135446Strhodes ISC_LINK(isc_logmessage_t) link; 106135446Strhodes}; 107135446Strhodes 108170222Sdougb/*! 109135446Strhodes * The isc_logconfig structure is used to store the configurable information 110135446Strhodes * about where messages are actually supposed to be sent -- the information 111135446Strhodes * that could changed based on some configuration file, as opposed to the 112135446Strhodes * the category/module specification of isc_log_[v]write[1] that is compiled 113135446Strhodes * into a program, or the debug_level which is dynamic state information. 114135446Strhodes */ 115135446Strhodesstruct isc_logconfig { 116135446Strhodes unsigned int magic; 117135446Strhodes isc_log_t * lctx; 118135446Strhodes ISC_LIST(isc_logchannel_t) channels; 119135446Strhodes ISC_LIST(isc_logchannellist_t) *channellists; 120135446Strhodes unsigned int channellist_count; 121135446Strhodes unsigned int duplicate_interval; 122135446Strhodes int highest_level; 123135446Strhodes char * tag; 124135446Strhodes isc_boolean_t dynamic; 125135446Strhodes}; 126135446Strhodes 127170222Sdougb/*! 128135446Strhodes * This isc_log structure provides the context for the isc_log functions. 129135446Strhodes * The log context locks itself in isc_log_doit, the internal backend to 130135446Strhodes * isc_log_write. The locking is necessary both to provide exclusive access 131193149Sdougb * to the buffer into which the message is formatted and to guard against 132135446Strhodes * competing threads trying to write to the same syslog resource. (On 133135446Strhodes * some systems, such as BSD/OS, stdio is thread safe but syslog is not.) 134135446Strhodes * Unfortunately, the lock cannot guard against a _different_ logging 135135446Strhodes * context in the same program competing for syslog's attention. Thus 136135446Strhodes * There Can Be Only One, but this is not enforced. 137135446Strhodes * XXXDCL enforce it? 138135446Strhodes * 139135446Strhodes * Note that the category and module information is not locked. 140135446Strhodes * This is because in the usual case, only one isc_log_t is ever created 141135446Strhodes * in a program, and the category/module registration happens only once. 142135446Strhodes * XXXDCL it might be wise to add more locking overall. 143135446Strhodes */ 144135446Strhodesstruct isc_log { 145135446Strhodes /* Not locked. */ 146135446Strhodes unsigned int magic; 147135446Strhodes isc_mem_t * mctx; 148135446Strhodes isc_logcategory_t * categories; 149135446Strhodes unsigned int category_count; 150135446Strhodes isc_logmodule_t * modules; 151135446Strhodes unsigned int module_count; 152135446Strhodes int debug_level; 153135446Strhodes isc_mutex_t lock; 154135446Strhodes /* Locked by isc_log lock. */ 155135446Strhodes isc_logconfig_t * logconfig; 156135446Strhodes char buffer[LOG_BUFFER_SIZE]; 157135446Strhodes ISC_LIST(isc_logmessage_t) messages; 158135446Strhodes}; 159135446Strhodes 160170222Sdougb/*! 161135446Strhodes * Used when ISC_LOG_PRINTLEVEL is enabled for a channel. 162135446Strhodes */ 163135446Strhodesstatic const char *log_level_strings[] = { 164135446Strhodes "debug", 165135446Strhodes "info", 166135446Strhodes "notice", 167135446Strhodes "warning", 168135446Strhodes "error", 169135446Strhodes "critical" 170135446Strhodes}; 171135446Strhodes 172170222Sdougb/*! 173135446Strhodes * Used to convert ISC_LOG_* priorities into syslog priorities. 174135446Strhodes * XXXDCL This will need modification for NT. 175135446Strhodes */ 176135446Strhodesstatic const int syslog_map[] = { 177135446Strhodes LOG_DEBUG, 178135446Strhodes LOG_INFO, 179135446Strhodes LOG_NOTICE, 180135446Strhodes LOG_WARNING, 181135446Strhodes LOG_ERR, 182135446Strhodes LOG_CRIT 183135446Strhodes}; 184135446Strhodes 185170222Sdougb/*! 186135446Strhodes * When adding new categories, a corresponding ISC_LOGCATEGORY_foo 187135446Strhodes * definition needs to be added to <isc/log.h>. 188135446Strhodes * 189135446Strhodes * The default category is provided so that the internal default can 190135446Strhodes * be overridden. Since the default is always looked up as the first 191135446Strhodes * channellist in the log context, it must come first in isc_categories[]. 192135446Strhodes */ 193135446StrhodesLIBISC_EXTERNAL_DATA isc_logcategory_t isc_categories[] = { 194135446Strhodes { "default", 0 }, /* "default" must come first. */ 195135446Strhodes { "general", 0 }, 196135446Strhodes { NULL, 0 } 197135446Strhodes}; 198135446Strhodes 199170222Sdougb/*! 200170222Sdougb * See above comment for categories on LIBISC_EXTERNAL_DATA, and apply it to modules. 201135446Strhodes */ 202135446StrhodesLIBISC_EXTERNAL_DATA isc_logmodule_t isc_modules[] = { 203135446Strhodes { "socket", 0 }, 204135446Strhodes { "time", 0 }, 205135446Strhodes { "interface", 0 }, 206135446Strhodes { "timer", 0 }, 207193149Sdougb { "file", 0 }, 208135446Strhodes { NULL, 0 } 209135446Strhodes}; 210135446Strhodes 211170222Sdougb/*! 212135446Strhodes * This essentially constant structure must be filled in at run time, 213135446Strhodes * because its channel member is pointed to a channel that is created 214135446Strhodes * dynamically with isc_log_createchannel. 215135446Strhodes */ 216135446Strhodesstatic isc_logchannellist_t default_channel; 217135446Strhodes 218170222Sdougb/*! 219135446Strhodes * libisc logs to this context. 220135446Strhodes */ 221135446StrhodesLIBISC_EXTERNAL_DATA isc_log_t *isc_lctx = NULL; 222135446Strhodes 223170222Sdougb/*! 224135446Strhodes * Forward declarations. 225135446Strhodes */ 226135446Strhodesstatic isc_result_t 227135446Strhodesassignchannel(isc_logconfig_t *lcfg, unsigned int category_id, 228135446Strhodes const isc_logmodule_t *module, isc_logchannel_t *channel); 229135446Strhodes 230135446Strhodesstatic isc_result_t 231135446Strhodessync_channellist(isc_logconfig_t *lcfg); 232135446Strhodes 233135446Strhodesstatic isc_result_t 234135446Strhodesgreatest_version(isc_logchannel_t *channel, int *greatest); 235135446Strhodes 236135446Strhodesstatic isc_result_t 237135446Strhodesroll_log(isc_logchannel_t *channel); 238135446Strhodes 239135446Strhodesstatic void 240135446Strhodesisc_log_doit(isc_log_t *lctx, isc_logcategory_t *category, 241135446Strhodes isc_logmodule_t *module, int level, isc_boolean_t write_once, 242135446Strhodes isc_msgcat_t *msgcat, int msgset, int msg, 243135446Strhodes const char *format, va_list args) 244135446Strhodes ISC_FORMAT_PRINTF(9, 0); 245135446Strhodes 246170222Sdougb/*@{*/ 247170222Sdougb/*! 248135446Strhodes * Convenience macros. 249135446Strhodes */ 250135446Strhodes 251135446Strhodes#define FACILITY(channel) (channel->destination.facility) 252135446Strhodes#define FILE_NAME(channel) (channel->destination.file.name) 253135446Strhodes#define FILE_STREAM(channel) (channel->destination.file.stream) 254135446Strhodes#define FILE_VERSIONS(channel) (channel->destination.file.versions) 255135446Strhodes#define FILE_MAXSIZE(channel) (channel->destination.file.maximum_size) 256135446Strhodes#define FILE_MAXREACHED(channel) (channel->destination.file.maximum_reached) 257135446Strhodes 258170222Sdougb/*@}*/ 259135446Strhodes/**** 260135446Strhodes **** Public interfaces. 261135446Strhodes ****/ 262135446Strhodes 263135446Strhodes/* 264135446Strhodes * Establish a new logging context, with default channels. 265135446Strhodes */ 266135446Strhodesisc_result_t 267135446Strhodesisc_log_create(isc_mem_t *mctx, isc_log_t **lctxp, isc_logconfig_t **lcfgp) { 268135446Strhodes isc_log_t *lctx; 269135446Strhodes isc_logconfig_t *lcfg = NULL; 270135446Strhodes isc_result_t result; 271135446Strhodes 272135446Strhodes REQUIRE(mctx != NULL); 273135446Strhodes REQUIRE(lctxp != NULL && *lctxp == NULL); 274135446Strhodes REQUIRE(lcfgp == NULL || *lcfgp == NULL); 275135446Strhodes 276135446Strhodes lctx = isc_mem_get(mctx, sizeof(*lctx)); 277135446Strhodes if (lctx != NULL) { 278254897Serwin lctx->mctx = NULL; 279254897Serwin isc_mem_attach(mctx, &lctx->mctx); 280135446Strhodes lctx->categories = NULL; 281135446Strhodes lctx->category_count = 0; 282135446Strhodes lctx->modules = NULL; 283135446Strhodes lctx->module_count = 0; 284135446Strhodes lctx->debug_level = 0; 285135446Strhodes 286135446Strhodes ISC_LIST_INIT(lctx->messages); 287135446Strhodes 288170222Sdougb result = isc_mutex_init(&lctx->lock); 289170222Sdougb if (result != ISC_R_SUCCESS) { 290254897Serwin isc_mem_putanddetach(&mctx, lctx, sizeof(*lctx)); 291170222Sdougb return (result); 292170222Sdougb } 293135446Strhodes 294135446Strhodes /* 295135446Strhodes * Normally setting the magic number is the last step done 296135446Strhodes * in a creation function, but a valid log context is needed 297135446Strhodes * by isc_log_registercategories and isc_logconfig_create. 298135446Strhodes * If either fails, the lctx is destroyed and not returned 299135446Strhodes * to the caller. 300135446Strhodes */ 301135446Strhodes lctx->magic = LCTX_MAGIC; 302135446Strhodes 303135446Strhodes isc_log_registercategories(lctx, isc_categories); 304135446Strhodes isc_log_registermodules(lctx, isc_modules); 305135446Strhodes result = isc_logconfig_create(lctx, &lcfg); 306135446Strhodes 307135446Strhodes } else 308135446Strhodes result = ISC_R_NOMEMORY; 309135446Strhodes 310135446Strhodes if (result == ISC_R_SUCCESS) 311135446Strhodes result = sync_channellist(lcfg); 312135446Strhodes 313135446Strhodes if (result == ISC_R_SUCCESS) { 314135446Strhodes lctx->logconfig = lcfg; 315135446Strhodes 316135446Strhodes *lctxp = lctx; 317135446Strhodes if (lcfgp != NULL) 318135446Strhodes *lcfgp = lcfg; 319135446Strhodes 320135446Strhodes } else { 321135446Strhodes if (lcfg != NULL) 322135446Strhodes isc_logconfig_destroy(&lcfg); 323135446Strhodes if (lctx != NULL) 324135446Strhodes isc_log_destroy(&lctx); 325135446Strhodes } 326135446Strhodes 327135446Strhodes return (result); 328135446Strhodes} 329135446Strhodes 330135446Strhodesisc_result_t 331135446Strhodesisc_logconfig_create(isc_log_t *lctx, isc_logconfig_t **lcfgp) { 332135446Strhodes isc_logconfig_t *lcfg; 333135446Strhodes isc_logdestination_t destination; 334135446Strhodes isc_result_t result = ISC_R_SUCCESS; 335135446Strhodes int level = ISC_LOG_INFO; 336135446Strhodes 337135446Strhodes REQUIRE(lcfgp != NULL && *lcfgp == NULL); 338135446Strhodes REQUIRE(VALID_CONTEXT(lctx)); 339135446Strhodes 340135446Strhodes lcfg = isc_mem_get(lctx->mctx, sizeof(*lcfg)); 341135446Strhodes 342135446Strhodes if (lcfg != NULL) { 343135446Strhodes lcfg->lctx = lctx; 344135446Strhodes lcfg->channellists = NULL; 345135446Strhodes lcfg->channellist_count = 0; 346135446Strhodes lcfg->duplicate_interval = 0; 347135446Strhodes lcfg->highest_level = level; 348135446Strhodes lcfg->tag = NULL; 349135446Strhodes lcfg->dynamic = ISC_FALSE; 350135446Strhodes 351135446Strhodes ISC_LIST_INIT(lcfg->channels); 352135446Strhodes 353135446Strhodes /* 354135446Strhodes * Normally the magic number is the last thing set in the 355135446Strhodes * structure, but isc_log_createchannel() needs a valid 356135446Strhodes * config. If the channel creation fails, the lcfg is not 357135446Strhodes * returned to the caller. 358135446Strhodes */ 359135446Strhodes lcfg->magic = LCFG_MAGIC; 360135446Strhodes 361135446Strhodes } else 362135446Strhodes result = ISC_R_NOMEMORY; 363135446Strhodes 364135446Strhodes /* 365135446Strhodes * Create the default channels: 366135446Strhodes * default_syslog, default_stderr, default_debug and null. 367135446Strhodes */ 368135446Strhodes if (result == ISC_R_SUCCESS) { 369135446Strhodes destination.facility = LOG_DAEMON; 370135446Strhodes result = isc_log_createchannel(lcfg, "default_syslog", 371135446Strhodes ISC_LOG_TOSYSLOG, level, 372135446Strhodes &destination, 0); 373135446Strhodes } 374135446Strhodes 375135446Strhodes if (result == ISC_R_SUCCESS) { 376135446Strhodes destination.file.stream = stderr; 377135446Strhodes destination.file.name = NULL; 378135446Strhodes destination.file.versions = ISC_LOG_ROLLNEVER; 379135446Strhodes destination.file.maximum_size = 0; 380135446Strhodes result = isc_log_createchannel(lcfg, "default_stderr", 381135446Strhodes ISC_LOG_TOFILEDESC, 382135446Strhodes level, 383135446Strhodes &destination, 384135446Strhodes ISC_LOG_PRINTTIME); 385135446Strhodes } 386135446Strhodes 387135446Strhodes if (result == ISC_R_SUCCESS) { 388135446Strhodes /* 389135446Strhodes * Set the default category's channel to default_stderr, 390135446Strhodes * which is at the head of the channels list because it was 391135446Strhodes * just created. 392135446Strhodes */ 393135446Strhodes default_channel.channel = ISC_LIST_HEAD(lcfg->channels); 394135446Strhodes 395135446Strhodes destination.file.stream = stderr; 396135446Strhodes destination.file.name = NULL; 397135446Strhodes destination.file.versions = ISC_LOG_ROLLNEVER; 398135446Strhodes destination.file.maximum_size = 0; 399135446Strhodes result = isc_log_createchannel(lcfg, "default_debug", 400135446Strhodes ISC_LOG_TOFILEDESC, 401135446Strhodes ISC_LOG_DYNAMIC, 402135446Strhodes &destination, 403135446Strhodes ISC_LOG_PRINTTIME); 404135446Strhodes } 405135446Strhodes 406135446Strhodes if (result == ISC_R_SUCCESS) 407135446Strhodes result = isc_log_createchannel(lcfg, "null", 408135446Strhodes ISC_LOG_TONULL, 409135446Strhodes ISC_LOG_DYNAMIC, 410135446Strhodes NULL, 0); 411135446Strhodes 412135446Strhodes if (result == ISC_R_SUCCESS) 413135446Strhodes *lcfgp = lcfg; 414135446Strhodes 415135446Strhodes else 416135446Strhodes if (lcfg != NULL) 417135446Strhodes isc_logconfig_destroy(&lcfg); 418135446Strhodes 419135446Strhodes return (result); 420135446Strhodes} 421135446Strhodes 422135446Strhodesisc_logconfig_t * 423135446Strhodesisc_logconfig_get(isc_log_t *lctx) { 424135446Strhodes REQUIRE(VALID_CONTEXT(lctx)); 425135446Strhodes 426135446Strhodes ENSURE(lctx->logconfig != NULL); 427135446Strhodes 428135446Strhodes return (lctx->logconfig); 429135446Strhodes} 430135446Strhodes 431135446Strhodesisc_result_t 432135446Strhodesisc_logconfig_use(isc_log_t *lctx, isc_logconfig_t *lcfg) { 433135446Strhodes isc_logconfig_t *old_cfg; 434135446Strhodes isc_result_t result; 435135446Strhodes 436135446Strhodes REQUIRE(VALID_CONTEXT(lctx)); 437135446Strhodes REQUIRE(VALID_CONFIG(lcfg)); 438135446Strhodes REQUIRE(lcfg->lctx == lctx); 439135446Strhodes 440135446Strhodes /* 441135446Strhodes * Ensure that lcfg->channellist_count == lctx->category_count. 442135446Strhodes * They won't be equal if isc_log_usechannel has not been called 443135446Strhodes * since any call to isc_log_registercategories. 444135446Strhodes */ 445135446Strhodes result = sync_channellist(lcfg); 446135446Strhodes if (result != ISC_R_SUCCESS) 447135446Strhodes return (result); 448135446Strhodes 449135446Strhodes LOCK(&lctx->lock); 450135446Strhodes 451135446Strhodes old_cfg = lctx->logconfig; 452135446Strhodes lctx->logconfig = lcfg; 453135446Strhodes 454135446Strhodes UNLOCK(&lctx->lock); 455135446Strhodes 456135446Strhodes isc_logconfig_destroy(&old_cfg); 457135446Strhodes 458135446Strhodes return (ISC_R_SUCCESS); 459135446Strhodes} 460135446Strhodes 461135446Strhodesvoid 462135446Strhodesisc_log_destroy(isc_log_t **lctxp) { 463135446Strhodes isc_log_t *lctx; 464135446Strhodes isc_logconfig_t *lcfg; 465135446Strhodes isc_mem_t *mctx; 466135446Strhodes isc_logmessage_t *message; 467135446Strhodes 468135446Strhodes REQUIRE(lctxp != NULL && VALID_CONTEXT(*lctxp)); 469135446Strhodes 470135446Strhodes lctx = *lctxp; 471135446Strhodes mctx = lctx->mctx; 472135446Strhodes 473135446Strhodes if (lctx->logconfig != NULL) { 474135446Strhodes lcfg = lctx->logconfig; 475135446Strhodes lctx->logconfig = NULL; 476135446Strhodes isc_logconfig_destroy(&lcfg); 477135446Strhodes } 478135446Strhodes 479135446Strhodes DESTROYLOCK(&lctx->lock); 480135446Strhodes 481135446Strhodes while ((message = ISC_LIST_HEAD(lctx->messages)) != NULL) { 482135446Strhodes ISC_LIST_UNLINK(lctx->messages, message, link); 483135446Strhodes 484135446Strhodes isc_mem_put(mctx, message, 485135446Strhodes sizeof(*message) + strlen(message->text) + 1); 486135446Strhodes } 487135446Strhodes 488135446Strhodes lctx->buffer[0] = '\0'; 489135446Strhodes lctx->debug_level = 0; 490135446Strhodes lctx->categories = NULL; 491135446Strhodes lctx->category_count = 0; 492135446Strhodes lctx->modules = NULL; 493135446Strhodes lctx->module_count = 0; 494135446Strhodes lctx->mctx = NULL; 495135446Strhodes lctx->magic = 0; 496135446Strhodes 497254897Serwin isc_mem_putanddetach(&mctx, lctx, sizeof(*lctx)); 498135446Strhodes 499135446Strhodes *lctxp = NULL; 500135446Strhodes} 501135446Strhodes 502135446Strhodesvoid 503135446Strhodesisc_logconfig_destroy(isc_logconfig_t **lcfgp) { 504135446Strhodes isc_logconfig_t *lcfg; 505135446Strhodes isc_mem_t *mctx; 506135446Strhodes isc_logchannel_t *channel; 507135446Strhodes isc_logchannellist_t *item; 508135446Strhodes char *filename; 509135446Strhodes unsigned int i; 510135446Strhodes 511135446Strhodes REQUIRE(lcfgp != NULL && VALID_CONFIG(*lcfgp)); 512135446Strhodes 513135446Strhodes lcfg = *lcfgp; 514135446Strhodes 515135446Strhodes /* 516135446Strhodes * This function cannot be called with a logconfig that is in 517135446Strhodes * use by a log context. 518135446Strhodes */ 519135446Strhodes REQUIRE(lcfg->lctx != NULL && lcfg->lctx->logconfig != lcfg); 520135446Strhodes 521135446Strhodes mctx = lcfg->lctx->mctx; 522135446Strhodes 523135446Strhodes while ((channel = ISC_LIST_HEAD(lcfg->channels)) != NULL) { 524135446Strhodes ISC_LIST_UNLINK(lcfg->channels, channel, link); 525135446Strhodes 526135446Strhodes if (channel->type == ISC_LOG_TOFILE) { 527135446Strhodes /* 528135446Strhodes * The filename for the channel may have ultimately 529135446Strhodes * started its life in user-land as a const string, 530135446Strhodes * but in isc_log_createchannel it gets copied 531135446Strhodes * into writable memory and is not longer truly const. 532135446Strhodes */ 533135446Strhodes DE_CONST(FILE_NAME(channel), filename); 534135446Strhodes isc_mem_free(mctx, filename); 535135446Strhodes 536135446Strhodes if (FILE_STREAM(channel) != NULL) 537135446Strhodes (void)fclose(FILE_STREAM(channel)); 538135446Strhodes } 539135446Strhodes 540135446Strhodes isc_mem_free(mctx, channel->name); 541135446Strhodes isc_mem_put(mctx, channel, sizeof(*channel)); 542135446Strhodes } 543135446Strhodes 544135446Strhodes for (i = 0; i < lcfg->channellist_count; i++) 545135446Strhodes while ((item = ISC_LIST_HEAD(lcfg->channellists[i])) != NULL) { 546135446Strhodes ISC_LIST_UNLINK(lcfg->channellists[i], item, link); 547135446Strhodes isc_mem_put(mctx, item, sizeof(*item)); 548135446Strhodes } 549135446Strhodes 550135446Strhodes if (lcfg->channellist_count > 0) 551135446Strhodes isc_mem_put(mctx, lcfg->channellists, 552135446Strhodes lcfg->channellist_count * 553135446Strhodes sizeof(ISC_LIST(isc_logchannellist_t))); 554135446Strhodes 555135446Strhodes lcfg->dynamic = ISC_FALSE; 556135446Strhodes if (lcfg->tag != NULL) 557135446Strhodes isc_mem_free(lcfg->lctx->mctx, lcfg->tag); 558135446Strhodes lcfg->tag = NULL; 559135446Strhodes lcfg->highest_level = 0; 560135446Strhodes lcfg->duplicate_interval = 0; 561135446Strhodes lcfg->magic = 0; 562135446Strhodes 563135446Strhodes isc_mem_put(mctx, lcfg, sizeof(*lcfg)); 564135446Strhodes 565135446Strhodes *lcfgp = NULL; 566135446Strhodes} 567135446Strhodes 568135446Strhodesvoid 569135446Strhodesisc_log_registercategories(isc_log_t *lctx, isc_logcategory_t categories[]) { 570135446Strhodes isc_logcategory_t *catp; 571135446Strhodes 572135446Strhodes REQUIRE(VALID_CONTEXT(lctx)); 573135446Strhodes REQUIRE(categories != NULL && categories[0].name != NULL); 574135446Strhodes 575135446Strhodes /* 576135446Strhodes * XXXDCL This somewhat sleazy situation of using the last pointer 577135446Strhodes * in one category array to point to the next array exists because 578135446Strhodes * this registration function returns void and I didn't want to have 579135446Strhodes * change everything that used it by making it return an isc_result_t. 580135446Strhodes * It would need to do that if it had to allocate memory to store 581135446Strhodes * pointers to each array passed in. 582135446Strhodes */ 583135446Strhodes if (lctx->categories == NULL) 584135446Strhodes lctx->categories = categories; 585135446Strhodes 586135446Strhodes else { 587135446Strhodes /* 588135446Strhodes * Adjust the last (NULL) pointer of the already registered 589135446Strhodes * categories to point to the incoming array. 590135446Strhodes */ 591135446Strhodes for (catp = lctx->categories; catp->name != NULL; ) 592135446Strhodes if (catp->id == UINT_MAX) 593135446Strhodes /* 594135446Strhodes * The name pointer points to the next array. 595135446Strhodes * Ick. 596135446Strhodes */ 597135446Strhodes DE_CONST(catp->name, catp); 598135446Strhodes else 599135446Strhodes catp++; 600135446Strhodes 601135446Strhodes catp->name = (void *)categories; 602135446Strhodes catp->id = UINT_MAX; 603135446Strhodes } 604135446Strhodes 605135446Strhodes /* 606135446Strhodes * Update the id number of the category with its new global id. 607135446Strhodes */ 608135446Strhodes for (catp = categories; catp->name != NULL; catp++) 609135446Strhodes catp->id = lctx->category_count++; 610135446Strhodes} 611135446Strhodes 612135446Strhodesisc_logcategory_t * 613135446Strhodesisc_log_categorybyname(isc_log_t *lctx, const char *name) { 614135446Strhodes isc_logcategory_t *catp; 615135446Strhodes 616135446Strhodes REQUIRE(VALID_CONTEXT(lctx)); 617135446Strhodes REQUIRE(name != NULL); 618135446Strhodes 619135446Strhodes for (catp = lctx->categories; catp->name != NULL; ) 620135446Strhodes if (catp->id == UINT_MAX) 621135446Strhodes /* 622135446Strhodes * catp is neither modified nor returned to the 623135446Strhodes * caller, so removing its const qualifier is ok. 624135446Strhodes */ 625135446Strhodes DE_CONST(catp->name, catp); 626135446Strhodes else { 627135446Strhodes if (strcmp(catp->name, name) == 0) 628135446Strhodes return (catp); 629135446Strhodes catp++; 630135446Strhodes } 631135446Strhodes 632135446Strhodes return (NULL); 633135446Strhodes} 634135446Strhodes 635135446Strhodesvoid 636135446Strhodesisc_log_registermodules(isc_log_t *lctx, isc_logmodule_t modules[]) { 637135446Strhodes isc_logmodule_t *modp; 638135446Strhodes 639135446Strhodes REQUIRE(VALID_CONTEXT(lctx)); 640135446Strhodes REQUIRE(modules != NULL && modules[0].name != NULL); 641135446Strhodes 642135446Strhodes /* 643135446Strhodes * XXXDCL This somewhat sleazy situation of using the last pointer 644135446Strhodes * in one category array to point to the next array exists because 645135446Strhodes * this registration function returns void and I didn't want to have 646135446Strhodes * change everything that used it by making it return an isc_result_t. 647135446Strhodes * It would need to do that if it had to allocate memory to store 648135446Strhodes * pointers to each array passed in. 649135446Strhodes */ 650135446Strhodes if (lctx->modules == NULL) 651135446Strhodes lctx->modules = modules; 652135446Strhodes 653135446Strhodes else { 654135446Strhodes /* 655135446Strhodes * Adjust the last (NULL) pointer of the already registered 656135446Strhodes * modules to point to the incoming array. 657135446Strhodes */ 658135446Strhodes for (modp = lctx->modules; modp->name != NULL; ) 659135446Strhodes if (modp->id == UINT_MAX) 660135446Strhodes /* 661135446Strhodes * The name pointer points to the next array. 662135446Strhodes * Ick. 663135446Strhodes */ 664135446Strhodes DE_CONST(modp->name, modp); 665135446Strhodes else 666135446Strhodes modp++; 667135446Strhodes 668135446Strhodes modp->name = (void *)modules; 669135446Strhodes modp->id = UINT_MAX; 670135446Strhodes } 671135446Strhodes 672135446Strhodes /* 673135446Strhodes * Update the id number of the module with its new global id. 674135446Strhodes */ 675135446Strhodes for (modp = modules; modp->name != NULL; modp++) 676135446Strhodes modp->id = lctx->module_count++; 677135446Strhodes} 678135446Strhodes 679135446Strhodesisc_logmodule_t * 680135446Strhodesisc_log_modulebyname(isc_log_t *lctx, const char *name) { 681135446Strhodes isc_logmodule_t *modp; 682135446Strhodes 683135446Strhodes REQUIRE(VALID_CONTEXT(lctx)); 684135446Strhodes REQUIRE(name != NULL); 685135446Strhodes 686135446Strhodes for (modp = lctx->modules; modp->name != NULL; ) 687135446Strhodes if (modp->id == UINT_MAX) 688135446Strhodes /* 689135446Strhodes * modp is neither modified nor returned to the 690135446Strhodes * caller, so removing its const qualifier is ok. 691135446Strhodes */ 692135446Strhodes DE_CONST(modp->name, modp); 693135446Strhodes else { 694135446Strhodes if (strcmp(modp->name, name) == 0) 695135446Strhodes return (modp); 696135446Strhodes modp++; 697135446Strhodes } 698135446Strhodes 699135446Strhodes return (NULL); 700135446Strhodes} 701135446Strhodes 702135446Strhodesisc_result_t 703135446Strhodesisc_log_createchannel(isc_logconfig_t *lcfg, const char *name, 704135446Strhodes unsigned int type, int level, 705135446Strhodes const isc_logdestination_t *destination, 706135446Strhodes unsigned int flags) 707135446Strhodes{ 708135446Strhodes isc_logchannel_t *channel; 709135446Strhodes isc_mem_t *mctx; 710135446Strhodes 711135446Strhodes REQUIRE(VALID_CONFIG(lcfg)); 712135446Strhodes REQUIRE(name != NULL); 713135446Strhodes REQUIRE(type == ISC_LOG_TOSYSLOG || type == ISC_LOG_TOFILE || 714135446Strhodes type == ISC_LOG_TOFILEDESC || type == ISC_LOG_TONULL); 715135446Strhodes REQUIRE(destination != NULL || type == ISC_LOG_TONULL); 716135446Strhodes REQUIRE(level >= ISC_LOG_CRITICAL); 717135446Strhodes REQUIRE((flags & 718135446Strhodes (unsigned int)~(ISC_LOG_PRINTALL | ISC_LOG_DEBUGONLY)) == 0); 719135446Strhodes 720135446Strhodes /* XXXDCL find duplicate names? */ 721135446Strhodes 722135446Strhodes mctx = lcfg->lctx->mctx; 723135446Strhodes 724135446Strhodes channel = isc_mem_get(mctx, sizeof(*channel)); 725135446Strhodes if (channel == NULL) 726135446Strhodes return (ISC_R_NOMEMORY); 727135446Strhodes 728135446Strhodes channel->name = isc_mem_strdup(mctx, name); 729135446Strhodes if (channel->name == NULL) { 730135446Strhodes isc_mem_put(mctx, channel, sizeof(*channel)); 731135446Strhodes return (ISC_R_NOMEMORY); 732135446Strhodes } 733135446Strhodes 734135446Strhodes channel->type = type; 735135446Strhodes channel->level = level; 736135446Strhodes channel->flags = flags; 737135446Strhodes ISC_LINK_INIT(channel, link); 738135446Strhodes 739135446Strhodes switch (type) { 740135446Strhodes case ISC_LOG_TOSYSLOG: 741135446Strhodes FACILITY(channel) = destination->facility; 742135446Strhodes break; 743135446Strhodes 744135446Strhodes case ISC_LOG_TOFILE: 745135446Strhodes /* 746135446Strhodes * The file name is copied because greatest_version wants 747135446Strhodes * to scribble on it, so it needs to be definitely in 748135446Strhodes * writable memory. 749135446Strhodes */ 750135446Strhodes FILE_NAME(channel) = 751135446Strhodes isc_mem_strdup(mctx, destination->file.name); 752135446Strhodes FILE_STREAM(channel) = NULL; 753135446Strhodes FILE_VERSIONS(channel) = destination->file.versions; 754135446Strhodes FILE_MAXSIZE(channel) = destination->file.maximum_size; 755135446Strhodes FILE_MAXREACHED(channel) = ISC_FALSE; 756135446Strhodes break; 757135446Strhodes 758135446Strhodes case ISC_LOG_TOFILEDESC: 759135446Strhodes FILE_NAME(channel) = NULL; 760135446Strhodes FILE_STREAM(channel) = destination->file.stream; 761135446Strhodes FILE_MAXSIZE(channel) = 0; 762135446Strhodes FILE_VERSIONS(channel) = ISC_LOG_ROLLNEVER; 763135446Strhodes break; 764135446Strhodes 765135446Strhodes case ISC_LOG_TONULL: 766135446Strhodes /* Nothing. */ 767135446Strhodes break; 768135446Strhodes 769135446Strhodes default: 770262706Serwin isc_mem_free(mctx, channel->name); 771135446Strhodes isc_mem_put(mctx, channel, sizeof(*channel)); 772135446Strhodes return (ISC_R_UNEXPECTED); 773135446Strhodes } 774135446Strhodes 775135446Strhodes ISC_LIST_PREPEND(lcfg->channels, channel, link); 776135446Strhodes 777135446Strhodes /* 778135446Strhodes * If default_stderr was redefined, make the default category 779135446Strhodes * point to the new default_stderr. 780135446Strhodes */ 781135446Strhodes if (strcmp(name, "default_stderr") == 0) 782135446Strhodes default_channel.channel = channel; 783135446Strhodes 784135446Strhodes return (ISC_R_SUCCESS); 785135446Strhodes} 786135446Strhodes 787135446Strhodesisc_result_t 788135446Strhodesisc_log_usechannel(isc_logconfig_t *lcfg, const char *name, 789135446Strhodes const isc_logcategory_t *category, 790135446Strhodes const isc_logmodule_t *module) 791135446Strhodes{ 792135446Strhodes isc_log_t *lctx; 793135446Strhodes isc_logchannel_t *channel; 794135446Strhodes isc_result_t result = ISC_R_SUCCESS; 795135446Strhodes unsigned int i; 796135446Strhodes 797135446Strhodes REQUIRE(VALID_CONFIG(lcfg)); 798135446Strhodes REQUIRE(name != NULL); 799135446Strhodes 800135446Strhodes lctx = lcfg->lctx; 801135446Strhodes 802135446Strhodes REQUIRE(category == NULL || category->id < lctx->category_count); 803135446Strhodes REQUIRE(module == NULL || module->id < lctx->module_count); 804135446Strhodes 805135446Strhodes for (channel = ISC_LIST_HEAD(lcfg->channels); channel != NULL; 806135446Strhodes channel = ISC_LIST_NEXT(channel, link)) 807135446Strhodes if (strcmp(name, channel->name) == 0) 808135446Strhodes break; 809135446Strhodes 810135446Strhodes if (channel == NULL) 811135446Strhodes return (ISC_R_NOTFOUND); 812135446Strhodes 813135446Strhodes if (category != NULL) 814135446Strhodes result = assignchannel(lcfg, category->id, module, channel); 815135446Strhodes 816135446Strhodes else 817135446Strhodes /* 818135446Strhodes * Assign to all categories. Note that this includes 819135446Strhodes * the default channel. 820135446Strhodes */ 821135446Strhodes for (i = 0; i < lctx->category_count; i++) { 822135446Strhodes result = assignchannel(lcfg, i, module, channel); 823135446Strhodes if (result != ISC_R_SUCCESS) 824135446Strhodes break; 825135446Strhodes } 826135446Strhodes 827135446Strhodes return (result); 828135446Strhodes} 829135446Strhodes 830135446Strhodesvoid 831135446Strhodesisc_log_write(isc_log_t *lctx, isc_logcategory_t *category, 832135446Strhodes isc_logmodule_t *module, int level, const char *format, ...) 833135446Strhodes{ 834135446Strhodes va_list args; 835135446Strhodes 836135446Strhodes /* 837135446Strhodes * Contract checking is done in isc_log_doit(). 838135446Strhodes */ 839135446Strhodes 840135446Strhodes va_start(args, format); 841135446Strhodes isc_log_doit(lctx, category, module, level, ISC_FALSE, 842135446Strhodes NULL, 0, 0, format, args); 843135446Strhodes va_end(args); 844135446Strhodes} 845135446Strhodes 846135446Strhodesvoid 847135446Strhodesisc_log_vwrite(isc_log_t *lctx, isc_logcategory_t *category, 848135446Strhodes isc_logmodule_t *module, int level, 849135446Strhodes const char *format, va_list args) 850135446Strhodes{ 851135446Strhodes /* 852135446Strhodes * Contract checking is done in isc_log_doit(). 853135446Strhodes */ 854135446Strhodes isc_log_doit(lctx, category, module, level, ISC_FALSE, 855135446Strhodes NULL, 0, 0, format, args); 856135446Strhodes} 857135446Strhodes 858135446Strhodesvoid 859135446Strhodesisc_log_write1(isc_log_t *lctx, isc_logcategory_t *category, 860135446Strhodes isc_logmodule_t *module, int level, const char *format, ...) 861135446Strhodes{ 862135446Strhodes va_list args; 863135446Strhodes 864135446Strhodes /* 865135446Strhodes * Contract checking is done in isc_log_doit(). 866135446Strhodes */ 867135446Strhodes 868135446Strhodes va_start(args, format); 869135446Strhodes isc_log_doit(lctx, category, module, level, ISC_TRUE, 870135446Strhodes NULL, 0, 0, format, args); 871135446Strhodes va_end(args); 872135446Strhodes} 873135446Strhodes 874135446Strhodesvoid 875135446Strhodesisc_log_vwrite1(isc_log_t *lctx, isc_logcategory_t *category, 876135446Strhodes isc_logmodule_t *module, int level, 877135446Strhodes const char *format, va_list args) 878135446Strhodes{ 879135446Strhodes /* 880135446Strhodes * Contract checking is done in isc_log_doit(). 881135446Strhodes */ 882135446Strhodes isc_log_doit(lctx, category, module, level, ISC_TRUE, 883135446Strhodes NULL, 0, 0, format, args); 884135446Strhodes} 885135446Strhodes 886135446Strhodesvoid 887135446Strhodesisc_log_iwrite(isc_log_t *lctx, isc_logcategory_t *category, 888135446Strhodes isc_logmodule_t *module, int level, 889135446Strhodes isc_msgcat_t *msgcat, int msgset, int msg, 890135446Strhodes const char *format, ...) 891135446Strhodes{ 892135446Strhodes va_list args; 893135446Strhodes 894135446Strhodes /* 895135446Strhodes * Contract checking is done in isc_log_doit(). 896135446Strhodes */ 897135446Strhodes 898135446Strhodes va_start(args, format); 899135446Strhodes isc_log_doit(lctx, category, module, level, ISC_FALSE, 900135446Strhodes msgcat, msgset, msg, format, args); 901135446Strhodes va_end(args); 902135446Strhodes} 903135446Strhodes 904135446Strhodesvoid 905135446Strhodesisc_log_ivwrite(isc_log_t *lctx, isc_logcategory_t *category, 906135446Strhodes isc_logmodule_t *module, int level, 907135446Strhodes isc_msgcat_t *msgcat, int msgset, int msg, 908135446Strhodes const char *format, va_list args) 909135446Strhodes{ 910135446Strhodes /* 911135446Strhodes * Contract checking is done in isc_log_doit(). 912135446Strhodes */ 913135446Strhodes isc_log_doit(lctx, category, module, level, ISC_FALSE, 914135446Strhodes msgcat, msgset, msg, format, args); 915135446Strhodes} 916135446Strhodes 917135446Strhodesvoid 918135446Strhodesisc_log_iwrite1(isc_log_t *lctx, isc_logcategory_t *category, 919135446Strhodes isc_logmodule_t *module, int level, 920135446Strhodes isc_msgcat_t *msgcat, int msgset, int msg, 921135446Strhodes const char *format, ...) 922135446Strhodes{ 923135446Strhodes va_list args; 924135446Strhodes 925135446Strhodes /* 926135446Strhodes * Contract checking is done in isc_log_doit(). 927135446Strhodes */ 928135446Strhodes 929135446Strhodes va_start(args, format); 930135446Strhodes isc_log_doit(lctx, category, module, level, ISC_TRUE, 931135446Strhodes msgcat, msgset, msg, format, args); 932135446Strhodes va_end(args); 933135446Strhodes} 934135446Strhodes 935135446Strhodesvoid 936135446Strhodesisc_log_ivwrite1(isc_log_t *lctx, isc_logcategory_t *category, 937135446Strhodes isc_logmodule_t *module, int level, 938135446Strhodes isc_msgcat_t *msgcat, int msgset, int msg, 939135446Strhodes const char *format, va_list args) 940135446Strhodes{ 941135446Strhodes /* 942135446Strhodes * Contract checking is done in isc_log_doit(). 943135446Strhodes */ 944135446Strhodes isc_log_doit(lctx, category, module, level, ISC_TRUE, 945135446Strhodes msgcat, msgset, msg, format, args); 946135446Strhodes} 947135446Strhodes 948135446Strhodesvoid 949135446Strhodesisc_log_setcontext(isc_log_t *lctx) { 950135446Strhodes isc_lctx = lctx; 951135446Strhodes} 952135446Strhodes 953135446Strhodesvoid 954135446Strhodesisc_log_setdebuglevel(isc_log_t *lctx, unsigned int level) { 955135446Strhodes isc_logchannel_t *channel; 956135446Strhodes 957135446Strhodes REQUIRE(VALID_CONTEXT(lctx)); 958135446Strhodes 959135446Strhodes LOCK(&lctx->lock); 960135446Strhodes 961135446Strhodes lctx->debug_level = level; 962135446Strhodes /* 963135446Strhodes * Close ISC_LOG_DEBUGONLY channels if level is zero. 964135446Strhodes */ 965135446Strhodes if (lctx->debug_level == 0) 966135446Strhodes for (channel = ISC_LIST_HEAD(lctx->logconfig->channels); 967135446Strhodes channel != NULL; 968135446Strhodes channel = ISC_LIST_NEXT(channel, link)) 969135446Strhodes if (channel->type == ISC_LOG_TOFILE && 970135446Strhodes (channel->flags & ISC_LOG_DEBUGONLY) != 0 && 971135446Strhodes FILE_STREAM(channel) != NULL) { 972135446Strhodes (void)fclose(FILE_STREAM(channel)); 973135446Strhodes FILE_STREAM(channel) = NULL; 974135446Strhodes } 975135446Strhodes UNLOCK(&lctx->lock); 976135446Strhodes} 977135446Strhodes 978135446Strhodesunsigned int 979135446Strhodesisc_log_getdebuglevel(isc_log_t *lctx) { 980135446Strhodes REQUIRE(VALID_CONTEXT(lctx)); 981135446Strhodes 982135446Strhodes return (lctx->debug_level); 983135446Strhodes} 984135446Strhodes 985135446Strhodesvoid 986135446Strhodesisc_log_setduplicateinterval(isc_logconfig_t *lcfg, unsigned int interval) { 987135446Strhodes REQUIRE(VALID_CONFIG(lcfg)); 988135446Strhodes 989135446Strhodes lcfg->duplicate_interval = interval; 990135446Strhodes} 991135446Strhodes 992135446Strhodesunsigned int 993135446Strhodesisc_log_getduplicateinterval(isc_logconfig_t *lcfg) { 994135446Strhodes REQUIRE(VALID_CONTEXT(lcfg)); 995135446Strhodes 996135446Strhodes return (lcfg->duplicate_interval); 997135446Strhodes} 998135446Strhodes 999135446Strhodesisc_result_t 1000135446Strhodesisc_log_settag(isc_logconfig_t *lcfg, const char *tag) { 1001135446Strhodes REQUIRE(VALID_CONFIG(lcfg)); 1002135446Strhodes 1003135446Strhodes if (tag != NULL && *tag != '\0') { 1004135446Strhodes if (lcfg->tag != NULL) 1005135446Strhodes isc_mem_free(lcfg->lctx->mctx, lcfg->tag); 1006135446Strhodes lcfg->tag = isc_mem_strdup(lcfg->lctx->mctx, tag); 1007135446Strhodes if (lcfg->tag == NULL) 1008135446Strhodes return (ISC_R_NOMEMORY); 1009135446Strhodes 1010135446Strhodes } else { 1011135446Strhodes if (lcfg->tag != NULL) 1012135446Strhodes isc_mem_free(lcfg->lctx->mctx, lcfg->tag); 1013135446Strhodes lcfg->tag = NULL; 1014135446Strhodes } 1015135446Strhodes 1016135446Strhodes return (ISC_R_SUCCESS); 1017135446Strhodes} 1018135446Strhodes 1019135446Strhodeschar * 1020135446Strhodesisc_log_gettag(isc_logconfig_t *lcfg) { 1021135446Strhodes REQUIRE(VALID_CONFIG(lcfg)); 1022135446Strhodes 1023135446Strhodes return (lcfg->tag); 1024135446Strhodes} 1025135446Strhodes 1026135446Strhodes/* XXXDCL NT -- This interface will assuredly be changing. */ 1027135446Strhodesvoid 1028135446Strhodesisc_log_opensyslog(const char *tag, int options, int facility) { 1029135446Strhodes (void)openlog(tag, options, facility); 1030135446Strhodes} 1031135446Strhodes 1032135446Strhodesvoid 1033135446Strhodesisc_log_closefilelogs(isc_log_t *lctx) { 1034135446Strhodes isc_logchannel_t *channel; 1035135446Strhodes 1036135446Strhodes REQUIRE(VALID_CONTEXT(lctx)); 1037135446Strhodes 1038135446Strhodes LOCK(&lctx->lock); 1039135446Strhodes for (channel = ISC_LIST_HEAD(lctx->logconfig->channels); 1040135446Strhodes channel != NULL; 1041135446Strhodes channel = ISC_LIST_NEXT(channel, link)) 1042135446Strhodes 1043135446Strhodes if (channel->type == ISC_LOG_TOFILE && 1044135446Strhodes FILE_STREAM(channel) != NULL) { 1045135446Strhodes (void)fclose(FILE_STREAM(channel)); 1046135446Strhodes FILE_STREAM(channel) = NULL; 1047135446Strhodes } 1048135446Strhodes UNLOCK(&lctx->lock); 1049135446Strhodes} 1050135446Strhodes 1051135446Strhodes/**** 1052135446Strhodes **** Internal functions 1053135446Strhodes ****/ 1054135446Strhodes 1055135446Strhodesstatic isc_result_t 1056135446Strhodesassignchannel(isc_logconfig_t *lcfg, unsigned int category_id, 1057135446Strhodes const isc_logmodule_t *module, isc_logchannel_t *channel) 1058135446Strhodes{ 1059135446Strhodes isc_logchannellist_t *new_item; 1060135446Strhodes isc_log_t *lctx; 1061135446Strhodes isc_result_t result; 1062135446Strhodes 1063135446Strhodes REQUIRE(VALID_CONFIG(lcfg)); 1064135446Strhodes 1065135446Strhodes lctx = lcfg->lctx; 1066135446Strhodes 1067135446Strhodes REQUIRE(category_id < lctx->category_count); 1068135446Strhodes REQUIRE(module == NULL || module->id < lctx->module_count); 1069135446Strhodes REQUIRE(channel != NULL); 1070135446Strhodes 1071135446Strhodes /* 1072135446Strhodes * Ensure lcfg->channellist_count == lctx->category_count. 1073135446Strhodes */ 1074135446Strhodes result = sync_channellist(lcfg); 1075135446Strhodes if (result != ISC_R_SUCCESS) 1076135446Strhodes return (result); 1077135446Strhodes 1078135446Strhodes new_item = isc_mem_get(lctx->mctx, sizeof(*new_item)); 1079135446Strhodes if (new_item == NULL) 1080135446Strhodes return (ISC_R_NOMEMORY); 1081135446Strhodes 1082135446Strhodes new_item->channel = channel; 1083135446Strhodes new_item->module = module; 1084135446Strhodes ISC_LIST_INITANDPREPEND(lcfg->channellists[category_id], 1085135446Strhodes new_item, link); 1086135446Strhodes 1087135446Strhodes /* 1088135446Strhodes * Remember the highest logging level set by any channel in the 1089135446Strhodes * logging config, so isc_log_doit() can quickly return if the 1090135446Strhodes * message is too high to be logged by any channel. 1091135446Strhodes */ 1092135446Strhodes if (channel->type != ISC_LOG_TONULL) { 1093135446Strhodes if (lcfg->highest_level < channel->level) 1094135446Strhodes lcfg->highest_level = channel->level; 1095135446Strhodes if (channel->level == ISC_LOG_DYNAMIC) 1096135446Strhodes lcfg->dynamic = ISC_TRUE; 1097135446Strhodes } 1098135446Strhodes 1099135446Strhodes return (ISC_R_SUCCESS); 1100135446Strhodes} 1101135446Strhodes 1102135446Strhodes/* 1103135446Strhodes * This would ideally be part of isc_log_registercategories(), except then 1104135446Strhodes * that function would have to return isc_result_t instead of void. 1105135446Strhodes */ 1106135446Strhodesstatic isc_result_t 1107135446Strhodessync_channellist(isc_logconfig_t *lcfg) { 1108135446Strhodes unsigned int bytes; 1109135446Strhodes isc_log_t *lctx; 1110135446Strhodes void *lists; 1111135446Strhodes 1112135446Strhodes REQUIRE(VALID_CONFIG(lcfg)); 1113135446Strhodes 1114135446Strhodes lctx = lcfg->lctx; 1115135446Strhodes 1116135446Strhodes REQUIRE(lctx->category_count != 0); 1117135446Strhodes 1118135446Strhodes if (lctx->category_count == lcfg->channellist_count) 1119135446Strhodes return (ISC_R_SUCCESS); 1120135446Strhodes 1121135446Strhodes bytes = lctx->category_count * sizeof(ISC_LIST(isc_logchannellist_t)); 1122135446Strhodes 1123135446Strhodes lists = isc_mem_get(lctx->mctx, bytes); 1124135446Strhodes 1125135446Strhodes if (lists == NULL) 1126135446Strhodes return (ISC_R_NOMEMORY); 1127135446Strhodes 1128135446Strhodes memset(lists, 0, bytes); 1129135446Strhodes 1130135446Strhodes if (lcfg->channellist_count != 0) { 1131135446Strhodes bytes = lcfg->channellist_count * 1132135446Strhodes sizeof(ISC_LIST(isc_logchannellist_t)); 1133262706Serwin memmove(lists, lcfg->channellists, bytes); 1134135446Strhodes isc_mem_put(lctx->mctx, lcfg->channellists, bytes); 1135135446Strhodes } 1136135446Strhodes 1137135446Strhodes lcfg->channellists = lists; 1138135446Strhodes lcfg->channellist_count = lctx->category_count; 1139135446Strhodes 1140135446Strhodes return (ISC_R_SUCCESS); 1141135446Strhodes} 1142135446Strhodes 1143135446Strhodesstatic isc_result_t 1144135446Strhodesgreatest_version(isc_logchannel_t *channel, int *greatestp) { 1145135446Strhodes /* XXXDCL HIGHLY NT */ 1146135446Strhodes char *basename, *digit_end; 1147135446Strhodes const char *dirname; 1148135446Strhodes int version, greatest = -1; 1149262706Serwin size_t basenamelen; 1150135446Strhodes isc_dir_t dir; 1151135446Strhodes isc_result_t result; 1152135446Strhodes char sep = '/'; 1153135446Strhodes#ifdef _WIN32 1154135446Strhodes char *basename2; 1155135446Strhodes#endif 1156135446Strhodes 1157135446Strhodes REQUIRE(channel->type == ISC_LOG_TOFILE); 1158135446Strhodes 1159135446Strhodes /* 1160135446Strhodes * It is safe to DE_CONST the file.name because it was copied 1161135446Strhodes * with isc_mem_strdup in isc_log_createchannel. 1162135446Strhodes */ 1163135446Strhodes basename = strrchr(FILE_NAME(channel), sep); 1164135446Strhodes#ifdef _WIN32 1165135446Strhodes basename2 = strrchr(FILE_NAME(channel), '\\'); 1166135446Strhodes if ((basename != NULL && basename2 != NULL && basename2 > basename) || 1167135446Strhodes (basename == NULL && basename2 != NULL)) { 1168135446Strhodes basename = basename2; 1169135446Strhodes sep = '\\'; 1170135446Strhodes } 1171135446Strhodes#endif 1172135446Strhodes if (basename != NULL) { 1173135446Strhodes *basename++ = '\0'; 1174135446Strhodes dirname = FILE_NAME(channel); 1175135446Strhodes } else { 1176135446Strhodes DE_CONST(FILE_NAME(channel), basename); 1177135446Strhodes dirname = "."; 1178135446Strhodes } 1179135446Strhodes basenamelen = strlen(basename); 1180135446Strhodes 1181135446Strhodes isc_dir_init(&dir); 1182135446Strhodes result = isc_dir_open(&dir, dirname); 1183135446Strhodes 1184135446Strhodes /* 1185135446Strhodes * Replace the file separator if it was taken out. 1186135446Strhodes */ 1187135446Strhodes if (basename != FILE_NAME(channel)) 1188135446Strhodes *(basename - 1) = sep; 1189135446Strhodes 1190135446Strhodes /* 1191135446Strhodes * Return if the directory open failed. 1192135446Strhodes */ 1193135446Strhodes if (result != ISC_R_SUCCESS) 1194135446Strhodes return (result); 1195135446Strhodes 1196135446Strhodes while (isc_dir_read(&dir) == ISC_R_SUCCESS) { 1197135446Strhodes if (dir.entry.length > basenamelen && 1198135446Strhodes strncmp(dir.entry.name, basename, basenamelen) == 0 && 1199135446Strhodes dir.entry.name[basenamelen] == '.') { 1200135446Strhodes 1201135446Strhodes version = strtol(&dir.entry.name[basenamelen + 1], 1202135446Strhodes &digit_end, 10); 1203135446Strhodes if (*digit_end == '\0' && version > greatest) 1204135446Strhodes greatest = version; 1205135446Strhodes } 1206135446Strhodes } 1207135446Strhodes isc_dir_close(&dir); 1208135446Strhodes 1209135446Strhodes *greatestp = ++greatest; 1210135446Strhodes 1211135446Strhodes return (ISC_R_SUCCESS); 1212135446Strhodes} 1213135446Strhodes 1214135446Strhodesstatic isc_result_t 1215135446Strhodesroll_log(isc_logchannel_t *channel) { 1216135446Strhodes int i, n, greatest; 1217135446Strhodes char current[PATH_MAX + 1]; 1218135446Strhodes char new[PATH_MAX + 1]; 1219135446Strhodes const char *path; 1220135446Strhodes isc_result_t result; 1221135446Strhodes 1222135446Strhodes /* 1223135446Strhodes * Do nothing (not even excess version trimming) if ISC_LOG_ROLLNEVER 1224135446Strhodes * is specified. Apparently complete external control over the log 1225135446Strhodes * files is desired. 1226135446Strhodes */ 1227135446Strhodes if (FILE_VERSIONS(channel) == ISC_LOG_ROLLNEVER) 1228135446Strhodes return (ISC_R_SUCCESS); 1229135446Strhodes 1230135446Strhodes path = FILE_NAME(channel); 1231135446Strhodes 1232135446Strhodes /* 1233135446Strhodes * Set greatest_version to the greatest existing version 1234135446Strhodes * (not the maximum requested version). This is 1 based even 1235135446Strhodes * though the file names are 0 based, so an oldest log of log.1 1236135446Strhodes * is a greatest_version of 2. 1237135446Strhodes */ 1238135446Strhodes result = greatest_version(channel, &greatest); 1239135446Strhodes if (result != ISC_R_SUCCESS) 1240135446Strhodes return (result); 1241135446Strhodes 1242135446Strhodes /* 1243135446Strhodes * Now greatest should be set to the highest version number desired. 1244135446Strhodes * Since the highest number is one less than FILE_VERSIONS(channel) 1245135446Strhodes * when not doing infinite log rolling, greatest will need to be 1246135446Strhodes * decremented when it is equal to -- or greater than -- 1247135446Strhodes * FILE_VERSIONS(channel). When greatest is less than 1248135446Strhodes * FILE_VERSIONS(channel), it is already suitable for use as 1249135446Strhodes * the maximum version number. 1250135446Strhodes */ 1251135446Strhodes 1252135446Strhodes if (FILE_VERSIONS(channel) == ISC_LOG_ROLLINFINITE || 1253135446Strhodes FILE_VERSIONS(channel) > greatest) 1254135446Strhodes ; /* Do nothing. */ 1255135446Strhodes else 1256135446Strhodes /* 1257135446Strhodes * When greatest is >= FILE_VERSIONS(channel), it needs to 1258135446Strhodes * be reduced until it is FILE_VERSIONS(channel) - 1. 1259135446Strhodes * Remove any excess logs on the way to that value. 1260135446Strhodes */ 1261135446Strhodes while (--greatest >= FILE_VERSIONS(channel)) { 1262135446Strhodes n = snprintf(current, sizeof(current), "%s.%d", 1263135446Strhodes path, greatest); 1264135446Strhodes if (n >= (int)sizeof(current) || n < 0) 1265135446Strhodes result = ISC_R_NOSPACE; 1266135446Strhodes else 1267135446Strhodes result = isc_file_remove(current); 1268135446Strhodes if (result != ISC_R_SUCCESS && 1269135446Strhodes result != ISC_R_FILENOTFOUND) 1270135446Strhodes syslog(LOG_ERR, 1271135446Strhodes "unable to remove log file '%s.%d': %s", 1272135446Strhodes path, greatest, 1273135446Strhodes isc_result_totext(result)); 1274135446Strhodes } 1275135446Strhodes 1276135446Strhodes for (i = greatest; i > 0; i--) { 1277135446Strhodes result = ISC_R_SUCCESS; 1278135446Strhodes n = snprintf(current, sizeof(current), "%s.%d", path, i - 1); 1279135446Strhodes if (n >= (int)sizeof(current) || n < 0) 1280135446Strhodes result = ISC_R_NOSPACE; 1281135446Strhodes if (result == ISC_R_SUCCESS) { 1282135446Strhodes n = snprintf(new, sizeof(new), "%s.%d", path, i); 1283135446Strhodes if (n >= (int)sizeof(new) || n < 0) 1284135446Strhodes result = ISC_R_NOSPACE; 1285135446Strhodes } 1286135446Strhodes if (result == ISC_R_SUCCESS) 1287135446Strhodes result = isc_file_rename(current, new); 1288135446Strhodes if (result != ISC_R_SUCCESS && 1289135446Strhodes result != ISC_R_FILENOTFOUND) 1290135446Strhodes syslog(LOG_ERR, 1291135446Strhodes "unable to rename log file '%s.%d' to " 1292135446Strhodes "'%s.%d': %s", path, i - 1, path, i, 1293135446Strhodes isc_result_totext(result)); 1294135446Strhodes } 1295135446Strhodes 1296135446Strhodes if (FILE_VERSIONS(channel) != 0) { 1297135446Strhodes n = snprintf(new, sizeof(new), "%s.0", path); 1298135446Strhodes if (n >= (int)sizeof(new) || n < 0) 1299135446Strhodes result = ISC_R_NOSPACE; 1300135446Strhodes else 1301135446Strhodes result = isc_file_rename(path, new); 1302135446Strhodes if (result != ISC_R_SUCCESS && 1303135446Strhodes result != ISC_R_FILENOTFOUND) 1304135446Strhodes syslog(LOG_ERR, 1305135446Strhodes "unable to rename log file '%s' to '%s.0': %s", 1306135446Strhodes path, path, isc_result_totext(result)); 1307135446Strhodes } else { 1308135446Strhodes result = isc_file_remove(path); 1309135446Strhodes if (result != ISC_R_SUCCESS && 1310135446Strhodes result != ISC_R_FILENOTFOUND) 1311135446Strhodes syslog(LOG_ERR, "unable to remove log file '%s': %s", 1312135446Strhodes path, isc_result_totext(result)); 1313135446Strhodes } 1314135446Strhodes 1315135446Strhodes return (ISC_R_SUCCESS); 1316135446Strhodes} 1317135446Strhodes 1318135446Strhodesstatic isc_result_t 1319135446Strhodesisc_log_open(isc_logchannel_t *channel) { 1320135446Strhodes struct stat statbuf; 1321135446Strhodes isc_boolean_t regular_file; 1322135446Strhodes isc_boolean_t roll = ISC_FALSE; 1323135446Strhodes isc_result_t result = ISC_R_SUCCESS; 1324135446Strhodes const char *path; 1325135446Strhodes 1326135446Strhodes REQUIRE(channel->type == ISC_LOG_TOFILE); 1327135446Strhodes REQUIRE(FILE_STREAM(channel) == NULL); 1328135446Strhodes 1329135446Strhodes path = FILE_NAME(channel); 1330135446Strhodes 1331135446Strhodes REQUIRE(path != NULL && *path != '\0'); 1332135446Strhodes 1333135446Strhodes /* 1334135446Strhodes * Determine type of file; only regular files will be 1335135446Strhodes * version renamed, and only if the base file exists 1336135446Strhodes * and either has no size limit or has reached its size limit. 1337135446Strhodes */ 1338135446Strhodes if (stat(path, &statbuf) == 0) { 1339135446Strhodes regular_file = S_ISREG(statbuf.st_mode) ? ISC_TRUE : ISC_FALSE; 1340135446Strhodes /* XXXDCL if not regular_file complain? */ 1341135446Strhodes if ((FILE_MAXSIZE(channel) == 0 && 1342135446Strhodes FILE_VERSIONS(channel) != ISC_LOG_ROLLNEVER) || 1343135446Strhodes (FILE_MAXSIZE(channel) > 0 && 1344135446Strhodes statbuf.st_size >= FILE_MAXSIZE(channel))) 1345135446Strhodes roll = regular_file; 1346225361Sdougb } else if (errno == ENOENT) { 1347135446Strhodes regular_file = ISC_TRUE; 1348225361Sdougb POST(regular_file); 1349225361Sdougb } else 1350135446Strhodes result = ISC_R_INVALIDFILE; 1351135446Strhodes 1352135446Strhodes /* 1353135446Strhodes * Version control. 1354135446Strhodes */ 1355135446Strhodes if (result == ISC_R_SUCCESS && roll) { 1356135446Strhodes if (FILE_VERSIONS(channel) == ISC_LOG_ROLLNEVER) 1357135446Strhodes return (ISC_R_MAXSIZE); 1358135446Strhodes result = roll_log(channel); 1359135446Strhodes if (result != ISC_R_SUCCESS) { 1360135446Strhodes if ((channel->flags & ISC_LOG_OPENERR) == 0) { 1361135446Strhodes syslog(LOG_ERR, 1362135446Strhodes "isc_log_open: roll_log '%s' " 1363135446Strhodes "failed: %s", 1364135446Strhodes FILE_NAME(channel), 1365135446Strhodes isc_result_totext(result)); 1366135446Strhodes channel->flags |= ISC_LOG_OPENERR; 1367135446Strhodes } 1368135446Strhodes return (result); 1369135446Strhodes } 1370135446Strhodes } 1371135446Strhodes 1372135446Strhodes result = isc_stdio_open(path, "a", &FILE_STREAM(channel)); 1373135446Strhodes 1374135446Strhodes return (result); 1375135446Strhodes} 1376135446Strhodes 1377135446Strhodesisc_boolean_t 1378135446Strhodesisc_log_wouldlog(isc_log_t *lctx, int level) { 1379135446Strhodes /* 1380135446Strhodes * Try to avoid locking the mutex for messages which can't 1381135446Strhodes * possibly be logged to any channels -- primarily debugging 1382135446Strhodes * messages that the debug level is not high enough to print. 1383135446Strhodes * 1384135446Strhodes * If the level is (mathematically) less than or equal to the 1385135446Strhodes * highest_level, or if there is a dynamic channel and the level is 1386135446Strhodes * less than or equal to the debug level, the main loop must be 1387135446Strhodes * entered to see if the message should really be output. 1388135446Strhodes * 1389135446Strhodes * NOTE: this is UNLOCKED access to the logconfig. However, 1390135446Strhodes * the worst thing that can happen is that a bad decision is made 1391135446Strhodes * about returning without logging, and that's not a big concern, 1392135446Strhodes * because that's a risk anyway if the logconfig is being 1393135446Strhodes * dynamically changed. 1394135446Strhodes */ 1395135446Strhodes 1396135446Strhodes if (lctx == NULL || lctx->logconfig == NULL) 1397135446Strhodes return (ISC_FALSE); 1398135446Strhodes 1399135446Strhodes return (ISC_TF(level <= lctx->logconfig->highest_level || 1400135446Strhodes (lctx->logconfig->dynamic && 1401135446Strhodes level <= lctx->debug_level))); 1402135446Strhodes} 1403135446Strhodes 1404135446Strhodesstatic void 1405135446Strhodesisc_log_doit(isc_log_t *lctx, isc_logcategory_t *category, 1406135446Strhodes isc_logmodule_t *module, int level, isc_boolean_t write_once, 1407135446Strhodes isc_msgcat_t *msgcat, int msgset, int msg, 1408135446Strhodes const char *format, va_list args) 1409135446Strhodes{ 1410135446Strhodes int syslog_level; 1411135446Strhodes char time_string[64]; 1412135446Strhodes char level_string[24]; 1413135446Strhodes const char *iformat; 1414135446Strhodes struct stat statbuf; 1415135446Strhodes isc_boolean_t matched = ISC_FALSE; 1416135446Strhodes isc_boolean_t printtime, printtag; 1417135446Strhodes isc_boolean_t printcategory, printmodule, printlevel; 1418135446Strhodes isc_logconfig_t *lcfg; 1419135446Strhodes isc_logchannel_t *channel; 1420135446Strhodes isc_logchannellist_t *category_channels; 1421135446Strhodes isc_result_t result; 1422135446Strhodes 1423135446Strhodes REQUIRE(lctx == NULL || VALID_CONTEXT(lctx)); 1424135446Strhodes REQUIRE(category != NULL); 1425135446Strhodes REQUIRE(module != NULL); 1426135446Strhodes REQUIRE(level != ISC_LOG_DYNAMIC); 1427135446Strhodes REQUIRE(format != NULL); 1428135446Strhodes 1429135446Strhodes /* 1430135446Strhodes * Programs can use libraries that use this logging code without 1431135446Strhodes * wanting to do any logging, thus the log context is allowed to 1432135446Strhodes * be non-existent. 1433135446Strhodes */ 1434135446Strhodes if (lctx == NULL) 1435135446Strhodes return; 1436135446Strhodes 1437135446Strhodes REQUIRE(category->id < lctx->category_count); 1438135446Strhodes REQUIRE(module->id < lctx->module_count); 1439135446Strhodes 1440135446Strhodes if (! isc_log_wouldlog(lctx, level)) 1441135446Strhodes return; 1442135446Strhodes 1443135446Strhodes if (msgcat != NULL) 1444135446Strhodes iformat = isc_msgcat_get(msgcat, msgset, msg, format); 1445135446Strhodes else 1446135446Strhodes iformat = format; 1447135446Strhodes 1448135446Strhodes time_string[0] = '\0'; 1449135446Strhodes level_string[0] = '\0'; 1450135446Strhodes 1451135446Strhodes LOCK(&lctx->lock); 1452135446Strhodes 1453135446Strhodes lctx->buffer[0] = '\0'; 1454193149Sdougb 1455135446Strhodes lcfg = lctx->logconfig; 1456135446Strhodes 1457135446Strhodes category_channels = ISC_LIST_HEAD(lcfg->channellists[category->id]); 1458135446Strhodes 1459135446Strhodes /* 1460135446Strhodes * XXXDCL add duplicate filtering? (To not write multiple times to 1461135446Strhodes * the same source via various channels). 1462135446Strhodes */ 1463135446Strhodes do { 1464135446Strhodes /* 1465135446Strhodes * If the channel list end was reached and a match was made, 1466135446Strhodes * everything is finished. 1467135446Strhodes */ 1468135446Strhodes if (category_channels == NULL && matched) 1469135446Strhodes break; 1470135446Strhodes 1471135446Strhodes if (category_channels == NULL && ! matched && 1472135446Strhodes category_channels != ISC_LIST_HEAD(lcfg->channellists[0])) 1473135446Strhodes /* 1474135446Strhodes * No category/module pair was explicitly configured. 1475135446Strhodes * Try the category named "default". 1476135446Strhodes */ 1477135446Strhodes category_channels = 1478135446Strhodes ISC_LIST_HEAD(lcfg->channellists[0]); 1479135446Strhodes 1480135446Strhodes if (category_channels == NULL && ! matched) 1481135446Strhodes /* 1482135446Strhodes * No matching module was explicitly configured 1483135446Strhodes * for the category named "default". Use the internal 1484135446Strhodes * default channel. 1485135446Strhodes */ 1486135446Strhodes category_channels = &default_channel; 1487135446Strhodes 1488135446Strhodes if (category_channels->module != NULL && 1489135446Strhodes category_channels->module != module) { 1490135446Strhodes category_channels = ISC_LIST_NEXT(category_channels, 1491135446Strhodes link); 1492135446Strhodes continue; 1493135446Strhodes } 1494135446Strhodes 1495135446Strhodes matched = ISC_TRUE; 1496135446Strhodes 1497135446Strhodes channel = category_channels->channel; 1498135446Strhodes category_channels = ISC_LIST_NEXT(category_channels, link); 1499135446Strhodes 1500135446Strhodes if (((channel->flags & ISC_LOG_DEBUGONLY) != 0) && 1501135446Strhodes lctx->debug_level == 0) 1502135446Strhodes continue; 1503135446Strhodes 1504135446Strhodes if (channel->level == ISC_LOG_DYNAMIC) { 1505135446Strhodes if (lctx->debug_level < level) 1506135446Strhodes continue; 1507135446Strhodes } else if (channel->level < level) 1508135446Strhodes continue; 1509135446Strhodes 1510135446Strhodes if ((channel->flags & ISC_LOG_PRINTTIME) != 0 && 1511135446Strhodes time_string[0] == '\0') { 1512135446Strhodes isc_time_t isctime; 1513193149Sdougb 1514135446Strhodes TIME_NOW(&isctime); 1515135446Strhodes isc_time_formattimestamp(&isctime, time_string, 1516135446Strhodes sizeof(time_string)); 1517135446Strhodes } 1518135446Strhodes 1519135446Strhodes if ((channel->flags & ISC_LOG_PRINTLEVEL) != 0 && 1520135446Strhodes level_string[0] == '\0') { 1521135446Strhodes if (level < ISC_LOG_CRITICAL) 1522135446Strhodes snprintf(level_string, sizeof(level_string), 1523135446Strhodes isc_msgcat_get(isc_msgcat, 1524193149Sdougb ISC_MSGSET_LOG, 1525193149Sdougb ISC_MSG_LEVEL, 1526193149Sdougb "level %d: "), 1527135446Strhodes level); 1528135446Strhodes else if (level > ISC_LOG_DYNAMIC) 1529135446Strhodes snprintf(level_string, sizeof(level_string), 1530135446Strhodes "%s %d: ", log_level_strings[0], 1531135446Strhodes level); 1532135446Strhodes else 1533135446Strhodes snprintf(level_string, sizeof(level_string), 1534135446Strhodes "%s: ", log_level_strings[-level]); 1535135446Strhodes } 1536135446Strhodes 1537135446Strhodes /* 1538135446Strhodes * Only format the message once. 1539135446Strhodes */ 1540135446Strhodes if (lctx->buffer[0] == '\0') { 1541135446Strhodes (void)vsnprintf(lctx->buffer, sizeof(lctx->buffer), 1542135446Strhodes iformat, args); 1543135446Strhodes 1544135446Strhodes /* 1545135446Strhodes * Check for duplicates. 1546135446Strhodes */ 1547135446Strhodes if (write_once) { 1548135446Strhodes isc_logmessage_t *message, *new; 1549135446Strhodes isc_time_t oldest; 1550135446Strhodes isc_interval_t interval; 1551135446Strhodes 1552135446Strhodes isc_interval_set(&interval, 1553135446Strhodes lcfg->duplicate_interval, 0); 1554135446Strhodes 1555135446Strhodes /* 1556135446Strhodes * 'oldest' is the age of the oldest messages 1557135446Strhodes * which fall within the duplicate_interval 1558135446Strhodes * range. 1559135446Strhodes */ 1560135446Strhodes TIME_NOW(&oldest); 1561135446Strhodes if (isc_time_subtract(&oldest, &interval, &oldest) 1562135446Strhodes != ISC_R_SUCCESS) 1563135446Strhodes /* 1564135446Strhodes * Can't effectively do the checking 1565135446Strhodes * without having a valid time. 1566135446Strhodes */ 1567135446Strhodes message = NULL; 1568135446Strhodes else 1569135446Strhodes message =ISC_LIST_HEAD(lctx->messages); 1570135446Strhodes 1571135446Strhodes while (message != NULL) { 1572135446Strhodes if (isc_time_compare(&message->time, 1573135446Strhodes &oldest) < 0) { 1574135446Strhodes /* 1575135446Strhodes * This message is older 1576135446Strhodes * than the duplicate_interval, 1577135446Strhodes * so it should be dropped from 1578135446Strhodes * the history. 1579135446Strhodes * 1580135446Strhodes * Setting the interval to be 1581135446Strhodes * to be longer will obviously 1582135446Strhodes * not cause the expired 1583135446Strhodes * message to spring back into 1584135446Strhodes * existence. 1585135446Strhodes */ 1586135446Strhodes new = ISC_LIST_NEXT(message, 1587135446Strhodes link); 1588135446Strhodes 1589135446Strhodes ISC_LIST_UNLINK(lctx->messages, 1590135446Strhodes message, link); 1591135446Strhodes 1592135446Strhodes isc_mem_put(lctx->mctx, 1593135446Strhodes message, 1594135446Strhodes sizeof(*message) + 1 + 1595135446Strhodes strlen(message->text)); 1596135446Strhodes 1597135446Strhodes message = new; 1598135446Strhodes continue; 1599135446Strhodes } 1600135446Strhodes 1601135446Strhodes /* 1602135446Strhodes * This message is in the duplicate 1603135446Strhodes * filtering interval ... 1604135446Strhodes */ 1605135446Strhodes if (strcmp(lctx->buffer, message->text) 1606135446Strhodes == 0) { 1607135446Strhodes /* 1608135446Strhodes * ... and it is a duplicate. 1609135446Strhodes * Unlock the mutex and 1610135446Strhodes * get the hell out of Dodge. 1611135446Strhodes */ 1612135446Strhodes UNLOCK(&lctx->lock); 1613135446Strhodes return; 1614135446Strhodes } 1615135446Strhodes 1616135446Strhodes message = ISC_LIST_NEXT(message, link); 1617135446Strhodes } 1618135446Strhodes 1619135446Strhodes /* 1620135446Strhodes * It wasn't in the duplicate interval, 1621135446Strhodes * so add it to the message list. 1622135446Strhodes */ 1623135446Strhodes new = isc_mem_get(lctx->mctx, 1624135446Strhodes sizeof(isc_logmessage_t) + 1625135446Strhodes strlen(lctx->buffer) + 1); 1626135446Strhodes if (new != NULL) { 1627135446Strhodes /* 1628135446Strhodes * Put the text immediately after 1629135446Strhodes * the struct. The strcpy is safe. 1630135446Strhodes */ 1631135446Strhodes new->text = (char *)(new + 1); 1632135446Strhodes strcpy(new->text, lctx->buffer); 1633135446Strhodes 1634135446Strhodes TIME_NOW(&new->time); 1635135446Strhodes 1636135446Strhodes ISC_LIST_APPEND(lctx->messages, 1637135446Strhodes new, link); 1638135446Strhodes } 1639135446Strhodes } 1640135446Strhodes } 1641135446Strhodes 1642135446Strhodes printtime = ISC_TF((channel->flags & ISC_LOG_PRINTTIME) 1643135446Strhodes != 0); 1644135446Strhodes printtag = ISC_TF((channel->flags & ISC_LOG_PRINTTAG) 1645135446Strhodes != 0 && lcfg->tag != NULL); 1646135446Strhodes printcategory = ISC_TF((channel->flags & ISC_LOG_PRINTCATEGORY) 1647135446Strhodes != 0); 1648135446Strhodes printmodule = ISC_TF((channel->flags & ISC_LOG_PRINTMODULE) 1649135446Strhodes != 0); 1650135446Strhodes printlevel = ISC_TF((channel->flags & ISC_LOG_PRINTLEVEL) 1651135446Strhodes != 0); 1652135446Strhodes 1653135446Strhodes switch (channel->type) { 1654135446Strhodes case ISC_LOG_TOFILE: 1655135446Strhodes if (FILE_MAXREACHED(channel)) { 1656135446Strhodes /* 1657135446Strhodes * If the file can be rolled, OR 1658135446Strhodes * If the file no longer exists, OR 1659135446Strhodes * If the file is less than the maximum size, 1660135446Strhodes * (such as if it had been renamed and 1661135446Strhodes * a new one touched, or it was truncated 1662135446Strhodes * in place) 1663135446Strhodes * ... then close it to trigger reopening. 1664135446Strhodes */ 1665135446Strhodes if (FILE_VERSIONS(channel) != 1666135446Strhodes ISC_LOG_ROLLNEVER || 1667135446Strhodes (stat(FILE_NAME(channel), &statbuf) != 0 && 1668135446Strhodes errno == ENOENT) || 1669135446Strhodes statbuf.st_size < FILE_MAXSIZE(channel)) { 1670135446Strhodes (void)fclose(FILE_STREAM(channel)); 1671135446Strhodes FILE_STREAM(channel) = NULL; 1672135446Strhodes FILE_MAXREACHED(channel) = ISC_FALSE; 1673135446Strhodes } else 1674135446Strhodes /* 1675135446Strhodes * Eh, skip it. 1676135446Strhodes */ 1677135446Strhodes break; 1678135446Strhodes } 1679135446Strhodes 1680135446Strhodes if (FILE_STREAM(channel) == NULL) { 1681135446Strhodes result = isc_log_open(channel); 1682135446Strhodes if (result != ISC_R_SUCCESS && 1683135446Strhodes result != ISC_R_MAXSIZE && 1684135446Strhodes (channel->flags & ISC_LOG_OPENERR) == 0) { 1685135446Strhodes syslog(LOG_ERR, 1686135446Strhodes "isc_log_open '%s' failed: %s", 1687135446Strhodes FILE_NAME(channel), 1688135446Strhodes isc_result_totext(result)); 1689135446Strhodes channel->flags |= ISC_LOG_OPENERR; 1690135446Strhodes } 1691135446Strhodes if (result != ISC_R_SUCCESS) 1692135446Strhodes break; 1693135446Strhodes channel->flags &= ~ISC_LOG_OPENERR; 1694135446Strhodes } 1695135446Strhodes /* FALLTHROUGH */ 1696135446Strhodes 1697135446Strhodes case ISC_LOG_TOFILEDESC: 1698135446Strhodes fprintf(FILE_STREAM(channel), "%s%s%s%s%s%s%s%s%s%s\n", 1699135446Strhodes printtime ? time_string : "", 1700135446Strhodes printtime ? " " : "", 1701135446Strhodes printtag ? lcfg->tag : "", 1702135446Strhodes printtag ? ": " : "", 1703135446Strhodes printcategory ? category->name : "", 1704135446Strhodes printcategory ? ": " : "", 1705135446Strhodes printmodule ? (module != NULL ? module->name 1706193149Sdougb : "no_module") 1707193149Sdougb : "", 1708135446Strhodes printmodule ? ": " : "", 1709135446Strhodes printlevel ? level_string : "", 1710135446Strhodes lctx->buffer); 1711135446Strhodes 1712135446Strhodes fflush(FILE_STREAM(channel)); 1713135446Strhodes 1714135446Strhodes /* 1715135446Strhodes * If the file now exceeds its maximum size 1716135446Strhodes * threshold, note it so that it will not be logged 1717135446Strhodes * to any more. 1718135446Strhodes */ 1719135446Strhodes if (FILE_MAXSIZE(channel) > 0) { 1720135446Strhodes INSIST(channel->type == ISC_LOG_TOFILE); 1721135446Strhodes 1722135446Strhodes /* XXXDCL NT fstat/fileno */ 1723135446Strhodes /* XXXDCL complain if fstat fails? */ 1724135446Strhodes if (fstat(fileno(FILE_STREAM(channel)), 1725135446Strhodes &statbuf) >= 0 && 1726135446Strhodes statbuf.st_size > FILE_MAXSIZE(channel)) 1727135446Strhodes FILE_MAXREACHED(channel) = ISC_TRUE; 1728135446Strhodes } 1729135446Strhodes 1730135446Strhodes break; 1731135446Strhodes 1732135446Strhodes case ISC_LOG_TOSYSLOG: 1733135446Strhodes if (level > 0) 1734135446Strhodes syslog_level = LOG_DEBUG; 1735135446Strhodes else if (level < ISC_LOG_CRITICAL) 1736135446Strhodes syslog_level = LOG_CRIT; 1737135446Strhodes else 1738135446Strhodes syslog_level = syslog_map[-level]; 1739135446Strhodes 1740135446Strhodes (void)syslog(FACILITY(channel) | syslog_level, 1741165071Sdougb "%s%s%s%s%s%s%s%s%s%s", 1742135446Strhodes printtime ? time_string : "", 1743165071Sdougb printtime ? " " : "", 1744135446Strhodes printtag ? lcfg->tag : "", 1745135446Strhodes printtag ? ": " : "", 1746135446Strhodes printcategory ? category->name : "", 1747135446Strhodes printcategory ? ": " : "", 1748135446Strhodes printmodule ? (module != NULL ? module->name 1749193149Sdougb : "no_module") 1750193149Sdougb : "", 1751135446Strhodes printmodule ? ": " : "", 1752135446Strhodes printlevel ? level_string : "", 1753135446Strhodes lctx->buffer); 1754135446Strhodes break; 1755135446Strhodes 1756135446Strhodes case ISC_LOG_TONULL: 1757135446Strhodes break; 1758135446Strhodes 1759135446Strhodes } 1760135446Strhodes 1761135446Strhodes } while (1); 1762135446Strhodes 1763135446Strhodes UNLOCK(&lctx->lock); 1764135446Strhodes} 1765