]> git.ipfire.org Git - thirdparty/bird.git/blame - sysdep/unix/log.c
The MRT protocol
[thirdparty/bird.git] / sysdep / unix / log.c
CommitLineData
6032aa6a
MM
1/*
2 * BIRD Library -- Logging Functions
3 *
73275d85 4 * (c) 1998--2000 Martin Mares <mj@ucw.cz>
6032aa6a
MM
5 *
6 * Can be freely distributed and used under the terms of the GNU GPL.
7 */
8
73275d85
MM
9/**
10 * DOC: Logging
11 *
12 * The Logging module offers a simple set of functions for writing
725270cb
MM
13 * messages to system logs and to the debug output. Message classes
14 * used by this module are described in |birdlib.h| and also in the
15 * user's manual.
73275d85
MM
16 */
17
6032aa6a
MM
18#include <stdio.h>
19#include <stdlib.h>
20#include <stdarg.h>
01b776e1 21#include <time.h>
6712e772
OZ
22#include <sys/types.h>
23#include <sys/stat.h>
e81b440f 24#include <unistd.h>
f0b822a8 25#include <errno.h>
6032aa6a
MM
26
27#include "nest/bird.h"
34350a52 28#include "nest/cli.h"
863ecfc7 29#include "conf/conf.h"
9556f225 30#include "lib/string.h"
a0c37b45 31#include "lib/lists.h"
7152e5ef 32#include "sysdep/unix/unix.h"
6032aa6a 33
44d4ab7a 34static FILE *dbgf;
a0c37b45 35static list *current_log_list;
44d4ab7a 36static char *current_syslog_name; /* NULL -> syslog closed */
6032aa6a 37
0e175f9f 38
1ec52253 39#ifdef USE_PTHREADS
0e175f9f
OZ
40
41#include <pthread.h>
4e398e34 42
0e175f9f
OZ
43static pthread_mutex_t log_mutex;
44static inline void log_lock(void) { pthread_mutex_lock(&log_mutex); }
45static inline void log_unlock(void) { pthread_mutex_unlock(&log_mutex); }
46
4e398e34
OZ
47static pthread_t main_thread;
48void main_thread_init(void) { main_thread = pthread_self(); }
49static int main_thread_self(void) { return pthread_equal(pthread_self(), main_thread); }
50
1ec52253
OZ
51#else
52
53static inline void log_lock(void) { }
54static inline void log_unlock(void) { }
4e398e34
OZ
55void main_thread_init(void) { }
56static int main_thread_self(void) { return 1; }
1ec52253
OZ
57
58#endif
59
cb530392 60
5d6dc930 61#ifdef HAVE_SYSLOG_H
6032aa6a
MM
62#include <sys/syslog.h>
63
64static int syslog_priorities[] = {
a0c37b45
MM
65 LOG_DEBUG,
66 LOG_DEBUG,
6032aa6a
MM
67 LOG_DEBUG,
68 LOG_INFO,
a0c37b45 69 LOG_ERR,
6032aa6a
MM
70 LOG_WARNING,
71 LOG_ERR,
a0c37b45
MM
72 LOG_ERR,
73 LOG_CRIT,
6032aa6a
MM
74 LOG_CRIT
75};
76#endif
77
78static char *class_names[] = {
79 "???",
80 "DBG",
a0c37b45 81 "TRACE",
6032aa6a 82 "INFO",
a0c37b45 83 "RMT",
6032aa6a
MM
84 "WARN",
85 "ERR",
86 "AUTH",
a0c37b45
MM
87 "FATAL",
88 "BUG"
6032aa6a
MM
89};
90
6712e772
OZ
91static inline off_t
92log_size(struct log_config *l)
93{
94 struct stat st;
95 return (!fstat(rf_fileno(l->rf), &st) && S_ISREG(st.st_mode)) ? st.st_size : 0;
96}
97
98static void
99log_close(struct log_config *l)
100{
101 rfree(l->rf);
102 l->rf = NULL;
103 l->fh = NULL;
104}
105
106static int
107log_open(struct log_config *l)
108{
109 l->rf = rf_open(config->pool, l->filename, "a");
110 if (!l->rf)
111 {
112 /* Well, we cannot do much in case of error as log is closed */
113 l->mask = 0;
114 return -1;
115 }
116
117 l->fh = rf_file(l->rf);
118 l->pos = log_size(l);
119
120 return 0;
121}
122
123static int
124log_rotate(struct log_config *l)
125{
126 log_close(l);
127
128 /* If we cannot rename the logfile, we at least try to delete it
129 in order to continue logging and not exceeding logfile size */
130 if ((rename(l->filename, l->backup) < 0) &&
131 (unlink(l->filename) < 0))
132 {
133 l->mask = 0;
134 return -1;
135 }
136
137 return log_open(l);
138}
9556f225 139
0d1b3c4c
OZ
140/**
141 * log_commit - commit a log message
142 * @class: message class information (%L_DEBUG to %L_BUG, see |lib/birdlib.h|)
8e433d6a 143 * @buf: message to write
0d1b3c4c
OZ
144 *
145 * This function writes a message prepared in the log buffer to the
146 * log file (as specified in the configuration). The log buffer is
147 * reset after that. The log message is a full line, log_commit()
148 * terminates it.
149 *
150 * The message class is an integer, not a first char of a string like
151 * in log(), so it should be written like *L_INFO.
152 */
153void
0e175f9f 154log_commit(int class, buffer *buf)
0d1b3c4c
OZ
155{
156 struct log_config *l;
9556f225 157
0e175f9f
OZ
158 if (buf->pos == buf->end)
159 strcpy(buf->end - 100, " ... <too long>");
160
161 log_lock();
a0c37b45 162 WALK_LIST(l, *current_log_list)
6032aa6a 163 {
a0c37b45
MM
164 if (!(l->mask & (1 << class)))
165 continue;
166 if (l->fh)
167 {
a0c37b45
MM
168 if (l->terminal_flag)
169 fputs("bird: ", l->fh);
170 else
171 {
c37e7851 172 byte tbuf[TM_DATETIME_BUFFER_SIZE];
863ecfc7
OZ
173 if (!tm_format_real_time(tbuf, sizeof(tbuf), config->tf_log.fmt1, current_real_time()))
174 strcpy(tbuf, "<error>");
6712e772
OZ
175
176 if (l->limit)
177 {
178 off_t msg_len = strlen(tbuf) + strlen(class_names[class]) +
179 (buf->pos - buf->start) + 5;
180
181 if (l->pos < 0)
182 l->pos = log_size(l);
183
184 if (l->pos + msg_len > l->limit)
185 if (log_rotate(l) < 0)
186 continue;
187
188 l->pos += msg_len;
189 }
190
c37e7851 191 fprintf(l->fh, "%s <%s> ", tbuf, class_names[class]);
a0c37b45 192 }
0e175f9f 193 fputs(buf->start, l->fh);
a0c37b45
MM
194 fputc('\n', l->fh);
195 fflush(l->fh);
196 }
5d6dc930 197#ifdef HAVE_SYSLOG_H
a0c37b45 198 else
0e175f9f 199 syslog(syslog_priorities[class], "%s", buf->start);
6032aa6a 200#endif
6032aa6a 201 }
0e175f9f 202 log_unlock();
0d1b3c4c 203
4e398e34
OZ
204 /* cli_echo is not thread-safe, so call it just from the main thread */
205 if (main_thread_self())
206 cli_echo(class, buf->start);
56027b5c
OZ
207
208 buf->pos = buf->start;
0d1b3c4c
OZ
209}
210
0e175f9f 211int buffer_vprint(buffer *buf, const char *fmt, va_list args);
0d1b3c4c
OZ
212
213static void
214vlog(int class, const char *msg, va_list args)
215{
0e175f9f
OZ
216 buffer buf;
217 LOG_BUFFER_INIT(buf);
218 buffer_vprint(&buf, msg, args);
219 log_commit(class, &buf);
0d1b3c4c
OZ
220}
221
222
73275d85
MM
223/**
224 * log - log a message
225 * @msg: printf-like formatting string with message class information
226 * prepended (%L_DEBUG to %L_BUG, see |lib/birdlib.h|)
227 *
228 * This function formats a message according to the format string @msg
2e9b2421 229 * and writes it to the corresponding log file (as specified in the
73275d85
MM
230 * configuration). Please note that the message is automatically
231 * formatted as a full line, no need to include |\n| inside.
0d1b3c4c 232 * It is essentially a sequence of log_reset(), logn() and log_commit().
73275d85 233 */
6032aa6a 234void
e598853e 235log_msg(const char *msg, ...)
6032aa6a
MM
236{
237 int class = 1;
238 va_list args;
239
240 va_start(args, msg);
98e87c86 241 if (*msg >= 1 && *msg <= 8)
6032aa6a
MM
242 class = *msg++;
243 vlog(class, msg, args);
244 va_end(args);
245}
246
cb530392 247void
e598853e 248log_rl(struct tbf *f, const char *msg, ...)
cb530392
OZ
249{
250 int class = 1;
251 va_list args;
252
1123e707 253 /* Rate limiting is a bit tricky here as it also logs '...' during the first hit */
574b2324 254 if (tbf_limit(f) && (f->drop > 1))
cb530392
OZ
255 return;
256
cb530392
OZ
257 if (*msg >= 1 && *msg <= 8)
258 class = *msg++;
1123e707
OZ
259
260 va_start(args, msg);
574b2324 261 vlog(class, (f->drop ? "..." : msg), args);
cb530392
OZ
262 va_end(args);
263}
264
73275d85
MM
265/**
266 * bug - report an internal error
267 * @msg: a printf-like error message
268 *
269 * This function logs an internal error and aborts execution
270 * of the program.
271 */
98e87c86 272void
e598853e 273bug(const char *msg, ...)
98e87c86
MM
274{
275 va_list args;
276
277 va_start(args, msg);
278 vlog(L_BUG[0], msg, args);
8f01879c 279 va_end(args);
818ff1e2 280 abort();
98e87c86
MM
281}
282
73275d85
MM
283/**
284 * bug - report a fatal error
285 * @msg: a printf-like error message
286 *
287 * This function logs a fatal error and aborts execution
288 * of the program.
289 */
6032aa6a 290void
e598853e 291die(const char *msg, ...)
6032aa6a
MM
292{
293 va_list args;
294
295 va_start(args, msg);
98e87c86 296 vlog(L_FATAL[0], msg, args);
8f01879c 297 va_end(args);
6032aa6a
MM
298 exit(1);
299}
300
73275d85
MM
301/**
302 * debug - write to debug output
303 * @msg: a printf-like message
304 *
305 * This function formats the message @msg and prints it out
306 * to the debugging output. No newline character is appended.
307 */
6032aa6a 308void
e598853e 309debug(const char *msg, ...)
6032aa6a
MM
310{
311 va_list args;
34350a52 312 char buf[1024];
6032aa6a
MM
313
314 va_start(args, msg);
315 if (dbgf)
a0c37b45
MM
316 {
317 if (bvsnprintf(buf, sizeof(buf), msg, args) < 0)
318 bsprintf(buf + sizeof(buf) - 100, " ... <too long>\n");
319 fputs(buf, dbgf);
320 }
6032aa6a
MM
321 va_end(args);
322}
323
44d4ab7a
OZ
324static list *
325default_log_list(int debug, int init, char **syslog_name)
6032aa6a 326{
44d4ab7a 327 static list init_log_list;
a0c37b45 328 init_list(&init_log_list);
44d4ab7a 329 *syslog_name = NULL;
6032aa6a 330
5d6dc930 331#ifdef HAVE_SYSLOG_H
a0c37b45 332 if (!debug)
6032aa6a 333 {
4a591d4b 334 static struct log_config lc_syslog = { .mask = ~0 };
44d4ab7a
OZ
335 add_tail(&init_log_list, &lc_syslog.n);
336 *syslog_name = bird_name;
5ddf4a58 337 if (!init)
44d4ab7a 338 return &init_log_list;
6032aa6a 339 }
a0c37b45
MM
340#endif
341
4a591d4b 342 static struct log_config lc_stderr = { .mask = ~0, .terminal_flag = 1 };
a0c37b45 343 lc_stderr.fh = stderr;
44d4ab7a
OZ
344 add_tail(&init_log_list, &lc_stderr.n);
345 return &init_log_list;
a0c37b45
MM
346}
347
348void
6712e772 349log_switch(int debug, list *logs, char *new_syslog_name)
a0c37b45 350{
6712e772
OZ
351 struct log_config *l;
352
353 if (!logs || EMPTY_LIST(*logs))
354 logs = default_log_list(debug, !logs, &new_syslog_name);
355
356 /* Close the logs to avoid pinning them on disk when deleted */
357 if (current_log_list)
358 WALK_LIST(l, *current_log_list)
359 if (l->rf)
360 log_close(l);
361
362 /* Reopen the logs, needed for 'configure undo' */
363 if (logs)
364 WALK_LIST(l, *logs)
365 if (l->filename && !l->rf)
366 log_open(l);
44d4ab7a 367
6712e772 368 current_log_list = logs;
44d4ab7a 369
5d6dc930 370#ifdef HAVE_SYSLOG_H
17fe57d8
OZ
371 if (current_syslog_name && new_syslog_name &&
372 !strcmp(current_syslog_name, new_syslog_name))
44d4ab7a
OZ
373 return;
374
17fe57d8
OZ
375 if (current_syslog_name)
376 {
44d4ab7a 377 closelog();
17fe57d8
OZ
378 xfree(current_syslog_name);
379 current_syslog_name = NULL;
380 }
44d4ab7a
OZ
381
382 if (new_syslog_name)
17fe57d8
OZ
383 {
384 current_syslog_name = xstrdup(new_syslog_name);
385 openlog(current_syslog_name, LOG_CONS | LOG_NDELAY, LOG_DAEMON);
386 }
44d4ab7a 387#endif
6032aa6a
MM
388}
389
390void
391log_init_debug(char *f)
392{
393 if (dbgf && dbgf != stderr)
394 fclose(dbgf);
395 if (!f)
6032aa6a 396 dbgf = NULL;
a0c37b45
MM
397 else if (!*f)
398 dbgf = stderr;
6032aa6a 399 else if (!(dbgf = fopen(f, "a")))
f0b822a8
OZ
400 {
401 /* Cannot use die() nor log() here, logging is not yet initialized */
402 fprintf(stderr, "bird: Unable to open debug file %s: %s\n", f, strerror(errno));
403 exit(1);
404 }
f098e072
MM
405 if (dbgf)
406 setvbuf(dbgf, NULL, _IONBF, 0);
6032aa6a 407}