Thou shalt not overflow even stupidly small buffers
[tor/rransom.git] / src / common / log.c
blob4b21fd9166d8b985a13aa25c2a590277622367f8
1 /* Copyright (c) 2001, Matej Pfajfar.
2 * Copyright (c) 2001-2004, Roger Dingledine.
3 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
4 * Copyright (c) 2007-2011, The Tor Project, Inc. */
5 /* See LICENSE for licensing information */
7 /**
8 * \file log.c
9 * \brief Functions to send messages to log files or the console.
10 **/
12 #include "orconfig.h"
13 #include <stdarg.h>
14 #include <assert.h>
15 // #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #ifdef HAVE_SYS_TIME_H
19 #include <sys/time.h>
20 #endif
21 #ifdef HAVE_TIME_H
22 #include <time.h>
23 #endif
24 #ifdef HAVE_UNISTD_H
25 #include <unistd.h>
26 #endif
27 #ifdef HAVE_SYS_TYPES_H
28 #include <sys/types.h>
29 #endif
30 #ifdef HAVE_FCNTL_H
31 #include <fcntl.h>
32 #endif
33 #include "compat.h"
34 #include "util.h"
35 #define LOG_PRIVATE
36 #include "torlog.h"
37 #include "container.h"
39 #define TRUNCATED_STR "[...truncated]"
40 #define TRUNCATED_STR_LEN 14
42 /** Information for a single logfile; only used in log.c */
43 typedef struct logfile_t {
44 struct logfile_t *next; /**< Next logfile_t in the linked list. */
45 char *filename; /**< Filename to open. */
46 int fd; /**< fd to receive log messages, or -1 for none. */
47 int seems_dead; /**< Boolean: true if the stream seems to be kaput. */
48 int needs_close; /**< Boolean: true if the stream gets closed on shutdown. */
49 int is_temporary; /**< Boolean: close after initializing logging subsystem.*/
50 int is_syslog; /**< Boolean: send messages to syslog. */
51 log_callback callback; /**< If not NULL, send messages to this function. */
52 log_severity_list_t *severities; /**< Which severity of messages should we
53 * log for each log domain? */
54 } logfile_t;
56 static void log_free(logfile_t *victim);
58 /** Helper: map a log severity to descriptive string. */
59 static INLINE const char *
60 sev_to_string(int severity)
62 switch (severity) {
63 case LOG_DEBUG: return "debug";
64 case LOG_INFO: return "info";
65 case LOG_NOTICE: return "notice";
66 case LOG_WARN: return "warn";
67 case LOG_ERR: return "err";
68 default: /* Call assert, not tor_assert, since tor_assert
69 * calls log on failure. */
70 assert(0); return "UNKNOWN";
74 /** Helper: decide whether to include the function name in the log message. */
75 static INLINE int
76 should_log_function_name(log_domain_mask_t domain, int severity)
78 switch (severity) {
79 case LOG_DEBUG:
80 case LOG_INFO:
81 /* All debugging messages occur in interesting places. */
82 return 1;
83 case LOG_NOTICE:
84 case LOG_WARN:
85 case LOG_ERR:
86 /* We care about places where bugs occur. */
87 return (domain == LD_BUG);
88 default:
89 /* Call assert, not tor_assert, since tor_assert calls log on failure. */
90 assert(0); return 0;
94 /** A mutex to guard changes to logfiles and logging. */
95 static tor_mutex_t log_mutex;
96 static int log_mutex_initialized = 0;
98 /** Linked list of logfile_t. */
99 static logfile_t *logfiles = NULL;
100 /** Boolean: do we report logging domains? */
101 static int log_domains_are_logged = 0;
103 #ifdef HAVE_SYSLOG_H
104 /** The number of open syslog log handlers that we have. When this reaches 0,
105 * we can close our connection to the syslog facility. */
106 static int syslog_count = 0;
107 #endif
109 /** Represents a log message that we are going to send to callback-driven
110 * loggers once we can do so in a non-reentrant way. */
111 typedef struct pending_cb_message_t {
112 int severity;
113 log_domain_mask_t domain;
114 char *msg;
115 } pending_cb_message_t;
117 /** Log messages waiting to be replayed onto callback-based logs */
118 static smartlist_t *pending_cb_messages = NULL;
120 #define LOCK_LOGS() STMT_BEGIN \
121 tor_mutex_acquire(&log_mutex); \
122 STMT_END
123 #define UNLOCK_LOGS() STMT_BEGIN tor_mutex_release(&log_mutex); STMT_END
125 /** What's the lowest log level anybody cares about? Checking this lets us
126 * bail out early from log_debug if we aren't debugging. */
127 int _log_global_min_severity = LOG_NOTICE;
129 static void delete_log(logfile_t *victim);
130 static void close_log(logfile_t *victim);
132 static char *domain_to_string(log_domain_mask_t domain,
133 char *buf, size_t buflen);
135 /** Name of the application: used to generate the message we write at the
136 * start of each new log. */
137 static char *appname = NULL;
139 /** Set the "application name" for the logs to <b>name</b>: we'll use this
140 * name in the message we write when starting up, and at the start of each new
141 * log.
143 * Tor uses this string to write the version number to the log file. */
144 void
145 log_set_application_name(const char *name)
147 tor_free(appname);
148 appname = name ? tor_strdup(name) : NULL;
151 /** Helper: Write the standard prefix for log lines to a
152 * <b>buf_len</b> character buffer in <b>buf</b>.
154 static INLINE size_t
155 _log_prefix(char *buf, size_t buf_len, int severity)
157 time_t t;
158 struct timeval now;
159 struct tm tm;
160 size_t n;
161 int r;
163 tor_gettimeofday(&now);
164 t = (time_t)now.tv_sec;
166 n = strftime(buf, buf_len, "%b %d %H:%M:%S", tor_localtime_r(&t, &tm));
167 r = tor_snprintf(buf+n, buf_len-n, ".%.3i [%s] ",
168 (int)now.tv_usec / 1000, sev_to_string(severity));
169 if (r<0)
170 return buf_len-1;
171 else
172 return n+r;
175 /** If lf refers to an actual file that we have just opened, and the file
176 * contains no data, log an "opening new logfile" message at the top.
178 * Return -1 if the log is broken and needs to be deleted, else return 0.
180 static int
181 log_tor_version(logfile_t *lf, int reset)
183 char buf[256];
184 size_t n;
185 int is_new;
187 if (!lf->needs_close)
188 /* If it doesn't get closed, it isn't really a file. */
189 return 0;
190 if (lf->is_temporary)
191 /* If it's temporary, it isn't really a file. */
192 return 0;
194 is_new = lf->fd >= 0 && tor_fd_getpos(lf->fd) == 0;
196 if (reset && !is_new)
197 /* We are resetting, but we aren't at the start of the file; no
198 * need to log again. */
199 return 0;
200 n = _log_prefix(buf, sizeof(buf), LOG_NOTICE);
201 if (appname) {
202 tor_snprintf(buf+n, sizeof(buf)-n,
203 "%s opening %slog file.\n", appname, is_new?"new ":"");
204 } else {
205 tor_snprintf(buf+n, sizeof(buf)-n,
206 "Tor %s opening %slog file.\n", VERSION, is_new?"new ":"");
208 if (write_all(lf->fd, buf, strlen(buf), 0) < 0) /* error */
209 return -1; /* failed */
210 return 0;
213 /** Helper: Format a log message into a fixed-sized buffer. (This is
214 * factored out of <b>logv</b> so that we never format a message more
215 * than once.) Return a pointer to the first character of the message
216 * portion of the formatted string.
218 static INLINE char *
219 format_msg(char *buf, size_t buf_len,
220 log_domain_mask_t domain, int severity, const char *funcname,
221 const char *format, va_list ap, size_t *msg_len_out)
223 size_t n;
224 int r;
225 char *end_of_prefix;
226 char *buf_end;
228 assert(buf_len >= 16); /* prevent integer underflow and general stupidity */
229 buf_len -= 2; /* subtract 2 characters so we have room for \n\0 */
230 buf_end = buf+buf_len; /* point *after* the last char we can write to */
232 n = _log_prefix(buf, buf_len, severity);
233 end_of_prefix = buf+n;
235 if (log_domains_are_logged) {
236 char *cp = buf+n;
237 if (cp == buf_end) goto format_msg_no_room_for_domains;
238 *cp++ = '{';
239 if (cp == buf_end) goto format_msg_no_room_for_domains;
240 cp = domain_to_string(domain, cp, (buf+buf_len-cp));
241 if (cp == buf_end) goto format_msg_no_room_for_domains;
242 *cp++ = '}';
243 if (cp == buf_end) goto format_msg_no_room_for_domains;
244 *cp++ = ' ';
245 if (cp == buf_end) goto format_msg_no_room_for_domains;
246 end_of_prefix = cp;
247 n = cp-buf;
248 format_msg_no_room_for_domains:
249 /* This will leave end_of_prefix and n unchanged, and thus cause
250 * whatever log domain string we had written to be clobbered. */
253 if (funcname && should_log_function_name(domain, severity)) {
254 r = tor_snprintf(buf+n, buf_len-n, "%s(): ", funcname);
255 if (r<0)
256 n = strlen(buf);
257 else
258 n += r;
261 if (domain == LD_BUG && buf_len-n > 6) {
262 memcpy(buf+n, "Bug: ", 6);
263 n += 5;
266 r = tor_vsnprintf(buf+n,buf_len-n,format,ap);
267 if (r < 0) {
268 /* The message was too long; overwrite the end of the buffer with
269 * "[...truncated]" */
270 if (buf_len >= TRUNCATED_STR_LEN) {
271 size_t offset = buf_len-TRUNCATED_STR_LEN;
272 /* We have an extra 2 characters after buf_len to hold the \n\0,
273 * so it's safe to add 1 to the size here. */
274 strlcpy(buf+offset, TRUNCATED_STR, buf_len-offset+1);
276 /* Set 'n' to the end of the buffer, where we'll be writing \n\0.
277 * Since we already subtracted 2 from buf_len, this is safe.*/
278 n = buf_len;
279 } else {
280 n += r;
282 buf[n]='\n';
283 buf[n+1]='\0';
284 *msg_len_out = n+1;
285 return end_of_prefix;
288 /** Helper: sends a message to the appropriate logfiles, at loglevel
289 * <b>severity</b>. If provided, <b>funcname</b> is prepended to the
290 * message. The actual message is derived as from tor_snprintf(format,ap).
292 static void
293 logv(int severity, log_domain_mask_t domain, const char *funcname,
294 const char *format, va_list ap)
296 char buf[10024];
297 size_t msg_len = 0;
298 int formatted = 0;
299 logfile_t *lf;
300 char *end_of_prefix=NULL;
301 int callbacks_deferred = 0;
303 /* Call assert, not tor_assert, since tor_assert calls log on failure. */
304 assert(format);
305 /* check that severity is sane. Overrunning the masks array leads to
306 * interesting and hard to diagnose effects */
307 assert(severity >= LOG_ERR && severity <= LOG_DEBUG);
308 LOCK_LOGS();
310 if ((! (domain & LD_NOCB)) && smartlist_len(pending_cb_messages))
311 flush_pending_log_callbacks();
313 lf = logfiles;
314 while (lf) {
315 if (! (lf->severities->masks[SEVERITY_MASK_IDX(severity)] & domain)) {
316 lf = lf->next;
317 continue;
319 if (! (lf->fd >= 0 || lf->is_syslog || lf->callback)) {
320 lf = lf->next;
321 continue;
323 if (lf->seems_dead) {
324 lf = lf->next;
325 continue;
328 if (!formatted) {
329 end_of_prefix =
330 format_msg(buf, sizeof(buf), domain, severity, funcname, format, ap,
331 &msg_len);
332 formatted = 1;
335 if (lf->is_syslog) {
336 #ifdef HAVE_SYSLOG_H
337 char *m = end_of_prefix;
338 #ifdef MAXLINE
339 /* Some syslog implementations have limits on the length of what you can
340 * pass them, and some very old ones do not detect overflow so well.
341 * Regrettably, they call their maximum line length MAXLINE. */
342 #if MAXLINE < 64
343 #warn "MAXLINE is a very low number; it might not be from syslog.h after all"
344 #endif
345 if (msg_len >= MAXLINE)
346 m = tor_strndup(end_of_prefix, MAXLINE-1);
347 #endif
348 syslog(severity, "%s", m);
349 #ifdef MAXLINE
350 if (m != end_of_prefix) {
351 tor_free(m);
353 #endif
354 #endif
355 lf = lf->next;
356 continue;
357 } else if (lf->callback) {
358 if (domain & LD_NOCB) {
359 if (!callbacks_deferred) {
360 pending_cb_message_t *msg = tor_malloc(sizeof(pending_cb_message_t));
361 msg->severity = severity;
362 msg->domain = domain;
363 msg->msg = tor_strdup(end_of_prefix);
364 smartlist_add(pending_cb_messages, msg);
366 callbacks_deferred = 1;
368 } else {
369 lf->callback(severity, domain, end_of_prefix);
371 lf = lf->next;
372 continue;
374 if (write_all(lf->fd, buf, msg_len, 0) < 0) { /* error */
375 /* don't log the error! mark this log entry to be blown away, and
376 * continue. */
377 lf->seems_dead = 1;
379 lf = lf->next;
381 UNLOCK_LOGS();
384 /** Output a message to the log. */
385 void
386 tor_log(int severity, log_domain_mask_t domain, const char *format, ...)
388 va_list ap;
389 if (severity > _log_global_min_severity)
390 return;
391 va_start(ap,format);
392 logv(severity, domain, NULL, format, ap);
393 va_end(ap);
396 /** Output a message to the log, prefixed with a function name <b>fn</b>. */
397 #ifdef __GNUC__
398 void
399 _log_fn(int severity, log_domain_mask_t domain, const char *fn,
400 const char *format, ...)
402 va_list ap;
403 if (severity > _log_global_min_severity)
404 return;
405 va_start(ap,format);
406 logv(severity, domain, fn, format, ap);
407 va_end(ap);
409 #else
410 const char *_log_fn_function_name=NULL;
411 void
412 _log_fn(int severity, log_domain_mask_t domain, const char *format, ...)
414 va_list ap;
415 if (severity > _log_global_min_severity)
416 return;
417 va_start(ap,format);
418 logv(severity, domain, _log_fn_function_name, format, ap);
419 va_end(ap);
420 _log_fn_function_name = NULL;
422 void
423 _log_debug(log_domain_mask_t domain, const char *format, ...)
425 va_list ap;
426 /* For GCC we do this check in the macro. */
427 if (PREDICT_LIKELY(LOG_DEBUG > _log_global_min_severity))
428 return;
429 va_start(ap,format);
430 logv(LOG_DEBUG, domain, _log_fn_function_name, format, ap);
431 va_end(ap);
432 _log_fn_function_name = NULL;
434 void
435 _log_info(log_domain_mask_t domain, const char *format, ...)
437 va_list ap;
438 if (LOG_INFO > _log_global_min_severity)
439 return;
440 va_start(ap,format);
441 logv(LOG_INFO, domain, _log_fn_function_name, format, ap);
442 va_end(ap);
443 _log_fn_function_name = NULL;
445 void
446 _log_notice(log_domain_mask_t domain, const char *format, ...)
448 va_list ap;
449 if (LOG_NOTICE > _log_global_min_severity)
450 return;
451 va_start(ap,format);
452 logv(LOG_NOTICE, domain, _log_fn_function_name, format, ap);
453 va_end(ap);
454 _log_fn_function_name = NULL;
456 void
457 _log_warn(log_domain_mask_t domain, const char *format, ...)
459 va_list ap;
460 if (LOG_WARN > _log_global_min_severity)
461 return;
462 va_start(ap,format);
463 logv(LOG_WARN, domain, _log_fn_function_name, format, ap);
464 va_end(ap);
465 _log_fn_function_name = NULL;
467 void
468 _log_err(log_domain_mask_t domain, const char *format, ...)
470 va_list ap;
471 if (LOG_ERR > _log_global_min_severity)
472 return;
473 va_start(ap,format);
474 logv(LOG_ERR, domain, _log_fn_function_name, format, ap);
475 va_end(ap);
476 _log_fn_function_name = NULL;
478 #endif
480 /** Free all storage held by <b>victim</b>. */
481 static void
482 log_free(logfile_t *victim)
484 if (!victim)
485 return;
486 tor_free(victim->severities);
487 tor_free(victim->filename);
488 tor_free(victim);
491 /** Close all open log files, and free other static memory. */
492 void
493 logs_free_all(void)
495 logfile_t *victim, *next;
496 LOCK_LOGS();
497 next = logfiles;
498 logfiles = NULL;
499 UNLOCK_LOGS();
500 while (next) {
501 victim = next;
502 next = next->next;
503 close_log(victim);
504 log_free(victim);
506 tor_free(appname);
508 /* We _could_ destroy the log mutex here, but that would screw up any logs
509 * that happened between here and the end of execution. */
512 /** Remove and free the log entry <b>victim</b> from the linked-list
513 * logfiles (it is probably present, but it might not be due to thread
514 * racing issues). After this function is called, the caller shouldn't
515 * refer to <b>victim</b> anymore.
517 * Long-term, we need to do something about races in the log subsystem
518 * in general. See bug 222 for more details.
520 static void
521 delete_log(logfile_t *victim)
523 logfile_t *tmpl;
524 if (victim == logfiles)
525 logfiles = victim->next;
526 else {
527 for (tmpl = logfiles; tmpl && tmpl->next != victim; tmpl=tmpl->next) ;
528 // tor_assert(tmpl);
529 // tor_assert(tmpl->next == victim);
530 if (!tmpl)
531 return;
532 tmpl->next = victim->next;
534 log_free(victim);
537 /** Helper: release system resources (but not memory) held by a single
538 * logfile_t. */
539 static void
540 close_log(logfile_t *victim)
542 if (victim->needs_close && victim->fd >= 0) {
543 close(victim->fd);
544 victim->fd = -1;
545 } else if (victim->is_syslog) {
546 #ifdef HAVE_SYSLOG_H
547 if (--syslog_count == 0) {
548 /* There are no other syslogs; close the logging facility. */
549 closelog();
551 #endif
555 /** Adjust a log severity configuration in <b>severity_out</b> to contain
556 * every domain between <b>loglevelMin</b> and <b>loglevelMax</b>, inclusive.
558 void
559 set_log_severity_config(int loglevelMin, int loglevelMax,
560 log_severity_list_t *severity_out)
562 int i;
563 tor_assert(loglevelMin >= loglevelMax);
564 tor_assert(loglevelMin >= LOG_ERR && loglevelMin <= LOG_DEBUG);
565 tor_assert(loglevelMax >= LOG_ERR && loglevelMax <= LOG_DEBUG);
566 memset(severity_out, 0, sizeof(log_severity_list_t));
567 for (i = loglevelMin; i >= loglevelMax; --i) {
568 severity_out->masks[SEVERITY_MASK_IDX(i)] = ~0u;
572 /** Add a log handler named <b>name</b> to send all messages in <b>severity</b>
573 * to <b>fd</b>. Copies <b>severity</b>. Helper: does no locking. */
574 static void
575 add_stream_log_impl(const log_severity_list_t *severity,
576 const char *name, int fd)
578 logfile_t *lf;
579 lf = tor_malloc_zero(sizeof(logfile_t));
580 lf->fd = fd;
581 lf->filename = tor_strdup(name);
582 lf->severities = tor_memdup(severity, sizeof(log_severity_list_t));
583 lf->next = logfiles;
585 logfiles = lf;
586 _log_global_min_severity = get_min_log_level();
589 /** Add a log handler named <b>name</b> to send all messages in <b>severity</b>
590 * to <b>fd</b>. Steals a reference to <b>severity</b>; the caller must
591 * not use it after calling this function. */
592 void
593 add_stream_log(const log_severity_list_t *severity, const char *name, int fd)
595 LOCK_LOGS();
596 add_stream_log_impl(severity, name, fd);
597 UNLOCK_LOGS();
600 /** Initialize the global logging facility */
601 void
602 init_logging(void)
604 if (!log_mutex_initialized) {
605 tor_mutex_init(&log_mutex);
606 log_mutex_initialized = 1;
608 if (pending_cb_messages == NULL)
609 pending_cb_messages = smartlist_create();
612 /** Set whether we report logging domains as a part of our log messages.
614 void
615 logs_set_domain_logging(int enabled)
617 LOCK_LOGS();
618 log_domains_are_logged = enabled;
619 UNLOCK_LOGS();
622 /** Add a log handler to receive messages during startup (before the real
623 * logs are initialized).
625 void
626 add_temp_log(int min_severity)
628 log_severity_list_t *s = tor_malloc_zero(sizeof(log_severity_list_t));
629 set_log_severity_config(min_severity, LOG_ERR, s);
630 LOCK_LOGS();
631 add_stream_log_impl(s, "<temp>", fileno(stdout));
632 tor_free(s);
633 logfiles->is_temporary = 1;
634 UNLOCK_LOGS();
638 * Add a log handler to send messages in <b>severity</b>
639 * to the function <b>cb</b>.
642 add_callback_log(const log_severity_list_t *severity, log_callback cb)
644 logfile_t *lf;
645 lf = tor_malloc_zero(sizeof(logfile_t));
646 lf->fd = -1;
647 lf->severities = tor_memdup(severity, sizeof(log_severity_list_t));
648 lf->filename = tor_strdup("<callback>");
649 lf->callback = cb;
650 lf->next = logfiles;
652 LOCK_LOGS();
653 logfiles = lf;
654 _log_global_min_severity = get_min_log_level();
655 UNLOCK_LOGS();
656 return 0;
659 /** Adjust the configured severity of any logs whose callback function is
660 * <b>cb</b>. */
661 void
662 change_callback_log_severity(int loglevelMin, int loglevelMax,
663 log_callback cb)
665 logfile_t *lf;
666 log_severity_list_t severities;
667 set_log_severity_config(loglevelMin, loglevelMax, &severities);
668 LOCK_LOGS();
669 for (lf = logfiles; lf; lf = lf->next) {
670 if (lf->callback == cb) {
671 memcpy(lf->severities, &severities, sizeof(severities));
674 _log_global_min_severity = get_min_log_level();
675 UNLOCK_LOGS();
678 /** If there are any log messages that were genered with LD_NOCB waiting to
679 * be sent to callback-based loggers, send them now. */
680 void
681 flush_pending_log_callbacks(void)
683 logfile_t *lf;
684 smartlist_t *messages, *messages_tmp;
686 LOCK_LOGS();
687 if (0 == smartlist_len(pending_cb_messages)) {
688 UNLOCK_LOGS();
689 return;
692 messages = pending_cb_messages;
693 pending_cb_messages = smartlist_create();
694 do {
695 SMARTLIST_FOREACH_BEGIN(messages, pending_cb_message_t *, msg) {
696 const int severity = msg->severity;
697 const int domain = msg->domain;
698 for (lf = logfiles; lf; lf = lf->next) {
699 if (! lf->callback || lf->seems_dead ||
700 ! (lf->severities->masks[SEVERITY_MASK_IDX(severity)] & domain)) {
701 continue;
703 lf->callback(severity, domain, msg->msg);
705 tor_free(msg->msg);
706 tor_free(msg);
707 } SMARTLIST_FOREACH_END(msg);
708 smartlist_clear(messages);
710 messages_tmp = pending_cb_messages;
711 pending_cb_messages = messages;
712 messages = messages_tmp;
713 } while (smartlist_len(messages));
715 smartlist_free(messages);
717 UNLOCK_LOGS();
720 /** Close any log handlers added by add_temp_log() or marked by
721 * mark_logs_temp(). */
722 void
723 close_temp_logs(void)
725 logfile_t *lf, **p;
727 LOCK_LOGS();
728 for (p = &logfiles; *p; ) {
729 if ((*p)->is_temporary) {
730 lf = *p;
731 /* we use *p here to handle the edge case of the head of the list */
732 *p = (*p)->next;
733 close_log(lf);
734 log_free(lf);
735 } else {
736 p = &((*p)->next);
740 _log_global_min_severity = get_min_log_level();
741 UNLOCK_LOGS();
744 /** Make all currently temporary logs (set to be closed by close_temp_logs)
745 * live again, and close all non-temporary logs. */
746 void
747 rollback_log_changes(void)
749 logfile_t *lf;
750 LOCK_LOGS();
751 for (lf = logfiles; lf; lf = lf->next)
752 lf->is_temporary = ! lf->is_temporary;
753 UNLOCK_LOGS();
754 close_temp_logs();
757 /** Configure all log handles to be closed by close_temp_logs(). */
758 void
759 mark_logs_temp(void)
761 logfile_t *lf;
762 LOCK_LOGS();
763 for (lf = logfiles; lf; lf = lf->next)
764 lf->is_temporary = 1;
765 UNLOCK_LOGS();
769 * Add a log handler to send messages to <b>filename</b>. If opening the
770 * logfile fails, -1 is returned and errno is set appropriately (by open(2)).
773 add_file_log(const log_severity_list_t *severity, const char *filename)
775 int fd;
776 logfile_t *lf;
778 fd = open(filename, O_WRONLY|O_CREAT|O_APPEND, 0644);
779 if (fd<0)
780 return -1;
781 if (tor_fd_seekend(fd)<0)
782 return -1;
784 LOCK_LOGS();
785 add_stream_log_impl(severity, filename, fd);
786 logfiles->needs_close = 1;
787 lf = logfiles;
788 _log_global_min_severity = get_min_log_level();
790 if (log_tor_version(lf, 0) < 0) {
791 delete_log(lf);
793 UNLOCK_LOGS();
795 return 0;
798 #ifdef HAVE_SYSLOG_H
800 * Add a log handler to send messages to they system log facility.
803 add_syslog_log(const log_severity_list_t *severity)
805 logfile_t *lf;
806 if (syslog_count++ == 0)
807 /* This is the first syslog. */
808 openlog("Tor", LOG_PID | LOG_NDELAY, LOGFACILITY);
810 lf = tor_malloc_zero(sizeof(logfile_t));
811 lf->fd = -1;
812 lf->severities = tor_memdup(severity, sizeof(log_severity_list_t));
813 lf->filename = tor_strdup("<syslog>");
814 lf->is_syslog = 1;
816 LOCK_LOGS();
817 lf->next = logfiles;
818 logfiles = lf;
819 _log_global_min_severity = get_min_log_level();
820 UNLOCK_LOGS();
821 return 0;
823 #endif
825 /** If <b>level</b> is a valid log severity, return the corresponding
826 * numeric value. Otherwise, return -1. */
828 parse_log_level(const char *level)
830 if (!strcasecmp(level, "err"))
831 return LOG_ERR;
832 if (!strcasecmp(level, "warn"))
833 return LOG_WARN;
834 if (!strcasecmp(level, "notice"))
835 return LOG_NOTICE;
836 if (!strcasecmp(level, "info"))
837 return LOG_INFO;
838 if (!strcasecmp(level, "debug"))
839 return LOG_DEBUG;
840 return -1;
843 /** Return the string equivalent of a given log level. */
844 const char *
845 log_level_to_string(int level)
847 return sev_to_string(level);
850 /** NULL-terminated array of names for log domains such that domain_list[dom]
851 * is a description of <b>dom</b>. */
852 static const char *domain_list[] = {
853 "GENERAL", "CRYPTO", "NET", "CONFIG", "FS", "PROTOCOL", "MM",
854 "HTTP", "APP", "CONTROL", "CIRC", "REND", "BUG", "DIR", "DIRSERV",
855 "OR", "EDGE", "ACCT", "HIST", "HANDSHAKE", NULL
858 /** Return a bitmask for the log domain for which <b>domain</b> is the name,
859 * or 0 if there is no such name. */
860 static log_domain_mask_t
861 parse_log_domain(const char *domain)
863 int i;
864 for (i=0; domain_list[i]; ++i) {
865 if (!strcasecmp(domain, domain_list[i]))
866 return (1u<<i);
868 return 0;
871 /** Translate a bitmask of log domains to a string. */
872 static char *
873 domain_to_string(log_domain_mask_t domain, char *buf, size_t buflen)
875 char *cp = buf;
876 char *eos = buf+buflen;
878 buf[0] = '\0';
879 if (! domain)
880 return buf;
881 while (1) {
882 const char *d;
883 int bit = tor_log2(domain);
884 size_t n;
885 if (bit >= N_LOGGING_DOMAINS) {
886 tor_snprintf(buf, buflen, "<BUG:Unknown domain %lx>", (long)domain);
887 return buf+strlen(buf);
889 d = domain_list[bit];
890 n = strlcpy(cp, d, eos-cp);
891 if (n >= buflen) {
892 tor_snprintf(buf, buflen, "<BUG:Truncating domain %lx>", (long)domain);
893 return buf+strlen(buf);
895 cp += n;
896 domain &= ~(1<<bit);
898 if (domain == 0 || (eos-cp) < 2)
899 return cp;
901 memcpy(cp, ",", 2); /*Nul-terminated ,"*/
902 cp++;
906 /** Parse a log severity pattern in *<b>cfg_ptr</b>. Advance cfg_ptr after
907 * the end of the severityPattern. Set the value of <b>severity_out</b> to
908 * the parsed pattern. Return 0 on success, -1 on failure.
910 * The syntax for a SeverityPattern is:
911 * <pre>
912 * SeverityPattern = *(DomainSeverity SP)* DomainSeverity
913 * DomainSeverity = (DomainList SP)? SeverityRange
914 * SeverityRange = MinSeverity ("-" MaxSeverity )?
915 * DomainList = "[" (SP? DomainSpec SP? ",") SP? DomainSpec "]"
916 * DomainSpec = "*" | Domain | "~" Domain
917 * </pre>
918 * A missing MaxSeverity defaults to ERR. Severities and domains are
919 * case-insensitive. "~" indicates negation for a domain; negation happens
920 * last inside a DomainList. Only one SeverityRange without a DomainList is
921 * allowed per line.
924 parse_log_severity_config(const char **cfg_ptr,
925 log_severity_list_t *severity_out)
927 const char *cfg = *cfg_ptr;
928 int got_anything = 0;
929 int got_an_unqualified_range = 0;
930 memset(severity_out, 0, sizeof(*severity_out));
932 cfg = eat_whitespace(cfg);
933 while (*cfg) {
934 const char *dash, *space;
935 char *sev_lo, *sev_hi;
936 int low, high, i;
937 log_domain_mask_t domains = ~0u;
939 if (*cfg == '[') {
940 int err = 0;
941 char *domains_str;
942 smartlist_t *domains_list;
943 log_domain_mask_t neg_domains = 0;
944 const char *closebracket = strchr(cfg, ']');
945 if (!closebracket)
946 return -1;
947 domains = 0;
948 domains_str = tor_strndup(cfg+1, closebracket-cfg-1);
949 domains_list = smartlist_create();
950 smartlist_split_string(domains_list, domains_str, ",", SPLIT_SKIP_SPACE,
951 -1);
952 tor_free(domains_str);
953 SMARTLIST_FOREACH(domains_list, const char *, domain,
955 if (!strcmp(domain, "*")) {
956 domains = ~0u;
957 } else {
958 int d;
959 int negate=0;
960 if (*domain == '~') {
961 negate = 1;
962 ++domain;
964 d = parse_log_domain(domain);
965 if (!d) {
966 log_warn(LD_CONFIG, "No such logging domain as %s", domain);
967 err = 1;
968 } else {
969 if (negate)
970 neg_domains |= d;
971 else
972 domains |= d;
976 SMARTLIST_FOREACH(domains_list, char *, d, tor_free(d));
977 smartlist_free(domains_list);
978 if (err)
979 return -1;
980 if (domains == 0 && neg_domains)
981 domains = ~neg_domains;
982 else
983 domains &= ~neg_domains;
984 cfg = eat_whitespace(closebracket+1);
985 } else {
986 ++got_an_unqualified_range;
988 if (!strcasecmpstart(cfg, "file") ||
989 !strcasecmpstart(cfg, "stderr") ||
990 !strcasecmpstart(cfg, "stdout") ||
991 !strcasecmpstart(cfg, "syslog")) {
992 goto done;
994 if (got_an_unqualified_range > 1)
995 return -1;
997 space = strchr(cfg, ' ');
998 dash = strchr(cfg, '-');
999 if (!space)
1000 space = strchr(cfg, '\0');
1001 if (dash && dash < space) {
1002 sev_lo = tor_strndup(cfg, dash-cfg);
1003 sev_hi = tor_strndup(dash+1, space-(dash+1));
1004 } else {
1005 sev_lo = tor_strndup(cfg, space-cfg);
1006 sev_hi = tor_strdup("ERR");
1008 low = parse_log_level(sev_lo);
1009 high = parse_log_level(sev_hi);
1010 tor_free(sev_lo);
1011 tor_free(sev_hi);
1012 if (low == -1)
1013 return -1;
1014 if (high == -1)
1015 return -1;
1017 got_anything = 1;
1018 for (i=low; i >= high; --i)
1019 severity_out->masks[SEVERITY_MASK_IDX(i)] |= domains;
1021 cfg = eat_whitespace(space);
1024 done:
1025 *cfg_ptr = cfg;
1026 return got_anything ? 0 : -1;
1029 /** Return the least severe log level that any current log is interested in. */
1031 get_min_log_level(void)
1033 logfile_t *lf;
1034 int i;
1035 int min = LOG_ERR;
1036 for (lf = logfiles; lf; lf = lf->next) {
1037 for (i = LOG_DEBUG; i > min; --i)
1038 if (lf->severities->masks[SEVERITY_MASK_IDX(i)])
1039 min = i;
1041 return min;
1044 /** Switch all logs to output at most verbose level. */
1045 void
1046 switch_logs_debug(void)
1048 logfile_t *lf;
1049 int i;
1050 LOCK_LOGS();
1051 for (lf = logfiles; lf; lf=lf->next) {
1052 for (i = LOG_DEBUG; i >= LOG_ERR; --i)
1053 lf->severities->masks[SEVERITY_MASK_IDX(i)] = ~0u;
1055 _log_global_min_severity = get_min_log_level();
1056 UNLOCK_LOGS();
1059 #if 0
1060 static void
1061 dump_log_info(logfile_t *lf)
1063 const char *tp;
1065 if (lf->filename) {
1066 printf("=== log into \"%s\" (%s-%s) (%stemporary)\n", lf->filename,
1067 sev_to_string(lf->min_loglevel),
1068 sev_to_string(lf->max_loglevel),
1069 lf->is_temporary?"":"not ");
1070 } else if (lf->is_syslog) {
1071 printf("=== syslog (%s-%s) (%stemporary)\n",
1072 sev_to_string(lf->min_loglevel),
1073 sev_to_string(lf->max_loglevel),
1074 lf->is_temporary?"":"not ");
1075 } else {
1076 printf("=== log (%s-%s) (%stemporary)\n",
1077 sev_to_string(lf->min_loglevel),
1078 sev_to_string(lf->max_loglevel),
1079 lf->is_temporary?"":"not ");
1083 void
1084 describe_logs(void)
1086 logfile_t *lf;
1087 printf("==== BEGIN LOGS ====\n");
1088 for (lf = logfiles; lf; lf = lf->next)
1089 dump_log_info(lf);
1090 printf("==== END LOGS ====\n");
1092 #endif