Avoid release of store if there have been later allocations. Bug 2199
[exim.git] / src / src / exim.c
index e199279b80816fe687cee3d843984fe1c21cbcf3..d71af0ac4056768586320b24e8b00b615ae19a03 100644 (file)
@@ -2,7 +2,7 @@
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
-/* Copyright (c) University of Cambridge 1995 - 2016 */
+/* Copyright (c) University of Cambridge 1995 - 2017 */
 /* See the file NOTICE for conditions of use and distribution. */
 
 
@@ -658,12 +658,13 @@ Returns:     does not return
 */
 
 void
-exim_exit(int rc)
+exim_exit(int rc, const uschar * process)
 {
 search_tidyup();
 DEBUG(D_any)
-  debug_printf(">>>>>>>>>>>>>>>> Exim pid=%d terminating with rc=%d "
-    ">>>>>>>>>>>>>>>>\n", (int)getpid(), rc);
+  debug_printf(">>>>>>>>>>>>>>>> Exim pid=%d %s%s%sterminating with rc=%d "
+    ">>>>>>>>>>>>>>>>\n", (int)getpid(),
+    process ? "(" : "", process, process ? ") " : "", rc);
 exit(rc);
 }
 
@@ -1456,6 +1457,39 @@ return TRUE;
 }
 
 
+/*************************************************
+*          Expansion testing                    *
+*************************************************/
+
+/* Expand and print one item, doing macro-processing.
+
+Arguments:
+  item         line for expansion
+*/
+
+static void
+expansion_test_line(uschar * line)
+{
+int len;
+BOOL dummy_macexp;
+
+Ustrncpy(big_buffer, line, big_buffer_size);
+big_buffer[big_buffer_size-1] = '\0';
+len = Ustrlen(big_buffer);
+
+(void) macros_expand(0, &len, &dummy_macexp);
+
+if (isupper(big_buffer[0]))
+  {
+  if (macro_read_assignment(big_buffer))
+    printf("Defined macro '%s'\n", mlast->name);
+  }
+else
+  if ((line = expand_string(big_buffer))) printf("%s\n", CS line);
+  else printf("Failed: %s\n", expand_string_message);
+}
+
+
 /*************************************************
 *          Entry point and high-level code       *
 *************************************************/
@@ -3195,10 +3229,10 @@ for (i = 1; i < argc; i++)
     which sets the host protocol and host name */
 
     if (*argrest == 0)
-      {
-      if (i+1 < argc) argrest = argv[++i]; else
+      if (i+1 < argc)
+       argrest = argv[++i];
+      else
         { badarg = TRUE; break; }
-      }
 
     if (*argrest != 0)
       {
@@ -3212,9 +3246,7 @@ for (i = 1; i < argc; i++)
 
       hn = Ustrchr(argrest, ':');
       if (hn == NULL)
-        {
         received_protocol = argrest;
-        }
       else
         {
        int old_pool = store_pool;
@@ -3794,12 +3826,9 @@ NOTE: immediatly after opening the configuration file we change the working
 directory to "/"! Later we change to $spool_directory. We do it there, because
 during readconf_main() some expansion takes place already. */
 
-/* Store the initial cwd before we change directories */
-if ((initial_cwd = os_getcwd(NULL, 0)) == NULL)
-  {
-  perror("exim: can't get the current working directory");
-  exit(EXIT_FAILURE);
-  }
+/* Store the initial cwd before we change directories.  Can be NULL if the
+dir has already been unlinked. */
+initial_cwd = os_getcwd(NULL, 0);
 
 /* checking:
     -be[m] expansion test        -
@@ -3877,7 +3906,7 @@ else
   }
 
 /* At this point, we know if the user is privileged and some command-line
-options become possibly imperssible, depending upon the configuration file. */
+options become possibly impermissible, depending upon the configuration file. */
 
 if (checking && commandline_checks_require_admin && !admin_user) {
   fprintf(stderr, "exim: those command-line flags are set to require admin\n");
@@ -4483,7 +4512,7 @@ if (test_retry_arg >= 0)
   if (test_retry_arg >= argc)
     {
     printf("-brt needs a domain or address argument\n");
-    exim_exit(EXIT_FAILURE);
+    exim_exit(EXIT_FAILURE, US"main");
     }
   s1 = argv[test_retry_arg++];
   s2 = NULL;
@@ -4589,7 +4618,7 @@ if (test_retry_arg >= 0)
 
     printf("\n");
     }
-  exim_exit(EXIT_SUCCESS);
+  exim_exit(EXIT_SUCCESS, US"main");
   }
 
 /* Handle a request to list one or more configuration options */
@@ -4613,14 +4642,14 @@ if (list_options)
         }
       else readconf_print(argv[i], NULL, flag_n);
       }
