Browse Source

Add an option to overwrite logs

 * Issue #5583
Arlo Breault 10 years ago
parent
commit
15e170e01b
8 changed files with 52 additions and 9 deletions
  1. 2 0
      changes/feature5583
  2. 3 0
      doc/tor.1.txt
  3. 13 2
      src/common/log.c
  4. 3 1
      src/common/torlog.h
  5. 24 5
      src/or/config.c
  6. 4 0
      src/or/main.c
  7. 2 0
      src/or/or.h
  8. 1 1
      src/test/test_logging.c

+ 2 - 0
changes/feature5583

@@ -0,0 +1,2 @@
+ o Minor features:
+   - Add an option to overwrite logs (TruncateLogFile). Closes ticket #5583.

+ 3 - 0
doc/tor.1.txt

@@ -561,6 +561,9 @@ GENERAL OPTIONS
     messages to affect times logged by a controller, times attached to
     syslog messages, or the mtime fields on log files.  (Default: 1 second)
 
+[[TruncateLogFile]] **TruncateLogFile** **0**|**1**::
+    If 1, Tor will overwrite logs, instead of appending them. (Default: 0)
+
 [[SafeLogging]] **SafeLogging** **0**|**1**|**relay**::
     Tor can scrub potentially sensitive strings from log messages (e.g.
     addresses) by replacing them with the string [scrubbed]. This way logs can

+ 13 - 2
src/common/log.c

@@ -1010,12 +1010,16 @@ mark_logs_temp(void)
  * logfile fails, -1 is returned and errno is set appropriately (by open(2)).
  */
 int
