log.c 25.6 KB
Newer Older
1
/* Copyright (c) 2001, Matej Pfajfar.
Roger Dingledine's avatar
Roger Dingledine committed
2
 * Copyright (c) 2001-2004, Roger Dingledine.
3
 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
Karsten Loesing's avatar
Karsten Loesing committed
4
 * Copyright (c) 2007-2009, The Tor Project, Inc. */
5
/* See LICENSE for licensing information */
Roger Dingledine's avatar
Roger Dingledine committed
6

Nick Mathewson's avatar
Nick Mathewson committed
7
8
9
/**
 * \file log.c
 * \brief Functions to send messages to log files or the console.
10
 **/
Nick Mathewson's avatar
Nick Mathewson committed
11

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
19
20
21
22
23
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#ifdef HAVE_TIME_H
#include <time.h>
#endif
24
25
26
27
28
29
30
31
32
33
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#include "compat.h"
34
#include "util.h"
35
#define LOG_PRIVATE
36
37
#include "log.h"
#include "container.h"
38

39
40
#define TRUNCATED_STR "[...truncated]"
#define TRUNCATED_STR_LEN 14
41

Nick Mathewson's avatar
Nick Mathewson committed
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. */
Nick Mathewson's avatar
Nick Mathewson committed
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. */
Nick Mathewson's avatar
Nick Mathewson committed
51
  log_callback callback; /**< If not NULL, send messages to this function. */
Nick Mathewson's avatar
Nick Mathewson committed
52
53
  log_severity_list_t *severities; /**< Which severity of messages should we
                                    * log for each log domain? */
54
55
} logfile_t;

56
57
static void log_free(logfile_t *victim);

58
/** Helper: map a log severity to descriptive string. */
59
60
61
static INLINE const char *
sev_to_string(int severity)
{
62
  switch (severity) {
63
64
    case LOG_DEBUG:   return "debug";
    case LOG_INFO:    return "info";
Roger Dingledine's avatar
Roger Dingledine committed
65
    case LOG_NOTICE:  return "notice";
Roger Dingledine's avatar
Roger Dingledine committed
66
    case LOG_WARN:    return "warn";
67
    case LOG_ERR:     return "err";
68
69
70
    default:          /* Call assert, not tor_assert, since tor_assert
                       * calls log on failure. */
                      assert(0); return "UNKNOWN";
71
72
73
  }
}

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)
77
78
79
80
81
82
83
{
  switch (severity) {
    case LOG_DEBUG:
    case LOG_INFO:
      /* All debugging messages occur in interesting places. */
      return 1;
    case LOG_NOTICE:
84
    case LOG_WARN:
85
86
87
88
    case LOG_ERR:
      /* We care about places where bugs occur. */
      return (domain == LD_BUG);
    default:
89
      /* Call assert, not tor_assert, since tor_assert calls log on failure. */
90
91
92
93
      assert(0); return 0;
  }
}

94
/** A mutex to guard changes to logfiles and logging. */
95
96
static tor_mutex_t log_mutex;
static int log_mutex_initialized = 0;
97

98
/** Linked list of logfile_t. */
99
static logfile_t *logfiles = NULL;
100
#ifdef HAVE_SYSLOG_H
101
102
/** The number of open syslog log handlers that we have.  When this reaches 0,
 * we can close our connection to the syslog facility. */
103
104
static int syslog_count = 0;
#endif
105

106
#define LOCK_LOGS() STMT_BEGIN                                          \
107
  tor_mutex_acquire(&log_mutex);                                        \
108
  STMT_END
109
#define UNLOCK_LOGS() STMT_BEGIN tor_mutex_release(&log_mutex); STMT_END
110

111
112
/** What's the lowest log level anybody cares about?  Checking this lets us
 * bail out early from log_debug if we aren't debugging.  */
113
114
int _log_global_min_severity = LOG_NOTICE;

Roger Dingledine's avatar
Roger Dingledine committed
115
static void delete_log(logfile_t *victim);
116
static void close_log(logfile_t *victim);
Roger Dingledine's avatar
Roger Dingledine committed
117

118
119
/** Name of the application: used to generate the message we write at the
 * start of each new log. */
120
121
static char *appname = NULL;

122
123
124
125
126
/** Set the "application name" for the logs to <b>name</b>: we'll use this
 * name in the message we write when starting up, and at the start of each new
 * log.
 *
 * Tor uses this string to write the version number to the log file. */
