log.c 44.7 KB
Newer Older
1
/*
Automatic Updater's avatar
Automatic Updater committed
2
 * Copyright (C) 2004-2007, 2009  Internet Systems Consortium, Inc. ("ISC")
Mark Andrews's avatar
Mark Andrews committed
3
 * Copyright (C) 1999-2003  Internet Software Consortium.
4
 *
Automatic Updater's avatar
Automatic Updater committed
5
 * Permission to use, copy, modify, and/or distribute this software for any
6 7
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
8
 *
Mark Andrews's avatar
Mark Andrews committed
9 10 11 12 13 14 15
 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
16 17
 */

Automatic Updater's avatar
Automatic Updater committed
18
/* $Id: log.c,v 1.97 2009/01/06 23:47:57 tbox Exp $ */
19

20 21
/*! \file
 * \author  Principal Authors: DCL */
22

David Lawrence's avatar
David Lawrence committed
23 24
#include <config.h>

25 26 27
#include <errno.h>
#include <stdlib.h>
#include <limits.h>
Brian Wellington's avatar
Brian Wellington committed
28
#include <time.h>
29

Mark Andrews's avatar
Mark Andrews committed
30
#include <sys/types.h>	/* dev_t FreeBSD 2.1 */
31 32

#include <isc/dir.h>
33
#include <isc/file.h>
34
#include <isc/log.h>
35
#include <isc/magic.h>
36
#include <isc/mem.h>
37
#include <isc/msgs.h>
38
#include <isc/print.h>
Mark Andrews's avatar
Mark Andrews committed
39
#include <isc/stat.h>
40
#include <isc/stdio.h>
41
#include <isc/string.h>
42
#include <isc/time.h>
43
#include <isc/util.h>
44

45
#define LCTX_MAGIC		ISC_MAGIC('L', 'c', 't', 'x')
46
#define VALID_CONTEXT(lctx)	ISC_MAGIC_VALID(lctx, LCTX_MAGIC)
47 48

#define LCFG_MAGIC		ISC_MAGIC('L', 'c', 'f', 'g')
49
#define VALID_CONFIG(lcfg)	ISC_MAGIC_VALID(lcfg, LCFG_MAGIC)
50

51 52 53
/*
 * XXXDCL make dynamic?
 */
54 55
#define LOG_BUFFER_SIZE	(8 * 1024)

56 57 58 59
#ifndef PATH_MAX
#define PATH_MAX 1024	/* AIX and others don't define this. */
#endif

60
/*!
61 62 63 64 65 66 67 68
 * This is the structure that holds each named channel.  A simple linked
 * list chains all of the channels together, so an individual channel is
 * found by doing strcmp()s with the names down the list.  Their should
 * be no peformance penalty from this as it is expected that the number
 * of named channels will be no more than a dozen or so, and name lookups
 * from the head of the list are only done when isc_log_usechannel() is
 * called, which should also be very infrequent.
 */
69 70
typedef struct isc_logchannel isc_logchannel_t;

71
struct isc_logchannel {
72 73 74 75 76 77
	char *				name;
	unsigned int			type;
	int 				level;
	unsigned int			flags;
	isc_logdestination_t 		destination;
	ISC_LINK(isc_logchannel_t)	link;
78 79
};

80
/*!
81
 * The logchannellist structure associates categories and modules with
82 83 84 85 86 87 88 89 90
 * channels.  First the appropriate channellist is found based on the
 * category, and then each structure in the linked list is checked for
 * a matching module.  It is expected that the number of channels
 * associated with any given category will be very short, no more than
 * three or four in the more unusual cases.
 */
typedef struct isc_logchannellist isc_logchannellist_t;

struct isc_logchannellist {
David Lawrence's avatar
David Lawrence committed
91
	const isc_logmodule_t *		module;
92 93
	isc_logchannel_t *		channel;
	ISC_LINK(isc_logchannellist_t)	link;
94 95
};

96
/*!
97 98 99 100 101 102
 * This structure is used to remember messages for pruning via
 * isc_log_[v]write1().
 */
typedef struct isc_logmessage isc_logmessage_t;

struct isc_logmessage {
103 104 105 106 107
	char *				text;
	isc_time_t			time;
	ISC_LINK(isc_logmessage_t)	link;
};

