2 * Copyright (C) 2004-2006 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.35.18.5 2006/03/02 00:37:21 marka Exp $ */
24 #include <isc/offset.h>
25 #include <isc/result.h>
26 #include <isc/stdio.h>
27 #include <isc/string.h>
28 #include <isc/syslog.h>
30 #include <isccfg/cfg.h>
31 #include <isccfg/log.h>
33 #include <named/log.h>
34 #include <named/logconf.h>
38 if (result != ISC_R_SUCCESS) goto cleanup; \
42 * Set up a logging category according to the named.conf data
43 * in 'ccat' and add it to 'lctx'.
46 category_fromconf(const cfg_obj_t
*ccat
, isc_logconfig_t
*lctx
) {
49 isc_logcategory_t
*category
;
50 isc_logmodule_t
*module
;
51 const cfg_obj_t
*destinations
= NULL
;
52 const cfg_listelt_t
*element
= NULL
;
54 catname
= cfg_obj_asstring(cfg_tuple_get(ccat
, "name"));
55 category
= isc_log_categorybyname(ns_g_lctx
, catname
);
56 if (category
== NULL
) {
57 cfg_obj_log(ccat
, ns_g_lctx
, ISC_LOG_ERROR
,
58 "unknown logging category '%s' ignored",
61 * Allow further processing by returning success.
63 return (ISC_R_SUCCESS
);
68 destinations
= cfg_tuple_get(ccat
, "destinations");
69 for (element
= cfg_list_first(destinations
);
71 element
= cfg_list_next(element
))
73 const cfg_obj_t
*channel
= cfg_listelt_value(element
);
74 const char *channelname
= cfg_obj_asstring(channel
);
76 result
= isc_log_usechannel(lctx
, channelname
, category
,
78 if (result
!= ISC_R_SUCCESS
) {
79 isc_log_write(ns_g_lctx
, CFG_LOGCATEGORY_CONFIG
,
80 NS_LOGMODULE_SERVER
, ISC_LOG_ERROR
,
81 "logging channel '%s': %s", channelname
,
82 isc_result_totext(result
));
86 return (ISC_R_SUCCESS
);
90 * Set up a logging channel according to the named.conf data
91 * in 'cchan' and add it to 'lctx'.
94 channel_fromconf(const cfg_obj_t
*channel
, isc_logconfig_t
*lctx
) {
96 isc_logdestination_t dest
;
98 unsigned int flags
= 0;
100 const char *channelname
;
101 const cfg_obj_t
*fileobj
= NULL
;
102 const cfg_obj_t
*syslogobj
= NULL
;
103 const cfg_obj_t
*nullobj
= NULL
;
104 const cfg_obj_t
*stderrobj
= NULL
;
105 const cfg_obj_t
*severity
= NULL
;
108 channelname
= cfg_obj_asstring(cfg_map_getname(channel
));
110 (void)cfg_map_get(channel
, "file", &fileobj
);
111 (void)cfg_map_get(channel
, "syslog", &syslogobj
);
112 (void)cfg_map_get(channel
, "null", &nullobj
);
113 (void)cfg_map_get(channel
, "stderr", &stderrobj
);
118 if (syslogobj
!= NULL
)
122 if (stderrobj
!= NULL
)
126 cfg_obj_log(channel
, ns_g_lctx
, ISC_LOG_ERROR
,
127 "channel '%s': exactly one of file, syslog, "
128 "null, and stderr must be present", channelname
);
129 return (ISC_R_FAILURE
);
132 type
= ISC_LOG_TONULL
;
134 if (fileobj
!= NULL
) {
135 const cfg_obj_t
*pathobj
= cfg_tuple_get(fileobj
, "file");
136 const cfg_obj_t
*sizeobj
= cfg_tuple_get(fileobj
, "size");
137 const cfg_obj_t
*versionsobj
=
138 cfg_tuple_get(fileobj
, "versions");
139 isc_int32_t versions
= ISC_LOG_ROLLNEVER
;
140 isc_offset_t size
= 0;
142 type
= ISC_LOG_TOFILE
;
144 if (versionsobj
!= NULL
&& cfg_obj_isuint32(versionsobj
))
145 versions
= cfg_obj_asuint32(versionsobj
);
146 if (versionsobj
!= NULL
&& cfg_obj_isstring(versionsobj
) &&
147 strcasecmp(cfg_obj_asstring(versionsobj
), "unlimited") == 0)
148 versions
= ISC_LOG_ROLLINFINITE
;
149 if (sizeobj
!= NULL
&&
150 cfg_obj_isuint64(sizeobj
) &&
151 cfg_obj_asuint64(sizeobj
) < ISC_OFFSET_MAXIMUM
)
152 size
= (isc_offset_t
)cfg_obj_asuint64(sizeobj
);
153 dest
.file
.stream
= NULL
;
154 dest
.file
.name
= cfg_obj_asstring(pathobj
);
155 dest
.file
.versions
= versions
;
156 dest
.file
.maximum_size
= size
;
157 } else if (syslogobj
!= NULL
) {
158 int facility
= LOG_DAEMON
;
160 type
= ISC_LOG_TOSYSLOG
;
162 if (cfg_obj_isstring(syslogobj
)) {
163 const char *facilitystr
= cfg_obj_asstring(syslogobj
);
164 (void)isc_syslog_facilityfromstring(facilitystr
,
167 dest
.facility
= facility
;
168 } else if (stderrobj
!= NULL
) {
169 type
= ISC_LOG_TOFILEDESC
;
170 dest
.file
.stream
= stderr
;
171 dest
.file
.name
= NULL
;
172 dest
.file
.versions
= ISC_LOG_ROLLNEVER
;
173 dest
.file
.maximum_size
= 0;
180 const cfg_obj_t
*printcat
= NULL
;
181 const cfg_obj_t
*printsev
= NULL
;
182 const cfg_obj_t
*printtime
= NULL
;
184 (void)cfg_map_get(channel
, "print-category", &printcat
);
185 (void)cfg_map_get(channel
, "print-severity", &printsev
);
186 (void)cfg_map_get(channel
, "print-time", &printtime
);
188 if (printcat
!= NULL
&& cfg_obj_asboolean(printcat
))
189 flags
|= ISC_LOG_PRINTCATEGORY
;
190 if (printtime
!= NULL
&& cfg_obj_asboolean(printtime
))
191 flags
|= ISC_LOG_PRINTTIME
;
192 if (printsev
!= NULL
&& cfg_obj_asboolean(printsev
))
193 flags
|= ISC_LOG_PRINTLEVEL
;
196 level
= ISC_LOG_INFO
;
197 if (cfg_map_get(channel
, "severity", &severity
) == ISC_R_SUCCESS
) {
198 if (cfg_obj_isstring(severity
)) {
199 const char *str
= cfg_obj_asstring(severity
);
200 if (strcasecmp(str
, "critical") == 0)
201 level
= ISC_LOG_CRITICAL
;
202 else if (strcasecmp(str
, "error") == 0)
203 level
= ISC_LOG_ERROR
;
204 else if (strcasecmp(str
, "warning") == 0)
205 level
= ISC_LOG_WARNING
;
206 else if (strcasecmp(str
, "notice") == 0)
207 level
= ISC_LOG_NOTICE
;
208 else if (strcasecmp(str
, "info") == 0)
209 level
= ISC_LOG_INFO
;
210 else if (strcasecmp(str
, "dynamic") == 0)
211 level
= ISC_LOG_DYNAMIC
;
214 level
= cfg_obj_asuint32(severity
);
217 result
= isc_log_createchannel(lctx
, channelname
,
218 type
, level
, &dest
, flags
);
220 if (result
== ISC_R_SUCCESS
&& type
== ISC_LOG_TOFILE
) {
224 * Test that the file can be opened, since isc_log_open()
225 * can't effectively report failures when called in
228 result
= isc_stdio_open(dest
.file
.name
, "a", &fp
);
229 if (result
!= ISC_R_SUCCESS
)
230 isc_log_write(ns_g_lctx
, CFG_LOGCATEGORY_CONFIG
,
231 NS_LOGMODULE_SERVER
, ISC_LOG_ERROR
,
232 "logging channel '%s' file '%s': %s",
233 channelname
, dest
.file
.name
,
234 isc_result_totext(result
));
236 (void)isc_stdio_close(fp
);
239 * Allow named to continue by returning success.
241 result
= ISC_R_SUCCESS
;
248 ns_log_configure(isc_logconfig_t
*logconf
, const cfg_obj_t
*logstmt
) {
250 const cfg_obj_t
*channels
= NULL
;
251 const cfg_obj_t
*categories
= NULL
;
252 const cfg_listelt_t
*element
;
253 isc_boolean_t default_set
= ISC_FALSE
;
254 isc_boolean_t unmatched_set
= ISC_FALSE
;
255 const cfg_obj_t
*catname
;
257 CHECK(ns_log_setdefaultchannels(logconf
));
259 (void)cfg_map_get(logstmt
, "channel", &channels
);
260 for (element
= cfg_list_first(channels
);
262 element
= cfg_list_next(element
))
264 const cfg_obj_t
*channel
= cfg_listelt_value(element
);
265 CHECK(channel_fromconf(channel
, logconf
));
268 (void)cfg_map_get(logstmt
, "category", &categories
);
269 for (element
= cfg_list_first(categories
);
271 element
= cfg_list_next(element
))
273 const cfg_obj_t
*category
= cfg_listelt_value(element
);
274 CHECK(category_fromconf(category
, logconf
));
276 catname
= cfg_tuple_get(category
, "name");
277 if (strcmp(cfg_obj_asstring(catname
), "default") == 0)
278 default_set
= ISC_TRUE
;
280 if (!unmatched_set
) {
281 catname
= cfg_tuple_get(category
, "name");
282 if (strcmp(cfg_obj_asstring(catname
), "unmatched") == 0)
283 unmatched_set
= ISC_TRUE
;
288 CHECK(ns_log_setdefaultcategory(logconf
));
291 CHECK(ns_log_setunmatchedcategory(logconf
));
293 return (ISC_R_SUCCESS
);
297 isc_logconfig_destroy(&logconf
);