127
128
129
130
131
132
133
void
log_set_application_name(const char *name)
{
  tor_free(appname);
  appname = name ? tor_strdup(name) : NULL;
}

134
135
136
/** Helper: Write the standard prefix for log lines to a
 * <b>buf_len</b> character buffer in <b>buf</b>.
 */
Roger Dingledine's avatar
Roger Dingledine committed
137
static INLINE size_t
138
_log_prefix(char *buf, size_t buf_len, int severity)
Roger Dingledine's avatar
Roger Dingledine committed
139
{
140
  time_t t;
141
  struct timeval now;
142
  struct tm tm;
143
  size_t n;
144
  int r;
145

146
  tor_gettimeofday(&now);
147
  t = (time_t)now.tv_sec;
148

149
  n = strftime(buf, buf_len, "%b %d %H:%M:%S", tor_localtime_r(&t, &tm));
150
151
  r = tor_snprintf(buf+n, buf_len-n, ".%.3i [%s] ",
                   (int)now.tv_usec / 1000, sev_to_string(severity));
152
153
154
155
  if (r<0)
    return buf_len-1;
  else
    return n+r;
156
157
158
}

/** If lf refers to an actual file that we have just opened, and the file
159
160
161
162
 * contains no data, log an "opening new logfile" message at the top.
 *
 * Return -1 if the log is broken and needs to be deleted, else return 0.
 */
163
164
static int
log_tor_version(logfile_t *lf, int reset)
165
166
167
{
  char buf[256];
  size_t n;
168
  int is_new;
169
170
171

  if (!lf->needs_close)
    /* If it doesn't get closed, it isn't really a file. */
172
    return 0;
173
174
  if (lf->is_temporary)
    /* If it's temporary, it isn't really a file. */
175
    return 0;
176
177
178

  is_new = lf->fd >= 0 && tor_fd_getpos(lf->fd) == 0;

179
180
181
  if (reset && !is_new)
    /* We are resetting, but we aren't at the start of the file; no
     * need to log again. */
182
    return 0;
183
  n = _log_prefix(buf, sizeof(buf), LOG_NOTICE);
184
185
186
187
188
189
190
  if (appname) {
    tor_snprintf(buf+n, sizeof(buf)-n,
                 "%s opening %slog file.\n", appname, is_new?"new ":"");
  } else {
    tor_snprintf(buf+n, sizeof(buf)-n,
                 "Tor %s opening %slog file.\n", VERSION, is_new?"new ":"");
  }
191
  if (write_all(lf->fd, buf, strlen(buf), 0) < 0) /* error */
192
193
    return -1; /* failed */
  return 0;
194
195
196
197
}

/** Helper: Format a log message into a fixed-sized buffer. (This is
 * factored out of <b>logv</b> so that we never format a message more
198
199
 * than once.)  Return a pointer to the first character of the message
 * portion of the formatted string.
200
 */
201
202
static INLINE char *
format_msg(char *buf, size_t buf_len,
203
           log_domain_mask_t domain, int severity, const char *funcname,
204
           const char *format, va_list ap, size_t *msg_len_out)
205
206
{
  size_t n;
207
  int r;
208
  char *end_of_prefix;
209

210
  assert(buf_len >= 2); /* prevent integer underflow */
211
212
  buf_len -= 2; /* subtract 2 characters so we have room for \n\0 */

213
  n = _log_prefix(buf, buf_len, severity);
214
  end_of_prefix = buf+n;
215

216
  if (funcname && should_log_function_name(domain, severity)) {
217
218
219
220
221
    r = tor_snprintf(buf+n, buf_len-n, "%s(): ", funcname);
    if (r<0)
      n = strlen(buf);
    else
      n += r;
222
  }
223

224
225
226
227
228
  if (domain == LD_BUG && buf_len-n > 6) {
    memcpy(buf+n, "Bug: ", 6);
    n += 5;
  }

229
  r = tor_vsnprintf(buf+n,buf_len-n,format,ap);
230
  if (r < 0) {
231
232
233
    /* The message was too long; overwrite the end of the buffer with
     * "[...truncated]" */
    if (buf_len >= TRUNCATED_STR_LEN) {
234
      size_t offset = buf_len-TRUNCATED_STR_LEN;
235
236
237
      /* We have an extra 2 characters after buf_len to hold the \n\0,
       * so it's safe to add 1 to the size here. */
      strlcpy(buf+offset, TRUNCATED_STR, buf_len-offset+1);
238
239
240
241
    }
    /* Set 'n' to the end of the buffer, where we'll be writing \n\0.
     * Since we already subtracted 2 from buf_len, this is safe.*/
    n = buf_len;
242
243
  } else {
    n += r;
244
  }
245
246
  buf[n]='\n';
  buf[n+1]='\0';
247
  *msg_len_out = n+1;
248
  return end_of_prefix;
249
250
}