108
/*!
109 110 111 112 113
 * The isc_logconfig structure is used to store the configurable information
 * about where messages are actually supposed to be sent -- the information
 * that could changed based on some configuration file, as opposed to the
 * the category/module specification of isc_log_[v]write[1] that is compiled
 * into a program, or the debug_level which is dynamic state information.
114 115 116 117
 */
struct isc_logconfig {
	unsigned int			magic;
	isc_log_t *			lctx;
118 119
	ISC_LIST(isc_logchannel_t)	channels;
	ISC_LIST(isc_logchannellist_t) *channellists;
120 121
	unsigned int			channellist_count;
	unsigned int			duplicate_interval;
122
	int				highest_level;
123
	char *				tag;
124
	isc_boolean_t			dynamic;
125 126
};

127
/*!
128
 * This isc_log structure provides the context for the isc_log functions.
129
 * The log context locks itself in isc_log_doit, the internal backend to
130
 * isc_log_write.  The locking is necessary both to provide exclusive access
131
 * to the buffer into which the message is formatted and to guard against
132 133 134 135 136
 * competing threads trying to write to the same syslog resource.  (On
 * some systems, such as BSD/OS, stdio is thread safe but syslog is not.)
 * Unfortunately, the lock cannot guard against a _different_ logging
 * context in the same program competing for syslog's attention.  Thus
 * There Can Be Only One, but this is not enforced.
137
 * XXXDCL enforce it?
138 139 140 141
 *
 * Note that the category and module information is not locked.
 * This is because in the usual case, only one isc_log_t is ever created
 * in a program, and the category/module registration happens only once.
142
 * XXXDCL it might be wise to add more locking overall.
143 144
 */
struct isc_log {
145
	/* Not locked. */
146 147
	unsigned int			magic;
	isc_mem_t *			mctx;
148
	isc_logcategory_t *		categories;
149
	unsigned int			category_count;
150
	isc_logmodule_t *		modules;
151
	unsigned int			module_count;
152 153 154 155
	int				debug_level;
	isc_mutex_t			lock;
	/* Locked by isc_log lock. */
	isc_logconfig_t * 		logconfig;
156 157
	char 				buffer[LOG_BUFFER_SIZE];
	ISC_LIST(isc_logmessage_t)	messages;
158 159
};

160
/*!
161 162
 * Used when ISC_LOG_PRINTLEVEL is enabled for a channel.
 */
163
static const char *log_level_strings[] = {
164 165 166 167 168 169
	"debug",
	"info",
	"notice",
	"warning",
	"error",
	"critical"
170 171
};

172
/*!
173
 * Used to convert ISC_LOG_* priorities into syslog priorities.
174
 * XXXDCL This will need modification for NT.
175 176
 */
static const int syslog_map[] = {
177 178 179 180 181 182
	LOG_DEBUG,
	LOG_INFO,
	LOG_NOTICE,
	LOG_WARNING,
	LOG_ERR,
	LOG_CRIT
183 184
};

185
/*!
186
 * When adding new categories, a corresponding ISC_LOGCATEGORY_foo
187
 * definition needs to be added to <isc/log.h>.
188 189 190 191 192
 *
 * The default category is provided so that the internal default can
 * be overridden.  Since the default is always looked up as the first
 * channellist in the log context, it must come first in isc_categories[].
 */
193
LIBISC_EXTERNAL_DATA isc_logcategory_t isc_categories[] = {
194
	{ "default", 0 },	/* "default" must come first. */
195
	{ "general", 0 },
196 197 198
	{ NULL, 0 }
};

199 200
/*!
 * See above comment for categories on LIBISC_EXTERNAL_DATA, and apply it to modules.
201
 */
202
LIBISC_EXTERNAL_DATA isc_logmodule_t isc_modules[] = {
203
	{ "socket", 0 },
204
	{ "time", 0 },
205
	{ "interface", 0 },
Michael Graff's avatar
Michael Graff committed
206
	{ "timer", 0 },
207 208 209
	{ NULL, 0 }
};

210
/*!
211
 * This essentially constant structure must be filled in at run time,
212 213
 * because its channel member is pointed to a channel that is created
 * dynamically with isc_log_createchannel.
214
 */
215
static isc_logchannellist_t default_channel;
216

217
/*!
218 219
 * libisc logs to this context.
 */
