Fix logging with empty element in log_file_path (Bug 2733)
authorJeremy Harris <jgh146exb@wizmail.org>
Sat, 15 May 2021 11:37:04 +0000 (13:37 +0200)
committerHeiko Schlittermann (HS12-RIPE) <hs@schlittermann.de>
Thu, 24 Jun 2021 19:47:02 +0000 (21:47 +0200)
(cherry picked from commit e19790f7707cc901435849e78d20f249056c16b5)

src/src/log.c

index dff7d321190d03ce8430a063a9fa153f8ce6e4af..4cb161ac0fbdf5024a2de1a77589981c0f0d834f 100644 (file)
@@ -288,8 +288,11 @@ if (fd < 0 && errno == ENOENT)
   uschar *lastslash = Ustrrchr(name, '/');
   *lastslash = 0;
   created = directory_make(NULL, name, LOG_DIRECTORY_MODE, FALSE);
-  DEBUG(D_any) debug_printf("%s log directory %s\n",
-    created ? "created" : "failed to create", name);
+  DEBUG(D_any)
+    if (created)
+      debug_printf("created log directory %s\n", name);
+    else
+      debug_printf("failed to create log directory %s: %s\n", name, strerror(errno));
   *lastslash = '/';
   if (created) fd = Uopen(name, flags, LOG_MODE);
   }
@@ -494,17 +497,24 @@ switch (type)
     it gets statted to see if it has been cycled. With a datestamp, the datestamp
     will be compared. The static slot for saving it is the same size as buffer,
     and the text has been checked above to fit, so this use of strcpy() is OK. */
+
     Ustrcpy(mainlog_name, buffer);
     if (string_datestamp_offset > 0)
       mainlog_datestamp = mainlog_name + string_datestamp_offset;
+    break;
+
   case lt_reject:
     /* Ditto for the reject log */
+
     Ustrcpy(rejectlog_name, buffer);
     if (string_datestamp_offset > 0)
       rejectlog_datestamp = rejectlog_name + string_datestamp_offset;
+    break;
+
   case lt_debug:
     /* and deal with the debug log (which keeps the datestamp, but does not
     update it) */
+
     Ustrcpy(debuglog_name, buffer);
     if (tag)
       {
@@ -514,10 +524,13 @@ switch (type)
       if (ok2)
         Ustrcpy(debuglog_name, buffer);
       }
+    break;
+
   default:
     /* Remove any datestamp if this is the panic log. This is rare, so there's no
   need to optimize getting the datestamp length. We remove one non-alphanumeric
   char afterwards if at the start, otherwise one before. */
+
     if (string_datestamp_offset >= 0)
       {
       uschar * from = buffer + string_datestamp_offset;
@@ -534,6 +547,7 @@ switch (type)
       due to overlap we must use memmove() not Ustrcpy(). */
       memmove(from, to, Ustrlen(to)+1);
       }
+    break;
   }
 
 /* If the file name is too long, it is an unrecoverable disaster */
@@ -547,9 +561,7 @@ if (!ok)
 *fd = log_open_as_exim(buffer);
 
 if (*fd >= 0)
-  {
   return;
-  }
 
 euid = geteuid();
 
@@ -701,6 +713,10 @@ return total_written;
 }
 
 
+/* Pull the file out of the configured or the compiled-in list.
+Called for an empty log_file_path element, for debug logging activation
+when file_path has not previously been set, and from the appenfile transport setup. */
+
 void
 set_file_path(BOOL *multiple)
 {
@@ -708,30 +724,42 @@ uschar *s;
 int sep = ':';              /* Fixed separator - outside use */
 const uschar *ss = *log_file_path ? log_file_path : US LOG_FILE_PATH;
 
-logging_mode = 0;
-while ((s = string_nextinlist(&ss, &sep, log_buffer, LOG_BUFFER_SIZE)))
-  {
-  if (Ustrcmp(s, "syslog") == 0)
-    logging_mode |= LOG_MODE_SYSLOG;
-  else if (logging_mode & LOG_MODE_FILE)  /* we know a file already */
+if (*ss)
+  for (logging_mode = 0;
+       s = string_nextinlist(&ss, &sep, log_buffer, LOG_BUFFER_SIZE); )
     {
-    if (multiple) *multiple = TRUE;
-    }
-  else
-    {
-    logging_mode |= LOG_MODE_FILE;
+    if (Ustrcmp(s, "syslog") == 0)
+      logging_mode |= LOG_MODE_SYSLOG;
+    else if (!(logging_mode & LOG_MODE_FILE))  /* no file yet */
+      {
+      /* If a non-empty path is given, use it */
+
+      if (*s)
+       file_path = string_copy(s);
 
-    /* If a non-empty path is given, use it */
+      /* If handling the config option, and the element is empty, we want to use
+      the first non-empty, non-syslog item in LOG_FILE_PATH, if there is one,
+      since the value of log_file_path may have been set at runtime. If there is
+      no such item, use the ultimate default in the spool directory. */
 
-    if (*s)
-      file_path = string_copy(s);
+      else if (*log_file_path && LOG_FILE_PATH[0])
+       {
+       ss = US LOG_FILE_PATH;
+       continue;
+       }
 
-    /* If the path is empty, we want to use the first non-empty, non-
-    syslog item in LOG_FILE_PATH, if there is one, since the value of
-    log_file_path may have been set at runtime. If there is no such item,
-    use the ultimate default in the spool directory. */
+      logging_mode |= LOG_MODE_FILE;
+      }
+    else
+      if (multiple) *multiple = TRUE;
     }
-  }
+  else
+    logging_mode = LOG_MODE_FILE;
+
+/* Set up the ultimate default if necessary. */
+
+if (logging_mode & LOG_MODE_FILE  &&  !*file_path)
+  file_path = string_sprintf("%s/log/%%slog", spool_directory);
 }
 
 
@@ -865,11 +893,8 @@ if (!path_inspected)
     die(US"Neither syslog nor file logging set in log_file_path",
         US"Unexpected logging failure");
 
-  /* Set up the ultimate default if necessary. Then revert to the old store
-  pool, and record that we've sorted out the path. */
+  /* Revert to the old store pool, and record that we've sorted out the path. */
 
-  if (logging_mode & LOG_MODE_FILE  &&  !file_path[0])
-    file_path = string_sprintf("%s/log/%%slog", spool_directory);
   store_pool = old_pool;
   path_inspected = TRUE;
 
@@ -1223,6 +1248,7 @@ if (flags & LOG_PANIC)
 
   if (logging_mode & LOG_MODE_FILE)
     {
+    if (!*file_path) set_file_path(NULL);
     panic_recurseflag = TRUE;
     open_log(&paniclogfd, lt_panic, NULL);  /* Won't return on failure */
     panic_recurseflag = FALSE;
@@ -1497,10 +1523,12 @@ debug_file = NULL;
 unlink_log(lt_debug);
 }
 
+/* Called from the appendfile transport setup. */
 void
 open_logs(void)
 {
 set_file_path(NULL);
+if (!(logging_mode & LOG_MODE_FILE)) return;
 open_log(&mainlogfd, lt_main, 0);
 open_log(&rejectlogfd, lt_reject, 0);
 }