Copyright year updates (things touched in 2015)
[exim.git] / src / src / log.c
index 2be1ff25dc14509cae6047dd89402ebd2e336f19..11b3edfdfc4303b6a4b39f49c61439daf146dc2e 100644 (file)
@@ -2,7 +2,7 @@
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
-/* Copyright (c) University of Cambridge 1995 - 2009 */
+/* Copyright (c) University of Cambridge 1995 - 2015 */
 /* See the file NOTICE for conditions of use and distribution. */
 
 /* Functions for writing log files. The code for maintaining datestamped
@@ -179,7 +179,7 @@ overwrite it temporarily if it is necessary to create the directory.
 Returns:       a file descriptor, or < 0 on failure (errno set)
 */
 
-static int
+int
 log_create(uschar *name)
 {
 int fd = Uopen(name, O_CREAT|O_APPEND|O_WRONLY, LOG_MODE);
@@ -513,6 +513,66 @@ log_write(0, LOG_PANIC_DIE, "failed to write to %s: length=%d result=%d "
 
 
 
+/*************************************************
+*     Write to an fd, retrying after signals     *
+*************************************************/
+
+/* Basic write to fd for logs, handling EINTR.
+
+Arguments:
+  fd        the fd to write to
+  buf       the string to write
+  length    the string length being written
+
+Returns:
+  length actually written, persisting an errno from write()
+*/
+ssize_t
+write_to_fd_buf(int fd, const uschar *buf, size_t length)
+{
+ssize_t wrote;
+size_t total_written = 0;
+const uschar *p = buf;
+size_t left = length;
+
+while (1)
+  {
+  wrote = write(fd, p, left);
+  if (wrote == (ssize_t)-1)
+    {
+    if (errno == EINTR) continue;
+    return wrote;
+    }
+  total_written += wrote;
+  if (wrote == left)
+    break;
+  else
+    {
+    p += wrote;
+    left -= wrote;
+    }
+  }
+return total_written;
+}
+
+
+
+static void
+set_file_path(void)
+{
+int sep = ':';              /* Fixed separator - outside use */
+uschar *t;
+const uschar *tt = US LOG_FILE_PATH;
+while ((t = string_nextinlist(&tt, &sep, log_buffer, LOG_BUFFER_SIZE)))
+  {
+  if (Ustrcmp(t, "syslog") == 0 || t[0] == 0) continue;
+  file_path = string_copy(t);
+  break;
+  }
+}
+
+
+
 /*************************************************
 *            Write message to log file           *
 *************************************************/
@@ -574,7 +634,7 @@ void
 log_write(unsigned int selector, int flags, const char *format, ...)
 {
 uschar *ptr;
-int length, rc;
+int length;
 int paniclogfd;
 ssize_t written_len;
 va_list ap;
@@ -625,13 +685,13 @@ if (!path_inspected)
   /* If nothing has been set, don't waste effort... the default values for the
   statics are file_path="" and logging_mode = LOG_MODE_FILE. */
 
-  if (log_file_path[0] != 0)
+  if (*log_file_path)
     {
     int sep = ':';              /* Fixed separator - outside use */
     uschar *s;
-    uschar *ss = log_file_path;
+    const uschar *ss = log_file_path;
     logging_mode = 0;
-    while ((s = string_nextinlist(&ss,&sep,log_buffer,LOG_BUFFER_SIZE)) != NULL)
+    while ((s = string_nextinlist(&ss, &sep, log_buffer, LOG_BUFFER_SIZE)))
       {
       if (Ustrcmp(s, "syslog") == 0)
         logging_mode |= LOG_MODE_SYSLOG;
@@ -642,10 +702,8 @@ if (!path_inspected)
 
         /* If a non-empty path is given, use it */
 
-        if (s[0] != 0)
-          {
+        if (*s)
           file_path = string_copy(s);
-          }
 
         /* 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
@@ -653,17 +711,7 @@ if (!path_inspected)
         use the ultimate default in the spool directory. */
 
         else
-          {
-          uschar *t;
-          uschar *tt = US LOG_FILE_PATH;
-          while ((t = string_nextinlist(&tt,&sep,log_buffer,LOG_BUFFER_SIZE))
-                != NULL)
-            {
-            if (Ustrcmp(t, "syslog") == 0 || t[0] == 0) continue;
-            file_path = string_copy(t);
-            break;
-            }
-          }  /* Empty item in log_file_path */
+         set_file_path();  /* Empty item in log_file_path */
         }    /* First non-syslog item in log_file_path */
       }      /* Scan of log_file_path */
     }
@@ -686,10 +734,8 @@ if (!path_inspected)
   should work since we have now set up the routing. */
 
   if (multiple)
-    {
     log_write(0, LOG_MAIN|LOG_PANIC,
       "More than one path given in log_file_path: using %s", file_path);
-    }
   }
 
 /* If debugging, show all log entries, but don't show headers. Do it all
@@ -892,11 +938,7 @@ if ((flags & LOG_MAIN) != 0 &&
 
     /* Failing to write to the log is disastrous */
 
-    while (
-        ((written_len = write(mainlogfd, log_buffer, length)) == (ssize_t)-1)
-        &&
-        (errno == EINTR)
-        ) /**/;
+    written_len = write_to_fd_buf(mainlogfd, log_buffer, length);
     if (written_len != length)
       {
       log_write_failed(US"main log", length, written_len);
@@ -1019,9 +1061,10 @@ if ((flags & LOG_REJECT) != 0)
       if (fstat(rejectlogfd, &statbuf) >= 0) rejectlog_inode = statbuf.st_ino;
       }
 
-    if ((rc = write(rejectlogfd, log_buffer, length)) != length)
+    written_len = write_to_fd_buf(rejectlogfd, log_buffer, length);
+    if (written_len != length)
       {
-      log_write_failed(US"reject log", length, rc);
+      log_write_failed(US"reject log", length, written_len);
       /* That function does not return */
       }
     }
