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