-  exim_exit(EXIT_SUCCESS);
+  exim_exit(EXIT_SUCCESS, US"main");
   }
 
 if (list_config)
   {
   set_process_info("listing config");
   readconf_print(US"config", NULL, flag_n);
-  exim_exit(EXIT_SUCCESS);
+  exim_exit(EXIT_SUCCESS, US"main");
   }
 
 
@@ -4649,7 +4678,7 @@ if (msg_action_arg > 0 && msg_action != MSG_LOAD)
   if (prod_requires_admin && !admin_user)
     {
     fprintf(stderr, "exim: Permission denied\n");
-    exim_exit(EXIT_FAILURE);
+    exim_exit(EXIT_FAILURE, US"main");
     }
   set_process_info("delivering specified messages");
   if (deliver_give_up) forced_delivery = deliver_force_thaw = TRUE;
@@ -4668,11 +4697,11 @@ if (msg_action_arg > 0 && msg_action != MSG_LOAD)
       {
       fprintf(stderr, "failed to fork delivery process for %s: %s\n", argv[i],
         strerror(errno));
-      exim_exit(EXIT_FAILURE);
+      exim_exit(EXIT_FAILURE, US"main");
       }
     else wait(&status);
     }
-  exim_exit(EXIT_SUCCESS);
+  exim_exit(EXIT_SUCCESS, US"main");
   }
 
 
@@ -4691,7 +4720,7 @@ if (queue_interval == 0 && !daemon_listen)
   else
     set_process_info("running the queue (single queue run)");
   queue_run(start_queue_run_id, stop_queue_run_id, FALSE);
-  exim_exit(EXIT_SUCCESS);
+  exim_exit(EXIT_SUCCESS, US"main");
   }
 
 
@@ -4844,10 +4873,10 @@ if (test_rewrite_arg >= 0)
   if (test_rewrite_arg >= argc)
     {
     printf("-brw needs an address argument\n");
-    exim_exit(EXIT_FAILURE);
+    exim_exit(EXIT_FAILURE, US"main");
     }
   rewrite_test(argv[test_rewrite_arg]);
-  exim_exit(EXIT_SUCCESS);
+  exim_exit(EXIT_SUCCESS, US"main");
   }
 
 /* A locally-supplied message is considered to be coming from a local user
@@ -4962,7 +4991,7 @@ if (verify_address_mode || address_test_mode)
     }
 
   route_tidyup();
-  exim_exit(exit_value);
+  exim_exit(exit_value, US"main");
   }
 
 /* Handle expansion checking. Either expand items on the command line, or read
@@ -4992,7 +5021,7 @@ if (expansion_test)
   /* Read a test message from a file. We fudge it up to be on stdin, saving
   stdin itself for later reading of expansion strings. */
 
-  else if (expansion_test_message != NULL)
+  else if (expansion_test_message)
     {
     int save_stdin = dup(0);
     int fd = Uopen(expansion_test_message, O_RDONLY, 0);
@@ -5012,6 +5041,10 @@ if (expansion_test)
     clearerr(stdin);               /* Required by Darwin */
     }
 
+  /* Only admin users may see config-file macros this way */
+
+  if (!admin_user) macros = mlast = NULL;
+
   /* Allow $recipients for this testing */
 
   enable_dollar_recipients = TRUE;
