]> git.netwichtig.de Git - user/henk/code/exim.git/blobdiff - src/src/log.c
Do not close the (main)_log, if we do not see a chance to open it again.
[user/henk/code/exim.git] / src / src / log.c
index bb6902ea082af8b86d7c72494c1f136655e057bf..90373adf0a074410a14284375d4ae0045fca266f 100644 (file)
@@ -299,9 +299,12 @@ return fd;
 
 
 
-/* Inspired by OpenSSH's mm_send_fd(). Thanks! */
+/* Inspired by OpenSSH's mm_send_fd(). Thanks!
+Send fd over socketpair.
+Return: true iff good.
+*/
 
-static int
+static BOOL
 log_send_fd(const int sock, const int fd)
 {
 struct msghdr msg;
@@ -310,8 +313,8 @@ union {
   char buf[CMSG_SPACE(sizeof(int))];
 } cmsgbuf;
 struct cmsghdr *cmsg;
-struct iovec vec;
 char ch = 'A';
+struct iovec vec = {.iov_base = &ch, .iov_len = 1};
 ssize_t n;
 
 memset(&msg, 0, sizeof(msg));
@@ -325,17 +328,16 @@ cmsg->cmsg_level = SOL_SOCKET;
 cmsg->cmsg_type = SCM_RIGHTS;
 *(int *)CMSG_DATA(cmsg) = fd;
 
-vec.iov_base = &ch;
-vec.iov_len = 1;
 msg.msg_iov = &vec;
 msg.msg_iovlen = 1;
 
 while ((n = sendmsg(sock, &msg, 0)) == -1 && errno == EINTR);
-if (n != 1) return -1;
-return 0;
+return n == 1;
 }
 
-/* Inspired by OpenSSH's mm_receive_fd(). Thanks! */
+/* Inspired by OpenSSH's mm_receive_fd(). Thanks!
+Return fd passed over socketpair, or -1 on error.
+*/
 
 static int
 log_recv_fd(const int sock)
@@ -346,14 +348,12 @@ union {
   char buf[CMSG_SPACE(sizeof(int))];
 } cmsgbuf;
 struct cmsghdr *cmsg;
-struct iovec vec;
-ssize_t n;
 char ch = '\0';
-int fd = -1;
+struct iovec vec = {.iov_base = &ch, .iov_len = 1};
+ssize_t n;
+int fd;
 
 memset(&msg, 0, sizeof(msg));
-vec.iov_base = &ch;
-vec.iov_len = 1;
 msg.msg_iov = &vec;
 msg.msg_iovlen = 1;
 
@@ -361,14 +361,12 @@ memset(&cmsgbuf, 0, sizeof(cmsgbuf));
 msg.msg_control = &cmsgbuf.buf;
 msg.msg_controllen = sizeof(cmsgbuf.buf);
 
-while ((n = recvmsg(sock, &msg, 0)) == -1 && errno == EINTR);
+while ((n = recvmsg(sock, &msg, 0)) == -1 && errno == EINTR) ;
 if (n != 1 || ch != 'A') return -1;
 
-cmsg = CMSG_FIRSTHDR(&msg);
-if (cmsg == NULL) return -1;
+if (!(cmsg = CMSG_FIRSTHDR(&msg))) return -1;
 if (cmsg->cmsg_type != SCM_RIGHTS) return -1;
-fd = *(const int *)CMSG_DATA(cmsg);
-if (fd < 0) return -1;
+if ((fd = *(const int *)CMSG_DATA(cmsg)) < 0) return -1;
 return fd;
 }
 
@@ -395,28 +393,26 @@ int fd = -1;
 const uid_t euid = geteuid();
 
 if (euid == exim_uid)
-  {
   fd = log_open_already_exim(name);
-  }
 else if (euid == root_uid)
   {
   int sock[2];
   if (socketpair(AF_UNIX, SOCK_STREAM, 0, sock) == 0)
     {
-    const pid_t pid = exim_fork(US"logfile-open");
+    const pid_t pid = fork();
     if (pid == 0)
       {
       (void)close(sock[0]);
-      if (setgroups(1, &exim_gid) != 0) _exit(EXIT_FAILURE);
-      if (setgid(exim_gid) != 0) _exit(EXIT_FAILURE);
-      if (setuid(exim_uid) != 0) _exit(EXIT_FAILURE);
+      if (  setgroups(1, &exim_gid) != 0
+         || setgid(exim_gid) != 0
+         || setuid(exim_uid) != 0
 
-      if (getuid() != exim_uid || geteuid() != exim_uid) _exit(EXIT_FAILURE);
-      if (getgid() != exim_gid || getegid() != exim_gid) _exit(EXIT_FAILURE);
+         || getuid() != exim_uid || geteuid() != exim_uid
+         || getgid() != exim_gid || getegid() != exim_gid
 
-      fd = log_open_already_exim(name);
-      if (fd < 0) _exit(EXIT_FAILURE);
-      if (log_send_fd(sock[1], fd) != 0) _exit(EXIT_FAILURE);
+         || (fd = log_open_already_exim(name)) < 0
+         || !log_send_fd(sock[1], fd)
+        ) _exit(EXIT_FAILURE);
       (void)close(sock[1]);
       _exit(EXIT_SUCCESS);
       }
@@ -440,9 +436,7 @@ if (fd >= 0)
   if (flags != -1) (void)fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
   }
 else
-  {
   errno = EACCES;
-  }
 
 return fd;
 }
@@ -493,62 +487,53 @@ people want, I hope. */
 
 ok = string_format(buffer, sizeof(buffer), CS file_path, log_names[type]);
 
