1*ce74bacaSMatthew Dillon /* $OpenBSD: log.c,v 1.50 2017/05/17 01:24:17 djm Exp $ */ 218de8d7fSPeter Avalos /* 318de8d7fSPeter Avalos * Author: Tatu Ylonen <ylo@cs.hut.fi> 418de8d7fSPeter Avalos * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 518de8d7fSPeter Avalos * All rights reserved 618de8d7fSPeter Avalos * 718de8d7fSPeter Avalos * As far as I am concerned, the code I have written for this software 818de8d7fSPeter Avalos * can be used freely for any purpose. Any derived versions of this 918de8d7fSPeter Avalos * software must be clearly marked as such, and if the derived work is 1018de8d7fSPeter Avalos * incompatible with the protocol description in the RFC file, it must be 1118de8d7fSPeter Avalos * called by a name other than "ssh" or "Secure Shell". 1218de8d7fSPeter Avalos */ 1318de8d7fSPeter Avalos /* 1418de8d7fSPeter Avalos * Copyright (c) 2000 Markus Friedl. All rights reserved. 1518de8d7fSPeter Avalos * 1618de8d7fSPeter Avalos * Redistribution and use in source and binary forms, with or without 1718de8d7fSPeter Avalos * modification, are permitted provided that the following conditions 1818de8d7fSPeter Avalos * are met: 1918de8d7fSPeter Avalos * 1. Redistributions of source code must retain the above copyright 2018de8d7fSPeter Avalos * notice, this list of conditions and the following disclaimer. 2118de8d7fSPeter Avalos * 2. Redistributions in binary form must reproduce the above copyright 2218de8d7fSPeter Avalos * notice, this list of conditions and the following disclaimer in the 2318de8d7fSPeter Avalos * documentation and/or other materials provided with the distribution. 2418de8d7fSPeter Avalos * 2518de8d7fSPeter Avalos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 2618de8d7fSPeter Avalos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2718de8d7fSPeter Avalos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2818de8d7fSPeter Avalos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2918de8d7fSPeter Avalos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 3018de8d7fSPeter Avalos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3118de8d7fSPeter Avalos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3218de8d7fSPeter Avalos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3318de8d7fSPeter Avalos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3418de8d7fSPeter Avalos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3518de8d7fSPeter Avalos */ 3618de8d7fSPeter Avalos 3718de8d7fSPeter Avalos #include "includes.h" 3818de8d7fSPeter Avalos 3918de8d7fSPeter Avalos #include <sys/types.h> 4018de8d7fSPeter Avalos 4136e94dc5SPeter Avalos #include <fcntl.h> 4218de8d7fSPeter Avalos #include <stdarg.h> 4318de8d7fSPeter Avalos #include <stdio.h> 4418de8d7fSPeter Avalos #include <stdlib.h> 4518de8d7fSPeter Avalos #include <string.h> 4618de8d7fSPeter Avalos #include <syslog.h> 4718de8d7fSPeter Avalos #include <unistd.h> 4818de8d7fSPeter Avalos #include <errno.h> 4936e94dc5SPeter Avalos #if defined(HAVE_STRNVIS) && defined(HAVE_VIS_H) && !defined(BROKEN_STRNVIS) 5018de8d7fSPeter Avalos # include <vis.h> 5118de8d7fSPeter Avalos #endif 5218de8d7fSPeter Avalos 5318de8d7fSPeter Avalos #include "log.h" 5418de8d7fSPeter Avalos 5518de8d7fSPeter Avalos static LogLevel log_level = SYSLOG_LEVEL_INFO; 5618de8d7fSPeter Avalos static int log_on_stderr = 1; 5736e94dc5SPeter Avalos static int log_stderr_fd = STDERR_FILENO; 5818de8d7fSPeter Avalos static int log_facility = LOG_AUTH; 5918de8d7fSPeter Avalos static char *argv0; 601c188a7fSPeter Avalos static log_handler_fn *log_handler; 611c188a7fSPeter Avalos static void *log_handler_ctx; 6218de8d7fSPeter Avalos 6318de8d7fSPeter Avalos extern char *__progname; 6418de8d7fSPeter Avalos 6518de8d7fSPeter Avalos #define LOG_SYSLOG_VIS (VIS_CSTYLE|VIS_NL|VIS_TAB|VIS_OCTAL) 6618de8d7fSPeter Avalos #define LOG_STDERR_VIS (VIS_SAFE|VIS_OCTAL) 6718de8d7fSPeter Avalos 6818de8d7fSPeter Avalos /* textual representation of log-facilities/levels */ 6918de8d7fSPeter Avalos 7018de8d7fSPeter Avalos static struct { 7118de8d7fSPeter Avalos const char *name; 7218de8d7fSPeter Avalos SyslogFacility val; 7318de8d7fSPeter Avalos } log_facilities[] = { 7418de8d7fSPeter Avalos { "DAEMON", SYSLOG_FACILITY_DAEMON }, 7518de8d7fSPeter Avalos { "USER", SYSLOG_FACILITY_USER }, 7618de8d7fSPeter Avalos { "AUTH", SYSLOG_FACILITY_AUTH }, 7718de8d7fSPeter Avalos #ifdef LOG_AUTHPRIV 7818de8d7fSPeter Avalos { "AUTHPRIV", SYSLOG_FACILITY_AUTHPRIV }, 7918de8d7fSPeter Avalos #endif 8018de8d7fSPeter Avalos { "LOCAL0", SYSLOG_FACILITY_LOCAL0 }, 8118de8d7fSPeter Avalos { "LOCAL1", SYSLOG_FACILITY_LOCAL1 }, 8218de8d7fSPeter Avalos { "LOCAL2", SYSLOG_FACILITY_LOCAL2 }, 8318de8d7fSPeter Avalos { "LOCAL3", SYSLOG_FACILITY_LOCAL3 }, 8418de8d7fSPeter Avalos { "LOCAL4", SYSLOG_FACILITY_LOCAL4 }, 8518de8d7fSPeter Avalos { "LOCAL5", SYSLOG_FACILITY_LOCAL5 }, 8618de8d7fSPeter Avalos { "LOCAL6", SYSLOG_FACILITY_LOCAL6 }, 8718de8d7fSPeter Avalos { "LOCAL7", SYSLOG_FACILITY_LOCAL7 }, 8818de8d7fSPeter Avalos { NULL, SYSLOG_FACILITY_NOT_SET } 8918de8d7fSPeter Avalos }; 9018de8d7fSPeter Avalos 9118de8d7fSPeter Avalos static struct { 9218de8d7fSPeter Avalos const char *name; 9318de8d7fSPeter Avalos LogLevel val; 9418de8d7fSPeter Avalos } log_levels[] = 9518de8d7fSPeter Avalos { 9618de8d7fSPeter Avalos { "QUIET", SYSLOG_LEVEL_QUIET }, 9718de8d7fSPeter Avalos { "FATAL", SYSLOG_LEVEL_FATAL }, 9818de8d7fSPeter Avalos { "ERROR", SYSLOG_LEVEL_ERROR }, 9918de8d7fSPeter Avalos { "INFO", SYSLOG_LEVEL_INFO }, 10018de8d7fSPeter Avalos { "VERBOSE", SYSLOG_LEVEL_VERBOSE }, 10118de8d7fSPeter Avalos { "DEBUG", SYSLOG_LEVEL_DEBUG1 }, 10218de8d7fSPeter Avalos { "DEBUG1", SYSLOG_LEVEL_DEBUG1 }, 10318de8d7fSPeter Avalos { "DEBUG2", SYSLOG_LEVEL_DEBUG2 }, 10418de8d7fSPeter Avalos { "DEBUG3", SYSLOG_LEVEL_DEBUG3 }, 10518de8d7fSPeter Avalos { NULL, SYSLOG_LEVEL_NOT_SET } 10618de8d7fSPeter Avalos }; 10718de8d7fSPeter Avalos 10818de8d7fSPeter Avalos SyslogFacility 10918de8d7fSPeter Avalos log_facility_number(char *name) 11018de8d7fSPeter Avalos { 11118de8d7fSPeter Avalos int i; 11218de8d7fSPeter Avalos 11318de8d7fSPeter Avalos if (name != NULL) 11418de8d7fSPeter Avalos for (i = 0; log_facilities[i].name; i++) 11518de8d7fSPeter Avalos if (strcasecmp(log_facilities[i].name, name) == 0) 11618de8d7fSPeter Avalos return log_facilities[i].val; 11718de8d7fSPeter Avalos return SYSLOG_FACILITY_NOT_SET; 11818de8d7fSPeter Avalos } 11918de8d7fSPeter Avalos 12018de8d7fSPeter Avalos const char * 12118de8d7fSPeter Avalos log_facility_name(SyslogFacility facility) 12218de8d7fSPeter Avalos { 12318de8d7fSPeter Avalos u_int i; 12418de8d7fSPeter Avalos 12518de8d7fSPeter Avalos for (i = 0; log_facilities[i].name; i++) 12618de8d7fSPeter Avalos if (log_facilities[i].val == facility) 12718de8d7fSPeter Avalos return log_facilities[i].name; 12818de8d7fSPeter Avalos return NULL; 12918de8d7fSPeter Avalos } 13018de8d7fSPeter Avalos 13118de8d7fSPeter Avalos LogLevel 13218de8d7fSPeter Avalos log_level_number(char *name) 13318de8d7fSPeter Avalos { 13418de8d7fSPeter Avalos int i; 13518de8d7fSPeter Avalos 13618de8d7fSPeter Avalos if (name != NULL) 13718de8d7fSPeter Avalos for (i = 0; log_levels[i].name; i++) 13818de8d7fSPeter Avalos if (strcasecmp(log_levels[i].name, name) == 0) 13918de8d7fSPeter Avalos return log_levels[i].val; 14018de8d7fSPeter Avalos return SYSLOG_LEVEL_NOT_SET; 14118de8d7fSPeter Avalos } 14218de8d7fSPeter Avalos 14318de8d7fSPeter Avalos const char * 14418de8d7fSPeter Avalos log_level_name(LogLevel level) 14518de8d7fSPeter Avalos { 14618de8d7fSPeter Avalos u_int i; 14718de8d7fSPeter Avalos 14818de8d7fSPeter Avalos for (i = 0; log_levels[i].name != NULL; i++) 14918de8d7fSPeter Avalos if (log_levels[i].val == level) 15018de8d7fSPeter Avalos return log_levels[i].name; 15118de8d7fSPeter Avalos return NULL; 15218de8d7fSPeter Avalos } 15318de8d7fSPeter Avalos 15418de8d7fSPeter Avalos /* Error messages that should be logged. */ 15518de8d7fSPeter Avalos 15618de8d7fSPeter Avalos void 15718de8d7fSPeter Avalos error(const char *fmt,...) 15818de8d7fSPeter Avalos { 15918de8d7fSPeter Avalos va_list args; 16018de8d7fSPeter Avalos 16118de8d7fSPeter Avalos va_start(args, fmt); 16218de8d7fSPeter Avalos do_log(SYSLOG_LEVEL_ERROR, fmt, args); 16318de8d7fSPeter Avalos va_end(args); 16418de8d7fSPeter Avalos } 16518de8d7fSPeter Avalos 16618de8d7fSPeter Avalos void 16718de8d7fSPeter Avalos sigdie(const char *fmt,...) 16818de8d7fSPeter Avalos { 16918de8d7fSPeter Avalos #ifdef DO_LOG_SAFE_IN_SIGHAND 17018de8d7fSPeter Avalos va_list args; 17118de8d7fSPeter Avalos 17218de8d7fSPeter Avalos va_start(args, fmt); 17318de8d7fSPeter Avalos do_log(SYSLOG_LEVEL_FATAL, fmt, args); 17418de8d7fSPeter Avalos va_end(args); 17518de8d7fSPeter Avalos #endif 17618de8d7fSPeter Avalos _exit(1); 17718de8d7fSPeter Avalos } 17818de8d7fSPeter Avalos 179e9778795SPeter Avalos void 180e9778795SPeter Avalos logdie(const char *fmt,...) 181e9778795SPeter Avalos { 182e9778795SPeter Avalos va_list args; 183e9778795SPeter Avalos 184e9778795SPeter Avalos va_start(args, fmt); 185e9778795SPeter Avalos do_log(SYSLOG_LEVEL_INFO, fmt, args); 186e9778795SPeter Avalos va_end(args); 187e9778795SPeter Avalos cleanup_exit(255); 188e9778795SPeter Avalos } 18918de8d7fSPeter Avalos 19018de8d7fSPeter Avalos /* Log this message (information that usually should go to the log). */ 19118de8d7fSPeter Avalos 19218de8d7fSPeter Avalos void 19318de8d7fSPeter Avalos logit(const char *fmt,...) 19418de8d7fSPeter Avalos { 19518de8d7fSPeter Avalos va_list args; 19618de8d7fSPeter Avalos 19718de8d7fSPeter Avalos va_start(args, fmt); 19818de8d7fSPeter Avalos do_log(SYSLOG_LEVEL_INFO, fmt, args); 19918de8d7fSPeter Avalos va_end(args); 20018de8d7fSPeter Avalos } 20118de8d7fSPeter Avalos 20218de8d7fSPeter Avalos /* More detailed messages (information that does not need to go to the log). */ 20318de8d7fSPeter Avalos 20418de8d7fSPeter Avalos void 20518de8d7fSPeter Avalos verbose(const char *fmt,...) 20618de8d7fSPeter Avalos { 20718de8d7fSPeter Avalos va_list args; 20818de8d7fSPeter Avalos 20918de8d7fSPeter Avalos va_start(args, fmt); 21018de8d7fSPeter Avalos do_log(SYSLOG_LEVEL_VERBOSE, fmt, args); 21118de8d7fSPeter Avalos va_end(args); 21218de8d7fSPeter Avalos } 21318de8d7fSPeter Avalos 21418de8d7fSPeter Avalos /* Debugging messages that should not be logged during normal operation. */ 21518de8d7fSPeter Avalos 21618de8d7fSPeter Avalos void 21718de8d7fSPeter Avalos debug(const char *fmt,...) 21818de8d7fSPeter Avalos { 21918de8d7fSPeter Avalos va_list args; 22018de8d7fSPeter Avalos 22118de8d7fSPeter Avalos va_start(args, fmt); 22218de8d7fSPeter Avalos do_log(SYSLOG_LEVEL_DEBUG1, fmt, args); 22318de8d7fSPeter Avalos va_end(args); 22418de8d7fSPeter Avalos } 22518de8d7fSPeter Avalos 22618de8d7fSPeter Avalos void 22718de8d7fSPeter Avalos debug2(const char *fmt,...) 22818de8d7fSPeter Avalos { 22918de8d7fSPeter Avalos va_list args; 23018de8d7fSPeter Avalos 23118de8d7fSPeter Avalos va_start(args, fmt); 23218de8d7fSPeter Avalos do_log(SYSLOG_LEVEL_DEBUG2, fmt, args); 23318de8d7fSPeter Avalos va_end(args); 23418de8d7fSPeter Avalos } 23518de8d7fSPeter Avalos 23618de8d7fSPeter Avalos void 23718de8d7fSPeter Avalos debug3(const char *fmt,...) 23818de8d7fSPeter Avalos { 23918de8d7fSPeter Avalos va_list args; 24018de8d7fSPeter Avalos 24118de8d7fSPeter Avalos va_start(args, fmt); 24218de8d7fSPeter Avalos do_log(SYSLOG_LEVEL_DEBUG3, fmt, args); 24318de8d7fSPeter Avalos va_end(args); 24418de8d7fSPeter Avalos } 24518de8d7fSPeter Avalos 24618de8d7fSPeter Avalos /* 24718de8d7fSPeter Avalos * Initialize the log. 24818de8d7fSPeter Avalos */ 24918de8d7fSPeter Avalos 25018de8d7fSPeter Avalos void 25118de8d7fSPeter Avalos log_init(char *av0, LogLevel level, SyslogFacility facility, int on_stderr) 25218de8d7fSPeter Avalos { 25318de8d7fSPeter Avalos #if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT) 25418de8d7fSPeter Avalos struct syslog_data sdata = SYSLOG_DATA_INIT; 25518de8d7fSPeter Avalos #endif 25618de8d7fSPeter Avalos 25718de8d7fSPeter Avalos argv0 = av0; 25818de8d7fSPeter Avalos 259*ce74bacaSMatthew Dillon if (log_change_level(level) != 0) { 26018de8d7fSPeter Avalos fprintf(stderr, "Unrecognized internal syslog level code %d\n", 26118de8d7fSPeter Avalos (int) level); 26218de8d7fSPeter Avalos exit(1); 26318de8d7fSPeter Avalos } 26418de8d7fSPeter Avalos 2651c188a7fSPeter Avalos log_handler = NULL; 2661c188a7fSPeter Avalos log_handler_ctx = NULL; 2671c188a7fSPeter Avalos 26818de8d7fSPeter Avalos log_on_stderr = on_stderr; 26918de8d7fSPeter Avalos if (on_stderr) 27018de8d7fSPeter Avalos return; 27118de8d7fSPeter Avalos 27218de8d7fSPeter Avalos switch (facility) { 27318de8d7fSPeter Avalos case SYSLOG_FACILITY_DAEMON: 27418de8d7fSPeter Avalos log_facility = LOG_DAEMON; 27518de8d7fSPeter Avalos break; 27618de8d7fSPeter Avalos case SYSLOG_FACILITY_USER: 27718de8d7fSPeter Avalos log_facility = LOG_USER; 27818de8d7fSPeter Avalos break; 27918de8d7fSPeter Avalos case SYSLOG_FACILITY_AUTH: 28018de8d7fSPeter Avalos log_facility = LOG_AUTH; 28118de8d7fSPeter Avalos break; 28218de8d7fSPeter Avalos #ifdef LOG_AUTHPRIV 28318de8d7fSPeter Avalos case SYSLOG_FACILITY_AUTHPRIV: 28418de8d7fSPeter Avalos log_facility = LOG_AUTHPRIV; 28518de8d7fSPeter Avalos break; 28618de8d7fSPeter Avalos #endif 28718de8d7fSPeter Avalos case SYSLOG_FACILITY_LOCAL0: 28818de8d7fSPeter Avalos log_facility = LOG_LOCAL0; 28918de8d7fSPeter Avalos break; 29018de8d7fSPeter Avalos case SYSLOG_FACILITY_LOCAL1: 29118de8d7fSPeter Avalos log_facility = LOG_LOCAL1; 29218de8d7fSPeter Avalos break; 29318de8d7fSPeter Avalos case SYSLOG_FACILITY_LOCAL2: 29418de8d7fSPeter Avalos log_facility = LOG_LOCAL2; 29518de8d7fSPeter Avalos break; 29618de8d7fSPeter Avalos case SYSLOG_FACILITY_LOCAL3: 29718de8d7fSPeter Avalos log_facility = LOG_LOCAL3; 29818de8d7fSPeter Avalos break; 29918de8d7fSPeter Avalos case SYSLOG_FACILITY_LOCAL4: 30018de8d7fSPeter Avalos log_facility = LOG_LOCAL4; 30118de8d7fSPeter Avalos break; 30218de8d7fSPeter Avalos case SYSLOG_FACILITY_LOCAL5: 30318de8d7fSPeter Avalos log_facility = LOG_LOCAL5; 30418de8d7fSPeter Avalos break; 30518de8d7fSPeter Avalos case SYSLOG_FACILITY_LOCAL6: 30618de8d7fSPeter Avalos log_facility = LOG_LOCAL6; 30718de8d7fSPeter Avalos break; 30818de8d7fSPeter Avalos case SYSLOG_FACILITY_LOCAL7: 30918de8d7fSPeter Avalos log_facility = LOG_LOCAL7; 31018de8d7fSPeter Avalos break; 31118de8d7fSPeter Avalos default: 31218de8d7fSPeter Avalos fprintf(stderr, 31318de8d7fSPeter Avalos "Unrecognized internal syslog facility code %d\n", 31418de8d7fSPeter Avalos (int) facility); 31518de8d7fSPeter Avalos exit(1); 31618de8d7fSPeter Avalos } 31718de8d7fSPeter Avalos 31818de8d7fSPeter Avalos /* 31918de8d7fSPeter Avalos * If an external library (eg libwrap) attempts to use syslog 32018de8d7fSPeter Avalos * immediately after reexec, syslog may be pointing to the wrong 32118de8d7fSPeter Avalos * facility, so we force an open/close of syslog here. 32218de8d7fSPeter Avalos */ 32318de8d7fSPeter Avalos #if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT) 32418de8d7fSPeter Avalos openlog_r(argv0 ? argv0 : __progname, LOG_PID, log_facility, &sdata); 32518de8d7fSPeter Avalos closelog_r(&sdata); 32618de8d7fSPeter Avalos #else 32718de8d7fSPeter Avalos openlog(argv0 ? argv0 : __progname, LOG_PID, log_facility); 32818de8d7fSPeter Avalos closelog(); 32918de8d7fSPeter Avalos #endif 33018de8d7fSPeter Avalos } 33118de8d7fSPeter Avalos 332*ce74bacaSMatthew Dillon int 33336e94dc5SPeter Avalos log_change_level(LogLevel new_log_level) 33436e94dc5SPeter Avalos { 33536e94dc5SPeter Avalos /* no-op if log_init has not been called */ 33636e94dc5SPeter Avalos if (argv0 == NULL) 337*ce74bacaSMatthew Dillon return 0; 338*ce74bacaSMatthew Dillon 339*ce74bacaSMatthew Dillon switch (new_log_level) { 340*ce74bacaSMatthew Dillon case SYSLOG_LEVEL_QUIET: 341*ce74bacaSMatthew Dillon case SYSLOG_LEVEL_FATAL: 342*ce74bacaSMatthew Dillon case SYSLOG_LEVEL_ERROR: 343*ce74bacaSMatthew Dillon case SYSLOG_LEVEL_INFO: 344*ce74bacaSMatthew Dillon case SYSLOG_LEVEL_VERBOSE: 345*ce74bacaSMatthew Dillon case SYSLOG_LEVEL_DEBUG1: 346*ce74bacaSMatthew Dillon case SYSLOG_LEVEL_DEBUG2: 347*ce74bacaSMatthew Dillon case SYSLOG_LEVEL_DEBUG3: 348*ce74bacaSMatthew Dillon log_level = new_log_level; 349*ce74bacaSMatthew Dillon return 0; 350*ce74bacaSMatthew Dillon default: 351*ce74bacaSMatthew Dillon return -1; 352*ce74bacaSMatthew Dillon } 35336e94dc5SPeter Avalos } 35436e94dc5SPeter Avalos 35536e94dc5SPeter Avalos int 35636e94dc5SPeter Avalos log_is_on_stderr(void) 35736e94dc5SPeter Avalos { 358e9778795SPeter Avalos return log_on_stderr && log_stderr_fd == STDERR_FILENO; 35936e94dc5SPeter Avalos } 36036e94dc5SPeter Avalos 36136e94dc5SPeter Avalos /* redirect what would usually get written to stderr to specified file */ 36236e94dc5SPeter Avalos void 36336e94dc5SPeter Avalos log_redirect_stderr_to(const char *logfile) 36436e94dc5SPeter Avalos { 36536e94dc5SPeter Avalos int fd; 36636e94dc5SPeter Avalos 36736e94dc5SPeter Avalos if ((fd = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0600)) == -1) { 36836e94dc5SPeter Avalos fprintf(stderr, "Couldn't open logfile %s: %s\n", logfile, 36936e94dc5SPeter Avalos strerror(errno)); 37036e94dc5SPeter Avalos exit(1); 37136e94dc5SPeter Avalos } 37236e94dc5SPeter Avalos log_stderr_fd = fd; 37336e94dc5SPeter Avalos } 37436e94dc5SPeter Avalos 37518de8d7fSPeter Avalos #define MSGBUFSIZ 1024 37618de8d7fSPeter Avalos 37718de8d7fSPeter Avalos void 3781c188a7fSPeter Avalos set_log_handler(log_handler_fn *handler, void *ctx) 3791c188a7fSPeter Avalos { 3801c188a7fSPeter Avalos log_handler = handler; 3811c188a7fSPeter Avalos log_handler_ctx = ctx; 3821c188a7fSPeter Avalos } 3831c188a7fSPeter Avalos 3841c188a7fSPeter Avalos void 3851c188a7fSPeter Avalos do_log2(LogLevel level, const char *fmt,...) 3861c188a7fSPeter Avalos { 3871c188a7fSPeter Avalos va_list args; 3881c188a7fSPeter Avalos 3891c188a7fSPeter Avalos va_start(args, fmt); 3901c188a7fSPeter Avalos do_log(level, fmt, args); 3911c188a7fSPeter Avalos va_end(args); 3921c188a7fSPeter Avalos } 3931c188a7fSPeter Avalos 3941c188a7fSPeter Avalos void 39518de8d7fSPeter Avalos do_log(LogLevel level, const char *fmt, va_list args) 39618de8d7fSPeter Avalos { 39718de8d7fSPeter Avalos #if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT) 39818de8d7fSPeter Avalos struct syslog_data sdata = SYSLOG_DATA_INIT; 39918de8d7fSPeter Avalos #endif 40018de8d7fSPeter Avalos char msgbuf[MSGBUFSIZ]; 40118de8d7fSPeter Avalos char fmtbuf[MSGBUFSIZ]; 40218de8d7fSPeter Avalos char *txt = NULL; 40318de8d7fSPeter Avalos int pri = LOG_INFO; 40418de8d7fSPeter Avalos int saved_errno = errno; 4051c188a7fSPeter Avalos log_handler_fn *tmp_handler; 40618de8d7fSPeter Avalos 40718de8d7fSPeter Avalos if (level > log_level) 40818de8d7fSPeter Avalos return; 40918de8d7fSPeter Avalos 41018de8d7fSPeter Avalos switch (level) { 41118de8d7fSPeter Avalos case SYSLOG_LEVEL_FATAL: 41218de8d7fSPeter Avalos if (!log_on_stderr) 41318de8d7fSPeter Avalos txt = "fatal"; 41418de8d7fSPeter Avalos pri = LOG_CRIT; 41518de8d7fSPeter Avalos break; 41618de8d7fSPeter Avalos case SYSLOG_LEVEL_ERROR: 41718de8d7fSPeter Avalos if (!log_on_stderr) 41818de8d7fSPeter Avalos txt = "error"; 41918de8d7fSPeter Avalos pri = LOG_ERR; 42018de8d7fSPeter Avalos break; 42118de8d7fSPeter Avalos case SYSLOG_LEVEL_INFO: 42218de8d7fSPeter Avalos pri = LOG_INFO; 42318de8d7fSPeter Avalos break; 42418de8d7fSPeter Avalos case SYSLOG_LEVEL_VERBOSE: 42518de8d7fSPeter Avalos pri = LOG_INFO; 42618de8d7fSPeter Avalos break; 42718de8d7fSPeter Avalos case SYSLOG_LEVEL_DEBUG1: 42818de8d7fSPeter Avalos txt = "debug1"; 42918de8d7fSPeter Avalos pri = LOG_DEBUG; 43018de8d7fSPeter Avalos break; 43118de8d7fSPeter Avalos case SYSLOG_LEVEL_DEBUG2: 43218de8d7fSPeter Avalos txt = "debug2"; 43318de8d7fSPeter Avalos pri = LOG_DEBUG; 43418de8d7fSPeter Avalos break; 43518de8d7fSPeter Avalos case SYSLOG_LEVEL_DEBUG3: 43618de8d7fSPeter Avalos txt = "debug3"; 43718de8d7fSPeter Avalos pri = LOG_DEBUG; 43818de8d7fSPeter Avalos break; 43918de8d7fSPeter Avalos default: 44018de8d7fSPeter Avalos txt = "internal error"; 44118de8d7fSPeter Avalos pri = LOG_ERR; 44218de8d7fSPeter Avalos break; 44318de8d7fSPeter Avalos } 4441c188a7fSPeter Avalos if (txt != NULL && log_handler == NULL) { 44518de8d7fSPeter Avalos snprintf(fmtbuf, sizeof(fmtbuf), "%s: %s", txt, fmt); 44618de8d7fSPeter Avalos vsnprintf(msgbuf, sizeof(msgbuf), fmtbuf, args); 44718de8d7fSPeter Avalos } else { 44818de8d7fSPeter Avalos vsnprintf(msgbuf, sizeof(msgbuf), fmt, args); 44918de8d7fSPeter Avalos } 45018de8d7fSPeter Avalos strnvis(fmtbuf, msgbuf, sizeof(fmtbuf), 45118de8d7fSPeter Avalos log_on_stderr ? LOG_STDERR_VIS : LOG_SYSLOG_VIS); 4521c188a7fSPeter Avalos if (log_handler != NULL) { 4531c188a7fSPeter Avalos /* Avoid recursion */ 4541c188a7fSPeter Avalos tmp_handler = log_handler; 4551c188a7fSPeter Avalos log_handler = NULL; 4561c188a7fSPeter Avalos tmp_handler(level, fmtbuf, log_handler_ctx); 4571c188a7fSPeter Avalos log_handler = tmp_handler; 4581c188a7fSPeter Avalos } else if (log_on_stderr) { 459*ce74bacaSMatthew Dillon snprintf(msgbuf, sizeof msgbuf, "%.*s\r\n", 460*ce74bacaSMatthew Dillon (int)sizeof msgbuf - 3, fmtbuf); 46136e94dc5SPeter Avalos (void)write(log_stderr_fd, msgbuf, strlen(msgbuf)); 46218de8d7fSPeter Avalos } else { 46318de8d7fSPeter Avalos #if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT) 46418de8d7fSPeter Avalos openlog_r(argv0 ? argv0 : __progname, LOG_PID, log_facility, &sdata); 46518de8d7fSPeter Avalos syslog_r(pri, &sdata, "%.500s", fmtbuf); 46618de8d7fSPeter Avalos closelog_r(&sdata); 46718de8d7fSPeter Avalos #else 46818de8d7fSPeter Avalos openlog(argv0 ? argv0 : __progname, LOG_PID, log_facility); 46918de8d7fSPeter Avalos syslog(pri, "%.500s", fmtbuf); 47018de8d7fSPeter Avalos closelog(); 47118de8d7fSPeter Avalos #endif 47218de8d7fSPeter Avalos } 47318de8d7fSPeter Avalos errno = saved_errno; 47418de8d7fSPeter Avalos } 475