]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/openbsm/bin/auditdistd/pjdlog.c
Merge LLVM libunwind release_80 branch r355677 (effectively, 8.0.0 rc4).
[FreeBSD/FreeBSD.git] / contrib / openbsm / bin / auditdistd / pjdlog.c
1 /*-
2  * Copyright (c) 2009-2010 The FreeBSD Foundation
3  * Copyright (c) 2011 Pawel Jakub Dawidek <pjd@FreeBSD.org>
4  * All rights reserved.
5  *
6  * This software was developed by Pawel Jakub Dawidek under sponsorship from
7  * the FreeBSD Foundation.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30
31 #include <sys/types.h>
32 #include <sys/socket.h>
33 #include <netinet/in.h>
34 #include <arpa/inet.h>
35
36 #include <assert.h>
37 #include <errno.h>
38 #include <stdarg.h>
39 #include <stdint.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <syslog.h>
44 #include <unistd.h>
45
46 #ifdef __FreeBSD__
47 #include <libutil.h>
48 #include <printf.h>
49 #endif
50
51 #include "pjdlog.h"
52
53 #define PJDLOG_NEVER_INITIALIZED        0
54 #define PJDLOG_NOT_INITIALIZED          1
55 #define PJDLOG_INITIALIZED              2
56
57 static int pjdlog_initialized = PJDLOG_NEVER_INITIALIZED;
58 static int pjdlog_mode, pjdlog_debug_level;
59 static char pjdlog_prefix[128];
60
61 #ifdef __FreeBSD__
62 static int
63 pjdlog_printf_arginfo_humanized_number(const struct printf_info *pi __unused,
64     size_t n, int *argt)
65 {
66
67         assert(n >= 1);
68         argt[0] = PA_INT | PA_FLAG_INTMAX;
69         return (1);
70 }
71
72 static int
73 pjdlog_printf_render_humanized_number(struct __printf_io *io,
74     const struct printf_info *pi, const void * const *arg)
75 {
76         char buf[5];
77         intmax_t num;
78         int ret;
79
80         num = *(const intmax_t *)arg[0];
81         humanize_number(buf, sizeof(buf), (int64_t)num, "", HN_AUTOSCALE,
82             HN_NOSPACE | HN_DECIMAL);
83         ret = __printf_out(io, pi, buf, strlen(buf));
84         __printf_flush(io);
85         return (ret);
86 }
87
88 static int
89 pjdlog_printf_arginfo_sockaddr(const struct printf_info *pi __unused,
90     size_t n, int *argt)
91 {
92
93         assert(n >= 1);
94         argt[0] = PA_POINTER;
95         return (1);
96 }
97
98 static int
99 pjdlog_printf_render_sockaddr(struct __printf_io *io,
100     const struct printf_info *pi, const void * const *arg)
101 {
102         const struct sockaddr_storage *ss;
103         char buf[64];
104         int ret;
105
106         ss = *(const struct sockaddr_storage * const *)arg[0];
107         switch (ss->ss_family) {
108         case AF_INET:
109             {
110                 char addr[INET_ADDRSTRLEN];
111                 const struct sockaddr_in *sin;
112                 unsigned int port;
113
114                 sin = (const struct sockaddr_in *)ss;
115                 port = ntohs(sin->sin_port);
116                 if (inet_ntop(ss->ss_family, &sin->sin_addr, addr,
117                     sizeof(addr)) == NULL) {
118                         PJDLOG_ABORT("inet_ntop(AF_INET) failed: %s.",
119                             strerror(errno));
120                 }
121                 snprintf(buf, sizeof(buf), "%s:%u", addr, port);
122                 break;
123             }
124         case AF_INET6:
125             {
126                 char addr[INET6_ADDRSTRLEN];
127                 const struct sockaddr_in6 *sin;
128                 unsigned int port;
129
130                 sin = (const struct sockaddr_in6 *)ss;
131                 port = ntohs(sin->sin6_port);
132                 if (inet_ntop(ss->ss_family, &sin->sin6_addr, addr,
133                     sizeof(addr)) == NULL) {
134                         PJDLOG_ABORT("inet_ntop(AF_INET6) failed: %s.",
135                             strerror(errno));
136                 }
137                 snprintf(buf, sizeof(buf), "[%s]:%u", addr, port);
138                 break;
139             }
140         default:
141                 snprintf(buf, sizeof(buf), "[unsupported family %hhu]",
142                     ss->ss_family);
143                 break;
144         }
145         ret = __printf_out(io, pi, buf, strlen(buf));
146         __printf_flush(io);
147         return (ret);
148 }
149 #endif  /* __FreeBSD__ */
150
151 void
152 pjdlog_init(int mode)
153 {
154         int saved_errno;
155
156         assert(pjdlog_initialized == PJDLOG_NEVER_INITIALIZED ||
157             pjdlog_initialized == PJDLOG_NOT_INITIALIZED);
158         assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG);
159
160         saved_errno = errno;
161
162         if (pjdlog_initialized == PJDLOG_NEVER_INITIALIZED) {
163 #ifdef __FreeBSD__
164                 __use_xprintf = 1;
165                 register_printf_render_std("T");
166                 register_printf_render('N',
167                     pjdlog_printf_render_humanized_number,
168                     pjdlog_printf_arginfo_humanized_number);
169                 register_printf_render('S',
170                     pjdlog_printf_render_sockaddr,
171                     pjdlog_printf_arginfo_sockaddr);
172 #endif
173         }
174
175         if (mode == PJDLOG_MODE_SYSLOG)
176                 openlog(NULL, LOG_PID | LOG_NDELAY, LOG_DAEMON);
177         pjdlog_mode = mode;
178         pjdlog_debug_level = 0;
179         bzero(pjdlog_prefix, sizeof(pjdlog_prefix));
180
181         pjdlog_initialized = PJDLOG_INITIALIZED;
182
183         errno = saved_errno;
184 }
185
186 void
187 pjdlog_fini(void)
188 {
189         int saved_errno;
190
191         assert(pjdlog_initialized == PJDLOG_INITIALIZED);
192
193         saved_errno = errno;
194
195         if (pjdlog_mode == PJDLOG_MODE_SYSLOG)
196                 closelog();
197
198         pjdlog_initialized = PJDLOG_NOT_INITIALIZED;
199
200         errno = saved_errno;
201 }
202
203 /*
204  * Configure where the logs should go.
205  * By default they are send to stdout/stderr, but after going into background
206  * (eg. by calling daemon(3)) application is responsible for changing mode to
207  * PJDLOG_MODE_SYSLOG, so logs will be send to syslog.
208  */
209 void
210 pjdlog_mode_set(int mode)
211 {
212         int saved_errno;
213
214         assert(pjdlog_initialized == PJDLOG_INITIALIZED);
215         assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG);
216
217         if (pjdlog_mode == mode)
218                 return;
219
220         saved_errno = errno;
221
222         if (mode == PJDLOG_MODE_SYSLOG)
223                 openlog(NULL, LOG_PID | LOG_NDELAY, LOG_DAEMON);
224         else /* if (mode == PJDLOG_MODE_STD) */
225                 closelog();
226
227         pjdlog_mode = mode;
228
229         errno = saved_errno;
230 }
231
232 /*
233  * Return current mode.
234  */
235 int
236 pjdlog_mode_get(void)
237 {
238
239         assert(pjdlog_initialized == PJDLOG_INITIALIZED);
240
241         return (pjdlog_mode);
242 }
243
244 /*
245  * Set debug level. All the logs above the level specified here will be
246  * ignored.
247  */
248 void
249 pjdlog_debug_set(int level)
250 {
251
252         assert(pjdlog_initialized == PJDLOG_INITIALIZED);
253         assert(level >= 0);
254
255         pjdlog_debug_level = level;
256 }
257
258 /*
259  * Return current debug level.
260  */
261 int
262 pjdlog_debug_get(void)
263 {
264
265         assert(pjdlog_initialized == PJDLOG_INITIALIZED);
266
267         return (pjdlog_debug_level);
268 }
269
270 /*
271  * Set prefix that will be used before each log.
272  * Setting prefix to NULL will remove it.
273  */
274 void
275 pjdlog_prefix_set(const char *fmt, ...)
276 {
277         va_list ap;
278
279         assert(pjdlog_initialized == PJDLOG_INITIALIZED);
280
281         va_start(ap, fmt);
282         pjdlogv_prefix_set(fmt, ap);
283         va_end(ap);
284 }
285
286 /*
287  * Set prefix that will be used before each log.
288  * Setting prefix to NULL will remove it.
289  */
290 void
291 pjdlogv_prefix_set(const char *fmt, va_list ap)
292 {
293         int saved_errno;
294
295         assert(pjdlog_initialized == PJDLOG_INITIALIZED);
296         assert(fmt != NULL);
297
298         saved_errno = errno;
299
300         vsnprintf(pjdlog_prefix, sizeof(pjdlog_prefix), fmt, ap);
301
302         errno = saved_errno;
303 }
304
305 /*
306  * Convert log level into string.
307  */
308 static const char *
309 pjdlog_level_string(int loglevel)
310 {
311
312         switch (loglevel) {
313         case LOG_EMERG:
314                 return ("EMERG");
315         case LOG_ALERT:
316                 return ("ALERT");
317         case LOG_CRIT:
318                 return ("CRIT");
319         case LOG_ERR:
320                 return ("ERROR");
321         case LOG_WARNING:
322                 return ("WARNING");
323         case LOG_NOTICE:
324                 return ("NOTICE");
325         case LOG_INFO:
326                 return ("INFO");
327         case LOG_DEBUG:
328                 return ("DEBUG");
329         }
330         assert(!"Invalid log level.");
331         abort();        /* XXX: gcc */
332 }
333
334 /*
335  * Common log routine.
336  */
337 void
338 pjdlog_common(int loglevel, int debuglevel, int error, const char *fmt, ...)
339 {
340         va_list ap;
341
342         assert(pjdlog_initialized == PJDLOG_INITIALIZED);
343
344         va_start(ap, fmt);
345         pjdlogv_common(loglevel, debuglevel, error, fmt, ap);
346         va_end(ap);
347 }
348
349 /*
350  * Common log routine, which can handle regular log level as well as debug
351  * level. We decide here where to send the logs (stdout/stderr or syslog).
352  */
353 void
354 pjdlogv_common(int loglevel, int debuglevel, int error, const char *fmt,
355     va_list ap)
356 {
357         int saved_errno;
358
359         assert(pjdlog_initialized == PJDLOG_INITIALIZED);
360         assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
361             loglevel == LOG_CRIT || loglevel == LOG_ERR ||
362             loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
363             loglevel == LOG_INFO || loglevel == LOG_DEBUG);
364         assert(loglevel != LOG_DEBUG || debuglevel > 0);
365         assert(error >= -1);
366
367         /* Ignore debug above configured level. */
368         if (loglevel == LOG_DEBUG && debuglevel > pjdlog_debug_level)
369                 return;
370
371         saved_errno = errno;
372
373         switch (pjdlog_mode) {
374         case PJDLOG_MODE_STD:
375             {
376                 FILE *out;
377
378                 /*
379                  * We send errors and warning to stderr and the rest to stdout.
380                  */
381                 switch (loglevel) {
382                 case LOG_EMERG:
383                 case LOG_ALERT:
384                 case LOG_CRIT:
385                 case LOG_ERR:
386                 case LOG_WARNING:
387                         out = stderr;
388                         break;
389                 case LOG_NOTICE:
390                 case LOG_INFO:
391                 case LOG_DEBUG:
392                         out = stdout;
393                         break;
394                 default:
395                         assert(!"Invalid loglevel.");
396                         abort();        /* XXX: gcc */
397                 }
398
399                 fprintf(out, "(%d) ", getpid());
400                 fprintf(out, "[%s]", pjdlog_level_string(loglevel));
401                 /* Attach debuglevel if this is debug log. */
402                 if (loglevel == LOG_DEBUG)
403                         fprintf(out, "[%d]", debuglevel);
404                 fprintf(out, " %s", pjdlog_prefix);
405                 vfprintf(out, fmt, ap);
406                 if (error != -1)
407                         fprintf(out, ": %s.", strerror(error));
408                 fprintf(out, "\n");
409                 fflush(out);
410                 break;
411             }
412         case PJDLOG_MODE_SYSLOG:
413             {
414                 char log[1024];
415                 int len;
416
417                 len = snprintf(log, sizeof(log), "%s", pjdlog_prefix);
418                 if ((size_t)len < sizeof(log))
419                         len += vsnprintf(log + len, sizeof(log) - len, fmt, ap);
420                 if (error != -1 && (size_t)len < sizeof(log)) {
421                         (void)snprintf(log + len, sizeof(log) - len, ": %s.",
422                             strerror(error));
423                 }
424                 syslog(loglevel, "%s", log);
425                 break;
426             }
427         default:
428                 assert(!"Invalid mode.");
429         }
430
431         errno = saved_errno;
432 }
433
434 /*
435  * Regular logs.
436  */
437 void
438 pjdlogv(int loglevel, const char *fmt, va_list ap)
439 {
440
441         assert(pjdlog_initialized == PJDLOG_INITIALIZED);
442
443         /* LOG_DEBUG is invalid here, pjdlogv?_debug() should be used. */
444         assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
445             loglevel == LOG_CRIT || loglevel == LOG_ERR ||
446             loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
447             loglevel == LOG_INFO);
448
449         pjdlogv_common(loglevel, 0, -1, fmt, ap);
450 }
451
452 /*
453  * Regular logs.
454  */
455 void
456 pjdlog(int loglevel, const char *fmt, ...)
457 {
458         va_list ap;
459
460         assert(pjdlog_initialized == PJDLOG_INITIALIZED);
461
462         va_start(ap, fmt);
463         pjdlogv(loglevel, fmt, ap);
464         va_end(ap);
465 }
466
467 /*
468  * Debug logs.
469  */
470 void
471 pjdlogv_debug(int debuglevel, const char *fmt, va_list ap)
472 {
473
474         assert(pjdlog_initialized == PJDLOG_INITIALIZED);
475
476         pjdlogv_common(LOG_DEBUG, debuglevel, -1, fmt, ap);
477 }
478
479 /*
480  * Debug logs.
481  */
482 void
483 pjdlog_debug(int debuglevel, const char *fmt, ...)
484 {
485         va_list ap;
486
487         assert(pjdlog_initialized == PJDLOG_INITIALIZED);
488
489         va_start(ap, fmt);
490         pjdlogv_debug(debuglevel, fmt, ap);
491         va_end(ap);
492 }
493
494 /*
495  * Error logs with errno logging.
496  */
497 void
498 pjdlogv_errno(int loglevel, const char *fmt, va_list ap)
499 {
500
501         assert(pjdlog_initialized == PJDLOG_INITIALIZED);
502
503         pjdlogv_common(loglevel, 0, errno, fmt, ap);
504 }
505
506 /*
507  * Error logs with errno logging.
508  */
509 void
510 pjdlog_errno(int loglevel, const char *fmt, ...)
511 {
512         va_list ap;
513
514         assert(pjdlog_initialized == PJDLOG_INITIALIZED);
515
516         va_start(ap, fmt);
517         pjdlogv_errno(loglevel, fmt, ap);
518         va_end(ap);
519 }
520
521 /*
522  * Log error, errno and exit.
523  */
524 void
525 pjdlogv_exit(int exitcode, const char *fmt, va_list ap)
526 {
527
528         assert(pjdlog_initialized == PJDLOG_INITIALIZED);
529
530         pjdlogv_errno(LOG_ERR, fmt, ap);
531         exit(exitcode);
532         /* NOTREACHED */
533 }
534
535 /*
536  * Log error, errno and exit.
537  */
538 void
539 pjdlog_exit(int exitcode, const char *fmt, ...)
540 {
541         va_list ap;
542
543         assert(pjdlog_initialized == PJDLOG_INITIALIZED);
544
545         va_start(ap, fmt);
546         pjdlogv_exit(exitcode, fmt, ap);
547         /* NOTREACHED */
548         va_end(ap);
549 }
550
551 /*
552  * Log error and exit.
553  */
554 void
555 pjdlogv_exitx(int exitcode, const char *fmt, va_list ap)
556 {
557
558         assert(pjdlog_initialized == PJDLOG_INITIALIZED);
559
560         pjdlogv(LOG_ERR, fmt, ap);
561         exit(exitcode);
562         /* NOTREACHED */
563 }
564
565 /*
566  * Log error and exit.
567  */
568 void
569 pjdlog_exitx(int exitcode, const char *fmt, ...)
570 {
571         va_list ap;
572
573         assert(pjdlog_initialized == PJDLOG_INITIALIZED);
574
575         va_start(ap, fmt);
576         pjdlogv_exitx(exitcode, fmt, ap);
577         /* NOTREACHED */
578         va_end(ap);
579 }
580
581 /*
582  * Log failure message and exit.
583  */
584 void
585 pjdlog_abort(const char *func, const char *file, int line,
586     const char *failedexpr, const char *fmt, ...)
587 {
588         va_list ap;
589
590         assert(pjdlog_initialized == PJDLOG_INITIALIZED);
591
592         /*
593          * When there is no message we pass __func__ as 'fmt'.
594          * It would be cleaner to pass NULL or "", but gcc generates a warning
595          * for both of those.
596          */
597         if (fmt != func) {
598                 va_start(ap, fmt);
599                 pjdlogv_critical(fmt, ap);
600                 va_end(ap);
601         }
602         if (failedexpr == NULL) {
603                 if (func == NULL) {
604                         pjdlog_critical("Aborted at file %s, line %d.", file,
605                             line);
606                 } else {
607                         pjdlog_critical("Aborted at function %s, file %s, line %d.",
608                             func, file, line);
609                 }
610         } else {
611                 if (func == NULL) {
612                         pjdlog_critical("Assertion failed: (%s), file %s, line %d.",
613                             failedexpr, file, line);
614                 } else {
615                         pjdlog_critical("Assertion failed: (%s), function %s, file %s, line %d.",
616                             failedexpr, func, file, line);
617                 }
618         }
619         abort();
620 }