-/* Save the name of the mainlog for rollover processing. Without a datestamp,
-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. */
-
-if (type == lt_main)
-  {
-  Ustrcpy(mainlog_name, buffer);
-  if (string_datestamp_offset > 0)
-    mainlog_datestamp = mainlog_name + string_datestamp_offset;
-  }
-
-/* Ditto for the reject log */
-
-else if (type == lt_reject)
+switch (type)
   {
-  Ustrcpy(rejectlog_name, buffer);
-  if (string_datestamp_offset > 0)
-    rejectlog_datestamp = rejectlog_name + string_datestamp_offset;
-  }
-
-/* and deal with the debug log (which keeps the datestamp, but does not
-update it) */
-
-else if (type == lt_debug)
-  {
-  Ustrcpy(debuglog_name, buffer);
-  if (tag)
-    {
-    /* this won't change the offset of the datestamp */
-    ok2 = string_format(buffer, sizeof(buffer), "%s%s",
-      debuglog_name, tag);
-    if (ok2)
-      Ustrcpy(debuglog_name, buffer);
-    }
-  }
-
-/* 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. */
-
-else if (string_datestamp_offset >= 0)
-  {
-  uschar * from = buffer + string_datestamp_offset;
-  uschar * to = from + string_datestamp_length;
+  case lt_main:
+    /* Save the name of the mainlog for rollover processing. Without a datestamp,
+    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;
+  case lt_reject:
+    /* Ditto for the reject log */
+    Ustrcpy(rejectlog_name, buffer);
+    if (string_datestamp_offset > 0)
+      rejectlog_datestamp = rejectlog_name + string_datestamp_offset;
+  case lt_debug:
+    /* and deal with the debug log (which keeps the datestamp, but does not
+    update it) */
+    Ustrcpy(debuglog_name, buffer);
+    if (tag)
+      {
+      /* this won't change the offset of the datestamp */
+      ok2 = string_format(buffer, sizeof(buffer), "%s%s",
+        debuglog_name, tag);
+      if (ok2)
+        Ustrcpy(debuglog_name, buffer);
+      }
+  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;
+      uschar * to = from + string_datestamp_length;
 
-  if (from == buffer || from[-1] == '/')
-    {
-    if (!isalnum(*to)) to++;
-    }
-  else
-    if (!isalnum(from[-1])) from--;
+      if (from == buffer || from[-1] == '/')
+        {
+        if (!isalnum(*to)) to++;
+        }
+      else
+        if (!isalnum(from[-1])) from--;
 
-  /* This copy is ok, because we know that to is a substring of from. But
-  due to overlap we must use memmove() not Ustrcpy(). */
-  memmove(from, to, Ustrlen(to)+1);
+      /* This copy is ok, because we know that to is a substring of from. But
+      due to overlap we must use memmove() not Ustrcpy(). */
+      memmove(from, to, Ustrlen(to)+1);
+      }
   }
 
 /* If the file name is too long, it is an unrecoverable disaster */
@@ -716,18 +701,36 @@ return total_written;
 }
 
 
-
-static void
-set_file_path(void)
+void
+set_file_path(BOOL *multiple)
 {
+uschar *s;
 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)))
+uschar *ss = *log_file_path ? log_file_path : LOG_FILE_PATH;
+
+logging_mode = 0;
+while ((s = string_nextinlist(&ss, &sep, log_buffer, LOG_BUFFER_SIZE)))
   {
-  if (Ustrcmp(t, "syslog") == 0 || t[0] == 0) continue;
-  file_path = string_copy(t);
-  break;
+  if (Ustrcmp(s, "syslog") == 0)
+    logging_mode |= LOG_MODE_SYSLOG;
+  else if (logging_mode & LOG_MODE_FILE)  /* we know a file already */
+    {
+    if (multiple) *multiple = TRUE;
+    }
+  else
+    {
+    logging_mode |= LOG_MODE_FILE;
+
+    /* If a non-empty path is given, use it */
+
+    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
+    log_file_path may have been set at runtime. If there is no such item,
+    use the ultimate default in the spool directory. */
+    }
   }
 }
 
@@ -735,7 +738,11 @@ while ((t = string_nextinlist(&tt, &sep, log_buffer, LOG_BUFFER_SIZE)))
 void
 mainlog_close(void)
 {
-if (mainlogfd < 0) return;
+/* avoid closing it if it is closed already or if we do not see a chance
+to open the file mainlog later again */
+if (mainlogfd < 0 /* already closed */
+   || !(geteuid() == 0 || geteuid() == exim_uid))
+  return;
 (void)close(mainlogfd);
 mainlogfd = -1;
 mainlog_inode = 0;
@@ -850,38 +857,7 @@ 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)
-    {
-    int sep = ':';              /* Fixed separator - outside use */
-    uschar *s;
-    const uschar *ss = 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)
-       multiple = TRUE;
-      else
-        {
-        logging_mode |= LOG_MODE_FILE;
-
-        /* If a non-empty path is given, use it */
-
-        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
-        log_file_path may have been set at runtime. If there is no such item,
-        use the ultimate default in the spool directory. */
-
-        else
-         set_file_path();  /* Empty item in log_file_path */
-        }    /* First non-syslog item in log_file_path */
-      }      /* Scan of log_file_path */
-    }
+  if (*log_file_path) set_file_path(&multiple);
 
   /* If no modes have been selected, it is a major disaster */
 
@@ -1499,7 +1475,7 @@ if (opts)
 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();
+if (!*file_path) set_file_path(NULL);
 
 open_log(&fd, lt_debug, tag_name);
 
@@ -1521,5 +1497,12 @@ debug_file = NULL;
 unlink_log(lt_debug);
 }
 
+void
+open_logs(const char *m)
+{
+set_file_path(NULL);
+open_log(&mainlogfd, lt_main, 0);
+open_log(&rejectlogfd, lt_reject, 0);
+}
 
 /* End of log.c */