1 /* $NetBSD: logconf.c,v 1.7 2014/12/10 04:37:51 christos Exp $ */
4 * Copyright (C) 2004-2007, 2011, 2013 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 1999-2001 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
20 /* Id: logconf.c,v 1.45 2011/03/05 23:52:29 tbox Exp */
27 #include <isc/offset.h>
28 #include <isc/result.h>
29 #include <isc/stdio.h>
30 #include <isc/string.h>
31 #include <isc/syslog.h>
33 #include <isccfg/cfg.h>
34 #include <isccfg/log.h>
36 #include <named/log.h>
37 #include <named/logconf.h>
41 if (result != ISC_R_SUCCESS) goto cleanup; \
42 } while (/*CONSTCOND*/0)
45 * Set up a logging category according to the named.conf data
46 * in 'ccat' and add it to 'logconfig'.
49 category_fromconf(const cfg_obj_t
*ccat
, isc_logconfig_t
*logconfig
) {
52 isc_logcategory_t
*category
;
53 isc_logmodule_t
*module
;
54 const cfg_obj_t
*destinations
= NULL
;
55 const cfg_listelt_t
*element
= NULL
;
57 catname
= cfg_obj_asstring(cfg_tuple_get(ccat
, "name"));
58 category
= isc_log_categorybyname(ns_g_lctx
, catname
);
59 if (category
== NULL
) {
60 cfg_obj_log(ccat
, ns_g_lctx
, ISC_LOG_ERROR
,
61 "unknown logging category '%s' ignored",
64 * Allow further processing by returning success.
66 return (ISC_R_SUCCESS
);
69 if (logconfig
== NULL
)
70 return (ISC_R_SUCCESS
);
74 destinations
= cfg_tuple_get(ccat
, "destinations");
75 for (element
= cfg_list_first(destinations
);
77 element
= cfg_list_next(element
))
79 const cfg_obj_t
*channel
= cfg_listelt_value(element
);
80 const char *channelname
= cfg_obj_asstring(channel
);
82 result
= isc_log_usechannel(logconfig
, channelname
, category
,
84 if (result
!= ISC_R_SUCCESS
) {
85 isc_log_write(ns_g_lctx
, CFG_LOGCATEGORY_CONFIG
,
86 NS_LOGMODULE_SERVER
, ISC_LOG_ERROR
,
87 "logging channel '%s': %s", channelname
,
88 isc_result_totext(result
));
92 return (ISC_R_SUCCESS
);
96 * Set up a logging channel according to the named.conf data
97 * in 'cchan' and add it to 'logconfig'.
100 channel_fromconf(const cfg_obj_t
*channel
, isc_logconfig_t
*logconfig
)
103 isc_logdestination_t dest
;
105 unsigned int flags
= 0;
107 const char *channelname
;
108 const cfg_obj_t
*fileobj
= NULL
;
109 const cfg_obj_t
*syslogobj
= NULL
;
110 const cfg_obj_t
*nullobj
= NULL
;
111 const cfg_obj_t
*stderrobj
= NULL
;
112 const cfg_obj_t
*severity
= NULL
;
115 channelname
= cfg_obj_asstring(cfg_map_getname(channel
));
117 (void)cfg_map_get(channel
, "file", &fileobj
);
118 (void)cfg_map_get(channel
, "syslog", &syslogobj
);
119 (void)cfg_map_get(channel
, "null", &nullobj
);
120 (void)cfg_map_get(channel
, "stderr", &stderrobj
);
125 if (syslogobj
!= NULL
)
129 if (stderrobj
!= NULL
)
133 cfg_obj_log(channel
, ns_g_lctx
, ISC_LOG_ERROR
,
134 "channel '%s': exactly one of file, syslog, "
135 "null, and stderr must be present", channelname
);
136 return (ISC_R_FAILURE
);
139 type
= ISC_LOG_TONULL
;
141 if (fileobj
!= NULL
) {
142 const cfg_obj_t
*pathobj
= cfg_tuple_get(fileobj
, "file");
143 const cfg_obj_t
*sizeobj
= cfg_tuple_get(fileobj
, "size");
144 const cfg_obj_t
*versionsobj
=
145 cfg_tuple_get(fileobj
, "versions");
146 isc_int32_t versions
= ISC_LOG_ROLLNEVER
;
147 isc_offset_t size
= 0;
149 type
= ISC_LOG_TOFILE
;
151 if (versionsobj
!= NULL
&& cfg_obj_isuint32(versionsobj
))
152 versions
= cfg_obj_asuint32(versionsobj
);
153 if (versionsobj
!= NULL
&& cfg_obj_isstring(versionsobj
) &&
154 strcasecmp(cfg_obj_asstring(versionsobj
), "unlimited") == 0)
155 versions
= ISC_LOG_ROLLINFINITE
;
156 if (sizeobj
!= NULL
&&
157 cfg_obj_isuint64(sizeobj
) &&
158 cfg_obj_asuint64(sizeobj
) < ISC_OFFSET_MAXIMUM
)
159 size
= (isc_offset_t
)cfg_obj_asuint64(sizeobj
);
160 dest
.file
.stream
= NULL
;
161 dest
.file
.name
= cfg_obj_asstring(pathobj
);
162 dest
.file
.versions
= versions
;
163 dest
.file
.maximum_size
= size
;
164 } else if (syslogobj
!= NULL
) {
165 int facility
= LOG_DAEMON
;
167 type
= ISC_LOG_TOSYSLOG
;
169 if (cfg_obj_isstring(syslogobj
)) {
170 const char *facilitystr
= cfg_obj_asstring(syslogobj
);
171 (void)isc_syslog_facilityfromstring(facilitystr
,
174 dest
.facility
= facility
;
175 } else if (stderrobj
!= NULL
) {
176 type
= ISC_LOG_TOFILEDESC
;
177 dest
.file
.stream
= stderr
;
178 dest
.file
.name
= NULL
;
179 dest
.file
.versions
= ISC_LOG_ROLLNEVER
;
180 dest
.file
.maximum_size
= 0;
187 const cfg_obj_t
*printcat
= NULL
;
188 const cfg_obj_t
*printsev
= NULL
;
189 const cfg_obj_t
*printtime
= NULL
;
191 (void)cfg_map_get(channel
, "print-category", &printcat
);
192 (void)cfg_map_get(channel
, "print-severity", &printsev
);
193 (void)cfg_map_get(channel
, "print-time", &printtime
);
195 if (printcat
!= NULL
&& cfg_obj_asboolean(printcat
))
196 flags
|= ISC_LOG_PRINTCATEGORY
;
197 if (printtime
!= NULL
&& cfg_obj_asboolean(printtime
))
198 flags
|= ISC_LOG_PRINTTIME
;
199 if (printsev
!= NULL
&& cfg_obj_asboolean(printsev
))
200 flags
|= ISC_LOG_PRINTLEVEL
;
203 level
= ISC_LOG_INFO
;
204 if (cfg_map_get(channel
, "severity", &severity
) == ISC_R_SUCCESS
) {
205 if (cfg_obj_isstring(severity
)) {
206 const char *str
= cfg_obj_asstring(severity
);
207 if (strcasecmp(str
, "critical") == 0)
208 level
= ISC_LOG_CRITICAL
;
209 else if (strcasecmp(str
, "error") == 0)
210 level
= ISC_LOG_ERROR
;
211 else if (strcasecmp(str
, "warning") == 0)
212 level
= ISC_LOG_WARNING
;
213 else if (strcasecmp(str
, "notice") == 0)
214 level
= ISC_LOG_NOTICE
;
215 else if (strcasecmp(str
, "info") == 0)
216 level
= ISC_LOG_INFO
;
217 else if (strcasecmp(str
, "dynamic") == 0)
218 level
= ISC_LOG_DYNAMIC
;
221 level
= cfg_obj_asuint32(severity
);
224 if (logconfig
== NULL
)
225 result
= ISC_R_SUCCESS
;
227 result
= isc_log_createchannel(logconfig
, channelname
,
228 type
, level
, &dest
, flags
);
230 if (result
== ISC_R_SUCCESS
&& type
== ISC_LOG_TOFILE
) {
234 * Test to make sure that file is a plain file.
237 result
= isc_file_isplainfile(dest
.file
.name
);
238 if (result
== ISC_R_SUCCESS
|| result
== ISC_R_FILENOTFOUND
) {
240 * Test that the file can be opened, since
241 * isc_log_open() can't effectively report
242 * failures when called in isc_log_doit().
244 result
= isc_stdio_open(dest
.file
.name
, "a", &fp
);
245 if (result
!= ISC_R_SUCCESS
) {
246 if (logconfig
!= NULL
&& !ns_g_nosyslog
)
248 "isc_stdio_open '%s' failed: "
249 "%s", dest
.file
.name
,
250 isc_result_totext(result
));
252 "isc_stdio_open '%s' failed: %s\n",
254 isc_result_totext(result
));
256 (void)isc_stdio_close(fp
);
259 if (logconfig
!= NULL
&& !ns_g_nosyslog
)
260 syslog(LOG_ERR
, "isc_file_isplainfile '%s' failed: %s",
261 dest
.file
.name
, isc_result_totext(result
));
262 fprintf(stderr
, "isc_file_isplainfile '%s' failed: %s\n",
263 dest
.file
.name
, isc_result_totext(result
));
271 ns_log_configure(isc_logconfig_t
*logconfig
, const cfg_obj_t
*logstmt
) {
273 const cfg_obj_t
*channels
= NULL
;
274 const cfg_obj_t
*categories
= NULL
;
275 const cfg_listelt_t
*element
;
276 isc_boolean_t default_set
= ISC_FALSE
;
277 isc_boolean_t unmatched_set
= ISC_FALSE
;
278 const cfg_obj_t
*catname
;
280 if (logconfig
!= NULL
)
281 CHECK(ns_log_setdefaultchannels(logconfig
));
283 (void)cfg_map_get(logstmt
, "channel", &channels
);
284 for (element
= cfg_list_first(channels
);
286 element
= cfg_list_next(element
))
288 const cfg_obj_t
*channel
= cfg_listelt_value(element
);
289 CHECK(channel_fromconf(channel
, logconfig
));
292 (void)cfg_map_get(logstmt
, "category", &categories
);
293 for (element
= cfg_list_first(categories
);
295 element
= cfg_list_next(element
))
297 const cfg_obj_t
*category
= cfg_listelt_value(element
);
298 CHECK(category_fromconf(category
, logconfig
));
300 catname
= cfg_tuple_get(category
, "name");
301 if (strcmp(cfg_obj_asstring(catname
), "default") == 0)
302 default_set
= ISC_TRUE
;
304 if (!unmatched_set
) {
305 catname
= cfg_tuple_get(category
, "name");
306 if (strcmp(cfg_obj_asstring(catname
), "unmatched") == 0)
307 unmatched_set
= ISC_TRUE
;
311 if (logconfig
!= NULL
&& !default_set
)
312 CHECK(ns_log_setdefaultcategory(logconfig
));
314 if (logconfig
!= NULL
&& !unmatched_set
)
315 CHECK(ns_log_setunmatchedcategory(logconfig
));
317 return (ISC_R_SUCCESS
);