Annotation of embedaddon/ntp/lib/isc/log.c, revision 1.1

1.1     ! misho       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.94.332.5 2009/02/16 02:04:05 marka 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>