-add_file_log(const log_severity_list_t *severity, const char *filename)
+add_file_log(const log_severity_list_t *severity, const char *filename,
+             const int truncate)
 {
   int fd;
   logfile_t *lf;
 
-  fd = tor_open_cloexec(filename, O_WRONLY|O_CREAT|O_APPEND, 0644);
+  int open_flags = O_WRONLY|O_CREAT;
+  open_flags |= truncate ? O_TRUNC : O_APPEND;
+
+  fd = tor_open_cloexec(filename, open_flags, 0644);
   if (fd<0)
     return -1;
   if (tor_fd_seekend(fd)<0) {
@@ -1297,3 +1301,10 @@ switch_logs_debug(void)
   UNLOCK_LOGS();
 }
 
+/** Truncate all the log files. */
+void
+truncate_logs(void)
+{
+  for (logfile_t *lf = logfiles; lf; lf = lf->next)
+    ftruncate(lf->fd, 0);
+}

+ 3 - 1
src/common/torlog.h

@@ -130,7 +130,8 @@ void set_log_severity_config(int minSeverity, int maxSeverity,
                              log_severity_list_t *severity_out);
 void add_stream_log(const log_severity_list_t *severity, const char *name,
                     int fd);
-int add_file_log(const log_severity_list_t *severity, const char *filename);
+int add_file_log(const log_severity_list_t *severity, const char *filename,
+                 const int truncate);
 #ifdef HAVE_SYSLOG_H
 int add_syslog_log(const log_severity_list_t *severity);
 #endif
@@ -148,6 +149,7 @@ void change_callback_log_severity(int loglevelMin, int loglevelMax,
 void flush_pending_log_callbacks(void);
 void log_set_application_name(const char *name);
 void set_log_time_granularity(int granularity_msec);
+void truncate_logs(void);
 
 void tor_log(int severity, log_domain_mask_t domain, const char *format, ...)
   CHECK_PRINTF(3,4);

+ 24 - 5
src/or/config.c

@@ -302,6 +302,7 @@ static config_var_t option_vars_[] = {
   OBSOLETE("LogLevel"),
   OBSOLETE("LogFile"),
   V(LogTimeGranularity,          MSEC_INTERVAL, "1 second"),
+  V(TruncateLogFile,             BOOL,     "0"),
   V(LongLivedPorts,              CSV,
         "21,22,706,1863,5050,5190,5222,5223,6523,6667,6697,8300"),
   VAR("MapAddress",              LINELIST, AddressMap,           NULL),
@@ -557,7 +558,8 @@ static int check_server_ports(const smartlist_t *ports,
 static int validate_data_directory(or_options_t *options);
 static int write_configuration_file(const char *fname,
                                     const or_options_t *options);
-static int options_init_logs(or_options_t *options, int validate_only);
+static int options_init_logs(const or_options_t *old_options,
+                             or_options_t *options, int validate_only);
 
 static void init_libevent(const or_options_t *options);
 static int opt_streq(const char *s1, const char *s2);
@@ -1145,7 +1147,8 @@ options_act_reversible(const or_options_t *old_options, char **msg)
 
   mark_logs_temp(); /* Close current logs once new logs are open. */
   logs_marked = 1;
-  if (options_init_logs(options, 0)<0) { /* Configure the tor_log(s) */
+  /* Configure the tor_log(s) */
+  if (options_init_logs(old_options, options, 0)<0) {
     *msg = tor_strdup("Failed to init Log options. See logs for details.");
     goto rollback;
   }
@@ -2547,7 +2550,8 @@ options_validate(or_options_t *old_options, or_options_t *options,
         config_line_append(&options->Logs, "Log", "warn stdout");
   }
 
-  if (options_init_logs(options, 1)<0) /* Validate the tor_log(s) */
+  /* Validate the tor_log(s) */
+  if (options_init_logs(old_options, options, 1)<0)
     REJECT("Failed to validate Log options. See logs for details.");
 
   if (authdir_mode(options)) {
@@ -4449,7 +4453,8 @@ addressmap_register_auto(const char *from, const char *to,
  * Initialize the logs based on the configuration file.
  */
 static int
-options_init_logs(or_options_t *options, int validate_only)
+options_init_logs(const or_options_t *old_options, or_options_t *options,
+                  int validate_only)
 {
   config_line_t *opt;
   int ok;
@@ -4542,7 +4547,21 @@ options_init_logs(or_options_t *options, int validate_only)
         !strcasecmp(smartlist_get(elts,0), "file")) {
       if (!validate_only) {
         char *fname = expand_filename(smartlist_get(elts, 1));
-        if (add_file_log(severity, fname) < 0) {
+        /* Truncate if TruncateLogFile is set and we haven't seen this option
+           line before. */
+        int truncate = 0;
+        if (options->TruncateLogFile) {
+          truncate = 1;
+          if (old_options) {
+            config_line_t *opt2;
+            for (opt2 = old_options->Logs; opt2; opt2 = opt2->next)
+              if (!strcmp(opt->value, opt2->value)) {
+                truncate = 0;
+                break;
+              }
+          }
+        }
+        if (add_file_log(severity, fname, truncate) < 0) {
           log_warn(LD_CONFIG, "Couldn't open file for 'Log %s': %s",
                    opt->value, strerror(errno));
           ok = 0;

+ 4 - 0
src/or/main.c

@@ -1861,6 +1861,10 @@ do_hup(void)
       return -1;
     }
     options = get_options(); /* they have changed now */
+    /* Logs are only truncated the first time they are opened, but were
+       probably intended to be cleaned up on signal. */
+    if (options->TruncateLogFile)
+      truncate_logs();
   } else {
     char *msg = NULL;
     log_notice(LD_GENERAL, "Not reloading config file: the controller told "

+ 2 - 0
src/or/or.h

@@ -3402,6 +3402,8 @@ typedef struct {
 
   int LogMessageDomains; /**< Boolean: Should we log the domain(s) in which
                           * each log message occurs? */
+  int TruncateLogFile; /**< Boolean: Should we truncate the log file
+                            before we start writing? */
 
   char *DebugLogFile; /**< Where to send verbose log messages. */
   char *DataDirectory; /**< OR only: where to store long-term data. */

+ 1 - 1
src/test/test_logging.c

@@ -89,7 +89,7 @@ test_sigsafe_err(void *arg)
 
   init_logging();
   mark_logs_temp();
-  add_file_log(&include_bug, fn);
+  add_file_log(&include_bug, fn, 0);
   tor_log_update_sigsafe_err_fds();
   close_temp_logs();