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