@@ -1053,14 +1096,18 @@ if ((flags & LOG_PANIC) != 0)
     panic_recurseflag = FALSE;
 
     if (panic_save_buffer != NULL)
-      (void) write(paniclogfd, panic_save_buffer, Ustrlen(panic_save_buffer));
+      {
+      int i = write(paniclogfd, panic_save_buffer, Ustrlen(panic_save_buffer));
+      i = i;   /* compiler quietening */
+      }
 
-    if ((rc = write(paniclogfd, log_buffer, length)) != length)
+    written_len = write_to_fd_buf(paniclogfd, log_buffer, length);
+    if (written_len != length)
       {
       int save_errno = errno;
       write_syslog(LOG_CRIT, log_buffer);
       sprintf(CS log_buffer, "write failed on panic log: length=%d result=%d "
-        "errno=%d (%s)", length, rc, save_errno, strerror(save_errno));
+        "errno=%d (%s)", length, (int)written_len, save_errno, strerror(save_errno));
       write_syslog(LOG_CRIT, log_buffer);
       flags |= LOG_PANIC_DIE;
       }
@@ -1265,7 +1312,7 @@ misconfiguration.
 
 The first use of this is in ACL logic, "control = debug/tag=foo/opts=+expand"
 which can be combined with conditions, etc, to activate extra logging only
-for certain sources. */
+for certain sources. The second use is inetd wait mode debug preservation. */
 
 void
 debug_logging_activate(uschar *tag_name, uschar *opts)
@@ -1275,7 +1322,7 @@ int fd = -1;
 if (debug_file)
   {
   debug_printf("DEBUGGING ACTIVATED FROM WITHIN CONFIG.\n"
-      "DEBUG: Tag=\"%s\" Opts=\"%s\"\n", tag_name, opts);
+      "DEBUG: Tag=\"%s\" Opts=\"%s\"\n", tag_name, opts ? opts : US"");
   return;
   }
 
@@ -1293,6 +1340,12 @@ if (opts)
       debug_options, debug_options_count, US"debug", DEBUG_FROM_CONFIG);
   }
 
+/* When activating from a transport process we may never have logged at all
+resulting in certain setup not having been done.  Hack this for now so we
+do not segfault; note that nondefault log locations will not work */
+
+if (!*file_path) set_file_path();
+
 open_log(&fd, lt_debug, tag_name);
 
 if (fd != -1)