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