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