|  | /* | 
|  | * Copyright (C) Tildeslash Ltd. All rights reserved. | 
|  | * | 
|  | * This program is free software: you can redistribute it and/or modify | 
|  | * it under the terms of the GNU Affero General Public License version 3. | 
|  | * | 
|  | * This program is distributed in the hope that it will be useful, | 
|  | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | * GNU General Public License for more details. | 
|  | * | 
|  | * You should have received a copy of the GNU Affero General Public License | 
|  | * along with this program.  If not, see <http://www.gnu.org/licenses/>. | 
|  | * | 
|  | * In addition, as a special exception, the copyright holders give | 
|  | * permission to link the code of portions of this program with the | 
|  | * OpenSSL library under certain conditions as described in each | 
|  | * individual source file, and distribute linked combinations | 
|  | * including the two. | 
|  | * | 
|  | * You must obey the GNU Affero General Public License in all respects | 
|  | * for all of the code used other than OpenSSL. | 
|  | */ | 
|  |  | 
|  | #include "config.h" | 
|  |  | 
|  | #ifdef HAVE_STDIO_H | 
|  | #include <stdio.h> | 
|  | #endif | 
|  |  | 
|  | #ifdef HAVE_STDLIB_H | 
|  | #include <stdlib.h> | 
|  | #endif | 
|  |  | 
|  | #ifdef HAVE_ERRNO_H | 
|  | #include <errno.h> | 
|  | #endif | 
|  |  | 
|  | #ifdef HAVE_STDARG_H | 
|  | #include <stdarg.h> | 
|  | #endif | 
|  |  | 
|  | #if TIME_WITH_SYS_TIME | 
|  | # include <sys/time.h> | 
|  | # include <time.h> | 
|  | #else | 
|  | # if HAVE_SYS_TIME_H | 
|  | #  include <sys/time.h> | 
|  | # else | 
|  | #  include <time.h> | 
|  | # endif | 
|  | #endif | 
|  |  | 
|  | #ifdef HAVE_SYSLOG_H | 
|  | #include <syslog.h> | 
|  | #endif | 
|  |  | 
|  | #ifdef HAVE_STRING_H | 
|  | #include <string.h> | 
|  | #endif | 
|  |  | 
|  | #ifdef HAVE_STRINGS_H | 
|  | #include <strings.h> | 
|  | #endif | 
|  |  | 
|  | #ifdef HAVE_UNISTD_H | 
|  | #include <unistd.h> | 
|  | #endif | 
|  |  | 
|  | #ifdef HAVE_EXECINFO_H | 
|  | #include <execinfo.h> | 
|  | #endif | 
|  |  | 
|  | #ifdef HAVE_SYS_TYPES_H | 
|  | #include <sys/types.h> | 
|  | #endif | 
|  |  | 
|  | #ifdef HAVE_SYS_STAT_H | 
|  | #include <sys/stat.h> | 
|  | #endif | 
|  |  | 
|  | #include "monit.h" | 
|  |  | 
|  |  | 
|  | /** | 
|  | *  Implementation of a logger that appends log messages to a file | 
|  | *  with a preceding timestamp. Methods support both syslog or own | 
|  | *  logfile. | 
|  | * | 
|  | *  @file | 
|  | */ | 
|  |  | 
|  |  | 
|  | /* ------------------------------------------------------------- Definitions */ | 
|  |  | 
|  |  | 
|  | static FILE *LOG= NULL; | 
|  | static pthread_mutex_t log_mutex = PTHREAD_MUTEX_INITIALIZER; | 
|  |  | 
|  |  | 
|  | static struct mylogpriority { | 
|  | int  priority; | 
|  | char *description; | 
|  | } logPriority[]= { | 
|  | {LOG_EMERG,   "emergency"}, | 
|  | {LOG_ALERT,   "alert"}, | 
|  | {LOG_CRIT,    "critical"}, | 
|  | {LOG_ERR,     "error"}, | 
|  | {LOG_WARNING, "warning"}, | 
|  | {LOG_NOTICE,  "notice"}, | 
|  | {LOG_INFO,    "info"}, | 
|  | {LOG_DEBUG,   "debug"}, | 
|  | {-1,          NULL} | 
|  | }; | 
|  |  | 
|  |  | 
|  | /* -------------------------------------------------------------- Prototypes */ | 
|  |  | 
|  |  | 
|  | static int  open_log(); | 
|  | static char *timefmt(char *t, int size); | 
|  | static const char *logPriorityDescription(int p); | 
|  | static void log_log(int priority, const char *s, va_list ap); | 
|  | static void log_backtrace(); | 
|  |  | 
|  |  | 
|  | /* ------------------------------------------------------------------ Public */ | 
|  |  | 
|  |  | 
|  | /** | 
|  | * Initialize the log system and 'log' function | 
|  | * @return TRUE if the log system was successfully initialized | 
|  | */ | 
|  | int log_init() { | 
|  |  | 
|  | if (!Run.dolog) { | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | if (!open_log()) { | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | /* Register log_close to be | 
|  | called at program termination */ | 
|  | atexit(log_close); | 
|  |  | 
|  | return TRUE; | 
|  |  | 
|  | } | 
|  |  | 
|  |  | 
|  | /** | 
|  | * Logging interface with priority support | 
|  | * @param s A formated (printf-style) string to log | 
|  | */ | 
|  | void LogEmergency(const char *s, ...) { | 
|  | va_list ap; | 
|  |  | 
|  | ASSERT(s); | 
|  |  | 
|  | va_start(ap, s); | 
|  | log_log(LOG_EMERG, s, ap); | 
|  | va_end(ap); | 
|  | log_backtrace(); | 
|  | } | 
|  |  | 
|  |  | 
|  | /** | 
|  | * Logging interface with priority support | 
|  | * @param s A formated (printf-style) string to log | 
|  | */ | 
|  | void LogAlert(const char *s, ...) { | 
|  | va_list ap; | 
|  |  | 
|  | ASSERT(s); | 
|  |  | 
|  | va_start(ap, s); | 
|  | log_log(LOG_ALERT, s, ap); | 
|  | va_end(ap); | 
|  | log_backtrace(); | 
|  | } | 
|  |  | 
|  |  | 
|  | /** | 
|  | * Logging interface with priority support | 
|  | * @param s A formated (printf-style) string to log | 
|  | */ | 
|  | void LogCritical(const char *s, ...) { | 
|  | va_list ap; | 
|  |  | 
|  | ASSERT(s); | 
|  |  | 
|  | va_start(ap, s); | 
|  | log_log(LOG_CRIT, s, ap); | 
|  | va_end(ap); | 
|  | log_backtrace(); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Called by libmonit on Exception. Log | 
|  | * error and abort the application | 
|  | */ | 
|  | void vLogAbortHandler(const char *s, va_list ap) { | 
|  | va_list ap_copy; | 
|  | ASSERT(s); | 
|  | va_copy(ap_copy, ap); | 
|  | log_log(LOG_CRIT, s, ap); | 
|  | va_end(ap_copy); | 
|  | abort(); | 
|  | } | 
|  |  | 
|  |  | 
|  | /** | 
|  | * Logging interface with priority support | 
|  | * @param s A formated (printf-style) string to log | 
|  | */ | 
|  | void LogError(const char *s, ...) { | 
|  | va_list ap; | 
|  |  | 
|  | ASSERT(s); | 
|  |  | 
|  | va_start(ap, s); | 
|  | log_log(LOG_ERR, s, ap); | 
|  | va_end(ap); | 
|  | log_backtrace(); | 
|  | } | 
|  |  | 
|  |  | 
|  | /** | 
|  | * Logging interface with priority support | 
|  | * @param s A formated (printf-style) string to log | 
|  | */ | 
|  | void vLogError(const char *s, va_list ap) { | 
|  | va_list ap_copy; | 
|  | ASSERT(s); | 
|  | va_copy(ap_copy, ap); | 
|  | log_log(LOG_ERR, s, ap); | 
|  | va_end(ap_copy); | 
|  | log_backtrace(); | 
|  | } | 
|  |  | 
|  |  | 
|  | /** | 
|  | * Logging interface with priority support | 
|  | * @param s A formated (printf-style) string to log | 
|  | */ | 
|  | void LogWarning(const char *s, ...) { | 
|  | va_list ap; | 
|  |  | 
|  | ASSERT(s); | 
|  |  | 
|  | va_start(ap, s); | 
|  | log_log(LOG_WARNING, s, ap); | 
|  | va_end(ap); | 
|  | } | 
|  |  | 
|  |  | 
|  | /** | 
|  | * Logging interface with priority support | 
|  | * @param s A formated (printf-style) string to log | 
|  | */ | 
|  | void LogNotice(const char *s, ...) { | 
|  | va_list ap; | 
|  |  | 
|  | ASSERT(s); | 
|  |  | 
|  | va_start(ap, s); | 
|  | log_log(LOG_NOTICE, s, ap); | 
|  | va_end(ap); | 
|  | } | 
|  |  | 
|  |  | 
|  | /** | 
|  | * Logging interface with priority support | 
|  | * @param s A formated (printf-style) string to log | 
|  | */ | 
|  | void LogInfo(const char *s, ...) { | 
|  | va_list ap; | 
|  |  | 
|  | ASSERT(s); | 
|  |  | 
|  | va_start(ap, s); | 
|  | log_log(LOG_INFO, s, ap); | 
|  | va_end(ap); | 
|  | } | 
|  |  | 
|  |  | 
|  | /** | 
|  | * Logging interface with priority support | 
|  | * @param s A formated (printf-style) string to log | 
|  | */ | 
|  | void LogDebug(const char *s, ...) { | 
|  | va_list ap; | 
|  |  | 
|  | ASSERT(s); | 
|  |  | 
|  | va_start(ap, s); | 
|  | log_log(LOG_DEBUG, s, ap); | 
|  | va_end(ap); | 
|  | } | 
|  |  | 
|  |  | 
|  | /** | 
|  | * Close the log file or syslog | 
|  | */ | 
|  | void log_close() { | 
|  |  | 
|  | if (Run.use_syslog) { | 
|  | closelog(); | 
|  | } | 
|  |  | 
|  | if (LOG  && (0 != fclose(LOG))) { | 
|  | LogError("%s: Error closing the log file -- %s\n",	prog, STRERROR); | 
|  | } | 
|  |  | 
|  | LOG= NULL; | 
|  |  | 
|  | } | 
|  |  | 
|  |  | 
|  | #ifndef HAVE_VSYSLOG | 
|  | #ifdef HAVE_SYSLOG | 
|  | void vsyslog (int facility_priority, const char *format, va_list arglist) { | 
|  | char msg[STRLEN+1]; | 
|  |  | 
|  | vsnprintf(msg, STRLEN, format, arglist); | 
|  | syslog(facility_priority, "%s", msg); | 
|  | } | 
|  | #endif /* HAVE_SYSLOG */ | 
|  | #endif /* HAVE_VSYSLOG */ | 
|  |  | 
|  |  | 
|  | /* ----------------------------------------------------------------- Private */ | 
|  |  | 
|  |  | 
|  | /** | 
|  | * Open a log file or syslog | 
|  | */ | 
|  | static int open_log() { | 
|  |  | 
|  | if (Run.use_syslog) { | 
|  | openlog(prog, LOG_PID, Run.facility); | 
|  | } else { | 
|  | umask(LOGMASK); | 
|  | if ((LOG= fopen(Run.logfile,"a+")) == (FILE *)NULL) { | 
|  | LogError("%s: Error opening the log file '%s' for writing -- %s\n", prog, Run.logfile, STRERROR); | 
|  | return(FALSE); | 
|  | } | 
|  | /* Set logger in unbuffered mode */ | 
|  | setvbuf(LOG, NULL, _IONBF, 0); | 
|  | } | 
|  |  | 
|  | return TRUE; | 
|  |  | 
|  | } | 
|  |  | 
|  |  | 
|  | /** | 
|  | * Returns the current time as a formated string, see the TIMEFORMAT | 
|  | * macro in monit.h | 
|  | */ | 
|  | static char *timefmt(char *t, int size) { | 
|  | time_t now; | 
|  | struct tm tm; | 
|  |  | 
|  | time(&now); | 
|  | localtime_r(&now, &tm); | 
|  | if ( !strftime(t, size, TIMEFORMAT, &tm)) | 
|  | *t = 0; | 
|  | return t; | 
|  | } | 
|  |  | 
|  |  | 
|  | /** | 
|  | * Get a textual description of the actual log priority. | 
|  | * @param p The log priority | 
|  | * @return A string describing the log priority in clear text. If the | 
|  | * priority is not found NULL is returned. | 
|  | */ | 
|  | static const char *logPriorityDescription(int p) { | 
|  |  | 
|  | struct mylogpriority *lp= logPriority; | 
|  |  | 
|  | while ((*lp).description) | 
|  | { | 
|  | if (p == (*lp).priority) | 
|  | { | 
|  | return (*lp).description; | 
|  | } | 
|  | lp++; | 
|  | } | 
|  |  | 
|  | return "unknown"; | 
|  |  | 
|  | } | 
|  |  | 
|  |  | 
|  | /** | 
|  | * Log a message to monits logfile or syslog. | 
|  | * @param priority A message priority | 
|  | * @param s A formated (printf-style) string to log | 
|  | */ | 
|  | static void log_log(int priority, const char *s, va_list ap) { | 
|  |  | 
|  | #ifdef HAVE_VA_COPY | 
|  | va_list ap_copy; | 
|  | #endif | 
|  |  | 
|  | ASSERT(s); | 
|  |  | 
|  | LOCK(log_mutex) | 
|  |  | 
|  | #ifdef HAVE_VA_COPY | 
|  | va_copy(ap_copy, ap); | 
|  | vfprintf(stderr, s, ap_copy); | 
|  | va_end(ap_copy); | 
|  | #else | 
|  | vfprintf(stderr, s, ap); | 
|  | #endif | 
|  | fflush(stderr); | 
|  |  | 
|  | if (Run.dolog) { | 
|  | if (Run.use_syslog) { | 
|  | #ifdef HAVE_VA_COPY | 
|  | va_copy(ap_copy, ap); | 
|  | vsyslog(priority, s, ap_copy); | 
|  | va_end(ap_copy); | 
|  | #else | 
|  | vsyslog(priority, s, ap); | 
|  | #endif | 
|  | } else if (LOG) { | 
|  | char datetime[STRLEN]; | 
|  | fprintf(LOG, "[%s] %-8s : ", timefmt(datetime, STRLEN), logPriorityDescription(priority)); | 
|  | #ifdef HAVE_VA_COPY | 
|  | va_copy(ap_copy, ap); | 
|  | vfprintf(LOG, s, ap_copy); | 
|  | va_end(ap_copy); | 
|  | #else | 
|  | vfprintf(LOG, s, ap); | 
|  | #endif | 
|  |  | 
|  | } | 
|  | } | 
|  | END_LOCK; | 
|  | } | 
|  |  | 
|  |  | 
|  | static void log_backtrace() { | 
|  | #ifdef HAVE_BACKTRACE | 
|  | int i, frames; | 
|  | void *callstack[128]; | 
|  | char **strs; | 
|  |  | 
|  | if (Run.debug >= 2) { | 
|  | frames = backtrace(callstack, 128); | 
|  | strs = backtrace_symbols(callstack, frames); | 
|  | LogDebug("-------------------------------------------------------------------------------\n"); | 
|  | for (i = 0; i < frames; ++i) | 
|  | LogDebug("    %s\n", strs[i]); | 
|  | LogDebug("-------------------------------------------------------------------------------\n"); | 
|  | FREE(strs); | 
|  | } | 
|  | #endif | 
|  | } | 
|  |  |