summaryrefslogtreecommitdiffstats
path: root/logging.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--logging.c352
1 files changed, 352 insertions, 0 deletions
diff --git a/logging.c b/logging.c
new file mode 100644
index 0000000..d858d2a
--- /dev/null
+++ b/logging.c
@@ -0,0 +1,352 @@
+/*
+ chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Richard P. Curnow 1997-2003
+ * Copyright (C) Miroslav Lichvar 2011-2014, 2018-2020
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * 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 General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ **********************************************************************
+
+ =======================================================================
+
+ Module to handle logging of diagnostic information
+ */
+
+#include "config.h"
+
+#include "sysincl.h"
+
+#include <syslog.h>
+
+#include "conf.h"
+#include "logging.h"
+#include "memory.h"
+#include "util.h"
+
+/* This is used by DEBUG_LOG macro */
+LOG_Severity log_min_severity = LOGS_INFO;
+
+/* ================================================== */
+/* Flag indicating we have initialised */
+static int initialised = 0;
+
+static FILE *file_log = NULL;
+static int system_log = 0;
+
+static int parent_fd = 0;
+
+struct LogFile {
+ const char *name;
+ const char *banner;
+ FILE *file;
+ unsigned long writes;
+};
+
+static int n_filelogs = 0;
+
+/* Increase this when adding a new logfile */
+#define MAX_FILELOGS 6
+
+static struct LogFile logfiles[MAX_FILELOGS];
+
+/* Global prefix for debug messages */
+static char *debug_prefix;
+
+/* ================================================== */
+/* Init function */
+
+void
+LOG_Initialise(void)
+{
+ debug_prefix = Strdup("");
+ initialised = 1;
+ LOG_OpenFileLog(NULL);
+}
+
+/* ================================================== */
+/* Fini function */
+
+void
+LOG_Finalise(void)
+{
+ if (system_log)
+ closelog();
+
+ if (file_log)
+ fclose(file_log);
+
+ LOG_CycleLogFiles();
+
+ Free(debug_prefix);
+
+ initialised = 0;
+}
+
+/* ================================================== */
+
+static void log_message(int fatal, LOG_Severity severity, const char *message)
+{
+ if (system_log) {
+ int priority;
+ switch (severity) {
+ case LOGS_DEBUG:
+ priority = LOG_DEBUG;
+ break;
+ case LOGS_INFO:
+ priority = LOG_INFO;
+ break;
+ case LOGS_WARN:
+ priority = LOG_WARNING;
+ break;
+ case LOGS_ERR:
+ priority = LOG_ERR;
+ break;
+ case LOGS_FATAL:
+ priority = LOG_CRIT;
+ break;
+ default:
+ assert(0);
+ }
+ syslog(priority, fatal ? "Fatal error : %s" : "%s", message);
+ } else if (file_log) {
+ fprintf(file_log, fatal ? "Fatal error : %s\n" : "%s\n", message);
+ }
+}
+
+/* ================================================== */
+
+void LOG_Message(LOG_Severity severity,
+#if DEBUG > 0
+ int line_number, const char *filename, const char *function_name,
+#endif
+ const char *format, ...)
+{
+ char buf[2048];
+ va_list other_args;
+ time_t t;
+ struct tm *tm;
+
+ assert(initialised);
+
+ if (!system_log && file_log && severity >= log_min_severity) {
+ /* Don't clutter up syslog with timestamps and internal debugging info */
+ time(&t);
+ tm = gmtime(&t);
+ if (tm) {
+ strftime(buf, sizeof (buf), "%Y-%m-%dT%H:%M:%SZ", tm);
+ fprintf(file_log, "%s ", buf);
+ }
+#if DEBUG > 0
+ if (log_min_severity <= LOGS_DEBUG)
+ fprintf(file_log, "%s%s:%d:(%s) ", debug_prefix, filename, line_number, function_name);
+#endif
+ }
+
+ va_start(other_args, format);
+ vsnprintf(buf, sizeof(buf), format, other_args);
+ va_end(other_args);
+
+ switch (severity) {
+ case LOGS_DEBUG:
+ case LOGS_INFO:
+ case LOGS_WARN:
+ case LOGS_ERR:
+ if (severity >= log_min_severity)
+ log_message(0, severity, buf);
+ break;
+ case LOGS_FATAL:
+ if (severity >= log_min_severity)
+ log_message(1, severity, buf);
+
+ /* Send the message also to the foreground process if it is
+ still running, or stderr if it is still open */
+ if (parent_fd > 0) {
+ if (write(parent_fd, buf, strlen(buf) + 1) < 0)
+ ; /* Not much we can do here */
+ } else if (system_log && parent_fd == 0) {
+ system_log = 0;
+ log_message(1, severity, buf);
+ }
+ exit(1);
+ break;
+ default:
+ assert(0);
+ }
+}
+
+/* ================================================== */
+
+void
+LOG_OpenFileLog(const char *log_file)
+{
+ FILE *f;
+
+ if (log_file) {
+ f = UTI_OpenFile(NULL, log_file, NULL, 'A', 0640);
+ } else {
+ f = stderr;
+ }
+
+ /* Enable line buffering */
+ setvbuf(f, NULL, _IOLBF, BUFSIZ);
+
+ if (file_log && file_log != stderr)
+ fclose(file_log);
+
+ file_log = f;
+}
+
+
+/* ================================================== */
+
+void
+LOG_OpenSystemLog(void)
+{
+ system_log = 1;
+ openlog("chronyd", LOG_PID, LOG_DAEMON);
+}
+
+/* ================================================== */
+
+void LOG_SetMinSeverity(LOG_Severity severity)
+{
+ /* Don't print any debug messages in a non-debug build */
+ log_min_severity = CLAMP(DEBUG > 0 ? LOGS_DEBUG : LOGS_INFO, severity, LOGS_FATAL);
+}
+
+/* ================================================== */
+
+LOG_Severity
+LOG_GetMinSeverity(void)
+{
+ return log_min_severity;
+}
+
+/* ================================================== */
+
+void
+LOG_SetDebugPrefix(const char *prefix)
+{
+ Free(debug_prefix);
+ debug_prefix = Strdup(prefix);
+}
+
+/* ================================================== */
+
+void
+LOG_SetParentFd(int fd)
+{
+ parent_fd = fd;
+ if (file_log == stderr)
+ file_log = NULL;
+}
+
+/* ================================================== */
+
+void
+LOG_CloseParentFd()
+{
+ if (parent_fd > 0)
+ close(parent_fd);
+ parent_fd = -1;
+}
+
+/* ================================================== */
+
+LOG_FileID
+LOG_FileOpen(const char *name, const char *banner)
+{
+ if (n_filelogs >= MAX_FILELOGS) {
+ assert(0);
+ return -1;
+ }
+
+ logfiles[n_filelogs].name = name;
+ logfiles[n_filelogs].banner = banner;
+ logfiles[n_filelogs].file = NULL;
+ logfiles[n_filelogs].writes = 0;
+
+ return n_filelogs++;
+}
+
+/* ================================================== */
+
+void
+LOG_FileWrite(LOG_FileID id, const char *format, ...)
+{
+ va_list other_args;
+ int banner;
+
+ if (id < 0 || id >= n_filelogs || !logfiles[id].name)
+ return;
+
+ if (!logfiles[id].file) {
+ char *logdir = CNF_GetLogDir();
+
+ if (!logdir) {
+ LOG(LOGS_WARN, "logdir not specified");
+ logfiles[id].name = NULL;
+ return;
+ }
+
+ logfiles[id].file = UTI_OpenFile(logdir, logfiles[id].name, ".log", 'a', 0644);
+ if (!logfiles[id].file) {
+ /* Disable the log */
+ logfiles[id].name = NULL;
+ return;
+ }
+ }
+
+ banner = CNF_GetLogBanner();
+ if (banner && logfiles[id].writes++ % banner == 0) {
+ char bannerline[256];
+ int i, bannerlen;
+
+ bannerlen = MIN(strlen(logfiles[id].banner), sizeof (bannerline) - 1);
+
+ for (i = 0; i < bannerlen; i++)
+ bannerline[i] = '=';
+ bannerline[i] = '\0';
+
+ fprintf(logfiles[id].file, "%s\n", bannerline);
+ fprintf(logfiles[id].file, "%s\n", logfiles[id].banner);
+ fprintf(logfiles[id].file, "%s\n", bannerline);
+ }
+
+ va_start(other_args, format);
+ vfprintf(logfiles[id].file, format, other_args);
+ va_end(other_args);
+ fprintf(logfiles[id].file, "\n");
+
+ fflush(logfiles[id].file);
+}
+
+/* ================================================== */
+
+void
+LOG_CycleLogFiles(void)
+{
+ LOG_FileID i;
+
+ for (i = 0; i < n_filelogs; i++) {
+ if (logfiles[i].file)
+ fclose(logfiles[i].file);
+ logfiles[i].file = NULL;
+ logfiles[i].writes = 0;
+ }
+}
+
+/* ================================================== */