1258945Sroberto/* 2280849Scy * Copyright (C) 2004-2007, 2009, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") 3258945Sroberto * Copyright (C) 1999-2003 Internet Software Consortium. 4258945Sroberto * 5258945Sroberto * Permission to use, copy, modify, and/or distribute this software for any 6258945Sroberto * purpose with or without fee is hereby granted, provided that the above 7258945Sroberto * copyright notice and this permission notice appear in all copies. 8258945Sroberto * 9258945Sroberto * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10258945Sroberto * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11258945Sroberto * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12258945Sroberto * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13258945Sroberto * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14258945Sroberto * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15258945Sroberto * PERFORMANCE OF THIS SOFTWARE. 16258945Sroberto */ 17258945Sroberto 18280849Scy/* $Id$ */ 19258945Sroberto 20258945Sroberto/*! \file 21258945Sroberto * \author Principal Authors: DCL */ 22258945Sroberto 23258945Sroberto#include <config.h> 24258945Sroberto 25258945Sroberto#include <errno.h> 26258945Sroberto#include <stdlib.h> 27258945Sroberto#include <limits.h> 28258945Sroberto#include <time.h> 29258945Sroberto 30258945Sroberto#include <sys/types.h> /* dev_t FreeBSD 2.1 */ 31258945Sroberto 32258945Sroberto#include <isc/dir.h> 33258945Sroberto#include <isc/file.h> 34258945Sroberto#include <isc/log.h> 35258945Sroberto#include <isc/magic.h> 36258945Sroberto#include <isc/mem.h> 37258945Sroberto#include <isc/msgs.h> 38258945Sroberto#include <isc/print.h> 39258945Sroberto#include <isc/stat.h> 40258945Sroberto#include <isc/stdio.h> 41258945Sroberto#include <isc/string.h> 42258945Sroberto#include <isc/time.h> 43258945Sroberto#include <isc/util.h> 44280849Scy#include "ntp_stdlib.h" /* NTP change for strlcpy, strlcat */ 45258945Sroberto 46258945Sroberto#define LCTX_MAGIC ISC_MAGIC('L', 'c', 't', 'x') 47258945Sroberto#define VALID_CONTEXT(lctx) ISC_MAGIC_VALID(lctx, LCTX_MAGIC) 48258945Sroberto 49258945Sroberto#define LCFG_MAGIC ISC_MAGIC('L', 'c', 'f', 'g') 50258945Sroberto#define VALID_CONFIG(lcfg) ISC_MAGIC_VALID(lcfg, LCFG_MAGIC) 51258945Sroberto 52258945Sroberto/* 53258945Sroberto * XXXDCL make dynamic? 54258945Sroberto */ 55258945Sroberto#define LOG_BUFFER_SIZE (8 * 1024) 56258945Sroberto 57258945Sroberto#ifndef PATH_MAX 58258945Sroberto#define PATH_MAX 1024 /* AIX and others don't define this. */ 59258945Sroberto#endif 60258945Sroberto 61258945Sroberto/*! 62258945Sroberto * This is the structure that holds each named channel. A simple linked 63258945Sroberto * list chains all of the channels together, so an individual channel is 64258945Sroberto * found by doing strcmp()s with the names down the list. Their should 65258945Sroberto * be no performance penalty from this as it is expected that the number 66258945Sroberto * of named channels will be no more than a dozen or so, and name lookups 67258945Sroberto * from the head of the list are only done when isc_log_usechannel() is 68258945Sroberto * called, which should also be very infrequent. 69258945Sroberto */ 70258945Srobertotypedef struct isc_logchannel isc_logchannel_t; 71258945Sroberto 72258945Srobertostruct isc_logchannel { 73258945Sroberto char * name; 74258945Sroberto unsigned int type; 75258945Sroberto int level; 76258945Sroberto unsigned int flags; 77258945Sroberto isc_logdestination_t destination; 78258945Sroberto ISC_LINK(isc_logchannel_t) link; 79258945Sroberto}; 80258945Sroberto 81258945Sroberto/*! 82258945Sroberto * The logchannellist structure associates categories and modules with 83258945Sroberto * channels. First the appropriate channellist is found based on the 84258945Sroberto * category, and then each structure in the linked list is checked for 85258945Sroberto * a matching module. It is expected that the number of channels 86258945Sroberto * associated with any given category will be very short, no more than 87258945Sroberto * three or four in the more unusual cases. 88258945Sroberto */ 89258945Srobertotypedef struct isc_logchannellist isc_logchannellist_t; 90258945Sroberto 91258945Srobertostruct isc_logchannellist { 92258945Sroberto const isc_logmodule_t * module; 93258945Sroberto isc_logchannel_t * channel; 94258945Sroberto ISC_LINK(isc_logchannellist_t) link; 95258945Sroberto}; 96258945Sroberto 97258945Sroberto/*! 98258945Sroberto * This structure is used to remember messages for pruning via 99258945Sroberto * isc_log_[v]write1(). 100258945Sroberto */ 101258945Srobertotypedef struct isc_logmessage isc_logmessage_t; 102258945Sroberto 103258945Srobertostruct isc_logmessage { 104258945Sroberto char * text; 105258945Sroberto isc_time_t time; 106258945Sroberto ISC_LINK(isc_logmessage_t) link; 107258945Sroberto}; 108258945Sroberto 109258945Sroberto/*! 110258945Sroberto * The isc_logconfig structure is used to store the configurable information 111258945Sroberto * about where messages are actually supposed to be sent -- the information 112258945Sroberto * that could changed based on some configuration file, as opposed to the 113258945Sroberto * the category/module specification of isc_log_[v]write[1] that is compiled 114258945Sroberto * into a program, or the debug_level which is dynamic state information. 115258945Sroberto */ 116258945Srobertostruct isc_logconfig { 117258945Sroberto unsigned int magic; 118258945Sroberto isc_log_t * lctx; 119258945Sroberto ISC_LIST(isc_logchannel_t) channels; 120258945Sroberto ISC_LIST(isc_logchannellist_t) *channellists; 121258945Sroberto unsigned int channellist_count; 122258945Sroberto unsigned int duplicate_interval; 123258945Sroberto int highest_level; 124258945Sroberto char * tag; 125258945Sroberto isc_boolean_t dynamic; 126258945Sroberto}; 127258945Sroberto 128258945Sroberto/*! 129258945Sroberto * This isc_log structure provides the context for the isc_log functions. 130258945Sroberto * The log context locks itself in isc_log_doit, the internal backend to 131258945Sroberto * isc_log_write. The locking is necessary both to provide exclusive access 132258945Sroberto * to the buffer into which the message is formatted and to guard against 133258945Sroberto * competing threads trying to write to the same syslog resource. (On 134258945Sroberto * some systems, such as BSD/OS, stdio is thread safe but syslog is not.) 135258945Sroberto * Unfortunately, the lock cannot guard against a _different_ logging 136258945Sroberto * context in the same program competing for syslog's attention. Thus 137258945Sroberto * There Can Be Only One, but this is not enforced. 138258945Sroberto * XXXDCL enforce it? 139258945Sroberto * 140258945Sroberto * Note that the category and module information is not locked. 141258945Sroberto * This is because in the usual case, only one isc_log_t is ever created 142258945Sroberto * in a program, and the category/module registration happens only once. 143258945Sroberto * XXXDCL it might be wise to add more locking overall. 144258945Sroberto */ 145258945Srobertostruct isc_log { 146258945Sroberto /* Not locked. */ 147258945Sroberto unsigned int magic; 148258945Sroberto isc_mem_t * mctx; 149258945Sroberto isc_logcategory_t * categories; 150258945Sroberto unsigned int category_count; 151258945Sroberto isc_logmodule_t * modules; 152258945Sroberto unsigned int module_count; 153258945Sroberto int debug_level; 154258945Sroberto isc_mutex_t lock; 155258945Sroberto /* Locked by isc_log lock. */ 156258945Sroberto isc_logconfig_t * logconfig; 157258945Sroberto char buffer[LOG_BUFFER_SIZE]; 158258945Sroberto ISC_LIST(isc_logmessage_t) messages; 159258945Sroberto}; 160258945Sroberto 161258945Sroberto/*! 162258945Sroberto * Used when ISC_LOG_PRINTLEVEL is enabled for a channel. 163258945Sroberto */ 164258945Srobertostatic const char *log_level_strings[] = { 165258945Sroberto "debug", 166258945Sroberto "info", 167258945Sroberto "notice", 168258945Sroberto "warning", 169258945Sroberto "error", 170258945Sroberto "critical" 171258945Sroberto}; 172258945Sroberto 173258945Sroberto/*! 174258945Sroberto * Used to convert ISC_LOG_* priorities into syslog priorities. 175258945Sroberto * XXXDCL This will need modification for NT. 176258945Sroberto */ 177258945Srobertostatic const int syslog_map[] = { 178258945Sroberto LOG_DEBUG, 179258945Sroberto LOG_INFO, 180258945Sroberto LOG_NOTICE, 181258945Sroberto LOG_WARNING, 182258945Sroberto LOG_ERR, 183258945Sroberto LOG_CRIT 184258945Sroberto}; 185258945Sroberto 186258945Sroberto/*! 187258945Sroberto * When adding new categories, a corresponding ISC_LOGCATEGORY_foo 188258945Sroberto * definition needs to be added to <isc/log.h>. 189258945Sroberto * 190258945Sroberto * The default category is provided so that the internal default can 191258945Sroberto * be overridden. Since the default is always looked up as the first 192258945Sroberto * channellist in the log context, it must come first in isc_categories[]. 193258945Sroberto */ 194258945SrobertoLIBISC_EXTERNAL_DATA isc_logcategory_t isc_categories[] = { 195258945Sroberto { "default", 0 }, /* "default" must come first. */ 196258945Sroberto { "general", 0 }, 197258945Sroberto { NULL, 0 } 198258945Sroberto}; 199258945Sroberto 200258945Sroberto/*! 201258945Sroberto * See above comment for categories on LIBISC_EXTERNAL_DATA, and apply it to modules. 202258945Sroberto */ 203258945SrobertoLIBISC_EXTERNAL_DATA isc_logmodule_t isc_modules[] = { 204258945Sroberto { "socket", 0 }, 205258945Sroberto { "time", 0 }, 206258945Sroberto { "interface", 0 }, 207258945Sroberto { "timer", 0 }, 208258945Sroberto { "file", 0 }, 209258945Sroberto { NULL, 0 } 210258945Sroberto}; 211258945Sroberto 212258945Sroberto/*! 213258945Sroberto * This essentially constant structure must be filled in at run time, 214258945Sroberto * because its channel member is pointed to a channel that is created 215258945Sroberto * dynamically with isc_log_createchannel. 216258945Sroberto */ 217258945Srobertostatic isc_logchannellist_t default_channel; 218258945Sroberto 219258945Sroberto/*! 220258945Sroberto * libisc logs to this context. 221258945Sroberto */ 222258945SrobertoLIBISC_EXTERNAL_DATA isc_log_t *isc_lctx = NULL; 223258945Sroberto 224258945Sroberto/*! 225258945Sroberto * Forward declarations. 226258945Sroberto */ 227258945Srobertostatic isc_result_t 228258945Srobertoassignchannel(isc_logconfig_t *lcfg, unsigned int category_id, 229258945Sroberto const isc_logmodule_t *module, isc_logchannel_t *channel); 230258945Sroberto 231258945Srobertostatic isc_result_t 232258945Srobertosync_channellist(isc_logconfig_t *lcfg); 233258945Sroberto 234258945Srobertostatic isc_result_t 235258945Srobertogreatest_version(isc_logchannel_t *channel, int *greatest); 236258945Sroberto 237258945Srobertostatic isc_result_t 238258945Srobertoroll_log(isc_logchannel_t *channel); 239258945Sroberto 240258945Srobertostatic void 241258945Srobertoisc_log_doit(isc_log_t *lctx, isc_logcategory_t *category, 242258945Sroberto isc_logmodule_t *module, int level, isc_boolean_t write_once, 243258945Sroberto isc_msgcat_t *msgcat, int msgset, int msg, 244258945Sroberto const char *format, va_list args) 245258945Sroberto ISC_FORMAT_PRINTF(9, 0); 246258945Sroberto 247258945Sroberto/*@{*/ 248258945Sroberto/*! 249258945Sroberto * Convenience macros. 250258945Sroberto */ 251258945Sroberto 252258945Sroberto#define FACILITY(channel) (channel->destination.facility) 253258945Sroberto#define FILE_NAME(channel) (channel->destination.file.name) 254258945Sroberto#define FILE_STREAM(channel) (channel->destination.file.stream) 255258945Sroberto#define FILE_VERSIONS(channel) (channel->destination.file.versions) 256258945Sroberto#define FILE_MAXSIZE(channel) (channel->destination.file.maximum_size) 257258945Sroberto#define FILE_MAXREACHED(channel) (channel->destination.file.maximum_reached) 258258945Sroberto 259258945Sroberto/*@}*/ 260258945Sroberto/**** 261258945Sroberto **** Public interfaces. 262258945Sroberto ****/ 263258945Sroberto 264258945Sroberto/* 265258945Sroberto * Establish a new logging context, with default channels. 266258945Sroberto */ 267258945Srobertoisc_result_t 268258945Srobertoisc_log_create(isc_mem_t *mctx, isc_log_t **lctxp, isc_logconfig_t **lcfgp) { 269258945Sroberto isc_log_t *lctx; 270258945Sroberto isc_logconfig_t *lcfg = NULL; 271258945Sroberto isc_result_t result; 272258945Sroberto 273258945Sroberto REQUIRE(mctx != NULL); 274258945Sroberto REQUIRE(lctxp != NULL && *lctxp == NULL); 275258945Sroberto REQUIRE(lcfgp == NULL || *lcfgp == NULL); 276258945Sroberto 277258945Sroberto lctx = isc_mem_get(mctx, sizeof(*lctx)); 278258945Sroberto if (lctx != NULL) { 279258945Sroberto lctx->mctx = mctx; 280258945Sroberto lctx->categories = NULL; 281258945Sroberto lctx->category_count = 0; 282258945Sroberto lctx->modules = NULL; 283258945Sroberto lctx->module_count = 0; 284258945Sroberto lctx->debug_level = 0; 285258945Sroberto 286258945Sroberto ISC_LIST_INIT(lctx->messages); 287258945Sroberto 288258945Sroberto result = isc_mutex_init(&lctx->lock); 289258945Sroberto if (result != ISC_R_SUCCESS) { 290258945Sroberto isc_mem_put(mctx, lctx, sizeof(*lctx)); 291258945Sroberto return (result); 292258945Sroberto } 293258945Sroberto 294258945Sroberto /* 295258945Sroberto * Normally setting the magic number is the last step done 296258945Sroberto * in a creation function, but a valid log context is needed 297258945Sroberto * by isc_log_registercategories and isc_logconfig_create. 298258945Sroberto * If either fails, the lctx is destroyed and not returned 299258945Sroberto * to the caller. 300258945Sroberto */ 301258945Sroberto lctx->magic = LCTX_MAGIC; 302258945Sroberto 303258945Sroberto isc_log_registercategories(lctx, isc_categories); 304258945Sroberto isc_log_registermodules(lctx, isc_modules); 305258945Sroberto result = isc_logconfig_create(lctx, &lcfg); 306258945Sroberto 307258945Sroberto } else 308258945Sroberto result = ISC_R_NOMEMORY; 309258945Sroberto 310258945Sroberto if (result == ISC_R_SUCCESS) 311258945Sroberto result = sync_channellist(lcfg); 312258945Sroberto 313258945Sroberto if (result == ISC_R_SUCCESS) { 314258945Sroberto lctx->logconfig = lcfg; 315258945Sroberto 316258945Sroberto *lctxp = lctx; 317258945Sroberto if (lcfgp != NULL) 318258945Sroberto *lcfgp = lcfg; 319258945Sroberto 320258945Sroberto } else { 321258945Sroberto if (lcfg != NULL) 322258945Sroberto isc_logconfig_destroy(&lcfg); 323258945Sroberto if (lctx != NULL) 324258945Sroberto isc_log_destroy(&lctx); 325258945Sroberto } 326258945Sroberto 327258945Sroberto return (result); 328258945Sroberto} 329258945Sroberto 330258945Srobertoisc_result_t 331258945Srobertoisc_logconfig_create(isc_log_t *lctx, isc_logconfig_t **lcfgp) { 332258945Sroberto isc_logconfig_t *lcfg; 333258945Sroberto isc_logdestination_t destination; 334258945Sroberto isc_result_t result = ISC_R_SUCCESS; 335258945Sroberto int level = ISC_LOG_INFO; 336258945Sroberto 337258945Sroberto REQUIRE(lcfgp != NULL && *lcfgp == NULL); 338258945Sroberto REQUIRE(VALID_CONTEXT(lctx)); 339258945Sroberto 340258945Sroberto lcfg = isc_mem_get(lctx->mctx, sizeof(*lcfg)); 341258945Sroberto 342258945Sroberto if (lcfg != NULL) { 343258945Sroberto lcfg->lctx = lctx; 344258945Sroberto lcfg->channellists = NULL; 345258945Sroberto lcfg->channellist_count = 0; 346258945Sroberto lcfg->duplicate_interval = 0; 347258945Sroberto lcfg->highest_level = level; 348258945Sroberto lcfg->tag = NULL; 349258945Sroberto lcfg->dynamic = ISC_FALSE; 350258945Sroberto 351258945Sroberto ISC_LIST_INIT(lcfg->channels); 352258945Sroberto 353258945Sroberto /* 354258945Sroberto * Normally the magic number is the last thing set in the 355258945Sroberto * structure, but isc_log_createchannel() needs a valid 356258945Sroberto * config. If the channel creation fails, the lcfg is not 357258945Sroberto * returned to the caller. 358258945Sroberto */ 359258945Sroberto lcfg->magic = LCFG_MAGIC; 360258945Sroberto 361258945Sroberto } else 362258945Sroberto result = ISC_R_NOMEMORY; 363258945Sroberto 364258945Sroberto /* 365258945Sroberto * Create the default channels: 366258945Sroberto * default_syslog, default_stderr, default_debug and null. 367258945Sroberto */ 368258945Sroberto if (result == ISC_R_SUCCESS) { 369258945Sroberto destination.facility = LOG_DAEMON; 370258945Sroberto result = isc_log_createchannel(lcfg, "default_syslog", 371258945Sroberto ISC_LOG_TOSYSLOG, level, 372258945Sroberto &destination, 0); 373258945Sroberto } 374258945Sroberto 375258945Sroberto if (result == ISC_R_SUCCESS) { 376258945Sroberto destination.file.stream = stderr; 377258945Sroberto destination.file.name = NULL; 378258945Sroberto destination.file.versions = ISC_LOG_ROLLNEVER; 379258945Sroberto destination.file.maximum_size = 0; 380258945Sroberto result = isc_log_createchannel(lcfg, "default_stderr", 381258945Sroberto ISC_LOG_TOFILEDESC, 382258945Sroberto level, 383258945Sroberto &destination, 384258945Sroberto ISC_LOG_PRINTTIME); 385258945Sroberto } 386258945Sroberto 387258945Sroberto if (result == ISC_R_SUCCESS) { 388258945Sroberto /* 389258945Sroberto * Set the default category's channel to default_stderr, 390258945Sroberto * which is at the head of the channels list because it was 391258945Sroberto * just created. 392258945Sroberto */ 393258945Sroberto default_channel.channel = ISC_LIST_HEAD(lcfg->channels); 394258945Sroberto 395258945Sroberto destination.file.stream = stderr; 396258945Sroberto destination.file.name = NULL; 397258945Sroberto destination.file.versions = ISC_LOG_ROLLNEVER; 398258945Sroberto destination.file.maximum_size = 0; 399258945Sroberto result = isc_log_createchannel(lcfg, "default_debug", 400258945Sroberto ISC_LOG_TOFILEDESC, 401258945Sroberto ISC_LOG_DYNAMIC, 402258945Sroberto &destination, 403258945Sroberto ISC_LOG_PRINTTIME); 404258945Sroberto } 405258945Sroberto 406258945Sroberto if (result == ISC_R_SUCCESS) 407258945Sroberto result = isc_log_createchannel(lcfg, "null", 408258945Sroberto ISC_LOG_TONULL, 409258945Sroberto ISC_LOG_DYNAMIC, 410258945Sroberto NULL, 0); 411258945Sroberto 412258945Sroberto if (result == ISC_R_SUCCESS) 413258945Sroberto *lcfgp = lcfg; 414258945Sroberto 415258945Sroberto else 416258945Sroberto if (lcfg != NULL) 417258945Sroberto isc_logconfig_destroy(&lcfg); 418258945Sroberto 419258945Sroberto return (result); 420258945Sroberto} 421258945Sroberto 422258945Srobertoisc_logconfig_t * 423258945Srobertoisc_logconfig_get(isc_log_t *lctx) { 424258945Sroberto REQUIRE(VALID_CONTEXT(lctx)); 425258945Sroberto 426258945Sroberto ENSURE(lctx->logconfig != NULL); 427258945Sroberto 428258945Sroberto return (lctx->logconfig); 429258945Sroberto} 430258945Sroberto 431258945Srobertoisc_result_t 432258945Srobertoisc_logconfig_use(isc_log_t *lctx, isc_logconfig_t *lcfg) { 433258945Sroberto isc_logconfig_t *old_cfg; 434258945Sroberto isc_result_t result; 435258945Sroberto 436258945Sroberto REQUIRE(VALID_CONTEXT(lctx)); 437258945Sroberto REQUIRE(VALID_CONFIG(lcfg)); 438258945Sroberto REQUIRE(lcfg->lctx == lctx); 439258945Sroberto 440258945Sroberto /* 441258945Sroberto * Ensure that lcfg->channellist_count == lctx->category_count. 442258945Sroberto * They won't be equal if isc_log_usechannel has not been called 443258945Sroberto * since any call to isc_log_registercategories. 444258945Sroberto */ 445258945Sroberto result = sync_channellist(lcfg); 446258945Sroberto if (result != ISC_R_SUCCESS) 447258945Sroberto return (result); 448258945Sroberto 449258945Sroberto LOCK(&lctx->lock); 450258945Sroberto 451258945Sroberto old_cfg = lctx->logconfig; 452258945Sroberto lctx->logconfig = lcfg; 453258945Sroberto 454258945Sroberto UNLOCK(&lctx->lock); 455258945Sroberto 456258945Sroberto isc_logconfig_destroy(&old_cfg); 457258945Sroberto 458258945Sroberto return (ISC_R_SUCCESS); 459258945Sroberto} 460258945Sroberto 461258945Srobertovoid 462258945Srobertoisc_log_destroy(isc_log_t **lctxp) { 463258945Sroberto isc_log_t *lctx; 464258945Sroberto isc_logconfig_t *lcfg; 465258945Sroberto isc_mem_t *mctx; 466258945Sroberto isc_logmessage_t *message; 467258945Sroberto 468258945Sroberto REQUIRE(lctxp != NULL && VALID_CONTEXT(*lctxp)); 469258945Sroberto 470258945Sroberto lctx = *lctxp; 471258945Sroberto mctx = lctx->mctx; 472258945Sroberto 473258945Sroberto if (lctx->logconfig != NULL) { 474258945Sroberto lcfg = lctx->logconfig; 475258945Sroberto lctx->logconfig = NULL; 476258945Sroberto isc_logconfig_destroy(&lcfg); 477258945Sroberto } 478258945Sroberto 479258945Sroberto DESTROYLOCK(&lctx->lock); 480258945Sroberto 481258945Sroberto while ((message = ISC_LIST_HEAD(lctx->messages)) != NULL) { 482258945Sroberto ISC_LIST_UNLINK(lctx->messages, message, link); 483258945Sroberto 484258945Sroberto isc_mem_put(mctx, message, 485258945Sroberto sizeof(*message) + strlen(message->text) + 1); 486258945Sroberto } 487258945Sroberto 488258945Sroberto lctx->buffer[0] = '\0'; 489258945Sroberto lctx->debug_level = 0; 490258945Sroberto lctx->categories = NULL; 491258945Sroberto lctx->category_count = 0; 492258945Sroberto lctx->modules = NULL; 493258945Sroberto lctx->module_count = 0; 494258945Sroberto lctx->mctx = NULL; 495258945Sroberto lctx->magic = 0; 496258945Sroberto 497258945Sroberto isc_mem_put(mctx, lctx, sizeof(*lctx)); 498258945Sroberto 499258945Sroberto *lctxp = NULL; 500258945Sroberto} 501258945Sroberto 502258945Srobertovoid 503258945Srobertoisc_logconfig_destroy(isc_logconfig_t **lcfgp) { 504258945Sroberto isc_logconfig_t *lcfg; 505258945Sroberto isc_mem_t *mctx; 506258945Sroberto isc_logchannel_t *channel; 507258945Sroberto isc_logchannellist_t *item; 508258945Sroberto char *filename; 509258945Sroberto unsigned int i; 510258945Sroberto 511258945Sroberto REQUIRE(lcfgp != NULL && VALID_CONFIG(*lcfgp)); 512258945Sroberto 513258945Sroberto lcfg = *lcfgp; 514258945Sroberto 515258945Sroberto /* 516258945Sroberto * This function cannot be called with a logconfig that is in 517258945Sroberto * use by a log context. 518258945Sroberto */ 519258945Sroberto REQUIRE(lcfg->lctx != NULL && lcfg->lctx->logconfig != lcfg); 520258945Sroberto 521258945Sroberto mctx = lcfg->lctx->mctx; 522258945Sroberto 523258945Sroberto while ((channel = ISC_LIST_HEAD(lcfg->channels)) != NULL) { 524258945Sroberto ISC_LIST_UNLINK(lcfg->channels, channel, link); 525258945Sroberto 526258945Sroberto if (channel->type == ISC_LOG_TOFILE) { 527258945Sroberto /* 528258945Sroberto * The filename for the channel may have ultimately 529258945Sroberto * started its life in user-land as a const string, 530258945Sroberto * but in isc_log_createchannel it gets copied 531258945Sroberto * into writable memory and is not longer truly const. 532258945Sroberto */ 533258945Sroberto DE_CONST(FILE_NAME(channel), filename); 534258945Sroberto isc_mem_free(mctx, filename); 535258945Sroberto 536258945Sroberto if (FILE_STREAM(channel) != NULL) 537258945Sroberto (void)fclose(FILE_STREAM(channel)); 538258945Sroberto } 539258945Sroberto 540258945Sroberto isc_mem_free(mctx, channel->name); 541258945Sroberto isc_mem_put(mctx, channel, sizeof(*channel)); 542258945Sroberto } 543258945Sroberto 544258945Sroberto for (i = 0; i < lcfg->channellist_count; i++) 545258945Sroberto while ((item = ISC_LIST_HEAD(lcfg->channellists[i])) != NULL) { 546258945Sroberto ISC_LIST_UNLINK(lcfg->channellists[i], item, link); 547258945Sroberto isc_mem_put(mctx, item, sizeof(*item)); 548258945Sroberto } 549258945Sroberto 550258945Sroberto if (lcfg->channellist_count > 0) 551258945Sroberto isc_mem_put(mctx, lcfg->channellists, 552258945Sroberto lcfg->channellist_count * 553258945Sroberto sizeof(ISC_LIST(isc_logchannellist_t))); 554258945Sroberto 555258945Sroberto lcfg->dynamic = ISC_FALSE; 556258945Sroberto if (lcfg->tag != NULL) 557258945Sroberto isc_mem_free(lcfg->lctx->mctx, lcfg->tag); 558258945Sroberto lcfg->tag = NULL; 559258945Sroberto lcfg->highest_level = 0; 560258945Sroberto lcfg->duplicate_interval = 0; 561258945Sroberto lcfg->magic = 0; 562258945Sroberto 563258945Sroberto isc_mem_put(mctx, lcfg, sizeof(*lcfg)); 564258945Sroberto 565258945Sroberto *lcfgp = NULL; 566258945Sroberto} 567258945Sroberto 568258945Srobertovoid 569258945Srobertoisc_log_registercategories(isc_log_t *lctx, isc_logcategory_t categories[]) { 570258945Sroberto isc_logcategory_t *catp; 571258945Sroberto 572258945Sroberto REQUIRE(VALID_CONTEXT(lctx)); 573258945Sroberto REQUIRE(categories != NULL && categories[0].name != NULL); 574258945Sroberto 575258945Sroberto /* 576258945Sroberto * XXXDCL This somewhat sleazy situation of using the last pointer 577258945Sroberto * in one category array to point to the next array exists because 578258945Sroberto * this registration function returns void and I didn't want to have 579258945Sroberto * change everything that used it by making it return an isc_result_t. 580258945Sroberto * It would need to do that if it had to allocate memory to store 581258945Sroberto * pointers to each array passed in. 582258945Sroberto */ 583258945Sroberto if (lctx->categories == NULL) 584258945Sroberto lctx->categories = categories; 585258945Sroberto 586258945Sroberto else { 587258945Sroberto /* 588258945Sroberto * Adjust the last (NULL) pointer of the already registered 589258945Sroberto * categories to point to the incoming array. 590258945Sroberto */ 591258945Sroberto for (catp = lctx->categories; catp->name != NULL; ) 592258945Sroberto if (catp->id == UINT_MAX) 593258945Sroberto /* 594258945Sroberto * The name pointer points to the next array. 595258945Sroberto * Ick. 596258945Sroberto */ 597258945Sroberto DE_CONST(catp->name, catp); 598258945Sroberto else 599258945Sroberto catp++; 600258945Sroberto 601258945Sroberto catp->name = (void *)categories; 602258945Sroberto catp->id = UINT_MAX; 603258945Sroberto } 604258945Sroberto 605258945Sroberto /* 606258945Sroberto * Update the id number of the category with its new global id. 607258945Sroberto */ 608258945Sroberto for (catp = categories; catp->name != NULL; catp++) 609258945Sroberto catp->id = lctx->category_count++; 610258945Sroberto} 611258945Sroberto 612258945Srobertoisc_logcategory_t * 613258945Srobertoisc_log_categorybyname(isc_log_t *lctx, const char *name) { 614258945Sroberto isc_logcategory_t *catp; 615258945Sroberto 616258945Sroberto REQUIRE(VALID_CONTEXT(lctx)); 617258945Sroberto REQUIRE(name != NULL); 618258945Sroberto 619258945Sroberto for (catp = lctx->categories; catp->name != NULL; ) 620258945Sroberto if (catp->id == UINT_MAX) 621258945Sroberto /* 622258945Sroberto * catp is neither modified nor returned to the 623258945Sroberto * caller, so removing its const qualifier is ok. 624258945Sroberto */ 625258945Sroberto DE_CONST(catp->name, catp); 626258945Sroberto else { 627258945Sroberto if (strcmp(catp->name, name) == 0) 628258945Sroberto return (catp); 629258945Sroberto catp++; 630258945Sroberto } 631258945Sroberto 632258945Sroberto return (NULL); 633258945Sroberto} 634258945Sroberto 635258945Srobertovoid 636258945Srobertoisc_log_registermodules(isc_log_t *lctx, isc_logmodule_t modules[]) { 637258945Sroberto isc_logmodule_t *modp; 638258945Sroberto 639258945Sroberto REQUIRE(VALID_CONTEXT(lctx)); 640258945Sroberto REQUIRE(modules != NULL && modules[0].name != NULL); 641258945Sroberto 642258945Sroberto /* 643258945Sroberto * XXXDCL This somewhat sleazy situation of using the last pointer 644258945Sroberto * in one category array to point to the next array exists because 645258945Sroberto * this registration function returns void and I didn't want to have 646258945Sroberto * change everything that used it by making it return an isc_result_t. 647258945Sroberto * It would need to do that if it had to allocate memory to store 648258945Sroberto * pointers to each array passed in. 649258945Sroberto */ 650258945Sroberto if (lctx->modules == NULL) 651258945Sroberto lctx->modules = modules; 652258945Sroberto 653258945Sroberto else { 654258945Sroberto /* 655258945Sroberto * Adjust the last (NULL) pointer of the already registered 656258945Sroberto * modules to point to the incoming array. 657258945Sroberto */ 658258945Sroberto for (modp = lctx->modules; modp->name != NULL; ) 659258945Sroberto if (modp->id == UINT_MAX) 660258945Sroberto /* 661258945Sroberto * The name pointer points to the next array. 662258945Sroberto * Ick. 663258945Sroberto */ 664258945Sroberto DE_CONST(modp->name, modp); 665258945Sroberto else 666258945Sroberto modp++; 667258945Sroberto 668258945Sroberto modp->name = (void *)modules; 669258945Sroberto modp->id = UINT_MAX; 670258945Sroberto } 671258945Sroberto 672258945Sroberto /* 673258945Sroberto * Update the id number of the module with its new global id. 674258945Sroberto */ 675258945Sroberto for (modp = modules; modp->name != NULL; modp++) 676258945Sroberto modp->id = lctx->module_count++; 677258945Sroberto} 678258945Sroberto 679258945Srobertoisc_logmodule_t * 680258945Srobertoisc_log_modulebyname(isc_log_t *lctx, const char *name) { 681258945Sroberto isc_logmodule_t *modp; 682258945Sroberto 683258945Sroberto REQUIRE(VALID_CONTEXT(lctx)); 684258945Sroberto REQUIRE(name != NULL); 685258945Sroberto 686258945Sroberto for (modp = lctx->modules; modp->name != NULL; ) 687258945Sroberto if (modp->id == UINT_MAX) 688258945Sroberto /* 689258945Sroberto * modp is neither modified nor returned to the 690258945Sroberto * caller, so removing its const qualifier is ok. 691258945Sroberto */ 692258945Sroberto DE_CONST(modp->name, modp); 693258945Sroberto else { 694258945Sroberto if (strcmp(modp->name, name) == 0) 695258945Sroberto return (modp); 696258945Sroberto modp++; 697258945Sroberto } 698258945Sroberto 699258945Sroberto return (NULL); 700258945Sroberto} 701258945Sroberto 702258945Srobertoisc_result_t 703258945Srobertoisc_log_createchannel(isc_logconfig_t *lcfg, const char *name, 704258945Sroberto unsigned int type, int level, 705258945Sroberto const isc_logdestination_t *destination, 706258945Sroberto unsigned int flags) 707258945Sroberto{ 708258945Sroberto isc_logchannel_t *channel; 709258945Sroberto isc_mem_t *mctx; 710258945Sroberto 711258945Sroberto REQUIRE(VALID_CONFIG(lcfg)); 712258945Sroberto REQUIRE(name != NULL); 713258945Sroberto REQUIRE(type == ISC_LOG_TOSYSLOG || type == ISC_LOG_TOFILE || 714258945Sroberto type == ISC_LOG_TOFILEDESC || type == ISC_LOG_TONULL); 715258945Sroberto REQUIRE(destination != NULL || type == ISC_LOG_TONULL); 716258945Sroberto REQUIRE(level >= ISC_LOG_CRITICAL); 717258945Sroberto REQUIRE((flags & 718258945Sroberto (unsigned int)~(ISC_LOG_PRINTALL | ISC_LOG_DEBUGONLY)) == 0); 719258945Sroberto 720258945Sroberto /* XXXDCL find duplicate names? */ 721258945Sroberto 722258945Sroberto mctx = lcfg->lctx->mctx; 723258945Sroberto 724258945Sroberto channel = isc_mem_get(mctx, sizeof(*channel)); 725258945Sroberto if (channel == NULL) 726258945Sroberto return (ISC_R_NOMEMORY); 727258945Sroberto 728258945Sroberto channel->name = isc_mem_strdup(mctx, name); 729258945Sroberto if (channel->name == NULL) { 730258945Sroberto isc_mem_put(mctx, channel, sizeof(*channel)); 731258945Sroberto return (ISC_R_NOMEMORY); 732258945Sroberto } 733258945Sroberto 734258945Sroberto channel->type = type; 735258945Sroberto channel->level = level; 736258945Sroberto channel->flags = flags; 737258945Sroberto ISC_LINK_INIT(channel, link); 738258945Sroberto 739258945Sroberto switch (type) { 740258945Sroberto case ISC_LOG_TOSYSLOG: 741258945Sroberto FACILITY(channel) = destination->facility; 742258945Sroberto break; 743258945Sroberto 744258945Sroberto case ISC_LOG_TOFILE: 745258945Sroberto /* 746258945Sroberto * The file name is copied because greatest_version wants 747258945Sroberto * to scribble on it, so it needs to be definitely in 748258945Sroberto * writable memory. 749258945Sroberto */ 750258945Sroberto FILE_NAME(channel) = 751258945Sroberto isc_mem_strdup(mctx, destination->file.name); 752258945Sroberto FILE_STREAM(channel) = NULL; 753258945Sroberto FILE_VERSIONS(channel) = destination->file.versions; 754258945Sroberto FILE_MAXSIZE(channel) = destination->file.maximum_size; 755258945Sroberto FILE_MAXREACHED(channel) = ISC_FALSE; 756258945Sroberto break; 757258945Sroberto 758258945Sroberto case ISC_LOG_TOFILEDESC: 759258945Sroberto FILE_NAME(channel) = NULL; 760258945Sroberto FILE_STREAM(channel) = destination->file.stream; 761258945Sroberto FILE_MAXSIZE(channel) = 0; 762258945Sroberto FILE_VERSIONS(channel) = ISC_LOG_ROLLNEVER; 763258945Sroberto break; 764258945Sroberto 765258945Sroberto case ISC_LOG_TONULL: 766258945Sroberto /* Nothing. */ 767258945Sroberto break; 768258945Sroberto 769258945Sroberto default: 770258945Sroberto isc_mem_put(mctx, channel->name, strlen(channel->name) + 1); 771258945Sroberto isc_mem_put(mctx, channel, sizeof(*channel)); 772258945Sroberto return (ISC_R_UNEXPECTED); 773258945Sroberto } 774258945Sroberto 775258945Sroberto ISC_LIST_PREPEND(lcfg->channels, channel, link); 776258945Sroberto 777258945Sroberto /* 778258945Sroberto * If default_stderr was redefined, make the default category 779258945Sroberto * point to the new default_stderr. 780258945Sroberto */ 781258945Sroberto if (strcmp(name, "default_stderr") == 0) 782258945Sroberto default_channel.channel = channel; 783258945Sroberto 784258945Sroberto return (ISC_R_SUCCESS); 785258945Sroberto} 786258945Sroberto 787258945Srobertoisc_result_t 788258945Srobertoisc_log_usechannel(isc_logconfig_t *lcfg, const char *name, 789258945Sroberto const isc_logcategory_t *category, 790258945Sroberto const isc_logmodule_t *module) 791258945Sroberto{ 792258945Sroberto isc_log_t *lctx; 793258945Sroberto isc_logchannel_t *channel; 794258945Sroberto isc_result_t result = ISC_R_SUCCESS; 795258945Sroberto unsigned int i; 796258945Sroberto 797258945Sroberto REQUIRE(VALID_CONFIG(lcfg)); 798258945Sroberto REQUIRE(name != NULL); 799258945Sroberto 800258945Sroberto lctx = lcfg->lctx; 801258945Sroberto 802258945Sroberto REQUIRE(category == NULL || category->id < lctx->category_count); 803258945Sroberto REQUIRE(module == NULL || module->id < lctx->module_count); 804258945Sroberto 805258945Sroberto for (channel = ISC_LIST_HEAD(lcfg->channels); channel != NULL; 806258945Sroberto channel = ISC_LIST_NEXT(channel, link)) 807258945Sroberto if (strcmp(name, channel->name) == 0) 808258945Sroberto break; 809258945Sroberto 810258945Sroberto if (channel == NULL) 811258945Sroberto return (ISC_R_NOTFOUND); 812258945Sroberto 813258945Sroberto if (category != NULL) 814258945Sroberto result = assignchannel(lcfg, category->id, module, channel); 815258945Sroberto 816258945Sroberto else 817258945Sroberto /* 818258945Sroberto * Assign to all categories. Note that this includes 819258945Sroberto * the default channel. 820258945Sroberto */ 821258945Sroberto for (i = 0; i < lctx->category_count; i++) { 822258945Sroberto result = assignchannel(lcfg, i, module, channel); 823258945Sroberto if (result != ISC_R_SUCCESS) 824258945Sroberto break; 825258945Sroberto } 826258945Sroberto 827258945Sroberto return (result); 828258945Sroberto} 829258945Sroberto 830258945Srobertovoid 831258945Srobertoisc_log_write(isc_log_t *lctx, isc_logcategory_t *category, 832258945Sroberto isc_logmodule_t *module, int level, const char *format, ...) 833258945Sroberto{ 834258945Sroberto va_list args; 835258945Sroberto 836258945Sroberto /* 837258945Sroberto * Contract checking is done in isc_log_doit(). 838258945Sroberto */ 839258945Sroberto 840258945Sroberto va_start(args, format); 841258945Sroberto isc_log_doit(lctx, category, module, level, ISC_FALSE, 842258945Sroberto NULL, 0, 0, format, args); 843258945Sroberto va_end(args); 844258945Sroberto} 845258945Sroberto 846258945Srobertovoid 847258945Srobertoisc_log_vwrite(isc_log_t *lctx, isc_logcategory_t *category, 848258945Sroberto isc_logmodule_t *module, int level, 849258945Sroberto const char *format, va_list args) 850258945Sroberto{ 851258945Sroberto /* 852258945Sroberto * Contract checking is done in isc_log_doit(). 853258945Sroberto */ 854258945Sroberto isc_log_doit(lctx, category, module, level, ISC_FALSE, 855258945Sroberto NULL, 0, 0, format, args); 856258945Sroberto} 857258945Sroberto 858258945Srobertovoid 859258945Srobertoisc_log_write1(isc_log_t *lctx, isc_logcategory_t *category, 860258945Sroberto isc_logmodule_t *module, int level, const char *format, ...) 861258945Sroberto{ 862258945Sroberto va_list args; 863258945Sroberto 864258945Sroberto /* 865258945Sroberto * Contract checking is done in isc_log_doit(). 866258945Sroberto */ 867258945Sroberto 868258945Sroberto va_start(args, format); 869258945Sroberto isc_log_doit(lctx, category, module, level, ISC_TRUE, 870258945Sroberto NULL, 0, 0, format, args); 871258945Sroberto va_end(args); 872258945Sroberto} 873258945Sroberto 874258945Srobertovoid 875258945Srobertoisc_log_vwrite1(isc_log_t *lctx, isc_logcategory_t *category, 876258945Sroberto isc_logmodule_t *module, int level, 877258945Sroberto const char *format, va_list args) 878258945Sroberto{ 879258945Sroberto /* 880258945Sroberto * Contract checking is done in isc_log_doit(). 881258945Sroberto */ 882258945Sroberto isc_log_doit(lctx, category, module, level, ISC_TRUE, 883258945Sroberto NULL, 0, 0, format, args); 884258945Sroberto} 885258945Sroberto 886258945Srobertovoid 887258945Srobertoisc_log_iwrite(isc_log_t *lctx, isc_logcategory_t *category, 888258945Sroberto isc_logmodule_t *module, int level, 889258945Sroberto isc_msgcat_t *msgcat, int msgset, int msg, 890258945Sroberto const char *format, ...) 891258945Sroberto{ 892258945Sroberto va_list args; 893258945Sroberto 894258945Sroberto /* 895258945Sroberto * Contract checking is done in isc_log_doit(). 896258945Sroberto */ 897258945Sroberto 898258945Sroberto va_start(args, format); 899258945Sroberto isc_log_doit(lctx, category, module, level, ISC_FALSE, 900258945Sroberto msgcat, msgset, msg, format, args); 901258945Sroberto va_end(args); 902258945Sroberto} 903258945Sroberto 904258945Srobertovoid 905258945Srobertoisc_log_ivwrite(isc_log_t *lctx, isc_logcategory_t *category, 906258945Sroberto isc_logmodule_t *module, int level, 907258945Sroberto isc_msgcat_t *msgcat, int msgset, int msg, 908258945Sroberto const char *format, va_list args) 909258945Sroberto{ 910258945Sroberto /* 911258945Sroberto * Contract checking is done in isc_log_doit(). 912258945Sroberto */ 913258945Sroberto isc_log_doit(lctx, category, module, level, ISC_FALSE, 914258945Sroberto msgcat, msgset, msg, format, args); 915258945Sroberto} 916258945Sroberto 917258945Srobertovoid 918258945Srobertoisc_log_iwrite1(isc_log_t *lctx, isc_logcategory_t *category, 919258945Sroberto isc_logmodule_t *module, int level, 920258945Sroberto isc_msgcat_t *msgcat, int msgset, int msg, 921258945Sroberto const char *format, ...) 922258945Sroberto{ 923258945Sroberto va_list args; 924258945Sroberto 925258945Sroberto /* 926258945Sroberto * Contract checking is done in isc_log_doit(). 927258945Sroberto */ 928258945Sroberto 929258945Sroberto va_start(args, format); 930258945Sroberto isc_log_doit(lctx, category, module, level, ISC_TRUE, 931258945Sroberto msgcat, msgset, msg, format, args); 932258945Sroberto va_end(args); 933258945Sroberto} 934258945Sroberto 935258945Srobertovoid 936258945Srobertoisc_log_ivwrite1(isc_log_t *lctx, isc_logcategory_t *category, 937258945Sroberto isc_logmodule_t *module, int level, 938258945Sroberto isc_msgcat_t *msgcat, int msgset, int msg, 939258945Sroberto const char *format, va_list args) 940258945Sroberto{ 941258945Sroberto /* 942258945Sroberto * Contract checking is done in isc_log_doit(). 943258945Sroberto */ 944258945Sroberto isc_log_doit(lctx, category, module, level, ISC_TRUE, 945258945Sroberto msgcat, msgset, msg, format, args); 946258945Sroberto} 947258945Sroberto 948258945Srobertovoid 949258945Srobertoisc_log_setcontext(isc_log_t *lctx) { 950258945Sroberto isc_lctx = lctx; 951258945Sroberto} 952258945Sroberto 953258945Srobertovoid 954258945Srobertoisc_log_setdebuglevel(isc_log_t *lctx, unsigned int level) { 955258945Sroberto isc_logchannel_t *channel; 956258945Sroberto 957258945Sroberto REQUIRE(VALID_CONTEXT(lctx)); 958258945Sroberto 959258945Sroberto LOCK(&lctx->lock); 960258945Sroberto 961258945Sroberto lctx->debug_level = level; 962258945Sroberto /* 963258945Sroberto * Close ISC_LOG_DEBUGONLY channels if level is zero. 964258945Sroberto */ 965258945Sroberto if (lctx->debug_level == 0) 966258945Sroberto for (channel = ISC_LIST_HEAD(lctx->logconfig->channels); 967258945Sroberto channel != NULL; 968258945Sroberto channel = ISC_LIST_NEXT(channel, link)) 969258945Sroberto if (channel->type == ISC_LOG_TOFILE && 970258945Sroberto (channel->flags & ISC_LOG_DEBUGONLY) != 0 && 971258945Sroberto FILE_STREAM(channel) != NULL) { 972258945Sroberto (void)fclose(FILE_STREAM(channel)); 973258945Sroberto FILE_STREAM(channel) = NULL; 974258945Sroberto } 975258945Sroberto UNLOCK(&lctx->lock); 976258945Sroberto} 977258945Sroberto 978258945Srobertounsigned int 979258945Srobertoisc_log_getdebuglevel(isc_log_t *lctx) { 980258945Sroberto REQUIRE(VALID_CONTEXT(lctx)); 981258945Sroberto 982258945Sroberto return (lctx->debug_level); 983258945Sroberto} 984258945Sroberto 985258945Srobertovoid 986258945Srobertoisc_log_setduplicateinterval(isc_logconfig_t *lcfg, unsigned int interval) { 987258945Sroberto REQUIRE(VALID_CONFIG(lcfg)); 988258945Sroberto 989258945Sroberto lcfg->duplicate_interval = interval; 990258945Sroberto} 991258945Sroberto 992258945Srobertounsigned int 993258945Srobertoisc_log_getduplicateinterval(isc_logconfig_t *lcfg) { 994258945Sroberto REQUIRE(VALID_CONTEXT(lcfg)); 995258945Sroberto 996258945Sroberto return (lcfg->duplicate_interval); 997258945Sroberto} 998258945Sroberto 999258945Srobertoisc_result_t 1000258945Srobertoisc_log_settag(isc_logconfig_t *lcfg, const char *tag) { 1001258945Sroberto REQUIRE(VALID_CONFIG(lcfg)); 1002258945Sroberto 1003258945Sroberto if (tag != NULL && *tag != '\0') { 1004258945Sroberto if (lcfg->tag != NULL) 1005258945Sroberto isc_mem_free(lcfg->lctx->mctx, lcfg->tag); 1006258945Sroberto lcfg->tag = isc_mem_strdup(lcfg->lctx->mctx, tag); 1007258945Sroberto if (lcfg->tag == NULL) 1008258945Sroberto return (ISC_R_NOMEMORY); 1009258945Sroberto 1010258945Sroberto } else { 1011258945Sroberto if (lcfg->tag != NULL) 1012258945Sroberto isc_mem_free(lcfg->lctx->mctx, lcfg->tag); 1013258945Sroberto lcfg->tag = NULL; 1014258945Sroberto } 1015258945Sroberto 1016258945Sroberto return (ISC_R_SUCCESS); 1017258945Sroberto} 1018258945Sroberto 1019258945Srobertochar * 1020258945Srobertoisc_log_gettag(isc_logconfig_t *lcfg) { 1021258945Sroberto REQUIRE(VALID_CONFIG(lcfg)); 1022258945Sroberto 1023258945Sroberto return (lcfg->tag); 1024258945Sroberto} 1025258945Sroberto 1026258945Sroberto/* XXXDCL NT -- This interface will assuredly be changing. */ 1027258945Srobertovoid 1028258945Srobertoisc_log_opensyslog(const char *tag, int options, int facility) { 1029258945Sroberto (void)openlog(tag, options, facility); 1030258945Sroberto} 1031258945Sroberto 1032258945Srobertovoid 1033258945Srobertoisc_log_closefilelogs(isc_log_t *lctx) { 1034258945Sroberto isc_logchannel_t *channel; 1035258945Sroberto 1036258945Sroberto REQUIRE(VALID_CONTEXT(lctx)); 1037258945Sroberto 1038258945Sroberto LOCK(&lctx->lock); 1039258945Sroberto for (channel = ISC_LIST_HEAD(lctx->logconfig->channels); 1040258945Sroberto channel != NULL; 1041258945Sroberto channel = ISC_LIST_NEXT(channel, link)) 1042258945Sroberto 1043258945Sroberto if (channel->type == ISC_LOG_TOFILE && 1044258945Sroberto FILE_STREAM(channel) != NULL) { 1045258945Sroberto (void)fclose(FILE_STREAM(channel)); 1046258945Sroberto FILE_STREAM(channel) = NULL; 1047258945Sroberto } 1048258945Sroberto UNLOCK(&lctx->lock); 1049258945Sroberto} 1050258945Sroberto 1051258945Sroberto/**** 1052258945Sroberto **** Internal functions 1053258945Sroberto ****/ 1054258945Sroberto 1055258945Srobertostatic isc_result_t 1056258945Srobertoassignchannel(isc_logconfig_t *lcfg, unsigned int category_id, 1057258945Sroberto const isc_logmodule_t *module, isc_logchannel_t *channel) 1058258945Sroberto{ 1059258945Sroberto isc_logchannellist_t *new_item; 1060258945Sroberto isc_log_t *lctx; 1061258945Sroberto isc_result_t result; 1062258945Sroberto 1063258945Sroberto REQUIRE(VALID_CONFIG(lcfg)); 1064258945Sroberto 1065258945Sroberto lctx = lcfg->lctx; 1066258945Sroberto 1067258945Sroberto REQUIRE(category_id < lctx->category_count); 1068258945Sroberto REQUIRE(module == NULL || module->id < lctx->module_count); 1069258945Sroberto REQUIRE(channel != NULL); 1070258945Sroberto 1071258945Sroberto /* 1072258945Sroberto * Ensure lcfg->channellist_count == lctx->category_count. 1073258945Sroberto */ 1074258945Sroberto result = sync_channellist(lcfg); 1075258945Sroberto if (result != ISC_R_SUCCESS) 1076258945Sroberto return (result); 1077258945Sroberto 1078258945Sroberto new_item = isc_mem_get(lctx->mctx, sizeof(*new_item)); 1079258945Sroberto if (new_item == NULL) 1080258945Sroberto return (ISC_R_NOMEMORY); 1081258945Sroberto 1082258945Sroberto new_item->channel = channel; 1083258945Sroberto new_item->module = module; 1084258945Sroberto ISC_LIST_INITANDPREPEND(lcfg->channellists[category_id], 1085258945Sroberto new_item, link); 1086258945Sroberto 1087258945Sroberto /* 1088258945Sroberto * Remember the highest logging level set by any channel in the 1089258945Sroberto * logging config, so isc_log_doit() can quickly return if the 1090258945Sroberto * message is too high to be logged by any channel. 1091258945Sroberto */ 1092258945Sroberto if (channel->type != ISC_LOG_TONULL) { 1093258945Sroberto if (lcfg->highest_level < channel->level) 1094258945Sroberto lcfg->highest_level = channel->level; 1095258945Sroberto if (channel->level == ISC_LOG_DYNAMIC) 1096258945Sroberto lcfg->dynamic = ISC_TRUE; 1097258945Sroberto } 1098258945Sroberto 1099258945Sroberto return (ISC_R_SUCCESS); 1100258945Sroberto} 1101258945Sroberto 1102258945Sroberto/* 1103258945Sroberto * This would ideally be part of isc_log_registercategories(), except then 1104258945Sroberto * that function would have to return isc_result_t instead of void. 1105258945Sroberto */ 1106258945Srobertostatic isc_result_t 1107258945Srobertosync_channellist(isc_logconfig_t *lcfg) { 1108258945Sroberto unsigned int bytes; 1109258945Sroberto isc_log_t *lctx; 1110258945Sroberto void *lists; 1111258945Sroberto 1112258945Sroberto REQUIRE(VALID_CONFIG(lcfg)); 1113258945Sroberto 1114258945Sroberto lctx = lcfg->lctx; 1115258945Sroberto 1116258945Sroberto REQUIRE(lctx->category_count != 0); 1117258945Sroberto 1118258945Sroberto if (lctx->category_count == lcfg->channellist_count) 1119258945Sroberto return (ISC_R_SUCCESS); 1120258945Sroberto 1121258945Sroberto bytes = lctx->category_count * sizeof(ISC_LIST(isc_logchannellist_t)); 1122258945Sroberto 1123258945Sroberto lists = isc_mem_get(lctx->mctx, bytes); 1124258945Sroberto 1125258945Sroberto if (lists == NULL) 1126258945Sroberto return (ISC_R_NOMEMORY); 1127258945Sroberto 1128258945Sroberto memset(lists, 0, bytes); 1129258945Sroberto 1130258945Sroberto if (lcfg->channellist_count != 0) { 1131258945Sroberto bytes = lcfg->channellist_count * 1132258945Sroberto sizeof(ISC_LIST(isc_logchannellist_t)); 1133258945Sroberto memcpy(lists, lcfg->channellists, bytes); 1134258945Sroberto isc_mem_put(lctx->mctx, lcfg->channellists, bytes); 1135258945Sroberto } 1136258945Sroberto 1137258945Sroberto lcfg->channellists = lists; 1138258945Sroberto lcfg->channellist_count = lctx->category_count; 1139258945Sroberto 1140258945Sroberto return (ISC_R_SUCCESS); 1141258945Sroberto} 1142258945Sroberto 1143258945Srobertostatic isc_result_t 1144258945Srobertogreatest_version(isc_logchannel_t *channel, int *greatestp) { 1145258945Sroberto /* XXXDCL HIGHLY NT */ 1146285612Sdelphij char *basenam, *digit_end; 1147258945Sroberto const char *dirname; 1148258945Sroberto int version, greatest = -1; 1149293650Sglebius size_t basenamelen; 1150258945Sroberto isc_dir_t dir; 1151258945Sroberto isc_result_t result; 1152258945Sroberto char sep = '/'; 1153258945Sroberto#ifdef _WIN32 1154258945Sroberto char *basename2; 1155258945Sroberto#endif 1156258945Sroberto 1157258945Sroberto REQUIRE(channel->type == ISC_LOG_TOFILE); 1158258945Sroberto 1159258945Sroberto /* 1160258945Sroberto * It is safe to DE_CONST the file.name because it was copied 1161258945Sroberto * with isc_mem_strdup in isc_log_createchannel. 1162258945Sroberto */ 1163285612Sdelphij basenam = strrchr(FILE_NAME(channel), sep); 1164258945Sroberto#ifdef _WIN32 1165258945Sroberto basename2 = strrchr(FILE_NAME(channel), '\\'); 1166285612Sdelphij if ((basenam != NULL && basename2 != NULL && basename2 > basenam) || 1167285612Sdelphij (basenam == NULL && basename2 != NULL)) { 1168285612Sdelphij basenam = basename2; 1169258945Sroberto sep = '\\'; 1170258945Sroberto } 1171258945Sroberto#endif 1172285612Sdelphij if (basenam != NULL) { 1173285612Sdelphij *basenam++ = '\0'; 1174258945Sroberto dirname = FILE_NAME(channel); 1175258945Sroberto } else { 1176285612Sdelphij DE_CONST(FILE_NAME(channel), basenam); 1177258945Sroberto dirname = "."; 1178258945Sroberto } 1179285612Sdelphij basenamelen = strlen(basenam); 1180258945Sroberto 1181258945Sroberto isc_dir_init(&dir); 1182258945Sroberto result = isc_dir_open(&dir, dirname); 1183258945Sroberto 1184258945Sroberto /* 1185258945Sroberto * Replace the file separator if it was taken out. 1186258945Sroberto */ 1187285612Sdelphij if (basenam != FILE_NAME(channel)) 1188285612Sdelphij *(basenam - 1) = sep; 1189258945Sroberto 1190258945Sroberto /* 1191258945Sroberto * Return if the directory open failed. 1192258945Sroberto */ 1193258945Sroberto if (result != ISC_R_SUCCESS) 1194258945Sroberto return (result); 1195258945Sroberto 1196258945Sroberto while (isc_dir_read(&dir) == ISC_R_SUCCESS) { 1197258945Sroberto if (dir.entry.length > basenamelen && 1198285612Sdelphij strncmp(dir.entry.name, basenam, basenamelen) == 0 && 1199258945Sroberto dir.entry.name[basenamelen] == '.') { 1200258945Sroberto 1201258945Sroberto version = strtol(&dir.entry.name[basenamelen + 1], 1202258945Sroberto &digit_end, 10); 1203258945Sroberto if (*digit_end == '\0' && version > greatest) 1204258945Sroberto greatest = version; 1205258945Sroberto } 1206258945Sroberto } 1207258945Sroberto isc_dir_close(&dir); 1208258945Sroberto 1209258945Sroberto *greatestp = ++greatest; 1210258945Sroberto 1211258945Sroberto return (ISC_R_SUCCESS); 1212258945Sroberto} 1213258945Sroberto 1214258945Srobertostatic isc_result_t 1215258945Srobertoroll_log(isc_logchannel_t *channel) { 1216258945Sroberto int i, n, greatest; 1217258945Sroberto char current[PATH_MAX + 1]; 1218258945Sroberto char new[PATH_MAX + 1]; 1219258945Sroberto const char *path; 1220258945Sroberto isc_result_t result; 1221258945Sroberto 1222258945Sroberto /* 1223258945Sroberto * Do nothing (not even excess version trimming) if ISC_LOG_ROLLNEVER 1224258945Sroberto * is specified. Apparently complete external control over the log 1225258945Sroberto * files is desired. 1226258945Sroberto */ 1227258945Sroberto if (FILE_VERSIONS(channel) == ISC_LOG_ROLLNEVER) 1228258945Sroberto return (ISC_R_SUCCESS); 1229258945Sroberto 1230258945Sroberto path = FILE_NAME(channel); 1231258945Sroberto 1232258945Sroberto /* 1233258945Sroberto * Set greatest_version to the greatest existing version 1234258945Sroberto * (not the maximum requested version). This is 1 based even 1235258945Sroberto * though the file names are 0 based, so an oldest log of log.1 1236258945Sroberto * is a greatest_version of 2. 1237258945Sroberto */ 1238258945Sroberto result = greatest_version(channel, &greatest); 1239258945Sroberto if (result != ISC_R_SUCCESS) 1240258945Sroberto return (result); 1241258945Sroberto 1242258945Sroberto /* 1243258945Sroberto * Now greatest should be set to the highest version number desired. 1244258945Sroberto * Since the highest number is one less than FILE_VERSIONS(channel) 1245258945Sroberto * when not doing infinite log rolling, greatest will need to be 1246258945Sroberto * decremented when it is equal to -- or greater than -- 1247258945Sroberto * FILE_VERSIONS(channel). When greatest is less than 1248258945Sroberto * FILE_VERSIONS(channel), it is already suitable for use as 1249258945Sroberto * the maximum version number. 1250258945Sroberto */ 1251258945Sroberto 1252258945Sroberto if (FILE_VERSIONS(channel) == ISC_LOG_ROLLINFINITE || 1253258945Sroberto FILE_VERSIONS(channel) > greatest) 1254258945Sroberto ; /* Do nothing. */ 1255258945Sroberto else 1256258945Sroberto /* 1257258945Sroberto * When greatest is >= FILE_VERSIONS(channel), it needs to 1258258945Sroberto * be reduced until it is FILE_VERSIONS(channel) - 1. 1259258945Sroberto * Remove any excess logs on the way to that value. 1260258945Sroberto */ 1261258945Sroberto while (--greatest >= FILE_VERSIONS(channel)) { 1262258945Sroberto n = snprintf(current, sizeof(current), "%s.%d", 1263258945Sroberto path, greatest); 1264258945Sroberto if (n >= (int)sizeof(current) || n < 0) 1265258945Sroberto result = ISC_R_NOSPACE; 1266258945Sroberto else 1267258945Sroberto result = isc_file_remove(current); 1268258945Sroberto if (result != ISC_R_SUCCESS && 1269258945Sroberto result != ISC_R_FILENOTFOUND) 1270258945Sroberto syslog(LOG_ERR, 1271258945Sroberto "unable to remove log file '%s.%d': %s", 1272258945Sroberto path, greatest, 1273258945Sroberto isc_result_totext(result)); 1274258945Sroberto } 1275258945Sroberto 1276258945Sroberto for (i = greatest; i > 0; i--) { 1277258945Sroberto result = ISC_R_SUCCESS; 1278258945Sroberto n = snprintf(current, sizeof(current), "%s.%d", path, i - 1); 1279258945Sroberto if (n >= (int)sizeof(current) || n < 0) 1280258945Sroberto result = ISC_R_NOSPACE; 1281258945Sroberto if (result == ISC_R_SUCCESS) { 1282258945Sroberto n = snprintf(new, sizeof(new), "%s.%d", path, i); 1283258945Sroberto if (n >= (int)sizeof(new) || n < 0) 1284258945Sroberto result = ISC_R_NOSPACE; 1285258945Sroberto } 1286258945Sroberto if (result == ISC_R_SUCCESS) 1287258945Sroberto result = isc_file_rename(current, new); 1288258945Sroberto if (result != ISC_R_SUCCESS && 1289258945Sroberto result != ISC_R_FILENOTFOUND) 1290258945Sroberto syslog(LOG_ERR, 1291258945Sroberto "unable to rename log file '%s.%d' to " 1292258945Sroberto "'%s.%d': %s", path, i - 1, path, i, 1293258945Sroberto isc_result_totext(result)); 1294258945Sroberto } 1295258945Sroberto 1296258945Sroberto if (FILE_VERSIONS(channel) != 0) { 1297258945Sroberto n = snprintf(new, sizeof(new), "%s.0", path); 1298258945Sroberto if (n >= (int)sizeof(new) || n < 0) 1299258945Sroberto result = ISC_R_NOSPACE; 1300258945Sroberto else 1301258945Sroberto result = isc_file_rename(path, new); 1302258945Sroberto if (result != ISC_R_SUCCESS && 1303258945Sroberto result != ISC_R_FILENOTFOUND) 1304258945Sroberto syslog(LOG_ERR, 1305258945Sroberto "unable to rename log file '%s' to '%s.0': %s", 1306258945Sroberto path, path, isc_result_totext(result)); 1307258945Sroberto } else { 1308258945Sroberto result = isc_file_remove(path); 1309258945Sroberto if (result != ISC_R_SUCCESS && 1310258945Sroberto result != ISC_R_FILENOTFOUND) 1311258945Sroberto syslog(LOG_ERR, "unable to remove log file '%s': %s", 1312258945Sroberto path, isc_result_totext(result)); 1313258945Sroberto } 1314258945Sroberto 1315258945Sroberto return (ISC_R_SUCCESS); 1316258945Sroberto} 1317258945Sroberto 1318258945Srobertostatic isc_result_t 1319258945Srobertoisc_log_open(isc_logchannel_t *channel) { 1320258945Sroberto struct stat statbuf; 1321258945Sroberto isc_boolean_t regular_file; 1322258945Sroberto isc_boolean_t roll = ISC_FALSE; 1323258945Sroberto isc_result_t result = ISC_R_SUCCESS; 1324258945Sroberto const char *path; 1325258945Sroberto 1326258945Sroberto REQUIRE(channel->type == ISC_LOG_TOFILE); 1327258945Sroberto REQUIRE(FILE_STREAM(channel) == NULL); 1328258945Sroberto 1329258945Sroberto path = FILE_NAME(channel); 1330258945Sroberto 1331258945Sroberto REQUIRE(path != NULL && *path != '\0'); 1332258945Sroberto 1333258945Sroberto /* 1334258945Sroberto * Determine type of file; only regular files will be 1335258945Sroberto * version renamed, and only if the base file exists 1336258945Sroberto * and either has no size limit or has reached its size limit. 1337258945Sroberto */ 1338258945Sroberto if (stat(path, &statbuf) == 0) { 1339258945Sroberto regular_file = S_ISREG(statbuf.st_mode) ? ISC_TRUE : ISC_FALSE; 1340258945Sroberto /* XXXDCL if not regular_file complain? */ 1341258945Sroberto if ((FILE_MAXSIZE(channel) == 0 && 1342258945Sroberto FILE_VERSIONS(channel) != ISC_LOG_ROLLNEVER) || 1343258945Sroberto (FILE_MAXSIZE(channel) > 0 && 1344258945Sroberto statbuf.st_size >= FILE_MAXSIZE(channel))) 1345258945Sroberto roll = regular_file; 1346280849Scy } else if (errno == ENOENT) { 1347258945Sroberto regular_file = ISC_TRUE; 1348280849Scy POST(regular_file); 1349280849Scy } else 1350258945Sroberto result = ISC_R_INVALIDFILE; 1351258945Sroberto 1352258945Sroberto /* 1353258945Sroberto * Version control. 1354258945Sroberto */ 1355258945Sroberto if (result == ISC_R_SUCCESS && roll) { 1356258945Sroberto if (FILE_VERSIONS(channel) == ISC_LOG_ROLLNEVER) 1357258945Sroberto return (ISC_R_MAXSIZE); 1358258945Sroberto result = roll_log(channel); 1359258945Sroberto if (result != ISC_R_SUCCESS) { 1360258945Sroberto if ((channel->flags & ISC_LOG_OPENERR) == 0) { 1361258945Sroberto syslog(LOG_ERR, 1362258945Sroberto "isc_log_open: roll_log '%s' " 1363258945Sroberto "failed: %s", 1364258945Sroberto FILE_NAME(channel), 1365258945Sroberto isc_result_totext(result)); 1366258945Sroberto channel->flags |= ISC_LOG_OPENERR; 1367258945Sroberto } 1368258945Sroberto return (result); 1369258945Sroberto } 1370258945Sroberto } 1371258945Sroberto 1372258945Sroberto result = isc_stdio_open(path, "a", &FILE_STREAM(channel)); 1373258945Sroberto 1374258945Sroberto return (result); 1375258945Sroberto} 1376258945Sroberto 1377258945Srobertoisc_boolean_t 1378258945Srobertoisc_log_wouldlog(isc_log_t *lctx, int level) { 1379258945Sroberto /* 1380258945Sroberto * Try to avoid locking the mutex for messages which can't 1381258945Sroberto * possibly be logged to any channels -- primarily debugging 1382258945Sroberto * messages that the debug level is not high enough to print. 1383258945Sroberto * 1384258945Sroberto * If the level is (mathematically) less than or equal to the 1385258945Sroberto * highest_level, or if there is a dynamic channel and the level is 1386258945Sroberto * less than or equal to the debug level, the main loop must be 1387258945Sroberto * entered to see if the message should really be output. 1388258945Sroberto * 1389258945Sroberto * NOTE: this is UNLOCKED access to the logconfig. However, 1390258945Sroberto * the worst thing that can happen is that a bad decision is made 1391258945Sroberto * about returning without logging, and that's not a big concern, 1392258945Sroberto * because that's a risk anyway if the logconfig is being 1393258945Sroberto * dynamically changed. 1394258945Sroberto */ 1395258945Sroberto 1396258945Sroberto if (lctx == NULL || lctx->logconfig == NULL) 1397258945Sroberto return (ISC_FALSE); 1398258945Sroberto 1399258945Sroberto return (ISC_TF(level <= lctx->logconfig->highest_level || 1400258945Sroberto (lctx->logconfig->dynamic && 1401258945Sroberto level <= lctx->debug_level))); 1402258945Sroberto} 1403258945Sroberto 1404258945Srobertostatic void 1405258945Srobertoisc_log_doit(isc_log_t *lctx, isc_logcategory_t *category, 1406258945Sroberto isc_logmodule_t *module, int level, isc_boolean_t write_once, 1407258945Sroberto isc_msgcat_t *msgcat, int msgset, int msg, 1408258945Sroberto const char *format, va_list args) 1409258945Sroberto{ 1410258945Sroberto int syslog_level; 1411258945Sroberto char time_string[64]; 1412258945Sroberto char level_string[24]; 1413280849Scy size_t octets; 1414258945Sroberto const char *iformat; 1415258945Sroberto struct stat statbuf; 1416258945Sroberto isc_boolean_t matched = ISC_FALSE; 1417258945Sroberto isc_boolean_t printtime, printtag; 1418258945Sroberto isc_boolean_t printcategory, printmodule, printlevel; 1419258945Sroberto isc_logconfig_t *lcfg; 1420258945Sroberto isc_logchannel_t *channel; 1421258945Sroberto isc_logchannellist_t *category_channels; 1422258945Sroberto isc_result_t result; 1423258945Sroberto 1424258945Sroberto REQUIRE(lctx == NULL || VALID_CONTEXT(lctx)); 1425258945Sroberto REQUIRE(category != NULL); 1426258945Sroberto REQUIRE(module != NULL); 1427258945Sroberto REQUIRE(level != ISC_LOG_DYNAMIC); 1428258945Sroberto REQUIRE(format != NULL); 1429258945Sroberto 1430258945Sroberto /* 1431258945Sroberto * Programs can use libraries that use this logging code without 1432258945Sroberto * wanting to do any logging, thus the log context is allowed to 1433258945Sroberto * be non-existent. 1434258945Sroberto */ 1435258945Sroberto if (lctx == NULL) 1436258945Sroberto return; 1437258945Sroberto 1438258945Sroberto REQUIRE(category->id < lctx->category_count); 1439258945Sroberto REQUIRE(module->id < lctx->module_count); 1440258945Sroberto 1441258945Sroberto if (! isc_log_wouldlog(lctx, level)) 1442258945Sroberto return; 1443258945Sroberto 1444258945Sroberto if (msgcat != NULL) 1445258945Sroberto iformat = isc_msgcat_get(msgcat, msgset, msg, format); 1446258945Sroberto else 1447258945Sroberto iformat = format; 1448258945Sroberto 1449258945Sroberto time_string[0] = '\0'; 1450258945Sroberto level_string[0] = '\0'; 1451258945Sroberto 1452258945Sroberto LOCK(&lctx->lock); 1453258945Sroberto 1454258945Sroberto lctx->buffer[0] = '\0'; 1455258945Sroberto 1456258945Sroberto lcfg = lctx->logconfig; 1457258945Sroberto 1458258945Sroberto category_channels = ISC_LIST_HEAD(lcfg->channellists[category->id]); 1459258945Sroberto 1460258945Sroberto /* 1461258945Sroberto * XXXDCL add duplicate filtering? (To not write multiple times to 1462258945Sroberto * the same source via various channels). 1463258945Sroberto */ 1464258945Sroberto do { 1465258945Sroberto /* 1466258945Sroberto * If the channel list end was reached and a match was made, 1467258945Sroberto * everything is finished. 1468258945Sroberto */ 1469258945Sroberto if (category_channels == NULL && matched) 1470258945Sroberto break; 1471258945Sroberto 1472258945Sroberto if (category_channels == NULL && ! matched && 1473258945Sroberto category_channels != ISC_LIST_HEAD(lcfg->channellists[0])) 1474258945Sroberto /* 1475258945Sroberto * No category/module pair was explicitly configured. 1476258945Sroberto * Try the category named "default". 1477258945Sroberto */ 1478258945Sroberto category_channels = 1479258945Sroberto ISC_LIST_HEAD(lcfg->channellists[0]); 1480258945Sroberto 1481258945Sroberto if (category_channels == NULL && ! matched) 1482258945Sroberto /* 1483258945Sroberto * No matching module was explicitly configured 1484258945Sroberto * for the category named "default". Use the internal 1485258945Sroberto * default channel. 1486258945Sroberto */ 1487258945Sroberto category_channels = &default_channel; 1488258945Sroberto 1489258945Sroberto if (category_channels->module != NULL && 1490258945Sroberto category_channels->module != module) { 1491258945Sroberto category_channels = ISC_LIST_NEXT(category_channels, 1492258945Sroberto link); 1493258945Sroberto continue; 1494258945Sroberto } 1495258945Sroberto 1496258945Sroberto matched = ISC_TRUE; 1497258945Sroberto 1498258945Sroberto channel = category_channels->channel; 1499258945Sroberto category_channels = ISC_LIST_NEXT(category_channels, link); 1500258945Sroberto 1501258945Sroberto if (((channel->flags & ISC_LOG_DEBUGONLY) != 0) && 1502258945Sroberto lctx->debug_level == 0) 1503258945Sroberto continue; 1504258945Sroberto 1505258945Sroberto if (channel->level == ISC_LOG_DYNAMIC) { 1506258945Sroberto if (lctx->debug_level < level) 1507258945Sroberto continue; 1508258945Sroberto } else if (channel->level < level) 1509258945Sroberto continue; 1510258945Sroberto 1511258945Sroberto if ((channel->flags & ISC_LOG_PRINTTIME) != 0 && 1512258945Sroberto time_string[0] == '\0') { 1513258945Sroberto isc_time_t isctime; 1514258945Sroberto 1515258945Sroberto TIME_NOW(&isctime); 1516258945Sroberto isc_time_formattimestamp(&isctime, time_string, 1517258945Sroberto sizeof(time_string)); 1518258945Sroberto } 1519258945Sroberto 1520258945Sroberto if ((channel->flags & ISC_LOG_PRINTLEVEL) != 0 && 1521258945Sroberto level_string[0] == '\0') { 1522258945Sroberto if (level < ISC_LOG_CRITICAL) 1523258945Sroberto snprintf(level_string, sizeof(level_string), 1524280849Scy "%s %d: ", 1525258945Sroberto isc_msgcat_get(isc_msgcat, 1526258945Sroberto ISC_MSGSET_LOG, 1527258945Sroberto ISC_MSG_LEVEL, 1528280849Scy "level"), 1529258945Sroberto level); 1530258945Sroberto else if (level > ISC_LOG_DYNAMIC) 1531258945Sroberto snprintf(level_string, sizeof(level_string), 1532258945Sroberto "%s %d: ", log_level_strings[0], 1533258945Sroberto level); 1534258945Sroberto else 1535258945Sroberto snprintf(level_string, sizeof(level_string), 1536258945Sroberto "%s: ", log_level_strings[-level]); 1537258945Sroberto } 1538258945Sroberto 1539258945Sroberto /* 1540258945Sroberto * Only format the message once. 1541258945Sroberto */ 1542258945Sroberto if (lctx->buffer[0] == '\0') { 1543258945Sroberto (void)vsnprintf(lctx->buffer, sizeof(lctx->buffer), 1544258945Sroberto iformat, args); 1545258945Sroberto 1546258945Sroberto /* 1547258945Sroberto * Check for duplicates. 1548258945Sroberto */ 1549258945Sroberto if (write_once) { 1550258945Sroberto isc_logmessage_t *message, *new; 1551258945Sroberto isc_time_t oldest; 1552258945Sroberto isc_interval_t interval; 1553258945Sroberto 1554258945Sroberto isc_interval_set(&interval, 1555258945Sroberto lcfg->duplicate_interval, 0); 1556258945Sroberto 1557258945Sroberto /* 1558258945Sroberto * 'oldest' is the age of the oldest messages 1559258945Sroberto * which fall within the duplicate_interval 1560258945Sroberto * range. 1561258945Sroberto */ 1562258945Sroberto TIME_NOW(&oldest); 1563258945Sroberto if (isc_time_subtract(&oldest, &interval, &oldest) 1564258945Sroberto != ISC_R_SUCCESS) 1565258945Sroberto /* 1566258945Sroberto * Can't effectively do the checking 1567258945Sroberto * without having a valid time. 1568258945Sroberto */ 1569258945Sroberto message = NULL; 1570258945Sroberto else 1571258945Sroberto message =ISC_LIST_HEAD(lctx->messages); 1572258945Sroberto 1573258945Sroberto while (message != NULL) { 1574258945Sroberto if (isc_time_compare(&message->time, 1575258945Sroberto &oldest) < 0) { 1576258945Sroberto /* 1577258945Sroberto * This message is older 1578258945Sroberto * than the duplicate_interval, 1579258945Sroberto * so it should be dropped from 1580258945Sroberto * the history. 1581258945Sroberto * 1582258945Sroberto * Setting the interval to be 1583258945Sroberto * to be longer will obviously 1584258945Sroberto * not cause the expired 1585258945Sroberto * message to spring back into 1586258945Sroberto * existence. 1587258945Sroberto */ 1588258945Sroberto new = ISC_LIST_NEXT(message, 1589258945Sroberto link); 1590258945Sroberto 1591258945Sroberto ISC_LIST_UNLINK(lctx->messages, 1592258945Sroberto message, link); 1593258945Sroberto 1594258945Sroberto isc_mem_put(lctx->mctx, 1595258945Sroberto message, 1596258945Sroberto sizeof(*message) + 1 + 1597258945Sroberto strlen(message->text)); 1598258945Sroberto 1599258945Sroberto message = new; 1600258945Sroberto continue; 1601258945Sroberto } 1602258945Sroberto 1603258945Sroberto /* 1604258945Sroberto * This message is in the duplicate 1605258945Sroberto * filtering interval ... 1606258945Sroberto */ 1607258945Sroberto if (strcmp(lctx->buffer, message->text) 1608258945Sroberto == 0) { 1609258945Sroberto /* 1610258945Sroberto * ... and it is a duplicate. 1611258945Sroberto * Unlock the mutex and 1612258945Sroberto * get the hell out of Dodge. 1613258945Sroberto */ 1614258945Sroberto UNLOCK(&lctx->lock); 1615258945Sroberto return; 1616258945Sroberto } 1617258945Sroberto 1618258945Sroberto message = ISC_LIST_NEXT(message, link); 1619258945Sroberto } 1620258945Sroberto 1621258945Sroberto /* 1622258945Sroberto * It wasn't in the duplicate interval, 1623258945Sroberto * so add it to the message list. 1624258945Sroberto */ 1625280849Scy octets = strlen(lctx->buffer) + 1; 1626258945Sroberto new = isc_mem_get(lctx->mctx, 1627258945Sroberto sizeof(isc_logmessage_t) + 1628280849Scy octets); 1629258945Sroberto if (new != NULL) { 1630258945Sroberto /* 1631258945Sroberto * Put the text immediately after 1632258945Sroberto * the struct. The strcpy is safe. 1633258945Sroberto */ 1634258945Sroberto new->text = (char *)(new + 1); 1635280849Scy strlcpy(new->text, lctx->buffer, octets); 1636258945Sroberto 1637258945Sroberto TIME_NOW(&new->time); 1638258945Sroberto 1639258945Sroberto ISC_LIST_APPEND(lctx->messages, 1640258945Sroberto new, link); 1641258945Sroberto } 1642258945Sroberto } 1643258945Sroberto } 1644258945Sroberto 1645258945Sroberto printtime = ISC_TF((channel->flags & ISC_LOG_PRINTTIME) 1646258945Sroberto != 0); 1647258945Sroberto printtag = ISC_TF((channel->flags & ISC_LOG_PRINTTAG) 1648258945Sroberto != 0 && lcfg->tag != NULL); 1649258945Sroberto printcategory = ISC_TF((channel->flags & ISC_LOG_PRINTCATEGORY) 1650258945Sroberto != 0); 1651258945Sroberto printmodule = ISC_TF((channel->flags & ISC_LOG_PRINTMODULE) 1652258945Sroberto != 0); 1653258945Sroberto printlevel = ISC_TF((channel->flags & ISC_LOG_PRINTLEVEL) 1654258945Sroberto != 0); 1655258945Sroberto 1656258945Sroberto switch (channel->type) { 1657258945Sroberto case ISC_LOG_TOFILE: 1658258945Sroberto if (FILE_MAXREACHED(channel)) { 1659258945Sroberto /* 1660258945Sroberto * If the file can be rolled, OR 1661258945Sroberto * If the file no longer exists, OR 1662258945Sroberto * If the file is less than the maximum size, 1663258945Sroberto * (such as if it had been renamed and 1664258945Sroberto * a new one touched, or it was truncated 1665258945Sroberto * in place) 1666258945Sroberto * ... then close it to trigger reopening. 1667258945Sroberto */ 1668258945Sroberto if (FILE_VERSIONS(channel) != 1669258945Sroberto ISC_LOG_ROLLNEVER || 1670258945Sroberto (stat(FILE_NAME(channel), &statbuf) != 0 && 1671258945Sroberto errno == ENOENT) || 1672258945Sroberto statbuf.st_size < FILE_MAXSIZE(channel)) { 1673258945Sroberto (void)fclose(FILE_STREAM(channel)); 1674258945Sroberto FILE_STREAM(channel) = NULL; 1675258945Sroberto FILE_MAXREACHED(channel) = ISC_FALSE; 1676258945Sroberto } else 1677258945Sroberto /* 1678258945Sroberto * Eh, skip it. 1679258945Sroberto */ 1680258945Sroberto break; 1681258945Sroberto } 1682258945Sroberto 1683258945Sroberto if (FILE_STREAM(channel) == NULL) { 1684258945Sroberto result = isc_log_open(channel); 1685258945Sroberto if (result != ISC_R_SUCCESS && 1686258945Sroberto result != ISC_R_MAXSIZE && 1687258945Sroberto (channel->flags & ISC_LOG_OPENERR) == 0) { 1688258945Sroberto syslog(LOG_ERR, 1689258945Sroberto "isc_log_open '%s' failed: %s", 1690258945Sroberto FILE_NAME(channel), 1691258945Sroberto isc_result_totext(result)); 1692258945Sroberto channel->flags |= ISC_LOG_OPENERR; 1693258945Sroberto } 1694258945Sroberto if (result != ISC_R_SUCCESS) 1695258945Sroberto break; 1696258945Sroberto channel->flags &= ~ISC_LOG_OPENERR; 1697258945Sroberto } 1698258945Sroberto /* FALLTHROUGH */ 1699258945Sroberto 1700258945Sroberto case ISC_LOG_TOFILEDESC: 1701258945Sroberto fprintf(FILE_STREAM(channel), "%s%s%s%s%s%s%s%s%s%s\n", 1702258945Sroberto printtime ? time_string : "", 1703258945Sroberto printtime ? " " : "", 1704258945Sroberto printtag ? lcfg->tag : "", 1705258945Sroberto printtag ? ": " : "", 1706258945Sroberto printcategory ? category->name : "", 1707258945Sroberto printcategory ? ": " : "", 1708258945Sroberto printmodule ? (module != NULL ? module->name 1709258945Sroberto : "no_module") 1710258945Sroberto : "", 1711258945Sroberto printmodule ? ": " : "", 1712258945Sroberto printlevel ? level_string : "", 1713258945Sroberto lctx->buffer); 1714258945Sroberto 1715258945Sroberto fflush(FILE_STREAM(channel)); 1716258945Sroberto 1717258945Sroberto /* 1718258945Sroberto * If the file now exceeds its maximum size 1719258945Sroberto * threshold, note it so that it will not be logged 1720258945Sroberto * to any more. 1721258945Sroberto */ 1722258945Sroberto if (FILE_MAXSIZE(channel) > 0) { 1723258945Sroberto INSIST(channel->type == ISC_LOG_TOFILE); 1724258945Sroberto 1725258945Sroberto /* XXXDCL NT fstat/fileno */ 1726258945Sroberto /* XXXDCL complain if fstat fails? */ 1727258945Sroberto if (fstat(fileno(FILE_STREAM(channel)), 1728258945Sroberto &statbuf) >= 0 && 1729258945Sroberto statbuf.st_size > FILE_MAXSIZE(channel)) 1730258945Sroberto FILE_MAXREACHED(channel) = ISC_TRUE; 1731258945Sroberto } 1732258945Sroberto 1733258945Sroberto break; 1734258945Sroberto 1735258945Sroberto case ISC_LOG_TOSYSLOG: 1736258945Sroberto if (level > 0) 1737258945Sroberto syslog_level = LOG_DEBUG; 1738258945Sroberto else if (level < ISC_LOG_CRITICAL) 1739258945Sroberto syslog_level = LOG_CRIT; 1740258945Sroberto else 1741258945Sroberto syslog_level = syslog_map[-level]; 1742258945Sroberto 1743258945Sroberto (void)syslog(FACILITY(channel) | syslog_level, 1744258945Sroberto "%s%s%s%s%s%s%s%s%s%s", 1745258945Sroberto printtime ? time_string : "", 1746258945Sroberto printtime ? " " : "", 1747258945Sroberto printtag ? lcfg->tag : "", 1748258945Sroberto printtag ? ": " : "", 1749258945Sroberto printcategory ? category->name : "", 1750258945Sroberto printcategory ? ": " : "", 1751258945Sroberto printmodule ? (module != NULL ? module->name 1752258945Sroberto : "no_module") 1753258945Sroberto : "", 1754258945Sroberto printmodule ? ": " : "", 1755258945Sroberto printlevel ? level_string : "", 1756258945Sroberto lctx->buffer); 1757258945Sroberto break; 1758258945Sroberto 1759258945Sroberto case ISC_LOG_TONULL: 1760258945Sroberto break; 1761258945Sroberto 1762258945Sroberto } 1763258945Sroberto 1764258945Sroberto } while (1); 1765258945Sroberto 1766258945Sroberto UNLOCK(&lctx->lock); 1767258945Sroberto} 1768