1 /*
2 * DNS Reply Tool (drool)
3 *
4 * Copyright (c) 2017-2018, OARC, Inc.
5 * Copyright (c) 2017, Comcast Corporation
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in
17 * the documentation and/or other materials provided with the
18 * distribution.
19 *
20 * 3. Neither the name of the copyright holder nor the names of its
21 * contributors may be used to endorse or promote products derived
22 * from this software without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
28 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
30 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
34 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
36 */
37
38 #include "config.h"
39
40 #include "log.h"
41 #include "assert.h"
42
43 #include <stdarg.h>
44 #include <stdio.h>
45 #include <string.h>
46 #include <pthread.h>
47 #include <time.h>
48
get_facility(const drool_log_t * log,const drool_log_facility_t facility)49 static const drool_log_settings_t* get_facility(const drool_log_t* log, const drool_log_facility_t facility)
50 {
51 drool_assert(log);
52 switch (facility) {
53 case LOG_FACILITY_CORE:
54 return &(log->core);
55 case LOG_FACILITY_NETWORK:
56 return &(log->network);
57 default:
58 break;
59 }
60 return &(log->none);
61 }
62
log_level_enable(drool_log_settings_t * settings,const drool_log_level_t level)63 inline int log_level_enable(drool_log_settings_t* settings, const drool_log_level_t level)
64 {
65 drool_assert(settings);
66
67 switch (level) {
68 case LOG_LEVEL_DEBUG:
69 settings->debug = 1;
70 return 0;
71 case LOG_LEVEL_INFO:
72 settings->info = 1;
73 return 0;
74 case LOG_LEVEL_NOTICE:
75 settings->notice = 1;
76 return 0;
77 case LOG_LEVEL_WARNING:
78 settings->warning = 1;
79 return 0;
80 case LOG_LEVEL_ERROR:
81 settings->error = 1;
82 return 0;
83 case LOG_LEVEL_CRITICAL:
84 settings->critical = 1;
85 return 0;
86 case LOG_LEVEL_ALL:
87 settings->debug = 1;
88 settings->info = 1;
89 settings->notice = 1;
90 settings->warning = 1;
91 settings->error = 1;
92 settings->critical = 1;
93 return 0;
94 default:
95 break;
96 }
97
98 return -1;
99 }
100
log_level_disable(drool_log_settings_t * settings,const drool_log_level_t level)101 inline int log_level_disable(drool_log_settings_t* settings, const drool_log_level_t level)
102 {
103 drool_assert(settings);
104
105 switch (level) {
106 case LOG_LEVEL_DEBUG:
107 settings->debug = 0;
108 return 0;
109 case LOG_LEVEL_INFO:
110 settings->info = 0;
111 return 0;
112 case LOG_LEVEL_NOTICE:
113 settings->notice = 0;
114 return 0;
115 case LOG_LEVEL_WARNING:
116 settings->warning = 0;
117 return 0;
118 case LOG_LEVEL_ERROR:
119 settings->error = 0;
120 return 0;
121 case LOG_LEVEL_CRITICAL:
122 settings->critical = 0;
123 return 0;
124 case LOG_LEVEL_ALL:
125 settings->debug = 0;
126 settings->info = 0;
127 settings->notice = 0;
128 settings->warning = 0;
129 settings->error = 0;
130 settings->critical = 0;
131 return 0;
132 default:
133 break;
134 }
135
136 return -1;
137 }
138
log_level_name(const drool_log_level_t level)139 const char* log_level_name(const drool_log_level_t level)
140 {
141 switch (level) {
142 case LOG_LEVEL_DEBUG:
143 return LOG_LEVEL_DEBUG_STR;
144 case LOG_LEVEL_INFO:
145 return LOG_LEVEL_INFO_STR;
146 case LOG_LEVEL_NOTICE:
147 return LOG_LEVEL_NOTICE_STR;
148 case LOG_LEVEL_WARNING:
149 return LOG_LEVEL_WARNING_STR;
150 case LOG_LEVEL_ERROR:
151 return LOG_LEVEL_ERROR_STR;
152 case LOG_LEVEL_CRITICAL:
153 return LOG_LEVEL_CRITICAL_STR;
154 case LOG_LEVEL_ALL:
155 return LOG_LEVEL_ALL_STR;
156 }
157 return LOG_LEVEL_UNKNOWN_STR;
158 }
159
log_facility_name(const drool_log_facility_t facility)160 const char* log_facility_name(const drool_log_facility_t facility)
161 {
162 switch (facility) {
163 case LOG_FACILITY_CORE:
164 return LOG_FACILITY_CORE_STR;
165 case LOG_FACILITY_NETWORK:
166 return LOG_FACILITY_NETWORK_STR;
167 case LOG_FACILITY_NONE:
168 return LOG_FACILITY_NONE_STR;
169 }
170 return LOG_FACILITY_UNKNOWN_STR;
171 }
172
log_is_enabled(const drool_log_t * log,const drool_log_facility_t facility,const drool_log_level_t level)173 int log_is_enabled(const drool_log_t* log, const drool_log_facility_t facility, const drool_log_level_t level)
174 {
175 const drool_log_settings_t* settings;
176
177 drool_assert(log);
178 if (!log) {
179 return 0;
180 }
181
182 settings = get_facility(log, facility);
183 drool_assert(settings);
184 if (!settings) {
185 return 0;
186 }
187
188 switch (level) {
189 case LOG_LEVEL_DEBUG:
190 if (settings->debug)
191 return 1;
192 break;
193
194 case LOG_LEVEL_INFO:
195 if (settings->info)
196 return 1;
197 break;
198
199 case LOG_LEVEL_NOTICE:
200 if (settings->notice)
201 return 1;
202 break;
203
204 case LOG_LEVEL_WARNING:
205 if (settings->warning)
206 return 1;
207 break;
208
209 case LOG_LEVEL_ERROR:
210 if (settings->error)
211 return 1;
212 break;
213
214 case LOG_LEVEL_CRITICAL:
215 if (settings->critical)
216 return 1;
217 break;
218
219 default:
220 break;
221 }
222
223 return 0;
224 }
225
log_enable(drool_log_t * log,const drool_log_facility_t facility,const drool_log_level_t level)226 inline int log_enable(drool_log_t* log, const drool_log_facility_t facility, const drool_log_level_t level)
227 {
228 drool_assert(log);
229
230 switch (facility) {
231 case LOG_FACILITY_CORE:
232 return log_level_enable(&(log->core), level);
233 case LOG_FACILITY_NETWORK:
234 return log_level_enable(&(log->network), level);
235 default:
236 break;
237 }
238
239 return -1;
240 }
241
log_disable(drool_log_t * log,const drool_log_facility_t facility,const drool_log_level_t level)242 inline int log_disable(drool_log_t* log, const drool_log_facility_t facility, const drool_log_level_t level)
243 {
244 drool_assert(log);
245
246 switch (facility) {
247 case LOG_FACILITY_CORE:
248 return log_level_disable(&(log->core), level);
249 case LOG_FACILITY_NETWORK:
250 return log_level_disable(&(log->network), level);
251 default:
252 break;
253 }
254
255 return -1;
256 }
257
log_printf_fileline(const drool_log_t * log,const drool_log_facility_t facility,const drool_log_level_t level,const char * file,size_t line,const char * format,...)258 void log_printf_fileline(const drool_log_t* log, const drool_log_facility_t facility, const drool_log_level_t level, const char* file, size_t line, const char* format, ...)
259 {
260 va_list ap;
261 char buf[1024];
262 size_t s;
263 int n, n2;
264 #if LOG_FILENAME_LINE && LOG_SHORT_FILENAME
265 char* filep;
266 #endif
267 #if LOG_DATETIME
268 struct tm tm;
269 time_t t;
270 #endif
271
272 drool_assert(log);
273 if (!log) {
274 return;
275 }
276 drool_assert(format);
277 if (!format) {
278 return;
279 }
280
281 if (!log_is_enabled(log, facility, level)) {
282 return;
283 }
284
285 #if LOG_DATETIME
286 memset(&tm, 0, sizeof(tm));
287 time(&t);
288 localtime_r(&t, &tm);
289 #endif
290
291 s = sizeof(buf) - 2;
292 n = snprintf(buf, s,
293 #if LOG_DATETIME
294 "%d-%02d-%02d %02d:%02d:%02d "
295 #endif
296 #if LOG_FILENAME_LINE
297 "%s:%04lu "
298 #endif
299 #if LOG_THREAD_ID
300 "t:%lu "
301 #endif
302 "%s %s: ",
303 #if LOG_DATETIME
304 1900 + tm.tm_year, 1 + tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
305 #endif
306 #if LOG_FILENAME_LINE
307 #if LOG_SHORT_FILENAME
308 (filep = strrchr(file, '/')) ? (filep + 1) : file,
309 #else
310 file,
311 #endif
312 line,
313 #endif
314 #if LOG_THREAD_ID
315 pthread_self(),
316 #endif
317 log_facility_name(facility), log_level_name(level));
318 if (n < 1) {
319 printf("log_printf_fileline(): snprintf() failed with %d\n", n);
320 return;
321 }
322 if (n < s) {
323 va_start(ap, format);
324 n2 = vsnprintf(&buf[n], s - n, format, ap);
325 va_end(ap);
326 if (n2 < 1) {
327 printf("log_printf_fileline(): vsnprintf() failed with %d\n", n2);
328 return;
329 }
330 }
331 fprintf(stdout, "%s\n", buf);
332 fflush(stdout);
333 }
334
log_errnumf_fileline(const drool_log_t * log,const drool_log_facility_t facility,const drool_log_level_t level,const char * file,size_t line,int errnum,const char * format,...)335 void log_errnumf_fileline(const drool_log_t* log, const drool_log_facility_t facility, const drool_log_level_t level, const char* file, size_t line, int errnum, const char* format, ...)
336 {
337 va_list ap;
338 char errbuf[512];
339 char buf[1024];
340 size_t s;
341 int n, n2;
342 #if LOG_FILENAME_LINE && LOG_SHORT_FILENAME
343 char* filep;
344 #endif
345 #if LOG_DATETIME
346 struct tm tm;
347 time_t t;
348 #endif
349
350 drool_assert(log);
351 if (!log) {
352 return;
353 }
354 drool_assert(format);
355 if (!format) {
356 return;
357 }
358
359 if (!log_is_enabled(log, facility, level)) {
360 return;
361 }
362
363 memset(errbuf, 0, sizeof(errbuf));
364
365 #if ((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !_GNU_SOURCE) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__) || defined(__DragonFly__)
366 /* XSI-compliant version */
367 {
368 int ret = strerror_r(errnum, errbuf, sizeof(errbuf));
369 if (ret > 0) {
370 (void)strerror_r(ret, errbuf, sizeof(errbuf));
371 } else {
372 (void)strerror_r(errno, errbuf, sizeof(errbuf));
373 }
374 }
375 #else
376 /* GNU-specific version */
377 errbuf = strerror_r(errnum, errbuf, sizeof(errbuf));
378 #endif
379
380 #if LOG_DATETIME
381 memset(&tm, 0, sizeof(tm));
382 time(&t);
383 localtime_r(&t, &tm);
384 #endif
385
386 s = sizeof(buf) - 2;
387 n = snprintf(buf, s,
388 #if LOG_DATETIME
389 "%d-%02d-%02d %02d:%02d:%02d "
390 #endif
391 #if LOG_FILENAME_LINE
392 "%s:%04lu "
393 #endif
394 #if LOG_THREAD_ID
395 "t:%lu "
396 #endif
397 "%s %s: ",
398 #if LOG_DATETIME
399 1900 + tm.tm_year, 1 + tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
400 #endif
401 #if LOG_FILENAME_LINE
402 #if LOG_SHORT_FILENAME
403 (filep = strrchr(file, '/')) ? (filep + 1) : file,
404 #else
405 file,
406 #endif
407 line,
408 #endif
409 #if LOG_THREAD_ID
410 pthread_self(),
411 #endif
412 log_facility_name(facility), log_level_name(level));
413 if (n < 1) {
414 printf("log_printf_fileline(): snprintf() failed with %d\n", n);
415 return;
416 }
417 if (n < s) {
418 va_start(ap, format);
419 n2 = vsnprintf(&buf[n], s - n, format, ap);
420 va_end(ap);
421 if (n2 < 1) {
422 printf("log_printf_fileline(): vsnprintf() failed with %d\n", n2);
423 return;
424 }
425 }
426 fprintf(stdout, "%s: %s\n", buf, errbuf);
427 fflush(stdout);
428 };
429