Nick Mathewson's avatar
Nick Mathewson committed
251
252
/** Helper: sends a message to the appropriate logfiles, at loglevel
 * <b>severity</b>.  If provided, <b>funcname</b> is prepended to the
253
 * message.  The actual message is derived as from tor_snprintf(format,ap).
Nick Mathewson's avatar
Nick Mathewson committed
254
 */
255
static void
256
257
logv(int severity, log_domain_mask_t domain, const char *funcname,
     const char *format, va_list ap)
258
{
259
  char buf[10024];
260
  size_t msg_len = 0;
261
262
  int formatted = 0;
  logfile_t *lf;
263
  char *end_of_prefix=NULL;
264

265
  /* Call assert, not tor_assert, since tor_assert calls log on failure. */
266
  assert(format);
267
268
269
  /* check that severity is sane.  Overrunning the masks array leads to
   * interesting and hard to diagnose effects */
  assert(severity >= LOG_ERR && severity <= LOG_DEBUG);
270
  LOCK_LOGS();
271
  lf = logfiles;
272
  while (lf) {
273
    if (! (lf->severities->masks[SEVERITY_MASK_IDX(severity)] & domain)) {
274
      lf = lf->next;
275
      continue;
276
    }
277
    if (! (lf->fd >= 0 || lf->is_syslog || lf->callback)) {
278
      lf = lf->next;
279
      continue;
280
    }
281
282
283
284
    if (lf->seems_dead) {
      lf = lf->next;
      continue;
    }
285

286
    if (!formatted) {
287
      end_of_prefix =
288
289
        format_msg(buf, sizeof(buf), domain, severity, funcname, format, ap,
                   &msg_len);
290
291
      formatted = 1;
    }
292
293
    if (lf->is_syslog) {
#ifdef HAVE_SYSLOG_H
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
      char *m = end_of_prefix;
#ifdef MAXLINE
      /* Some syslog implementations have limits on the length of what you can
       * pass them, and some very old ones do not detect overflow so well.
       * Regrettably, they call their maximum line length MAXLINE. */
#if MAXLINE < 64
#warn "MAXLINE is a very low number; it might not be from syslog.h after all"
#endif
      if (msg_len >= MAXLINE)
        m = tor_strndup(end_of_prefix, MAXLINE-1);
#endif
      syslog(severity, "%s", m);
#ifdef MAXLINE
      if (m != end_of_prefix) {
        tor_free(m);
      }
#endif
311
312
313
#endif
      lf = lf->next;
      continue;
314
    } else if (lf->callback) {
315
      lf->callback(severity, domain, end_of_prefix);
316
317
      lf = lf->next;
      continue;
318
    }
319
    if (write_all(lf->fd, buf, msg_len, 0) < 0) { /* error */
320
321
322
      /* don't log the error! mark this log entry to be blown away, and
       * continue. */
      lf->seems_dead = 1;
Roger Dingledine's avatar
Roger Dingledine committed
323
    }
324
    lf = lf->next;
325
  }
326
  UNLOCK_LOGS();
327
}
328

Nick Mathewson's avatar
Nick Mathewson committed
329
/** Output a message to the log. */
330
void
331
_log(int severity, log_domain_mask_t domain, const char *format, ...)
332
333
{
  va_list ap;
334
335
  if (severity > _log_global_min_severity)
    return;
336
  va_start(ap,format);
337
  logv(severity, domain, NULL, format, ap);
338
  va_end(ap);
Roger Dingledine's avatar
Roger Dingledine committed
339
}
340

341
/** Output a message to the log, prefixed with a function name <b>fn</b>. */
342
#ifdef __GNUC__
343
void
344
345
_log_fn(int severity, log_domain_mask_t domain, const char *fn,
        const char *format, ...)
