Merge from vendor branch BZIP:
[dragonfly.git] / contrib / bind-9.3 / lib / isc / log.c
1 /*
2  * Copyright (C) 2004, 2006  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 1999-2003  Internet Software Consortium.
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15  * PERFORMANCE OF THIS SOFTWARE.
16  */
17
18 /* $Id: log.c,v 1.70.2.8.2.14 2006/03/02 00:37:20 marka Exp $ */
19
20 /* Principal Authors: DCL */
21
22 #include <config.h>
23
24 #include <errno.h>
25 #include <stdlib.h>
26 #include <limits.h>
27 #include <time.h>
28
29 #include <sys/types.h>  /* dev_t FreeBSD 2.1 */
30
31 #include <isc/dir.h>
32 #include <isc/file.h>
33 #include <isc/log.h>
34 #include <isc/magic.h>
35 #include <isc/mem.h>
36 #include <isc/msgs.h>
37 #include <isc/print.h>
38 #include <isc/stat.h>
39 #include <isc/stdio.h>
40 #include <isc/string.h>
41 #include <isc/time.h>
42 #include <isc/util.h>
43
44 #define LCTX_MAGIC              ISC_MAGIC('L', 'c', 't', 'x')
45 #define VALID_CONTEXT(lctx)     ISC_MAGIC_VALID(lctx, LCTX_MAGIC)
46
47 #define LCFG_MAGIC              ISC_MAGIC('L', 'c', 'f', 'g')
48 #define VALID_CONFIG(lcfg)      ISC_MAGIC_VALID(lcfg, LCFG_MAGIC)
49
50 /*
51  * XXXDCL make dynamic?
52  */
53 #define LOG_BUFFER_SIZE (8 * 1024)
54
55 #ifndef PATH_MAX
56 #define PATH_MAX 1024   /* AIX and others don't define this. */
57 #endif
58
59 /*
60  * This is the structure that holds each named channel.  A simple linked
61  * list chains all of the channels together, so an individual channel is
62  * found by doing strcmp()s with the names down the list.  Their should
63  * be no peformance penalty from this as it is expected that the number
64  * of named channels will be no more than a dozen or so, and name lookups
65  * from the head of the list are only done when isc_log_usechannel() is
66  * called, which should also be very infrequent.
67  */
68 typedef struct isc_logchannel isc_logchannel_t;
69
70 struct isc_logchannel {
71         char *                          name;
72         unsigned int                    type;
73         int                             level;
74         unsigned int                    flags;
75         isc_logdestination_t            destination;
76         ISC_LINK(isc_logchannel_t)      link;
77 };
78
79 /*
80  * The logchannellist structure associates categories and modules with
81  * channels.  First the appropriate channellist is found based on the
82  * category, and then each structure in the linked list is checked for
83  * a matching module.  It is expected that the number of channels
84  * associated with any given category will be very short, no more than
85  * three or four in the more unusual cases.
86  */
87 typedef struct isc_logchannellist isc_logchannellist_t;
88
89 struct isc_logchannellist {
90         const isc_logmodule_t *         module;
91         isc_logchannel_t *              channel;
92         ISC_LINK(isc_logchannellist_t)  link;
93 };
94
95 /*
96  * This structure is used to remember messages for pruning via
97  * isc_log_[v]write1().
98  */
99 typedef struct isc_logmessage isc_logmessage_t;
100
101 struct isc_logmessage {
102         char *                          text;
103         isc_time_t                      time;
104         ISC_LINK(isc_logmessage_t)      link;
105 };
106
107 /*
108  * The isc_logconfig structure is used to store the configurable information
109  * about where messages are actually supposed to be sent -- the information
110  * that could changed based on some configuration file, as opposed to the
111  * the category/module specification of isc_log_[v]write[1] that is compiled
112  * into a program, or the debug_level which is dynamic state information.
113  */
114 struct isc_logconfig {
115         unsigned int                    magic;
116         isc_log_t *                     lctx;
117         ISC_LIST(isc_logchannel_t)      channels;
118         ISC_LIST(isc_logchannellist_t) *channellists;
119         unsigned int                    channellist_count;
120         unsigned int                    duplicate_interval;
121         int                             highest_level;
122         char *                          tag;
123         isc_boolean_t                   dynamic;
124 };
125
126 /*
127  * This isc_log structure provides the context for the isc_log functions.
128  * The log context locks itself in isc_log_doit, the internal backend to
129  * isc_log_write.  The locking is necessary both to provide exclusive access
130  * to the the buffer into which the message is formatted and to guard against
131  * competing threads trying to write to the same syslog resource.  (On
132  * some systems, such as BSD/OS, stdio is thread safe but syslog is not.)
133  * Unfortunately, the lock cannot guard against a _different_ logging
134  * context in the same program competing for syslog's attention.  Thus
135  * There Can Be Only One, but this is not enforced.
136  * XXXDCL enforce it?
137  *
138  * Note that the category and module information is not locked.
139  * This is because in the usual case, only one isc_log_t is ever created
140  * in a program, and the category/module registration happens only once.
141  * XXXDCL it might be wise to add more locking overall.
142  */
143 struct isc_log {
144         /* Not locked. */
145         unsigned int                    magic;
146         isc_mem_t *                     mctx;
147         isc_logcategory_t *             categories;
148         unsigned int                    category_count;
149         isc_logmodule_t *               modules;
150         unsigned int                    module_count;
151         int                             debug_level;
152         isc_mutex_t                     lock;
153         /* Locked by isc_log lock. */
154         isc_logconfig_t *               logconfig;
155         char                            buffer[LOG_BUFFER_SIZE];
156         ISC_LIST(isc_logmessage_t)      messages;
157 };
158
159 /*
160  * Used when ISC_LOG_PRINTLEVEL is enabled for a channel.
161  */
162 static const char *log_level_strings[] = {
163         "debug",
164         "info",
165         "notice",
166         "warning",
167         "error",
168         "critical"
169 };
170
171 /*
172  * Used to convert ISC_LOG_* priorities into syslog priorities.
173  * XXXDCL This will need modification for NT.
174  */
175 static const int syslog_map[] = {
176         LOG_DEBUG,
177         LOG_INFO,
178         LOG_NOTICE,
179         LOG_WARNING,
180         LOG_ERR,
181         LOG_CRIT
182 };
183
184 /*
185  * When adding new categories, a corresponding ISC_LOGCATEGORY_foo
186  * definition needs to be added to <isc/log.h>.
187  *
188  * The default category is provided so that the internal default can
189  * be overridden.  Since the default is always looked up as the first
190  * channellist in the log context, it must come first in isc_categories[].
191  */
192 LIBISC_EXTERNAL_DATA isc_logcategory_t isc_categories[] = {
193         { "default", 0 },       /* "default" must come first. */
194         { "general", 0 },
195         { NULL, 0 }
196 };
197
198 /*
199  * See above comment for categories, and apply it to modules.
200  */
201 LIBISC_EXTERNAL_DATA isc_logmodule_t isc_modules[] = {
202         { "socket", 0 },
203         { "time", 0 },
204         { "interface", 0 },
205         { "timer", 0 },
206         { NULL, 0 }
207 };
208
209 /*
210  * This essentially constant structure must be filled in at run time,
211  * because its channel member is pointed to a channel that is created
212  * dynamically with isc_log_createchannel.
213  */
214 static isc_logchannellist_t default_channel;
215
216 /*
217  * libisc logs to this context.
218  */
219 LIBISC_EXTERNAL_DATA isc_log_t *isc_lctx = NULL;
220
221 /*
222  * Forward declarations.
223  */
224 static isc_result_t
225 assignchannel(isc_logconfig_t *lcfg, unsigned int category_id,
226               const isc_logmodule_t *module, isc_logchannel_t *channel);
227
228 static isc_result_t
229 sync_channellist(isc_logconfig_t *lcfg);
230
231 static isc_result_t
232 greatest_version(isc_logchannel_t *channel, int *greatest);
233
234 static isc_result_t
235 roll_log(isc_logchannel_t *channel);
236
237 static void
238 isc_log_doit(isc_log_t *lctx, isc_logcategory_t *category,
239              isc_logmodule_t *module, int level, isc_boolean_t write_once,
240              isc_msgcat_t *msgcat, int msgset, int msg,
241              const char *format, va_list args)
242      ISC_FORMAT_PRINTF(9, 0);
243
244 /*
245  * Convenience macros.
246  */
247
248 #define FACILITY(channel)        (channel->destination.facility)
249 #define FILE_NAME(channel)       (channel->destination.file.name)
250 #define FILE_STREAM(channel)     (channel->destination.file.stream)
251 #define FILE_VERSIONS(channel)   (channel->destination.file.versions)
252 #define FILE_MAXSIZE(channel)    (channel->destination.file.maximum_size)
253 #define FILE_MAXREACHED(channel) (channel->destination.file.maximum_reached)
254
255 /****
256  **** Public interfaces.
257  ****/
258
259 /*
260  * Establish a new logging context, with default channels.
261  */
262 isc_result_t
263 isc_log_create(isc_mem_t *mctx, isc_log_t **lctxp, isc_logconfig_t **lcfgp) {
264         isc_log_t *lctx;
265         isc_logconfig_t *lcfg = NULL;
266         isc_result_t result;
267
268         REQUIRE(mctx != NULL);
269         REQUIRE(lctxp != NULL && *lctxp == NULL);
270         REQUIRE(lcfgp == NULL || *lcfgp == NULL);
271
272         lctx = isc_mem_get(mctx, sizeof(*lctx));
273         if (lctx != NULL) {
274                 lctx->mctx = mctx;
275                 lctx->categories = NULL;
276                 lctx->category_count = 0;
277                 lctx->modules = NULL;
278                 lctx->module_count = 0;
279                 lctx->debug_level = 0;
280
281                 ISC_LIST_INIT(lctx->messages);
282
283                 RUNTIME_CHECK(isc_mutex_init(&lctx->lock) == ISC_R_SUCCESS);
284
285                 /*
286                  * Normally setting the magic number is the last step done
287                  * in a creation function, but a valid log context is needed
288                  * by isc_log_registercategories and isc_logconfig_create.
289                  * If either fails, the lctx is destroyed and not returned
290                  * to the caller.
291                  */
292                 lctx->magic = LCTX_MAGIC;
293
294                 isc_log_registercategories(lctx, isc_categories);
295                 isc_log_registermodules(lctx, isc_modules);
296                 result = isc_logconfig_create(lctx, &lcfg);
297
298         } else
299                 result = ISC_R_NOMEMORY;
300
301         if (result == ISC_R_SUCCESS)
302                 result = sync_channellist(lcfg);
303
304         if (result == ISC_R_SUCCESS) {
305                 lctx->logconfig = lcfg;
306
307                 *lctxp = lctx;
308                 if (lcfgp != NULL)
309                         *lcfgp = lcfg;
310
311         } else {
312                 if (lcfg != NULL)
313                         isc_logconfig_destroy(&lcfg);
314                 if (lctx != NULL)
315                         isc_log_destroy(&lctx);
316         }
317
318         return (result);
319 }
320
321 isc_result_t
322 isc_logconfig_create(isc_log_t *lctx, isc_logconfig_t **lcfgp) {
323         isc_logconfig_t *lcfg;
324         isc_logdestination_t destination;
325         isc_result_t result = ISC_R_SUCCESS;
326         int level = ISC_LOG_INFO;
327
328         REQUIRE(lcfgp != NULL && *lcfgp == NULL);
329         REQUIRE(VALID_CONTEXT(lctx));
330
331         lcfg = isc_mem_get(lctx->mctx, sizeof(*lcfg));
332
333         if (lcfg != NULL) {
334                 lcfg->lctx = lctx;
335                 lcfg->channellists = NULL;
336                 lcfg->channellist_count = 0;
337                 lcfg->duplicate_interval = 0;
338                 lcfg->highest_level = level;
339                 lcfg->tag = NULL;
340                 lcfg->dynamic = ISC_FALSE;
341
342                 ISC_LIST_INIT(lcfg->channels);
343
344                 /*
345                  * Normally the magic number is the last thing set in the
346                  * structure, but isc_log_createchannel() needs a valid
347                  * config.  If the channel creation fails, the lcfg is not
348                  * returned to the caller.
349                  */
350                 lcfg->magic = LCFG_MAGIC;
351
352         } else
353                 result = ISC_R_NOMEMORY;
354
355         /*
356          * Create the default channels:
357          *      default_syslog, default_stderr, default_debug and null.
358          */
359         if (result == ISC_R_SUCCESS) {
360                 destination.facility = LOG_DAEMON;
361                 result = isc_log_createchannel(lcfg, "default_syslog",
362                                                ISC_LOG_TOSYSLOG, level,
363                                                &destination, 0);
364         }
365
366         if (result == ISC_R_SUCCESS) {
367                 destination.file.stream = stderr;
368                 destination.file.name = NULL;
369                 destination.file.versions = ISC_LOG_ROLLNEVER;
370                 destination.file.maximum_size = 0;
371                 result = isc_log_createchannel(lcfg, "default_stderr",
372                                                ISC_LOG_TOFILEDESC,
373                                                level,
374                                                &destination,
375                                                ISC_LOG_PRINTTIME);
376         }
377
378         if (result == ISC_R_SUCCESS) {
379                 /*
380                  * Set the default category's channel to default_stderr,
381                  * which is at the head of the channels list because it was
382                  * just created.
383                  */
384                 default_channel.channel = ISC_LIST_HEAD(lcfg->channels);
385
386                 destination.file.stream = stderr;
387                 destination.file.name = NULL;
388                 destination.file.versions = ISC_LOG_ROLLNEVER;
389                 destination.file.maximum_size = 0;
390                 result = isc_log_createchannel(lcfg, "default_debug",
391                                                ISC_LOG_TOFILEDESC,
392                                                ISC_LOG_DYNAMIC,
393                                                &destination,
394                                                ISC_LOG_PRINTTIME);
395         }
396
397         if (result == ISC_R_SUCCESS)
398                 result = isc_log_createchannel(lcfg, "null",
399                                                ISC_LOG_TONULL,
400                                                ISC_LOG_DYNAMIC,
401                                                NULL, 0);
402
403         if (result == ISC_R_SUCCESS)
404                 *lcfgp = lcfg;
405
406         else
407                 if (lcfg != NULL)
408                         isc_logconfig_destroy(&lcfg);
409
410         return (result);
411 }
412
413 isc_logconfig_t *
414 isc_logconfig_get(isc_log_t *lctx) {
415         REQUIRE(VALID_CONTEXT(lctx));
416
417         ENSURE(lctx->logconfig != NULL);
418
419         return (lctx->logconfig);
420 }
421
422 isc_result_t
423 isc_logconfig_use(isc_log_t *lctx, isc_logconfig_t *lcfg) {
424         isc_logconfig_t *old_cfg;
425         isc_result_t result;
426
427         REQUIRE(VALID_CONTEXT(lctx));
428         REQUIRE(VALID_CONFIG(lcfg));
429         REQUIRE(lcfg->lctx == lctx);
430
431         /*
432          * Ensure that lcfg->channellist_count == lctx->category_count.
433          * They won't be equal if isc_log_usechannel has not been called
434          * since any call to isc_log_registercategories.
435          */
436         result = sync_channellist(lcfg);
437         if (result != ISC_R_SUCCESS)
438                 return (result);
439
440         LOCK(&lctx->lock);
441
442         old_cfg = lctx->logconfig;
443         lctx->logconfig = lcfg;
444
445         UNLOCK(&lctx->lock);
446
447         isc_logconfig_destroy(&old_cfg);
448
449         return (ISC_R_SUCCESS);
450 }
451
452 void
453 isc_log_destroy(isc_log_t **lctxp) {
454         isc_log_t *lctx;
455         isc_logconfig_t *lcfg;
456         isc_mem_t *mctx;
457         isc_logmessage_t *message;
458
459         REQUIRE(lctxp != NULL && VALID_CONTEXT(*lctxp));
460
461         lctx = *lctxp;
462         mctx = lctx->mctx;
463
464         if (lctx->logconfig != NULL) {
465                 lcfg = lctx->logconfig;
466                 lctx->logconfig = NULL;
467                 isc_logconfig_destroy(&lcfg);
468         }
469
470         DESTROYLOCK(&lctx->lock);
471
472         while ((message = ISC_LIST_HEAD(lctx->messages)) != NULL) {
473                 ISC_LIST_UNLINK(lctx->messages, message, link);
474
475                 isc_mem_put(mctx, message,
476                             sizeof(*message) + strlen(message->text) + 1);
477         }
478
479         lctx->buffer[0] = '\0';
480         lctx->debug_level = 0;
481         lctx->categories = NULL;
482         lctx->category_count = 0;
483         lctx->modules = NULL;
484         lctx->module_count = 0;
485         lctx->mctx = NULL;
486         lctx->magic = 0;
487
488         isc_mem_put(mctx, lctx, sizeof(*lctx));
489
490         *lctxp = NULL;
491 }
492
493 void
494 isc_logconfig_destroy(isc_logconfig_t **lcfgp) {
495         isc_logconfig_t *lcfg;
496         isc_mem_t *mctx;
497         isc_logchannel_t *channel;
498         isc_logchannellist_t *item;
499         char *filename;
500         unsigned int i;
501
502         REQUIRE(lcfgp != NULL && VALID_CONFIG(*lcfgp));
503
504         lcfg = *lcfgp;
505
506         /*
507          * This function cannot be called with a logconfig that is in
508          * use by a log context.
509          */
510         REQUIRE(lcfg->lctx != NULL && lcfg->lctx->logconfig != lcfg);
511
512         mctx = lcfg->lctx->mctx;
513
514         while ((channel = ISC_LIST_HEAD(lcfg->channels)) != NULL) {
515                 ISC_LIST_UNLINK(lcfg->channels, channel, link);
516
517                 if (channel->type == ISC_LOG_TOFILE) {
518                         /*
519                          * The filename for the channel may have ultimately
520                          * started its life in user-land as a const string,
521                          * but in isc_log_createchannel it gets copied
522                          * into writable memory and is not longer truly const.
523                          */
524                         DE_CONST(FILE_NAME(channel), filename);
525                         isc_mem_free(mctx, filename);
526
527                         if (FILE_STREAM(channel) != NULL)
528                                 (void)fclose(FILE_STREAM(channel));
529                 }
530
531                 isc_mem_free(mctx, channel->name);
532                 isc_mem_put(mctx, channel, sizeof(*channel));
533         }
534
535         for (i = 0; i < lcfg->channellist_count; i++)
536                 while ((item = ISC_LIST_HEAD(lcfg->channellists[i])) != NULL) {
537                         ISC_LIST_UNLINK(lcfg->channellists[i], item, link);
538                         isc_mem_put(mctx, item, sizeof(*item));
539                 }
540
541         if (lcfg->channellist_count > 0)
542                 isc_mem_put(mctx, lcfg->channellists,
543                             lcfg->channellist_count *
544                             sizeof(ISC_LIST(isc_logchannellist_t)));
545
546         lcfg->dynamic = ISC_FALSE;
547         if (lcfg->tag != NULL)
548                 isc_mem_free(lcfg->lctx->mctx, lcfg->tag);
549         lcfg->tag = NULL;
550         lcfg->highest_level = 0;
551         lcfg->duplicate_interval = 0;
552         lcfg->magic = 0;
553
554         isc_mem_put(mctx, lcfg, sizeof(*lcfg));
555
556         *lcfgp = NULL;
557 }
558
559 void
560 isc_log_registercategories(isc_log_t *lctx, isc_logcategory_t categories[]) {
561         isc_logcategory_t *catp;
562
563         REQUIRE(VALID_CONTEXT(lctx));
564         REQUIRE(categories != NULL && categories[0].name != NULL);
565
566         /*
567          * XXXDCL This somewhat sleazy situation of using the last pointer
568          * in one category array to point to the next array exists because
569          * this registration function returns void and I didn't want to have
570          * change everything that used it by making it return an isc_result_t.
571          * It would need to do that if it had to allocate memory to store
572          * pointers to each array passed in.
573          */
574         if (lctx->categories == NULL)
575                 lctx->categories = categories;
576
577         else {
578                 /*
579                  * Adjust the last (NULL) pointer of the already registered
580                  * categories to point to the incoming array.
581                  */
582                 for (catp = lctx->categories; catp->name != NULL; )
583                         if (catp->id == UINT_MAX)
584                                 /*
585                                  * The name pointer points to the next array.
586                                  * Ick.
587                                  */
588                                 DE_CONST(catp->name, catp);
589                         else
590                                 catp++;
591
592                 catp->name = (void *)categories;
593                 catp->id = UINT_MAX;
594         }
595
596         /*
597          * Update the id number of the category with its new global id.
598          */
599         for (catp = categories; catp->name != NULL; catp++)
600                 catp->id = lctx->category_count++;
601 }
602
603 isc_logcategory_t *
604 isc_log_categorybyname(isc_log_t *lctx, const char *name) {
605         isc_logcategory_t *catp;
606
607         REQUIRE(VALID_CONTEXT(lctx));
608         REQUIRE(name != NULL);
609
610         for (catp = lctx->categories; catp->name != NULL; )
611                 if (catp->id == UINT_MAX)
612                         /*
613                          * catp is neither modified nor returned to the
614                          * caller, so removing its const qualifier is ok.
615                          */
616                         DE_CONST(catp->name, catp);
617                 else {
618                         if (strcmp(catp->name, name) == 0)
619                                 return (catp);
620                         catp++;
621                 }
622
623         return (NULL);
624 }
625
626 void
627 isc_log_registermodules(isc_log_t *lctx, isc_logmodule_t modules[]) {
628         isc_logmodule_t *modp;
629
630         REQUIRE(VALID_CONTEXT(lctx));
631         REQUIRE(modules != NULL && modules[0].name != NULL);
632
633         /*
634          * XXXDCL This somewhat sleazy situation of using the last pointer
635          * in one category array to point to the next array exists because
636          * this registration function returns void and I didn't want to have
637          * change everything that used it by making it return an isc_result_t.
638          * It would need to do that if it had to allocate memory to store
639          * pointers to each array passed in.
640          */
641         if (lctx->modules == NULL)
642                 lctx->modules = modules;
643
644         else {
645                 /*
646                  * Adjust the last (NULL) pointer of the already registered
647                  * modules to point to the incoming array.
648                  */
649                 for (modp = lctx->modules; modp->name != NULL; )
650                         if (modp->id == UINT_MAX)
651                                 /*
652                                  * The name pointer points to the next array.
653                                  * Ick.
654                                  */
655                                 DE_CONST(modp->name, modp);
656                         else
657                                 modp++;
658
659                 modp->name = (void *)modules;
660                 modp->id = UINT_MAX;
661         }
662
663         /*
664          * Update the id number of the module with its new global id.
665          */
666         for (modp = modules; modp->name != NULL; modp++)
667                 modp->id = lctx->module_count++;
668 }
669
670 isc_logmodule_t *
671 isc_log_modulebyname(isc_log_t *lctx, const char *name) {
672         isc_logmodule_t *modp;
673
674         REQUIRE(VALID_CONTEXT(lctx));
675         REQUIRE(name != NULL);
676
677         for (modp = lctx->modules; modp->name != NULL; )
678                 if (modp->id == UINT_MAX)
679                         /*
680                          * modp is neither modified nor returned to the
681                          * caller, so removing its const qualifier is ok.
682                          */
683                         DE_CONST(modp->name, modp);
684                 else {
685                         if (strcmp(modp->name, name) == 0)
686                                 return (modp);
687                         modp++;
688                 }
689
690         return (NULL);
691 }
692
693 isc_result_t
694 isc_log_createchannel(isc_logconfig_t *lcfg, const char *name,
695                       unsigned int type, int level,
696                       const isc_logdestination_t *destination,
697                       unsigned int flags)
698 {
699         isc_logchannel_t *channel;
700         isc_mem_t *mctx;
701
702         REQUIRE(VALID_CONFIG(lcfg));
703         REQUIRE(name != NULL);
704         REQUIRE(type == ISC_LOG_TOSYSLOG   || type == ISC_LOG_TOFILE ||
705                 type == ISC_LOG_TOFILEDESC || type == ISC_LOG_TONULL);
706         REQUIRE(destination != NULL || type == ISC_LOG_TONULL);
707         REQUIRE(level >= ISC_LOG_CRITICAL);
708         REQUIRE((flags &
709                  (unsigned int)~(ISC_LOG_PRINTALL | ISC_LOG_DEBUGONLY)) == 0);
710
711         /* XXXDCL find duplicate names? */
712
713         mctx = lcfg->lctx->mctx;
714
715         channel = isc_mem_get(mctx, sizeof(*channel));
716         if (channel == NULL)
717                 return (ISC_R_NOMEMORY);
718
719         channel->name = isc_mem_strdup(mctx, name);
720         if (channel->name == NULL) {
721                 isc_mem_put(mctx, channel, sizeof(*channel));
722                 return (ISC_R_NOMEMORY);
723         }
724
725         channel->type = type;
726         channel->level = level;
727         channel->flags = flags;
728         ISC_LINK_INIT(channel, link);
729
730         switch (type) {
731         case ISC_LOG_TOSYSLOG:
732                 FACILITY(channel) = destination->facility;
733                 break;
734
735         case ISC_LOG_TOFILE:
736                 /*
737                  * The file name is copied because greatest_version wants
738                  * to scribble on it, so it needs to be definitely in
739                  * writable memory.
740                  */
741                 FILE_NAME(channel) =
742                         isc_mem_strdup(mctx, destination->file.name);
743                 FILE_STREAM(channel) = NULL;
744                 FILE_VERSIONS(channel) = destination->file.versions;
745                 FILE_MAXSIZE(channel) = destination->file.maximum_size;
746                 FILE_MAXREACHED(channel) = ISC_FALSE;
747                 break;
748
749         case ISC_LOG_TOFILEDESC:
750                 FILE_NAME(channel) = NULL;
751                 FILE_STREAM(channel) = destination->file.stream;
752                 FILE_MAXSIZE(channel) = 0;
753                 FILE_VERSIONS(channel) = ISC_LOG_ROLLNEVER;
754                 break;
755
756         case ISC_LOG_TONULL:
757                 /* Nothing. */
758                 break;
759
760         default:
761                 isc_mem_put(mctx, channel->name, strlen(channel->name) + 1);
762                 isc_mem_put(mctx, channel, sizeof(*channel));
763                 return (ISC_R_UNEXPECTED);
764         }
765
766         ISC_LIST_PREPEND(lcfg->channels, channel, link);
767
768         /*
769          * If default_stderr was redefined, make the default category
770          * point to the new default_stderr.
771          */
772         if (strcmp(name, "default_stderr") == 0)
773                 default_channel.channel = channel;
774
775         return (ISC_R_SUCCESS);
776 }
777
778 isc_result_t
779 isc_log_usechannel(isc_logconfig_t *lcfg, const char *name,
780                    const isc_logcategory_t *category,
781                    const isc_logmodule_t *module)
782 {
783         isc_log_t *lctx;
784         isc_logchannel_t *channel;
785         isc_result_t result = ISC_R_SUCCESS;
786         unsigned int i;
787
788         REQUIRE(VALID_CONFIG(lcfg));
789         REQUIRE(name != NULL);
790
791         lctx = lcfg->lctx;
792
793         REQUIRE(category == NULL || category->id < lctx->category_count);
794         REQUIRE(module == NULL || module->id < lctx->module_count);
795
796         for (channel = ISC_LIST_HEAD(lcfg->channels); channel != NULL;
797              channel = ISC_LIST_NEXT(channel, link))
798                 if (strcmp(name, channel->name) == 0)
799                         break;
800
801         if (channel == NULL)
802                 return (ISC_R_NOTFOUND);
803
804         if (category != NULL)
805                 result = assignchannel(lcfg, category->id, module, channel);
806
807         else
808                 /*
809                  * Assign to all categories.  Note that this includes
810                  * the default channel.
811                  */
812                 for (i = 0; i < lctx->category_count; i++) {
813                         result = assignchannel(lcfg, i, module, channel);
814                         if (result != ISC_R_SUCCESS)
815                                 break;
816                 }
817
818         return (result);
819 }
820
821 void
822 isc_log_write(isc_log_t *lctx, isc_logcategory_t *category,
823               isc_logmodule_t *module, int level, const char *format, ...)
824 {
825         va_list args;
826
827         /*
828          * Contract checking is done in isc_log_doit().
829          */
830
831         va_start(args, format);
832         isc_log_doit(lctx, category, module, level, ISC_FALSE,
833                      NULL, 0, 0, format, args);
834         va_end(args);
835 }
836
837 void
838 isc_log_vwrite(isc_log_t *lctx, isc_logcategory_t *category,
839                isc_logmodule_t *module, int level,
840                const char *format, va_list args)
841 {
842         /*
843          * Contract checking is done in isc_log_doit().
844          */
845         isc_log_doit(lctx, category, module, level, ISC_FALSE,
846                      NULL, 0, 0, format, args);
847 }
848
849 void
850 isc_log_write1(isc_log_t *lctx, isc_logcategory_t *category,
851                isc_logmodule_t *module, int level, const char *format, ...)
852 {
853         va_list args;
854
855         /*
856          * Contract checking is done in isc_log_doit().
857          */
858
859         va_start(args, format);
860         isc_log_doit(lctx, category, module, level, ISC_TRUE,
861                      NULL, 0, 0, format, args);
862         va_end(args);
863 }
864
865 void
866 isc_log_vwrite1(isc_log_t *lctx, isc_logcategory_t *category,
867                 isc_logmodule_t *module, int level,
868                 const char *format, va_list args)
869 {
870         /*
871          * Contract checking is done in isc_log_doit().
872          */
873         isc_log_doit(lctx, category, module, level, ISC_TRUE,
874                      NULL, 0, 0, format, args);
875 }
876
877 void
878 isc_log_iwrite(isc_log_t *lctx, isc_logcategory_t *category,
879                isc_logmodule_t *module, int level,
880                isc_msgcat_t *msgcat, int msgset, int msg,
881                const char *format, ...)
882 {
883         va_list args;
884
885         /*
886          * Contract checking is done in isc_log_doit().
887          */
888
889         va_start(args, format);
890         isc_log_doit(lctx, category, module, level, ISC_FALSE,
891                      msgcat, msgset, msg, format, args);
892         va_end(args);
893 }
894
895 void
896 isc_log_ivwrite(isc_log_t *lctx, isc_logcategory_t *category,
897                isc_logmodule_t *module, int level,
898                isc_msgcat_t *msgcat, int msgset, int msg,
899                const char *format, va_list args)
900 {
901         /*
902          * Contract checking is done in isc_log_doit().
903          */
904         isc_log_doit(lctx, category, module, level, ISC_FALSE,
905                      msgcat, msgset, msg, format, args);
906 }
907
908 void
909 isc_log_iwrite1(isc_log_t *lctx, isc_logcategory_t *category,
910                 isc_logmodule_t *module, int level,
911                 isc_msgcat_t *msgcat, int msgset, int msg,
912                 const char *format, ...)
913 {
914         va_list args;
915
916         /*
917          * Contract checking is done in isc_log_doit().
918          */
919
920         va_start(args, format);
921         isc_log_doit(lctx, category, module, level, ISC_TRUE,
922                      msgcat, msgset, msg, format, args);
923         va_end(args);
924 }
925
926 void
927 isc_log_ivwrite1(isc_log_t *lctx, isc_logcategory_t *category,
928                  isc_logmodule_t *module, int level,
929                  isc_msgcat_t *msgcat, int msgset, int msg,
930                  const char *format, va_list args)
931 {
932         /*
933          * Contract checking is done in isc_log_doit().
934          */
935         isc_log_doit(lctx, category, module, level, ISC_TRUE,
936                      msgcat, msgset, msg, format, args);
937 }
938
939 void
940 isc_log_setcontext(isc_log_t *lctx) {
941         isc_lctx = lctx;
942 }
943
944 void
945 isc_log_setdebuglevel(isc_log_t *lctx, unsigned int level) {
946         isc_logchannel_t *channel;
947
948         REQUIRE(VALID_CONTEXT(lctx));
949
950         LOCK(&lctx->lock);
951
952         lctx->debug_level = level;
953         /*
954          * Close ISC_LOG_DEBUGONLY channels if level is zero.
955          */
956         if (lctx->debug_level == 0)
957                 for (channel = ISC_LIST_HEAD(lctx->logconfig->channels);
958                      channel != NULL;
959                      channel = ISC_LIST_NEXT(channel, link))
960                         if (channel->type == ISC_LOG_TOFILE &&
961                             (channel->flags & ISC_LOG_DEBUGONLY) != 0 &&
962                             FILE_STREAM(channel) != NULL) {
963                                 (void)fclose(FILE_STREAM(channel));
964                                 FILE_STREAM(channel) = NULL;
965                         }
966         UNLOCK(&lctx->lock);
967 }
968
969 unsigned int
970 isc_log_getdebuglevel(isc_log_t *lctx) {
971         REQUIRE(VALID_CONTEXT(lctx));
972
973         return (lctx->debug_level);
974 }
975
976 void
977 isc_log_setduplicateinterval(isc_logconfig_t *lcfg, unsigned int interval) {
978         REQUIRE(VALID_CONFIG(lcfg));
979
980         lcfg->duplicate_interval = interval;
981 }
982
983 unsigned int
984 isc_log_getduplicateinterval(isc_logconfig_t *lcfg) {
985         REQUIRE(VALID_CONTEXT(lcfg));
986
987         return (lcfg->duplicate_interval);
988 }
989
990 isc_result_t
991 isc_log_settag(isc_logconfig_t *lcfg, const char *tag) {
992         REQUIRE(VALID_CONFIG(lcfg));
993
994         if (tag != NULL && *tag != '\0') {
995                 if (lcfg->tag != NULL)
996                         isc_mem_free(lcfg->lctx->mctx, lcfg->tag);
997                 lcfg->tag = isc_mem_strdup(lcfg->lctx->mctx, tag);
998                 if (lcfg->tag == NULL)
999                         return (ISC_R_NOMEMORY);
1000
1001         } else {
1002                 if (lcfg->tag != NULL)
1003                         isc_mem_free(lcfg->lctx->mctx, lcfg->tag);
1004                 lcfg->tag = NULL;
1005         }
1006
1007         return (ISC_R_SUCCESS);
1008 }
1009
1010 char *
1011 isc_log_gettag(isc_logconfig_t *lcfg) {
1012         REQUIRE(VALID_CONFIG(lcfg));
1013
1014         return (lcfg->tag);
1015 }
1016
1017 /* XXXDCL NT  -- This interface will assuredly be changing. */
1018 void
1019 isc_log_opensyslog(const char *tag, int options, int facility) {
1020         (void)openlog(tag, options, facility);
1021 }
1022
1023 void
1024 isc_log_closefilelogs(isc_log_t *lctx) {
1025         isc_logchannel_t *channel;
1026
1027         REQUIRE(VALID_CONTEXT(lctx));
1028
1029         LOCK(&lctx->lock);
1030         for (channel = ISC_LIST_HEAD(lctx->logconfig->channels);
1031              channel != NULL;
1032              channel = ISC_LIST_NEXT(channel, link))
1033
1034                 if (channel->type == ISC_LOG_TOFILE &&
1035                     FILE_STREAM(channel) != NULL) {
1036                         (void)fclose(FILE_STREAM(channel));
1037                         FILE_STREAM(channel) = NULL;
1038                 }
1039         UNLOCK(&lctx->lock);
1040 }
1041
1042 /****
1043  **** Internal functions
1044  ****/
1045
1046 static isc_result_t
1047 assignchannel(isc_logconfig_t *lcfg, unsigned int category_id,
1048               const isc_logmodule_t *module, isc_logchannel_t *channel)
1049 {
1050         isc_logchannellist_t *new_item;
1051         isc_log_t *lctx;
1052         isc_result_t result;
1053
1054         REQUIRE(VALID_CONFIG(lcfg));
1055
1056         lctx = lcfg->lctx;
1057
1058         REQUIRE(category_id < lctx->category_count);
1059         REQUIRE(module == NULL || module->id < lctx->module_count);
1060         REQUIRE(channel != NULL);
1061
1062         /*
1063          * Ensure lcfg->channellist_count == lctx->category_count.
1064          */
1065         result = sync_channellist(lcfg);
1066         if (result != ISC_R_SUCCESS)
1067                 return (result);
1068
1069         new_item = isc_mem_get(lctx->mctx, sizeof(*new_item));
1070         if (new_item == NULL)
1071                 return (ISC_R_NOMEMORY);
1072
1073         new_item->channel = channel;
1074         new_item->module = module;
1075         ISC_LIST_INITANDPREPEND(lcfg->channellists[category_id],
1076                                new_item, link);
1077
1078         /*
1079          * Remember the highest logging level set by any channel in the
1080          * logging config, so isc_log_doit() can quickly return if the
1081          * message is too high to be logged by any channel.
1082          */
1083         if (channel->type != ISC_LOG_TONULL) {
1084                 if (lcfg->highest_level < channel->level)
1085                         lcfg->highest_level = channel->level;
1086                 if (channel->level == ISC_LOG_DYNAMIC)
1087                         lcfg->dynamic = ISC_TRUE;
1088         }
1089
1090         return (ISC_R_SUCCESS);
1091 }
1092
1093 /*
1094  * This would ideally be part of isc_log_registercategories(), except then
1095  * that function would have to return isc_result_t instead of void.
1096  */
1097 static isc_result_t
1098 sync_channellist(isc_logconfig_t *lcfg) {
1099         unsigned int bytes;
1100         isc_log_t *lctx;
1101         void *lists;
1102
1103         REQUIRE(VALID_CONFIG(lcfg));
1104
1105         lctx = lcfg->lctx;
1106
1107         REQUIRE(lctx->category_count != 0);
1108
1109         if (lctx->category_count == lcfg->channellist_count)
1110                 return (ISC_R_SUCCESS);
1111
1112         bytes = lctx->category_count * sizeof(ISC_LIST(isc_logchannellist_t));
1113
1114         lists = isc_mem_get(lctx->mctx, bytes);
1115
1116         if (lists == NULL)
1117                 return (ISC_R_NOMEMORY);
1118
1119         memset(lists, 0, bytes);
1120
1121         if (lcfg->channellist_count != 0) {
1122                 bytes = lcfg->channellist_count *
1123                         sizeof(ISC_LIST(isc_logchannellist_t));
1124                 memcpy(lists, lcfg->channellists, bytes);
1125                 isc_mem_put(lctx->mctx, lcfg->channellists, bytes);
1126         }
1127
1128         lcfg->channellists = lists;
1129         lcfg->channellist_count = lctx->category_count;
1130
1131         return (ISC_R_SUCCESS);
1132 }
1133
1134 static isc_result_t
1135 greatest_version(isc_logchannel_t *channel, int *greatestp) {
1136         /* XXXDCL HIGHLY NT */
1137         char *basename, *digit_end;
1138         const char *dirname;
1139         int version, greatest = -1;
1140         unsigned int basenamelen;
1141         isc_dir_t dir;
1142         isc_result_t result;
1143         char sep = '/';
1144 #ifdef _WIN32
1145         char *basename2;
1146 #endif
1147
1148         REQUIRE(channel->type == ISC_LOG_TOFILE);
1149
1150         /*
1151          * It is safe to DE_CONST the file.name because it was copied
1152          * with isc_mem_strdup in isc_log_createchannel.
1153          */
1154         basename = strrchr(FILE_NAME(channel), sep);
1155 #ifdef _WIN32
1156         basename2 = strrchr(FILE_NAME(channel), '\\');
1157         if ((basename != NULL && basename2 != NULL && basename2 > basename) ||
1158             (basename == NULL && basename2 != NULL)) {
1159                 basename = basename2;
1160                 sep = '\\';
1161         }
1162 #endif
1163         if (basename != NULL) {
1164                 *basename++ = '\0';
1165                 dirname = FILE_NAME(channel);
1166         } else {
1167                 DE_CONST(FILE_NAME(channel), basename);
1168                 dirname = ".";
1169         }
1170         basenamelen = strlen(basename);
1171
1172         isc_dir_init(&dir);
1173         result = isc_dir_open(&dir, dirname);
1174
1175         /*
1176          * Replace the file separator if it was taken out.
1177          */
1178         if (basename != FILE_NAME(channel))
1179                 *(basename - 1) = sep;
1180
1181         /*
1182          * Return if the directory open failed.
1183          */
1184         if (result != ISC_R_SUCCESS)
1185                 return (result);
1186
1187         while (isc_dir_read(&dir) == ISC_R_SUCCESS) {
1188                 if (dir.entry.length > basenamelen &&
1189                     strncmp(dir.entry.name, basename, basenamelen) == 0 &&
1190                     dir.entry.name[basenamelen] == '.') {
1191
1192                         version = strtol(&dir.entry.name[basenamelen + 1],
1193                                          &digit_end, 10);
1194                         if (*digit_end == '\0' && version > greatest)
1195                                 greatest = version;
1196                 }
1197         }
1198         isc_dir_close(&dir);
1199
1200         *greatestp = ++greatest;
1201
1202         return (ISC_R_SUCCESS);
1203 }
1204
1205 static isc_result_t
1206 roll_log(isc_logchannel_t *channel) {
1207         int i, n, greatest;
1208         char current[PATH_MAX + 1];
1209         char new[PATH_MAX + 1];
1210         const char *path;
1211         isc_result_t result;
1212
1213         /*
1214          * Do nothing (not even excess version trimming) if ISC_LOG_ROLLNEVER
1215          * is specified.  Apparently complete external control over the log
1216          * files is desired.
1217          */
1218         if (FILE_VERSIONS(channel) == ISC_LOG_ROLLNEVER)
1219                 return (ISC_R_SUCCESS);
1220
1221         path = FILE_NAME(channel);
1222
1223         /*
1224          * Set greatest_version to the greatest existing version
1225          * (not the maximum requested version).  This is 1 based even
1226          * though the file names are 0 based, so an oldest log of log.1
1227          * is a greatest_version of 2.
1228          */
1229         result = greatest_version(channel, &greatest);
1230         if (result != ISC_R_SUCCESS)
1231                 return (result);
1232
1233         /*
1234          * Now greatest should be set to the highest version number desired.
1235          * Since the highest number is one less than FILE_VERSIONS(channel)
1236          * when not doing infinite log rolling, greatest will need to be
1237          * decremented when it is equal to -- or greater than --
1238          * FILE_VERSIONS(channel).  When greatest is less than
1239          * FILE_VERSIONS(channel), it is already suitable for use as
1240          * the maximum version number.
1241          */
1242
1243         if (FILE_VERSIONS(channel) == ISC_LOG_ROLLINFINITE ||
1244             FILE_VERSIONS(channel) > greatest)
1245                 ;               /* Do nothing. */
1246         else
1247                 /*
1248                  * When greatest is >= FILE_VERSIONS(channel), it needs to
1249                  * be reduced until it is FILE_VERSIONS(channel) - 1.
1250                  * Remove any excess logs on the way to that value.
1251                  */
1252                 while (--greatest >= FILE_VERSIONS(channel)) {
1253                         n = snprintf(current, sizeof(current), "%s.%d",
1254                                      path, greatest);
1255                         if (n >= (int)sizeof(current) || n < 0)
1256                                 result = ISC_R_NOSPACE;
1257                         else
1258                                 result = isc_file_remove(current);
1259                         if (result != ISC_R_SUCCESS &&
1260                             result != ISC_R_FILENOTFOUND)
1261                                 syslog(LOG_ERR,
1262                                        "unable to remove log file '%s.%d': %s",
1263                                        path, greatest,
1264                                        isc_result_totext(result));
1265                 }
1266
1267         for (i = greatest; i > 0; i--) {
1268                 result = ISC_R_SUCCESS;
1269                 n = snprintf(current, sizeof(current), "%s.%d", path, i - 1);
1270                 if (n >= (int)sizeof(current) || n < 0)
1271                         result = ISC_R_NOSPACE;
1272                 if (result == ISC_R_SUCCESS) {
1273                         n = snprintf(new, sizeof(new), "%s.%d", path, i);
1274                         if (n >= (int)sizeof(new) || n < 0)
1275                                 result = ISC_R_NOSPACE;
1276                 }
1277                 if (result == ISC_R_SUCCESS)
1278                         result = isc_file_rename(current, new);
1279                 if (result != ISC_R_SUCCESS &&
1280                     result != ISC_R_FILENOTFOUND)
1281                         syslog(LOG_ERR,
1282                                "unable to rename log file '%s.%d' to "
1283                                "'%s.%d': %s", path, i - 1, path, i,
1284                                isc_result_totext(result));
1285         }
1286
1287         if (FILE_VERSIONS(channel) != 0) {
1288                 n = snprintf(new, sizeof(new), "%s.0", path);
1289                 if (n >= (int)sizeof(new) || n < 0)
1290                         result = ISC_R_NOSPACE;
1291                 else
1292                         result = isc_file_rename(path, new);
1293                 if (result != ISC_R_SUCCESS &&
1294                     result != ISC_R_FILENOTFOUND)
1295                         syslog(LOG_ERR,
1296                                "unable to rename log file '%s' to '%s.0': %s",
1297                                path, path, isc_result_totext(result));
1298         } else {
1299                 result = isc_file_remove(path);
1300                 if (result != ISC_R_SUCCESS &&
1301                     result != ISC_R_FILENOTFOUND)
1302                         syslog(LOG_ERR, "unable to remove log file '%s': %s",
1303                                path, isc_result_totext(result));
1304         }
1305
1306         return (ISC_R_SUCCESS);
1307 }
1308
1309 static isc_result_t
1310 isc_log_open(isc_logchannel_t *channel) {
1311         struct stat statbuf;
1312         isc_boolean_t regular_file;
1313         isc_boolean_t roll = ISC_FALSE;
1314         isc_result_t result = ISC_R_SUCCESS;
1315         const char *path;
1316
1317         REQUIRE(channel->type == ISC_LOG_TOFILE);
1318         REQUIRE(FILE_STREAM(channel) == NULL);
1319
1320         path = FILE_NAME(channel);
1321
1322         REQUIRE(path != NULL && *path != '\0');
1323
1324         /*
1325          * Determine type of file; only regular files will be
1326          * version renamed, and only if the base file exists
1327          * and either has no size limit or has reached its size limit.
1328          */
1329         if (stat(path, &statbuf) == 0) {
1330                 regular_file = S_ISREG(statbuf.st_mode) ? ISC_TRUE : ISC_FALSE;
1331                 /* XXXDCL if not regular_file complain? */
1332                 if ((FILE_MAXSIZE(channel) == 0 &&
1333                      FILE_VERSIONS(channel) != ISC_LOG_ROLLNEVER) ||
1334                     (FILE_MAXSIZE(channel) > 0 &&
1335                      statbuf.st_size >= FILE_MAXSIZE(channel)))
1336                         roll = regular_file;
1337         } else if (errno == ENOENT)
1338                 regular_file = ISC_TRUE;
1339         else
1340                 result = ISC_R_INVALIDFILE;
1341
1342         /*
1343          * Version control.
1344          */
1345         if (result == ISC_R_SUCCESS && roll) {
1346                 if (FILE_VERSIONS(channel) == ISC_LOG_ROLLNEVER)
1347                         return (ISC_R_MAXSIZE);
1348                 result = roll_log(channel);
1349                 if (result != ISC_R_SUCCESS) {
1350                         if ((channel->flags & ISC_LOG_OPENERR) == 0) {
1351                                 syslog(LOG_ERR,
1352                                        "isc_log_open: roll_log '%s' "
1353                                        "failed: %s",
1354                                        FILE_NAME(channel),
1355                                        isc_result_totext(result));
1356                                 channel->flags |= ISC_LOG_OPENERR;
1357                         }
1358                         return (result);
1359                 }
1360         }
1361
1362         result = isc_stdio_open(path, "a", &FILE_STREAM(channel));
1363
1364         return (result);
1365 }
1366
1367 isc_boolean_t
1368 isc_log_wouldlog(isc_log_t *lctx, int level) {
1369         /*
1370          * Try to avoid locking the mutex for messages which can't
1371          * possibly be logged to any channels -- primarily debugging
1372          * messages that the debug level is not high enough to print.
1373          *
1374          * If the level is (mathematically) less than or equal to the
1375          * highest_level, or if there is a dynamic channel and the level is
1376          * less than or equal to the debug level, the main loop must be
1377          * entered to see if the message should really be output.
1378          *
1379          * NOTE: this is UNLOCKED access to the logconfig.  However,
1380          * the worst thing that can happen is that a bad decision is made
1381          * about returning without logging, and that's not a big concern,
1382          * because that's a risk anyway if the logconfig is being
1383          * dynamically changed.
1384          */
1385
1386         if (lctx == NULL || lctx->logconfig == NULL)
1387                 return (ISC_FALSE);
1388
1389         return (ISC_TF(level <= lctx->logconfig->highest_level ||
1390                        (lctx->logconfig->dynamic &&
1391                         level <= lctx->debug_level)));
1392 }
1393
1394 static void
1395 isc_log_doit(isc_log_t *lctx, isc_logcategory_t *category,
1396              isc_logmodule_t *module, int level, isc_boolean_t write_once,
1397              isc_msgcat_t *msgcat, int msgset, int msg,
1398              const char *format, va_list args)
1399 {
1400         int syslog_level;
1401         char time_string[64];
1402         char level_string[24];
1403         const char *iformat;
1404         struct stat statbuf;
1405         isc_boolean_t matched = ISC_FALSE;
1406         isc_boolean_t printtime, printtag;
1407         isc_boolean_t printcategory, printmodule, printlevel;
1408         isc_logconfig_t *lcfg;
1409         isc_logchannel_t *channel;
1410         isc_logchannellist_t *category_channels;
1411         isc_result_t result;
1412
1413         REQUIRE(lctx == NULL || VALID_CONTEXT(lctx));
1414         REQUIRE(category != NULL);
1415         REQUIRE(module != NULL);
1416         REQUIRE(level != ISC_LOG_DYNAMIC);
1417         REQUIRE(format != NULL);
1418
1419         /*
1420          * Programs can use libraries that use this logging code without
1421          * wanting to do any logging, thus the log context is allowed to
1422          * be non-existent.
1423          */
1424         if (lctx == NULL)
1425                 return;
1426
1427         REQUIRE(category->id < lctx->category_count);
1428         REQUIRE(module->id < lctx->module_count);
1429
1430         if (! isc_log_wouldlog(lctx, level))
1431                 return;
1432
1433         if (msgcat != NULL)
1434                 iformat = isc_msgcat_get(msgcat, msgset, msg, format);
1435         else
1436                 iformat = format;
1437
1438         time_string[0]  = '\0';
1439         level_string[0] = '\0';
1440
1441         LOCK(&lctx->lock);
1442
1443         lctx->buffer[0] = '\0';
1444         
1445         lcfg = lctx->logconfig;
1446
1447         category_channels = ISC_LIST_HEAD(lcfg->channellists[category->id]);
1448
1449         /*
1450          * XXXDCL add duplicate filtering? (To not write multiple times to
1451          * the same source via various channels).
1452          */
1453         do {
1454                 /*
1455                  * If the channel list end was reached and a match was made,
1456                  * everything is finished.
1457                  */
1458                 if (category_channels == NULL && matched)
1459                         break;
1460
1461                 if (category_channels == NULL && ! matched &&
1462                     category_channels != ISC_LIST_HEAD(lcfg->channellists[0]))
1463                         /*
1464                          * No category/module pair was explicitly configured.
1465                          * Try the category named "default".
1466                          */
1467                         category_channels =
1468                                 ISC_LIST_HEAD(lcfg->channellists[0]);
1469
1470                 if (category_channels == NULL && ! matched)
1471                         /*
1472                          * No matching module was explicitly configured
1473                          * for the category named "default".  Use the internal
1474                          * default channel.
1475                          */
1476                         category_channels = &default_channel;
1477
1478                 if (category_channels->module != NULL &&
1479                     category_channels->module != module) {
1480                         category_channels = ISC_LIST_NEXT(category_channels,
1481                                                           link);
1482                         continue;
1483                 }
1484
1485                 matched = ISC_TRUE;
1486
1487                 channel = category_channels->channel;
1488                 category_channels = ISC_LIST_NEXT(category_channels, link);
1489
1490                 if (((channel->flags & ISC_LOG_DEBUGONLY) != 0) &&
1491                     lctx->debug_level == 0)
1492                         continue;
1493
1494                 if (channel->level == ISC_LOG_DYNAMIC) {
1495                         if (lctx->debug_level < level)
1496                                 continue;
1497                 } else if (channel->level < level)
1498                         continue;
1499
1500                 if ((channel->flags & ISC_LOG_PRINTTIME) != 0 &&
1501                     time_string[0] == '\0') {
1502                         isc_time_t isctime;
1503                         
1504                         TIME_NOW(&isctime);
1505                         isc_time_formattimestamp(&isctime, time_string,
1506                                                  sizeof(time_string));
1507                 }
1508
1509                 if ((channel->flags & ISC_LOG_PRINTLEVEL) != 0 &&
1510                     level_string[0] == '\0') {
1511                         if (level < ISC_LOG_CRITICAL)
1512                                 snprintf(level_string, sizeof(level_string),
1513                                          isc_msgcat_get(isc_msgcat,
1514                                                         ISC_MSGSET_LOG,
1515                                                         ISC_MSG_LEVEL,
1516                                                         "level %d: "),
1517                                          level);
1518                         else if (level > ISC_LOG_DYNAMIC)
1519                                 snprintf(level_string, sizeof(level_string),
1520                                          "%s %d: ", log_level_strings[0],
1521                                          level);
1522                         else
1523                                 snprintf(level_string, sizeof(level_string),
1524                                          "%s: ", log_level_strings[-level]);
1525                 }
1526
1527                 /*
1528                  * Only format the message once.
1529                  */
1530                 if (lctx->buffer[0] == '\0') {
1531                         (void)vsnprintf(lctx->buffer, sizeof(lctx->buffer),
1532                                         iformat, args);
1533
1534                         /*
1535                          * Check for duplicates.
1536                          */
1537                         if (write_once) {
1538                                 isc_logmessage_t *message, *new;
1539                                 isc_time_t oldest;
1540                                 isc_interval_t interval;
1541
1542                                 isc_interval_set(&interval,
1543                                                  lcfg->duplicate_interval, 0);
1544
1545                                 /*
1546                                  * 'oldest' is the age of the oldest messages
1547                                  * which fall within the duplicate_interval
1548                                  * range.
1549                                  */
1550                                 TIME_NOW(&oldest);
1551                                 if (isc_time_subtract(&oldest, &interval, &oldest)
1552                                     != ISC_R_SUCCESS)
1553                                         /*
1554                                          * Can't effectively do the checking
1555                                          * without having a valid time.
1556                                          */
1557                                         message = NULL;
1558                                 else
1559                                         message =ISC_LIST_HEAD(lctx->messages);
1560
1561                                 while (message != NULL) {
1562                                         if (isc_time_compare(&message->time,
1563                                                              &oldest) < 0) {
1564                                                 /*
1565                                                  * This message is older
1566                                                  * than the duplicate_interval,
1567                                                  * so it should be dropped from
1568                                                  * the history.
1569                                                  *
1570                                                  * Setting the interval to be
1571                                                  * to be longer will obviously
1572                                                  * not cause the expired
1573                                                  * message to spring back into
1574                                                  * existence.
1575                                                  */
1576                                                 new = ISC_LIST_NEXT(message,
1577                                                                     link);
1578
1579                                                 ISC_LIST_UNLINK(lctx->messages,
1580                                                                 message, link);
1581
1582                                                 isc_mem_put(lctx->mctx,
1583                                                         message,
1584                                                         sizeof(*message) + 1 +
1585                                                         strlen(message->text));
1586
1587                                                 message = new;
1588                                                 continue;
1589                                         }
1590
1591                                         /*
1592                                          * This message is in the duplicate
1593                                          * filtering interval ...
1594                                          */
1595                                         if (strcmp(lctx->buffer, message->text)
1596                                             == 0) {
1597                                                 /*
1598                                                  * ... and it is a duplicate.
1599                                                  * Unlock the mutex and
1600                                                  * get the hell out of Dodge.
1601                                                  */
1602                                                 UNLOCK(&lctx->lock);
1603                                                 return;
1604                                         }
1605
1606                                         message = ISC_LIST_NEXT(message, link);
1607                                 }
1608
1609                                 /*
1610                                  * It wasn't in the duplicate interval,
1611                                  * so add it to the message list.
1612                                  */
1613                                 new = isc_mem_get(lctx->mctx,
1614                                                   sizeof(isc_logmessage_t) +
1615                                                   strlen(lctx->buffer) + 1);
1616                                 if (new != NULL) {
1617                                         /*
1618                                          * Put the text immediately after
1619                                          * the struct.  The strcpy is safe.
1620                                          */
1621                                         new->text = (char *)(new + 1);
1622                                         strcpy(new->text, lctx->buffer);
1623
1624                                         TIME_NOW(&new->time);
1625
1626                                         ISC_LIST_APPEND(lctx->messages,
1627                                                         new, link);
1628                                 }
1629                         }
1630                 }
1631
1632                 printtime     = ISC_TF((channel->flags & ISC_LOG_PRINTTIME)
1633                                        != 0);
1634                 printtag      = ISC_TF((channel->flags & ISC_LOG_PRINTTAG)
1635                                        != 0 && lcfg->tag != NULL);
1636                 printcategory = ISC_TF((channel->flags & ISC_LOG_PRINTCATEGORY)
1637                                        != 0);
1638                 printmodule   = ISC_TF((channel->flags & ISC_LOG_PRINTMODULE)
1639                                        != 0);
1640                 printlevel    = ISC_TF((channel->flags & ISC_LOG_PRINTLEVEL)
1641                                        != 0);
1642
1643                 switch (channel->type) {
1644                 case ISC_LOG_TOFILE:
1645                         if (FILE_MAXREACHED(channel)) {
1646                                 /*
1647                                  * If the file can be rolled, OR
1648                                  * If the file no longer exists, OR
1649                                  * If the file is less than the maximum size,
1650                                  *    (such as if it had been renamed and
1651                                  *     a new one touched, or it was truncated
1652                                  *     in place)
1653                                  * ... then close it to trigger reopening.
1654                                  */
1655                                 if (FILE_VERSIONS(channel) !=
1656                                     ISC_LOG_ROLLNEVER ||
1657                                     (stat(FILE_NAME(channel), &statbuf) != 0 &&
1658                                      errno == ENOENT) ||
1659                                     statbuf.st_size < FILE_MAXSIZE(channel)) {
1660                                         (void)fclose(FILE_STREAM(channel));
1661                                         FILE_STREAM(channel) = NULL;
1662                                         FILE_MAXREACHED(channel) = ISC_FALSE;
1663                                 } else
1664                                         /*
1665                                          * Eh, skip it.
1666                                          */
1667                                         break;
1668                         }
1669
1670                         if (FILE_STREAM(channel) == NULL) {
1671                                 result = isc_log_open(channel);
1672                                 if (result != ISC_R_SUCCESS &&
1673                                     result != ISC_R_MAXSIZE &&
1674                                     (channel->flags & ISC_LOG_OPENERR) == 0) {
1675                                         syslog(LOG_ERR,
1676                                                "isc_log_open '%s' failed: %s",
1677                                                FILE_NAME(channel),
1678                                                isc_result_totext(result));
1679                                         channel->flags |= ISC_LOG_OPENERR;
1680                                 }
1681                                 if (result != ISC_R_SUCCESS)
1682                                         break;
1683                                 channel->flags &= ~ISC_LOG_OPENERR;
1684                         }
1685                         /* FALLTHROUGH */
1686
1687                 case ISC_LOG_TOFILEDESC:
1688                         fprintf(FILE_STREAM(channel), "%s%s%s%s%s%s%s%s%s%s\n",
1689                                 printtime     ? time_string     : "",
1690                                 printtime     ? " "             : "",
1691                                 printtag      ? lcfg->tag       : "",
1692                                 printtag      ? ": "            : "",
1693                                 printcategory ? category->name  : "",
1694                                 printcategory ? ": "            : "",
1695                                 printmodule   ? (module != NULL ? module->name
1696                                                                 : "no_module")
1697                                                                 : "",
1698                                 printmodule   ? ": "            : "",
1699                                 printlevel    ? level_string    : "",
1700                                 lctx->buffer);
1701
1702                         fflush(FILE_STREAM(channel));
1703
1704                         /*
1705                          * If the file now exceeds its maximum size
1706                          * threshold, note it so that it will not be logged
1707                          * to any more.
1708                          */
1709                         if (FILE_MAXSIZE(channel) > 0) {
1710                                 INSIST(channel->type == ISC_LOG_TOFILE);
1711
1712                                 /* XXXDCL NT fstat/fileno */
1713                                 /* XXXDCL complain if fstat fails? */
1714                                 if (fstat(fileno(FILE_STREAM(channel)),
1715                                           &statbuf) >= 0 &&
1716                                     statbuf.st_size > FILE_MAXSIZE(channel))
1717                                         FILE_MAXREACHED(channel) = ISC_TRUE;
1718                         }
1719
1720                         break;
1721
1722                 case ISC_LOG_TOSYSLOG:
1723                         if (level > 0)
1724                                 syslog_level = LOG_DEBUG;
1725                         else if (level < ISC_LOG_CRITICAL)
1726                                 syslog_level = LOG_CRIT;
1727                         else
1728                                 syslog_level = syslog_map[-level];
1729
1730                         (void)syslog(FACILITY(channel) | syslog_level,
1731                                "%s%s%s%s%s%s%s%s%s%s",
1732                                printtime     ? time_string      : "",
1733                                printtime     ? " "              : "",
1734                                printtag      ? lcfg->tag        : "",
1735                                printtag      ? ": "             : "",
1736                                printcategory ? category->name   : "",
1737                                printcategory ? ": "             : "",
1738                                printmodule   ? (module != NULL  ? module->name
1739                                                                 : "no_module")
1740                                                                 : "",
1741                                printmodule   ? ": "             : "",
1742                                printlevel    ? level_string     : "",
1743                                lctx->buffer);
1744                         break;
1745
1746                 case ISC_LOG_TONULL:
1747                         break;
1748
1749                 }
1750
1751         } while (1);
1752
1753         UNLOCK(&lctx->lock);
1754 }