File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / ntp / lib / isc / log.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue May 29 12:08:38 2012 UTC (12 years, 7 months ago) by misho
Branches: ntp, MAIN
CVS tags: v4_2_6p5p0, v4_2_6p5, HEAD
ntp 4.2.6p5

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>