220
LIBISC_EXTERNAL_DATA isc_log_t *isc_lctx = NULL;
221

222
/*!
223 224
 * Forward declarations.
 */
225
static isc_result_t
226
assignchannel(isc_logconfig_t *lcfg, unsigned int category_id,
David Lawrence's avatar
David Lawrence committed
227
	      const isc_logmodule_t *module, isc_logchannel_t *channel);
228

229 230 231
static isc_result_t
sync_channellist(isc_logconfig_t *lcfg);

232
static isc_result_t
233
greatest_version(isc_logchannel_t *channel, int *greatest);
234 235 236 237

static isc_result_t
roll_log(isc_logchannel_t *channel);

238 239 240
static void
isc_log_doit(isc_log_t *lctx, isc_logcategory_t *category,
	     isc_logmodule_t *module, int level, isc_boolean_t write_once,
241
	     isc_msgcat_t *msgcat, int msgset, int msg,
242 243
	     const char *format, va_list args)
     ISC_FORMAT_PRINTF(9, 0);
244

245 246
/*@{*/
/*!
247 248 249
 * Convenience macros.
 */

250 251 252 253 254 255
#define FACILITY(channel)	 (channel->destination.facility)
#define FILE_NAME(channel)	 (channel->destination.file.name)
#define FILE_STREAM(channel)	 (channel->destination.file.stream)
#define FILE_VERSIONS(channel)	 (channel->destination.file.versions)
#define FILE_MAXSIZE(channel)	 (channel->destination.file.maximum_size)
#define FILE_MAXREACHED(channel) (channel->destination.file.maximum_reached)
256

257
/*@}*/
258 259 260 261 262 263 264 265
/****
 **** Public interfaces.
 ****/

/*
 * Establish a new logging context, with default channels.
 */
isc_result_t
266
isc_log_create(isc_mem_t *mctx, isc_log_t **lctxp, isc_logconfig_t **lcfgp) {
267
	isc_log_t *lctx;
268
	isc_logconfig_t *lcfg = NULL;
269
	isc_result_t result;
270 271 272

	REQUIRE(mctx != NULL);
	REQUIRE(lctxp != NULL && *lctxp == NULL);
273
	REQUIRE(lcfgp == NULL || *lcfgp == NULL);
274

275
	lctx = isc_mem_get(mctx, sizeof(*lctx));
276 277
	if (lctx != NULL) {
		lctx->mctx = mctx;
278
		lctx->categories = NULL;
279
		lctx->category_count = 0;
280
		lctx->modules = NULL;
281 282
		lctx->module_count = 0;
		lctx->debug_level = 0;
283

284
		ISC_LIST_INIT(lctx->messages);
285

286 287 288 289 290
		result = isc_mutex_init(&lctx->lock);
		if (result != ISC_R_SUCCESS) {
			isc_mem_put(mctx, lctx, sizeof(*lctx));
			return (result);
		}
291 292 293 294 295 296 297 298 299

		/*
		 * Normally setting the magic number is the last step done
		 * in a creation function, but a valid log context is needed
		 * by isc_log_registercategories and isc_logconfig_create.
		 * If either fails, the lctx is destroyed and not returned
		 * to the caller.
		 */
		lctx->magic = LCTX_MAGIC;
300

301
		isc_log_registercategories(lctx, isc_categories);
302
		isc_log_registermodules(lctx, isc_modules);
303
		result = isc_logconfig_create(lctx, &lcfg);
304

305 306 307
	} else
		result = ISC_R_NOMEMORY;

308 309 310
	if (result == ISC_R_SUCCESS)
		result = sync_channellist(lcfg);

311 312 313 314 315 316
	if (result == ISC_R_SUCCESS) {
		lctx->logconfig = lcfg;

		*lctxp = lctx;
		if (lcfgp != NULL)
			*lcfgp = lcfg;
317

318 319 320
	} else {
		if (lcfg != NULL)
			isc_logconfig_destroy(&lcfg);
321 322
		if (lctx != NULL)
			isc_log_destroy(&lctx);
323
	}
324 325 326 327 328 329 330 331 332

	return (result);
}

