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