A new tempcomp directive can be used to specify a file for reading current temperature, update interval and compensation coefficients. The clock frequency corrections are applied in local module and are invisible in upper layers. The measurements and corrections can be logged to tempcomp.log file.
361 lines
7.8 KiB
C
361 lines
7.8 KiB
C
/*
|
|
$Header: /cvs/src/chrony/logging.c,v 1.15 2003/09/22 21:22:30 richard Exp $
|
|
|
|
=======================================================================
|
|
|
|
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
|
|
|
**********************************************************************
|
|
* Copyright (C) Richard P. Curnow 1997-2003
|
|
*
|
|
* 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 "sysincl.h"
|
|
|
|
#include "main.h"
|
|
#include "conf.h"
|
|
#include "logging.h"
|
|
#include "version.h"
|
|
#include "mkdirpp.h"
|
|
|
|
/* ================================================== */
|
|
/* Flag indicating we have initialised */
|
|
static int initialised = 0;
|
|
|
|
static int is_detached = 0;
|
|
|
|
static time_t last_limited = 0;
|
|
|
|
#ifdef WINNT
|
|
static FILE *logfile;
|
|
#endif
|
|
|
|
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];
|
|
|
|
/* ================================================== */
|
|
/* Init function */
|
|
|
|
void
|
|
LOG_Initialise(void)
|
|
{
|
|
initialised = 1;
|
|
|
|
#ifdef WINNT
|
|
logfile = fopen("./chronyd.err", "a");
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
/* ================================================== */
|
|
/* Fini function */
|
|
|
|
void
|
|
LOG_Finalise(void)
|
|
{
|
|
#ifdef WINNT
|
|
if (logfile) {
|
|
fclose(logfile);
|
|
}
|
|
#else
|
|
if (is_detached) {
|
|
closelog();
|
|
}
|
|
#endif
|
|
|
|
LOG_CycleLogFiles();
|
|
|
|
initialised = 0;
|
|
return;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
void
|
|
LOG_Line_Function(LOG_Severity severity, LOG_Facility facility, const char *format, ...)
|
|
{
|
|
char buf[2048];
|
|
va_list other_args;
|
|
va_start(other_args, format);
|
|
vsnprintf(buf, sizeof(buf), format, other_args);
|
|
va_end(other_args);
|
|
#ifdef WINNT
|
|
if (logfile) {
|
|
fprintf(logfile, "%s\n", buf);
|
|
}
|
|
#else
|
|
if (is_detached) {
|
|
switch (severity) {
|
|
case LOGS_INFO:
|
|
syslog(LOG_INFO, "%s", buf);
|
|
break;
|
|
case LOGS_WARN:
|
|
syslog(LOG_WARNING, "%s", buf);
|
|
break;
|
|
case LOGS_ERR:
|
|
default:
|
|
syslog(LOG_ERR, "%s", buf);
|
|
break;
|
|
}
|
|
} else {
|
|
fprintf(stderr, "%s\n", buf);
|
|
}
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
void
|
|
LOG_Fatal_Function(LOG_Facility facility, const char *format, ...)
|
|
{
|
|
char buf[2048];
|
|
va_list other_args;
|
|
va_start(other_args, format);
|
|
vsnprintf(buf, sizeof(buf), format, other_args);
|
|
va_end(other_args);
|
|
|
|
#ifdef WINNT
|
|
if (logfile) {
|
|
fprintf(logfile, "Fatal error : %s\n", buf);
|
|
}
|
|
#else
|
|
if (is_detached) {
|
|
syslog(LOG_CRIT, "Fatal error : %s", buf);
|
|
} else {
|
|
fprintf(stderr, "Fatal error : %s\n", buf);
|
|
}
|
|
#endif
|
|
|
|
MAI_CleanupAndExit();
|
|
|
|
return;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
void
|
|
LOG_Position(const char *filename, int line_number, const char *function_name)
|
|
{
|
|
#ifdef WINNT
|
|
#else
|
|
time_t t;
|
|
struct tm stm;
|
|
char buf[64];
|
|
if (!is_detached) {
|
|
/* Don't clutter up syslog with internal debugging info */
|
|
time(&t);
|
|
stm = *gmtime(&t);
|
|
strftime(buf, sizeof(buf), "%d-%H:%M:%S", &stm);
|
|
fprintf(stderr, "%s:%d:(%s)[%s] ", filename, line_number, function_name, buf);
|
|
}
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
void
|
|
LOG_GoDaemon(void)
|
|
{
|
|
#ifdef WINNT
|
|
|
|
|
|
#else
|
|
|
|
int pid, fd;
|
|
|
|
/* Does this preserve existing signal handlers? */
|
|
pid = fork();
|
|
|
|
if (pid < 0) {
|
|
LOG(LOGS_ERR, LOGF_Logging, "Could not detach, fork failed : %s", strerror(errno));
|
|
} else if (pid > 0) {
|
|
exit(0); /* In the 'grandparent' */
|
|
} else {
|
|
|
|
setsid();
|
|
|
|
/* Do 2nd fork, as-per recommended practice for launching daemons. */
|
|
pid = fork();
|
|
|
|
if (pid < 0) {
|
|
LOG(LOGS_ERR, LOGF_Logging, "Could not detach, fork failed : %s", strerror(errno));
|
|
} else if (pid > 0) {
|
|
exit(0); /* In the 'parent' */
|
|
} else {
|
|
/* In the child we want to leave running as the daemon */
|
|
|
|
/* Don't keep stdin/out/err from before. */
|
|
for (fd=0; fd<1024; fd++) {
|
|
close(fd);
|
|
}
|
|
|
|
is_detached = 1;
|
|
|
|
openlog("chronyd", LOG_PID, LOG_DAEMON);
|
|
|
|
LOG(LOGS_INFO, LOGF_Logging, "chronyd version %s starting", PROGRAM_VERSION_STRING);
|
|
|
|
}
|
|
}
|
|
|
|
#endif
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
int
|
|
LOG_RateLimited(void)
|
|
{
|
|
time_t now;
|
|
|
|
now = time(NULL);
|
|
|
|
if (last_limited + 10 > now && last_limited <= now)
|
|
return 1;
|
|
|
|
last_limited = now;
|
|
return 0;
|
|
}
|
|
|
|
/* ================================================== */
|
|
/* Force a core dump and exit without doing abort() or assert(0).
|
|
These do funny things with the call stack in the core file that is
|
|
generated, which makes diagnosis difficult. */
|
|
|
|
int
|
|
croak(const char *file, int line, const char *msg)
|
|
{
|
|
int a;
|
|
LOG(LOGS_ERR, LOGF_Util, "Unexpected condition [%s] at %s:%d, core dumped",
|
|
msg, file, line);
|
|
a = * (int *) 0;
|
|
return a; /* Can't happen - this stops the optimiser optimising the
|
|
line above */
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
LOG_FileID
|
|
LOG_FileOpen(const char *name, const char *banner)
|
|
{
|
|
assert(n_filelogs < MAX_FILELOGS);
|
|
|
|
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;
|
|
|
|
if (id < 0 || id >= n_filelogs || !logfiles[id].name)
|
|
return;
|
|
|
|
if (!logfiles[id].file) {
|
|
char filename[512];
|
|
|
|
if (snprintf(filename, sizeof(filename), "%s/%s.log",
|
|
CNF_GetLogDir(), logfiles[id].name) >= sizeof(filename) ||
|
|
!(logfiles[id].file = fopen(filename, "a"))) {
|
|
LOG(LOGS_WARN, LOGF_Refclock, "Couldn't open logfile %s for update", filename);
|
|
logfiles[id].name = NULL;
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (logfiles[id].writes++ % 32 == 0) {
|
|
char bannerline[256];
|
|
int i, bannerlen;
|
|
|
|
bannerlen = strlen(logfiles[id].banner);
|
|
|
|
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_CreateLogFileDir(void)
|
|
{
|
|
const char *logdir;
|
|
|
|
if (n_filelogs <= 0)
|
|
return;
|
|
|
|
logdir = CNF_GetLogDir();
|
|
|
|
if (!mkdir_and_parents(logdir)) {
|
|
LOG(LOGS_ERR, LOGF_Logging, "Could not create directory %s", logdir);
|
|
n_filelogs = 0;
|
|
}
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
/* ================================================== */
|