diff options
-rw-r--r-- | configure.in | 2 | ||||
-rw-r--r-- | doc/tor.1.in | 4 | ||||
-rw-r--r-- | src/common/log.c | 108 | ||||
-rw-r--r-- | src/common/log.h | 30 | ||||
-rw-r--r-- | src/common/util.c | 4 | ||||
-rw-r--r-- | src/config/torrc.sample.in | 3 | ||||
-rw-r--r-- | src/or/config.c | 27 |
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; |