346
347
{
  va_list ap;
348
349
  if (severity > _log_global_min_severity)
    return;
350
  va_start(ap,format);
351
  logv(severity, domain, fn, format, ap);
352
353
  va_end(ap);
}
354
355
#else
const char *_log_fn_function_name=NULL;
356
void
357
_log_fn(int severity, log_domain_mask_t domain, const char *format, ...)
358
359
{
  va_list ap;
360
361
  if (severity > _log_global_min_severity)
    return;
362
  va_start(ap,format);
363
364
365
366
367
  logv(severity, domain, _log_fn_function_name, format, ap);
  va_end(ap);
  _log_fn_function_name = NULL;
}
void
368
_log_debug(log_domain_mask_t domain, const char *format, ...)
369
370
{
  va_list ap;
371
372
373
  /* For GCC we do this check in the macro. */
  if (PREDICT_LIKELY(LOG_DEBUG > _log_global_min_severity))
    return;
374
  va_start(ap,format);
375
  logv(LOG_DEBUG, domain, _log_fn_function_name, format, ap);
376
377
378
379
  va_end(ap);
  _log_fn_function_name = NULL;
}
void
380
_log_info(log_domain_mask_t domain, const char *format, ...)
381
382
{
  va_list ap;
383
384
  if (LOG_INFO > _log_global_min_severity)
    return;
385
  va_start(ap,format);
386
  logv(LOG_INFO, domain, _log_fn_function_name, format, ap);
387
388
389
390
  va_end(ap);
  _log_fn_function_name = NULL;
}
void
391
_log_notice(log_domain_mask_t domain, const char *format, ...)
392
393
{
  va_list ap;
394
395
  if (LOG_NOTICE > _log_global_min_severity)
    return;
396
  va_start(ap,format);
397
  logv(LOG_NOTICE, domain, _log_fn_function_name, format, ap);
398
399
400
401
  va_end(ap);
  _log_fn_function_name = NULL;
}
void
402
_log_warn(log_domain_mask_t domain, const char *format, ...)
403
404
{
  va_list ap;
405
406
  if (LOG_WARN > _log_global_min_severity)
    return;
407
  va_start(ap,format);
408
  logv(LOG_WARN, domain, _log_fn_function_name, format, ap);
409
410
411
412
  va_end(ap);
  _log_fn_function_name = NULL;
}
void
413
_log_err(log_domain_mask_t domain, const char *format, ...)
414
415
{
  va_list ap;
416
417
  if (LOG_ERR > _log_global_min_severity)
    return;
418
  va_start(ap,format);
419
  logv(LOG_ERR, domain, _log_fn_function_name, format, ap);
420
421
422
423
  va_end(ap);
  _log_fn_function_name = NULL;
}
#endif
424

Nick Mathewson's avatar
Nick Mathewson committed
425
/** Free all storage held by <b>victim</b>. */
426
427
428
static void
log_free(logfile_t *victim)
{
429
430
  if (!victim)
    return;
431
432
433
434
435
  tor_free(victim->severities);
  tor_free(victim->filename);
  tor_free(victim);
}

436
/** Close all open log files, and free other static memory. */
437
void
438
logs_free_all(void)
439
{
440
  logfile_t *victim, *next;
441
  LOCK_LOGS();
442
443
  next = logfiles;
  logfiles = NULL;
444
  UNLOCK_LOGS();
445
446
447
  while (next) {
    victim = next;
    next = next->next;
448
    close_log(victim);
449
    log_free(victim);
450
  }
451
  tor_free(appname);
452
453
454

  /* We _could_ destroy the log mutex here, but that would screw up any logs
   * that happened between here and the end of execution. */
455
}
456

Roger Dingledine's avatar
Roger Dingledine committed
457
/** Remove and free the log entry <b>victim</b> from the linked-list
458
459
460
461
462
463
 * logfiles (it is probably present, but it might not be due to thread
 * racing issues). After this function is called, the caller shouldn't
 * refer to <b>victim</b> anymore.
 *
 * Long-term, we need to do something about races in the log subsystem
 * in general. See bug 222 for more details.
Roger Dingledine's avatar
Roger Dingledine committed
464
 */