isc_result_t
isc_logconfig_create(isc_log_t *lctx, isc_logconfig_t **lcfgp) {
	isc_logconfig_t *lcfg;
	isc_logdestination_t destination;
	isc_result_t result = ISC_R_SUCCESS;
333
	int level = ISC_LOG_INFO;
334 335 336 337

	REQUIRE(lcfgp != NULL && *lcfgp == NULL);
	REQUIRE(VALID_CONTEXT(lctx));

338
	lcfg = isc_mem_get(lctx->mctx, sizeof(*lcfg));
339 340 341 342 343 344

	if (lcfg != NULL) {
		lcfg->lctx = lctx;
		lcfg->channellists = NULL;
		lcfg->channellist_count = 0;
		lcfg->duplicate_interval = 0;
345
		lcfg->highest_level = level;
346
		lcfg->tag = NULL;
347
		lcfg->dynamic = ISC_FALSE;
348

349 350
		ISC_LIST_INIT(lcfg->channels);

351 352 353 354 355 356 357 358 359
		/*
		 * Normally the magic number is the last thing set in the
		 * structure, but isc_log_createchannel() needs a valid
		 * config.  If the channel creation fails, the lcfg is not
		 * returned to the caller.
		 */
		lcfg->magic = LCFG_MAGIC;

	} else
360
		result = ISC_R_NOMEMORY;
361 362 363

	/*
	 * Create the default channels:
Mark Andrews's avatar
Mark Andrews committed
364
	 *   	default_syslog, default_stderr, default_debug and null.
365 366
	 */
	if (result == ISC_R_SUCCESS) {
367
		destination.facility = LOG_DAEMON;
368
		result = isc_log_createchannel(lcfg, "default_syslog",
369
					       ISC_LOG_TOSYSLOG, level,
370 371 372 373 374 375 376 377
					       &destination, 0);
	}

	if (result == ISC_R_SUCCESS) {
		destination.file.stream = stderr;
		destination.file.name = NULL;
		destination.file.versions = ISC_LOG_ROLLNEVER;
		destination.file.maximum_size = 0;
378
		result = isc_log_createchannel(lcfg, "default_stderr",
379
					       ISC_LOG_TOFILEDESC,
380
					       level,
381 382 383 384 385
					       &destination,
					       ISC_LOG_PRINTTIME);
	}

	if (result == ISC_R_SUCCESS) {
386 387 388 389 390 391 392
		/*
		 * Set the default category's channel to default_stderr,
		 * which is at the head of the channels list because it was
		 * just created.
		 */
		default_channel.channel = ISC_LIST_HEAD(lcfg->channels);

393 394 395 396
		destination.file.stream = stderr;
		destination.file.name = NULL;
		destination.file.versions = ISC_LOG_ROLLNEVER;
		destination.file.maximum_size = 0;
397
		result = isc_log_createchannel(lcfg, "default_debug",
398 399 400
					       ISC_LOG_TOFILEDESC,
					       ISC_LOG_DYNAMIC,
					       &destination,
401
					       ISC_LOG_PRINTTIME);
402 403 404
	}

	if (result == ISC_R_SUCCESS)
405
		result = isc_log_createchannel(lcfg, "null",
406 407 408 409 410
					       ISC_LOG_TONULL,
					       ISC_LOG_DYNAMIC,
					       NULL, 0);

	if (result == ISC_R_SUCCESS)
411 412 413 414 415 416 417 418 419 420 421
		*lcfgp = lcfg;

	else
		if (lcfg != NULL)
			isc_logconfig_destroy(&lcfg);

	return (result);
}

isc_logconfig_t *
isc_logconfig_get(isc_log_t *lctx) {
422 423 424 425
	REQUIRE(VALID_CONTEXT(lctx));

	ENSURE(lctx->logconfig != NULL);

426 427
	return (lctx->logconfig);
}
428

429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444
isc_result_t
isc_logconfig_use(isc_log_t *lctx, isc_logconfig_t *lcfg) {
	isc_logconfig_t *old_cfg;
	isc_result_t result;

	REQUIRE(VALID_CONTEXT(lctx));
	REQUIRE(VALID_CONFIG(lcfg));
	REQUIRE(lcfg->lctx == lctx);

	/*
	 * Ensure that lcfg->channellist_count == lctx->category_count.
	 * They won't be equal if isc_log_usechannel has not been called
	 * since any call to isc_log_registercategories.
	 */
	result = sync_channellist(lcfg);
	if (result != ISC_R_SUCCESS)
445 446
		return (result);

447 448 449 450 451 452 453 454
	LOCK(&lctx->lock);

	old_cfg = lctx->logconfig;
	lctx->logconfig = lcfg;

	UNLOCK(&lctx->lock);

	isc_logconfig_destroy(&old_cfg);
455 456 457 458 459 460 461

	return (ISC_R_SUCCESS);
}

