Blame lib/logger.c

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
}