etc/services - sync with NetBSD-8
[minix.git] / external / bsd / bind / dist / bin / named / logconf.c
blob375fc05566c38bd81b8526477d851870acabf13a
1 /* $NetBSD: logconf.c,v 1.7 2014/12/10 04:37:51 christos Exp $ */
3 /*
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 */
22 /*! \file */
24 #include <config.h>
26 #include <isc/file.h>
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>
39 #define CHECK(op) \
40 do { result = (op); \
41 if (result != ISC_R_SUCCESS) goto cleanup; \
42 } while (/*CONSTCOND*/0)
44 /*%
45 * Set up a logging category according to the named.conf data
46 * in 'ccat' and add it to 'logconfig'.
48 static isc_result_t
49 category_fromconf(const cfg_obj_t *ccat, isc_logconfig_t *logconfig) {
50 isc_result_t result;
51 const char *catname;
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",
62 catname);
64 * Allow further processing by returning success.
66 return (ISC_R_SUCCESS);
69 if (logconfig == NULL)
70 return (ISC_R_SUCCESS);
72 module = NULL;
74 destinations = cfg_tuple_get(ccat, "destinations");
75 for (element = cfg_list_first(destinations);
76 element != NULL;
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,
83 module);
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));
89 return (result);
92 return (ISC_R_SUCCESS);
95 /*%
96 * Set up a logging channel according to the named.conf data
97 * in 'cchan' and add it to 'logconfig'.
99 static isc_result_t
100 channel_fromconf(const cfg_obj_t *channel, isc_logconfig_t *logconfig)
102 isc_result_t result;
103 isc_logdestination_t dest;
104 unsigned int type;
105 unsigned int flags = 0;
106 int level;
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;
113 int i;
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);
122 i = 0;
123 if (fileobj != NULL)
124 i++;
125 if (syslogobj != NULL)
126 i++;
127 if (nullobj != NULL)
128 i++;
129 if (stderrobj != NULL)
130 i++;
132 if (i != 1) {
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,
172 &facility);
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;
184 * Munge flags.
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;
219 } else
220 /* debug */
221 level = cfg_obj_asuint32(severity);
224 if (logconfig == NULL)
225 result = ISC_R_SUCCESS;
226 else
227 result = isc_log_createchannel(logconfig, channelname,
228 type, level, &dest, flags);
230 if (result == ISC_R_SUCCESS && type == ISC_LOG_TOFILE) {
231 FILE *fp;
234 * Test to make sure that file is a plain file.
235 * Fix defect #22771
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)
247 syslog(LOG_ERR,
248 "isc_stdio_open '%s' failed: "
249 "%s", dest.file.name,
250 isc_result_totext(result));
251 fprintf(stderr,
252 "isc_stdio_open '%s' failed: %s\n",
253 dest.file.name,
254 isc_result_totext(result));
255 } else
256 (void)isc_stdio_close(fp);
257 goto done;
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));
266 done:
267 return (result);
270 isc_result_t
271 ns_log_configure(isc_logconfig_t *logconfig, const cfg_obj_t *logstmt) {
272 isc_result_t result;
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);
285 element != NULL;
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);
294 element != NULL;
295 element = cfg_list_next(element))
297 const cfg_obj_t *category = cfg_listelt_value(element);
298 CHECK(category_fromconf(category, logconfig));
299 if (!default_set) {
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);
319 cleanup:
320 return (result);