]>
Commit | Line | Data |
---|---|---|
88840341 | 1 | /* |
88840341 RC |
2 | chronyd/chronyc - Programs for keeping computer clocks accurate. |
3 | ||
4 | ********************************************************************** | |
6672f045 | 5 | * Copyright (C) Richard P. Curnow 1997-2003 |
3916c336 | 6 | * Copyright (C) Miroslav Lichvar 2011-2014, 2018-2020 |
88840341 RC |
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., | |
8e23110a | 19 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
88840341 RC |
20 | * |
21 | ********************************************************************** | |
22 | ||
23 | ======================================================================= | |
24 | ||
25 | Module to handle logging of diagnostic information | |
26 | */ | |
27 | ||
da2c8d90 ML |
28 | #include "config.h" |
29 | ||
88840341 RC |
30 | #include "sysincl.h" |
31 | ||
903fa247 ML |
32 | #include <syslog.h> |
33 | ||
e78e65ef | 34 | #include "conf.h" |
88840341 | 35 | #include "logging.h" |
51d77d6c | 36 | #include "memory.h" |
9d35b5de | 37 | #include "util.h" |
88840341 | 38 | |
0dea8d97 | 39 | /* This is used by DEBUG_LOG macro */ |
1227873b | 40 | LOG_Severity log_min_severity = LOGS_INFO; |
0dea8d97 | 41 | |
88840341 RC |
42 | /* ================================================== */ |
43 | /* Flag indicating we have initialised */ | |
44 | static int initialised = 0; | |
45 | ||
d05e9fb2 | 46 | static FILE *file_log = NULL; |
fe4b661f | 47 | static int system_log = 0; |
88840341 | 48 | |
1d2a0856 ML |
49 | static int parent_fd = 0; |
50 | ||
e78e65ef ML |
51 | struct LogFile { |
52 | const char *name; | |
53 | const char *banner; | |
54 | FILE *file; | |
55 | unsigned long writes; | |
56 | }; | |
57 | ||
58 | static int n_filelogs = 0; | |
59 | ||
60 | /* Increase this when adding a new logfile */ | |
c386d117 | 61 | #define MAX_FILELOGS 6 |
e78e65ef ML |
62 | |
63 | static struct LogFile logfiles[MAX_FILELOGS]; | |
64 | ||
51d77d6c ML |
65 | /* Global prefix for debug messages */ |
66 | static char *debug_prefix; | |
67 | ||
88840341 RC |
68 | /* ================================================== */ |
69 | /* Init function */ | |
70 | ||
71 | void | |
72 | LOG_Initialise(void) | |
73 | { | |
51d77d6c | 74 | debug_prefix = Strdup(""); |
88840341 | 75 | initialised = 1; |
d05e9fb2 | 76 | LOG_OpenFileLog(NULL); |
88840341 RC |
77 | } |
78 | ||
79 | /* ================================================== */ | |
80 | /* Fini function */ | |
81 | ||
82 | void | |
83 | LOG_Finalise(void) | |
84 | { | |
7b98443a | 85 | if (system_log) |
88840341 | 86 | closelog(); |
7b98443a ML |
87 | |
88 | if (file_log) | |
6cbeb107 | 89 | fclose(file_log); |
88840341 | 90 | |
e78e65ef ML |
91 | LOG_CycleLogFiles(); |
92 | ||
51d77d6c ML |
93 | Free(debug_prefix); |
94 | ||
88840341 | 95 | initialised = 0; |
88840341 RC |
96 | } |
97 | ||
98 | /* ================================================== */ | |
99 | ||
cd7bfa25 | 100 | static void log_message(int fatal, LOG_Severity severity, const char *message) |
88840341 | 101 | { |
fe4b661f | 102 | if (system_log) { |
cd7bfa25 | 103 | int priority; |
88840341 | 104 | switch (severity) { |
4bbc5520 ML |
105 | case LOGS_DEBUG: |
106 | priority = LOG_DEBUG; | |
107 | break; | |
88840341 | 108 | case LOGS_INFO: |
cd7bfa25 | 109 | priority = LOG_INFO; |
88840341 RC |
110 | break; |
111 | case LOGS_WARN: | |
cd7bfa25 | 112 | priority = LOG_WARNING; |
88840341 RC |
113 | break; |
114 | case LOGS_ERR: | |
cd7bfa25 ML |
115 | priority = LOG_ERR; |
116 | break; | |
117 | case LOGS_FATAL: | |
118 | priority = LOG_CRIT; | |
88840341 | 119 | break; |
cd7bfa25 ML |
120 | default: |
121 | assert(0); | |
88840341 | 122 | } |
cd7bfa25 | 123 | syslog(priority, fatal ? "Fatal error : %s" : "%s", message); |
7b98443a | 124 | } else if (file_log) { |
6cbeb107 | 125 | fprintf(file_log, fatal ? "Fatal error : %s\n" : "%s\n", message); |
88840341 | 126 | } |
88840341 RC |
127 | } |
128 | ||
129 | /* ================================================== */ | |
130 | ||
7b2430fc ML |
131 | void LOG_Message(LOG_Severity severity, |
132 | #if DEBUG > 0 | |
f282856c | 133 | int line_number, const char *filename, const char *function_name, |
7b2430fc ML |
134 | #endif |
135 | const char *format, ...) | |
88840341 RC |
136 | { |
137 | char buf[2048]; | |
138 | va_list other_args; | |
cd7bfa25 | 139 | time_t t; |
63fe34e8 | 140 | struct tm *tm; |
88840341 | 141 | |
51d77d6c ML |
142 | assert(initialised); |
143 | ||
1227873b | 144 | if (!system_log && file_log && severity >= log_min_severity) { |
788e7fcd | 145 | /* Don't clutter up syslog with timestamps and internal debugging info */ |
88840341 | 146 | time(&t); |
63fe34e8 ML |
147 | tm = gmtime(&t); |
148 | if (tm) { | |
149 | strftime(buf, sizeof (buf), "%Y-%m-%dT%H:%M:%SZ", tm); | |
150 | fprintf(file_log, "%s ", buf); | |
151 | } | |
7b2430fc | 152 | #if DEBUG > 0 |
1227873b | 153 | if (log_min_severity <= LOGS_DEBUG) |
51d77d6c | 154 | fprintf(file_log, "%s%s:%d:(%s) ", debug_prefix, filename, line_number, function_name); |
7b2430fc | 155 | #endif |
88840341 | 156 | } |
cd7bfa25 ML |
157 | |
158 | va_start(other_args, format); | |
159 | vsnprintf(buf, sizeof(buf), format, other_args); | |
160 | va_end(other_args); | |
161 | ||
162 | switch (severity) { | |
4bbc5520 | 163 | case LOGS_DEBUG: |
cd7bfa25 ML |
164 | case LOGS_INFO: |
165 | case LOGS_WARN: | |
166 | case LOGS_ERR: | |
1227873b ML |
167 | if (severity >= log_min_severity) |
168 | log_message(0, severity, buf); | |
cd7bfa25 ML |
169 | break; |
170 | case LOGS_FATAL: | |
1227873b ML |
171 | if (severity >= log_min_severity) |
172 | log_message(1, severity, buf); | |
cd7bfa25 | 173 | |
7b98443a ML |
174 | /* Send the message also to the foreground process if it is |
175 | still running, or stderr if it is still open */ | |
176 | if (parent_fd > 0) { | |
177 | if (write(parent_fd, buf, strlen(buf) + 1) < 0) | |
178 | ; /* Not much we can do here */ | |
179 | } else if (system_log && parent_fd == 0) { | |
180 | system_log = 0; | |
181 | log_message(1, severity, buf); | |
cd7bfa25 | 182 | } |
f4c6a00b | 183 | exit(1); |
cd7bfa25 ML |
184 | break; |
185 | default: | |
186 | assert(0); | |
187 | } | |
88840341 RC |
188 | } |
189 | ||
6cbeb107 ML |
190 | /* ================================================== */ |
191 | ||
192 | void | |
193 | LOG_OpenFileLog(const char *log_file) | |
194 | { | |
195 | FILE *f; | |
196 | ||
eb8c9ad6 | 197 | if (log_file) { |
794cbfbb | 198 | f = UTI_OpenFile(NULL, log_file, NULL, 'A', 0640); |
eb8c9ad6 ML |
199 | } else { |
200 | f = stderr; | |
201 | } | |
6cbeb107 | 202 | |
d70df3da ML |
203 | /* Enable line buffering */ |
204 | setvbuf(f, NULL, _IOLBF, BUFSIZ); | |
205 | ||
68475366 ML |
206 | if (file_log && file_log != stderr) |
207 | fclose(file_log); | |
208 | ||
6cbeb107 ML |
209 | file_log = f; |
210 | } | |
211 | ||
212 | ||
88840341 RC |
213 | /* ================================================== */ |
214 | ||
215 | void | |
fe4b661f | 216 | LOG_OpenSystemLog(void) |
88840341 | 217 | { |
fe4b661f ML |
218 | system_log = 1; |
219 | openlog("chronyd", LOG_PID, LOG_DAEMON); | |
88840341 RC |
220 | } |
221 | ||
032ac800 ML |
222 | /* ================================================== */ |
223 | ||
1227873b | 224 | void LOG_SetMinSeverity(LOG_Severity severity) |
4bbc5520 | 225 | { |
c7223f4c ML |
226 | /* Don't print any debug messages in a non-debug build */ |
227 | log_min_severity = CLAMP(DEBUG > 0 ? LOGS_DEBUG : LOGS_INFO, severity, LOGS_FATAL); | |
4bbc5520 ML |
228 | } |
229 | ||
230 | /* ================================================== */ | |
231 | ||
51d77d6c ML |
232 | LOG_Severity |
233 | LOG_GetMinSeverity(void) | |
234 | { | |
235 | return log_min_severity; | |
236 | } | |
237 | ||
238 | /* ================================================== */ | |
239 | ||
240 | void | |
241 | LOG_SetDebugPrefix(const char *prefix) | |
242 | { | |
243 | Free(debug_prefix); | |
244 | debug_prefix = Strdup(prefix); | |
245 | } | |
246 | ||
247 | /* ================================================== */ | |
248 | ||
1d2a0856 ML |
249 | void |
250 | LOG_SetParentFd(int fd) | |
251 | { | |
252 | parent_fd = fd; | |
7b98443a ML |
253 | if (file_log == stderr) |
254 | file_log = NULL; | |
1d2a0856 ML |
255 | } |
256 | ||
257 | /* ================================================== */ | |
258 | ||
259 | void | |
260 | LOG_CloseParentFd() | |
261 | { | |
262 | if (parent_fd > 0) | |
263 | close(parent_fd); | |
ed0ac6e3 | 264 | parent_fd = -1; |
1d2a0856 ML |
265 | } |
266 | ||
267 | /* ================================================== */ | |
268 | ||
e78e65ef ML |
269 | LOG_FileID |
270 | LOG_FileOpen(const char *name, const char *banner) | |
271 | { | |
c9f03fb2 ML |
272 | if (n_filelogs >= MAX_FILELOGS) { |
273 | assert(0); | |
274 | return -1; | |
275 | } | |
e78e65ef ML |
276 | |
277 | logfiles[n_filelogs].name = name; | |
278 | logfiles[n_filelogs].banner = banner; | |
279 | logfiles[n_filelogs].file = NULL; | |
280 | logfiles[n_filelogs].writes = 0; | |
281 | ||
282 | return n_filelogs++; | |
283 | } | |
284 | ||
285 | /* ================================================== */ | |
286 | ||
287 | void | |
288 | LOG_FileWrite(LOG_FileID id, const char *format, ...) | |
289 | { | |
290 | va_list other_args; | |
7ab2c0e4 | 291 | int banner; |
e78e65ef ML |
292 | |
293 | if (id < 0 || id >= n_filelogs || !logfiles[id].name) | |
294 | return; | |
295 | ||
296 | if (!logfiles[id].file) { | |
e18903a6 | 297 | char *logdir = CNF_GetLogDir(); |
fb5d4f1d | 298 | |
60049f15 | 299 | if (!logdir) { |
f282856c | 300 | LOG(LOGS_WARN, "logdir not specified"); |
fb5d4f1d ML |
301 | logfiles[id].name = NULL; |
302 | return; | |
303 | } | |
e78e65ef | 304 | |
e18903a6 ML |
305 | logfiles[id].file = UTI_OpenFile(logdir, logfiles[id].name, ".log", 'a', 0644); |
306 | if (!logfiles[id].file) { | |
307 | /* Disable the log */ | |
e78e65ef ML |
308 | logfiles[id].name = NULL; |
309 | return; | |
310 | } | |
311 | } | |
312 | ||
7ab2c0e4 ML |
313 | banner = CNF_GetLogBanner(); |
314 | if (banner && logfiles[id].writes++ % banner == 0) { | |
e78e65ef ML |
315 | char bannerline[256]; |
316 | int i, bannerlen; | |
317 | ||
96771d68 | 318 | bannerlen = MIN(strlen(logfiles[id].banner), sizeof (bannerline) - 1); |
e78e65ef ML |
319 | |
320 | for (i = 0; i < bannerlen; i++) | |
321 | bannerline[i] = '='; | |
322 | bannerline[i] = '\0'; | |
323 | ||
324 | fprintf(logfiles[id].file, "%s\n", bannerline); | |
325 | fprintf(logfiles[id].file, "%s\n", logfiles[id].banner); | |
326 | fprintf(logfiles[id].file, "%s\n", bannerline); | |
327 | } | |
328 | ||
329 | va_start(other_args, format); | |
330 | vfprintf(logfiles[id].file, format, other_args); | |
331 | va_end(other_args); | |
332 | fprintf(logfiles[id].file, "\n"); | |
333 | ||
334 | fflush(logfiles[id].file); | |
335 | } | |
336 | ||
337 | /* ================================================== */ | |
338 | ||
e78e65ef ML |
339 | void |
340 | LOG_CycleLogFiles(void) | |
341 | { | |
342 | LOG_FileID i; | |
343 | ||
344 | for (i = 0; i < n_filelogs; i++) { | |
345 | if (logfiles[i].file) | |
346 | fclose(logfiles[i].file); | |
347 | logfiles[i].file = NULL; | |
348 | logfiles[i].writes = 0; | |
349 | } | |
350 | } | |
351 | ||
352 | /* ================================================== */ |