2 * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-2001 Internet Software Consortium.
5 * Permission to use, copy, modify, and 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.
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.
18 /* $Id: logconf.c,v 1.30.2.3.10.2 2004/03/06 10:21:18 marka Exp $ */
22 #include <isc/offset.h>
23 #include <isc/result.h>
24 #include <isc/stdio.h>
25 #include <isc/string.h>
26 #include <isc/syslog.h>
28 #include <isccfg/cfg.h>
29 #include <isccfg/log.h>
31 #include <named/log.h>
32 #include <named/logconf.h>
36 if (result != ISC_R_SUCCESS) goto cleanup; \
40 * Set up a logging category according to the named.conf data
41 * in 'ccat' and add it to 'lctx'.
44 category_fromconf(cfg_obj_t *ccat, isc_logconfig_t *lctx) {
47 isc_logcategory_t *category;
48 isc_logmodule_t *module;
49 cfg_obj_t *destinations = NULL;
50 cfg_listelt_t *element = NULL;
52 catname = cfg_obj_asstring(cfg_tuple_get(ccat, "name"));
53 category = isc_log_categorybyname(ns_g_lctx, catname);
54 if (category == NULL) {
55 cfg_obj_log(ccat, ns_g_lctx, ISC_LOG_ERROR,
56 "unknown logging category '%s' ignored",
59 * Allow further processing by returning success.
61 return (ISC_R_SUCCESS);
66 destinations = cfg_tuple_get(ccat, "destinations");
67 for (element = cfg_list_first(destinations);
69 element = cfg_list_next(element))
71 cfg_obj_t *channel = cfg_listelt_value(element);
72 char *channelname = cfg_obj_asstring(channel);
74 result = isc_log_usechannel(lctx, channelname, category,
76 if (result != ISC_R_SUCCESS) {
77 isc_log_write(ns_g_lctx, CFG_LOGCATEGORY_CONFIG,
78 NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
79 "logging channel '%s': %s", channelname,
80 isc_result_totext(result));
84 return (ISC_R_SUCCESS);
88 * Set up a logging channel according to the named.conf data
89 * in 'cchan' and add it to 'lctx'.
92 channel_fromconf(cfg_obj_t *channel, isc_logconfig_t *lctx) {
94 isc_logdestination_t dest;
96 unsigned int flags = 0;
98 const char *channelname;
99 cfg_obj_t *fileobj = NULL;
100 cfg_obj_t *syslogobj = NULL;
101 cfg_obj_t *nullobj = NULL;
102 cfg_obj_t *stderrobj = NULL;
103 cfg_obj_t *severity = NULL;
106 channelname = cfg_obj_asstring(cfg_map_getname(channel));
108 (void)cfg_map_get(channel, "file", &fileobj);
109 (void)cfg_map_get(channel, "syslog", &syslogobj);
110 (void)cfg_map_get(channel, "null", &nullobj);
111 (void)cfg_map_get(channel, "stderr", &stderrobj);
116 if (syslogobj != NULL)
120 if (stderrobj != NULL)
124 cfg_obj_log(channel, ns_g_lctx, ISC_LOG_ERROR,
125 "channel '%s': exactly one of file, syslog, "
126 "null, and stderr must be present", channelname);
127 return (ISC_R_FAILURE);
130 type = ISC_LOG_TONULL;
132 if (fileobj != NULL) {
133 cfg_obj_t *pathobj = cfg_tuple_get(fileobj, "file");
134 cfg_obj_t *sizeobj = cfg_tuple_get(fileobj, "size");
135 cfg_obj_t *versionsobj = cfg_tuple_get(fileobj, "versions");
136 isc_int32_t versions = ISC_LOG_ROLLNEVER;
137 isc_offset_t size = 0;
139 type = ISC_LOG_TOFILE;
141 if (versionsobj != NULL && cfg_obj_isuint32(versionsobj))
142 versions = cfg_obj_asuint32(versionsobj);
143 if (versionsobj != NULL && cfg_obj_isstring(versionsobj) &&
144 strcasecmp(cfg_obj_asstring(versionsobj), "unlimited") == 0)
145 versions = ISC_LOG_ROLLINFINITE;
146 if (sizeobj != NULL &&
147 cfg_obj_isuint64(sizeobj) &&
148 cfg_obj_asuint64(sizeobj) < ISC_OFFSET_MAXIMUM)
149 size = (isc_offset_t)cfg_obj_asuint64(sizeobj);
150 dest.file.stream = NULL;
151 dest.file.name = cfg_obj_asstring(pathobj);
152 dest.file.versions = versions;
153 dest.file.maximum_size = size;
154 } else if (syslogobj != NULL) {
155 int facility = LOG_DAEMON;
157 type = ISC_LOG_TOSYSLOG;
159 if (cfg_obj_isstring(syslogobj)) {
160 char *facilitystr = cfg_obj_asstring(syslogobj);
161 (void)isc_syslog_facilityfromstring(facilitystr,
164 dest.facility = facility;
165 } else if (stderrobj != NULL) {
166 type = ISC_LOG_TOFILEDESC;
167 dest.file.stream = stderr;
168 dest.file.name = NULL;
169 dest.file.versions = ISC_LOG_ROLLNEVER;
170 dest.file.maximum_size = 0;
177 cfg_obj_t *printcat = NULL;
178 cfg_obj_t *printsev = NULL;
179 cfg_obj_t *printtime = NULL;
181 (void)cfg_map_get(channel, "print-category", &printcat);
182 (void)cfg_map_get(channel, "print-severity", &printsev);
183 (void)cfg_map_get(channel, "print-time", &printtime);
185 if (printcat != NULL && cfg_obj_asboolean(printcat))
186 flags |= ISC_LOG_PRINTCATEGORY;
187 if (printtime != NULL && cfg_obj_asboolean(printtime))
188 flags |= ISC_LOG_PRINTTIME;
189 if (printsev != NULL && cfg_obj_asboolean(printsev))
190 flags |= ISC_LOG_PRINTLEVEL;
193 level = ISC_LOG_INFO;
194 if (cfg_map_get(channel, "severity", &severity) == ISC_R_SUCCESS) {
195 if (cfg_obj_isstring(severity)) {
196 char *str = cfg_obj_asstring(severity);
197 if (strcasecmp(str, "critical") == 0)
198 level = ISC_LOG_CRITICAL;
199 else if (strcasecmp(str, "error") == 0)
200 level = ISC_LOG_ERROR;
201 else if (strcasecmp(str, "warning") == 0)
202 level = ISC_LOG_WARNING;
203 else if (strcasecmp(str, "notice") == 0)
204 level = ISC_LOG_NOTICE;
205 else if (strcasecmp(str, "info") == 0)
206 level = ISC_LOG_INFO;
207 else if (strcasecmp(str, "dynamic") == 0)
208 level = ISC_LOG_DYNAMIC;
211 level = cfg_obj_asuint32(severity);
214 result = isc_log_createchannel(lctx, channelname,
215 type, level, &dest, flags);
217 if (result == ISC_R_SUCCESS && type == ISC_LOG_TOFILE) {
221 * Test that the file can be opened, since isc_log_open()
222 * can't effectively report failures when called in
225 result = isc_stdio_open(dest.file.name, "a", &fp);
226 if (result != ISC_R_SUCCESS)
227 isc_log_write(ns_g_lctx, CFG_LOGCATEGORY_CONFIG,
228 NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
229 "logging channel '%s' file '%s': %s",
230 channelname, dest.file.name,
231 isc_result_totext(result));
233 (void)isc_stdio_close(fp);
236 * Allow named to continue by returning success.
238 result = ISC_R_SUCCESS;
245 ns_log_configure(isc_logconfig_t *logconf, cfg_obj_t *logstmt) {
247 cfg_obj_t *channels = NULL;
248 cfg_obj_t *categories = NULL;
249 cfg_listelt_t *element;
250 isc_boolean_t default_set = ISC_FALSE;
251 isc_boolean_t unmatched_set = ISC_FALSE;
253 CHECK(ns_log_setdefaultchannels(logconf));
255 (void)cfg_map_get(logstmt, "channel", &channels);
256 for (element = cfg_list_first(channels);
258 element = cfg_list_next(element))
260 cfg_obj_t *channel = cfg_listelt_value(element);
261 CHECK(channel_fromconf(channel, logconf));
264 (void)cfg_map_get(logstmt, "category", &categories);
265 for (element = cfg_list_first(categories);
267 element = cfg_list_next(element))
269 cfg_obj_t *category = cfg_listelt_value(element);
270 CHECK(category_fromconf(category, logconf));
272 cfg_obj_t *catname = cfg_tuple_get(category, "name");
273 if (strcmp(cfg_obj_asstring(catname), "default") == 0)
274 default_set = ISC_TRUE;
276 if (!unmatched_set) {
277 cfg_obj_t *catname = cfg_tuple_get(category, "name");
278 if (strcmp(cfg_obj_asstring(catname), "unmatched") == 0)
279 unmatched_set = ISC_TRUE;
284 CHECK(ns_log_setdefaultcategory(logconf));
287 CHECK(ns_log_setunmatchedcategory(logconf));
289 return (ISC_R_SUCCESS);
293 isc_logconfig_destroy(&logconf);