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