void
isc_log_destroy(isc_log_t **lctxp) {
	isc_log_t *lctx;
462
	isc_logconfig_t *lcfg;
463
	isc_mem_t *mctx;
464
	isc_logmessage_t *message;
465 466 467 468 469 470

	REQUIRE(lctxp != NULL && VALID_CONTEXT(*lctxp));

	lctx = *lctxp;
	mctx = lctx->mctx;

471 472 473 474 475 476
	if (lctx->logconfig != NULL) {
		lcfg = lctx->logconfig;
		lctx->logconfig = NULL;
		isc_logconfig_destroy(&lcfg);
	}

477
	DESTROYLOCK(&lctx->lock);
478 479 480 481 482 483 484 485 486 487

	while ((message = ISC_LIST_HEAD(lctx->messages)) != NULL) {
		ISC_LIST_UNLINK(lctx->messages, message, link);

		isc_mem_put(mctx, message,
			    sizeof(*message) + strlen(message->text) + 1);
	}

	lctx->buffer[0] = '\0';
	lctx->debug_level = 0;
488
	lctx->categories = NULL;
489
	lctx->category_count = 0;
490
	lctx->modules = NULL;
491 492 493 494 495 496 497 498 499 500 501 502 503
	lctx->module_count = 0;
	lctx->mctx = NULL;
	lctx->magic = 0;

	isc_mem_put(mctx, lctx, sizeof(*lctx));

	*lctxp = NULL;
}

void
isc_logconfig_destroy(isc_logconfig_t **lcfgp) {
	isc_logconfig_t *lcfg;
	isc_mem_t *mctx;
504 505
	isc_logchannel_t *channel;
	isc_logchannellist_t *item;
David Lawrence's avatar
David Lawrence committed
506
	char *filename;
507 508 509 510 511 512 513 514 515 516 517 518 519 520
	unsigned int i;

	REQUIRE(lcfgp != NULL && VALID_CONFIG(*lcfgp));

	lcfg = *lcfgp;

	/*
	 * This function cannot be called with a logconfig that is in
	 * use by a log context.
	 */
	REQUIRE(lcfg->lctx != NULL && lcfg->lctx->logconfig != lcfg);

	mctx = lcfg->lctx->mctx;

521 522
	while ((channel = ISC_LIST_HEAD(lcfg->channels)) != NULL) {
		ISC_LIST_UNLINK(lcfg->channels, channel, link);
523 524

		if (channel->type == ISC_LOG_TOFILE) {
David Lawrence's avatar
David Lawrence committed
525 526 527 528 529 530 531 532
			/*
			 * The filename for the channel may have ultimately
			 * started its life in user-land as a const string,
			 * but in isc_log_createchannel it gets copied
			 * into writable memory and is not longer truly const.
			 */
			DE_CONST(FILE_NAME(channel), filename);
			isc_mem_free(mctx, filename);
533

David Lawrence's avatar
David Lawrence committed
534 535
			if (FILE_STREAM(channel) != NULL)
				(void)fclose(FILE_STREAM(channel));
536 537 538 539 540 541
		}

		isc_mem_free(mctx, channel->name);
		isc_mem_put(mctx, channel, sizeof(*channel));
	}

542
	for (i = 0; i < lcfg->channellist_count; i++)
543 544 545
		while ((item = ISC_LIST_HEAD(lcfg->channellists[i])) != NULL) {
			ISC_LIST_UNLINK(lcfg->channellists[i], item, link);
			isc_mem_put(mctx, item, sizeof(*item));
546 547
		}

548 549 550 551
	if (lcfg->channellist_count > 0)
		isc_mem_put(mctx, lcfg->channellists,
			    lcfg->channellist_count *
			    sizeof(ISC_LIST(isc_logchannellist_t)));
552

553
	lcfg->dynamic = ISC_FALSE;
554
	if (lcfg->tag != NULL)
555
		isc_mem_free(lcfg->lctx->mctx, lcfg->tag);
556
	lcfg->tag = NULL;
557
	lcfg->highest_level = 0;
558 559
	lcfg->duplicate_interval = 0;
	lcfg->magic = 0;
560

561
	isc_mem_put(mctx, lcfg, sizeof(*lcfg));
562

563
	*lcfgp = NULL;
564 565
}

