| File: | src/usr.bin/dig/lib/isc/log.c |
| Warning: | line 407, column 2 The left operand of '!=' is a garbage value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* | |||
| 2 | * Copyright (C) Internet Systems Consortium, Inc. ("ISC") | |||
| 3 | * | |||
| 4 | * Permission to use, copy, modify, and/or distribute this software for any | |||
| 5 | * purpose with or without fee is hereby granted, provided that the above | |||
| 6 | * copyright notice and this permission notice appear in all copies. | |||
| 7 | * | |||
| 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH | |||
| 9 | * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY | |||
| 10 | * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, | |||
| 11 | * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM | |||
| 12 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE | |||
| 13 | * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR | |||
| 14 | * PERFORMANCE OF THIS SOFTWARE. | |||
| 15 | */ | |||
| 16 | ||||
| 17 | /* $Id: log.c,v 1.18 2020/09/14 08:40:44 florian Exp $ */ | |||
| 18 | ||||
| 19 | /*! \file | |||
| 20 | * \author Principal Authors: DCL */ | |||
| 21 | ||||
| 22 | #include <sys/time.h> | |||
| 23 | #include <limits.h> | |||
| 24 | #include <stdlib.h> | |||
| 25 | #include <string.h> | |||
| 26 | #include <syslog.h> | |||
| 27 | #include <time.h> | |||
| 28 | ||||
| 29 | #include <isc/log.h> | |||
| 30 | #include <isc/util.h> | |||
| 31 | ||||
| 32 | /* | |||
| 33 | * XXXDCL make dynamic? | |||
| 34 | */ | |||
| 35 | #define LOG_BUFFER_SIZE(8 * 1024) (8 * 1024) | |||
| 36 | ||||
| 37 | /*! | |||
| 38 | * This is the structure that holds each named channel. A simple linked | |||
| 39 | * list chains all of the channels together, so an individual channel is | |||
| 40 | * found by doing strcmp()s with the names down the list. Their should | |||
| 41 | * be no performance penalty from this as it is expected that the number | |||
| 42 | * of named channels will be no more than a dozen or so, and name lookups | |||
| 43 | * from the head of the list are only done when isc_log_usechannel() is | |||
| 44 | * called, which should also be very infrequent. | |||
| 45 | */ | |||
| 46 | typedef struct isc_logchannel isc_logchannel_t; | |||
| 47 | ||||
| 48 | struct isc_logchannel { | |||
| 49 | char * name; | |||
| 50 | unsigned int type; | |||
| 51 | int level; | |||
| 52 | unsigned int flags; | |||
| 53 | isc_logdestination_t destination; | |||
| 54 | ISC_LINK(isc_logchannel_t)struct { isc_logchannel_t *prev, *next; } link; | |||
| 55 | }; | |||
| 56 | ||||
| 57 | /*! | |||
| 58 | * The logchannellist structure associates categories and modules with | |||
| 59 | * channels. First the appropriate channellist is found based on the | |||
| 60 | * category, and then each structure in the linked list is checked for | |||
| 61 | * a matching module. It is expected that the number of channels | |||
| 62 | * associated with any given category will be very short, no more than | |||
| 63 | * three or four in the more unusual cases. | |||
| 64 | */ | |||
| 65 | typedef struct isc_logchannellist isc_logchannellist_t; | |||
| 66 | ||||
| 67 | struct isc_logchannellist { | |||
| 68 | const isc_logmodule_t * module; | |||
| 69 | isc_logchannel_t * channel; | |||
| 70 | ISC_LINK(isc_logchannellist_t)struct { isc_logchannellist_t *prev, *next; } link; | |||
| 71 | }; | |||
| 72 | ||||
| 73 | /*! | |||
| 74 | * This structure is used to remember messages for pruning via | |||
| 75 | * isc_log_[v]write1(). | |||
| 76 | */ | |||
| 77 | typedef struct isc_logmessage isc_logmessage_t; | |||
| 78 | ||||
| 79 | struct isc_logmessage { | |||
| 80 | char * text; | |||
| 81 | struct timespec time; | |||
| 82 | ISC_LINK(isc_logmessage_t)struct { isc_logmessage_t *prev, *next; } link; | |||
| 83 | }; | |||
| 84 | ||||
| 85 | /*! | |||
| 86 | * The isc_logconfig structure is used to store the configurable information | |||
| 87 | * about where messages are actually supposed to be sent -- the information | |||
| 88 | * that could changed based on some configuration file, as opposed to the | |||
| 89 | * the category/module specification of isc_log_[v]write[1] that is compiled | |||
| 90 | * into a program, or the debug_level which is dynamic state information. | |||
| 91 | */ | |||
| 92 | struct isc_logconfig { | |||
| 93 | isc_log_t * lctx; | |||
| 94 | ISC_LIST(isc_logchannel_t)struct { isc_logchannel_t *head, *tail; } channels; | |||
| 95 | ISC_LIST(isc_logchannellist_t)struct { isc_logchannellist_t *head, *tail; } *channellists; | |||
| 96 | unsigned int channellist_count; | |||
| 97 | unsigned int duplicate_interval; | |||
| 98 | int highest_level; | |||
| 99 | char * tag; | |||
| 100 | int dynamic; | |||
| 101 | }; | |||
| 102 | ||||
| 103 | /*! | |||
| 104 | * This isc_log structure provides the context for the isc_log functions. | |||
| 105 | * The log context locks itself in isc_log_doit, the internal backend to | |||
| 106 | * isc_log_write. The locking is necessary both to provide exclusive access | |||
| 107 | * to the buffer into which the message is formatted and to guard against | |||
| 108 | * competing threads trying to write to the same syslog resource. (On | |||
| 109 | * some systems, such as BSD/OS, stdio is thread safe but syslog is not.) | |||
| 110 | * Unfortunately, the lock cannot guard against a _different_ logging | |||
| 111 | * context in the same program competing for syslog's attention. Thus | |||
| 112 | * There Can Be Only One, but this is not enforced. | |||
| 113 | * XXXDCL enforce it? | |||
| 114 | * | |||
| 115 | * Note that the category and module information is not locked. | |||
| 116 | * This is because in the usual case, only one isc_log_t is ever created | |||
| 117 | * in a program, and the category/module registration happens only once. | |||
| 118 | * XXXDCL it might be wise to add more locking overall. | |||
| 119 | */ | |||
| 120 | struct isc_log { | |||
| 121 | /* Not locked. */ | |||
| 122 | isc_logcategory_t * categories; | |||
| 123 | unsigned int category_count; | |||
| 124 | isc_logmodule_t * modules; | |||
| 125 | unsigned int module_count; | |||
| 126 | int debug_level; | |||
| 127 | /* Locked by isc_log lock. */ | |||
| 128 | isc_logconfig_t * logconfig; | |||
| 129 | char buffer[LOG_BUFFER_SIZE(8 * 1024)]; | |||
| 130 | ISC_LIST(isc_logmessage_t)struct { isc_logmessage_t *head, *tail; } messages; | |||
| 131 | }; | |||
| 132 | ||||
| 133 | /*! | |||
| 134 | * Used when ISC_LOG_PRINTLEVEL is enabled for a channel. | |||
| 135 | */ | |||
| 136 | static const char *log_level_strings[] = { | |||
| 137 | "debug", | |||
| 138 | "info", | |||
| 139 | "notice", | |||
| 140 | "warning", | |||
| 141 | "error", | |||
| 142 | "critical" | |||
| 143 | }; | |||
| 144 | ||||
| 145 | /*! | |||
| 146 | * Used to convert ISC_LOG_* priorities into syslog priorities. | |||
| 147 | * XXXDCL This will need modification for NT. | |||
| 148 | */ | |||
| 149 | static const int syslog_map[] = { | |||
| 150 | LOG_DEBUG7, | |||
| 151 | LOG_INFO6, | |||
| 152 | LOG_NOTICE5, | |||
| 153 | LOG_WARNING4, | |||
| 154 | LOG_ERR3, | |||
| 155 | LOG_CRIT2 | |||
| 156 | }; | |||
| 157 | ||||
| 158 | /*! | |||
| 159 | * When adding new categories, a corresponding ISC_LOGCATEGORY_foo | |||
| 160 | * definition needs to be added to <isc/log.h>. | |||
| 161 | * | |||
| 162 | * The default category is provided so that the internal default can | |||
| 163 | * be overridden. Since the default is always looked up as the first | |||
| 164 | * channellist in the log context, it must come first in isc_categories[]. | |||
| 165 | */ | |||
| 166 | isc_logcategory_t isc_categories[] = { | |||
| 167 | { "default", 0 }, /* "default" must come first. */ | |||
| 168 | { "general", 0 }, | |||
| 169 | { NULL((void *)0), 0 } | |||
| 170 | }; | |||
| 171 | ||||
| 172 | /*! | |||
| 173 | * See above comment for categories on LIBISC_EXTERNAL_DATA, and apply it to modules. | |||
| 174 | */ | |||
| 175 | isc_logmodule_t isc_modules[] = { | |||
| 176 | { "socket", 0 }, | |||
| 177 | { "time", 0 }, | |||
| 178 | { "interface", 0 }, | |||
| 179 | { "timer", 0 }, | |||
| 180 | { "file", 0 }, | |||
| 181 | { "other", 0 }, | |||
| 182 | { NULL((void *)0), 0 } | |||
| 183 | }; | |||
| 184 | ||||
| 185 | /*! | |||
| 186 | * This essentially constant structure must be filled in at run time, | |||
| 187 | * because its channel member is pointed to a channel that is created | |||
| 188 | * dynamically with isc_log_createchannel. | |||
| 189 | */ | |||
| 190 | static isc_logchannellist_t default_channel; | |||
| 191 | ||||
| 192 | /*! | |||
| 193 | * libisc logs to this context. | |||
| 194 | */ | |||
| 195 | isc_log_t *isc_lctx = NULL((void *)0); | |||
| 196 | ||||
| 197 | /*! | |||
| 198 | * Forward declarations. | |||
| 199 | */ | |||
| 200 | static isc_result_t | |||
| 201 | assignchannel(isc_logconfig_t *lcfg, unsigned int category_id, | |||
| 202 | const isc_logmodule_t *module, isc_logchannel_t *channel); | |||
| 203 | ||||
| 204 | static isc_result_t | |||
| 205 | sync_channellist(isc_logconfig_t *lcfg); | |||
| 206 | ||||
| 207 | static void | |||
| 208 | isc_log_doit(isc_log_t *lctx, isc_logcategory_t *category, | |||
| 209 | isc_logmodule_t *module, int level, int write_once, | |||
| 210 | const char *format, va_list args) | |||
| 211 | __attribute__((__format__(__printf__, 6, 0))); | |||
| 212 | ||||
| 213 | /*@{*/ | |||
| 214 | /*! | |||
| 215 | * Convenience macros. | |||
| 216 | */ | |||
| 217 | ||||
| 218 | #define FACILITY(channel)(channel->destination.facility) (channel->destination.facility) | |||
| 219 | #define FILE_NAME(channel)(channel->destination.file.name) (channel->destination.file.name) | |||
| 220 | #define FILE_STREAM(channel)(channel->destination.file.stream) (channel->destination.file.stream) | |||
| 221 | #define FILE_VERSIONS(channel)(channel->destination.file.versions) (channel->destination.file.versions) | |||
| 222 | #define FILE_MAXSIZE(channel)(channel->destination.file.maximum_size) (channel->destination.file.maximum_size) | |||
| 223 | ||||
| 224 | /*@}*/ | |||
| 225 | /**** | |||
| 226 | **** Public interfaces. | |||
| 227 | ****/ | |||
| 228 | ||||
| 229 | /* | |||
| 230 | * Establish a new logging context, with default channels. | |||
| 231 | */ | |||
| 232 | isc_result_t | |||
| 233 | isc_log_create(isc_log_t **lctxp, isc_logconfig_t **lcfgp) { | |||
| 234 | isc_log_t *lctx; | |||
| 235 | isc_logconfig_t *lcfg = NULL((void *)0); | |||
| 236 | isc_result_t result; | |||
| 237 | ||||
| 238 | REQUIRE(lctxp != NULL && *lctxp == NULL)((void) ((lctxp != ((void *)0) && *lctxp == ((void *) 0)) || ((isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/log.c" , 238, isc_assertiontype_require, "lctxp != ((void *)0) && *lctxp == ((void *)0)" ), 0))); | |||
| ||||
| 239 | REQUIRE(lcfgp == NULL || *lcfgp == NULL)((void) ((lcfgp == ((void *)0) || *lcfgp == ((void *)0)) || ( (isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/log.c", 239 , isc_assertiontype_require, "lcfgp == ((void *)0) || *lcfgp == ((void *)0)" ), 0))); | |||
| 240 | ||||
| 241 | lctx = malloc(sizeof(*lctx)); | |||
| 242 | if (lctx != NULL((void *)0)) { | |||
| 243 | lctx->categories = NULL((void *)0); | |||
| 244 | lctx->category_count = 0; | |||
| 245 | lctx->modules = NULL((void *)0); | |||
| 246 | lctx->module_count = 0; | |||
| 247 | lctx->debug_level = 0; | |||
| 248 | ||||
| 249 | ISC_LIST_INIT(lctx->messages)do { (lctx->messages).head = ((void *)0); (lctx->messages ).tail = ((void *)0); } while (0); | |||
| 250 | ||||
| 251 | isc_log_registercategories(lctx, isc_categories); | |||
| 252 | isc_log_registermodules(lctx, isc_modules); | |||
| 253 | result = isc_logconfig_create(lctx, &lcfg); | |||
| 254 | ||||
| 255 | } else | |||
| 256 | result = ISC_R_NOMEMORY1; | |||
| 257 | ||||
| 258 | if (result == ISC_R_SUCCESS0) | |||
| 259 | result = sync_channellist(lcfg); | |||
| 260 | ||||
| 261 | if (result == ISC_R_SUCCESS0) { | |||
| 262 | lctx->logconfig = lcfg; | |||
| 263 | ||||
| 264 | *lctxp = lctx; | |||
| 265 | if (lcfgp != NULL((void *)0)) | |||
| 266 | *lcfgp = lcfg; | |||
| 267 | ||||
| 268 | } else { | |||
| 269 | if (lcfg != NULL((void *)0)) | |||
| 270 | isc_logconfig_destroy(&lcfg); | |||
| 271 | if (lctx != NULL((void *)0)) | |||
| 272 | isc_log_destroy(&lctx); | |||
| 273 | } | |||
| 274 | ||||
| 275 | return (result); | |||
| 276 | } | |||
| 277 | ||||
| 278 | isc_result_t | |||
| 279 | isc_logconfig_create(isc_log_t *lctx, isc_logconfig_t **lcfgp) { | |||
| 280 | isc_logconfig_t *lcfg; | |||
| 281 | isc_logdestination_t destination; | |||
| 282 | isc_result_t result = ISC_R_SUCCESS0; | |||
| 283 | int level = ISC_LOG_INFO(-1); | |||
| 284 | ||||
| 285 | REQUIRE(lcfgp != NULL && *lcfgp == NULL)((void) ((lcfgp != ((void *)0) && *lcfgp == ((void *) 0)) || ((isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/log.c" , 285, isc_assertiontype_require, "lcfgp != ((void *)0) && *lcfgp == ((void *)0)" ), 0))); | |||
| 286 | ||||
| 287 | lcfg = malloc(sizeof(*lcfg)); | |||
| 288 | ||||
| 289 | if (lcfg != NULL((void *)0)) { | |||
| 290 | lcfg->lctx = lctx; | |||
| 291 | lcfg->channellists = NULL((void *)0); | |||
| 292 | lcfg->channellist_count = 0; | |||
| 293 | lcfg->duplicate_interval = 0; | |||
| 294 | lcfg->highest_level = level; | |||
| 295 | lcfg->tag = NULL((void *)0); | |||
| 296 | lcfg->dynamic = 0; | |||
| 297 | ||||
| 298 | ISC_LIST_INIT(lcfg->channels)do { (lcfg->channels).head = ((void *)0); (lcfg->channels ).tail = ((void *)0); } while (0); | |||
| 299 | ||||
| 300 | } else | |||
| 301 | result = ISC_R_NOMEMORY1; | |||
| 302 | ||||
| 303 | /* | |||
| 304 | * Create the default channels: | |||
| 305 | * default_syslog, default_stderr, default_debug and null. | |||
| 306 | */ | |||
| 307 | if (result
| |||
| 308 | destination.facility = LOG_DAEMON(3<<3); | |||
| 309 | result = isc_log_createchannel(lcfg, "default_syslog", | |||
| 310 | ISC_LOG_TOSYSLOG2, level, | |||
| 311 | &destination, 0); | |||
| 312 | } | |||
| 313 | ||||
| 314 | if (result
| |||
| 315 | destination.file.stream = stderr(&__sF[2]); | |||
| 316 | destination.file.name = NULL((void *)0); | |||
| 317 | destination.file.versions = ISC_LOG_ROLLNEVER(-2); | |||
| 318 | destination.file.maximum_size = 0; | |||
| 319 | result = isc_log_createchannel(lcfg, "default_stderr", | |||
| 320 | ISC_LOG_TOFILEDESC3, | |||
| 321 | level, | |||
| 322 | &destination, | |||
| 323 | ISC_LOG_PRINTTIME0x0001); | |||
| 324 | } | |||
| 325 | ||||
| 326 | if (result
| |||
| 327 | /* | |||
| 328 | * Set the default category's channel to default_stderr, | |||
| 329 | * which is at the head of the channels list because it was | |||
| 330 | * just created. | |||
| 331 | */ | |||
| 332 | default_channel.channel = ISC_LIST_HEAD(lcfg->channels)((lcfg->channels).head); | |||
| 333 | ||||
| 334 | destination.file.stream = stderr(&__sF[2]); | |||
| 335 | destination.file.name = NULL((void *)0); | |||
| 336 | destination.file.versions = ISC_LOG_ROLLNEVER(-2); | |||
| 337 | destination.file.maximum_size = 0; | |||
| 338 | result = isc_log_createchannel(lcfg, "default_debug", | |||
| 339 | ISC_LOG_TOFILEDESC3, | |||
| 340 | ISC_LOG_DYNAMIC0, | |||
| 341 | &destination, | |||
| 342 | ISC_LOG_PRINTTIME0x0001); | |||
| 343 | } | |||
| 344 | ||||
| 345 | if (result
| |||
| 346 | result = isc_log_createchannel(lcfg, "null", | |||
| 347 | ISC_LOG_TONULL1, | |||
| 348 | ISC_LOG_DYNAMIC0, | |||
| 349 | NULL((void *)0), 0); | |||
| 350 | ||||
| 351 | if (result
| |||
| 352 | *lcfgp = lcfg; | |||
| 353 | ||||
| 354 | else | |||
| 355 | if (lcfg
| |||
| 356 | isc_logconfig_destroy(&lcfg); | |||
| 357 | ||||
| 358 | return (result); | |||
| 359 | } | |||
| 360 | ||||
| 361 | void | |||
| 362 | isc_log_destroy(isc_log_t **lctxp) { | |||
| 363 | isc_log_t *lctx; | |||
| 364 | isc_logconfig_t *lcfg; | |||
| 365 | isc_logmessage_t *message; | |||
| 366 | ||||
| 367 | REQUIRE(lctxp != NULL)((void) ((lctxp != ((void *)0)) || ((isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/log.c" , 367, isc_assertiontype_require, "lctxp != ((void *)0)"), 0) )); | |||
| 368 | ||||
| 369 | lctx = *lctxp; | |||
| 370 | if (lctx->logconfig != NULL((void *)0)) { | |||
| 371 | lcfg = lctx->logconfig; | |||
| 372 | lctx->logconfig = NULL((void *)0); | |||
| 373 | isc_logconfig_destroy(&lcfg); | |||
| 374 | } | |||
| 375 | ||||
| 376 | while ((message = ISC_LIST_HEAD(lctx->messages)((lctx->messages).head)) != NULL((void *)0)) { | |||
| 377 | ISC_LIST_UNLINK(lctx->messages, message, link)do { do { if ((message)->link.next != ((void *)0)) (message )->link.next->link.prev = (message)->link.prev; else { ((void) (((lctx->messages).tail == (message)) || ((isc_assertion_failed )("/usr/src/usr.bin/dig/lib/isc/log.c", 377, isc_assertiontype_insist , "(lctx->messages).tail == (message)"), 0))); (lctx->messages ).tail = (message)->link.prev; } if ((message)->link.prev != ((void *)0)) (message)->link.prev->link.next = (message )->link.next; else { ((void) (((lctx->messages).head == (message)) || ((isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/log.c" , 377, isc_assertiontype_insist, "(lctx->messages).head == (message)" ), 0))); (lctx->messages).head = (message)->link.next; } (message)->link.prev = (void *)(-1); (message)->link.next = (void *)(-1); ((void) (((lctx->messages).head != (message )) || ((isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/log.c" , 377, isc_assertiontype_insist, "(lctx->messages).head != (message)" ), 0))); ((void) (((lctx->messages).tail != (message)) || ( (isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/log.c", 377 , isc_assertiontype_insist, "(lctx->messages).tail != (message)" ), 0))); } while (0); } while (0); | |||
| 378 | ||||
| 379 | free(message); | |||
| 380 | } | |||
| 381 | ||||
| 382 | lctx->buffer[0] = '\0'; | |||
| 383 | lctx->debug_level = 0; | |||
| 384 | lctx->categories = NULL((void *)0); | |||
| 385 | lctx->category_count = 0; | |||
| 386 | lctx->modules = NULL((void *)0); | |||
| 387 | lctx->module_count = 0; | |||
| 388 | free(lctx); | |||
| 389 | *lctxp = NULL((void *)0); | |||
| 390 | } | |||
| 391 | ||||
| 392 | void | |||
| 393 | isc_logconfig_destroy(isc_logconfig_t **lcfgp) { | |||
| 394 | isc_logconfig_t *lcfg; | |||
| 395 | isc_logchannel_t *channel; | |||
| 396 | isc_logchannellist_t *item; | |||
| 397 | unsigned int i; | |||
| 398 | ||||
| 399 | REQUIRE(lcfgp != NULL)((void) ((lcfgp != ((void *)0)) || ((isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/log.c" , 399, isc_assertiontype_require, "lcfgp != ((void *)0)"), 0) )); | |||
| 400 | ||||
| 401 | lcfg = *lcfgp; | |||
| 402 | ||||
| 403 | /* | |||
| 404 | * This function cannot be called with a logconfig that is in | |||
| 405 | * use by a log context. | |||
| 406 | */ | |||
| 407 | REQUIRE(lcfg->lctx != NULL && lcfg->lctx->logconfig != lcfg)((void) ((lcfg->lctx != ((void *)0) && lcfg->lctx ->logconfig != lcfg) || ((isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/log.c" , 407, isc_assertiontype_require, "lcfg->lctx != ((void *)0) && lcfg->lctx->logconfig != lcfg" ), 0))); | |||
| ||||
| 408 | ||||
| 409 | while ((channel = ISC_LIST_HEAD(lcfg->channels)((lcfg->channels).head)) != NULL((void *)0)) { | |||
| 410 | ISC_LIST_UNLINK(lcfg->channels, channel, link)do { do { if ((channel)->link.next != ((void *)0)) (channel )->link.next->link.prev = (channel)->link.prev; else { ((void) (((lcfg->channels).tail == (channel)) || ((isc_assertion_failed )("/usr/src/usr.bin/dig/lib/isc/log.c", 410, isc_assertiontype_insist , "(lcfg->channels).tail == (channel)"), 0))); (lcfg->channels ).tail = (channel)->link.prev; } if ((channel)->link.prev != ((void *)0)) (channel)->link.prev->link.next = (channel )->link.next; else { ((void) (((lcfg->channels).head == (channel)) || ((isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/log.c" , 410, isc_assertiontype_insist, "(lcfg->channels).head == (channel)" ), 0))); (lcfg->channels).head = (channel)->link.next; } (channel)->link.prev = (void *)(-1); (channel)->link.next = (void *)(-1); ((void) (((lcfg->channels).head != (channel )) || ((isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/log.c" , 410, isc_assertiontype_insist, "(lcfg->channels).head != (channel)" ), 0))); ((void) (((lcfg->channels).tail != (channel)) || ( (isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/log.c", 410 , isc_assertiontype_insist, "(lcfg->channels).tail != (channel)" ), 0))); } while (0); } while (0); | |||
| 411 | ||||
| 412 | free(channel->name); | |||
| 413 | free(channel); | |||
| 414 | } | |||
| 415 | ||||
| 416 | for (i = 0; i < lcfg->channellist_count; i++) | |||
| 417 | while ((item = ISC_LIST_HEAD(lcfg->channellists[i])((lcfg->channellists[i]).head)) != NULL((void *)0)) { | |||
| 418 | ISC_LIST_UNLINK(lcfg->channellists[i], item, link)do { do { if ((item)->link.next != ((void *)0)) (item)-> link.next->link.prev = (item)->link.prev; else { ((void ) (((lcfg->channellists[i]).tail == (item)) || ((isc_assertion_failed )("/usr/src/usr.bin/dig/lib/isc/log.c", 418, isc_assertiontype_insist , "(lcfg->channellists[i]).tail == (item)"), 0))); (lcfg-> channellists[i]).tail = (item)->link.prev; } if ((item)-> link.prev != ((void *)0)) (item)->link.prev->link.next = (item)->link.next; else { ((void) (((lcfg->channellists [i]).head == (item)) || ((isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/log.c" , 418, isc_assertiontype_insist, "(lcfg->channellists[i]).head == (item)" ), 0))); (lcfg->channellists[i]).head = (item)->link.next ; } (item)->link.prev = (void *)(-1); (item)->link.next = (void *)(-1); ((void) (((lcfg->channellists[i]).head != (item)) || ((isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/log.c" , 418, isc_assertiontype_insist, "(lcfg->channellists[i]).head != (item)" ), 0))); ((void) (((lcfg->channellists[i]).tail != (item)) || ((isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/log.c" , 418, isc_assertiontype_insist, "(lcfg->channellists[i]).tail != (item)" ), 0))); } while (0); } while (0); | |||
| 419 | free(item); | |||
| 420 | } | |||
| 421 | ||||
| 422 | if (lcfg->channellist_count > 0) | |||
| 423 | free(lcfg->channellists); | |||
| 424 | ||||
| 425 | lcfg->dynamic = 0; | |||
| 426 | if (lcfg->tag != NULL((void *)0)) | |||
| 427 | free(lcfg->tag); | |||
| 428 | lcfg->tag = NULL((void *)0); | |||
| 429 | lcfg->highest_level = 0; | |||
| 430 | lcfg->duplicate_interval = 0; | |||
| 431 | free(lcfg); | |||
| 432 | *lcfgp = NULL((void *)0); | |||
| 433 | } | |||
| 434 | ||||
| 435 | void | |||
| 436 | isc_log_registercategories(isc_log_t *lctx, isc_logcategory_t categories[]) { | |||
| 437 | isc_logcategory_t *catp; | |||
| 438 | ||||
| 439 | REQUIRE(categories != NULL && categories[0].name != NULL)((void) ((categories != ((void *)0) && categories[0]. name != ((void *)0)) || ((isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/log.c" , 439, isc_assertiontype_require, "categories != ((void *)0) && categories[0].name != ((void *)0)" ), 0))); | |||
| 440 | ||||
| 441 | /* | |||
| 442 | * XXXDCL This somewhat sleazy situation of using the last pointer | |||
| 443 | * in one category array to point to the next array exists because | |||
| 444 | * this registration function returns void and I didn't want to have | |||
| 445 | * change everything that used it by making it return an isc_result_t. | |||
| 446 | * It would need to do that if it had to allocate memory to store | |||
| 447 | * pointers to each array passed in. | |||
| 448 | */ | |||
| 449 | if (lctx->categories
| |||
| 450 | lctx->categories = categories; | |||
| 451 | ||||
| 452 | else { | |||
| 453 | /* | |||
| 454 | * Adjust the last (NULL) pointer of the already registered | |||
| 455 | * categories to point to the incoming array. | |||
| 456 | */ | |||
| 457 | for (catp = lctx->categories; catp->name != NULL((void *)0); ) | |||
| 458 | if (catp->id == UINT_MAX0xffffffffU) | |||
| 459 | /* | |||
| 460 | * The name pointer points to the next array. | |||
| 461 | * Ick. | |||
| 462 | */ | |||
| 463 | DE_CONST(catp->name, catp)do { union { const void *k; void *v; } _u; _u.k = catp->name ; catp = _u.v; } while (0); | |||
| 464 | else | |||
| 465 | catp++; | |||
| 466 | ||||
| 467 | catp->name = (void *)categories; | |||
| 468 | catp->id = UINT_MAX0xffffffffU; | |||
| 469 | } | |||
| 470 | ||||
| 471 | /* | |||
| 472 | * Update the id number of the category with its new global id. | |||
| 473 | */ | |||
| 474 | for (catp = categories; catp->name
| |||
| 475 | catp->id = lctx->category_count++; | |||
| 476 | } | |||
| 477 | ||||
| 478 | void | |||
| 479 | isc_log_registermodules(isc_log_t *lctx, isc_logmodule_t modules[]) { | |||
| 480 | isc_logmodule_t *modp; | |||
| 481 | ||||
| 482 | REQUIRE(modules != NULL && modules[0].name != NULL)((void) ((modules != ((void *)0) && modules[0].name != ((void *)0)) || ((isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/log.c" , 482, isc_assertiontype_require, "modules != ((void *)0) && modules[0].name != ((void *)0)" ), 0))); | |||
| 483 | ||||
| 484 | /* | |||
| 485 | * XXXDCL This somewhat sleazy situation of using the last pointer | |||
| 486 | * in one category array to point to the next array exists because | |||
| 487 | * this registration function returns void and I didn't want to have | |||
| 488 | * change everything that used it by making it return an isc_result_t. | |||
| 489 | * It would need to do that if it had to allocate memory to store | |||
| 490 | * pointers to each array passed in. | |||
| 491 | */ | |||
| 492 | if (lctx->modules
| |||
| 493 | lctx->modules = modules; | |||
| 494 | ||||
| 495 | else { | |||
| 496 | /* | |||
| 497 | * Adjust the last (NULL) pointer of the already registered | |||
| 498 | * modules to point to the incoming array. | |||
| 499 | */ | |||
| 500 | for (modp = lctx->modules; modp->name != NULL((void *)0); ) | |||
| 501 | if (modp->id == UINT_MAX0xffffffffU) | |||
| 502 | /* | |||
| 503 | * The name pointer points to the next array. | |||
| 504 | * Ick. | |||
| 505 | */ | |||
| 506 | DE_CONST(modp->name, modp)do { union { const void *k; void *v; } _u; _u.k = modp->name ; modp = _u.v; } while (0); | |||
| 507 | else | |||
| 508 | modp++; | |||
| 509 | ||||
| 510 | modp->name = (void *)modules; | |||
| 511 | modp->id = UINT_MAX0xffffffffU; | |||
| 512 | } | |||
| 513 | ||||
| 514 | /* | |||
| 515 | * Update the id number of the module with its new global id. | |||
| 516 | */ | |||
| 517 | for (modp = modules; modp->name
| |||
| 518 | modp->id = lctx->module_count++; | |||
| 519 | } | |||
| 520 | ||||
| 521 | isc_result_t | |||
| 522 | isc_log_createchannel(isc_logconfig_t *lcfg, const char *name, | |||
| 523 | unsigned int type, int level, | |||
| 524 | const isc_logdestination_t *destination, | |||
| 525 | unsigned int flags) | |||
| 526 | { | |||
| 527 | isc_logchannel_t *channel; | |||
| 528 | ||||
| 529 | REQUIRE(name != NULL)((void) ((name != ((void *)0)) || ((isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/log.c" , 529, isc_assertiontype_require, "name != ((void *)0)"), 0)) ); | |||
| 530 | REQUIRE(type == ISC_LOG_TOSYSLOG ||((void) ((type == 2 || type == 3 || type == 1) || ((isc_assertion_failed )("/usr/src/usr.bin/dig/lib/isc/log.c", 531, isc_assertiontype_require , "type == 2 || type == 3 || type == 1"), 0))) | |||
| 531 | type == ISC_LOG_TOFILEDESC || type == ISC_LOG_TONULL)((void) ((type == 2 || type == 3 || type == 1) || ((isc_assertion_failed )("/usr/src/usr.bin/dig/lib/isc/log.c", 531, isc_assertiontype_require , "type == 2 || type == 3 || type == 1"), 0))); | |||
| 532 | REQUIRE(destination != NULL || type == ISC_LOG_TONULL)((void) ((destination != ((void *)0) || type == 1) || ((isc_assertion_failed )("/usr/src/usr.bin/dig/lib/isc/log.c", 532, isc_assertiontype_require , "destination != ((void *)0) || type == 1"), 0))); | |||
| 533 | REQUIRE(level >= ISC_LOG_CRITICAL)((void) ((level >= (-5)) || ((isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/log.c" , 533, isc_assertiontype_require, "level >= (-5)"), 0))); | |||
| 534 | REQUIRE((flags &((void) (((flags & (unsigned int)~(0x003F | 0x1000)) == 0 ) || ((isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/log.c" , 535, isc_assertiontype_require, "(flags & (unsigned int)~(0x003F | 0x1000)) == 0" ), 0))) | |||
| 535 | (unsigned int)~(ISC_LOG_PRINTALL | ISC_LOG_DEBUGONLY)) == 0)((void) (((flags & (unsigned int)~(0x003F | 0x1000)) == 0 ) || ((isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/log.c" , 535, isc_assertiontype_require, "(flags & (unsigned int)~(0x003F | 0x1000)) == 0" ), 0))); | |||
| 536 | ||||
| 537 | /* XXXDCL find duplicate names? */ | |||
| 538 | ||||
| 539 | channel = malloc(sizeof(*channel)); | |||
| 540 | if (channel == NULL((void *)0)) | |||
| 541 | return (ISC_R_NOMEMORY1); | |||
| 542 | ||||
| 543 | channel->name = strdup(name); | |||
| 544 | if (channel->name == NULL((void *)0)) { | |||
| 545 | free(channel); | |||
| 546 | return (ISC_R_NOMEMORY1); | |||
| 547 | } | |||
| 548 | ||||
| 549 | channel->type = type; | |||
| 550 | channel->level = level; | |||
| 551 | channel->flags = flags; | |||
| 552 | ISC_LINK_INIT(channel, link)do { (channel)->link.prev = (void *)(-1); (channel)->link .next = (void *)(-1); } while (0); | |||
| 553 | ||||
| 554 | switch (type) { | |||
| 555 | case ISC_LOG_TOSYSLOG2: | |||
| 556 | FACILITY(channel)(channel->destination.facility) = destination->facility; | |||
| 557 | break; | |||
| 558 | ||||
| 559 | case ISC_LOG_TOFILEDESC3: | |||
| 560 | FILE_NAME(channel)(channel->destination.file.name) = NULL((void *)0); | |||
| 561 | FILE_STREAM(channel)(channel->destination.file.stream) = destination->file.stream; | |||
| 562 | FILE_MAXSIZE(channel)(channel->destination.file.maximum_size) = 0; | |||
| 563 | FILE_VERSIONS(channel)(channel->destination.file.versions) = ISC_LOG_ROLLNEVER(-2); | |||
| 564 | break; | |||
| 565 | ||||
| 566 | case ISC_LOG_TONULL1: | |||
| 567 | /* Nothing. */ | |||
| 568 | break; | |||
| 569 | ||||
| 570 | default: | |||
| 571 | free(channel->name); | |||
| 572 | free(channel); | |||
| 573 | return (ISC_R_UNEXPECTED34); | |||
| 574 | } | |||
| 575 | ||||
| 576 | ISC_LIST_PREPEND(lcfg->channels, channel, link)do { do { if ((lcfg->channels).head != ((void *)0)) (lcfg-> channels).head->link.prev = (channel); else (lcfg->channels ).tail = (channel); (channel)->link.prev = ((void *)0); (channel )->link.next = (lcfg->channels).head; (lcfg->channels ).head = (channel); } while (0); } while (0); | |||
| 577 | ||||
| 578 | /* | |||
| 579 | * If default_stderr was redefined, make the default category | |||
| 580 | * point to the new default_stderr. | |||
| 581 | */ | |||
| 582 | if (strcmp(name, "default_stderr") == 0) | |||
| 583 | default_channel.channel = channel; | |||
| 584 | ||||
| 585 | return (ISC_R_SUCCESS0); | |||
| 586 | } | |||
| 587 | ||||
| 588 | isc_result_t | |||
| 589 | isc_log_usechannel(isc_logconfig_t *lcfg, const char *name, | |||
| 590 | const isc_logcategory_t *category, | |||
| 591 | const isc_logmodule_t *module) | |||
| 592 | { | |||
| 593 | isc_log_t *lctx; | |||
| 594 | isc_logchannel_t *channel; | |||
| 595 | isc_result_t result = ISC_R_SUCCESS0; | |||
| 596 | unsigned int i; | |||
| 597 | ||||
| 598 | REQUIRE(name != NULL)((void) ((name != ((void *)0)) || ((isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/log.c" , 598, isc_assertiontype_require, "name != ((void *)0)"), 0)) ); | |||
| 599 | ||||
| 600 | lctx = lcfg->lctx; | |||
| 601 | ||||
| 602 | REQUIRE(category == NULL || category->id < lctx->category_count)((void) ((category == ((void *)0) || category->id < lctx ->category_count) || ((isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/log.c" , 602, isc_assertiontype_require, "category == ((void *)0) || category->id < lctx->category_count" ), 0))); | |||
| 603 | REQUIRE(module == NULL || module->id < lctx->module_count)((void) ((module == ((void *)0) || module->id < lctx-> module_count) || ((isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/log.c" , 603, isc_assertiontype_require, "module == ((void *)0) || module->id < lctx->module_count" ), 0))); | |||
| 604 | ||||
| 605 | for (channel = ISC_LIST_HEAD(lcfg->channels)((lcfg->channels).head); channel != NULL((void *)0); | |||
| 606 | channel = ISC_LIST_NEXT(channel, link)((channel)->link.next)) | |||
| 607 | if (strcmp(name, channel->name) == 0) | |||
| 608 | break; | |||
| 609 | ||||
| 610 | if (channel == NULL((void *)0)) | |||
| 611 | return (ISC_R_NOTFOUND23); | |||
| 612 | ||||
| 613 | if (category != NULL((void *)0)) | |||
| 614 | result = assignchannel(lcfg, category->id, module, channel); | |||
| 615 | ||||
| 616 | else | |||
| 617 | /* | |||
| 618 | * Assign to all categories. Note that this includes | |||
| 619 | * the default channel. | |||
| 620 | */ | |||
| 621 | for (i = 0; i < lctx->category_count; i++) { | |||
| 622 | result = assignchannel(lcfg, i, module, channel); | |||
| 623 | if (result != ISC_R_SUCCESS0) | |||
| 624 | break; | |||
| 625 | } | |||
| 626 | ||||
| 627 | return (result); | |||
| 628 | } | |||
| 629 | ||||
| 630 | void | |||
| 631 | isc_log_write(isc_log_t *lctx, isc_logcategory_t *category, | |||
| 632 | isc_logmodule_t *module, int level, const char *format, ...) | |||
| 633 | { | |||
| 634 | va_list args; | |||
| 635 | ||||
| 636 | /* | |||
| 637 | * Contract checking is done in isc_log_doit(). | |||
| 638 | */ | |||
| 639 | ||||
| 640 | va_start(args, format)__builtin_va_start((args), format); | |||
| 641 | isc_log_doit(lctx, category, module, level, 0, format, args); | |||
| 642 | va_end(args)__builtin_va_end((args)); | |||
| 643 | } | |||
| 644 | ||||
| 645 | void | |||
| 646 | isc_log_setcontext(isc_log_t *lctx) { | |||
| 647 | isc_lctx = lctx; | |||
| 648 | } | |||
| 649 | ||||
| 650 | void | |||
| 651 | isc_log_setdebuglevel(isc_log_t *lctx, unsigned int level) { | |||
| 652 | ||||
| 653 | lctx->debug_level = level; | |||
| 654 | } | |||
| 655 | ||||
| 656 | /**** | |||
| 657 | **** Internal functions | |||
| 658 | ****/ | |||
| 659 | ||||
| 660 | static isc_result_t | |||
| 661 | assignchannel(isc_logconfig_t *lcfg, unsigned int category_id, | |||
| 662 | const isc_logmodule_t *module, isc_logchannel_t *channel) | |||
| 663 | { | |||
| 664 | isc_logchannellist_t *new_item; | |||
| 665 | isc_log_t *lctx; | |||
| 666 | isc_result_t result; | |||
| 667 | ||||
| 668 | lctx = lcfg->lctx; | |||
| 669 | ||||
| 670 | REQUIRE(category_id < lctx->category_count)((void) ((category_id < lctx->category_count) || ((isc_assertion_failed )("/usr/src/usr.bin/dig/lib/isc/log.c", 670, isc_assertiontype_require , "category_id < lctx->category_count"), 0))); | |||
| 671 | REQUIRE(module == NULL || module->id < lctx->module_count)((void) ((module == ((void *)0) || module->id < lctx-> module_count) || ((isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/log.c" , 671, isc_assertiontype_require, "module == ((void *)0) || module->id < lctx->module_count" ), 0))); | |||
| 672 | REQUIRE(channel != NULL)((void) ((channel != ((void *)0)) || ((isc_assertion_failed)( "/usr/src/usr.bin/dig/lib/isc/log.c", 672, isc_assertiontype_require , "channel != ((void *)0)"), 0))); | |||
| 673 | ||||
| 674 | /* | |||
| 675 | * Ensure lcfg->channellist_count == lctx->category_count. | |||
| 676 | */ | |||
| 677 | result = sync_channellist(lcfg); | |||
| 678 | if (result != ISC_R_SUCCESS0) | |||
| 679 | return (result); | |||
| 680 | ||||
| 681 | new_item = malloc(sizeof(*new_item)); | |||
| 682 | if (new_item == NULL((void *)0)) | |||
| 683 | return (ISC_R_NOMEMORY1); | |||
| 684 | ||||
| 685 | new_item->channel = channel; | |||
| 686 | new_item->module = module; | |||
| 687 | ISC_LIST_INITANDPREPEND(lcfg->channellists[category_id],do { if ((lcfg->channellists[category_id]).head != ((void * )0)) (lcfg->channellists[category_id]).head->link.prev = (new_item); else (lcfg->channellists[category_id]).tail = (new_item); (new_item)->link.prev = ((void *)0); (new_item )->link.next = (lcfg->channellists[category_id]).head; ( lcfg->channellists[category_id]).head = (new_item); } while (0) | |||
| 688 | new_item, link)do { if ((lcfg->channellists[category_id]).head != ((void * )0)) (lcfg->channellists[category_id]).head->link.prev = (new_item); else (lcfg->channellists[category_id]).tail = (new_item); (new_item)->link.prev = ((void *)0); (new_item )->link.next = (lcfg->channellists[category_id]).head; ( lcfg->channellists[category_id]).head = (new_item); } while (0); | |||
| 689 | ||||
| 690 | /* | |||
| 691 | * Remember the highest logging level set by any channel in the | |||
| 692 | * logging config, so isc_log_doit() can quickly return if the | |||
| 693 | * message is too high to be logged by any channel. | |||
| 694 | */ | |||
| 695 | if (channel->type != ISC_LOG_TONULL1) { | |||
| 696 | if (lcfg->highest_level < channel->level) | |||
| 697 | lcfg->highest_level = channel->level; | |||
| 698 | if (channel->level == ISC_LOG_DYNAMIC0) | |||
| 699 | lcfg->dynamic = 1; | |||
| 700 | } | |||
| 701 | ||||
| 702 | return (ISC_R_SUCCESS0); | |||
| 703 | } | |||
| 704 | ||||
| 705 | /* | |||
| 706 | * This would ideally be part of isc_log_registercategories(), except then | |||
| 707 | * that function would have to return isc_result_t instead of void. | |||
| 708 | */ | |||
| 709 | static isc_result_t | |||
| 710 | sync_channellist(isc_logconfig_t *lcfg) { | |||
| 711 | unsigned int bytes; | |||
| 712 | isc_log_t *lctx; | |||
| 713 | void *lists; | |||
| 714 | ||||
| 715 | lctx = lcfg->lctx; | |||
| 716 | ||||
| 717 | REQUIRE(lctx->category_count != 0)((void) ((lctx->category_count != 0) || ((isc_assertion_failed )("/usr/src/usr.bin/dig/lib/isc/log.c", 717, isc_assertiontype_require , "lctx->category_count != 0"), 0))); | |||
| 718 | ||||
| 719 | if (lctx->category_count == lcfg->channellist_count) | |||
| 720 | return (ISC_R_SUCCESS0); | |||
| 721 | ||||
| 722 | bytes = lctx->category_count * sizeof(ISC_LIST(isc_logchannellist_t)struct { isc_logchannellist_t *head, *tail; }); | |||
| 723 | ||||
| 724 | lists = malloc(bytes); | |||
| 725 | ||||
| 726 | if (lists == NULL((void *)0)) | |||
| 727 | return (ISC_R_NOMEMORY1); | |||
| 728 | ||||
| 729 | memset(lists, 0, bytes); | |||
| 730 | ||||
| 731 | if (lcfg->channellist_count != 0) { | |||
| 732 | bytes = lcfg->channellist_count * | |||
| 733 | sizeof(ISC_LIST(isc_logchannellist_t)struct { isc_logchannellist_t *head, *tail; }); | |||
| 734 | memmove(lists, lcfg->channellists, bytes); | |||
| 735 | free(lcfg->channellists); | |||
| 736 | } | |||
| 737 | ||||
| 738 | lcfg->channellists = lists; | |||
| 739 | lcfg->channellist_count = lctx->category_count; | |||
| 740 | ||||
| 741 | return (ISC_R_SUCCESS0); | |||
| 742 | } | |||
| 743 | ||||
| 744 | int | |||
| 745 | isc_log_wouldlog(isc_log_t *lctx, int level) { | |||
| 746 | /* | |||
| 747 | * If the level is (mathematically) less than or equal to the | |||
| 748 | * highest_level, or if there is a dynamic channel and the level is | |||
| 749 | * less than or equal to the debug level, the main loop must be | |||
| 750 | * entered to see if the message should really be output. | |||
| 751 | * | |||
| 752 | * NOTE: this is UNLOCKED access to the logconfig. However, | |||
| 753 | * the worst thing that can happen is that a bad decision is made | |||
| 754 | * about returning without logging, and that's not a big concern, | |||
| 755 | * because that's a risk anyway if the logconfig is being | |||
| 756 | * dynamically changed. | |||
| 757 | */ | |||
| 758 | ||||
| 759 | if (lctx == NULL((void *)0) || lctx->logconfig == NULL((void *)0)) | |||
| 760 | return (0); | |||
| 761 | ||||
| 762 | return (level <= lctx->logconfig->highest_level || | |||
| 763 | (lctx->logconfig->dynamic && | |||
| 764 | level <= lctx->debug_level)); | |||
| 765 | } | |||
| 766 | ||||
| 767 | static void | |||
| 768 | isc_log_doit(isc_log_t *lctx, isc_logcategory_t *category, | |||
| 769 | isc_logmodule_t *module, int level, int write_once, | |||
| 770 | const char *format, va_list args) | |||
| 771 | { | |||
| 772 | int syslog_level; | |||
| 773 | char time_string[64]; | |||
| 774 | char level_string[24]; | |||
| 775 | const char *iformat; | |||
| 776 | int matched = 0; | |||
| 777 | int printtime, printtag, printcolon; | |||
| 778 | int printcategory, printmodule, printlevel; | |||
| 779 | isc_logconfig_t *lcfg; | |||
| 780 | isc_logchannel_t *channel; | |||
| 781 | isc_logchannellist_t *category_channels; | |||
| 782 | ||||
| 783 | REQUIRE(category != NULL)((void) ((category != ((void *)0)) || ((isc_assertion_failed) ("/usr/src/usr.bin/dig/lib/isc/log.c", 783, isc_assertiontype_require , "category != ((void *)0)"), 0))); | |||
| 784 | REQUIRE(module != NULL)((void) ((module != ((void *)0)) || ((isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/log.c" , 784, isc_assertiontype_require, "module != ((void *)0)"), 0 ))); | |||
| 785 | REQUIRE(level != ISC_LOG_DYNAMIC)((void) ((level != 0) || ((isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/log.c" , 785, isc_assertiontype_require, "level != 0"), 0))); | |||
| 786 | REQUIRE(format != NULL)((void) ((format != ((void *)0)) || ((isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/log.c" , 786, isc_assertiontype_require, "format != ((void *)0)"), 0 ))); | |||
| 787 | ||||
| 788 | /* | |||
| 789 | * Programs can use libraries that use this logging code without | |||
| 790 | * wanting to do any logging, thus the log context is allowed to | |||
| 791 | * be non-existent. | |||
| 792 | */ | |||
| 793 | if (lctx == NULL((void *)0)) | |||
| 794 | return; | |||
| 795 | ||||
| 796 | REQUIRE(category->id < lctx->category_count)((void) ((category->id < lctx->category_count) || (( isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/log.c", 796 , isc_assertiontype_require, "category->id < lctx->category_count" ), 0))); | |||
| 797 | REQUIRE(module->id < lctx->module_count)((void) ((module->id < lctx->module_count) || ((isc_assertion_failed )("/usr/src/usr.bin/dig/lib/isc/log.c", 797, isc_assertiontype_require , "module->id < lctx->module_count"), 0))); | |||
| 798 | ||||
| 799 | if (! isc_log_wouldlog(lctx, level)) | |||
| 800 | return; | |||
| 801 | ||||
| 802 | iformat = format; | |||
| 803 | ||||
| 804 | time_string[0] = '\0'; | |||
| 805 | level_string[0] = '\0'; | |||
| 806 | ||||
| 807 | lctx->buffer[0] = '\0'; | |||
| 808 | ||||
| 809 | lcfg = lctx->logconfig; | |||
| 810 | ||||
| 811 | category_channels = ISC_LIST_HEAD(lcfg->channellists[category->id])((lcfg->channellists[category->id]).head); | |||
| 812 | ||||
| 813 | /* | |||
| 814 | * XXXDCL add duplicate filtering? (To not write multiple times to | |||
| 815 | * the same source via various channels). | |||
| 816 | */ | |||
| 817 | do { | |||
| 818 | /* | |||
| 819 | * If the channel list end was reached and a match was made, | |||
| 820 | * everything is finished. | |||
| 821 | */ | |||
| 822 | if (category_channels == NULL((void *)0) && matched) | |||
| 823 | break; | |||
| 824 | ||||
| 825 | if (category_channels == NULL((void *)0) && ! matched && | |||
| 826 | category_channels != ISC_LIST_HEAD(lcfg->channellists[0])((lcfg->channellists[0]).head)) | |||
| 827 | /* | |||
| 828 | * No category/module pair was explicitly configured. | |||
| 829 | * Try the category named "default". | |||
| 830 | */ | |||
| 831 | category_channels = | |||
| 832 | ISC_LIST_HEAD(lcfg->channellists[0])((lcfg->channellists[0]).head); | |||
| 833 | ||||
| 834 | if (category_channels == NULL((void *)0) && ! matched) | |||
| 835 | /* | |||
| 836 | * No matching module was explicitly configured | |||
| 837 | * for the category named "default". Use the internal | |||
| 838 | * default channel. | |||
| 839 | */ | |||
| 840 | category_channels = &default_channel; | |||
| 841 | ||||
| 842 | if (category_channels->module != NULL((void *)0) && | |||
| 843 | category_channels->module != module) { | |||
| 844 | category_channels = ISC_LIST_NEXT(category_channels,((category_channels)->link.next) | |||
| 845 | link)((category_channels)->link.next); | |||
| 846 | continue; | |||
| 847 | } | |||
| 848 | ||||
| 849 | matched = 1; | |||
| 850 | ||||
| 851 | channel = category_channels->channel; | |||
| 852 | category_channels = ISC_LIST_NEXT(category_channels, link)((category_channels)->link.next); | |||
| 853 | ||||
| 854 | if (((channel->flags & ISC_LOG_DEBUGONLY0x1000) != 0) && | |||
| 855 | lctx->debug_level == 0) | |||
| 856 | continue; | |||
| 857 | ||||
| 858 | if (channel->level == ISC_LOG_DYNAMIC0) { | |||
| 859 | if (lctx->debug_level < level) | |||
| 860 | continue; | |||
| 861 | } else if (channel->level < level) | |||
| 862 | continue; | |||
| 863 | ||||
| 864 | if ((channel->flags & ISC_LOG_PRINTTIME0x0001) != 0 && | |||
| 865 | time_string[0] == '\0') { | |||
| 866 | time_t now; | |||
| 867 | now = time(NULL((void *)0)); | |||
| 868 | strftime(time_string, sizeof(time_string), | |||
| 869 | "%d-%b-%Y %X", localtime(&now)); | |||
| 870 | } | |||
| 871 | ||||
| 872 | if ((channel->flags & ISC_LOG_PRINTLEVEL0x0002) != 0 && | |||
| 873 | level_string[0] == '\0') { | |||
| 874 | if (level < ISC_LOG_CRITICAL(-5)) | |||
| 875 | snprintf(level_string, sizeof(level_string), | |||
| 876 | "level %d: ", level); | |||
| 877 | else if (level > ISC_LOG_DYNAMIC0) | |||
| 878 | snprintf(level_string, sizeof(level_string), | |||
| 879 | "%s %d: ", log_level_strings[0], | |||
| 880 | level); | |||
| 881 | else | |||
| 882 | snprintf(level_string, sizeof(level_string), | |||
| 883 | "%s: ", log_level_strings[-level]); | |||
| 884 | } | |||
| 885 | ||||
| 886 | /* | |||
| 887 | * Only format the message once. | |||
| 888 | */ | |||
| 889 | if (lctx->buffer[0] == '\0') { | |||
| 890 | (void)vsnprintf(lctx->buffer, sizeof(lctx->buffer), | |||
| 891 | iformat, args); | |||
| 892 | ||||
| 893 | /* | |||
| 894 | * Check for duplicates. | |||
| 895 | */ | |||
| 896 | if (write_once) { | |||
| 897 | isc_logmessage_t *message, *next; | |||
| 898 | struct timespec oldest; | |||
| 899 | struct timespec interval; | |||
| 900 | size_t size; | |||
| 901 | interval.tv_sec = lcfg->duplicate_interval; | |||
| 902 | interval.tv_nsec = 0; | |||
| 903 | ||||
| 904 | /* | |||
| 905 | * 'oldest' is the age of the oldest messages | |||
| 906 | * which fall within the duplicate_interval | |||
| 907 | * range. | |||
| 908 | */ | |||
| 909 | clock_gettime(CLOCK_MONOTONIC3, &oldest); | |||
| 910 | timespecsub(&oldest, &interval, &oldest)do { (&oldest)->tv_sec = (&oldest)->tv_sec - (& interval)->tv_sec; (&oldest)->tv_nsec = (&oldest )->tv_nsec - (&interval)->tv_nsec; if ((&oldest )->tv_nsec < 0) { (&oldest)->tv_sec--; (&oldest )->tv_nsec += 1000000000L; } } while (0); | |||
| 911 | message = ISC_LIST_HEAD(lctx->messages)((lctx->messages).head); | |||
| 912 | ||||
| 913 | while (message != NULL((void *)0)) { | |||
| 914 | if (timespeccmp(&message->time,(((&message->time)->tv_sec == (&oldest)->tv_sec ) ? ((&message->time)->tv_nsec < (&oldest)-> tv_nsec) : ((&message->time)->tv_sec < (&oldest )->tv_sec)) | |||
| 915 | &oldest, <)(((&message->time)->tv_sec == (&oldest)->tv_sec ) ? ((&message->time)->tv_nsec < (&oldest)-> tv_nsec) : ((&message->time)->tv_sec < (&oldest )->tv_sec))) { | |||
| 916 | /* | |||
| 917 | * This message is older | |||
| 918 | * than the duplicate_interval, | |||
| 919 | * so it should be dropped from | |||
| 920 | * the history. | |||
| 921 | * | |||
| 922 | * Setting the interval to be | |||
| 923 | * to be longer will obviously | |||
| 924 | * not cause the expired | |||
| 925 | * message to spring back into | |||
| 926 | * existence. | |||
| 927 | */ | |||
| 928 | next = ISC_LIST_NEXT(message,((message)->link.next) | |||
| 929 | link)((message)->link.next); | |||
| 930 | ||||
| 931 | ISC_LIST_UNLINK(lctx->messages,do { do { if ((message)->link.next != ((void *)0)) (message )->link.next->link.prev = (message)->link.prev; else { ((void) (((lctx->messages).tail == (message)) || ((isc_assertion_failed )("/usr/src/usr.bin/dig/lib/isc/log.c", 932, isc_assertiontype_insist , "(lctx->messages).tail == (message)"), 0))); (lctx->messages ).tail = (message)->link.prev; } if ((message)->link.prev != ((void *)0)) (message)->link.prev->link.next = (message )->link.next; else { ((void) (((lctx->messages).head == (message)) || ((isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/log.c" , 932, isc_assertiontype_insist, "(lctx->messages).head == (message)" ), 0))); (lctx->messages).head = (message)->link.next; } (message)->link.prev = (void *)(-1); (message)->link.next = (void *)(-1); ((void) (((lctx->messages).head != (message )) || ((isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/log.c" , 932, isc_assertiontype_insist, "(lctx->messages).head != (message)" ), 0))); ((void) (((lctx->messages).tail != (message)) || ( (isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/log.c", 932 , isc_assertiontype_insist, "(lctx->messages).tail != (message)" ), 0))); } while (0); } while (0) | |||
| 932 | message, link)do { do { if ((message)->link.next != ((void *)0)) (message )->link.next->link.prev = (message)->link.prev; else { ((void) (((lctx->messages).tail == (message)) || ((isc_assertion_failed )("/usr/src/usr.bin/dig/lib/isc/log.c", 932, isc_assertiontype_insist , "(lctx->messages).tail == (message)"), 0))); (lctx->messages ).tail = (message)->link.prev; } if ((message)->link.prev != ((void *)0)) (message)->link.prev->link.next = (message )->link.next; else { ((void) (((lctx->messages).head == (message)) || ((isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/log.c" , 932, isc_assertiontype_insist, "(lctx->messages).head == (message)" ), 0))); (lctx->messages).head = (message)->link.next; } (message)->link.prev = (void *)(-1); (message)->link.next = (void *)(-1); ((void) (((lctx->messages).head != (message )) || ((isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/log.c" , 932, isc_assertiontype_insist, "(lctx->messages).head != (message)" ), 0))); ((void) (((lctx->messages).tail != (message)) || ( (isc_assertion_failed)("/usr/src/usr.bin/dig/lib/isc/log.c", 932 , isc_assertiontype_insist, "(lctx->messages).tail != (message)" ), 0))); } while (0); } while (0); | |||
| 933 | ||||
| 934 | free(message); | |||
| 935 | ||||
| 936 | message = next; | |||
| 937 | continue; | |||
| 938 | } | |||
| 939 | ||||
| 940 | /* | |||
| 941 | * This message is in the duplicate | |||
| 942 | * filtering interval ... | |||
| 943 | */ | |||
| 944 | if (strcmp(lctx->buffer, message->text) | |||
| 945 | == 0) { | |||
| 946 | /* | |||
| 947 | * ... and it is a duplicate. | |||
| 948 | */ | |||
| 949 | return; | |||
| 950 | } | |||
| 951 | ||||
| 952 | message = ISC_LIST_NEXT(message, link)((message)->link.next); | |||
| 953 | } | |||
| 954 | ||||
| 955 | /* | |||
| 956 | * It wasn't in the duplicate interval, | |||
| 957 | * so add it to the message list. | |||
| 958 | */ | |||
| 959 | size = sizeof(isc_logmessage_t) + | |||
| 960 | strlen(lctx->buffer) + 1; | |||
| 961 | message = malloc(size); | |||
| 962 | if (message != NULL((void *)0)) { | |||
| 963 | /* | |||
| 964 | * Put the text immediately after | |||
| 965 | * the struct. The strcpy is safe. | |||
| 966 | */ | |||
| 967 | message->text = (char *)(message + 1); | |||
| 968 | size -= sizeof(isc_logmessage_t); | |||
| 969 | strlcpy(message->text, lctx->buffer, | |||
| 970 | size); | |||
| 971 | ||||
| 972 | clock_gettime(CLOCK_MONOTONIC3, | |||
| 973 | &message->time); | |||
| 974 | ||||
| 975 | ISC_LINK_INIT(message, link)do { (message)->link.prev = (void *)(-1); (message)->link .next = (void *)(-1); } while (0); | |||
| 976 | ISC_LIST_APPEND(lctx->messages,do { do { if ((lctx->messages).tail != ((void *)0)) (lctx-> messages).tail->link.next = (message); else (lctx->messages ).head = (message); (message)->link.prev = (lctx->messages ).tail; (message)->link.next = ((void *)0); (lctx->messages ).tail = (message); } while (0); } while (0) | |||
| 977 | message, link)do { do { if ((lctx->messages).tail != ((void *)0)) (lctx-> messages).tail->link.next = (message); else (lctx->messages ).head = (message); (message)->link.prev = (lctx->messages ).tail; (message)->link.next = ((void *)0); (lctx->messages ).tail = (message); } while (0); } while (0); | |||
| 978 | } | |||
| 979 | } | |||
| 980 | } | |||
| 981 | ||||
| 982 | printtime = (channel->flags & ISC_LOG_PRINTTIME0x0001) != 0; | |||
| 983 | printtag = (channel->flags & | |||
| 984 | (ISC_LOG_PRINTTAG0x0010|ISC_LOG_PRINTPREFIX0x0020)) | |||
| 985 | != 0 && lcfg->tag != NULL((void *)0); | |||
| 986 | printcolon = (channel->flags & ISC_LOG_PRINTTAG0x0010) | |||
| 987 | != 0 && lcfg->tag != NULL((void *)0); | |||
| 988 | printcategory = (channel->flags & ISC_LOG_PRINTCATEGORY0x0004) != 0; | |||
| 989 | printmodule = (channel->flags & ISC_LOG_PRINTMODULE0x0008) != 0; | |||
| 990 | printlevel = (channel->flags & ISC_LOG_PRINTLEVEL0x0002) != 0; | |||
| 991 | ||||
| 992 | switch (channel->type) { | |||
| 993 | case ISC_LOG_TOFILEDESC3: | |||
| 994 | fprintf(FILE_STREAM(channel)(channel->destination.file.stream), | |||
| 995 | "%s%s%s%s%s%s%s%s%s%s\n", | |||
| 996 | printtime ? time_string : "", | |||
| 997 | printtime ? " " : "", | |||
| 998 | printtag ? lcfg->tag : "", | |||
| 999 | printcolon ? ": " : "", | |||
| 1000 | printcategory ? category->name : "", | |||
| 1001 | printcategory ? ": " : "", | |||
| 1002 | printmodule ? (module != NULL((void *)0) ? module->name | |||
| 1003 | : "no_module") | |||
| 1004 | : "", | |||
| 1005 | printmodule ? ": " : "", | |||
| 1006 | printlevel ? level_string : "", | |||
| 1007 | lctx->buffer); | |||
| 1008 | ||||
| 1009 | fflush(FILE_STREAM(channel)(channel->destination.file.stream)); | |||
| 1010 | break; | |||
| 1011 | ||||
| 1012 | case ISC_LOG_TOSYSLOG2: | |||
| 1013 | if (level > 0) | |||
| 1014 | syslog_level = LOG_DEBUG7; | |||
| 1015 | else if (level < ISC_LOG_CRITICAL(-5)) | |||
| 1016 | syslog_level = LOG_CRIT2; | |||
| 1017 | else | |||
| 1018 | syslog_level = syslog_map[-level]; | |||
| 1019 | ||||
| 1020 | (void)syslog(FACILITY(channel)(channel->destination.facility) | syslog_level, | |||
| 1021 | "%s%s%s%s%s%s%s%s%s%s", | |||
| 1022 | printtime ? time_string : "", | |||
| 1023 | printtime ? " " : "", | |||
| 1024 | printtag ? lcfg->tag : "", | |||
| 1025 | printcolon ? ": " : "", | |||
| 1026 | printcategory ? category->name : "", | |||
| 1027 | printcategory ? ": " : "", | |||
| 1028 | printmodule ? (module != NULL((void *)0) | |||
| 1029 | ? module->name | |||
| 1030 | : "no_module") | |||
| 1031 | : "", | |||
| 1032 | printmodule ? ": " : "", | |||
| 1033 | printlevel ? level_string : "", | |||
| 1034 | lctx->buffer); | |||
| 1035 | break; | |||
| 1036 | ||||
| 1037 | case ISC_LOG_TONULL1: | |||
| 1038 | break; | |||
| 1039 | ||||
| 1040 | } | |||
| 1041 | ||||
| 1042 | } while (1); | |||
| 1043 | } |