465
466
467
static void
delete_log(logfile_t *victim)
{
Roger Dingledine's avatar
Roger Dingledine committed
468
  logfile_t *tmpl;
469
  if (victim == logfiles)
Roger Dingledine's avatar
Roger Dingledine committed
470
471
    logfiles = victim->next;
  else {
472
    for (tmpl = logfiles; tmpl && tmpl->next != victim; tmpl=tmpl->next) ;
473
474
475
476
//    tor_assert(tmpl);
//    tor_assert(tmpl->next == victim);
    if (!tmpl)
      return;
Roger Dingledine's avatar
Roger Dingledine committed
477
478
    tmpl->next = victim->next;
  }
479
  log_free(victim);
Roger Dingledine's avatar
Roger Dingledine committed
480
481
}

482
483
/** Helper: release system resources (but not memory) held by a single
 * logfile_t. */
484
485
static void
close_log(logfile_t *victim)
486
{
487
488
489
  if (victim->needs_close && victim->fd >= 0) {
    close(victim->fd);
    victim->fd = -1;
490
491
  } else if (victim->is_syslog) {
#ifdef HAVE_SYSLOG_H
492
    if (--syslog_count == 0) {
493
494
      /* There are no other syslogs; close the logging facility. */
      closelog();
495
    }
496
497
498
499
#endif
  }
}

500
501
502
503
504
505
/** Adjust a log severity configuration in <b>severity_out</b> to contain
 * every domain between <b>loglevelMin</b> and <b>loglevelMax</b>, inclusive.
 */
void
set_log_severity_config(int loglevelMin, int loglevelMax,
                        log_severity_list_t *severity_out)
506
507
{
  int i;
508
509
510
511
  tor_assert(loglevelMin >= loglevelMax);
  tor_assert(loglevelMin >= LOG_ERR && loglevelMin <= LOG_DEBUG);
  tor_assert(loglevelMax >= LOG_ERR && loglevelMax <= LOG_DEBUG);
  memset(severity_out, 0, sizeof(log_severity_list_t));
512
  for (i = loglevelMin; i >= loglevelMax; --i) {
513
    severity_out->masks[SEVERITY_MASK_IDX(i)] = ~0u;
514
515
516
517
  }
}

/** Add a log handler named <b>name</b> to send all messages in <b>severity</b>
518
 * to <b>fd</b>. Copies <b>severity</b>. Helper: does no locking. */
519
static void
520
add_stream_log_impl(const log_severity_list_t *severity,
521
                    const char *name, int fd)
522
523
{
  logfile_t *lf;
524
  lf = tor_malloc_zero(sizeof(logfile_t));
525
  lf->fd = fd;
526
  lf->filename = tor_strdup(name);
527
  lf->severities = tor_memdup(severity, sizeof(log_severity_list_t));
528
  lf->next = logfiles;
529

530
  logfiles = lf;
531
  _log_global_min_severity = get_min_log_level();
532
533
}

534
/** Add a log handler named <b>name</b> to send all messages in <b>severity</b>
535
 * to <b>fd</b>. Steals a reference to <b>severity</b>; the caller must
536
 * not use it after calling this function. */
537
void
538
add_stream_log(const log_severity_list_t *severity,
539
               const char *name, int fd)
540
541
{
  LOCK_LOGS();
542
  add_stream_log_impl(severity, name, fd);
543
544
545
546
547
548
549
  UNLOCK_LOGS();
}

/** Initialize the global logging facility */
void
init_logging(void)
{
550
551
552
553
  if (!log_mutex_initialized) {
    tor_mutex_init(&log_mutex);
    log_mutex_initialized = 1;
  }
554
555
}

556
557
558
/** Add a log handler to receive messages during startup (before the real
 * logs are initialized).
 */
559
void
Peter Palfrader's avatar
Peter Palfrader committed
560
add_temp_log(int min_severity)
561
{
562
  log_severity_list_t *s = tor_malloc_zero(sizeof(log_severity_list_t));
Peter Palfrader's avatar
Peter Palfrader committed
563
  set_log_severity_config(min_severity, LOG_ERR, s);
564
  LOCK_LOGS();
565
  add_stream_log_impl(s, "<temp>", fileno(stdout));
566
  tor_free(s);
567
  logfiles->is_temporary = 1;
568
  UNLOCK_LOGS();
569
570
}

571
/**
572
573
 * Add a log handler to send messages in <b>severity</b>
 * to the function <b>cb</b>.
574
 */