566
void
567 568 569 570
isc_log_registercategories(isc_log_t *lctx, isc_logcategory_t categories[]) {
	isc_logcategory_t *catp;

	REQUIRE(VALID_CONTEXT(lctx));
571
	REQUIRE(categories != NULL && categories[0].name != NULL);
572

573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588
	/*
	 * XXXDCL This somewhat sleazy situation of using the last pointer
	 * in one category array to point to the next array exists because
	 * this registration function returns void and I didn't want to have
	 * change everything that used it by making it return an isc_result_t.
	 * It would need to do that if it had to allocate memory to store
	 * pointers to each array passed in.
	 */
	if (lctx->categories == NULL)
		lctx->categories = categories;

	else {
		/*
		 * Adjust the last (NULL) pointer of the already registered
		 * categories to point to the incoming array.
		 */
589
		for (catp = lctx->categories; catp->name != NULL; )
590
			if (catp->id == UINT_MAX)
David Lawrence's avatar
David Lawrence committed
591 592 593 594 595
				/*
				 * The name pointer points to the next array.
				 * Ick.
				 */
				DE_CONST(catp->name, catp);
596 597
			else
				catp++;
598 599 600 601

		catp->name = (void *)categories;
		catp->id = UINT_MAX;
	}
602 603 604 605

	/*
	 * Update the id number of the category with its new global id.
	 */
606 607 608 609 610 611 612 613 614
	for (catp = categories; catp->name != NULL; catp++)
		catp->id = lctx->category_count++;
}

isc_logcategory_t *
isc_log_categorybyname(isc_log_t *lctx, const char *name) {
	isc_logcategory_t *catp;

	REQUIRE(VALID_CONTEXT(lctx));
615
	REQUIRE(name != NULL);
616

617
	for (catp = lctx->categories; catp->name != NULL; )
618
		if (catp->id == UINT_MAX)
David Lawrence's avatar
David Lawrence committed
619 620 621 622 623
			/*
			 * catp is neither modified nor returned to the
			 * caller, so removing its const qualifier is ok.
			 */
			DE_CONST(catp->name, catp);
624
		else {
625
			if (strcmp(catp->name, name) == 0)
David Lawrence's avatar
David Lawrence committed
626
				return (catp);
627 628
			catp++;
		}
629

630
	return (NULL);
631 632 633 634 635 636 637
}

void
isc_log_registermodules(isc_log_t *lctx, isc_logmodule_t modules[]) {
	isc_logmodule_t *modp;

	REQUIRE(VALID_CONTEXT(lctx));
638
	REQUIRE(modules != NULL && modules[0].name != NULL);
639

640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655
	/*
	 * XXXDCL This somewhat sleazy situation of using the last pointer
	 * in one category array to point to the next array exists because
	 * this registration function returns void and I didn't want to have
	 * change everything that used it by making it return an isc_result_t.
	 * It would need to do that if it had to allocate memory to store
	 * pointers to each array passed in.
	 */
	if (lctx->modules == NULL)
		lctx->modules = modules;

	else {
		/*
		 * Adjust the last (NULL) pointer of the already registered
		 * modules to point to the incoming array.
		 */
656
		for (modp = lctx->modules; modp->name != NULL; )
657
			if (modp->id == UINT_MAX)
David Lawrence's avatar
David Lawrence committed
658 659 660 661 662
				/*
				 * The name pointer points to the next array.
				 * Ick.
				 */
				DE_CONST(modp->name, modp);
663 664
			else
				modp++;
665 666 667 668

		modp->name = (void *)modules;
		modp->id = UINT_MAX;
	}
669 670 671 672

	/*
	 * Update the id number of the module with its new global id.
	 */
673 674 675 676 677 678 679 680 681
	for (modp = modules; modp->name != NULL; modp++)
		modp->id = lctx->module_count++;
}

