1 /*
2 ** Zabbix
3 ** Copyright (C) 2001-2021 Zabbix SIA
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 **/
19
20 #include "common.h"
21 #include "log.h"
22 #include "mutexs.h"
23 #include "threads.h"
24 #include "cfg.h"
25 #ifdef _WINDOWS
26 # include "messages.h"
27 # include "service.h"
28 # include "sysinfo.h"
29 static HANDLE system_log_handle = INVALID_HANDLE_VALUE;
30 #endif
31
32 static char log_filename[MAX_STRING_LEN];
33 static int log_type = LOG_TYPE_UNDEFINED;
34 static zbx_mutex_t log_access = ZBX_MUTEX_NULL;
35 int zbx_log_level = LOG_LEVEL_WARNING;
36
37 #ifdef _WINDOWS
38 # define LOCK_LOG zbx_mutex_lock(log_access)
39 # define UNLOCK_LOG zbx_mutex_unlock(log_access)
40 #else
41 # define LOCK_LOG lock_log()
42 # define UNLOCK_LOG unlock_log()
43 #endif
44
45 #define ZBX_MESSAGE_BUF_SIZE 1024
46
47 #ifdef _WINDOWS
48 # define STDIN_FILENO _fileno(stdin)
49 # define STDOUT_FILENO _fileno(stdout)
50 # define STDERR_FILENO _fileno(stderr)
51
52 # define ZBX_DEV_NULL "NUL"
53
54 # define dup2(fd1, fd2) _dup2(fd1, fd2)
55 #else
56 # define ZBX_DEV_NULL "/dev/null"
57 #endif
58
59 #ifndef _WINDOWS
zabbix_get_log_level_string(void)60 const char *zabbix_get_log_level_string(void)
61 {
62 switch (zbx_log_level)
63 {
64 case LOG_LEVEL_EMPTY:
65 return "0 (none)";
66 case LOG_LEVEL_CRIT:
67 return "1 (critical)";
68 case LOG_LEVEL_ERR:
69 return "2 (error)";
70 case LOG_LEVEL_WARNING:
71 return "3 (warning)";
72 case LOG_LEVEL_DEBUG:
73 return "4 (debug)";
74 case LOG_LEVEL_TRACE:
75 return "5 (trace)";
76 }
77
78 THIS_SHOULD_NEVER_HAPPEN;
79 exit(EXIT_FAILURE);
80 }
81
zabbix_increase_log_level(void)82 int zabbix_increase_log_level(void)
83 {
84 if (LOG_LEVEL_TRACE == zbx_log_level)
85 return FAIL;
86
87 zbx_log_level = zbx_log_level + 1;
88
89 return SUCCEED;
90 }
91
zabbix_decrease_log_level(void)92 int zabbix_decrease_log_level(void)
93 {
94 if (LOG_LEVEL_EMPTY == zbx_log_level)
95 return FAIL;
96
97 zbx_log_level = zbx_log_level - 1;
98
99 return SUCCEED;
100 }
101 #endif
102
zbx_redirect_stdio(const char * filename)103 int zbx_redirect_stdio(const char *filename)
104 {
105 const char default_file[] = ZBX_DEV_NULL;
106 int open_flags = O_WRONLY, fd;
107
108 if (NULL != filename && '\0' != *filename)
109 open_flags |= O_CREAT | O_APPEND;
110 else
111 filename = default_file;
112
113 if (-1 == (fd = open(filename, open_flags, 0666)))
114 {
115 zbx_error("cannot open \"%s\": %s", filename, zbx_strerror(errno));
116 return FAIL;
117 }
118
119 fflush(stdout);
120 if (-1 == dup2(fd, STDOUT_FILENO))
121 zbx_error("cannot redirect stdout to \"%s\": %s", filename, zbx_strerror(errno));
122
123 fflush(stderr);
124 if (-1 == dup2(fd, STDERR_FILENO))
125 zbx_error("cannot redirect stderr to \"%s\": %s", filename, zbx_strerror(errno));
126
127 close(fd);
128
129 if (-1 == (fd = open(default_file, O_RDONLY)))
130 {
131 zbx_error("cannot open \"%s\": %s", default_file, zbx_strerror(errno));
132 return FAIL;
133 }
134
135 if (-1 == dup2(fd, STDIN_FILENO))
136 zbx_error("cannot redirect stdin to \"%s\": %s", default_file, zbx_strerror(errno));
137
138 close(fd);
139
140 return SUCCEED;
141 }
142
rotate_log(const char * filename)143 static void rotate_log(const char *filename)
144 {
145 zbx_stat_t buf;
146 zbx_uint64_t new_size;
147 static zbx_uint64_t old_size = ZBX_MAX_UINT64; /* redirect stdout and stderr */
148 #if !defined(_WINDOWS)
149 static zbx_uint64_t st_ino, st_dev;
150 #endif
151
152 if (0 != zbx_stat(filename, &buf))
153 {
154 zbx_redirect_stdio(filename);
155 return;
156 }
157
158 new_size = buf.st_size;
159
160 if (0 != CONFIG_LOG_FILE_SIZE && (zbx_uint64_t)CONFIG_LOG_FILE_SIZE * ZBX_MEBIBYTE < new_size)
161 {
162 char filename_old[MAX_STRING_LEN];
163
164 strscpy(filename_old, filename);
165 zbx_strlcat(filename_old, ".old", MAX_STRING_LEN);
166 remove(filename_old);
167 #ifdef _WINDOWS
168 zbx_redirect_stdio(NULL);
169 #endif
170 if (0 != rename(filename, filename_old))
171 {
172 FILE *log_file = NULL;
173
174 if (NULL != (log_file = fopen(filename, "w")))
175 {
176 long milliseconds;
177 struct tm tm;
178
179 zbx_get_time(&tm, &milliseconds, NULL);
180
181 fprintf(log_file, "%6li:%.4d%.2d%.2d:%.2d%.2d%.2d.%03ld"
182 " cannot rename log file \"%s\" to \"%s\": %s\n",
183 zbx_get_thread_id(),
184 tm.tm_year + 1900,
185 tm.tm_mon + 1,
186 tm.tm_mday,
187 tm.tm_hour,
188 tm.tm_min,
189 tm.tm_sec,
190 milliseconds,
191 filename,
192 filename_old,
193 zbx_strerror(errno));
194
195 fprintf(log_file, "%6li:%.4d%.2d%.2d:%.2d%.2d%.2d.%03ld"
196 " Logfile \"%s\" size reached configured limit"
197 " LogFileSize but moving it to \"%s\" failed. The logfile"
198 " was truncated.\n",
199 zbx_get_thread_id(),
200 tm.tm_year + 1900,
201 tm.tm_mon + 1,
202 tm.tm_mday,
203 tm.tm_hour,
204 tm.tm_min,
205 tm.tm_sec,
206 milliseconds,
207 filename,
208 filename_old);
209
210 zbx_fclose(log_file);
211
212 new_size = 0;
213 }
214 }
215 else
216 new_size = 0;
217 }
218
219 if (old_size > new_size)
220 zbx_redirect_stdio(filename);
221 #if !defined(_WINDOWS)
222 else if (st_ino != buf.st_ino || st_dev != buf.st_dev)
223 {
224 st_ino = buf.st_ino;
225 st_dev = buf.st_dev;
226 zbx_redirect_stdio(filename);
227 }
228 #endif
229
230 old_size = new_size;
231 }
232
233 #ifndef _WINDOWS
234 static sigset_t orig_mask;
235
lock_log(void)236 static void lock_log(void)
237 {
238 sigset_t mask;
239
240 /* block signals to prevent deadlock on log file mutex when signal handler attempts to lock log */
241 sigemptyset(&mask);
242 sigaddset(&mask, SIGUSR1);
243 sigaddset(&mask, SIGUSR2);
244 sigaddset(&mask, SIGTERM);
245 sigaddset(&mask, SIGINT);
246 sigaddset(&mask, SIGQUIT);
247 sigaddset(&mask, SIGHUP);
248
249 if (0 > sigprocmask(SIG_BLOCK, &mask, &orig_mask))
250 zbx_error("cannot set sigprocmask to block the user signal");
251
252 zbx_mutex_lock(log_access);
253 }
254
unlock_log(void)255 static void unlock_log(void)
256 {
257 zbx_mutex_unlock(log_access);
258
259 if (0 > sigprocmask(SIG_SETMASK, &orig_mask, NULL))
260 zbx_error("cannot restore sigprocmask");
261 }
262 #else
lock_log(void)263 static void lock_log(void)
264 {
265 #ifdef ZABBIX_AGENT
266 if (0 == (ZBX_MUTEX_LOGGING_DENIED & get_thread_global_mutex_flag()))
267 #endif
268 LOCK_LOG;
269 }
270
unlock_log(void)271 static void unlock_log(void)
272 {
273 #ifdef ZABBIX_AGENT
274 if (0 == (ZBX_MUTEX_LOGGING_DENIED & get_thread_global_mutex_flag()))
275 #endif
276 UNLOCK_LOG;
277 }
278 #endif
279
zbx_handle_log(void)280 void zbx_handle_log(void)
281 {
282 if (LOG_TYPE_FILE != log_type)
283 return;
284
285 LOCK_LOG;
286
287 rotate_log(log_filename);
288
289 UNLOCK_LOG;
290 }
291
zabbix_open_log(int type,int level,const char * filename,char ** error)292 int zabbix_open_log(int type, int level, const char *filename, char **error)
293 {
294 log_type = type;
295 zbx_log_level = level;
296
297 if (LOG_TYPE_SYSTEM == type)
298 {
299 #ifdef _WINDOWS
300 wchar_t *wevent_source;
301
302 wevent_source = zbx_utf8_to_unicode(ZABBIX_EVENT_SOURCE);
303 system_log_handle = RegisterEventSource(NULL, wevent_source);
304 zbx_free(wevent_source);
305 #else
306 openlog(syslog_app_name, LOG_PID, LOG_DAEMON);
307 #endif
308 }
309 else if (LOG_TYPE_FILE == type)
310 {
311 FILE *log_file = NULL;
312
313 if (MAX_STRING_LEN <= strlen(filename))
314 {
315 *error = zbx_strdup(*error, "too long path for logfile");
316 return FAIL;
317 }
318
319 if (SUCCEED != zbx_mutex_create(&log_access, ZBX_MUTEX_LOG, error))
320 return FAIL;
321
322 if (NULL == (log_file = fopen(filename, "a+")))
323 {
324 *error = zbx_dsprintf(*error, "unable to open log file [%s]: %s", filename, zbx_strerror(errno));
325 return FAIL;
326 }
327
328 strscpy(log_filename, filename);
329 zbx_fclose(log_file);
330 }
331 else if (LOG_TYPE_CONSOLE == type || LOG_TYPE_UNDEFINED == type)
332 {
333 if (SUCCEED != zbx_mutex_create(&log_access, ZBX_MUTEX_LOG, error))
334 {
335 *error = zbx_strdup(*error, "unable to create mutex for standard output");
336 return FAIL;
337 }
338
339 fflush(stderr);
340 if (-1 == dup2(STDOUT_FILENO, STDERR_FILENO))
341 zbx_error("cannot redirect stderr to stdout: %s", zbx_strerror(errno));
342 }
343 else
344 {
345 *error = zbx_strdup(*error, "unknown log type");
346 return FAIL;
347 }
348
349 return SUCCEED;
350 }
351
zabbix_close_log(void)352 void zabbix_close_log(void)
353 {
354 if (LOG_TYPE_SYSTEM == log_type)
355 {
356 #ifdef _WINDOWS
357 if (NULL != system_log_handle)
358 DeregisterEventSource(system_log_handle);
359 #else
360 closelog();
361 #endif
362 }
363 else if (LOG_TYPE_FILE == log_type || LOG_TYPE_CONSOLE == log_type || LOG_TYPE_UNDEFINED == log_type)
364 {
365 zbx_mutex_destroy(&log_access);
366 }
367 }
368
__zbx_zabbix_log(int level,const char * fmt,...)369 void __zbx_zabbix_log(int level, const char *fmt, ...)
370 {
371 char message[MAX_BUFFER_LEN];
372 va_list args;
373 #ifdef _WINDOWS
374 WORD wType;
375 wchar_t thread_id[20], *strings[2];
376 #endif
377
378 #ifndef ZBX_ZABBIX_LOG_CHECK
379 if (SUCCEED != ZBX_CHECK_LOG_LEVEL(level))
380 return;
381 #endif
382 if (LOG_TYPE_FILE == log_type)
383 {
384 FILE *log_file;
385
386 LOCK_LOG;
387
388 if (0 != CONFIG_LOG_FILE_SIZE)
389 rotate_log(log_filename);
390
391 if (NULL != (log_file = fopen(log_filename, "a+")))
392 {
393 long milliseconds;
394 struct tm tm;
395
396 zbx_get_time(&tm, &milliseconds, NULL);
397
398 fprintf(log_file,
399 "%6li:%.4d%.2d%.2d:%.2d%.2d%.2d.%03ld ",
400 zbx_get_thread_id(),
401 tm.tm_year + 1900,
402 tm.tm_mon + 1,
403 tm.tm_mday,
404 tm.tm_hour,
405 tm.tm_min,
406 tm.tm_sec,
407 milliseconds
408 );
409
410 va_start(args, fmt);
411 vfprintf(log_file, fmt, args);
412 va_end(args);
413
414 fprintf(log_file, "\n");
415
416 zbx_fclose(log_file);
417 }
418 else
419 {
420 zbx_error("failed to open log file: %s", zbx_strerror(errno));
421
422 va_start(args, fmt);
423 zbx_vsnprintf(message, sizeof(message), fmt, args);
424 va_end(args);
425
426 zbx_error("failed to write [%s] into log file", message);
427 }
428
429 UNLOCK_LOG;
430
431 return;
432 }
433
434 if (LOG_TYPE_CONSOLE == log_type)
435 {
436 long milliseconds;
437 struct tm tm;
438
439 LOCK_LOG;
440
441 zbx_get_time(&tm, &milliseconds, NULL);
442
443 fprintf(stdout,
444 "%6li:%.4d%.2d%.2d:%.2d%.2d%.2d.%03ld ",
445 zbx_get_thread_id(),
446 tm.tm_year + 1900,
447 tm.tm_mon + 1,
448 tm.tm_mday,
449 tm.tm_hour,
450 tm.tm_min,
451 tm.tm_sec,
452 milliseconds
453 );
454
455 va_start(args, fmt);
456 vfprintf(stdout, fmt, args);
457 va_end(args);
458
459 fprintf(stdout, "\n");
460
461 fflush(stdout);
462
463 UNLOCK_LOG;
464
465 return;
466 }
467
468 va_start(args, fmt);
469 zbx_vsnprintf(message, sizeof(message), fmt, args);
470 va_end(args);
471
472 if (LOG_TYPE_SYSTEM == log_type)
473 {
474 #ifdef _WINDOWS
475 switch (level)
476 {
477 case LOG_LEVEL_CRIT:
478 case LOG_LEVEL_ERR:
479 wType = EVENTLOG_ERROR_TYPE;
480 break;
481 case LOG_LEVEL_WARNING:
482 wType = EVENTLOG_WARNING_TYPE;
483 break;
484 default:
485 wType = EVENTLOG_INFORMATION_TYPE;
486 break;
487 }
488
489 StringCchPrintf(thread_id, ARRSIZE(thread_id), TEXT("[%li]: "), zbx_get_thread_id());
490 strings[0] = thread_id;
491 strings[1] = zbx_utf8_to_unicode(message);
492
493 ReportEvent(
494 system_log_handle,
495 wType,
496 0,
497 MSG_ZABBIX_MESSAGE,
498 NULL,
499 sizeof(strings) / sizeof(*strings),
500 0,
501 strings,
502 NULL);
503
504 zbx_free(strings[1]);
505
506 #else /* not _WINDOWS */
507
508 /* for nice printing into syslog */
509 switch (level)
510 {
511 case LOG_LEVEL_CRIT:
512 syslog(LOG_CRIT, "%s", message);
513 break;
514 case LOG_LEVEL_ERR:
515 syslog(LOG_ERR, "%s", message);
516 break;
517 case LOG_LEVEL_WARNING:
518 syslog(LOG_WARNING, "%s", message);
519 break;
520 case LOG_LEVEL_DEBUG:
521 case LOG_LEVEL_TRACE:
522 syslog(LOG_DEBUG, "%s", message);
523 break;
524 case LOG_LEVEL_INFORMATION:
525 syslog(LOG_INFO, "%s", message);
526 break;
527 default:
528 /* LOG_LEVEL_EMPTY - print nothing */
529 break;
530 }
531
532 #endif /* _WINDOWS */
533 } /* LOG_TYPE_SYSLOG */
534 else /* LOG_TYPE_UNDEFINED == log_type */
535 {
536 LOCK_LOG;
537
538 switch (level)
539 {
540 case LOG_LEVEL_CRIT:
541 zbx_error("ERROR: %s", message);
542 break;
543 case LOG_LEVEL_ERR:
544 zbx_error("Error: %s", message);
545 break;
546 case LOG_LEVEL_WARNING:
547 zbx_error("Warning: %s", message);
548 break;
549 case LOG_LEVEL_DEBUG:
550 zbx_error("DEBUG: %s", message);
551 break;
552 case LOG_LEVEL_TRACE:
553 zbx_error("TRACE: %s", message);
554 break;
555 default:
556 zbx_error("%s", message);
557 break;
558 }
559
560 UNLOCK_LOG;
561 }
562 }
563
zbx_get_log_type(const char * logtype)564 int zbx_get_log_type(const char *logtype)
565 {
566 const char *logtypes[] = {ZBX_OPTION_LOGTYPE_SYSTEM, ZBX_OPTION_LOGTYPE_FILE, ZBX_OPTION_LOGTYPE_CONSOLE};
567 int i;
568
569 for (i = 0; i < (int)ARRSIZE(logtypes); i++)
570 {
571 if (0 == strcmp(logtype, logtypes[i]))
572 return i + 1;
573 }
574
575 return LOG_TYPE_UNDEFINED;
576 }
577
zbx_validate_log_parameters(ZBX_TASK_EX * task)578 int zbx_validate_log_parameters(ZBX_TASK_EX *task)
579 {
580 if (LOG_TYPE_UNDEFINED == CONFIG_LOG_TYPE)
581 {
582 zabbix_log(LOG_LEVEL_CRIT, "invalid \"LogType\" configuration parameter: '%s'", CONFIG_LOG_TYPE_STR);
583 return FAIL;
584 }
585
586 if (LOG_TYPE_CONSOLE == CONFIG_LOG_TYPE && 0 == (task->flags & ZBX_TASK_FLAG_FOREGROUND) &&
587 ZBX_TASK_START == task->task)
588 {
589 zabbix_log(LOG_LEVEL_CRIT, "\"LogType\" \"console\" parameter can only be used with the"
590 " -f (--foreground) command line option");
591 return FAIL;
592 }
593
594 if (LOG_TYPE_FILE == CONFIG_LOG_TYPE && (NULL == CONFIG_LOG_FILE || '\0' == *CONFIG_LOG_FILE))
595 {
596 zabbix_log(LOG_LEVEL_CRIT, "\"LogType\" \"file\" parameter requires \"LogFile\" parameter to be set");
597 return FAIL;
598 }
599
600 return SUCCEED;
601 }
602
603 /******************************************************************************
604 * *
605 * Comments: replace strerror to print also the error number *
606 * *
607 ******************************************************************************/
zbx_strerror(int errnum)608 char *zbx_strerror(int errnum)
609 {
610 /* !!! Attention: static !!! Not thread-safe for Win32 */
611 static char utf8_string[ZBX_MESSAGE_BUF_SIZE];
612
613 zbx_snprintf(utf8_string, sizeof(utf8_string), "[%d] %s", errnum, strerror(errnum));
614
615 return utf8_string;
616 }
617
strerror_from_system(unsigned long error)618 char *strerror_from_system(unsigned long error)
619 {
620 #ifdef _WINDOWS
621 size_t offset = 0;
622 wchar_t wide_string[ZBX_MESSAGE_BUF_SIZE];
623 /* !!! Attention: static !!! Not thread-safe for Win32 */
624 static char utf8_string[ZBX_MESSAGE_BUF_SIZE];
625
626 offset += zbx_snprintf(utf8_string, sizeof(utf8_string), "[0x%08lX] ", error);
627
628 /* we don't know the inserts so we pass NULL and enable appropriate flag */
629 if (0 == FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, error,
630 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), wide_string, ZBX_MESSAGE_BUF_SIZE, NULL))
631 {
632 zbx_snprintf(utf8_string + offset, sizeof(utf8_string) - offset,
633 "unable to find message text [0x%08lX]", GetLastError());
634
635 return utf8_string;
636 }
637
638 zbx_unicode_to_utf8_static(wide_string, utf8_string + offset, (int)(sizeof(utf8_string) - offset));
639
640 zbx_rtrim(utf8_string, "\r\n ");
641
642 return utf8_string;
643 #else /* not _WINDOWS */
644 ZBX_UNUSED(error);
645
646 return zbx_strerror(errno);
647 #endif /* _WINDOWS */
648 }
649
650 #ifdef _WINDOWS
strerror_from_module(unsigned long error,const wchar_t * module)651 char *strerror_from_module(unsigned long error, const wchar_t *module)
652 {
653 size_t offset = 0;
654 wchar_t wide_string[ZBX_MESSAGE_BUF_SIZE];
655 HMODULE hmodule;
656 /* !!! Attention: static !!! not thread-safe for Win32 */
657 static char utf8_string[ZBX_MESSAGE_BUF_SIZE];
658
659 *utf8_string = '\0';
660 hmodule = GetModuleHandle(module);
661
662 offset += zbx_snprintf(utf8_string, sizeof(utf8_string), "[0x%08lX] ", error);
663
664 /* we don't know the inserts so we pass NULL and enable appropriate flag */
665 if (0 == FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, hmodule, error,
666 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), wide_string, sizeof(wide_string), NULL))
667 {
668 zbx_snprintf(utf8_string + offset, sizeof(utf8_string) - offset,
669 "unable to find message text: %s", strerror_from_system(GetLastError()));
670
671 return utf8_string;
672 }
673
674 zbx_unicode_to_utf8_static(wide_string, utf8_string + offset, (int)(sizeof(utf8_string) - offset));
675
676 zbx_rtrim(utf8_string, "\r\n ");
677
678 return utf8_string;
679 }
680 #endif /* _WINDOWS */
681