@@ -5019,15 +5052,8 @@ if (expansion_test)
   /* Expand command line items */
 
   if (recipients_arg < argc)
-    {
     while (recipients_arg < argc)
-      {
-      uschar *s = argv[recipients_arg++];
-      uschar *ss = expand_string(s);
-      if (ss == NULL) printf ("Failed: %s\n", expand_string_message);
-      else printf("%s\n", CS ss);
-      }
-    }
+      expansion_test_line(argv[recipients_arg++]);
 
   /* Read stdin */
 
@@ -5035,25 +5061,18 @@ if (expansion_test)
     {
     char *(*fn_readline)(const char *) = NULL;
     void (*fn_addhist)(const char *) = NULL;
+    uschar * s;
 
-    #ifdef USE_READLINE
+#ifdef USE_READLINE
     void *dlhandle = set_readline(&fn_readline, &fn_addhist);
-    #endif
+#endif
 
-    for (;;)
-      {
-      uschar *ss;
-      uschar *source = get_stdinput(fn_readline, fn_addhist);
-      if (source == NULL) break;
-      ss = expand_string(source);
-      if (ss == NULL)
-        printf ("Failed: %s\n", expand_string_message);
-      else printf("%s\n", CS ss);
-      }
+    while (s = get_stdinput(fn_readline, fn_addhist))
+      expansion_test_line(s);
 
-    #ifdef USE_READLINE
-    if (dlhandle != NULL) dlclose(dlhandle);
-    #endif
+#ifdef USE_READLINE
+    if (dlhandle) dlclose(dlhandle);
+#endif
     }
 
   /* The data file will be open after -Mset */
@@ -5064,7 +5083,7 @@ if (expansion_test)
     deliver_datafile = -1;
     }
 
-  exim_exit(EXIT_SUCCESS);
+  exim_exit(EXIT_SUCCESS, US"main: expansion test");
   }
 
 
@@ -5158,7 +5177,7 @@ if (host_checking)
       }
     smtp_log_no_mail();
     }
-  exim_exit(EXIT_SUCCESS);
+  exim_exit(EXIT_SUCCESS, US"main");
   }
 
 
@@ -5322,7 +5341,7 @@ if (smtp_input)
   if (!smtp_start_session())
     {
     mac_smtp_fflush();
-    exim_exit(EXIT_SUCCESS);
+    exim_exit(EXIT_SUCCESS, US"smtp_start toplevel");
     }
   }
 
@@ -5437,14 +5456,14 @@ while (more)
        cancel_cutthrough_connection(TRUE, US"receive dropped");
         if (more) goto moreloop;
         smtp_log_no_mail();               /* Log no mail if configured */
-        exim_exit(EXIT_FAILURE);
+        exim_exit(EXIT_FAILURE, US"receive toplevel");
         }
       }
     else
       {
       cancel_cutthrough_connection(TRUE, US"message setup dropped");
       smtp_log_no_mail();               /* Log no mail if configured */
-      exim_exit((rc == 0)? EXIT_SUCCESS : EXIT_FAILURE);
+      exim_exit(rc ? EXIT_FAILURE : EXIT_SUCCESS, US"msg setup toplevel");
       }
     }
 
@@ -5495,14 +5514,12 @@ while (more)
           if (error_handling == ERRORS_STDERR)
             {
             fprintf(stderr, "exim: too many recipients\n");
-            exim_exit(EXIT_FAILURE);
+            exim_exit(EXIT_FAILURE, US"main");
             }
           else
