1 /*
2  * Copyright (C) Tildeslash Ltd. All rights reserved.
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU Affero General Public License version 3.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU Affero General Public License
13  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
14  *
15  * In addition, as a special exception, the copyright holders give
16  * permission to link the code of portions of this program with the
17  * OpenSSL library under certain conditions as described in each
18  * individual source file, and distribute linked combinations
19  * including the two.
20  *
21  * You must obey the GNU Affero General Public License in all respects
22  * for all of the code used other than OpenSSL.
23  */
24 
25 #include "config.h"
26 
27 #ifdef HAVE_STDIO_H
28 #include <stdio.h>
29 #endif
30 
31 #ifdef HAVE_STDLIB_H
32 #include <stdlib.h>
33 #endif
34 
35 #ifdef HAVE_ERRNO_H
36 #include <errno.h>
37 #endif
38 
39 #ifdef HAVE_STDARG_H
40 #include <stdarg.h>
41 #endif
42 
43 #ifdef HAVE_SYSLOG_H
44 #include <syslog.h>
45 #endif
46 
47 #ifdef HAVE_STRING_H
48 #include <string.h>
49 #endif
50 
51 #ifdef HAVE_STRINGS_H
52 #include <strings.h>
53 #endif
54 
55 #ifdef HAVE_UNISTD_H
56 #include <unistd.h>
57 #endif
58 
59 #ifdef HAVE_EXECINFO_H
60 #include <execinfo.h>
61 #endif
62 
63 #ifdef HAVE_SYS_TYPES_H
64 #include <sys/types.h>
65 #endif
66 
67 #ifdef HAVE_SYS_STAT_H
68 #include <sys/stat.h>
69 #endif
70 
71 #include "monit.h"
72 
73 // libmonit
74 #include "system/Time.h"
75 
76 
77 /**
78  *  Implementation of a logger that appends log messages to a file
79  *  with a preceding timestamp. Methods support both syslog or own
80  *  logfile.
81  *
82  *  @file
83  */
84 
85 
86 /* ------------------------------------------------------------- Definitions */
87 
88 
89 static FILE *_LOG = NULL;
90 static Mutex_T _mutex = PTHREAD_MUTEX_INITIALIZER;
91 
92 
93 static struct mylogpriority {
94         int  priority;
95         const char *description;
96 } logPriority[] = {
97         {LOG_EMERG,   "emergency"},
98         {LOG_ALERT,   "alert"},
99         {LOG_CRIT,    "critical"},
100         {LOG_ERR,     "error"},
101         {LOG_WARNING, "warning"},
102         {LOG_NOTICE,  "notice"},
103         {LOG_INFO,    "info"},
104         {LOG_DEBUG,   "debug"},
105         {-1,          NULL}
106 };
107 
108 
109 /* ----------------------------------------------------------------- Private */
110 
111 
112 /**
113  * Open a log file or syslog
114  */
_open(void)115 static bool _open(void) {
116         if (Run.flags & Run_UseSyslog) {
117                 openlog(prog, LOG_PID, Run.facility);
118         } else {
119                 _LOG = fopen(Run.files.log, "a");
120                 if (! _LOG) {
121                         Log_error("Error opening the log file '%s' for writing -- %s\n", Run.files.log, STRERROR);
122                         return false;
123                 }
124                 /* Set logger in unbuffered mode */
125                 setvbuf(_LOG, NULL, _IONBF, 0);
126         }
127         return true;
128 }
129 
130 
131 /**
132  * Get a textual description of the actual log priority.
133  * @param p The log priority
134  * @return A string describing the log priority in clear text. If the
135  * priority is not found NULL is returned.
136  */
_priorityDescription(int p)137 static const char *_priorityDescription(int p) {
138         struct mylogpriority *lp = logPriority;
139         while ((*lp).description) {
140                 if (p == (*lp).priority) {
141                         return (*lp).description;
142                 }
143                 lp++;
144         }
145         return "unknown";
146 }
147 
148 
149 /**
150  * Log a message to monits logfile or syslog.
151  * @param priority A message priority
152  * @param s A formatted (printf-style) string to log
153  */
154 __attribute__((format (printf, 2, 0)))
_log(int priority,const char * s,va_list ap)155 static void _log(int priority, const char *s, va_list ap) {
156         ASSERT(s);
157         va_list ap_copy;
158         LOCK(_mutex)
159         {
160 
161                 FILE *output = priority < LOG_INFO ? stderr : stdout;
162                 va_copy(ap_copy, ap);
163                 vfprintf(output, s, ap_copy);
164                 va_end(ap_copy);
165                 fflush(output);
166                 if (Run.flags & Run_Log) {
167                         if (Run.flags & Run_UseSyslog) {
168                                 va_copy(ap_copy, ap);
169                                 vsyslog(priority, s, ap_copy);
170                                 va_end(ap_copy);
171                         } else if (_LOG) {
172                                 fprintf(_LOG, "[%s] %-8s : ", Time_fmt((char[STRLEN]){}, STRLEN, TIMEFORMAT, Time_now()), _priorityDescription(priority));
173                                 va_copy(ap_copy, ap);
174                                 vfprintf(_LOG, s, ap_copy);
175                                 va_end(ap_copy);
176                         }
177                 }
178         }
179         END_LOCK;
180 }
181 
182 
_backtrace(void)183 static void _backtrace(void) {
184 #ifdef HAVE_BACKTRACE
185         int i, frames;
186         void *callstack[128];
187         char **strs;
188 
189         if (Run.debug >= 2) {
190                 frames = backtrace(callstack, 128);
191                 strs = backtrace_symbols(callstack, frames);
192                 Log_debug("-------------------------------------------------------------------------------\n");
193                 for (i = 0; i < frames; ++i)
194                 Log_debug("    %s\n", strs[i]);
195                 Log_debug("-------------------------------------------------------------------------------\n");
196                 FREE(strs);
197         }
198 #endif
199 }
200 
201 
202 /* ------------------------------------------------------------------------- */
203 
204 
205 #ifndef HAVE_VSYSLOG
206 #ifdef HAVE_SYSLOG
vsyslog(int facility_priority,const char * format,va_list arglist)207 void vsyslog(int facility_priority, const char *format, va_list arglist) {
208         char msg[STRLEN+1];
209         vsnprintf(msg, STRLEN, format, arglist);
210         syslog(facility_priority, "%s", msg);
211 }
212 #endif /* HAVE_SYSLOG */
213 #endif /* HAVE_VSYSLOG */
214 
215 
216 /* ------------------------------------------------------------------ Public */
217 
218 
219 /**
220  * Initialize the log system and 'log' function
221  * @return true if the log system was successfully initialized
222  */
Log_init()223 bool Log_init() {
224         if (! (Run.flags & Run_Log))
225                 return true;
226         if (! _open())
227                 return false;
228         /* Register Log_close to be called at program termination */
229         atexit(Log_close);
230         return true;
231 }
232 
233 
234 /**
235  * Logging interface with priority support
236  * @param s A formatted (printf-style) string to log
237  */
Log_emergency(const char * s,...)238 void Log_emergency(const char *s, ...) {
239         ASSERT(s);
240         va_list ap;
241         va_start(ap, s);
242         _log(LOG_EMERG, s, ap);
243         va_end(ap);
244         _backtrace();
245 }
246 
247 
248 /**
249  * Logging interface with priority support
250  * @param s A formatted (printf-style) string to log
251  * @param ap A variable argument list
252  */
Log_vemergency(const char * s,va_list ap)253 void Log_vemergency(const char *s, va_list ap) {
254         ASSERT(s);
255         va_list ap_copy;
256         va_copy(ap_copy, ap);
257         _log(LOG_EMERG, s, ap);
258         va_end(ap_copy);
259         _backtrace();
260 }
261 
262 
263 /**
264  * Logging interface with priority support
265  * @param s A formatted (printf-style) string to log
266  */
Log_alert(const char * s,...)267 void Log_alert(const char *s, ...) {
268         ASSERT(s);
269         va_list ap;
270         va_start(ap, s);
271         _log(LOG_ALERT, s, ap);
272         va_end(ap);
273         _backtrace();
274 }
275 
276 
277 /**
278  * Logging interface with priority support
279  * @param s A formatted (printf-style) string to log
280  * @param ap A variable argument list
281  */
Log_valert(const char * s,va_list ap)282 void Log_valert(const char *s, va_list ap) {
283         ASSERT(s);
284         va_list ap_copy;
285         va_copy(ap_copy, ap);
286         _log(LOG_ALERT, s, ap);
287         va_end(ap_copy);
288         _backtrace();
289 }
290 
291 
292 /**
293  * Logging interface with priority support
294  * @param s A formatted (printf-style) string to log
295  */
Log_critical(const char * s,...)296 void Log_critical(const char *s, ...) {
297         ASSERT(s);
298         va_list ap;
299         va_start(ap, s);
300         _log(LOG_CRIT, s, ap);
301         va_end(ap);
302         _backtrace();
303 }
304 
305 
306 /**
307  * Logging interface with priority support
308  * @param s A formatted (printf-style) string to log
309  * @param ap A variable argument list
310  */
Log_vcritical(const char * s,va_list ap)311 void Log_vcritical(const char *s, va_list ap) {
312         ASSERT(s);
313         va_list ap_copy;
314         va_copy(ap_copy, ap);
315         _log(LOG_CRIT, s, ap);
316         va_end(ap_copy);
317         _backtrace();
318 }
319 
320 
321 /*
322  * Called by libmonit on Exception. Log
323  * error and abort the application
324  */
Log_abort_handler(const char * s,va_list ap)325 void Log_abort_handler(const char *s, va_list ap) {
326         ASSERT(s);
327         va_list ap_copy;
328         va_copy(ap_copy, ap);
329         _log(LOG_CRIT, s, ap);
330         va_end(ap_copy);
331         if (Run.debug)
332                 abort();
333         exit(1);
334 }
335 
336 
337 /**
338  * Logging interface with priority support
339  * @param s A formatted (printf-style) string to log
340  */
Log_error(const char * s,...)341 void Log_error(const char *s, ...) {
342         ASSERT(s);
343         va_list ap;
344         va_start(ap, s);
345         _log(LOG_ERR, s, ap);
346         va_end(ap);
347         _backtrace();
348 }
349 
350 
351 /**
352  * Logging interface with priority support
353  * @param s A formatted (printf-style) string to log
354  * @param ap A variable argument list
355  */
Log_verror(const char * s,va_list ap)356 void Log_verror(const char *s, va_list ap) {
357         ASSERT(s);
358         va_list ap_copy;
359         va_copy(ap_copy, ap);
360         _log(LOG_ERR, s, ap);
361         va_end(ap_copy);
362         _backtrace();
363 }
364 
365 
366 /**
367  * Logging interface with priority support
368  * @param s A formatted (printf-style) string to log
369  */
Log_warning(const char * s,...)370 void Log_warning(const char *s, ...) {
371         ASSERT(s);
372         va_list ap;
373         va_start(ap, s);
374         _log(LOG_WARNING, s, ap);
375         va_end(ap);
376 }
377 
378 
379 /**
380  * Logging interface with priority support
381  * @param s A formatted (printf-style) string to log
382  * @param ap A variable argument list
383  */
Log_vwarning(const char * s,va_list ap)384 void Log_vwarning(const char *s, va_list ap) {
385         ASSERT(s);
386         va_list ap_copy;
387         va_copy(ap_copy, ap);
388         _log(LOG_WARNING, s, ap);
389         va_end(ap_copy);
390 }
391 
392 
393 /**
394  * Logging interface with priority support
395  * @param s A formatted (printf-style) string to log
396  */
Log_notice(const char * s,...)397 void Log_notice(const char *s, ...) {
398         ASSERT(s);
399         va_list ap;
400         va_start(ap, s);
401         _log(LOG_NOTICE, s, ap);
402         va_end(ap);
403 }
404 
405 
406 /**
407  * Logging interface with priority support
408  * @param s A formatted (printf-style) string to log
409  * @param ap A variable argument list
410  */
Log_vnotice(const char * s,va_list ap)411 void Log_vnotice(const char *s, va_list ap) {
412         ASSERT(s);
413         va_list ap_copy;
414         va_copy(ap_copy, ap);
415         _log(LOG_NOTICE, s, ap);
416         va_end(ap_copy);
417 }
418 
419 
420 /**
421  * Logging interface with priority support
422  * @param s A formatted (printf-style) string to log
423  */
Log_info(const char * s,...)424 void Log_info(const char *s, ...) {
425         ASSERT(s);
426         va_list ap;
427         va_start(ap, s);
428         _log(LOG_INFO, s, ap);
429         va_end(ap);
430 }
431 
432 
433 /**
434  * Logging interface with priority support
435  * @param s A formatted (printf-style) string to log
436  * @param ap A variable argument list
437  */
Log_vinfo(const char * s,va_list ap)438 void Log_vinfo(const char *s, va_list ap) {
439         ASSERT(s);
440         va_list ap_copy;
441         va_copy(ap_copy, ap);
442         _log(LOG_INFO, s, ap);
443         va_end(ap_copy);
444 }
445 
446 
447 /**
448  * Logging interface with priority support
449  * @param s A formatted (printf-style) string to log
450  */
Log_debug(const char * s,...)451 void Log_debug(const char *s, ...) {
452         ASSERT(s);
453         if (Run.debug) {
454                 va_list ap;
455                 va_start(ap, s);
456                 _log(LOG_DEBUG, s, ap);
457                 va_end(ap);
458         }
459 }
460 
461 
462 /**
463  * Logging interface with priority support
464  * @param s A formatted (printf-style) string to log
465  * @param ap A variable argument list
466  */
Log_vdebug(const char * s,va_list ap)467 void Log_vdebug(const char *s, va_list ap) {
468         ASSERT(s);
469         if (Run.debug) {
470                 va_list ap_copy;
471                 va_copy(ap_copy, ap);
472                 _log(LOG_NOTICE, s, ap);
473                 va_end(ap_copy);
474         }
475 }
476 
477 
478 /**
479  * Close the log file or syslog
480  */
Log_close()481 void Log_close() {
482         if (Run.flags & Run_UseSyslog) {
483                 closelog();
484         }
485         if (_LOG  && (0 != fclose(_LOG))) {
486                 Log_error("Error closing the log file -- %s\n", STRERROR);
487         }
488         _LOG = NULL;
489 }
490