Line data Source code
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-2021, The Tor Project, Inc. */
5 : /* See LICENSE for licensing information */
6 :
7 : /**
8 : * \file log.c
9 : * \brief Functions to send messages to log files or the console.
10 : **/
11 :
12 : #include "orconfig.h"
13 : #include <stdarg.h>
14 : #include <stdio.h>
15 : #include <stdlib.h>
16 : #include <string.h>
17 : #ifdef HAVE_SYS_TIME_H
18 : #include <sys/time.h>
19 : #endif
20 : #ifdef HAVE_TIME_H
21 : #include <time.h>
22 : #endif
23 : #ifdef HAVE_UNISTD_H
24 : #include <unistd.h>
25 : #endif
26 : #ifdef HAVE_SYS_TYPES_H
27 : #include <sys/types.h>
28 : #endif
29 : #ifdef HAVE_FCNTL_H
30 : #include <fcntl.h>
31 : #endif
32 :
33 : #define LOG_PRIVATE
34 : #include "lib/log/log.h"
35 : #include "lib/log/log_sys.h"
36 : #include "lib/version/git_revision.h"
37 : #include "lib/log/ratelim.h"
38 : #include "lib/lock/compat_mutex.h"
39 : #include "lib/smartlist_core/smartlist_core.h"
40 : #include "lib/smartlist_core/smartlist_foreach.h"
41 : #include "lib/smartlist_core/smartlist_split.h"
42 : #include "lib/err/torerr.h"
43 : #include "lib/intmath/bits.h"
44 : #include "lib/string/compat_string.h"
45 : #include "lib/string/printf.h"
46 : #include "lib/malloc/malloc.h"
47 : #include "lib/string/util_string.h"
48 : #include "lib/wallclock/tor_gettimeofday.h"
49 : #include "lib/wallclock/approx_time.h"
50 : #include "lib/wallclock/time_to_tm.h"
51 : #include "lib/fdio/fdio.h"
52 : #include "lib/cc/ctassert.h"
53 :
54 : /** @{ */
55 : /** The string we stick at the end of a log message when it is too long,
56 : * and its length. */
57 : #define TRUNCATED_STR "[...truncated]"
58 : #define TRUNCATED_STR_LEN 14
59 : /** @} */
60 :
61 : /** Defining compile-time constants for Tor log levels (used by the Rust
62 : * log wrapper at src/rust/tor_log) */
63 : const int LOG_WARN_ = LOG_WARN;
64 : const int LOG_NOTICE_ = LOG_NOTICE;
65 : const log_domain_mask_t LD_GENERAL_ = LD_GENERAL;
66 : const log_domain_mask_t LD_NET_ = LD_NET;
67 :
68 : /** Information for a single logfile; only used in log.c */
69 : typedef struct logfile_t {
70 : struct logfile_t *next; /**< Next logfile_t in the linked list. */
71 : char *filename; /**< Filename to open. */
72 : int fd; /**< fd to receive log messages, or -1 for none. */
73 : int seems_dead; /**< Boolean: true if the stream seems to be kaput. */
74 : int needs_close; /**< Boolean: true if the stream gets closed on shutdown. */
75 : int is_temporary; /**< Boolean: close after initializing logging subsystem.*/
76 : int is_syslog; /**< Boolean: send messages to syslog. */
77 : log_callback callback; /**< If not NULL, send messages to this function. */
78 : log_severity_list_t *severities; /**< Which severity of messages should we
79 : * log for each log domain? */
80 : } logfile_t;
81 :
82 : static void log_free_(logfile_t *victim);
83 : #define log_free(lg) \
84 : FREE_AND_NULL(logfile_t, log_free_, (lg))
85 :
86 : /** Helper: map a log severity to descriptive string. */
87 : static inline const char *
88 9899 : sev_to_string(int severity)
89 : {
90 9899 : switch (severity) {
91 : case LOG_DEBUG: return "debug";
92 0 : case LOG_INFO: return "info";
93 6817 : case LOG_NOTICE: return "notice";
94 3030 : case LOG_WARN: return "warn";
95 52 : case LOG_ERR: return "err";
96 : default: /* Call raw_assert, not tor_assert, since tor_assert
97 : * calls log on failure. */
98 : raw_assert_unreached(); return "UNKNOWN"; // LCOV_EXCL_LINE
99 : }
100 : }
101 :
102 : /** Helper: decide whether to include the function name in the log message. */
103 : static inline int
104 9882 : should_log_function_name(log_domain_mask_t domain, int severity)
105 : {
106 9882 : switch (severity) {
107 0 : case LOG_DEBUG:
108 : case LOG_INFO:
109 : /* All debugging messages occur in interesting places. */
110 0 : return (domain & LD_NOFUNCNAME) == 0;
111 9882 : case LOG_NOTICE:
112 : case LOG_WARN:
113 : case LOG_ERR:
114 : /* We care about places where bugs occur. */
115 9882 : return (domain & (LD_BUG|LD_NOFUNCNAME)) == LD_BUG;
116 : default:
117 : /* Call raw_assert, not tor_assert, since tor_assert calls
118 : * log on failure. */
119 : raw_assert(0); return 0; // LCOV_EXCL_LINE
120 : }
121 : }
122 :
123 : /** A mutex to guard changes to logfiles and logging. */
124 : static tor_mutex_t log_mutex;
125 : /** True iff we have initialized log_mutex */
126 : static int log_mutex_initialized = 0;
127 :
128 : /** Linked list of logfile_t. */
129 : static logfile_t *logfiles = NULL;
130 : /** Boolean: do we report logging domains? */
131 : static int log_domains_are_logged = 0;
132 :
133 : #ifdef HAVE_SYSLOG_H
134 : /** The number of open syslog log handlers that we have. When this reaches 0,
135 : * we can close our connection to the syslog facility. */
136 : static int syslog_count = 0;
137 : #endif
138 :
139 : /** Represents a log message that we are going to send to callback-driven
140 : * loggers once we can do so in a non-reentrant way. */
141 : typedef struct pending_log_message_t {
142 : int severity; /**< The severity of the message */
143 : log_domain_mask_t domain; /**< The domain of the message */
144 : char *fullmsg; /**< The message, with all decorations */
145 : char *msg; /**< The content of the message */
146 : } pending_log_message_t;
147 :
148 : /** Log messages waiting to be replayed onto callback-based logs */
149 : static smartlist_t *pending_cb_messages = NULL;
150 :
151 : /** Callback to invoke when pending_cb_messages becomes nonempty. */
152 : static pending_callback_callback pending_cb_cb = NULL;
153 :
154 : /** Log messages waiting to be replayed once the logging system is initialized.
155 : */
156 : static smartlist_t *pending_startup_messages = NULL;
157 :
158 : /** Number of bytes of messages queued in pending_startup_messages. (This is
159 : * the length of the messages, not the number of bytes used to store
160 : * them.) */
161 : static size_t pending_startup_messages_len;
162 :
163 : /** True iff we should store messages while waiting for the logs to get
164 : * configured. */
165 : static int queue_startup_messages = 1;
166 :
167 : /** True iff __PRETTY_FUNCTION__ includes parenthesized arguments. */
168 : static int pretty_fn_has_parens = 0;
169 :
170 : /** Don't store more than this many bytes of messages while waiting for the
171 : * logs to get configured. */
172 : #define MAX_STARTUP_MSG_LEN (1<<16)
173 :
174 : /** Lock the log_mutex to prevent others from changing the logfile_t list */
175 : #define LOCK_LOGS() STMT_BEGIN \
176 : raw_assert(log_mutex_initialized); \
177 : tor_mutex_acquire(&log_mutex); \
178 : STMT_END
179 : /** Unlock the log_mutex */
180 : #define UNLOCK_LOGS() STMT_BEGIN \
181 : raw_assert(log_mutex_initialized); \
182 : tor_mutex_release(&log_mutex); \
183 : STMT_END
184 :
185 : /** What's the lowest log level anybody cares about? Checking this lets us
186 : * bail out early from log_debug if we aren't debugging. */
187 : int log_global_min_severity_ = LOG_NOTICE;
188 :
189 : static void delete_log(logfile_t *victim);
190 : static void close_log(logfile_t *victim);
191 : static void close_log_sigsafe(logfile_t *victim);
192 :
193 : static char *domain_to_string(log_domain_mask_t domain,
194 : char *buf, size_t buflen);
195 : static inline char *format_msg(char *buf, size_t buf_len,
196 : log_domain_mask_t domain, int severity, const char *funcname,
197 : const char *suffix,
198 : const char *format, va_list ap, size_t *msg_len_out)
199 : CHECK_PRINTF(7,0);
200 :
201 : /** Name of the application: used to generate the message we write at the
202 : * start of each new log. */
203 : static char *appname = NULL;
204 :
205 : /** Set the "application name" for the logs to <b>name</b>: we'll use this
206 : * name in the message we write when starting up, and at the start of each new
207 : * log.
208 : *
209 : * Tor uses this string to write the version number to the log file. */
210 : void
211 235 : log_set_application_name(const char *name)
212 : {
213 235 : tor_free(appname);
214 235 : appname = name ? tor_strdup(name) : NULL;
215 235 : }
216 :
217 : /** Return true if some of the running logs might be interested in a log
218 : * message of the given severity in the given domains. If this function
219 : * returns true, the log message might be ignored anyway, but if it returns
220 : * false, it is definitely_ safe not to log the message. */
221 : int
222 0 : log_message_is_interesting(int severity, log_domain_mask_t domain)
223 : {
224 0 : (void) domain;
225 0 : return (severity <= log_global_min_severity_);
226 : }
227 :
228 : /**
229 : * As tor_log, but takes an optional function name, and does not treat its
230 : * <b>string</b> as a printf format.
231 : *
232 : * For use by Rust integration.
233 : */
234 : void
235 0 : tor_log_string(int severity, log_domain_mask_t domain,
236 : const char *function, const char *string)
237 : {
238 0 : log_fn_(severity, domain, function, "%s", string);
239 0 : }
240 :
241 : /** Log time granularity in milliseconds. */
242 : static int log_time_granularity = 1;
243 :
244 : /** Define log time granularity for all logs to be <b>granularity_msec</b>
245 : * milliseconds. */
246 14 : MOCK_IMPL(void,
247 : set_log_time_granularity,(int granularity_msec))
248 : {
249 14 : log_time_granularity = granularity_msec;
250 14 : tor_log_sigsafe_err_set_granularity(granularity_msec);
251 14 : }
252 :
253 : /** Helper: Write the standard prefix for log lines to a
254 : * <b>buf_len</b> character buffer in <b>buf</b>.
255 : */
256 : static inline size_t
257 9899 : log_prefix_(char *buf, size_t buf_len, int severity)
258 : {
259 9899 : time_t t;
260 9899 : struct timeval now;
261 9899 : struct tm tm;
262 9899 : size_t n;
263 9899 : int r, ms;
264 :
265 9899 : tor_gettimeofday(&now);
266 9899 : t = (time_t)now.tv_sec;
267 9899 : ms = (int)now.tv_usec / 1000;
268 9899 : if (log_time_granularity >= 1000) {
269 9 : t -= t % (log_time_granularity / 1000);
270 9 : ms = 0;
271 : } else {
272 9890 : ms -= ((int)now.tv_usec / 1000) % log_time_granularity;
273 : }
274 :
275 19798 : n = strftime(buf, buf_len, "%b %d %H:%M:%S",
276 9899 : tor_localtime_r_msg(&t, &tm, NULL));
277 9899 : r = tor_snprintf(buf+n, buf_len-n, ".%.3i [%s] ", ms,
278 : sev_to_string(severity));
279 :
280 9899 : if (r<0)
281 0 : return buf_len-1;
282 : else
283 9899 : return n+r;
284 : }
285 :
286 : /** If lf refers to an actual file that we have just opened, and the file
287 : * contains no data, log an "opening new logfile" message at the top.
288 : *
289 : * Return -1 if the log is broken and needs to be deleted, else return 0.
290 : */
291 : static int
292 1 : log_tor_version(logfile_t *lf, int reset)
293 : {
294 1 : char buf[256];
295 1 : size_t n;
296 1 : int is_new;
297 :
298 1 : if (!lf->needs_close)
299 : /* If it doesn't get closed, it isn't really a file. */
300 : return 0;
301 1 : if (lf->is_temporary)
302 : /* If it's temporary, it isn't really a file. */
303 : return 0;
304 :
305 1 : is_new = lf->fd >= 0 && tor_fd_getpos(lf->fd) == 0;
306 :
307 1 : if (reset && !is_new)
308 : /* We are resetting, but we aren't at the start of the file; no
309 : * need to log again. */
310 : return 0;
311 1 : n = log_prefix_(buf, sizeof(buf), LOG_NOTICE);
312 1 : if (appname) {
313 0 : tor_snprintf(buf+n, sizeof(buf)-n,
314 : "%s opening %slog file.\n", appname, is_new?"new ":"");
315 : } else {
316 1 : tor_snprintf(buf+n, sizeof(buf)-n,
317 : "Tor %s opening %slog file.\n", VERSION, is_new?"new ":"");
318 : }
319 1 : if (write_all_to_fd_minimal(lf->fd, buf, strlen(buf)) < 0) /* error */
320 0 : return -1; /* failed */
321 : return 0;
322 : }
323 :
324 : /** Helper: Format a log message into a fixed-sized buffer. (This is
325 : * factored out of <b>logv</b> so that we never format a message more
326 : * than once.) Return a pointer to the first character of the message
327 : * portion of the formatted string.
328 : */
329 : static inline char *
330 9898 : format_msg(char *buf, size_t buf_len,
331 : log_domain_mask_t domain, int severity, const char *funcname,
332 : const char *suffix,
333 : const char *format, va_list ap, size_t *msg_len_out)
334 : {
335 9898 : size_t n;
336 9898 : int r;
337 9898 : char *end_of_prefix;
338 9898 : char *buf_end;
339 :
340 9898 : raw_assert(buf_len >= 16); /* prevent integer underflow and stupidity */
341 9898 : buf_len -= 2; /* subtract 2 characters so we have room for \n\0 */
342 9898 : buf_end = buf+buf_len; /* point *after* the last char we can write to */
343 :
344 9898 : n = log_prefix_(buf, buf_len, severity);
345 9898 : end_of_prefix = buf+n;
346 :
347 9898 : if (log_domains_are_logged) {
348 0 : char *cp = buf+n;
349 0 : if (cp == buf_end) goto format_msg_no_room_for_domains;
350 0 : *cp++ = '{';
351 0 : if (cp == buf_end) goto format_msg_no_room_for_domains;
352 0 : cp = domain_to_string(domain, cp, (buf+buf_len-cp));
353 0 : if (cp == buf_end) goto format_msg_no_room_for_domains;
354 0 : *cp++ = '}';
355 0 : if (cp == buf_end) goto format_msg_no_room_for_domains;
356 0 : *cp++ = ' ';
357 0 : if (cp == buf_end) goto format_msg_no_room_for_domains;
358 0 : end_of_prefix = cp;
359 0 : n = cp-buf;
360 9898 : format_msg_no_room_for_domains:
361 : /* This will leave end_of_prefix and n unchanged, and thus cause
362 : * whatever log domain string we had written to be clobbered. */
363 9898 : ;
364 : }
365 :
366 9898 : if (funcname && should_log_function_name(domain, severity)) {
367 2668 : r = tor_snprintf(buf+n, buf_len-n,
368 2668 : pretty_fn_has_parens ? "%s: " : "%s(): ",
369 : funcname);
370 2668 : if (r<0)
371 0 : n = strlen(buf);
372 : else
373 2668 : n += r;
374 : }
375 :
376 9898 : if (domain == LD_BUG && buf_len-n > 6) {
377 2667 : memcpy(buf+n, "Bug: ", 6);
378 2667 : n += 5;
379 : }
380 :
381 9898 : r = tor_vsnprintf(buf+n,buf_len-n,format,ap);
382 9898 : if (r < 0) {
383 : /* The message was too long; overwrite the end of the buffer with
384 : * "[...truncated]" */
385 0 : if (buf_len >= TRUNCATED_STR_LEN) {
386 0 : size_t offset = buf_len-TRUNCATED_STR_LEN;
387 : /* We have an extra 2 characters after buf_len to hold the \n\0,
388 : * so it's safe to add 1 to the size here. */
389 0 : strlcpy(buf+offset, TRUNCATED_STR, buf_len-offset+1);
390 : }
391 : /* Set 'n' to the end of the buffer, where we'll be writing \n\0.
392 : * Since we already subtracted 2 from buf_len, this is safe.*/
393 0 : n = buf_len;
394 : } else {
395 9898 : n += r;
396 9898 : if (suffix) {
397 0 : size_t suffix_len = strlen(suffix);
398 0 : if (buf_len-n >= suffix_len) {
399 0 : memcpy(buf+n, suffix, suffix_len);
400 0 : n += suffix_len;
401 : }
402 : }
403 : }
404 :
405 9898 : if (domain == LD_BUG &&
406 2667 : buf_len - n > strlen(tor_bug_suffix)+1) {
407 2667 : memcpy(buf+n, tor_bug_suffix, strlen(tor_bug_suffix));
408 2667 : n += strlen(tor_bug_suffix);
409 : }
410 :
411 9898 : buf[n]='\n';
412 9898 : buf[n+1]='\0';
413 9898 : *msg_len_out = n+1;
414 9898 : return end_of_prefix;
415 : }
416 :
417 : /* Create a new pending_log_message_t with appropriate values */
418 : static pending_log_message_t *
419 7217 : pending_log_message_new(int severity, log_domain_mask_t domain,
420 : const char *fullmsg, const char *shortmsg)
421 : {
422 7217 : pending_log_message_t *m = tor_malloc(sizeof(pending_log_message_t));
423 7217 : m->severity = severity;
424 7217 : m->domain = domain;
425 7217 : m->fullmsg = fullmsg ? tor_strdup(fullmsg) : NULL;
426 7217 : m->msg = tor_strdup(shortmsg);
427 7217 : return m;
428 : }
429 :
430 : #define pending_log_message_free(msg) \
431 : FREE_AND_NULL(pending_log_message_t, pending_log_message_free_, (msg))
432 :
433 : /** Release all storage held by <b>msg</b>. */
434 : static void
435 7217 : pending_log_message_free_(pending_log_message_t *msg)
436 : {
437 7217 : if (!msg)
438 : return;
439 7217 : tor_free(msg->msg);
440 7217 : tor_free(msg->fullmsg);
441 7217 : tor_free(msg);
442 : }
443 :
444 : /** Helper function: returns true iff the log file, given in <b>lf</b>, is
445 : * handled externally via the system log API, or is an
446 : * external callback function. */
447 : static inline int
448 52 : logfile_is_external(const logfile_t *lf)
449 : {
450 52 : raw_assert(lf);
451 52 : return lf->is_syslog || lf->callback;
452 : }
453 :
454 : /** Return true iff <b>lf</b> would like to receive a message with the
455 : * specified <b>severity</b> in the specified <b>domain</b>.
456 : */
457 : static inline int
458 16747 : logfile_wants_message(const logfile_t *lf, int severity,
459 : log_domain_mask_t domain)
460 : {
461 16747 : if (! (lf->severities->masks[SEVERITY_MASK_IDX(severity)] & domain)) {
462 : return 0;
463 : }
464 3465 : if (! (lf->fd >= 0 || logfile_is_external(lf))) {
465 : return 0;
466 : }
467 3465 : if (lf->seems_dead) {
468 0 : return 0;
469 : }
470 :
471 : return 1;
472 : }
473 :
474 : /** Send a message to <b>lf</b>. The full message, with time prefix and
475 : * severity, is in <b>buf</b>. The message itself is in
476 : * <b>msg_after_prefix</b>. If <b>callbacks_deferred</b> points to true, then
477 : * we already deferred this message for pending callbacks and don't need to do
478 : * it again. Otherwise, if we need to do it, do it, and set
479 : * <b>callbacks_deferred</b> to 1. */
480 : static inline void
481 3449 : logfile_deliver(logfile_t *lf, const char *buf, size_t msg_len,
482 : const char *msg_after_prefix, log_domain_mask_t domain,
483 : int severity, int *callbacks_deferred)
484 : {
485 :
486 3449 : if (lf->is_syslog) {
487 : #ifdef HAVE_SYSLOG_H
488 : #ifdef MAXLINE
489 : /* Some syslog implementations have limits on the length of what you can
490 : * pass them, and some very old ones do not detect overflow so well.
491 : * Regrettably, they call their maximum line length MAXLINE. */
492 : #if MAXLINE < 64
493 : #warning "MAXLINE is very low; it might not be from syslog.h."
494 : #endif
495 : char *m = msg_after_prefix;
496 : if (msg_len >= MAXLINE)
497 : m = tor_strndup(msg_after_prefix, MAXLINE-1);
498 : syslog(severity, "%s", m);
499 : if (m != msg_after_prefix) {
500 : tor_free(m);
501 : }
502 : #else /* !defined(MAXLINE) */
503 : /* We have syslog but not MAXLINE. That's promising! */
504 0 : syslog(severity, "%s", msg_after_prefix);
505 : #endif /* defined(MAXLINE) */
506 : #endif /* defined(HAVE_SYSLOG_H) */
507 3449 : } else if (lf->callback) {
508 14 : if (domain & LD_NOCB) {
509 0 : if (!*callbacks_deferred && pending_cb_messages) {
510 0 : smartlist_add(pending_cb_messages,
511 0 : pending_log_message_new(severity,domain,NULL,msg_after_prefix));
512 0 : *callbacks_deferred = 1;
513 0 : if (smartlist_len(pending_cb_messages) == 1 && pending_cb_cb) {
514 0 : pending_cb_cb();
515 : }
516 : }
517 : } else {
518 14 : lf->callback(severity, domain, msg_after_prefix);
519 : }
520 : } else {
521 3435 : if (write_all_to_fd_minimal(lf->fd, buf, msg_len) < 0) { /* error */
522 : /* don't log the error! mark this log entry to be blown away, and
523 : * continue. */
524 0 : lf->seems_dead = 1;
525 : }
526 : }
527 3449 : }
528 :
529 : /** Helper: sends a message to the appropriate logfiles, at loglevel
530 : * <b>severity</b>. If provided, <b>funcname</b> is prepended to the
531 : * message. The actual message is derived as from tor_snprintf(format,ap).
532 : */
533 21616 : MOCK_IMPL(STATIC void,
534 : logv,(int severity, log_domain_mask_t domain, const char *funcname,
535 : const char *suffix, const char *format, va_list ap))
536 : {
537 21616 : char buf[10240];
538 21616 : size_t msg_len = 0;
539 21616 : int formatted = 0;
540 21616 : logfile_t *lf;
541 21616 : char *end_of_prefix=NULL;
542 21616 : int callbacks_deferred = 0;
543 :
544 : /* Call raw_assert, not tor_assert, since tor_assert calls log on failure. */
545 21616 : raw_assert(format);
546 : /* check that severity is sane. Overrunning the masks array leads to
547 : * interesting and hard to diagnose effects */
548 21616 : raw_assert(severity >= LOG_ERR && severity <= LOG_DEBUG);
549 :
550 21616 : LOCK_LOGS();
551 :
552 21616 : if ((! (domain & LD_NOCB)) && pending_cb_messages
553 21616 : && smartlist_len(pending_cb_messages))
554 0 : flush_pending_log_callbacks();
555 :
556 21616 : if (queue_startup_messages &&
557 7217 : pending_startup_messages_len < MAX_STARTUP_MSG_LEN) {
558 7217 : end_of_prefix =
559 7217 : format_msg(buf, sizeof(buf), domain, severity, funcname, suffix,
560 : format, ap, &msg_len);
561 7217 : formatted = 1;
562 :
563 7217 : smartlist_add(pending_startup_messages,
564 7217 : pending_log_message_new(severity,domain,buf,end_of_prefix));
565 7217 : pending_startup_messages_len += msg_len;
566 : }
567 :
568 38307 : for (lf = logfiles; lf; lf = lf->next) {
569 16691 : if (! logfile_wants_message(lf, severity, domain))
570 13242 : continue;
571 :
572 3449 : if (!formatted) {
573 2681 : end_of_prefix =
574 2681 : format_msg(buf, sizeof(buf), domain, severity, funcname, suffix,
575 : format, ap, &msg_len);
576 2681 : formatted = 1;
577 : }
578 :
579 3449 : logfile_deliver(lf, buf, msg_len, end_of_prefix, domain, severity,
580 : &callbacks_deferred);
581 : }
582 21616 : UNLOCK_LOGS();
583 21616 : }
584 :
585 : /** Output a message to the log. It gets logged to all logfiles that
586 : * care about messages with <b>severity</b> in <b>domain</b>. The content
587 : * is formatted printf-style based on <b>format</b> and extra arguments.
588 : * */
589 : void
590 1109 : tor_log(int severity, log_domain_mask_t domain, const char *format, ...)
591 : {
592 1109 : va_list ap;
593 :
594 : /* check that domain is composed of known domains and flags */
595 1109 : raw_assert((domain & (LD_ALL_DOMAINS|LD_ALL_FLAGS)) == domain);
596 :
597 1109 : if (severity > log_global_min_severity_)
598 329 : return;
599 780 : va_start(ap,format);
600 : #ifdef TOR_UNIT_TESTS
601 780 : if (domain & LD_NO_MOCK)
602 619 : logv__real(severity, domain, NULL, NULL, format, ap);
603 : else
604 : #endif
605 161 : logv(severity, domain, NULL, NULL, format, ap);
606 780 : va_end(ap);
607 : }
608 :
609 : /** Helper function; return true iff the <b>n</b>-element array <b>array</b>
610 : * contains <b>item</b>. */
611 : static int
612 34 : int_array_contains(const int *array, int n, int item)
613 : {
614 34 : int j;
615 99 : for (j = 0; j < n; ++j) {
616 75 : if (array[j] == item)
617 : return 1;
618 : }
619 : return 0;
620 : }
621 :
622 : /** Function to call whenever the list of logs changes to get ready to log
623 : * from signal handlers. */
624 : void
625 13 : tor_log_update_sigsafe_err_fds(void)
626 : {
627 13 : const logfile_t *lf;
628 13 : int found_real_stderr = 0;
629 :
630 : /* The fds are the file descriptors of tor's stdout, stderr, and file
631 : * logs. The log and err modules flush these fds during their shutdowns. */
632 13 : int fds[TOR_SIGSAFE_LOG_MAX_FDS];
633 13 : int n_fds;
634 :
635 13 : LOCK_LOGS();
636 : /* Reserve the first one for stderr. This is safe because when we daemonize,
637 : * we dup2 /dev/null to stderr. */
638 13 : fds[0] = STDERR_FILENO;
639 13 : n_fds = 1;
640 :
641 52 : for (lf = logfiles; lf; lf = lf->next) {
642 : /* Don't try callback to the control port, syslogs, or any
643 : * other non-file descriptor log: We can't call arbitrary functions from a
644 : * signal handler.
645 : */
646 40 : if (lf->is_temporary || logfile_is_external(lf)
647 28 : || lf->seems_dead || lf->fd < 0)
648 12 : continue;
649 28 : if (lf->severities->masks[SEVERITY_MASK_IDX(LOG_ERR)] &
650 : (LD_BUG|LD_GENERAL)) {
651 22 : if (lf->fd == STDERR_FILENO)
652 1 : found_real_stderr = 1;
653 : /* Avoid duplicates by checking the log module fd against fds */
654 22 : if (int_array_contains(fds, n_fds, lf->fd))
655 1 : continue;
656 : /* Update fds using the log module's fd */
657 21 : fds[n_fds] = lf->fd;
658 21 : n_fds++;
659 21 : if (n_fds == TOR_SIGSAFE_LOG_MAX_FDS)
660 : break;
661 : }
662 : }
663 :
664 13 : if (!found_real_stderr &&
665 12 : int_array_contains(fds, n_fds, STDOUT_FILENO)) {
666 : /* Don't use a virtual stderr when we're also logging to stdout.
667 : * If we reached max_fds logs, we'll now have (max_fds - 1) logs.
668 : * That's ok, max_fds is large enough that most tor instances don't exceed
669 : * it. */
670 9 : raw_assert(n_fds >= 2); /* Don't tor_assert inside log fns */
671 9 : --n_fds;
672 9 : fds[0] = fds[n_fds];
673 : }
674 :
675 13 : UNLOCK_LOGS();
676 :
677 13 : tor_log_set_sigsafe_err_fds(fds, n_fds);
678 13 : }
679 :
680 : /** Add to <b>out</b> a copy of every currently configured log file name. Used
681 : * to enable access to these filenames with the sandbox code. */
682 : void
683 0 : tor_log_get_logfile_names(smartlist_t *out)
684 : {
685 0 : logfile_t *lf;
686 0 : raw_assert(out);
687 :
688 0 : LOCK_LOGS();
689 :
690 0 : for (lf = logfiles; lf; lf = lf->next) {
691 0 : if (lf->is_temporary || logfile_is_external(lf))
692 0 : continue;
693 0 : if (lf->filename == NULL)
694 0 : continue;
695 0 : smartlist_add_strdup(out, lf->filename);
696 : }
697 :
698 0 : UNLOCK_LOGS();
699 0 : }
700 :
701 : /** Implementation of the log_fn backend, used when we have
702 : * variadic macros. All arguments are as for log_fn, except for
703 : * <b>fn</b>, which is the name of the calling function. */
704 : void
705 417311 : log_fn_(int severity, log_domain_mask_t domain, const char *fn,
706 : const char *format, ...)
707 : {
708 417311 : va_list ap;
709 417311 : if (severity > log_global_min_severity_)
710 395473 : return;
711 21838 : va_start(ap,format);
712 21838 : logv(severity, domain, fn, NULL, format, ap);
713 21838 : va_end(ap);
714 : }
715 : void
716 38 : log_fn_ratelim_(ratelim_t *ratelim, int severity, log_domain_mask_t domain,
717 : const char *fn, const char *format, ...)
718 : {
719 38 : va_list ap;
720 38 : char *m;
721 38 : if (severity > log_global_min_severity_)
722 25 : return;
723 17 : m = rate_limit_log(ratelim, approx_time());
724 17 : if (m == NULL)
725 : return;
726 13 : va_start(ap, format);
727 13 : logv(severity, domain, fn, m, format, ap);
728 13 : va_end(ap);
729 13 : tor_free(m);
730 : }
731 :
732 : /** Free all storage held by <b>victim</b>. */
733 : static void
734 141 : log_free_(logfile_t *victim)
735 : {
736 141 : if (!victim)
737 : return;
738 141 : tor_free(victim->severities);
739 141 : tor_free(victim->filename);
740 141 : tor_free(victim);
741 : }
742 :
743 : /** Close all open log files, and free other static memory. */
744 : void
745 236 : logs_free_all(void)
746 : {
747 236 : logfile_t *victim, *next;
748 236 : smartlist_t *messages, *messages2;
749 236 : LOCK_LOGS();
750 236 : next = logfiles;
751 236 : logfiles = NULL;
752 236 : messages = pending_cb_messages;
753 236 : pending_cb_messages = NULL;
754 236 : pending_cb_cb = NULL;
755 236 : messages2 = pending_startup_messages;
756 236 : pending_startup_messages = NULL;
757 236 : UNLOCK_LOGS();
758 236 : while (next) {
759 122 : victim = next;
760 122 : next = next->next;
761 122 : close_log(victim);
762 358 : log_free(victim);
763 : }
764 236 : tor_free(appname);
765 :
766 236 : SMARTLIST_FOREACH(messages, pending_log_message_t *, msg, {
767 : pending_log_message_free(msg);
768 : });
769 236 : smartlist_free(messages);
770 :
771 236 : if (messages2) {
772 2111 : SMARTLIST_FOREACH(messages2, pending_log_message_t *, msg, {
773 : pending_log_message_free(msg);
774 : });
775 231 : smartlist_free(messages2);
776 : }
777 :
778 : /* We _could_ destroy the log mutex here, but that would screw up any logs
779 : * that happened between here and the end of execution.
780 : * If tor is re-initialized, log_mutex_initialized will still be 1. So we
781 : * won't trigger any undefined behaviour by trying to re-initialize the
782 : * log mutex. */
783 236 : }
784 :
785 : /** Flush the signal-safe log files.
786 : *
787 : * This function is safe to call from a signal handler. It is currently called
788 : * by the BUG() macros, when terminating the process on an abnormal condition.
789 : */
790 : void
791 0 : logs_flush_sigsafe(void)
792 : {
793 : /* If we don't have fsync() in unistd.h, we can't flush the logs. */
794 : #ifdef HAVE_FSYNC
795 0 : logfile_t *victim, *next;
796 : /* We can't LOCK_LOGS() in a signal handler, because it may call
797 : * signal-unsafe functions. And we can't deallocate memory, either. */
798 0 : next = logfiles;
799 0 : logfiles = NULL;
800 0 : while (next) {
801 0 : victim = next;
802 0 : next = next->next;
803 0 : if (victim->needs_close) {
804 : /* We can't do anything useful if the flush fails. */
805 0 : (void)fsync(victim->fd);
806 : }
807 : }
808 : #endif /* defined(HAVE_FSYNC) */
809 0 : }
810 :
811 : /** Remove and free the log entry <b>victim</b> from the linked-list
812 : * logfiles (it is probably present, but it might not be due to thread
813 : * racing issues). After this function is called, the caller shouldn't
814 : * refer to <b>victim</b> anymore.
815 : */
816 : static void
817 0 : delete_log(logfile_t *victim)
818 : {
819 0 : logfile_t *tmpl;
820 0 : if (victim == logfiles)
821 0 : logfiles = victim->next;
822 : else {
823 0 : for (tmpl = logfiles; tmpl && tmpl->next != victim; tmpl=tmpl->next) ;
824 : // raw_assert(tmpl);
825 : // raw_assert(tmpl->next == victim);
826 0 : if (!tmpl)
827 : return;
828 0 : tmpl->next = victim->next;
829 : }
830 0 : log_free(victim);
831 : }
832 :
833 : /** Helper: release system resources (but not memory) held by a single
834 : * signal-safe logfile_t. If the log's resources can not be released in
835 : * a signal handler, does nothing. */
836 : static void
837 1 : close_log_sigsafe(logfile_t *victim)
838 : {
839 1 : if (victim->needs_close && victim->fd >= 0) {
840 : /* We can't do anything useful here if close() fails: we're shutting
841 : * down logging, and the err module only does fatal errors. */
842 1 : close(victim->fd);
843 1 : victim->fd = -1;
844 : }
845 1 : }
846 :
847 : /** Helper: release system resources (but not memory) held by a single
848 : * logfile_t. */
849 : static void
850 141 : close_log(logfile_t *victim)
851 : {
852 141 : if (victim->needs_close) {
853 1 : close_log_sigsafe(victim);
854 140 : } else if (victim->is_syslog) {
855 : #ifdef HAVE_SYSLOG_H
856 0 : if (--syslog_count == 0) {
857 : /* There are no other syslogs; close the logging facility. */
858 0 : closelog();
859 : }
860 : #endif /* defined(HAVE_SYSLOG_H) */
861 : }
862 141 : }
863 :
864 : /** Adjust a log severity configuration in <b>severity_out</b> to contain
865 : * every domain between <b>loglevelMin</b> and <b>loglevelMax</b>, inclusive.
866 : */
867 : void
868 5699 : set_log_severity_config(int loglevelMin, int loglevelMax,
869 : log_severity_list_t *severity_out)
870 : {
871 5699 : int i;
872 5699 : raw_assert(loglevelMin >= loglevelMax);
873 5699 : raw_assert(loglevelMin >= LOG_ERR && loglevelMin <= LOG_DEBUG);
874 5699 : raw_assert(loglevelMax >= LOG_ERR && loglevelMax <= LOG_DEBUG);
875 5699 : memset(severity_out, 0, sizeof(log_severity_list_t));
876 11615 : for (i = loglevelMin; i >= loglevelMax; --i) {
877 5916 : severity_out->masks[SEVERITY_MASK_IDX(i)] = LD_ALL_DOMAINS;
878 : }
879 5699 : }
880 :
881 : /** Add a log handler named <b>name</b> to send all messages in <b>severity</b>
882 : * to <b>fd</b>. Copies <b>severity</b>. Helper: does no locking. */
883 5465 : MOCK_IMPL(STATIC void,
884 : add_stream_log_impl,(const log_severity_list_t *severity,
885 : const char *name, int fd))
886 : {
887 5465 : logfile_t *lf;
888 5465 : lf = tor_malloc_zero(sizeof(logfile_t));
889 5465 : lf->fd = fd;
890 5465 : lf->filename = tor_strdup(name);
891 5465 : lf->severities = tor_memdup(severity, sizeof(log_severity_list_t));
892 5465 : lf->next = logfiles;
893 :
894 5465 : logfiles = lf;
895 5465 : log_global_min_severity_ = get_min_log_level();
896 5465 : }
897 :
898 : /** Add a log handler named <b>name</b> to send all messages in <b>severity</b>
899 : * to <b>fd</b>. Steals a reference to <b>severity</b>; the caller must
900 : * not use it after calling this function. */
901 : void
902 5343 : add_stream_log(const log_severity_list_t *severity, const char *name, int fd)
903 : {
904 5343 : LOCK_LOGS();
905 5343 : add_stream_log_impl(severity, name, fd);
906 5343 : UNLOCK_LOGS();
907 5343 : }
908 :
909 : /** Initialize the global logging facility */
910 : void
911 5564 : init_logging(int disable_startup_queue)
912 : {
913 5564 : if (!log_mutex_initialized) {
914 5562 : tor_mutex_init(&log_mutex);
915 5562 : log_mutex_initialized = 1;
916 : }
917 : #ifdef __GNUC__
918 5564 : if (strchr(__PRETTY_FUNCTION__, '(')) {
919 : pretty_fn_has_parens = 1;
920 : }
921 : #endif
922 5564 : if (pending_cb_messages == NULL)
923 5562 : pending_cb_messages = smartlist_new();
924 5564 : if (disable_startup_queue)
925 11 : queue_startup_messages = 0;
926 5564 : if (pending_startup_messages == NULL && queue_startup_messages) {
927 5553 : pending_startup_messages = smartlist_new();
928 : }
929 5564 : }
930 :
931 : /** Set whether we report logging domains as a part of our log messages.
932 : */
933 : void
934 18 : logs_set_domain_logging(int enabled)
935 : {
936 18 : LOCK_LOGS();
937 18 : log_domains_are_logged = enabled;
938 18 : UNLOCK_LOGS();
939 18 : }
940 :
941 : /** Add a log handler to accept messages when no other log is configured.
942 : */
943 : void
944 123 : add_default_log(int min_severity)
945 : {
946 123 : log_severity_list_t *s = tor_malloc_zero(sizeof(log_severity_list_t));
947 123 : set_log_severity_config(min_severity, LOG_ERR, s);
948 123 : LOCK_LOGS();
949 123 : add_stream_log_impl(s, "<default>", fileno(stdout));
950 123 : tor_free(s);
951 123 : UNLOCK_LOGS();
952 123 : }
953 :
954 : /**
955 : * Register "cb" as the callback to call when there are new pending log
956 : * callbacks to be flushed with flush_pending_log_callbacks().
957 : *
958 : * Note that this callback, if present, can be invoked from any thread.
959 : *
960 : * This callback must not log.
961 : *
962 : * It is intentional that this function contains the name "callback" twice: it
963 : * sets a "callback" to be called on the condition that there is a "pending
964 : * callback".
965 : **/
966 : void
967 7 : logs_set_pending_callback_callback(pending_callback_callback cb)
968 : {
969 7 : pending_cb_cb = cb;
970 7 : }
971 :
972 : /**
973 : * Add a log handler to send messages in <b>severity</b>
974 : * to the function <b>cb</b>.
975 : */
976 : int
977 19 : add_callback_log(const log_severity_list_t *severity, log_callback cb)
978 : {
979 19 : logfile_t *lf;
980 19 : lf = tor_malloc_zero(sizeof(logfile_t));
981 19 : lf->fd = -1;
982 19 : lf->severities = tor_memdup(severity, sizeof(log_severity_list_t));
983 19 : lf->filename = tor_strdup("<callback>");
984 19 : lf->callback = cb;
985 19 : lf->next = logfiles;
986 :
987 19 : LOCK_LOGS();
988 19 : logfiles = lf;
989 19 : log_global_min_severity_ = get_min_log_level();
990 19 : UNLOCK_LOGS();
991 19 : return 0;
992 : }
993 :
994 : /** Adjust the configured severity of any logs whose callback function is
995 : * <b>cb</b>. */
996 : void
997 244 : change_callback_log_severity(int loglevelMin, int loglevelMax,
998 : log_callback cb)
999 : {
1000 244 : logfile_t *lf;
1001 244 : log_severity_list_t severities;
1002 244 : set_log_severity_config(loglevelMin, loglevelMax, &severities);
1003 244 : LOCK_LOGS();
1004 383 : for (lf = logfiles; lf; lf = lf->next) {
1005 139 : if (lf->callback == cb) {
1006 139 : memcpy(lf->severities, &severities, sizeof(severities));
1007 : }
1008 : }
1009 244 : log_global_min_severity_ = get_min_log_level();
1010 244 : UNLOCK_LOGS();
1011 244 : }
1012 :
1013 : /** If there are any log messages that were generated with LD_NOCB waiting to
1014 : * be sent to callback-based loggers, send them now. */
1015 : void
1016 0 : flush_pending_log_callbacks(void)
1017 : {
1018 0 : logfile_t *lf;
1019 0 : smartlist_t *messages, *messages_tmp;
1020 :
1021 0 : LOCK_LOGS();
1022 0 : if (!pending_cb_messages || 0 == smartlist_len(pending_cb_messages)) {
1023 0 : UNLOCK_LOGS();
1024 0 : return;
1025 : }
1026 :
1027 0 : messages = pending_cb_messages;
1028 0 : pending_cb_messages = smartlist_new();
1029 0 : do {
1030 0 : SMARTLIST_FOREACH_BEGIN(messages, pending_log_message_t *, msg) {
1031 0 : const int severity = msg->severity;
1032 0 : const log_domain_mask_t domain = msg->domain;
1033 0 : for (lf = logfiles; lf; lf = lf->next) {
1034 0 : if (! lf->callback || lf->seems_dead ||
1035 0 : ! (lf->severities->masks[SEVERITY_MASK_IDX(severity)] & domain)) {
1036 0 : continue;
1037 : }
1038 0 : lf->callback(severity, domain, msg->msg);
1039 : }
1040 0 : pending_log_message_free(msg);
1041 0 : } SMARTLIST_FOREACH_END(msg);
1042 0 : smartlist_clear(messages);
1043 :
1044 0 : messages_tmp = pending_cb_messages;
1045 0 : pending_cb_messages = messages;
1046 0 : messages = messages_tmp;
1047 0 : } while (smartlist_len(messages));
1048 :
1049 0 : smartlist_free(messages);
1050 :
1051 0 : UNLOCK_LOGS();
1052 : }
1053 :
1054 : /** Flush all the messages we stored from startup while waiting for log
1055 : * initialization.
1056 : */
1057 : void
1058 5325 : flush_log_messages_from_startup(void)
1059 : {
1060 5325 : logfile_t *lf;
1061 :
1062 5325 : LOCK_LOGS();
1063 5325 : queue_startup_messages = 0;
1064 5325 : pending_startup_messages_len = 0;
1065 5325 : if (! pending_startup_messages)
1066 3 : goto out;
1067 :
1068 10659 : SMARTLIST_FOREACH_BEGIN(pending_startup_messages, pending_log_message_t *,
1069 : msg) {
1070 5337 : int callbacks_deferred = 0;
1071 5393 : for (lf = logfiles; lf; lf = lf->next) {
1072 56 : if (! logfile_wants_message(lf, msg->severity, msg->domain))
1073 40 : continue;
1074 :
1075 : /* We configure a temporary startup log that goes to stdout, so we
1076 : * shouldn't replay to stdout/stderr*/
1077 16 : if (lf->fd == STDOUT_FILENO || lf->fd == STDERR_FILENO) {
1078 16 : continue;
1079 : }
1080 :
1081 0 : logfile_deliver(lf, msg->fullmsg, strlen(msg->fullmsg), msg->msg,
1082 : msg->domain, msg->severity, &callbacks_deferred);
1083 : }
1084 5337 : pending_log_message_free(msg);
1085 5337 : } SMARTLIST_FOREACH_END(msg);
1086 5322 : smartlist_free(pending_startup_messages);
1087 5322 : pending_startup_messages = NULL;
1088 :
1089 5325 : out:
1090 5325 : UNLOCK_LOGS();
1091 5325 : }
1092 :
1093 : /** Close any log handlers marked by mark_logs_temp(). */
1094 : void
1095 13 : close_temp_logs(void)
1096 : {
1097 13 : logfile_t *lf, **p;
1098 :
1099 13 : LOCK_LOGS();
1100 61 : for (p = &logfiles; *p; ) {
1101 35 : if ((*p)->is_temporary) {
1102 19 : lf = *p;
1103 : /* we use *p here to handle the edge case of the head of the list */
1104 19 : *p = (*p)->next;
1105 19 : close_log(lf);
1106 19 : log_free(lf);
1107 : } else {
1108 16 : p = &((*p)->next);
1109 : }
1110 : }
1111 :
1112 13 : log_global_min_severity_ = get_min_log_level();
1113 13 : UNLOCK_LOGS();
1114 13 : }
1115 :
1116 : /** Make all currently temporary logs (set to be closed by close_temp_logs)
1117 : * live again, and close all non-temporary logs. */
1118 : void
1119 2 : rollback_log_changes(void)
1120 : {
1121 2 : logfile_t *lf;
1122 2 : LOCK_LOGS();
1123 7 : for (lf = logfiles; lf; lf = lf->next)
1124 5 : lf->is_temporary = ! lf->is_temporary;
1125 2 : UNLOCK_LOGS();
1126 2 : close_temp_logs();
1127 2 : }
1128 :
1129 : /** Configure all log handles to be closed by close_temp_logs(). */
1130 : void
1131 14 : mark_logs_temp(void)
1132 : {
1133 14 : logfile_t *lf;
1134 14 : LOCK_LOGS();
1135 39 : for (lf = logfiles; lf; lf = lf->next)
1136 25 : lf->is_temporary = 1;
1137 14 : UNLOCK_LOGS();
1138 14 : }
1139 :
1140 : /**
1141 : * Add a log handler to send messages to <b>filename</b> via <b>fd</b>. If
1142 : * opening the logfile failed, -1 is returned and errno is set appropriately
1143 : * (by open(2)). Takes ownership of fd.
1144 : */
1145 1 : MOCK_IMPL(int,
1146 : add_file_log,(const log_severity_list_t *severity,
1147 : const char *filename,
1148 : int fd))
1149 : {
1150 1 : logfile_t *lf;
1151 :
1152 1 : if (fd<0)
1153 : return -1;
1154 1 : if (tor_fd_seekend(fd)<0) {
1155 0 : close(fd);
1156 0 : return -1;
1157 : }
1158 :
1159 1 : LOCK_LOGS();
1160 1 : add_stream_log_impl(severity, filename, fd);
1161 1 : logfiles->needs_close = 1;
1162 1 : lf = logfiles;
1163 1 : log_global_min_severity_ = get_min_log_level();
1164 :
1165 1 : if (log_tor_version(lf, 0) < 0) {
1166 0 : delete_log(lf);
1167 : }
1168 1 : UNLOCK_LOGS();
1169 :
1170 1 : return 0;
1171 : }
1172 :
1173 : #ifdef HAVE_SYSLOG_H
1174 : /**
1175 : * Add a log handler to send messages to they system log facility.
1176 : *
1177 : * If this is the first log handler, opens syslog with ident Tor or
1178 : * Tor-<syslog_identity_tag> if that is not NULL.
1179 : */
1180 : int
1181 0 : add_syslog_log(const log_severity_list_t *severity,
1182 : const char* syslog_identity_tag)
1183 : {
1184 0 : logfile_t *lf;
1185 0 : if (syslog_count++ == 0) {
1186 : /* This is the first syslog. */
1187 0 : static char buf[256];
1188 0 : if (syslog_identity_tag) {
1189 0 : tor_snprintf(buf, sizeof(buf), "Tor-%s", syslog_identity_tag);
1190 : } else {
1191 0 : tor_snprintf(buf, sizeof(buf), "Tor");
1192 : }
1193 0 : openlog(buf, LOG_PID | LOG_NDELAY, LOGFACILITY);
1194 : }
1195 :
1196 0 : lf = tor_malloc_zero(sizeof(logfile_t));
1197 0 : lf->fd = -1;
1198 0 : lf->severities = tor_memdup(severity, sizeof(log_severity_list_t));
1199 0 : lf->filename = tor_strdup("<syslog>");
1200 0 : lf->is_syslog = 1;
1201 :
1202 0 : LOCK_LOGS();
1203 0 : lf->next = logfiles;
1204 0 : logfiles = lf;
1205 0 : log_global_min_severity_ = get_min_log_level();
1206 0 : UNLOCK_LOGS();
1207 0 : return 0;
1208 : }
1209 : #endif /* defined(HAVE_SYSLOG_H) */
1210 :
1211 : /** If <b>level</b> is a valid log severity, return the corresponding
1212 : * numeric value. Otherwise, return -1. */
1213 : int
1214 42 : parse_log_level(const char *level)
1215 : {
1216 42 : if (!strcasecmp(level, "err"))
1217 : return LOG_ERR;
1218 21 : if (!strcasecmp(level, "warn"))
1219 : return LOG_WARN;
1220 20 : if (!strcasecmp(level, "notice"))
1221 : return LOG_NOTICE;
1222 13 : if (!strcasecmp(level, "info"))
1223 : return LOG_INFO;
1224 7 : if (!strcasecmp(level, "debug"))
1225 6 : return LOG_DEBUG;
1226 : return -1;
1227 : }
1228 :
1229 : /** Return the string equivalent of a given log level. */
1230 : const char *
1231 0 : log_level_to_string(int level)
1232 : {
1233 0 : return sev_to_string(level);
1234 : }
1235 :
1236 : /** NULL-terminated array of names for log domains such that domain_list[dom]
1237 : * is a description of <b>dom</b>.
1238 : *
1239 : * Remember to update doc/man/tor.1.txt if you modify this list.
1240 : * */
1241 : static const char *domain_list[] = {
1242 : "GENERAL", "CRYPTO", "NET", "CONFIG", "FS", "PROTOCOL", "MM",
1243 : "HTTP", "APP", "CONTROL", "CIRC", "REND", "BUG", "DIR", "DIRSERV",
1244 : "OR", "EDGE", "ACCT", "HIST", "HANDSHAKE", "HEARTBEAT", "CHANNEL",
1245 : "SCHED", "GUARD", "CONSDIFF", "DOS", "PROCESS", "PT", "BTRACK", "MESG",
1246 : NULL
1247 : };
1248 :
1249 : CTASSERT(ARRAY_LENGTH(domain_list) == N_LOGGING_DOMAINS + 1);
1250 :
1251 : CTASSERT(HIGHEST_RESERVED_LD_DOMAIN_ < LD_ALL_DOMAINS);
1252 : CTASSERT(LD_ALL_DOMAINS < LOWEST_RESERVED_LD_FLAG_);
1253 : CTASSERT(LOWEST_RESERVED_LD_FLAG_ < LD_ALL_FLAGS);
1254 :
1255 : /** Return a bitmask for the log domain for which <b>domain</b> is the name,
1256 : * or 0 if there is no such name. */
1257 : static log_domain_mask_t
1258 6 : parse_log_domain(const char *domain)
1259 : {
1260 6 : int i;
1261 60 : for (i=0; domain_list[i]; ++i) {
1262 60 : if (!strcasecmp(domain, domain_list[i]))
1263 6 : return (UINT64_C(1)<<i);
1264 : }
1265 : return 0;
1266 : }
1267 :
1268 : /** Translate a bitmask of log domains to a string. */
1269 : static char *
1270 0 : domain_to_string(log_domain_mask_t domain, char *buf, size_t buflen)
1271 : {
1272 0 : char *cp = buf;
1273 0 : char *eos = buf+buflen;
1274 :
1275 0 : buf[0] = '\0';
1276 0 : if (! domain)
1277 : return buf;
1278 0 : while (1) {
1279 0 : const char *d;
1280 0 : int bit = tor_log2(domain);
1281 0 : size_t n;
1282 0 : if ((unsigned)bit >= ARRAY_LENGTH(domain_list)-1 ||
1283 : bit >= N_LOGGING_DOMAINS) {
1284 0 : tor_snprintf(buf, buflen, "<BUG:Unknown domain %lx>", (long)domain);
1285 0 : return buf+strlen(buf);
1286 : }
1287 0 : d = domain_list[bit];
1288 0 : n = strlcpy(cp, d, eos-cp);
1289 0 : if (n >= buflen) {
1290 0 : tor_snprintf(buf, buflen, "<BUG:Truncating domain %lx>", (long)domain);
1291 0 : return buf+strlen(buf);
1292 : }
1293 0 : cp += n;
1294 0 : domain &= ~(1<<bit);
1295 :
1296 0 : if (domain == 0 || (eos-cp) < 2)
1297 0 : return cp;
1298 :
1299 0 : memcpy(cp, ",", 2); /*Nul-terminated ,"*/
1300 0 : cp++;
1301 : }
1302 : }
1303 :
1304 : /** Parse a log severity pattern in *<b>cfg_ptr</b>. Advance cfg_ptr after
1305 : * the end of the severityPattern. Set the value of <b>severity_out</b> to
1306 : * the parsed pattern. Return 0 on success, -1 on failure.
1307 : *
1308 : * The syntax for a SeverityPattern is:
1309 : * <pre>
1310 : * SeverityPattern = *(DomainSeverity SP)* DomainSeverity
1311 : * DomainSeverity = (DomainList SP)? SeverityRange
1312 : * SeverityRange = MinSeverity ("-" MaxSeverity )?
1313 : * DomainList = "[" (SP? DomainSpec SP? ",") SP? DomainSpec "]"
1314 : * DomainSpec = "*" | Domain | "~" Domain
1315 : * </pre>
1316 : * A missing MaxSeverity defaults to ERR. Severities and domains are
1317 : * case-insensitive. "~" indicates negation for a domain; negation happens
1318 : * last inside a DomainList. Only one SeverityRange without a DomainList is
1319 : * allowed per line.
1320 : */
1321 : int
1322 17 : parse_log_severity_config(const char **cfg_ptr,
1323 : log_severity_list_t *severity_out)
1324 : {
1325 17 : const char *cfg = *cfg_ptr;
1326 17 : int got_anything = 0;
1327 17 : int got_an_unqualified_range = 0;
1328 17 : memset(severity_out, 0, sizeof(*severity_out));
1329 :
1330 17 : cfg = eat_whitespace(cfg);
1331 37 : while (*cfg) {
1332 37 : const char *dash, *space;
1333 37 : char *sev_lo, *sev_hi;
1334 37 : int low, high, i;
1335 37 : log_domain_mask_t domains = LD_ALL_DOMAINS;
1336 :
1337 37 : if (*cfg == '[') {
1338 4 : int err = 0;
1339 4 : char *domains_str;
1340 4 : smartlist_t *domains_list;
1341 4 : log_domain_mask_t neg_domains = 0;
1342 4 : const char *closebracket = strchr(cfg, ']');
1343 4 : if (!closebracket)
1344 17 : return -1;
1345 4 : domains = 0;
1346 4 : domains_str = tor_strndup(cfg+1, closebracket-cfg-1);
1347 4 : domains_list = smartlist_new();
1348 4 : smartlist_split_string(domains_list, domains_str, ",", SPLIT_SKIP_SPACE,
1349 : -1);
1350 4 : tor_free(domains_str);
1351 10 : SMARTLIST_FOREACH_BEGIN(domains_list, const char *, domain) {
1352 6 : if (!strcmp(domain, "*")) {
1353 : domains = LD_ALL_DOMAINS;
1354 : } else {
1355 6 : log_domain_mask_t d;
1356 6 : int negate=0;
1357 6 : if (*domain == '~') {
1358 4 : negate = 1;
1359 4 : ++domain;
1360 : }
1361 6 : d = parse_log_domain(domain);
1362 6 : if (!d) {
1363 0 : log_warn(LD_CONFIG, "No such logging domain as %s", domain);
1364 0 : err = 1;
1365 : } else {
1366 6 : if (negate)
1367 4 : neg_domains |= d;
1368 : else
1369 2 : domains |= d;
1370 : }
1371 : }
1372 6 : } SMARTLIST_FOREACH_END(domain);
1373 10 : SMARTLIST_FOREACH(domains_list, char *, d, tor_free(d));
1374 4 : smartlist_free(domains_list);
1375 4 : if (err)
1376 : return -1;
1377 4 : if (domains == 0 && neg_domains)
1378 2 : domains = ~neg_domains;
1379 : else
1380 2 : domains &= ~neg_domains;
1381 4 : cfg = eat_whitespace(closebracket+1);
1382 : } else {
1383 33 : ++got_an_unqualified_range;
1384 : }
1385 65 : if (!strcasecmpstart(cfg, "file") ||
1386 56 : !strcasecmpstart(cfg, "stderr") ||
1387 50 : !strcasecmpstart(cfg, "stdout") ||
1388 22 : !strcasecmpstart(cfg, "syslog")) {
1389 15 : goto done;
1390 : }
1391 22 : if (got_an_unqualified_range > 1)
1392 : return -1;
1393 :
1394 21 : space = find_whitespace(cfg);
1395 21 : dash = strchr(cfg, '-');
1396 21 : if (dash && dash < space) {
1397 0 : sev_lo = tor_strndup(cfg, dash-cfg);
1398 0 : sev_hi = tor_strndup(dash+1, space-(dash+1));
1399 : } else {
1400 21 : sev_lo = tor_strndup(cfg, space-cfg);
1401 21 : sev_hi = tor_strdup("ERR");
1402 : }
1403 21 : low = parse_log_level(sev_lo);
1404 21 : high = parse_log_level(sev_hi);
1405 21 : tor_free(sev_lo);
1406 21 : tor_free(sev_hi);
1407 21 : if (low == -1)
1408 : return -1;
1409 20 : if (high == -1)
1410 : return -1;
1411 :
1412 97 : got_anything = 1;
1413 97 : for (i=low; i >= high; --i)
1414 77 : severity_out->masks[SEVERITY_MASK_IDX(i)] |= domains;
1415 :
1416 20 : cfg = eat_whitespace(space);
1417 : }
1418 :
1419 0 : done:
1420 15 : *cfg_ptr = cfg;
1421 15 : return got_anything ? 0 : -1;
1422 : }
1423 :
1424 : /** Return the least severe log level that any current log is interested in. */
1425 : int
1426 6185 : get_min_log_level(void)
1427 : {
1428 6185 : logfile_t *lf;
1429 6185 : int i;
1430 6185 : int min = LOG_ERR;
1431 12329 : for (lf = logfiles; lf; lf = lf->next) {
1432 29937 : for (i = LOG_DEBUG; i > min; --i)
1433 23793 : if (lf->severities->masks[SEVERITY_MASK_IDX(i)])
1434 5849 : min = i;
1435 : }
1436 6185 : return min;
1437 : }
1438 :
1439 : /** Switch all logs to output at most verbose level. */
1440 : void
1441 0 : switch_logs_debug(void)
1442 : {
1443 0 : logfile_t *lf;
1444 0 : int i;
1445 0 : LOCK_LOGS();
1446 0 : for (lf = logfiles; lf; lf=lf->next) {
1447 0 : for (i = LOG_DEBUG; i >= LOG_ERR; --i)
1448 0 : lf->severities->masks[SEVERITY_MASK_IDX(i)] = LD_ALL_DOMAINS;
1449 : }
1450 0 : log_global_min_severity_ = get_min_log_level();
1451 0 : UNLOCK_LOGS();
1452 0 : }
1453 :
1454 : /** Truncate all the log files. */
1455 : void
1456 0 : truncate_logs(void)
1457 : {
1458 0 : logfile_t *lf;
1459 0 : for (lf = logfiles; lf; lf = lf->next) {
1460 0 : if (lf->fd >= 0) {
1461 0 : tor_ftruncate(lf->fd);
1462 : }
1463 : }
1464 0 : }
|