-            {
             return
               moan_to_sender(ERRMESS_TOOMANYRECIP, NULL, NULL, stdin, TRUE)?
                 errors_sender_rc : EXIT_FAILURE;
-            }
 
 #ifdef SUPPORT_I18N
        {
@@ -5531,7 +5548,7 @@ while (more)
             {
             fprintf(stderr, "exim: bad recipient address \"%s\": %s\n",
               string_printing(list[i]), errmess);
-            exim_exit(EXIT_FAILURE);
+            exim_exit(EXIT_FAILURE, US"main");
             }
           else
             {
@@ -5604,7 +5621,7 @@ while (more)
     for real; when reading the headers of a message for filter testing,
     it is TRUE if the headers were terminated by '.' and FALSE otherwise. */
 
-    if (message_id[0] == 0) exim_exit(EXIT_FAILURE);
+    if (message_id[0] == 0) exim_exit(EXIT_FAILURE, US"main");
     }  /* Non-SMTP message reception */
 
   /* If this is a filter testing run, there are headers in store, but
@@ -5649,7 +5666,7 @@ while (more)
     if (chdir("/"))   /* Get away from wherever the user is running this from */
       {
       DEBUG(D_receive) debug_printf("chdir(\"/\") failed\n");
-      exim_exit(EXIT_FAILURE);
+      exim_exit(EXIT_FAILURE, US"main");
       }
 
     /* Now we run either a system filter test, or a user filter test, or both.
@@ -5658,20 +5675,16 @@ while (more)
     explicitly. */
 
     if ((filter_test & FTEST_SYSTEM) != 0)
-      {
       if (!filter_runtest(filter_sfd, filter_test_sfile, TRUE, more))
-        exim_exit(EXIT_FAILURE);
-      }
+        exim_exit(EXIT_FAILURE, US"main");
 
     memcpy(filter_sn, filter_n, sizeof(filter_sn));
 
     if ((filter_test & FTEST_USER) != 0)
-      {
       if (!filter_runtest(filter_ufd, filter_test_ufile, FALSE, more))
-        exim_exit(EXIT_FAILURE);
-      }
+        exim_exit(EXIT_FAILURE, US"main");
 
-    exim_exit(EXIT_SUCCESS);
+    exim_exit(EXIT_SUCCESS, US"main");
     }
 
   /* Else act on the result of message reception. We should not get here unless
@@ -5797,7 +5810,7 @@ while (more)
          log_write(0, LOG_MAIN|LOG_PANIC,
            "process %d crashed with signal %d while delivering %s",
            (int)pid, status & 0x00ff, message_id);
-       if (mua_wrapper && (status & 0xffff) != 0) exim_exit(EXIT_FAILURE);
+       if (mua_wrapper && (status & 0xffff) != 0) exim_exit(EXIT_FAILURE, US"main");
        }
       }
     }
@@ -5829,54 +5842,9 @@ moreloop:
   store_reset(reset_point);
   }
 
-exim_exit(EXIT_SUCCESS);   /* Never returns */
+exim_exit(EXIT_SUCCESS, US"main");   /* Never returns */
 return 0;                  /* To stop compiler warning */
 }
 
-/*************************************************
-*          read as much as requested             *
-*************************************************/
-
-/* The syscall read(2) doesn't always returns as much as we want. For
-several reasons it might get less. (Not talking about signals, as syscalls
-are restartable). When reading from a network or pipe connection the sender
-might send in smaller chunks, with delays between these chunks. The read(2)
-may return such a chunk.
-
-The more the writer writes and the smaller the pipe between write and read is,
-the more we get the chance of reading leass than requested. (See bug 2130)
-
-This function read(2)s until we got all the data we *requested*.
-
-Note: This function may block. Use it only if you're sure about the
-amount of data you will get.
-
-Argument:
-  fd          the file descriptor to read from
-  buffer      pointer to a buffer of size len
-  len         the requested(!) amount of bytes
-
-Returns:      the amount of bytes read
-*/
-ssize_t
-readn(int fd, void *buffer, size_t len)
-{
-  void *next = buffer;
-  void *end = buffer + len;
-
-  while (next < end)
-    {
-    ssize_t got = read(fd, next, end - next);
-
-    /* I'm not sure if there are signals that can interrupt us,
-    for now I assume the worst */
-    if (got == -1 && errno == EINTR) continue;
-    if (got <= 0) return next - buffer;
-    next += got;
-    }
-
-  return len;
-}
-
 
 /* End of exim.c */