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