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