]> git.ipfire.org Git - thirdparty/chrony.git/blob - logging.c
ntp: fix log message for replaced source
[thirdparty/chrony.git] / logging.c
1 /*
2 chronyd/chronyc - Programs for keeping computer clocks accurate.
3
4 **********************************************************************
5 * Copyright (C) Richard P. Curnow 1997-2003
6 * Copyright (C) Miroslav Lichvar 2011-2014, 2018
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of version 2 of the GNU General Public License as
10 * published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 **********************************************************************
22
23 =======================================================================
24
25 Module to handle logging of diagnostic information
26 */
27
28 #include "config.h"
29
30 #include "sysincl.h"
31
32 #include <syslog.h>
33
34 #include "conf.h"
35 #include "logging.h"
36 #include "util.h"
37
38 /* This is used by DEBUG_LOG macro */
39 LOG_Severity log_min_severity = LOGS_INFO;
40
41 /* ================================================== */
42 /* Flag indicating we have initialised */
43 static int initialised = 0;
44
45 static FILE *file_log = NULL;
46 static int system_log = 0;
47
48 static int parent_fd = 0;
49
50 struct LogFile {
51 const char *name;
52 const char *banner;
53 FILE *file;
54 unsigned long writes;
55 };
56
57 static int n_filelogs = 0;
58
59 /* Increase this when adding a new logfile */
60 #define MAX_FILELOGS 6
61
62 static struct LogFile logfiles[MAX_FILELOGS];
63
64 /* ================================================== */
65 /* Init function */
66
67 void
68 LOG_Initialise(void)
69 {
70 initialised = 1;
71 LOG_OpenFileLog(NULL);
72 }
73
74 /* ================================================== */
75 /* Fini function */
76
77 void
78 LOG_Finalise(void)
79 {
80 if (system_log)
81 closelog();
82
83 if (file_log)
84 fclose(file_log);
85
86 LOG_CycleLogFiles();
87
88 initialised = 0;
89 }
90
91 /* ================================================== */
92
93 static void log_message(int fatal, LOG_Severity severity, const char *message)
94 {
95 if (system_log) {
96 int priority;
97 switch (severity) {
98 case LOGS_DEBUG:
99 priority = LOG_DEBUG;
100 break;
101 case LOGS_INFO:
102 priority = LOG_INFO;
103 break;
104 case LOGS_WARN:
105 priority = LOG_WARNING;
106 break;
107 case LOGS_ERR:
108 priority = LOG_ERR;
109 break;
110 case LOGS_FATAL:
111 priority = LOG_CRIT;
112 break;
113 default:
114 assert(0);
115 }
116 syslog(priority, fatal ? "Fatal error : %s" : "%s", message);
117 } else if (file_log) {
118 fprintf(file_log, fatal ? "Fatal error : %s\n" : "%s\n", message);
119 }
120 }
121
122 /* ================================================== */
123
124 void LOG_Message(LOG_Severity severity,
125 #if DEBUG > 0
126 int line_number, const char *filename, const char *function_name,
127 #endif
128 const char *format, ...)
129 {
130 char buf[2048];
131 va_list other_args;
132 time_t t;
133 struct tm *tm;
134
135 if (!system_log && file_log && severity >= log_min_severity) {
136 /* Don't clutter up syslog with timestamps and internal debugging info */
137 time(&t);
138 tm = gmtime(&t);
139 if (tm) {
140 strftime(buf, sizeof (buf), "%Y-%m-%dT%H:%M:%SZ", tm);
141 fprintf(file_log, "%s ", buf);
142 }
143 #if DEBUG > 0
144 if (log_min_severity <= LOGS_DEBUG)
145 fprintf(file_log, "%s:%d:(%s) ", filename, line_number, function_name);
146 #endif
147 }
148
149 va_start(other_args, format);
150 vsnprintf(buf, sizeof(buf), format, other_args);
151 va_end(other_args);
152
153 switch (severity) {
154 case LOGS_DEBUG:
155 case LOGS_INFO:
156 case LOGS_WARN:
157 case LOGS_ERR:
158 if (severity >= log_min_severity)
159 log_message(0, severity, buf);
160 break;
161 case LOGS_FATAL:
162 if (severity >= log_min_severity)
163 log_message(1, severity, buf);
164
165 /* Send the message also to the foreground process if it is
166 still running, or stderr if it is still open */
167 if (parent_fd > 0) {
168 if (write(parent_fd, buf, strlen(buf) + 1) < 0)
169 ; /* Not much we can do here */
170 } else if (system_log && parent_fd == 0) {
171 system_log = 0;
172 log_message(1, severity, buf);
173 }
174 exit(1);
175 break;
176 default:
177 assert(0);
178 }
179 }
180
181 /* ================================================== */
182
183 void
184 LOG_OpenFileLog(const char *log_file)
185 {
186 FILE *f;
187
188 if (log_file) {
189 f = UTI_OpenFile(NULL, log_file, NULL, 'A', 0640);
190 } else {
191 f = stderr;
192 }
193
194 /* Enable line buffering */
195 setvbuf(f, NULL, _IOLBF, BUFSIZ);
196
197 if (file_log && file_log != stderr)
198 fclose(file_log);
199
200 file_log = f;
201 }
202
203
204 /* ================================================== */
205
206 void
207 LOG_OpenSystemLog(void)
208 {
209 system_log = 1;
210 openlog("chronyd", LOG_PID, LOG_DAEMON);
211 }
212
213 /* ================================================== */
214
215 void LOG_SetMinSeverity(LOG_Severity severity)
216 {
217 /* Don't print any debug messages in a non-debug build */
218 log_min_severity = CLAMP(DEBUG > 0 ? LOGS_DEBUG : LOGS_INFO, severity, LOGS_FATAL);
219 }
220
221 /* ================================================== */
222
223 void
224 LOG_SetParentFd(int fd)
225 {
226 parent_fd = fd;
227 if (file_log == stderr)
228 file_log = NULL;
229 }
230
231 /* ================================================== */
232
233 void
234 LOG_CloseParentFd()
235 {
236 if (parent_fd > 0)
237 close(parent_fd);
238 parent_fd = -1;
239 }
240
241 /* ================================================== */
242
243 LOG_FileID
244 LOG_FileOpen(const char *name, const char *banner)
245 {
246 assert(n_filelogs < MAX_FILELOGS);
247
248 logfiles[n_filelogs].name = name;
249 logfiles[n_filelogs].banner = banner;
250 logfiles[n_filelogs].file = NULL;
251 logfiles[n_filelogs].writes = 0;
252
253 return n_filelogs++;
254 }
255
256 /* ================================================== */
257
258 void
259 LOG_FileWrite(LOG_FileID id, const char *format, ...)
260 {
261 va_list other_args;
262 int banner;
263
264 if (id < 0 || id >= n_filelogs || !logfiles[id].name)
265 return;
266
267 if (!logfiles[id].file) {
268 char *logdir = CNF_GetLogDir();
269
270 if (logdir[0] == '\0') {
271 LOG(LOGS_WARN, "logdir not specified");
272 logfiles[id].name = NULL;
273 return;
274 }
275
276 logfiles[id].file = UTI_OpenFile(logdir, logfiles[id].name, ".log", 'a', 0644);
277 if (!logfiles[id].file) {
278 /* Disable the log */
279 logfiles[id].name = NULL;
280 return;
281 }
282 }
283
284 banner = CNF_GetLogBanner();
285 if (banner && logfiles[id].writes++ % banner == 0) {
286 char bannerline[256];
287 int i, bannerlen;
288
289 bannerlen = MIN(strlen(logfiles[id].banner), sizeof (bannerline) - 1);
290
291 for (i = 0; i < bannerlen; i++)
292 bannerline[i] = '=';
293 bannerline[i] = '\0';
294
295 fprintf(logfiles[id].file, "%s\n", bannerline);
296 fprintf(logfiles[id].file, "%s\n", logfiles[id].banner);
297 fprintf(logfiles[id].file, "%s\n", bannerline);
298 }
299
300 va_start(other_args, format);
301 vfprintf(logfiles[id].file, format, other_args);
302 va_end(other_args);
303 fprintf(logfiles[id].file, "\n");
304
305 fflush(logfiles[id].file);
306 }
307
308 /* ================================================== */
309
310 void
311 LOG_CycleLogFiles(void)
312 {
313 LOG_FileID i;
314
315 for (i = 0; i < n_filelogs; i++) {
316 if (logfiles[i].file)
317 fclose(logfiles[i].file);
318 logfiles[i].file = NULL;
319 logfiles[i].writes = 0;
320 }
321 }
322
323 /* ================================================== */