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 } 621