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 58 static int pjdlog_initialized = PJDLOG_NEVER_INITIALIZED; 59 static int pjdlog_mode, pjdlog_debug_level; 60 static char pjdlog_prefix[128]; 61 62 #ifdef __FreeBSD__ 63 static int 64 pjdlog_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 73 static int 74 pjdlog_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 89 static int 90 pjdlog_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 99 static int 100 pjdlog_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 152 void 153 pjdlog_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 187 void 188 pjdlog_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 */ 210 void 211 pjdlog_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 */ 236 int 237 pjdlog_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 */ 249 void 250 pjdlog_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 */ 262 int 263 pjdlog_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 */ 275 void 276 pjdlog_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 */ 291 void 292 pjdlogv_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 */ 309 static const char * 310 pjdlog_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 */ 338 void 339 pjdlog_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 */ 354 void 355 pjdlogv_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 */ 438 void 439 pjdlogv(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 */ 456 void 457 pjdlog(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 */ 471 void 472 pjdlogv_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 */ 483 void 484 pjdlog_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 */ 498 void 499 pjdlogv_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 */ 510 void 511 pjdlog_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 */ 525 void 526 pjdlogv_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 */ 539 void 540 pjdlog_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 */ 555 void 556 pjdlogv_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 */ 569 void 570 pjdlog_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 */ 585 void 586 pjdlog_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