|
Packit |
c22fc9 |
/*
|
|
Packit |
c22fc9 |
* Soft: Keepalived is a failover program for the LVS project
|
|
Packit |
c22fc9 |
* <www.linuxvirtualserver.org>. It monitor & manipulate
|
|
Packit |
c22fc9 |
* a loadbalanced server pool using multi-layer checks.
|
|
Packit |
c22fc9 |
*
|
|
Packit |
c22fc9 |
* Part: logging facility.
|
|
Packit |
c22fc9 |
*
|
|
Packit |
c22fc9 |
* Author: Alexandre Cassen, <acassen@linux-vs.org>
|
|
Packit |
c22fc9 |
*
|
|
Packit |
c22fc9 |
* This program is distributed in the hope that it will be useful,
|
|
Packit |
c22fc9 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
c22fc9 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
Packit |
c22fc9 |
* See the GNU General Public License for more details.
|
|
Packit |
c22fc9 |
*
|
|
Packit |
c22fc9 |
* This program is free software; you can redistribute it and/or
|
|
Packit |
c22fc9 |
* modify it under the terms of the GNU General Public License
|
|
Packit |
c22fc9 |
* as published by the Free Software Foundation; either version
|
|
Packit |
c22fc9 |
* 2 of the License, or (at your option) any later version.
|
|
Packit |
c22fc9 |
*
|
|
Packit |
c22fc9 |
* Copyright (C) 2001-2017 Alexandre Cassen, <acassen@gmail.com>
|
|
Packit |
c22fc9 |
*/
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
#include "config.h"
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
#include <stdio.h>
|
|
Packit |
c22fc9 |
#include <stdbool.h>
|
|
Packit |
c22fc9 |
#include <time.h>
|
|
Packit |
c22fc9 |
#include <unistd.h>
|
|
Packit |
c22fc9 |
#include <fcntl.h>
|
|
Packit |
c22fc9 |
#include <string.h>
|
|
Packit |
c22fc9 |
#include <memory.h>
|
|
Packit Service |
dfccb1 |
#ifndef HAVE_SIGNALFD
|
|
Packit Service |
dfccb1 |
#include <signal.h>
|
|
Packit Service |
dfccb1 |
#endif
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
#include "logger.h"
|
|
Packit |
c22fc9 |
#include "bitops.h"
|
|
Packit |
c22fc9 |
#include "utils.h"
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Boolean flag - send messages to console as well as syslog */
|
|
Packit |
c22fc9 |
static bool log_console = false;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
#ifdef ENABLE_LOG_TO_FILE
|
|
Packit |
c22fc9 |
/* File to write log messages to */
|
|
Packit Service |
dfccb1 |
const char *log_file_name;
|
|
Packit |
c22fc9 |
static FILE *log_file;
|
|
Packit |
c22fc9 |
bool always_flush_log_file;
|
|
Packit |
c22fc9 |
#endif
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
void
|
|
Packit |
c22fc9 |
enable_console_log(void)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
log_console = true;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
#ifdef ENABLE_LOG_TO_FILE
|
|
Packit |
c22fc9 |
void
|
|
Packit |
c22fc9 |
set_flush_log_file(void)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
always_flush_log_file = true;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
void
|
|
Packit |
c22fc9 |
close_log_file(void)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
if (log_file) {
|
|
Packit |
c22fc9 |
fclose(log_file);
|
|
Packit |
c22fc9 |
log_file = NULL;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
void
|
|
Packit |
c22fc9 |
open_log_file(const char *name, const char *prog, const char *namespace, const char *instance)
|
|
Packit |
c22fc9 |
{
|
|
Packit Service |
dfccb1 |
const char *file_name;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (log_file) {
|
|
Packit |
c22fc9 |
fclose(log_file);
|
|
Packit |
c22fc9 |
log_file = NULL;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (!name)
|
|
Packit |
c22fc9 |
return;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
file_name = make_file_name(name, prog, namespace, instance);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
log_file = fopen_safe(file_name, "a");
|
|
Packit |
c22fc9 |
if (log_file) {
|
|
Packit |
c22fc9 |
int n = fileno(log_file);
|
|
Packit Service |
dfccb1 |
if (fcntl(n, F_SETFD, FD_CLOEXEC | fcntl(n, F_GETFD)) == -1)
|
|
Packit Service |
dfccb1 |
log_message(LOG_INFO, "Failed to set CLOEXEC on log file %s", file_name);
|
|
Packit Service |
dfccb1 |
if (fcntl(n, F_SETFL, O_NONBLOCK | fcntl(n, F_GETFL)) == -1)
|
|
Packit Service |
dfccb1 |
log_message(LOG_INFO, "Failed to set NONBLOCK on log file %s", file_name);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit Service |
dfccb1 |
FREE_CONST(file_name);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
void
|
|
Packit |
c22fc9 |
flush_log_file(void)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
if (log_file)
|
|
Packit |
c22fc9 |
fflush(log_file);
|
|
Packit |
c22fc9 |
}
|
|
Packit Service |
dfccb1 |
|
|
Packit Service |
dfccb1 |
void
|
|
Packit Service |
dfccb1 |
update_log_file_perms(mode_t umask_bits)
|
|
Packit Service |
dfccb1 |
{
|
|
Packit Service |
dfccb1 |
if (log_file)
|
|
Packit Service |
dfccb1 |
fchmod(fileno(log_file), (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) & ~umask_bits);
|
|
Packit Service |
dfccb1 |
}
|
|
Packit Service |
dfccb1 |
#endif
|
|
Packit Service |
dfccb1 |
|
|
Packit Service |
dfccb1 |
#ifndef HAVE_SIGNALFD
|
|
Packit Service |
dfccb1 |
static inline bool
|
|
Packit Service |
dfccb1 |
block_signals(sigset_t *cur_set)
|
|
Packit Service |
dfccb1 |
{
|
|
Packit Service |
dfccb1 |
sigset_t block_set;
|
|
Packit Service |
dfccb1 |
|
|
Packit Service |
dfccb1 |
sigfillset(&block_set);
|
|
Packit Service |
dfccb1 |
if (!sigprocmask(SIG_BLOCK, &block_set, cur_set))
|
|
Packit Service |
dfccb1 |
return false;
|
|
Packit Service |
dfccb1 |
|
|
Packit Service |
dfccb1 |
/* Yes, we are logging without disabling signals,
|
|
Packit Service |
dfccb1 |
* but it would be useful to know that sigprocmask has
|
|
Packit Service |
dfccb1 |
* failed. The only error that could occur according
|
|
Packit Service |
dfccb1 |
* to sigprocmask(2) is EFAULT, which would be very
|
|
Packit Service |
dfccb1 |
* strange since the sigsets are on the stack. */
|
|
Packit Service |
dfccb1 |
syslog(LOG_ERR, "%s", "sigprocmask failed in block_signals()");
|
|
Packit Service |
dfccb1 |
|
|
Packit Service |
dfccb1 |
return true;
|
|
Packit Service |
dfccb1 |
}
|
|
Packit |
c22fc9 |
#endif
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
void
|
|
Packit Service |
dfccb1 |
vlog_message(int facility, const char* format, va_list args)
|
|
Packit |
c22fc9 |
{
|
|
Packit Service |
dfccb1 |
#ifndef HAVE_SIGNALFD
|
|
Packit Service |
dfccb1 |
sigset_t cur_set;
|
|
Packit Service |
dfccb1 |
bool restore_signals = false;
|
|
Packit Service |
dfccb1 |
#endif
|
|
Packit |
c22fc9 |
#if !HAVE_VSYSLOG
|
|
Packit |
c22fc9 |
char buf[MAX_LOG_MSG+1];
|
|
Packit |
c22fc9 |
#endif
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Don't write syslog if testing configuration */
|
|
Packit |
c22fc9 |
if (__test_bit(CONFIG_TEST_BIT, &debug))
|
|
Packit |
c22fc9 |
return;
|
|
Packit |
c22fc9 |
|
|
Packit Service |
dfccb1 |
#if !HAVE_VSYSLOG
|
|
Packit Service |
dfccb1 |
vsnprintf(buf, sizeof(buf), format, args);
|
|
Packit Service |
dfccb1 |
#endif
|
|
Packit Service |
dfccb1 |
|
|
Packit |
c22fc9 |
if (
|
|
Packit |
c22fc9 |
#ifdef ENABLE_LOG_TO_FILE
|
|
Packit |
c22fc9 |
log_file ||
|
|
Packit |
c22fc9 |
#endif
|
|
Packit |
c22fc9 |
(__test_bit(DONT_FORK_BIT, &debug) && log_console)) {
|
|
Packit |
c22fc9 |
#if HAVE_VSYSLOG
|
|
Packit |
c22fc9 |
va_list args1;
|
|
Packit |
c22fc9 |
char buf[2 * MAX_LOG_MSG + 1];
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
va_copy(args1, args);
|
|
Packit |
c22fc9 |
vsnprintf(buf, sizeof(buf), format, args1);
|
|
Packit |
c22fc9 |
va_end(args1);
|
|
Packit |
c22fc9 |
#endif
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* timestamp setup */
|
|
Packit Service |
dfccb1 |
#ifdef ENABLE_LOG_TO_FILE
|
|
Packit Service |
dfccb1 |
struct timespec ts;
|
|
Packit Service |
dfccb1 |
time_t t;
|
|
Packit Service |
dfccb1 |
char *p;
|
|
Packit Service |
dfccb1 |
|
|
Packit Service |
dfccb1 |
clock_gettime(CLOCK_REALTIME, &ts);
|
|
Packit Service |
dfccb1 |
t = ts.tv_sec;
|
|
Packit Service |
dfccb1 |
#else
|
|
Packit |
c22fc9 |
time_t t = time(NULL);
|
|
Packit Service |
dfccb1 |
#endif
|
|
Packit |
c22fc9 |
struct tm tm;
|
|
Packit |
c22fc9 |
char timestamp[64];
|
|
Packit |
c22fc9 |
|
|
Packit Service |
dfccb1 |
localtime_r(&t, &tm;;
|
|
Packit Service |
dfccb1 |
|
|
Packit Service |
dfccb1 |
if (log_console && __test_bit(DONT_FORK_BIT, &debug)) {
|
|
Packit Service |
dfccb1 |
#ifndef HAVE_SIGNALFD
|
|
Packit Service |
dfccb1 |
if (!block_signals(&cur_set))
|
|
Packit Service |
dfccb1 |
restore_signals = true;
|
|
Packit Service |
dfccb1 |
#endif
|
|
Packit Service |
dfccb1 |
|
|
Packit Service |
dfccb1 |
strftime(timestamp, sizeof(timestamp), "%c", &tm;;
|
|
Packit |
c22fc9 |
fprintf(stderr, "%s: %s\n", timestamp, buf);
|
|
Packit Service |
dfccb1 |
}
|
|
Packit |
c22fc9 |
#ifdef ENABLE_LOG_TO_FILE
|
|
Packit |
c22fc9 |
if (log_file) {
|
|
Packit Service |
dfccb1 |
p = timestamp;
|
|
Packit Service |
dfccb1 |
p += strftime(timestamp, sizeof(timestamp), "%a %b %T", &tm;;
|
|
Packit Service |
dfccb1 |
p += snprintf(p, timestamp + sizeof(timestamp) - p, ".%9.9ld", ts.tv_nsec);
|
|
Packit Service |
dfccb1 |
strftime(p, timestamp + sizeof(timestamp) - p, " %Y", &tm;;
|
|
Packit Service |
dfccb1 |
#ifndef HAVE_SIGNALFD
|
|
Packit Service |
dfccb1 |
if (!restore_signals && !block_signals(&cur_set))
|
|
Packit Service |
dfccb1 |
restore_signals = true;
|
|
Packit Service |
dfccb1 |
#endif
|
|
Packit |
c22fc9 |
fprintf(log_file, "%s: %s\n", timestamp, buf);
|
|
Packit |
c22fc9 |
if (always_flush_log_file)
|
|
Packit |
c22fc9 |
fflush(log_file);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
#endif
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit Service |
dfccb1 |
if (!__test_bit(NO_SYSLOG_BIT, &debug)) {
|
|
Packit Service |
dfccb1 |
#ifndef HAVE_SIGNALFD
|
|
Packit Service |
dfccb1 |
if (!restore_signals && !block_signals(&cur_set))
|
|
Packit Service |
dfccb1 |
restore_signals = true;
|
|
Packit Service |
dfccb1 |
#endif
|
|
Packit Service |
dfccb1 |
|
|
Packit Service |
dfccb1 |
if (!(facility & LOG_FACMASK))
|
|
Packit Service |
dfccb1 |
facility |= LOG_USER;
|
|
Packit Service |
dfccb1 |
|
|
Packit |
c22fc9 |
#if HAVE_VSYSLOG
|
|
Packit |
c22fc9 |
vsyslog(facility, format, args);
|
|
Packit |
c22fc9 |
#else
|
|
Packit |
c22fc9 |
syslog(facility, "%s", buf);
|
|
Packit |
c22fc9 |
#endif
|
|
Packit Service |
dfccb1 |
}
|
|
Packit Service |
dfccb1 |
|
|
Packit Service |
dfccb1 |
#ifndef HAVE_SIGNALFD
|
|
Packit Service |
dfccb1 |
if (restore_signals)
|
|
Packit Service |
dfccb1 |
sigprocmask(SIG_SETMASK, &cur_set, NULL);
|
|
Packit Service |
dfccb1 |
#endif
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
void
|
|
Packit |
c22fc9 |
log_message(const int facility, const char *format, ...)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
va_list args;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
va_start(args, format);
|
|
Packit |
c22fc9 |
vlog_message(facility, format, args);
|
|
Packit |
c22fc9 |
va_end(args);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
void
|
|
Packit |
c22fc9 |
conf_write(FILE *fp, const char *format, ...)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
va_list args;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
va_start(args, format);
|
|
Packit |
c22fc9 |
if (fp) {
|
|
Packit |
c22fc9 |
vfprintf(fp, format, args);
|
|
Packit |
c22fc9 |
fprintf(fp, "\n");
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
else
|
|
Packit |
c22fc9 |
vlog_message(LOG_INFO, format, args);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
va_end(args);
|
|
Packit |
c22fc9 |
}
|