Added log selector +smtp_no_mail to log when no MAIL is issued (for
[exim.git] / src / src / daemon.c
index 21d11102381921d9c9ecfc367589117894a257fd..81c32020e7ba4debe136c730e45deb38503e31f9 100644 (file)
@@ -1,10 +1,10 @@
-/* $Cambridge: exim/src/src/daemon.c,v 1.10 2005/03/15 14:09:12 ph10 Exp $ */
+/* $Cambridge: exim/src/src/daemon.c,v 1.20 2007/01/15 15:59:22 ph10 Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
-/* Copyright (c) University of Cambridge 1995 - 2005 */
+/* Copyright (c) University of Cambridge 1995 - 2007 */
 /* See the file NOTICE for conditions of use and distribution. */
 
 /* Functions concerned with running Exim as a daemon */
@@ -186,13 +186,14 @@ if (smtp_in == NULL)
   goto ERROR_RETURN;
   }
 
-/* Get the data for the local interface address. */
+/* Get the data for the local interface address. Panic for most errors, but
+"connection reset by peer" just means the connection went away. */
 
 if (getsockname(accept_socket, (struct sockaddr *)(&interface_sockaddr),
      &ifsize) < 0)
   {
-  log_write(0, LOG_MAIN|LOG_PANIC, "getsockname() failed: %s",
-    strerror(errno));
+  log_write(0, LOG_MAIN | ((errno == ECONNRESET)? 0 : LOG_PANIC),
+    "getsockname() failed: %s", strerror(errno));
   smtp_printf("421 Local problem: getsockname() failed; please try again later\r\n");
   goto ERROR_RETURN;
   }
@@ -419,7 +420,7 @@ if (pid == 0)
   extensive comment before the reception loop in exim.c for a fuller
   explanation of this logic. */
 
-  for (i = 0; i < listen_socket_count; i++) close(listen_sockets[i]);
+  for (i = 0; i < listen_socket_count; i++) (void)close(listen_sockets[i]);
 
   #ifdef SA_NOCLDWAIT
   act.sa_handler = SIG_IGN;
@@ -499,6 +500,7 @@ if (pid == 0)
       if (!ok)                            /* Connection was dropped */
         {
         mac_smtp_fflush();
+        smtp_log_no_mail();               /* Log no mail if configured */
         _exit(EXIT_SUCCESS);
         }
       if (message_id[0] == 0) continue;   /* No message was accepted */
@@ -507,6 +509,7 @@ if (pid == 0)
       {
       mac_smtp_fflush();
       search_tidyup();
+      smtp_log_no_mail();                 /* Log no mail if configured */
       _exit((rc == 0)? EXIT_SUCCESS : EXIT_FAILURE);
       }
 
