summaryrefslogtreecommitdiffstats
path: root/bin/named/logconf.c
diff options
context:
space:
mode:
Diffstat (limited to 'bin/named/logconf.c')
-rw-r--r--bin/named/logconf.c299
1 files changed, 299 insertions, 0 deletions
diff --git a/bin/named/logconf.c b/bin/named/logconf.c
new file mode 100644
index 0000000..e324965
--- /dev/null
+++ b/bin/named/logconf.c
@@ -0,0 +1,299 @@
+/*
+ * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2001 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: logconf.c,v 1.42 2007/06/19 23:46:59 tbox Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/offset.h>
+#include <isc/result.h>
+#include <isc/stdio.h>
+#include <isc/string.h>
+#include <isc/syslog.h>
+
+#include <isccfg/cfg.h>
+#include <isccfg/log.h>
+
+#include <named/log.h>
+#include <named/logconf.h>
+
+#define CHECK(op) \
+ do { result = (op); \
+ if (result != ISC_R_SUCCESS) goto cleanup; \
+ } while (0)
+
+/*%
+ * Set up a logging category according to the named.conf data
+ * in 'ccat' and add it to 'lctx'.
+ */
+static isc_result_t
+category_fromconf(const cfg_obj_t *ccat, isc_logconfig_t *lctx) {
+ isc_result_t result;
+ const char *catname;
+ isc_logcategory_t *category;
+ isc_logmodule_t *module;
+ const cfg_obj_t *destinations = NULL;
+ const cfg_listelt_t *element = NULL;
+
+ catname = cfg_obj_asstring(cfg_tuple_get(ccat, "name"));
+ category = isc_log_categorybyname(ns_g_lctx, catname);
+ if (category == NULL) {
+ cfg_obj_log(ccat, ns_g_lctx, ISC_LOG_ERROR,
+ "unknown logging category '%s' ignored",
+ catname);
+ /*
+ * Allow further processing by returning success.
+ */
+ return (ISC_R_SUCCESS);
+ }
+
+ module = NULL;
+
+ destinations = cfg_tuple_get(ccat, "destinations");
+ for (element = cfg_list_first(destinations);
+ element != NULL;
+ element = cfg_list_next(element))
+ {
+ const cfg_obj_t *channel = cfg_listelt_value(element);
+ const char *channelname = cfg_obj_asstring(channel);
+
+ result = isc_log_usechannel(lctx, channelname, category,
+ module);
+ if (result != ISC_R_SUCCESS) {
+ isc_log_write(ns_g_lctx, CFG_LOGCATEGORY_CONFIG,
+ NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
+ "logging channel '%s': %s", channelname,
+ isc_result_totext(result));
+ return (result);
+ }
+ }
+ return (ISC_R_SUCCESS);
+}
+
+/*%
+ * Set up a logging channel according to the named.conf data
+ * in 'cchan' and add it to 'lctx'.
+ */
+static isc_result_t
+channel_fromconf(const cfg_obj_t *channel, isc_logconfig_t *lctx) {
+ isc_result_t result;
+ isc_logdestination_t dest;
+ unsigned int type;
+ unsigned int flags = 0;
+ int level;
+ const char *channelname;
+ const cfg_obj_t *fileobj = NULL;
+ const cfg_obj_t *syslogobj = NULL;
+ const cfg_obj_t *nullobj = NULL;
+ const cfg_obj_t *stderrobj = NULL;
+ const cfg_obj_t *severity = NULL;
+ int i;
+
+ channelname = cfg_obj_asstring(cfg_map_getname(channel));
+
+ (void)cfg_map_get(channel, "file", &fileobj);
+ (void)cfg_map_get(channel, "syslog", &syslogobj);
+ (void)cfg_map_get(channel, "null", &nullobj);
+ (void)cfg_map_get(channel, "stderr", &stderrobj);
+
+ i = 0;
+ if (fileobj != NULL)
+ i++;
+ if (syslogobj != NULL)
+ i++;
+ if (nullobj != NULL)
+ i++;
+ if (stderrobj != NULL)
+ i++;
+
+ if (i != 1) {
+ cfg_obj_log(channel, ns_g_lctx, ISC_LOG_ERROR,
+ "channel '%s': exactly one of file, syslog, "
+ "null, and stderr must be present", channelname);
+ return (ISC_R_FAILURE);
+ }
+
+ type = ISC_LOG_TONULL;
+
+ if (fileobj != NULL) {
+ const cfg_obj_t *pathobj = cfg_tuple_get(fileobj, "file");
+ const cfg_obj_t *sizeobj = cfg_tuple_get(fileobj, "size");
+ const cfg_obj_t *versionsobj =
+ cfg_tuple_get(fileobj, "versions");
+ isc_int32_t versions = ISC_LOG_ROLLNEVER;
+ isc_offset_t size = 0;
+
+ type = ISC_LOG_TOFILE;
+
+ if (versionsobj != NULL && cfg_obj_isuint32(versionsobj))
+ versions = cfg_obj_asuint32(versionsobj);
+ if (versionsobj != NULL && cfg_obj_isstring(versionsobj) &&
+ strcasecmp(cfg_obj_asstring(versionsobj), "unlimited") == 0)
+ versions = ISC_LOG_ROLLINFINITE;
+ if (sizeobj != NULL &&
+ cfg_obj_isuint64(sizeobj) &&
+ cfg_obj_asuint64(sizeobj) < ISC_OFFSET_MAXIMUM)
+ size = (isc_offset_t)cfg_obj_asuint64(sizeobj);
+ dest.file.stream = NULL;
+ dest.file.name = cfg_obj_asstring(pathobj);
+ dest.file.versions = versions;
+ dest.file.maximum_size = size;
+ } else if (syslogobj != NULL) {
+ int facility = LOG_DAEMON;
+
+ type = ISC_LOG_TOSYSLOG;
+
+ if (cfg_obj_isstring(syslogobj)) {
+ const char *facilitystr = cfg_obj_asstring(syslogobj);
+ (void)isc_syslog_facilityfromstring(facilitystr,
+ &facility);
+ }
+ dest.facility = facility;
+ } else if (stderrobj != NULL) {
+ type = ISC_LOG_TOFILEDESC;
+ dest.file.stream = stderr;
+ dest.file.name = NULL;
+ dest.file.versions = ISC_LOG_ROLLNEVER;
+ dest.file.maximum_size = 0;
+ }
+
+ /*
+ * Munge flags.
+ */
+ {
+ const cfg_obj_t *printcat = NULL;
+ const cfg_obj_t *printsev = NULL;
+ const cfg_obj_t *printtime = NULL;
+
+ (void)cfg_map_get(channel, "print-category", &printcat);
+ (void)cfg_map_get(channel, "print-severity", &printsev);
+ (void)cfg_map_get(channel, "print-time", &printtime);
+
+ if (printcat != NULL && cfg_obj_asboolean(printcat))
+ flags |= ISC_LOG_PRINTCATEGORY;
+ if (printtime != NULL && cfg_obj_asboolean(printtime))
+ flags |= ISC_LOG_PRINTTIME;
+ if (printsev != NULL && cfg_obj_asboolean(printsev))
+ flags |= ISC_LOG_PRINTLEVEL;
+ }
+
+ level = ISC_LOG_INFO;
+ if (cfg_map_get(channel, "severity", &severity) == ISC_R_SUCCESS) {
+ if (cfg_obj_isstring(severity)) {
+ const char *str = cfg_obj_asstring(severity);
+ if (strcasecmp(str, "critical") == 0)
+ level = ISC_LOG_CRITICAL;
+ else if (strcasecmp(str, "error") == 0)
+ level = ISC_LOG_ERROR;
+ else if (strcasecmp(str, "warning") == 0)
+ level = ISC_LOG_WARNING;
+ else if (strcasecmp(str, "notice") == 0)
+ level = ISC_LOG_NOTICE;
+ else if (strcasecmp(str, "info") == 0)
+ level = ISC_LOG_INFO;
+ else if (strcasecmp(str, "dynamic") == 0)
+ level = ISC_LOG_DYNAMIC;
+ } else
+ /* debug */
+ level = cfg_obj_asuint32(severity);
+ }
+
+ result = isc_log_createchannel(lctx, channelname,
+ type, level, &dest, flags);
+
+ if (result == ISC_R_SUCCESS && type == ISC_LOG_TOFILE) {
+ FILE *fp;
+
+ /*
+ * Test that the file can be opened, since isc_log_open()
+ * can't effectively report failures when called in
+ * isc_log_doit().
+ */
+ result = isc_stdio_open(dest.file.name, "a", &fp);
+ if (result != ISC_R_SUCCESS)
+ isc_log_write(ns_g_lctx, CFG_LOGCATEGORY_CONFIG,
+ NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
+ "logging channel '%s' file '%s': %s",
+ channelname, dest.file.name,
+ isc_result_totext(result));
+ else
+ (void)isc_stdio_close(fp);
+
+ /*
+ * Allow named to continue by returning success.
+ */
+ result = ISC_R_SUCCESS;
+ }
+
+ return (result);
+}
+
+isc_result_t
+ns_log_configure(isc_logconfig_t *logconf, const cfg_obj_t *logstmt) {
+ isc_result_t result;
+ const cfg_obj_t *channels = NULL;
+ const cfg_obj_t *categories = NULL;
+ const cfg_listelt_t *element;
+ isc_boolean_t default_set = ISC_FALSE;
+ isc_boolean_t unmatched_set = ISC_FALSE;
+ const cfg_obj_t *catname;
+
+ CHECK(ns_log_setdefaultchannels(logconf));
+
+ (void)cfg_map_get(logstmt, "channel", &channels);
+ for (element = cfg_list_first(channels);
+ element != NULL;
+ element = cfg_list_next(element))
+ {
+ const cfg_obj_t *channel = cfg_listelt_value(element);
+ CHECK(channel_fromconf(channel, logconf));
+ }
+
+ (void)cfg_map_get(logstmt, "category", &categories);
+ for (element = cfg_list_first(categories);
+ element != NULL;
+ element = cfg_list_next(element))
+ {
+ const cfg_obj_t *category = cfg_listelt_value(element);
+ CHECK(category_fromconf(category, logconf));
+ if (!default_set) {
+ catname = cfg_tuple_get(category, "name");
+ if (strcmp(cfg_obj_asstring(catname), "default") == 0)
+ default_set = ISC_TRUE;
+ }
+ if (!unmatched_set) {
+ catname = cfg_tuple_get(category, "name");
+ if (strcmp(cfg_obj_asstring(catname), "unmatched") == 0)
+ unmatched_set = ISC_TRUE;
+ }
+ }
+
+ if (!default_set)
+ CHECK(ns_log_setdefaultcategory(logconf));
+
+ if (!unmatched_set)
+ CHECK(ns_log_setunmatchedcategory(logconf));
+
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ if (logconf != NULL)
+ isc_logconfig_destroy(&logconf);
+ return (result);
+}