2 * Copyright (C) 2004-2007, 2011 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-2001 Internet Software Consortium.
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.
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.42.816.3 2011/03/05 23:52:06 tbox Exp $ */
25 #include <isc/offset.h>
26 #include <isc/result.h>
27 #include <isc/stdio.h>
28 #include <isc/string.h>
29 #include <isc/syslog.h>
31 #include <isccfg/cfg.h>
32 #include <isccfg/log.h>
34 #include <named/log.h>
35 #include <named/logconf.h>
39 if (result != ISC_R_SUCCESS) goto cleanup; \
43 * Set up a logging category according to the named.conf data
44 * in 'ccat' and add it to 'lctx'.
47 category_fromconf(const cfg_obj_t *ccat, isc_logconfig_t *lctx) {
50 isc_logcategory_t *category;
51 isc_logmodule_t *module;
52 const cfg_obj_t *destinations = NULL;
53 const cfg_listelt_t *element = NULL;
55 catname = cfg_obj_asstring(cfg_tuple_get(ccat, "name"));
56 category = isc_log_categorybyname(ns_g_lctx, catname);
57 if (category == NULL) {
58 cfg_obj_log(ccat, ns_g_lctx, ISC_LOG_ERROR,
59 "unknown logging category '%s' ignored",
62 * Allow further processing by returning success.
64 return (ISC_R_SUCCESS);
69 destinations = cfg_tuple_get(ccat, "destinations");
70 for (element = cfg_list_first(destinations);
72 element = cfg_list_next(element))
74 const cfg_obj_t *channel = cfg_listelt_value(element);
75 const char *channelname = cfg_obj_asstring(channel);
77 result = isc_log_usechannel(lctx, channelname, category,
79 if (result != ISC_R_SUCCESS) {
80 isc_log_write(ns_g_lctx, CFG_LOGCATEGORY_CONFIG,
81 NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
82 "logging channel '%s': %s", channelname,
83 isc_result_totext(result));
87 return (ISC_R_SUCCESS);
91 * Set up a logging channel according to the named.conf data
92 * in 'cchan' and add it to 'lctx'.
95 channel_fromconf(const cfg_obj_t *channel, isc_logconfig_t *lctx) {
97 isc_logdestination_t dest;
99 unsigned int flags = 0;
101 const char *channelname;
102 const cfg_obj_t *fileobj = NULL;
103 const cfg_obj_t *syslogobj = NULL;
104 const cfg_obj_t *nullobj = NULL;
105 const cfg_obj_t *stderrobj = NULL;
106 const cfg_obj_t *severity = NULL;
109 channelname = cfg_obj_asstring(cfg_map_getname(channel));
111 (void)cfg_map_get(channel, "file", &fileobj);
112 (void)cfg_map_get(channel, "syslog", &syslogobj);
113 (void)cfg_map_get(channel, "null", &nullobj);
114 (void)cfg_map_get(channel, "stderr", &stderrobj);
119 if (syslogobj != NULL)
123 if (stderrobj != NULL)
127 cfg_obj_log(channel, ns_g_lctx, ISC_LOG_ERROR,
128 "channel '%s': exactly one of file, syslog, "
129 "null, and stderr must be present", channelname);
130 return (ISC_R_FAILURE);
133 type = ISC_LOG_TONULL;
135 if (fileobj != NULL) {
136 const cfg_obj_t *pathobj = cfg_tuple_get(fileobj, "file");
137 const cfg_obj_t *sizeobj = cfg_tuple_get(fileobj, "size");
138 const cfg_obj_t *versionsobj =
139 cfg_tuple_get(fileobj, "versions");
140 isc_int32_t versions = ISC_LOG_ROLLNEVER;
141 isc_offset_t size = 0;
143 type = ISC_LOG_TOFILE;
145 if (versionsobj != NULL && cfg_obj_isuint32(versionsobj))
146 versions = cfg_obj_asuint32(versionsobj);
147 if (versionsobj != NULL && cfg_obj_isstring(versionsobj) &&
148 strcasecmp(cfg_obj_asstring(versionsobj), "unlimited") == 0)
149 versions = ISC_LOG_ROLLINFINITE;
150 if (sizeobj != NULL &&
151 cfg_obj_isuint64(sizeobj) &&
152 cfg_obj_asuint64(sizeobj) < ISC_OFFSET_MAXIMUM)
153 size = (isc_offset_t)cfg_obj_asuint64(sizeobj);
154 dest.file.stream = NULL;
155 dest.file.name = cfg_obj_asstring(pathobj);
156 dest.file.versions = versions;
157 dest.file.maximum_size = size;
158 } else if (syslogobj != NULL) {
159 int facility = LOG_DAEMON;
161 type = ISC_LOG_TOSYSLOG;
163 if (cfg_obj_isstring(syslogobj)) {
164 const char *facilitystr = cfg_obj_asstring(syslogobj);
165 (void)isc_syslog_facilityfromstring(facilitystr,
168 dest.facility = facility;
169 } else if (stderrobj != NULL) {
170 type = ISC_LOG_TOFILEDESC;
171 dest.file.stream = stderr;
172 dest.file.name = NULL;
173 dest.file.versions = ISC_LOG_ROLLNEVER;
174 dest.file.maximum_size = 0;
181 const cfg_obj_t *printcat = NULL;
182 const cfg_obj_t *printsev = NULL;
183 const cfg_obj_t *printtime = NULL;
185 (void)cfg_map_get(channel, "print-category", &printcat);
186 (void)cfg_map_get(channel, "print-severity", &printsev);
187 (void)cfg_map_get(channel, "print-time", &printtime);
189 if (printcat != NULL && cfg_obj_asboolean(printcat))
190 flags |= ISC_LOG_PRINTCATEGORY;
191 if (printtime != NULL && cfg_obj_asboolean(printtime))
192 flags |= ISC_LOG_PRINTTIME;
193 if (printsev != NULL && cfg_obj_asboolean(printsev))
194 flags |= ISC_LOG_PRINTLEVEL;
197 level = ISC_LOG_INFO;
198 if (cfg_map_get(channel, "severity", &severity) == ISC_R_SUCCESS) {
199 if (cfg_obj_isstring(severity)) {
200 const char *str = cfg_obj_asstring(severity);
201 if (strcasecmp(str, "critical") == 0)
202 level = ISC_LOG_CRITICAL;
203 else if (strcasecmp(str, "error") == 0)
204 level = ISC_LOG_ERROR;
205 else if (strcasecmp(str, "warning") == 0)
206 level = ISC_LOG_WARNING;
207 else if (strcasecmp(str, "notice") == 0)
208 level = ISC_LOG_NOTICE;
209 else if (strcasecmp(str, "info") == 0)
210 level = ISC_LOG_INFO;
211 else if (strcasecmp(str, "dynamic") == 0)
212 level = ISC_LOG_DYNAMIC;
215 level = cfg_obj_asuint32(severity);
218 result = isc_log_createchannel(lctx, channelname,
219 type, level, &dest, flags);
221 if (result == ISC_R_SUCCESS && type == ISC_LOG_TOFILE) {
225 * Test to make sure that file is a plain file.
228 result = isc_file_isplainfile(dest.file.name);
229 if (result == ISC_R_SUCCESS ||
230 result == ISC_R_FILENOTFOUND) {
232 * Test that the file can be opened, since
233 * isc_log_open() can't effectively report
234 * failures when called in
237 result = isc_stdio_open(dest.file.name, "a", &fp);
238 if (result != ISC_R_SUCCESS) {
240 "isc_stdio_open '%s' failed: %s",
242 isc_result_totext(result));
244 "isc_stdio_open '%s' failed: %s",
246 isc_result_totext(result));
248 (void)isc_stdio_close(fp);
250 syslog(LOG_ERR, "isc_file_isplainfile '%s' failed: %s",
251 dest.file.name, isc_result_totext(result));
252 fprintf(stderr, "isc_file_isplainfile '%s' failed: %s",
253 dest.file.name, isc_result_totext(result));
261 ns_log_configure(isc_logconfig_t *logconf, const cfg_obj_t *logstmt) {
263 const cfg_obj_t *channels = NULL;
264 const cfg_obj_t *categories = NULL;
265 const cfg_listelt_t *element;
266 isc_boolean_t default_set = ISC_FALSE;
267 isc_boolean_t unmatched_set = ISC_FALSE;
268 const cfg_obj_t *catname;
270 CHECK(ns_log_setdefaultchannels(logconf));
272 (void)cfg_map_get(logstmt, "channel", &channels);
273 for (element = cfg_list_first(channels);
275 element = cfg_list_next(element))
277 const cfg_obj_t *channel = cfg_listelt_value(element);
278 CHECK(channel_fromconf(channel, logconf));
281 (void)cfg_map_get(logstmt, "category", &categories);
282 for (element = cfg_list_first(categories);
284 element = cfg_list_next(element))
286 const cfg_obj_t *category = cfg_listelt_value(element);
287 CHECK(category_fromconf(category, logconf));
289 catname = cfg_tuple_get(category, "name");
290 if (strcmp(cfg_obj_asstring(catname), "default") == 0)
291 default_set = ISC_TRUE;
293 if (!unmatched_set) {
294 catname = cfg_tuple_get(category, "name");
295 if (strcmp(cfg_obj_asstring(catname), "unmatched") == 0)
296 unmatched_set = ISC_TRUE;
301 CHECK(ns_log_setdefaultcategory(logconf));
304 CHECK(ns_log_setunmatchedcategory(logconf));
306 return (ISC_R_SUCCESS);
310 isc_logconfig_destroy(&logconf);