575
int
576
add_callback_log(const log_severity_list_t *severity, log_callback cb)
577
578
579
{
  logfile_t *lf;
  lf = tor_malloc_zero(sizeof(logfile_t));
580
  lf->fd = -1;
581
  lf->severities = tor_memdup(severity, sizeof(log_severity_list_t));
Nick Mathewson's avatar
Nick Mathewson committed
582
  lf->filename = tor_strdup("<callback>");
583
584
  lf->callback = cb;
  lf->next = logfiles;
585

586
587
  LOCK_LOGS();
  logfiles = lf;
588
  _log_global_min_severity = get_min_log_level();
589
  UNLOCK_LOGS();
590
591
592
  return 0;
}

593
594
/** Adjust the configured severity of any logs whose callback function is
 * <b>cb</b>. */
595
596
597
void
change_callback_log_severity(int loglevelMin, int loglevelMax,
                             log_callback cb)
598
599
{
  logfile_t *lf;
600
601
  log_severity_list_t severities;
  set_log_severity_config(loglevelMin, loglevelMax, &severities);
602
  LOCK_LOGS();
603
604
  for (lf = logfiles; lf; lf = lf->next) {
    if (lf->callback == cb) {
605
      memcpy(lf->severities, &severities, sizeof(severities));
606
607
    }
  }
608
  _log_global_min_severity = get_min_log_level();
609
  UNLOCK_LOGS();
610
611
}

612
613
/** Close any log handlers added by add_temp_log() or marked by
 * mark_logs_temp(). */
614
615
void
close_temp_logs(void)
616
{
617
  logfile_t *lf, **p;
618
619

  LOCK_LOGS();
620
621
622
  for (p = &logfiles; *p; ) {
    if ((*p)->is_temporary) {
      lf = *p;
623
      /* we use *p here to handle the edge case of the head of the list */
624
625
      *p = (*p)->next;
      close_log(lf);
626
      log_free(lf);
627
    } else {
628
      p = &((*p)->next);
629
630
    }
  }
631
632

  _log_global_min_severity = get_min_log_level();
633
  UNLOCK_LOGS();
634
635
}

636
637
638
639
640
641
/** Make all currently temporary logs (set to be closed by close_temp_logs)
 * live again, and close all non-temporary logs. */
void
rollback_log_changes(void)
{
  logfile_t *lf;
642
  LOCK_LOGS();
643
644
  for (lf = logfiles; lf; lf = lf->next)
    lf->is_temporary = ! lf->is_temporary;
645
  UNLOCK_LOGS();
646
647
648
  close_temp_logs();
}

649
/** Configure all log handles to be closed by close_temp_logs(). */
650
651
void
mark_logs_temp(void)
652
653
{
  logfile_t *lf;
654
  LOCK_LOGS();
655
656
  for (lf = logfiles; lf; lf = lf->next)
    lf->is_temporary = 1;
657
  UNLOCK_LOGS();
658
659
}

Nick Mathewson's avatar
Nick Mathewson committed
660
/**
661
662
 * Add a log handler to send messages to <b>filename</b>. If opening the
 * logfile fails, -1 is returned and errno is set appropriately (by open(2)).
663
 */
664
int
665
add_file_log(const log_severity_list_t *severity, const char *filename)
666
{
667
  int fd;
668
  logfile_t *lf;
669
670
671
672
673
674
675

  fd = open(filename, O_WRONLY|O_CREAT|O_APPEND, 0644);
  if (fd<0)
    return -1;
  if (tor_fd_seekend(fd)<0)
    return -1;

676
  LOCK_LOGS();
677
  add_stream_log_impl(severity, filename, fd);
678
  logfiles->needs_close = 1;
679
  lf = logfiles;
680
  _log_global_min_severity = get_min_log_level();
681
682
683
684
685
686
687
688
  UNLOCK_LOGS();

  if (log_tor_version(lf, 0) < 0) {
    LOCK_LOGS();
    delete_log(lf);
    UNLOCK_LOGS();
  }

689
  return 0;
690
}
691

692
693
694
695
#ifdef HAVE_SYSLOG_H
/**
 * Add a log handler to send messages to they system log facility.
 */