isc_logmodule_t *
isc_log_modulebyname(isc_log_t *lctx, const char *name) {
	isc_logmodule_t *modp;

	REQUIRE(VALID_CONTEXT(lctx));
682
	REQUIRE(name != NULL);
683

684
	for (modp = lctx->modules; modp->name != NULL; )
685
		if (modp->id == UINT_MAX)
David Lawrence's avatar
David Lawrence committed
686
			/*
687
			 * modp is neither modified nor returned to the
David Lawrence's avatar
David Lawrence committed
688 689 690
			 * caller, so removing its const qualifier is ok.
			 */
			DE_CONST(modp->name, modp);
691
		else {
692
			if (strcmp(modp->name, name) == 0)
David Lawrence's avatar
David Lawrence committed
693
				return (modp);
694 695
			modp++;
		}
696

697
	return (NULL);
698 699 700
}

isc_result_t
701 702
isc_log_createchannel(isc_logconfig_t *lcfg, const char *name,
		      unsigned int type, int level,
David Lawrence's avatar
David Lawrence committed
703 704
		      const isc_logdestination_t *destination,
		      unsigned int flags)
705 706
{
	isc_logchannel_t *channel;
707
	isc_mem_t *mctx;
708

709
	REQUIRE(VALID_CONFIG(lcfg));
710 711 712 713 714
	REQUIRE(name != NULL);
	REQUIRE(type == ISC_LOG_TOSYSLOG   || type == ISC_LOG_TOFILE ||
		type == ISC_LOG_TOFILEDESC || type == ISC_LOG_TONULL);
	REQUIRE(destination != NULL || type == ISC_LOG_TONULL);
	REQUIRE(level >= ISC_LOG_CRITICAL);
David Lawrence's avatar
David Lawrence committed
715 716
	REQUIRE((flags &
		 (unsigned int)~(ISC_LOG_PRINTALL | ISC_LOG_DEBUGONLY)) == 0);
717

718
	/* XXXDCL find duplicate names? */
719

720 721
	mctx = lcfg->lctx->mctx;

722
	channel = isc_mem_get(mctx, sizeof(*channel));
723 724 725
	if (channel == NULL)
		return (ISC_R_NOMEMORY);

726
	channel->name = isc_mem_strdup(mctx, name);
727
	if (channel->name == NULL) {
728
		isc_mem_put(mctx, channel, sizeof(*channel));
729 730 731 732 733 734
		return (ISC_R_NOMEMORY);
	}

	channel->type = type;
	channel->level = level;
	channel->flags = flags;
735
	ISC_LINK_INIT(channel, link);
736 737 738 739 740 741 742 743 744 745 746 747 748

	switch (type) {
	case ISC_LOG_TOSYSLOG:
		FACILITY(channel) = destination->facility;
		break;

	case ISC_LOG_TOFILE:
		/*
		 * The file name is copied because greatest_version wants
		 * to scribble on it, so it needs to be definitely in
		 * writable memory.
		 */
		FILE_NAME(channel) =
749
			isc_mem_strdup(mctx, destination->file.name);
750 751
		FILE_STREAM(channel) = NULL;
		FILE_VERSIONS(channel) = destination->file.versions;
752 753
		FILE_MAXSIZE(channel) = destination->file.maximum_size;
		FILE_MAXREACHED(channel) = ISC_FALSE;
754 755 756 757 758 759 760 761 762 763 764 765 766 767
		break;

	case ISC_LOG_TOFILEDESC:
		FILE_NAME(channel) = NULL;
		FILE_STREAM(channel) = destination->file.stream;
		FILE_MAXSIZE(channel) = 0;
		FILE_VERSIONS(channel) = ISC_LOG_ROLLNEVER;
		break;

	case ISC_LOG_TONULL:
		/* Nothing. */
		break;

	default:
768 769
		isc_mem_put(mctx, channel->name, strlen(channel->name) + 1);
		isc_mem_put(mctx, channel, sizeof(*channel));
770 771
		return (ISC_R_UNEXPECTED);
	}
772

773
	ISC_LIST_PREPEND(lcfg->channels, channel, link);
774 775 776 777 778 779 780 781 782 783 784 785

	/*
	 * If default_stderr was redefined, make the default category
	 * point to the new default_stderr.
	 */
	if (strcmp(name, "default_stderr") == 0)
		default_channel.channel = channel;

	return (ISC_R_SUCCESS);
}

