00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <config.h>
00023
00024 #include <isc/file.h>
00025 #include <isc/offset.h>
00026 #include <isc/result.h>
00027 #include <isc/stdio.h>
00028 #include <isc/string.h>
00029 #include <isc/syslog.h>
00030
00031 #include <isccfg/cfg.h>
00032 #include <isccfg/log.h>
00033
00034 #include <named/log.h>
00035 #include <named/logconf.h>
00036
00037 #define CHECK(op) \
00038 do { result = (op); \
00039 if (result != ISC_R_SUCCESS) goto cleanup; \
00040 } while (0)
00041
00042
00043
00044
00045
00046 static isc_result_t
00047 category_fromconf(const cfg_obj_t *ccat, isc_logconfig_t *logconfig) {
00048 isc_result_t result;
00049 const char *catname;
00050 isc_logcategory_t *category;
00051 isc_logmodule_t *module;
00052 const cfg_obj_t *destinations = NULL;
00053 const cfg_listelt_t *element = NULL;
00054
00055 catname = cfg_obj_asstring(cfg_tuple_get(ccat, "name"));
00056 category = isc_log_categorybyname(ns_g_lctx, catname);
00057 if (category == NULL) {
00058 cfg_obj_log(ccat, ns_g_lctx, ISC_LOG_ERROR,
00059 "unknown logging category '%s' ignored",
00060 catname);
00061
00062
00063
00064 return (ISC_R_SUCCESS);
00065 }
00066
00067 if (logconfig == NULL)
00068 return (ISC_R_SUCCESS);
00069
00070 module = NULL;
00071
00072 destinations = cfg_tuple_get(ccat, "destinations");
00073 for (element = cfg_list_first(destinations);
00074 element != NULL;
00075 element = cfg_list_next(element))
00076 {
00077 const cfg_obj_t *channel = cfg_listelt_value(element);
00078 const char *channelname = cfg_obj_asstring(channel);
00079
00080 result = isc_log_usechannel(logconfig, channelname, category,
00081 module);
00082 if (result != ISC_R_SUCCESS) {
00083 isc_log_write(ns_g_lctx, CFG_LOGCATEGORY_CONFIG,
00084 NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
00085 "logging channel '%s': %s", channelname,
00086 isc_result_totext(result));
00087 return (result);
00088 }
00089 }
00090 return (ISC_R_SUCCESS);
00091 }
00092
00093
00094
00095
00096
00097 static isc_result_t
00098 channel_fromconf(const cfg_obj_t *channel, isc_logconfig_t *logconfig)
00099 {
00100 isc_result_t result;
00101 isc_logdestination_t dest;
00102 unsigned int type;
00103 unsigned int flags = 0;
00104 int level;
00105 const char *channelname;
00106 const cfg_obj_t *fileobj = NULL;
00107 const cfg_obj_t *syslogobj = NULL;
00108 const cfg_obj_t *nullobj = NULL;
00109 const cfg_obj_t *stderrobj = NULL;
00110 const cfg_obj_t *severity = NULL;
00111 int i;
00112
00113 channelname = cfg_obj_asstring(cfg_map_getname(channel));
00114
00115 (void)cfg_map_get(channel, "file", &fileobj);
00116 (void)cfg_map_get(channel, "syslog", &syslogobj);
00117 (void)cfg_map_get(channel, "null", &nullobj);
00118 (void)cfg_map_get(channel, "stderr", &stderrobj);
00119
00120 i = 0;
00121 if (fileobj != NULL)
00122 i++;
00123 if (syslogobj != NULL)
00124 i++;
00125 if (nullobj != NULL)
00126 i++;
00127 if (stderrobj != NULL)
00128 i++;
00129
00130 if (i != 1) {
00131 cfg_obj_log(channel, ns_g_lctx, ISC_LOG_ERROR,
00132 "channel '%s': exactly one of file, syslog, "
00133 "null, and stderr must be present", channelname);
00134 return (ISC_R_FAILURE);
00135 }
00136
00137 type = ISC_LOG_TONULL;
00138
00139 if (fileobj != NULL) {
00140 const cfg_obj_t *pathobj = cfg_tuple_get(fileobj, "file");
00141 const cfg_obj_t *sizeobj = cfg_tuple_get(fileobj, "size");
00142 const cfg_obj_t *versionsobj =
00143 cfg_tuple_get(fileobj, "versions");
00144 isc_int32_t versions = ISC_LOG_ROLLNEVER;
00145 isc_offset_t size = 0;
00146
00147 type = ISC_LOG_TOFILE;
00148
00149 if (versionsobj != NULL && cfg_obj_isuint32(versionsobj))
00150 versions = cfg_obj_asuint32(versionsobj);
00151 if (versionsobj != NULL && cfg_obj_isstring(versionsobj) &&
00152 strcasecmp(cfg_obj_asstring(versionsobj), "unlimited") == 0)
00153 versions = ISC_LOG_ROLLINFINITE;
00154 if (sizeobj != NULL &&
00155 cfg_obj_isuint64(sizeobj) &&
00156 cfg_obj_asuint64(sizeobj) < ISC_OFFSET_MAXIMUM)
00157 size = (isc_offset_t)cfg_obj_asuint64(sizeobj);
00158 dest.file.stream = NULL;
00159 dest.file.name = cfg_obj_asstring(pathobj);
00160 dest.file.versions = versions;
00161 dest.file.maximum_size = size;
00162 } else if (syslogobj != NULL) {
00163 int facility = LOG_DAEMON;
00164
00165 type = ISC_LOG_TOSYSLOG;
00166
00167 if (cfg_obj_isstring(syslogobj)) {
00168 const char *facilitystr = cfg_obj_asstring(syslogobj);
00169 (void)isc_syslog_facilityfromstring(facilitystr,
00170 &facility);
00171 }
00172 dest.facility = facility;
00173 } else if (stderrobj != NULL) {
00174 type = ISC_LOG_TOFILEDESC;
00175 dest.file.stream = stderr;
00176 dest.file.name = NULL;
00177 dest.file.versions = ISC_LOG_ROLLNEVER;
00178 dest.file.maximum_size = 0;
00179 }
00180
00181
00182
00183
00184 {
00185 const cfg_obj_t *printcat = NULL;
00186 const cfg_obj_t *printsev = NULL;
00187 const cfg_obj_t *printtime = NULL;
00188 const cfg_obj_t *buffered = NULL;
00189
00190 (void)cfg_map_get(channel, "print-category", &printcat);
00191 (void)cfg_map_get(channel, "print-severity", &printsev);
00192 (void)cfg_map_get(channel, "print-time", &printtime);
00193 (void)cfg_map_get(channel, "buffered", &buffered);
00194
00195 if (printcat != NULL && cfg_obj_asboolean(printcat))
00196 flags |= ISC_LOG_PRINTCATEGORY;
00197 if (printtime != NULL && cfg_obj_asboolean(printtime))
00198 flags |= ISC_LOG_PRINTTIME;
00199 if (printsev != NULL && cfg_obj_asboolean(printsev))
00200 flags |= ISC_LOG_PRINTLEVEL;
00201 if (buffered != NULL && cfg_obj_asboolean(buffered))
00202 flags |= ISC_LOG_BUFFERED;
00203 }
00204
00205 level = ISC_LOG_INFO;
00206 if (cfg_map_get(channel, "severity", &severity) == ISC_R_SUCCESS) {
00207 if (cfg_obj_isstring(severity)) {
00208 const char *str = cfg_obj_asstring(severity);
00209 if (strcasecmp(str, "critical") == 0)
00210 level = ISC_LOG_CRITICAL;
00211 else if (strcasecmp(str, "error") == 0)
00212 level = ISC_LOG_ERROR;
00213 else if (strcasecmp(str, "warning") == 0)
00214 level = ISC_LOG_WARNING;
00215 else if (strcasecmp(str, "notice") == 0)
00216 level = ISC_LOG_NOTICE;
00217 else if (strcasecmp(str, "info") == 0)
00218 level = ISC_LOG_INFO;
00219 else if (strcasecmp(str, "dynamic") == 0)
00220 level = ISC_LOG_DYNAMIC;
00221 } else
00222
00223 level = cfg_obj_asuint32(severity);
00224 }
00225
00226 if (logconfig == NULL)
00227 result = ISC_R_SUCCESS;
00228 else
00229 result = isc_log_createchannel(logconfig, channelname,
00230 type, level, &dest, flags);
00231
00232 if (result == ISC_R_SUCCESS && type == ISC_LOG_TOFILE) {
00233 FILE *fp;
00234
00235
00236
00237
00238
00239 result = isc_file_isplainfile(dest.file.name);
00240 if (result == ISC_R_SUCCESS || result == ISC_R_FILENOTFOUND) {
00241
00242
00243
00244
00245
00246 result = isc_stdio_open(dest.file.name, "a", &fp);
00247 if (result != ISC_R_SUCCESS) {
00248 if (logconfig != NULL && !ns_g_nosyslog)
00249 syslog(LOG_ERR,
00250 "isc_stdio_open '%s' failed: "
00251 "%s", dest.file.name,
00252 isc_result_totext(result));
00253 fprintf(stderr,
00254 "isc_stdio_open '%s' failed: %s\n",
00255 dest.file.name,
00256 isc_result_totext(result));
00257 } else
00258 (void)isc_stdio_close(fp);
00259 goto done;
00260 }
00261 if (logconfig != NULL && !ns_g_nosyslog)
00262 syslog(LOG_ERR, "isc_file_isplainfile '%s' failed: %s",
00263 dest.file.name, isc_result_totext(result));
00264 fprintf(stderr, "isc_file_isplainfile '%s' failed: %s\n",
00265 dest.file.name, isc_result_totext(result));
00266 }
00267
00268 done:
00269 return (result);
00270 }
00271
00272 isc_result_t
00273 ns_log_configure(isc_logconfig_t *logconfig, const cfg_obj_t *logstmt) {
00274 isc_result_t result;
00275 const cfg_obj_t *channels = NULL;
00276 const cfg_obj_t *categories = NULL;
00277 const cfg_listelt_t *element;
00278 isc_boolean_t default_set = ISC_FALSE;
00279 isc_boolean_t unmatched_set = ISC_FALSE;
00280 const cfg_obj_t *catname;
00281
00282 if (logconfig != NULL)
00283 CHECK(ns_log_setdefaultchannels(logconfig));
00284
00285 (void)cfg_map_get(logstmt, "channel", &channels);
00286 for (element = cfg_list_first(channels);
00287 element != NULL;
00288 element = cfg_list_next(element))
00289 {
00290 const cfg_obj_t *channel = cfg_listelt_value(element);
00291 CHECK(channel_fromconf(channel, logconfig));
00292 }
00293
00294 (void)cfg_map_get(logstmt, "category", &categories);
00295 for (element = cfg_list_first(categories);
00296 element != NULL;
00297 element = cfg_list_next(element))
00298 {
00299 const cfg_obj_t *category = cfg_listelt_value(element);
00300 CHECK(category_fromconf(category, logconfig));
00301 if (!default_set) {
00302 catname = cfg_tuple_get(category, "name");
00303 if (strcmp(cfg_obj_asstring(catname), "default") == 0)
00304 default_set = ISC_TRUE;
00305 }
00306 if (!unmatched_set) {
00307 catname = cfg_tuple_get(category, "name");
00308 if (strcmp(cfg_obj_asstring(catname), "unmatched") == 0)
00309 unmatched_set = ISC_TRUE;
00310 }
00311 }
00312
00313 if (logconfig != NULL && !default_set)
00314 CHECK(ns_log_setdefaultcategory(logconfig));
00315
00316 if (logconfig != NULL && !unmatched_set)
00317 CHECK(ns_log_setunmatchedcategory(logconfig));
00318
00319 return (ISC_R_SUCCESS);
00320
00321 cleanup:
00322 return (result);
00323 }