696
int
697
add_syslog_log(const log_severity_list_t *severity)
698
699
700
{
  logfile_t *lf;
  if (syslog_count++ == 0)
Roger Dingledine's avatar
Roger Dingledine committed
701
    /* This is the first syslog. */
702
    openlog("Tor", LOG_PID | LOG_NDELAY, LOGFACILITY);
703
704

  lf = tor_malloc_zero(sizeof(logfile_t));
705
  lf->fd = -1;
706
  lf->severities = tor_memdup(severity, sizeof(log_severity_list_t));
707
  lf->filename = tor_strdup("<syslog>");
708

709
  lf->is_syslog = 1;
710
711

  LOCK_LOGS();
712
713
  lf->next = logfiles;
  logfiles = lf;
714
  _log_global_min_severity = get_min_log_level();
715
  UNLOCK_LOGS();
716
717
718
719
  return 0;
}
#endif

720
721
/** If <b>level</b> is a valid log severity, return the corresponding
 * numeric value.  Otherwise, return -1. */
722
723
724
int
parse_log_level(const char *level)
{
725
726
  if (!strcasecmp(level, "err"))
    return LOG_ERR;
727
728
729
  if (!strcasecmp(level, "warn"))
    return LOG_WARN;
  if (!strcasecmp(level, "notice"))
730
    return LOG_NOTICE;
731
  if (!strcasecmp(level, "info"))
732
    return LOG_INFO;
733
  if (!strcasecmp(level, "debug"))
734
    return LOG_DEBUG;
735
  return -1;
736
737
}

738
/** Return the string equivalent of a given log level. */
739
740
const char *
log_level_to_string(int level)
741
742
743
744
{
  return sev_to_string(level);
}

Nick Mathewson's avatar
Nick Mathewson committed
745
746
/** NULL-terminated array of names for log domains such that domain_list[dom]
 * is a description of <b>dom</b>. */
747
748
749
static const char *domain_list[] = {
  "GENERAL", "CRYPTO", "NET", "CONFIG", "FS", "PROTOCOL", "MM",
  "HTTP", "APP", "CONTROL", "CIRC", "REND", "BUG", "DIR", "DIRSERV",
750
  "OR", "EDGE", "ACCT", "HIST", "HANDSHAKE", NULL
751
752
};

753
754
/** Return a bitmask for the log domain for which <b>domain</b> is the name,
 * or 0 if there is no such name. */
755
756
757
758
759
760
761
762
763
764
765
static log_domain_mask_t
parse_log_domain(const char *domain)
{
  int i;
  for (i=0; domain_list[i]; ++i) {
    if (!strcasecmp(domain, domain_list[i]))
      return (1u<<i);
  }
  return 0;
}
#if 0
766
767
/** Translate a bitmask of log domains to a string, or NULL if the bitmask
 * is undecodable. */
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
static const char *
domain_to_string(log_domain_mask_t domain)
{
  int bit = tor_log2(domain);
  if ((bit == 0 && domain == 0) || bit >= N_LOGGING_DOMAINS)
    return NULL;
  return domain_list[bit];
}
#endif

/** Parse a log severity pattern in *<b>cfg_ptr</b>.  Advance cfg_ptr after
 * the end of the severityPattern.  Set the value of <b>severity_out</b> to
 * the parsed pattern.  Return 0 on success, -1 on failure.
 *
 * The syntax for a SeverityPattern is:
 * <pre>
 *   SeverityPattern = *(DomainSeverity SP)* DomainSeverity
 *   DomainSeverity = (DomainList SP)? SeverityRange
 *   SeverityRange = MinSeverity ("-" MaxSeverity )?
 *   DomainList = "[" (SP? DomainSpec SP? ",") SP? DomainSpec "]"
 *   DomainSpec = "*" | Domain | "~" Domain
 * </pre>
 * A missing MaxSeverity defaults to ERR.  Severities and domains are
 * case-insensitive.  "~" indicates negation for a domain; negation happens
 * last inside a DomainList.  Only one SeverityRange without a DomainList is
 * allowed per line.
 */