@@ -603,8 +606,8 @@ if (pid == 0)
 
       if ((dpid = fork()) == 0)
         {
-        fclose(smtp_in);
-        fclose(smtp_out);
+        (void)fclose(smtp_in);
+        (void)fclose(smtp_out);
 
         /* Don't ever molest the parent's SSL connection, but do clean up
         the data structures if necessary. */
@@ -680,27 +683,28 @@ ERROR_RETURN:
 /* Close the streams associated with the socket which will also close the
 socket fds in this process. We can't do anything if fclose() fails, but
 logging brings it to someone's attention. However, "connection reset by peer"
-isn't really a problem, so skip that one. If the streams don't exist, something
-went wrong while setting things up. Make sure the socket descriptors are
-closed, in order to drop the connection. */
+isn't really a problem, so skip that one. On Solaris, a dropped connection can
+manifest itself as a broken pipe, so drop that one too. If the streams don't
+exist, something went wrong while setting things up. Make sure the socket
+descriptors are closed, in order to drop the connection. */
 
 if (smtp_out != NULL)
   {
-  if (fclose(smtp_out) != 0 && errno != ECONNRESET)
+  if (fclose(smtp_out) != 0 && errno != ECONNRESET && errno != EPIPE)
     log_write(0, LOG_MAIN|LOG_PANIC, "daemon: fclose(smtp_out) failed: %s",
       strerror(errno));
   smtp_out = NULL;
   }
-else close(accept_socket);
+else (void)close(accept_socket);
 
 if (smtp_in != NULL)
   {
-  if (fclose(smtp_in) != 0 && errno != ECONNRESET)
+  if (fclose(smtp_in) != 0 && errno != ECONNRESET && errno != EPIPE)
     log_write(0, LOG_MAIN|LOG_PANIC, "daemon: fclose(smtp_in) failed: %s",
       strerror(errno));
   smtp_in = NULL;
   }
-else close(dup_accept_socket);
+else (void)close(dup_accept_socket);
 
 /* Release any store used in this process, including the store used for holding
 the incoming host address and an expanded active_hostname. */
@@ -1208,9 +1212,9 @@ if (background_daemon)
   {
   log_close_all();    /* Just in case anything was logged earlier */
   search_tidyup();    /* Just in case any were used in reading the config. */
-  close(0);           /* Get rid of stdin/stdout/stderr */
-  close(1);
-  close(2);
+  (void)close(0);           /* Get rid of stdin/stdout/stderr */
+  (void)close(1);
+  (void)close(2);
   exim_nullstd();     /* Connect stdin/stdout/stderr to /dev/null */
   log_stderr = NULL;  /* So no attempt to copy paniclog output */
 
@@ -1249,7 +1253,6 @@ if (daemon_listen)
     {
     BOOL wildcard;
     ip_address_item *ipa2;
-    int retries = 9;
     int af;
 
     if (Ustrchr(ipa->address, ':') != NULL)
@@ -1321,19 +1324,22 @@ if (daemon_listen)
         {
         DEBUG(D_any) debug_printf("wildcard IPv4 bind() failed after IPv6 "
           "listen() success; EADDRINUSE ignored\n");
-        close(listen_sockets[sk]);
+        (void)close(listen_sockets[sk]);
         goto SKIP_SOCKET;
         }
       msg = US strerror(errno);
       addr = wildcard? ((af == AF_INET6)? US"(any IPv6)" : US"(any IPv4)") :
         ipa->address;
-      if (retries-- <= 0)
+      if (daemon_startup_retries <= 0)
         log_write(0, LOG_MAIN|LOG_PANIC_DIE,
           "socket bind() to port %d for address %s failed: %s: "
           "daemon abandoned", ipa->port, addr, msg);
       log_write(0, LOG_MAIN, "socket bind() to port %d for address %s "
-        "failed: %s: waiting before trying again", ipa->port, addr, msg);
-      sleep(30);
+        "failed: %s: waiting %s before trying again (%d more %s)",
+        ipa->port, addr, msg, readconf_printtime(daemon_startup_sleep),
+        daemon_startup_retries, (daemon_startup_retries > 1)? "tries" : "try");
+      daemon_startup_retries--;
+      sleep(daemon_startup_sleep);
       }
 
     DEBUG(D_any)
@@ -1364,7 +1370,7 @@ if (daemon_listen)
 
     DEBUG(D_any) debug_printf("wildcard IPv4 listen() failed after IPv6 "
       "listen() success; EADDRINUSE ignored\n");
-    close(listen_sockets[sk]);
+    (void)close(listen_sockets[sk]);
 
     /* Come here if there has been a problem with the socket which we
     are going to ignore. We remove the address from the chain, and back up the
@@ -1412,12 +1418,11 @@ if (running_in_test_harness || write_pid)
   if (pid_file_path[0] == 0)
     pid_file_path = string_sprintf("%s/exim-daemon.pid", spool_directory);
 
-  f = Ufopen(pid_file_path, "wb");
+  f = modefopen(pid_file_path, "wb", 0644);
   if (f != NULL)
     {
-    fprintf(f, "%d\n", (int)getpid());
-    fchmod(fileno(f), 0644);
-    fclose(f);
+    (void)fprintf(f, "%d\n", (int)getpid());
+    (void)fclose(f);
     DEBUG(D_any) debug_printf("pid written to %s\n", pid_file_path);
     }
   else
@@ -1611,7 +1616,8 @@ for (;;)
 
         /* Close any open listening sockets in the child */
 
-        for (sk = 0; sk < listen_socket_count; sk++) close(listen_sockets[sk]);
+        for (sk = 0; sk < listen_socket_count; sk++)
+          (void)close(listen_sockets[sk]);
 
         /* Reset SIGHUP and SIGCHLD in the child in both cases. */
 
@@ -1625,6 +1631,8 @@ for (;;)
           {
           uschar opt[8];
           uschar *p = opt;
+          uschar *extra[4];
+          int extracount = 1;
 
           signal(SIGALRM, SIG_DFL);
           *p++ = '-';
@@ -1635,8 +1643,29 @@ for (;;)
           if (deliver_force_thaw) *p++ = 'f';
           if (queue_run_local) *p++ = 'l';
           *p = 0;
+          extra[0] = opt;
+
+          /* If -R or -S were on the original command line, ensure they get
+          passed on. */
+
+          if (deliver_selectstring != NULL)
+            {
+            extra[extracount++] = deliver_selectstring_regex? US"-Rr" : US"-R";
+            extra[extracount++] = deliver_selectstring;
+            }
+
+          if (deliver_selectstring_sender != NULL)
+            {
+            extra[extracount++] = deliver_selectstring_sender_regex?
+              US"-Sr" : US"-S";
+            extra[extracount++] = deliver_selectstring_sender;
+            }
+
+          /* Overlay this process with a new execution. */
+
+          (void)child_exec_exim(CEE_EXEC_PANIC, FALSE, NULL, TRUE, extracount,
+            extra[0], extra[1], extra[2], extra[3], extra[4]);
 
-          (void)child_exec_exim(CEE_EXEC_PANIC, FALSE, NULL, TRUE, 1, opt);
           /* Control never returns here. */
           }
 
@@ -1855,7 +1884,8 @@ for (;;)
     int sk;
     log_write(0, LOG_MAIN, "pid %d: SIGHUP received: re-exec daemon",
       getpid());
-    for (sk = 0; sk < listen_socket_count; sk++) close(listen_sockets[sk]);
+    for (sk = 0; sk < listen_socket_count; sk++)
+      (void)close(listen_sockets[sk]);
     alarm(0);
     signal(SIGHUP, SIG_IGN);
     sighup_argv[0] = exim_path;