1*664f4763Szrj /* $OpenBSD: log.c,v 1.51 2018/07/27 12:03:17 markus 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 108*664f4763Szrj LogLevel 109*664f4763Szrj log_level_get(void) 110*664f4763Szrj { 111*664f4763Szrj return log_level; 112*664f4763Szrj } 113*664f4763Szrj 11418de8d7fSPeter Avalos SyslogFacility 11518de8d7fSPeter Avalos log_facility_number(char *name) 11618de8d7fSPeter Avalos { 11718de8d7fSPeter Avalos int i; 11818de8d7fSPeter Avalos 11918de8d7fSPeter Avalos if (name != NULL) 12018de8d7fSPeter Avalos for (i = 0; log_facilities[i].name; i++) 12118de8d7fSPeter Avalos if (strcasecmp(log_facilities[i].name, name) == 0) 12218de8d7fSPeter Avalos return log_facilities[i].val; 12318de8d7fSPeter Avalos return SYSLOG_FACILITY_NOT_SET; 12418de8d7fSPeter Avalos } 12518de8d7fSPeter Avalos 12618de8d7fSPeter Avalos const char * 12718de8d7fSPeter Avalos log_facility_name(SyslogFacility facility) 12818de8d7fSPeter Avalos { 12918de8d7fSPeter Avalos u_int i; 13018de8d7fSPeter Avalos 13118de8d7fSPeter Avalos for (i = 0; log_facilities[i].name; i++) 13218de8d7fSPeter Avalos if (log_facilities[i].val == facility) 13318de8d7fSPeter Avalos return log_facilities[i].name; 13418de8d7fSPeter Avalos return NULL; 13518de8d7fSPeter Avalos } 13618de8d7fSPeter Avalos 13718de8d7fSPeter Avalos LogLevel 13818de8d7fSPeter Avalos log_level_number(char *name) 13918de8d7fSPeter Avalos { 14018de8d7fSPeter Avalos int i; 14118de8d7fSPeter Avalos 14218de8d7fSPeter Avalos if (name != NULL) 14318de8d7fSPeter Avalos for (i = 0; log_levels[i].name; i++) 14418de8d7fSPeter Avalos if (strcasecmp(log_levels[i].name, name) == 0) 14518de8d7fSPeter Avalos return log_levels[i].val; 14618de8d7fSPeter Avalos return SYSLOG_LEVEL_NOT_SET; 14718de8d7fSPeter Avalos } 14818de8d7fSPeter Avalos 14918de8d7fSPeter Avalos const char * 15018de8d7fSPeter Avalos log_level_name(LogLevel level) 15118de8d7fSPeter Avalos { 15218de8d7fSPeter Avalos u_int i; 15318de8d7fSPeter Avalos 15418de8d7fSPeter Avalos for (i = 0; log_levels[i].name != NULL; i++) 15518de8d7fSPeter Avalos if (log_levels[i].val == level) 15618de8d7fSPeter Avalos return log_levels[i].name; 15718de8d7fSPeter Avalos return NULL; 15818de8d7fSPeter Avalos } 15918de8d7fSPeter Avalos 16018de8d7fSPeter Avalos /* Error messages that should be logged. */ 16118de8d7fSPeter Avalos 16218de8d7fSPeter Avalos void 16318de8d7fSPeter Avalos error(const char *fmt,...) 16418de8d7fSPeter Avalos { 16518de8d7fSPeter Avalos va_list args; 16618de8d7fSPeter Avalos 16718de8d7fSPeter Avalos va_start(args, fmt); 16818de8d7fSPeter Avalos do_log(SYSLOG_LEVEL_ERROR, fmt, args); 16918de8d7fSPeter Avalos va_end(args); 17018de8d7fSPeter Avalos } 17118de8d7fSPeter Avalos 17218de8d7fSPeter Avalos void 17318de8d7fSPeter Avalos sigdie(const char *fmt,...) 17418de8d7fSPeter Avalos { 17518de8d7fSPeter Avalos #ifdef DO_LOG_SAFE_IN_SIGHAND 17618de8d7fSPeter Avalos va_list args; 17718de8d7fSPeter Avalos 17818de8d7fSPeter Avalos va_start(args, fmt); 17918de8d7fSPeter Avalos do_log(SYSLOG_LEVEL_FATAL, fmt, args); 18018de8d7fSPeter Avalos va_end(args); 18118de8d7fSPeter Avalos #endif 18218de8d7fSPeter Avalos _exit(1); 18318de8d7fSPeter Avalos } 18418de8d7fSPeter Avalos 185e9778795SPeter Avalos void 186e9778795SPeter Avalos logdie(const char *fmt,...) 187e9778795SPeter Avalos { 188e9778795SPeter Avalos va_list args; 189e9778795SPeter Avalos 190e9778795SPeter Avalos va_start(args, fmt); 191e9778795SPeter Avalos do_log(SYSLOG_LEVEL_INFO, fmt, args); 192e9778795SPeter Avalos va_end(args); 193e9778795SPeter Avalos cleanup_exit(255); 194e9778795SPeter Avalos } 19518de8d7fSPeter Avalos 19618de8d7fSPeter Avalos /* Log this message (information that usually should go to the log). */ 19718de8d7fSPeter Avalos 19818de8d7fSPeter Avalos void 19918de8d7fSPeter Avalos logit(const char *fmt,...) 20018de8d7fSPeter Avalos { 20118de8d7fSPeter Avalos va_list args; 20218de8d7fSPeter Avalos 20318de8d7fSPeter Avalos va_start(args, fmt); 20418de8d7fSPeter Avalos do_log(SYSLOG_LEVEL_INFO, fmt, args); 20518de8d7fSPeter Avalos va_end(args); 20618de8d7fSPeter Avalos } 20718de8d7fSPeter Avalos 20818de8d7fSPeter Avalos /* More detailed messages (information that does not need to go to the log). */ 20918de8d7fSPeter Avalos 21018de8d7fSPeter Avalos void 21118de8d7fSPeter Avalos verbose(const char *fmt,...) 21218de8d7fSPeter Avalos { 21318de8d7fSPeter Avalos va_list args; 21418de8d7fSPeter Avalos 21518de8d7fSPeter Avalos va_start(args, fmt); 21618de8d7fSPeter Avalos do_log(SYSLOG_LEVEL_VERBOSE, fmt, args); 21718de8d7fSPeter Avalos va_end(args); 21818de8d7fSPeter Avalos } 21918de8d7fSPeter Avalos 22018de8d7fSPeter Avalos /* Debugging messages that should not be logged during normal operation. */ 22118de8d7fSPeter Avalos 22218de8d7fSPeter Avalos void 22318de8d7fSPeter Avalos debug(const char *fmt,...) 22418de8d7fSPeter Avalos { 22518de8d7fSPeter Avalos va_list args; 22618de8d7fSPeter Avalos 22718de8d7fSPeter Avalos va_start(args, fmt); 22818de8d7fSPeter Avalos do_log(SYSLOG_LEVEL_DEBUG1, fmt, args); 22918de8d7fSPeter Avalos va_end(args); 23018de8d7fSPeter Avalos } 23118de8d7fSPeter Avalos 23218de8d7fSPeter Avalos void 23318de8d7fSPeter Avalos debug2(const char *fmt,...) 23418de8d7fSPeter Avalos { 23518de8d7fSPeter Avalos va_list args; 23618de8d7fSPeter Avalos 23718de8d7fSPeter Avalos va_start(args, fmt); 23818de8d7fSPeter Avalos do_log(SYSLOG_LEVEL_DEBUG2, fmt, args); 23918de8d7fSPeter Avalos va_end(args); 24018de8d7fSPeter Avalos } 24118de8d7fSPeter Avalos 24218de8d7fSPeter Avalos void 24318de8d7fSPeter Avalos debug3(const char *fmt,...) 24418de8d7fSPeter Avalos { 24518de8d7fSPeter Avalos va_list args; 24618de8d7fSPeter Avalos 24718de8d7fSPeter Avalos va_start(args, fmt); 24818de8d7fSPeter Avalos do_log(SYSLOG_LEVEL_DEBUG3, fmt, args); 24918de8d7fSPeter Avalos va_end(args); 25018de8d7fSPeter Avalos } 25118de8d7fSPeter Avalos 25218de8d7fSPeter Avalos /* 25318de8d7fSPeter Avalos * Initialize the log. 25418de8d7fSPeter Avalos */ 25518de8d7fSPeter Avalos 25618de8d7fSPeter Avalos void 25718de8d7fSPeter Avalos log_init(char *av0, LogLevel level, SyslogFacility facility, int on_stderr) 25818de8d7fSPeter Avalos { 25918de8d7fSPeter Avalos #if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT) 26018de8d7fSPeter Avalos struct syslog_data sdata = SYSLOG_DATA_INIT; 26118de8d7fSPeter Avalos #endif 26218de8d7fSPeter Avalos 26318de8d7fSPeter Avalos argv0 = av0; 26418de8d7fSPeter Avalos 265ce74bacaSMatthew Dillon if (log_change_level(level) != 0) { 26618de8d7fSPeter Avalos fprintf(stderr, "Unrecognized internal syslog level code %d\n", 26718de8d7fSPeter Avalos (int) level); 26818de8d7fSPeter Avalos exit(1); 26918de8d7fSPeter Avalos } 27018de8d7fSPeter Avalos 2711c188a7fSPeter Avalos log_handler = NULL; 2721c188a7fSPeter Avalos log_handler_ctx = NULL; 2731c188a7fSPeter Avalos 27418de8d7fSPeter Avalos log_on_stderr = on_stderr; 27518de8d7fSPeter Avalos if (on_stderr) 27618de8d7fSPeter Avalos return; 27718de8d7fSPeter Avalos 27818de8d7fSPeter Avalos switch (facility) { 27918de8d7fSPeter Avalos case SYSLOG_FACILITY_DAEMON: 28018de8d7fSPeter Avalos log_facility = LOG_DAEMON; 28118de8d7fSPeter Avalos break; 28218de8d7fSPeter Avalos case SYSLOG_FACILITY_USER: 28318de8d7fSPeter Avalos log_facility = LOG_USER; 28418de8d7fSPeter Avalos break; 28518de8d7fSPeter Avalos case SYSLOG_FACILITY_AUTH: 28618de8d7fSPeter Avalos log_facility = LOG_AUTH; 28718de8d7fSPeter Avalos break; 28818de8d7fSPeter Avalos #ifdef LOG_AUTHPRIV 28918de8d7fSPeter Avalos case SYSLOG_FACILITY_AUTHPRIV: 29018de8d7fSPeter Avalos log_facility = LOG_AUTHPRIV; 29118de8d7fSPeter Avalos break; 29218de8d7fSPeter Avalos #endif 29318de8d7fSPeter Avalos case SYSLOG_FACILITY_LOCAL0: 29418de8d7fSPeter Avalos log_facility = LOG_LOCAL0; 29518de8d7fSPeter Avalos break; 29618de8d7fSPeter Avalos case SYSLOG_FACILITY_LOCAL1: 29718de8d7fSPeter Avalos log_facility = LOG_LOCAL1; 29818de8d7fSPeter Avalos break; 29918de8d7fSPeter Avalos case SYSLOG_FACILITY_LOCAL2: 30018de8d7fSPeter Avalos log_facility = LOG_LOCAL2; 30118de8d7fSPeter Avalos break; 30218de8d7fSPeter Avalos case SYSLOG_FACILITY_LOCAL3: 30318de8d7fSPeter Avalos log_facility = LOG_LOCAL3; 30418de8d7fSPeter Avalos break; 30518de8d7fSPeter Avalos case SYSLOG_FACILITY_LOCAL4: 30618de8d7fSPeter Avalos log_facility = LOG_LOCAL4; 30718de8d7fSPeter Avalos break; 30818de8d7fSPeter Avalos case SYSLOG_FACILITY_LOCAL5: 30918de8d7fSPeter Avalos log_facility = LOG_LOCAL5; 31018de8d7fSPeter Avalos break; 31118de8d7fSPeter Avalos case SYSLOG_FACILITY_LOCAL6: 31218de8d7fSPeter Avalos log_facility = LOG_LOCAL6; 31318de8d7fSPeter Avalos break; 31418de8d7fSPeter Avalos case SYSLOG_FACILITY_LOCAL7: 31518de8d7fSPeter Avalos log_facility = LOG_LOCAL7; 31618de8d7fSPeter Avalos break; 31718de8d7fSPeter Avalos default: 31818de8d7fSPeter Avalos fprintf(stderr, 31918de8d7fSPeter Avalos "Unrecognized internal syslog facility code %d\n", 32018de8d7fSPeter Avalos (int) facility); 32118de8d7fSPeter Avalos exit(1); 32218de8d7fSPeter Avalos } 32318de8d7fSPeter Avalos 32418de8d7fSPeter Avalos /* 32518de8d7fSPeter Avalos * If an external library (eg libwrap) attempts to use syslog 32618de8d7fSPeter Avalos * immediately after reexec, syslog may be pointing to the wrong 32718de8d7fSPeter Avalos * facility, so we force an open/close of syslog here. 32818de8d7fSPeter Avalos */ 32918de8d7fSPeter Avalos #if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT) 33018de8d7fSPeter Avalos openlog_r(argv0 ? argv0 : __progname, LOG_PID, log_facility, &sdata); 33118de8d7fSPeter Avalos closelog_r(&sdata); 33218de8d7fSPeter Avalos #else 33318de8d7fSPeter Avalos openlog(argv0 ? argv0 : __progname, LOG_PID, log_facility); 33418de8d7fSPeter Avalos closelog(); 33518de8d7fSPeter Avalos #endif 33618de8d7fSPeter Avalos } 33718de8d7fSPeter Avalos 338ce74bacaSMatthew Dillon int 33936e94dc5SPeter Avalos log_change_level(LogLevel new_log_level) 34036e94dc5SPeter Avalos { 34136e94dc5SPeter Avalos /* no-op if log_init has not been called */ 34236e94dc5SPeter Avalos if (argv0 == NULL) 343ce74bacaSMatthew Dillon return 0; 344ce74bacaSMatthew Dillon 345ce74bacaSMatthew Dillon switch (new_log_level) { 346ce74bacaSMatthew Dillon case SYSLOG_LEVEL_QUIET: 347ce74bacaSMatthew Dillon case SYSLOG_LEVEL_FATAL: 348ce74bacaSMatthew Dillon case SYSLOG_LEVEL_ERROR: 349ce74bacaSMatthew Dillon case SYSLOG_LEVEL_INFO: 350ce74bacaSMatthew Dillon case SYSLOG_LEVEL_VERBOSE: 351ce74bacaSMatthew Dillon case SYSLOG_LEVEL_DEBUG1: 352ce74bacaSMatthew Dillon case SYSLOG_LEVEL_DEBUG2: 353ce74bacaSMatthew Dillon case SYSLOG_LEVEL_DEBUG3: 354ce74bacaSMatthew Dillon log_level = new_log_level; 355ce74bacaSMatthew Dillon return 0; 356ce74bacaSMatthew Dillon default: 357ce74bacaSMatthew Dillon return -1; 358ce74bacaSMatthew Dillon } 35936e94dc5SPeter Avalos } 36036e94dc5SPeter Avalos 36136e94dc5SPeter Avalos int 36236e94dc5SPeter Avalos log_is_on_stderr(void) 36336e94dc5SPeter Avalos { 364e9778795SPeter Avalos return log_on_stderr && log_stderr_fd == STDERR_FILENO; 36536e94dc5SPeter Avalos } 36636e94dc5SPeter Avalos 36736e94dc5SPeter Avalos /* redirect what would usually get written to stderr to specified file */ 36836e94dc5SPeter Avalos void 36936e94dc5SPeter Avalos log_redirect_stderr_to(const char *logfile) 37036e94dc5SPeter Avalos { 37136e94dc5SPeter Avalos int fd; 37236e94dc5SPeter Avalos 37336e94dc5SPeter Avalos if ((fd = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0600)) == -1) { 37436e94dc5SPeter Avalos fprintf(stderr, "Couldn't open logfile %s: %s\n", logfile, 37536e94dc5SPeter Avalos strerror(errno)); 37636e94dc5SPeter Avalos exit(1); 37736e94dc5SPeter Avalos } 37836e94dc5SPeter Avalos log_stderr_fd = fd; 37936e94dc5SPeter Avalos } 38036e94dc5SPeter Avalos 38118de8d7fSPeter Avalos #define MSGBUFSIZ 1024 38218de8d7fSPeter Avalos 38318de8d7fSPeter Avalos void 3841c188a7fSPeter Avalos set_log_handler(log_handler_fn *handler, void *ctx) 3851c188a7fSPeter Avalos { 3861c188a7fSPeter Avalos log_handler = handler; 3871c188a7fSPeter Avalos log_handler_ctx = ctx; 3881c188a7fSPeter Avalos } 3891c188a7fSPeter Avalos 3901c188a7fSPeter Avalos void 3911c188a7fSPeter Avalos do_log2(LogLevel level, const char *fmt,...) 3921c188a7fSPeter Avalos { 3931c188a7fSPeter Avalos va_list args; 3941c188a7fSPeter Avalos 3951c188a7fSPeter Avalos va_start(args, fmt); 3961c188a7fSPeter Avalos do_log(level, fmt, args); 3971c188a7fSPeter Avalos va_end(args); 3981c188a7fSPeter Avalos } 3991c188a7fSPeter Avalos 4001c188a7fSPeter Avalos void 40118de8d7fSPeter Avalos do_log(LogLevel level, const char *fmt, va_list args) 40218de8d7fSPeter Avalos { 40318de8d7fSPeter Avalos #if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT) 40418de8d7fSPeter Avalos struct syslog_data sdata = SYSLOG_DATA_INIT; 40518de8d7fSPeter Avalos #endif 40618de8d7fSPeter Avalos char msgbuf[MSGBUFSIZ]; 40718de8d7fSPeter Avalos char fmtbuf[MSGBUFSIZ]; 40818de8d7fSPeter Avalos char *txt = NULL; 40918de8d7fSPeter Avalos int pri = LOG_INFO; 41018de8d7fSPeter Avalos int saved_errno = errno; 4111c188a7fSPeter Avalos log_handler_fn *tmp_handler; 41218de8d7fSPeter Avalos 41318de8d7fSPeter Avalos if (level > log_level) 41418de8d7fSPeter Avalos return; 41518de8d7fSPeter Avalos 41618de8d7fSPeter Avalos switch (level) { 41718de8d7fSPeter Avalos case SYSLOG_LEVEL_FATAL: 41818de8d7fSPeter Avalos if (!log_on_stderr) 41918de8d7fSPeter Avalos txt = "fatal"; 42018de8d7fSPeter Avalos pri = LOG_CRIT; 42118de8d7fSPeter Avalos break; 42218de8d7fSPeter Avalos case SYSLOG_LEVEL_ERROR: 42318de8d7fSPeter Avalos if (!log_on_stderr) 42418de8d7fSPeter Avalos txt = "error"; 42518de8d7fSPeter Avalos pri = LOG_ERR; 42618de8d7fSPeter Avalos break; 42718de8d7fSPeter Avalos case SYSLOG_LEVEL_INFO: 42818de8d7fSPeter Avalos pri = LOG_INFO; 42918de8d7fSPeter Avalos break; 43018de8d7fSPeter Avalos case SYSLOG_LEVEL_VERBOSE: 43118de8d7fSPeter Avalos pri = LOG_INFO; 43218de8d7fSPeter Avalos break; 43318de8d7fSPeter Avalos case SYSLOG_LEVEL_DEBUG1: 43418de8d7fSPeter Avalos txt = "debug1"; 43518de8d7fSPeter Avalos pri = LOG_DEBUG; 43618de8d7fSPeter Avalos break; 43718de8d7fSPeter Avalos case SYSLOG_LEVEL_DEBUG2: 43818de8d7fSPeter Avalos txt = "debug2"; 43918de8d7fSPeter Avalos pri = LOG_DEBUG; 44018de8d7fSPeter Avalos break; 44118de8d7fSPeter Avalos case SYSLOG_LEVEL_DEBUG3: 44218de8d7fSPeter Avalos txt = "debug3"; 44318de8d7fSPeter Avalos pri = LOG_DEBUG; 44418de8d7fSPeter Avalos break; 44518de8d7fSPeter Avalos default: 44618de8d7fSPeter Avalos txt = "internal error"; 44718de8d7fSPeter Avalos pri = LOG_ERR; 44818de8d7fSPeter Avalos break; 44918de8d7fSPeter Avalos } 4501c188a7fSPeter Avalos if (txt != NULL && log_handler == NULL) { 45118de8d7fSPeter Avalos snprintf(fmtbuf, sizeof(fmtbuf), "%s: %s", txt, fmt); 45218de8d7fSPeter Avalos vsnprintf(msgbuf, sizeof(msgbuf), fmtbuf, args); 45318de8d7fSPeter Avalos } else { 45418de8d7fSPeter Avalos vsnprintf(msgbuf, sizeof(msgbuf), fmt, args); 45518de8d7fSPeter Avalos } 45618de8d7fSPeter Avalos strnvis(fmtbuf, msgbuf, sizeof(fmtbuf), 45718de8d7fSPeter Avalos log_on_stderr ? LOG_STDERR_VIS : LOG_SYSLOG_VIS); 4581c188a7fSPeter Avalos if (log_handler != NULL) { 4591c188a7fSPeter Avalos /* Avoid recursion */ 4601c188a7fSPeter Avalos tmp_handler = log_handler; 4611c188a7fSPeter Avalos log_handler = NULL; 4621c188a7fSPeter Avalos tmp_handler(level, fmtbuf, log_handler_ctx); 4631c188a7fSPeter Avalos log_handler = tmp_handler; 4641c188a7fSPeter Avalos } else if (log_on_stderr) { 465ce74bacaSMatthew Dillon snprintf(msgbuf, sizeof msgbuf, "%.*s\r\n", 466ce74bacaSMatthew Dillon (int)sizeof msgbuf - 3, fmtbuf); 46736e94dc5SPeter Avalos (void)write(log_stderr_fd, msgbuf, strlen(msgbuf)); 46818de8d7fSPeter Avalos } else { 46918de8d7fSPeter Avalos #if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT) 47018de8d7fSPeter Avalos openlog_r(argv0 ? argv0 : __progname, LOG_PID, log_facility, &sdata); 47118de8d7fSPeter Avalos syslog_r(pri, &sdata, "%.500s", fmtbuf); 47218de8d7fSPeter Avalos closelog_r(&sdata); 47318de8d7fSPeter Avalos #else 47418de8d7fSPeter Avalos openlog(argv0 ? argv0 : __progname, LOG_PID, log_facility); 47518de8d7fSPeter Avalos syslog(pri, "%.500s", fmtbuf); 47618de8d7fSPeter Avalos closelog(); 47718de8d7fSPeter Avalos #endif 47818de8d7fSPeter Avalos } 47918de8d7fSPeter Avalos errno = saved_errno; 48018de8d7fSPeter Avalos } 481