aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configure.in2
-rw-r--r--doc/tor.1.in4
-rw-r--r--src/common/log.c108
-rw-r--r--src/common/log.h30
-rw-r--r--src/common/util.c4
-rw-r--r--src/config/torrc.sample.in3
-rw-r--r--src/or/config.c27
7 files changed, 139 insertions, 39 deletions
diff --git a/configure.in b/configure.in
index 0463f4023..e7314e6df 100644
--- a/configure.in
+++ b/configure.in
@@ -143,7 +143,7 @@ AC_CHECK_HEADERS(unistd.h string.h signal.h netdb.h ctype.h poll.h sys/stat.h sy
dnl These headers are not essential
-AC_CHECK_HEADERS(stdint.h sys/types.h inttypes.h sys/param.h sys/wait.h sys/limits.h netinet/in.h arpa/inet.h machine/limits.h)
+AC_CHECK_HEADERS(stdint.h sys/types.h inttypes.h sys/param.h sys/wait.h sys/limits.h netinet/in.h arpa/inet.h machine/limits.h syslog.h)
AC_CHECK_FUNCS(gettimeofday ftime socketpair uname inet_aton strptime)
AC_REPLACE_FUNCS(strlcat strlcpy)
diff --git a/doc/tor.1.in b/doc/tor.1.in
index 541a5ded9..8ce4205f9 100644
--- a/doc/tor.1.in
+++ b/doc/tor.1.in
@@ -32,6 +32,10 @@ Set the verboseness level of the primary log. (Default: warn)
\fBlogfile \fR\fIFILE\fP
Rather than logging to stdout, log to FILE.
.TP
+\fBsyslog\fP
+Rather than logging to stdout, send messages to the system log. (Not
+supported on all platforms)
+.TP
\fBbandwidthrate \fR\fINUM\fP
A token bucket limits the average incoming bandwidth on this node to NUM bytes per second. (Default: 800000)
.TP
diff --git a/src/common/log.c b/src/common/log.c
index 07a83e36f..3a64750ca 100644
--- a/src/common/log.c
+++ b/src/common/log.c
@@ -34,6 +34,7 @@ typedef struct logfile_t {
int loglevel; /**< Lowest severity level to send to this stream. */
int max_loglevel; /**< Highest severity level to send to this stream. */
int is_temporary; /**< Boolean: close after initializing logging subsystem.*/
+ int is_syslog; /**< Boolean: send messages to syslog. */
} logfile_t;
/** Helper: map a log severity to descriptive string. */
@@ -50,8 +51,13 @@ static INLINE const char *sev_to_string(int severity) {
/** Linked list of logfile_t. */
static logfile_t *logfiles = NULL;
+#ifdef HAVE_SYSLOG_H
+static int syslog_count = 0;
+#endif
static void delete_log(logfile_t *victim);
+static void close_log(logfile_t *victim);
+static int reset_log(logfile_t *lf);
static INLINE size_t
_log_prefix(char *buf, size_t buf_len, int severity)
@@ -104,16 +110,19 @@ static void log_tor_version(logfile_t *lf, int reset)
/** 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
- * than once.)
+ * than once.) Return a pointer to the first character of the message
+ * portion of the formatted string.
*/
-static INLINE void format_msg(char *buf, size_t buf_len,
+static INLINE char *format_msg(char *buf, size_t buf_len,
int severity, const char *funcname,
const char *format, va_list ap)
{
size_t n;
+ char *end_of_prefix;
buf_len -= 2; /* subtract 2 characters so we have room for \n\0 */
n = _log_prefix(buf, buf_len, severity);
+ end_of_prefix = buf+n;
if (funcname) {
n += snprintf(buf+n, buf_len-n, "%s(): ", funcname);
@@ -128,6 +137,7 @@ static INLINE void format_msg(char *buf, size_t buf_len,
}
buf[n]='\n';
buf[n+1]='\0';
+ return end_of_prefix;
}
/** Helper: sends a message to the appropriate logfiles, at loglevel
@@ -140,23 +150,32 @@ logv(int severity, const char *funcname, const char *format, va_list ap)
char buf[10024];
int formatted = 0;
logfile_t *lf;
+ char *end_of_prefix=NULL;
assert(format);
lf = logfiles;
while(lf) {
- if (severity < lf->loglevel || severity > lf->max_loglevel) {
+ if (severity > lf->loglevel || severity < lf->max_loglevel) {
lf = lf->next;
continue;
}
- if (!lf->file) {
+ if (! (lf->file || lf->is_syslog)) {
lf = lf->next;
continue;
}
if (!formatted) {
- format_msg(buf, sizeof(buf), severity, funcname, format, ap);
+ end_of_prefix =
+ format_msg(buf, sizeof(buf), severity, funcname, format, ap);
formatted = 1;
}
+ if (lf->is_syslog) {
+#ifdef HAVE_SYSLOG_H
+ syslog(severity, "%s", end_of_prefix);
+#endif
+ lf = lf->next;
+ continue;
+ }
if(fputs(buf, lf->file) == EOF ||
fflush(lf->file) == EOF) { /* error */
/* don't log the error! Blow away this log entry and continue. */
@@ -194,8 +213,7 @@ void close_logs()
while(logfiles) {
victim = logfiles;
logfiles = logfiles->next;
- if (victim->needs_close)
- fclose(victim->file);
+ close_log(victim);
tor_free(victim->filename);
tor_free(victim);
}
@@ -206,17 +224,12 @@ void reset_logs()
{
logfile_t *lf = logfiles;
while(lf) {
- if (lf->needs_close) {
- if(fclose(lf->file)==EOF ||
- !(lf->file = fopen(lf->filename, "a"))) {
- /* error. don't log it. delete the log entry and continue. */
- logfile_t *victim = lf;
- lf = victim->next;
- delete_log(victim);
- continue;
- } else {
- log_tor_version(lf, 1);
- }
+ if (reset_log(lf)) {
+ /* error. don't log it. delete the log entry and continue. */
+ logfile_t *victim = lf;
+ lf = victim->next;
+ delete_log(victim);
+ continue;
}
lf = lf->next;
}
@@ -241,19 +254,43 @@ static void delete_log(logfile_t *victim) {
tor_free(victim);
}
+static void close_log(logfile_t *victim)
+{
+ if (victim->needs_close && victim->file) {
+ fclose(victim->file);
+ } else if (victim->is_syslog) {
+#ifdef HAVE_SYSLOG_H
+ if (--syslog_count == 0)
+ /* There are no other syslogs; close the logging facility. */
+ closelog();
+#endif
+ }
+}
+
+static int reset_log(logfile_t *lf)
+{
+ if (lf->needs_close) {
+ if(fclose(lf->file)==EOF ||
+ !(lf->file = fopen(lf->filename, "a"))) {
+ return -1;
+ } else {
+ log_tor_version(lf, 1);
+ }
+ }
+ return 0;
+}
+
/** Add a log handler to send all messages of severity <b>loglevel</b>
* or higher to <b>stream</b>. */
void add_stream_log(int loglevelMin, int loglevelMax, const char *name, FILE *stream)
{
logfile_t *lf;
- lf = tor_malloc(sizeof(logfile_t));
+ lf = tor_malloc_zero(sizeof(logfile_t));
lf->filename = tor_strdup(name);
- lf->needs_close = 0;
lf->loglevel = loglevelMin;
lf->max_loglevel = loglevelMax;
lf->file = stream;
lf->next = logfiles;
- lf->is_temporary = 0;
logfiles = lf;
}
@@ -266,6 +303,7 @@ void add_temp_log(void)
logfiles->is_temporary = 1;
}
+/** Close any log handlers added by add_temp_log or marked by mark_logs_temp */
void close_temp_logs(void)
{
logfile_t *lf, **p;
@@ -273,8 +311,7 @@ void close_temp_logs(void)
if ((*p)->is_temporary) {
lf = *p;
*p = (*p)->next;
- if (lf->needs_close)
- fclose(lf->file);
+ close_log(lf);
tor_free(lf->filename);
tor_free(lf);
} else {
@@ -283,6 +320,7 @@ void close_temp_logs(void)
}
}
+/** Configure all log handles to be closed by close_temp_logs */
void mark_logs_temp(void)
{
logfile_t *lf;
@@ -306,6 +344,28 @@ int add_file_log(int loglevelMin, int loglevelMax, const char *filename)
return 0;
}
+#ifdef HAVE_SYSLOG_H
+/**
+ * Add a log handler to send messages to they system log facility.
+ */
+int add_syslog_log(int loglevelMin, int loglevelMax)
+{
+ logfile_t *lf;
+ if (syslog_count++ == 0)
+ /* This is the the first syslog. */
+ openlog("Tor", LOG_NDELAY, LOG_DAEMON);
+
+ lf = tor_malloc_zero(sizeof(logfile_t));
+ lf->loglevel = loglevelMin;
+ lf->filename = tor_strdup("<syslog>");
+ lf->max_loglevel = loglevelMax;
+ lf->is_syslog = 1;
+ lf->next = logfiles;
+ logfiles = lf;
+ return 0;
+}
+#endif
+
/** If <b>level</b> is a valid log severity, return the corresponding
* numeric value. Otherwise, return -1. */
int parse_log_level(const char *level) {
@@ -327,7 +387,7 @@ int get_min_log_level(void)
logfile_t *lf;
int min = LOG_ERR;
for (lf = logfiles; lf; lf = lf->next) {
- if (lf->loglevel < min)
+ if (lf->loglevel > min)
min = lf->loglevel;
}
return min;
diff --git a/src/common/log.h b/src/common/log.h
index 7ce5ceee0..0e458142f 100644
--- a/src/common/log.h
+++ b/src/common/log.h
@@ -18,24 +18,37 @@
#ifdef HAVE_SYSLOG_H
#include <syslog.h>
#define LOG_WARN LOG_WARNING
+#if LOG_DEBUG < LOG_ERR
+#error "Your syslog.h thinks high numbers are more important. We aren't prepared to deal with that."
+#endif
#else
+/* XXXX Note: The code was originally written to refer to severities,
+ * with 0 being the least severe; while syslog's logging code refers to
+ * priorities, with 0 being the most important. Thus, all our comparisons
+ * needed to be reversed when we added syslog support.
+ *
+ * The upshot of this is that comments about log levels may be messed
+ * up: for "maximum severity" read "most severe" and "numerically
+ * *lowest* severity".
+ */
+
/** Debug-level severity: for hyper-verbose messages of no interest to
* anybody but developers. */
-#define LOG_DEBUG 0
+#define LOG_DEBUG 7
/** Info-level severity: for messages that appear frequently during normal
* operation. */
-#define LOG_INFO 1
+#define LOG_INFO 6
/** Notice-level severity: for messages that appear infrequently
* during normal operation; that the user will probably care about;
* and that are not errors.
*/
-#define LOG_NOTICE 2
+#define LOG_NOTICE 5
/** Warn-level severity: for messages that only appear when something has gone
* wrong. */
-#define LOG_WARN 3
+#define LOG_WARN 4
/** Error-level severity: for messages that only appear when something has gone
* very wrong, and the Tor process can no longer proceed. */
-#define LOG_ERR 4
+#define LOG_ERR 3
#endif
/* magic to make GCC check for proper format strings. */
@@ -49,9 +62,12 @@
int parse_log_level(const char *level);
void add_stream_log(int severityMin, int severityMax, const char *name, FILE *stream);
int add_file_log(int severityMin, int severityMax, const char *filename);
+#ifdef HAVE_SYSLOG_H
+int add_syslog_log(int loglevelMin, int loglevelMax);
+#endif
int get_min_log_level(void);
-void close_logs();
-void reset_logs();
+void close_logs(void);
+void reset_logs(void);
void add_temp_log(void);
void close_temp_logs(void);
void mark_logs_temp(void);
diff --git a/src/common/util.c b/src/common/util.c
index d7f2f1a28..023463bcf 100644
--- a/src/common/util.c
+++ b/src/common/util.c
@@ -1740,13 +1740,17 @@ try_next_line:
while(*value && isspace((int)*value))
value++;
+#if 0
if(!*end || !*value) { /* only a key on this line. no value. */
*end = 0;
log_fn(LOG_WARN,"Line has keyword '%s' but no value. Failing.",key);
return -1;
}
+#endif
*end = 0; /* null it out */
+ tor_assert(key);
+ tor_assert(value);
log_fn(LOG_DEBUG,"got keyword '%s', value '%s'", key, value);
*key_out = key, *value_out = value;
return 1;
diff --git a/src/config/torrc.sample.in b/src/config/torrc.sample.in
index 5fcdabef5..c2dab9513 100644
--- a/src/config/torrc.sample.in
+++ b/src/config/torrc.sample.in
@@ -29,6 +29,9 @@ AllowUnverifiedNodes middle,rendezvous
### Send all debug messages ONLY to /var/log/tor/debug
#LogFile /var/log/tor/debug
#LogLevel debug-debug
+### To use the system log instead of Tor's logfiles, uncomment these lines:
+#SysLog
+#LogLevel notice
# Uncomment this to start the process in the background
#RunAsDaemon 1
diff --git a/src/or/config.c b/src/or/config.c
index aafe4c2d0..d12b5e9db 100644
--- a/src/or/config.c
+++ b/src/or/config.c
@@ -292,7 +292,7 @@ config_assign(or_options_t *options, struct config_line_t *list)
config_compare(list, "SocksPort", CONFIG_TYPE_UINT, &options->SocksPort) ||
config_compare(list, "SocksBindAddress",CONFIG_TYPE_LINELIST,&options->SocksBindAddress) ||
config_compare(list, "SocksPolicy", CONFIG_TYPE_LINELIST,&options->SocksPolicy) ||
-
+ config_compare(list, "SysLog", CONFIG_TYPE_LINELIST,&options->LogOptions) ||
config_compare(list, "TrafficShaping", CONFIG_TYPE_OBSOLETE, NULL) ||
config_compare(list, "User", CONFIG_TYPE_STRING, &options->User)
@@ -964,7 +964,8 @@ add_single_log(struct config_line_t *level_opt,
} else {
levelMax = LOG_ERR;
}
- if (file_opt) {
+
+ if (file_opt && !strcasecmp(file_opt->key, "LogFile")) {
if (add_file_log(levelMin, levelMax, file_opt->value) < 0) {
log_fn(LOG_WARN, "Cannot write to LogFile '%s': %s.", file_opt->value,
strerror(errno));
@@ -972,6 +973,16 @@ add_single_log(struct config_line_t *level_opt,
}
log_fn(LOG_NOTICE, "Successfully opened LogFile '%s', redirecting output.",
file_opt->value);
+ } else if (file_opt && !strcasecmp(file_opt->key, "SysLog")) {
+#ifdef HAVE_SYSLOG_H
+ if (add_syslog_log(levelMin, levelMax) < 0) {
+ log_fn(LOG_WARN, "Cannot open system log facility");
+ return -1;
+ }
+ log_fn(LOG_NOTICE, "Successfully opened system log, redirecting output.");
+#else
+ log_fn(LOG_WARN, "Tor was compiled without system logging enabled; can't enable SysLog.");
+#endif
} else if (!isDaemon) {
add_stream_log(levelMin, levelMax, "<stdout>", stdout);
close_temp_logs();
@@ -998,7 +1009,8 @@ config_init_logs(or_options_t *options)
/* Special case for if first option is LogLevel. */
if (opt && !strcasecmp(opt->key, "LogLevel")) {
- if (opt->next && !strcasecmp(opt->next->key, "LogFile")) {
+ if (opt->next && (!strcasecmp(opt->next->key, "LogFile") ||
+ !strcasecmp(opt->next->key, "SysLog"))) {
if (add_single_log(opt, opt->next, options->RunAsDaemon) < 0)
return -1;
opt = opt->next->next;
@@ -1013,17 +1025,18 @@ config_init_logs(or_options_t *options)
while (opt) {
if (!strcasecmp(opt->key, "LogLevel")) {
- log_fn(LOG_WARN, "Two LogLevel options in a row without intervening LogFile");
+ log_fn(LOG_WARN, "Two LogLevel options in a row without intervening LogFile or SysLog");
opt = opt->next;
} else {
- tor_assert(!strcasecmp(opt->key, "LogFile"));
+ tor_assert(!strcasecmp(opt->key, "LogFile") ||
+ !strcasecmp(opt->key, "SysLog"));
if (opt->next && !strcasecmp(opt->next->key, "LogLevel")) {
- /* LogFile followed by LogLevel */
+ /* LogFile/SysLog followed by LogLevel */
if (add_single_log(opt->next, opt, options->RunAsDaemon) < 0)
return -1;
opt = opt->next->next;
} else {
- /* LogFile followed by LogFile or end of list. */
+ /* LogFile/SysLog followed by LogFile/SysLog or end of list. */
if (add_single_log(NULL, opt, options->RunAsDaemon) < 0)
return -1;
opt = opt->next;