aboutsummaryrefslogtreecommitdiff
path: root/src/common/log.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/log.c')
-rw-r--r--src/common/log.c130
1 files changed, 109 insertions, 21 deletions
diff --git a/src/common/log.c b/src/common/log.c
index 4db1c9f0d0..9f4a8b2bc2 100644
--- a/src/common/log.c
+++ b/src/common/log.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2016, The Tor Project, Inc. */
+ * Copyright (c) 2007-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -35,6 +35,9 @@
#define LOG_PRIVATE
#include "torlog.h"
#include "container.h"
+#ifdef HAVE_ANDROID_LOG_H
+#include <android/log.h>
+#endif // HAVE_ANDROID_LOG_H.
/** Given a severity, yields an index into log_severity_list_t.masks to use
* for that severity. */
@@ -58,12 +61,16 @@ typedef struct logfile_t {
int needs_close; /**< Boolean: true if the stream gets closed on shutdown. */
int is_temporary; /**< Boolean: close after initializing logging subsystem.*/
int is_syslog; /**< Boolean: send messages to syslog. */
+ int is_android; /**< Boolean: send messages to Android's log subsystem. */
+ char *android_tag; /**< Identity Tag used in Android's log subsystem. */
log_callback callback; /**< If not NULL, send messages to this function. */
log_severity_list_t *severities; /**< Which severity of messages should we
* log for each log domain? */
} logfile_t;
-static void log_free(logfile_t *victim);
+static void log_free_(logfile_t *victim);
+#define log_free(lg) \
+ FREE_AND_NULL(logfile_t, log_free_, (lg))
/** Helper: map a log severity to descriptive string. */
static inline const char *
@@ -101,6 +108,33 @@ should_log_function_name(log_domain_mask_t domain, int severity)
}
}
+#ifdef HAVE_ANDROID_LOG_H
+/** Helper function to convert Tor's log severity into the matching
+ * Android log priority.
+ */
+static int
+severity_to_android_log_priority(int severity)
+{
+ switch (severity) {
+ case LOG_DEBUG:
+ return ANDROID_LOG_VERBOSE;
+ case LOG_INFO:
+ return ANDROID_LOG_DEBUG;
+ case LOG_NOTICE:
+ return ANDROID_LOG_INFO;
+ case LOG_WARN:
+ return ANDROID_LOG_WARN;
+ case LOG_ERR:
+ return ANDROID_LOG_ERROR;
+ default:
+ // LCOV_EXCL_START
+ raw_assert(0);
+ return 0;
+ // LCOV_EXCL_STOP
+ }
+}
+#endif // HAVE_ANDROID_LOG_H.
+
/** A mutex to guard changes to logfiles and logging. */
static tor_mutex_t log_mutex;
/** True iff we have initialized log_mutex */
@@ -385,9 +419,12 @@ pending_log_message_new(int severity, log_domain_mask_t domain,
return m;
}
+#define pending_log_message_free(msg) \
+ FREE_AND_NULL(pending_log_message_t, pending_log_message_free_, (msg))
+
/** Release all storage held by <b>msg</b>. */
static void
-pending_log_message_free(pending_log_message_t *msg)
+pending_log_message_free_(pending_log_message_t *msg)
{
if (!msg)
return;
@@ -396,6 +433,16 @@ pending_log_message_free(pending_log_message_t *msg)
tor_free(msg);
}
+/** Helper function: returns true iff the log file, given in <b>lf</b>, is
+ * handled externally via the system log API, the Android logging API, or is an
+ * external callback function. */
+static inline int
+logfile_is_external(const logfile_t *lf)
+{
+ raw_assert(lf);
+ return lf->is_syslog || lf->is_android || lf->callback;
+}
+
/** Return true iff <b>lf</b> would like to receive a message with the
* specified <b>severity</b> in the specified <b>domain</b>.
*/
@@ -406,7 +453,7 @@ logfile_wants_message(const logfile_t *lf, int severity,
if (! (lf->severities->masks[SEVERITY_MASK_IDX(severity)] & domain)) {
return 0;
}
- if (! (lf->fd >= 0 || lf->is_syslog || lf->callback)) {
+ if (! (lf->fd >= 0 || logfile_is_external(lf))) {
return 0;
}
if (lf->seems_dead) {
@@ -444,11 +491,16 @@ logfile_deliver(logfile_t *lf, const char *buf, size_t msg_len,
if (m != msg_after_prefix) {
tor_free(m);
}
-#else
+#else /* !(defined(MAXLINE)) */
/* We have syslog but not MAXLINE. That's promising! */
syslog(severity, "%s", msg_after_prefix);
-#endif
-#endif
+#endif /* defined(MAXLINE) */
+#endif /* defined(HAVE_SYSLOG_H) */
+ } else if (lf->is_android) {
+#ifdef HAVE_ANDROID_LOG_H
+ int priority = severity_to_android_log_priority(severity);
+ __android_log_write(priority, lf->android_tag, msg_after_prefix);
+#endif // HAVE_ANDROID_LOG_H.
} else if (lf->callback) {
if (domain & LD_NOCB) {
if (!*callbacks_deferred && pending_cb_messages) {
@@ -641,8 +693,8 @@ tor_log_update_sigsafe_err_fds(void)
/* Don't try callback to the control port, or syslogs: We can't
* do them from a signal handler. Don't try stdout: we always do stderr.
*/
- if (lf->is_temporary || lf->is_syslog ||
- lf->callback || lf->seems_dead || lf->fd < 0)
+ if (lf->is_temporary || logfile_is_external(lf)
+ || lf->seems_dead || lf->fd < 0)
continue;
if (lf->severities->masks[SEVERITY_MASK_IDX(LOG_ERR)] &
(LD_BUG|LD_GENERAL)) {
@@ -678,11 +730,11 @@ tor_log_get_logfile_names(smartlist_t *out)
LOCK_LOGS();
for (lf = logfiles; lf; lf = lf->next) {
- if (lf->is_temporary || lf->is_syslog || lf->callback)
+ if (lf->is_temporary || logfile_is_external(lf))
continue;
if (lf->filename == NULL)
continue;
- smartlist_add(out, tor_strdup(lf->filename));
+ smartlist_add_strdup(out, lf->filename);
}
UNLOCK_LOGS();
@@ -721,12 +773,13 @@ log_fn_ratelim_(ratelim_t *ratelim, int severity, log_domain_mask_t domain,
/** Free all storage held by <b>victim</b>. */
static void
-log_free(logfile_t *victim)
+log_free_(logfile_t *victim)
{
if (!victim)
return;
tor_free(victim->severities);
tor_free(victim->filename);
+ tor_free(victim->android_tag);
tor_free(victim);
}
@@ -807,7 +860,7 @@ close_log(logfile_t *victim)
/* There are no other syslogs; close the logging facility. */
closelog();
}
-#endif
+#endif /* defined(HAVE_SYSLOG_H) */
}
}
@@ -1086,7 +1139,7 @@ add_file_log(const log_severity_list_t *severity, const char *filename,
int open_flags = O_WRONLY|O_CREAT;
open_flags |= truncate_log ? O_TRUNC : O_APPEND;
- fd = tor_open_cloexec(filename, open_flags, 0644);
+ fd = tor_open_cloexec(filename, open_flags, 0640);
if (fd<0)
return -1;
if (tor_fd_seekend(fd)<0) {
@@ -1144,7 +1197,40 @@ add_syslog_log(const log_severity_list_t *severity,
UNLOCK_LOGS();
return 0;
}
-#endif
+#endif /* defined(HAVE_SYSLOG_H) */
+
+#ifdef HAVE_ANDROID_LOG_H
+/**
+ * Add a log handler to send messages to the Android platform log facility.
+ */
+int
+add_android_log(const log_severity_list_t *severity,
+ const char *android_tag)
+{
+ logfile_t *lf = NULL;
+
+ lf = tor_malloc_zero(sizeof(logfile_t));
+ lf->fd = -1;
+ lf->severities = tor_memdup(severity, sizeof(log_severity_list_t));
+ lf->filename = tor_strdup("<android>");
+ lf->is_android = 1;
+
+ if (android_tag == NULL)
+ lf->android_tag = tor_strdup("Tor");
+ else {
+ char buf[256];
+ tor_snprintf(buf, sizeof(buf), "Tor-%s", android_tag);
+ lf->android_tag = tor_strdup(buf);
+ }
+
+ LOCK_LOGS();
+ lf->next = logfiles;
+ logfiles = lf;
+ log_global_min_severity_ = get_min_log_level();
+ UNLOCK_LOGS();
+ return 0;
+}
+#endif // HAVE_ANDROID_LOG_H.
/** If <b>level</b> is a valid log severity, return the corresponding
* numeric value. Otherwise, return -1. */
@@ -1172,12 +1258,15 @@ log_level_to_string(int level)
}
/** NULL-terminated array of names for log domains such that domain_list[dom]
- * is a description of <b>dom</b>. */
+ * is a description of <b>dom</b>.
+ *
+ * Remember to update doc/tor.1.txt if you modify this list.
+ * */
static const char *domain_list[] = {
"GENERAL", "CRYPTO", "NET", "CONFIG", "FS", "PROTOCOL", "MM",
"HTTP", "APP", "CONTROL", "CIRC", "REND", "BUG", "DIR", "DIRSERV",
"OR", "EDGE", "ACCT", "HIST", "HANDSHAKE", "HEARTBEAT", "CHANNEL",
- "SCHED", "DOS", NULL
+ "SCHED", "GUARD", "CONSDIFF", "DOS", NULL
};
/** Return a bitmask for the log domain for which <b>domain</b> is the name,
@@ -1313,16 +1402,15 @@ parse_log_severity_config(const char **cfg_ptr,
if (!strcasecmpstart(cfg, "file") ||
!strcasecmpstart(cfg, "stderr") ||
!strcasecmpstart(cfg, "stdout") ||
- !strcasecmpstart(cfg, "syslog")) {
+ !strcasecmpstart(cfg, "syslog") ||
+ !strcasecmpstart(cfg, "android")) {
goto done;
}
if (got_an_unqualified_range > 1)
return -1;
- space = strchr(cfg, ' ');
+ space = find_whitespace(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));