int
parse_log_severity_config(const char **cfg_ptr,
                          log_severity_list_t *severity_out)
{
  const char *cfg = *cfg_ptr;
  int got_anything = 0;
  int got_an_unqualified_range = 0;
  memset(severity_out, 0, sizeof(*severity_out));

  cfg = eat_whitespace(cfg);
  while (*cfg) {
    const char *dash, *space;
    char *sev_lo, *sev_hi;
    int low, high, i;
    log_domain_mask_t domains = ~0u;

    if (*cfg == '[') {
      int err = 0;
      char *domains_str;
      smartlist_t *domains_list;
      log_domain_mask_t neg_domains = 0;
      const char *closebracket = strchr(cfg, ']');
      if (!closebracket)
        return -1;
      domains = 0;
      domains_str = tor_strndup(cfg+1, closebracket-cfg-1);
      domains_list = smartlist_create();
      smartlist_split_string(domains_list, domains_str, ",", SPLIT_SKIP_SPACE,
                             -1);
      tor_free(domains_str);
      SMARTLIST_FOREACH(domains_list, const char *, domain,
          {
            if (!strcmp(domain, "*")) {
              domains = ~0u;
            } else {
              int d;
              int negate=0;
              if (*domain == '~') {
                negate = 1;
                ++domain;
              }
              d = parse_log_domain(domain);
              if (!d) {
838
                log_warn(LD_CONFIG, "No such logging domain as %s", domain);
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
                err = 1;
              } else {
                if (negate)
                  neg_domains |= d;
                else
                  domains |= d;
              }
            }
          });
      SMARTLIST_FOREACH(domains_list, char *, d, tor_free(d));
      smartlist_free(domains_list);
      if (err)
        return -1;
      domains &= ~neg_domains;
      cfg = eat_whitespace(closebracket+1);
    } else {
      ++got_an_unqualified_range;
    }
    if (!strcasecmpstart(cfg, "file") ||
        !strcasecmpstart(cfg, "stderr") ||
        !strcasecmpstart(cfg, "stdout") ||
        !strcasecmpstart(cfg, "syslog")) {
      goto done;
    }
    if (got_an_unqualified_range > 1)
      return -1;

    space = strchr(cfg, ' ');
    dash = strchr(cfg, '-');
    if (!space)
      space = strchr(cfg, '\0');
    if (dash && dash < space) {
      sev_lo = tor_strndup(cfg, dash-cfg);
      sev_hi = tor_strndup(dash+1, space-(dash+1));
    } else {
      sev_lo = tor_strndup(cfg, space-cfg);
      sev_hi = tor_strdup("ERR");
    }
877
878
879
880
881
    low = parse_log_level(sev_lo);
    high = parse_log_level(sev_hi);
    tor_free(sev_lo);
    tor_free(sev_hi);
    if (low == -1)
882
      return -1;
883
    if (high == -1)
884
885
886
887
888
889
890
891
892
893
894
895
896
897
      return -1;

    got_anything = 1;
    for (i=low; i >= high; --i)
      severity_out->masks[SEVERITY_MASK_IDX(i)] |= domains;

    cfg = eat_whitespace(space);
  }

 done:
  *cfg_ptr = cfg;
  return got_anything ? 0 : -1;
}

898
/** Return the least severe log level that any current log is interested in. */
899
900
int
get_min_log_level(void)
901
902
{
  logfile_t *lf;
903
  int i;
904
905
  int min = LOG_ERR;
  for (lf = logfiles; lf; lf = lf->next) {
906
907
908
    for (i = LOG_DEBUG; i > min; --i)
      if (lf->severities->masks[SEVERITY_MASK_IDX(i)])
        min = i;
909
910
911
912
  }
  return min;
}

913
/** Switch all logs to output at most verbose level. */
914
915
void
switch_logs_debug(void)
916
917
{
  logfile_t *lf;
918
  int i;
919
  LOCK_LOGS();
920
  for (lf = logfiles; lf; lf=lf->next) {
921
    for (i = LOG_DEBUG; i >= LOG_ERR; --i)
922
      lf->severities->masks[SEVERITY_MASK_IDX(i)] = ~0u;
923
  }
924
  _log_global_min_severity = get_min_log_level();
925
  UNLOCK_LOGS();
926
927
}

928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
#if 0
static void
dump_log_info(logfile_t *lf)
{
  const char *tp;

  if (lf->filename) {
    printf("=== log into \"%s\" (%s-%s) (%stemporary)\n", lf->filename,
           sev_to_string(lf->min_loglevel),
           sev_to_string(lf->max_loglevel),
           lf->is_temporary?"":"not ");
  } else if (lf->is_syslog) {
    printf("=== syslog (%s-%s) (%stemporary)\n",
           sev_to_string(lf->min_loglevel),
           sev_to_string(lf->max_loglevel),
           lf->is_temporary?"":"not ");
  } else {
    printf("=== log (%s-%s) (%stemporary)\