isc_result_t
786
isc_log_usechannel(isc_logconfig_t *lcfg, const char *name,
David Lawrence's avatar
David Lawrence committed
787 788
		   const isc_logcategory_t *category,
		   const isc_logmodule_t *module)
789
{
790
	isc_log_t *lctx;
791
	isc_logchannel_t *channel;
792
	isc_result_t result = ISC_R_SUCCESS;
793 794
	unsigned int i;

795
	REQUIRE(VALID_CONFIG(lcfg));
796
	REQUIRE(name != NULL);
797 798 799

	lctx = lcfg->lctx;

800 801 802
	REQUIRE(category == NULL || category->id < lctx->category_count);
	REQUIRE(module == NULL || module->id < lctx->module_count);

803 804
	for (channel = ISC_LIST_HEAD(lcfg->channels); channel != NULL;
	     channel = ISC_LIST_NEXT(channel, link))
805 806 807 808 809 810 811
		if (strcmp(name, channel->name) == 0)
			break;

	if (channel == NULL)
		return (ISC_R_NOTFOUND);

	if (category != NULL)
812
		result = assignchannel(lcfg, category->id, module, channel);
813 814 815 816 817 818 819

	else
		/*
		 * Assign to all categories.  Note that this includes
		 * the default channel.
		 */
		for (i = 0; i < lctx->category_count; i++) {
820
			result = assignchannel(lcfg, i, module, channel);
821 822 823 824 825 826 827 828
			if (result != ISC_R_SUCCESS)
				break;
		}

	return (result);
}

void
829 830
isc_log_write(isc_log_t *lctx, isc_logcategory_t *category,
	      isc_logmodule_t *module, int level, const char *format, ...)
831 832 833 834
{
	va_list args;

	/*
835
	 * Contract checking is done in isc_log_doit().
836 837 838
	 */

	va_start(args, format);
839
	isc_log_doit(lctx, category, module, level, ISC_FALSE,
840
		     NULL, 0, 0, format, args);
841 842 843
	va_end(args);
}

844
void
845
isc_log_vwrite(isc_log_t *lctx, isc_logcategory_t *category,
846 847 848 849 850 851
	       isc_logmodule_t *module, int level,
	       const char *format, va_list args)
{
	/*
	 * Contract checking is done in isc_log_doit().
	 */
852
	isc_log_doit(lctx, category, module, level, ISC_FALSE,
853
		     NULL, 0, 0, format, args);
854 855 856
}

void
857 858
isc_log_write1(isc_log_t *lctx, isc_logcategory_t *category,
	       isc_logmodule_t *module, int level, const char *format, ...)
859 860 861 862 863 864 865 866
{
	va_list args;

	/*
	 * Contract checking is done in isc_log_doit().
	 */

	va_start(args, format);
867
	isc_log_doit(lctx, category, module, level, ISC_TRUE,
868
		     NULL, 0, 0, format, args);
869 870 871 872
	va_end(args);
}

void
873
isc_log_vwrite1(isc_log_t *lctx, isc_logcategory_t *category,
874 875 876 877 878 879 880
		isc_logmodule_t *module, int level,
		const char *format, va_list args)
{
	/*
	 * Contract checking is done in isc_log_doit().
	 */
	isc_log_doit(lctx, category, module, level, ISC_TRUE,
881
		     NULL, 0, 0, format, args);
882 883 884
}

void
885 886 887 888
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 890 891 892 893 894 895 896 897
{
	va_list args;

	/*
	 * Contract checking is done in isc_log_doit().
	 */

	va_start(args, format);
	isc_log_doit(lctx, category, module, level, ISC_FALSE,
898
		     msgcat, msgset, msg, format, args);
899 900 901 902
	va_end(args);
}

void
903 904 905 906
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 908 909 910 911
{
	/*
	 * Contract checking is done in isc_log_doit().
	 */
	isc_log_doit(lctx, category, module, level, ISC_FALSE,
912
		     msgcat, msgset, msg, format, args);
913
}
914

915
void
916 917 918 919
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
{
921 922
	va_list args;

923 924 925
	/*
	 * Contract checking is done in isc_log_doit().
	 */
926 927 928

	va_start(args, format);
	isc_log_doit(lctx, category, module, level, ISC_TRUE,