labelled-process fork function
authorJeremy Harris <jgh146exb@wizmail.org>
Sun, 15 Mar 2020 17:34:02 +0000 (17:34 +0000)
committerJeremy Harris <jgh146exb@wizmail.org>
Sun, 15 Mar 2020 17:34:02 +0000 (17:34 +0000)
20 files changed:
src/src/child.c
src/src/daemon.c
src/src/deliver.c
src/src/exim.c
src/src/functions.h
src/src/globals.c
src/src/globals.h
src/src/local_scan.h
src/src/log.c
src/src/moan.c
src/src/queue.c
src/src/rda.c
src/src/route.c
src/src/sieve.c
src/src/smtp_in.c
src/src/tls.c
src/src/transport.c
src/src/transports/autoreply.c
src/src/transports/pipe.c
src/src/transports/smtp.c

index c5054b6..f6d44e1 100644 (file)
@@ -185,13 +185,15 @@ to exist, even if all calls from within Exim are changed, because it is
 documented for use from local_scan().
 
 Argument: fdptr   pointer to int for the stdin fd
+         purpose of the child process, for debug
 Returns:          pid of the created process or -1 if anything has gone wrong
 */
 
 pid_t
-child_open_exim(int *fdptr)
+child_open_exim_function(int * fdptr, const uschar * purpose)
 {
-return child_open_exim2(fdptr, US"<>", bounce_sender_authentication);
+return child_open_exim2_function(fdptr, US"<>", bounce_sender_authentication,
+  purpose);
 }
 
 
@@ -202,12 +204,14 @@ Arguments:
   fdptr                   pointer to int for the stdin fd
   sender                  for a sender address (data for -f)
   sender_authentication   authenticated sender address or NULL
+  purpose                of the child process, for debug
 
 Returns:          pid of the created process or -1 if anything has gone wrong
 */
 
 pid_t
-child_open_exim2(int *fdptr, uschar *sender, uschar *sender_authentication)
+child_open_exim2_function(int * fdptr, uschar * sender,
+  uschar * sender_authentication, const uschar * purpose)
 {
 int pfd[2];
 int save_errno;
@@ -220,7 +224,7 @@ on the wait. */
 
 if (pipe(pfd) != 0) return (pid_t)(-1);
 oldsignal = signal(SIGCHLD, SIG_DFL);
-pid = fork();
+pid = exim_fork(purpose);
 
 /* Child process: make the reading end of the pipe into the standard input and
 close the writing end. If debugging, pass debug_fd as stderr. Then re-exec
@@ -337,7 +341,7 @@ that the child process can be waited for. We sometimes get here with it set
 otherwise. Save the old state for resetting on the wait. */
 
 oldsignal = signal(SIGCHLD, SIG_DFL);
-pid = fork();
+pid = exim_fork(US"queryprogram");     /* queryprogram tpt is sole caller */
 
 /* Handle the child process. First, set the required environment. We must do
 this before messing with the pipes, in order to be able to write debugging
index aa36a5d..a1ef1f9 100644 (file)
@@ -367,7 +367,7 @@ if (LOGGING(smtp_connection))
 expansion above did a lookup. */
 
 search_tidyup();
-pid = fork();
+pid = exim_fork(US"daemon accept");
 
 /* Handle the child process */
 
@@ -663,7 +663,7 @@ if (pid == 0)
 
       mac_smtp_fflush();
 
-      if ((dpid = fork()) == 0)
+      if ((dpid = exim_fork(US"daemon-accept delivery")) == 0)
         {
         (void)fclose(smtp_in);
         (void)fclose(smtp_out);
@@ -981,7 +981,7 @@ if (daemon_notifier_fd >= 0)
 
 if (f.running_in_test_harness || write_pid)
   {
-  if ((pid = fork()) == 0)
+  if ((pid = exim_fork(US"daemon del pidfile")) == 0)
     {
     if (override_pid_file_path)
       (void)child_exec_exim(CEE_EXEC_PANIC, FALSE, NULL, FALSE, 3,
@@ -1601,7 +1601,7 @@ if (f.background_daemon)
 
   if (getppid() != 1)
     {
-    pid_t pid = fork();
+    pid_t pid = exim_fork(US"daemon");
     if (pid < 0) log_write(0, LOG_MAIN|LOG_PANIC_DIE,
       "fork() failed when starting daemon: %s", strerror(errno));
     if (pid > 0) exit(EXIT_SUCCESS);      /* in parent process, just exit */
@@ -2130,7 +2130,7 @@ for (;;)
       if (queue_interval > 0 &&
          (local_queue_run_max <= 0 || queue_run_count < local_queue_run_max))
         {
-        if ((pid = fork()) == 0)
+        if ((pid = exim_fork(US"queue runner")) == 0)
           {
           DEBUG(D_any) debug_printf("Starting queue-runner: pid %d\n",
             (int)getpid());
index 5c5167b..5d825cd 100644 (file)
@@ -2268,7 +2268,7 @@ a clean slate and doesn't interfere with the parent process. */
 
 search_tidyup();
 
-if ((pid = fork()) == 0)
+if ((pid = exim_fork(US"delivery (local)")) == 0)
   {
   BOOL replicate = TRUE;
 
@@ -2615,7 +2615,7 @@ if (addr->special_action == SPECIAL_WARN && addr->transport->warn_message)
       "message for %s transport): %s", addr->transport->warn_message,
       addr->transport->name, expand_string_message);
 
-  else if ((pid = child_open_exim(&fd)) > 0)
+  else if ((pid = child_open_exim(&fd, US"warning message")) > 0)
     {
     FILE *f = fdopen(fd, "wb");
     if (errors_reply_to && !contains_header(US"Reply-To", warn_message))
@@ -4647,7 +4647,7 @@ all pipes, so I do not see a reason to use non-blocking IO here
   search_tidyup();
 
   DEBUG(D_deliver) debug_printf("forking transport process\n");
-  if ((pid = fork()) == 0)
+  if ((pid = exim_fork(US"transport")) == 0)
     {
     int fd = pfd[pipe_write];
     host_item *h;
@@ -7336,7 +7336,7 @@ if (addr_senddsn)
   int fd;
 
   /* create exim process to send message */
-  pid = child_open_exim(&fd);
+  pid = child_open_exim(&fd, US"DSN");
 
   DEBUG(D_deliver) debug_printf("DSN: child_open_exim returns: %d\n", pid);
 
@@ -7537,7 +7537,7 @@ while (addr_failed)
 
     /* Make a subprocess to send a message */
 
-    if ((pid = child_open_exim(&fd)) < 0)
+    if ((pid = child_open_exim(&fd, US"bounce message")) < 0)
       log_write(0, LOG_MAIN|LOG_PANIC_DIE, "Process %d (parent %d) failed to "
         "create child process to send failure message: %s", getpid(),
         getppid(), strerror(errno));
@@ -8195,7 +8195,7 @@ else if (addr_defer != (address_item *)(+1))
       {
       header_line *h;
       int fd;
-      pid_t pid = child_open_exim(&fd);
+      pid_t pid = child_open_exim(&fd, US"delay-warning message");
 
       if (pid > 0)
         {
@@ -8583,7 +8583,7 @@ if (cutthrough.cctx.sock >= 0 && cutthrough.callout_hold_only)
       goto fail;
 
     where = US"fork";
-    if ((pid = fork()) < 0)
+    if ((pid = exim_fork(US"tls-proxy interproc")) < 0)
       goto fail;
 
     else if (pid == 0)         /* child: fork again to totally disconnect */
index 4e4b6bb..6bde8fd 100644 (file)
@@ -4608,7 +4608,7 @@ if (msg_action_arg > 0 && msg_action != MSG_LOAD)
     pid_t pid;
     if (i == argc - 1)
       (void)deliver_message(argv[i], forced_delivery, deliver_give_up);
-    else if ((pid = fork()) == 0)
+    else if ((pid = exim_fork(US"cmdline-delivery")) == 0)
       {
       (void)deliver_message(argv[i], forced_delivery, deliver_give_up);
       exim_underbar_exit(EXIT_SUCCESS, US"cmdline-delivery");
@@ -5694,7 +5694,7 @@ while (more)
     pid_t pid;
     search_tidyup();
 
-    if ((pid = fork()) == 0)
+    if ((pid = exim_fork(US"local-accept delivery")) == 0)
       {
       int rc;
       close_unwanted();      /* Close unwanted file descriptors and TLS */
index 042006f..9e71d0c 100644 (file)
@@ -150,6 +150,9 @@ extern void    bits_set(unsigned int *, size_t, int *);
 extern void    cancel_cutthrough_connection(BOOL, const uschar *);
 extern int     check_host(void *, const uschar *, const uschar **, uschar **);
 extern uschar **child_exec_exim(int, BOOL, int *, BOOL, int, ...);
+extern pid_t   child_open_exim_function(int *, const uschar *);
+extern pid_t   child_open_exim2_function(int *, uschar *, uschar *,
+                const uschar *);
 extern pid_t   child_open_uid(const uschar **, const uschar **, int,
                 uid_t *, gid_t *, int *, int *, uschar *, BOOL);
 extern BOOL    cleanup_environment(void);
@@ -1108,6 +1111,21 @@ errno = EACCES;
 return NULL;
 }
 
+/******************************************************************************/
+/* Process manipulation */
+
+static inline pid_t
+exim_fork(const unsigned char * purpose)
+{
+pid_t pid = fork();
+if (pid == 0) process_purpose = purpose;
+return pid;
+}
+
+#define child_open_exim(p, r)        child_open_exim_function((p), (r))
+#define child_open_exim2(p, s, a, r) child_open_exim2_function((p), (s), (a), (r))
+
+/******************************************************************************/
 #endif /* !MACRO_PREDEF */
 
 #endif  /* _FUNCTIONS_H_ */
index a771f11..28e78d4 100644 (file)
@@ -1188,6 +1188,7 @@ uschar *primary_hostname       = NULL;
 uschar *process_info;
 int     process_info_len       = 0;
 uschar *process_log_path       = NULL;
+const uschar *process_purpose  = US"fresh exec";
 
 #if defined(SUPPORT_PROXY) || defined(SUPPORT_SOCKS)
 uschar *hosts_proxy            = NULL;
index 28d170c..c922274 100644 (file)
@@ -771,6 +771,7 @@ extern BOOL    print_topbitchars;      /* Topbit chars are printing chars */
 extern uschar *process_info;           /* For SIGUSR1 output */
 extern int     process_info_len;
 extern uschar *process_log_path;       /* Alternate path */
+extern const uschar *process_purpose;  /* for debug output */
 extern BOOL    prod_requires_admin;    /* TRUE if prodding requires admin */
 
 #if defined(SUPPORT_PROXY) || defined(SUPPORT_SOCKS)
index 206a843..bb131d3 100644 (file)
@@ -31,6 +31,21 @@ settings, and the store functions. */
 #include "store.h"
 
 
+/* Some people (Marc Merlin et al) are maintaining a patch that allows for
+dynamic local_scan() libraries. This code is not yet in Exim proper, but it
+helps the maintainers if we keep their ABI version numbers here. This may
+mutate into more general support later. The major number is increased when the
+ABI is changed in a non backward compatible way. The minor number is increased
+each time a new feature is added (in a way that doesn't break backward
+compatibility). */
+
+#define LOCAL_SCAN_ABI_VERSION_MAJOR 4
+#define LOCAL_SCAN_ABI_VERSION_MINOR 1
+#define LOCAL_SCAN_ABI_VERSION \
+  LOCAL_SCAN_ABI_VERSION_MAJOR.LOCAL_SCAN_ABI_VERSION_MINOR
+
+
+
 /* The function and its return codes. */
 
 extern int local_scan(int, uschar **);
@@ -99,19 +114,6 @@ the name of the data file to be present in the first line. */
 
 #define SPOOL_DATA_START_OFFSET (MESSAGE_ID_LENGTH+3)
 
-/* Some people (Marc Merlin et al) are maintaining a patch that allows for
-dynamic local_scan() libraries. This code is not yet in Exim proper, but it
-helps the maintainers if we keep their ABI version numbers here. This may
-mutate into more general support later. The major number is increased when the
-ABI is changed in a non backward compatible way. The minor number is increased
-each time a new feature is added (in a way that doesn't break backward
-compatibility). */
-
-#define LOCAL_SCAN_ABI_VERSION_MAJOR 4
-#define LOCAL_SCAN_ABI_VERSION_MINOR 0
-#define LOCAL_SCAN_ABI_VERSION \
-  LOCAL_SCAN_ABI_VERSION_MAJOR.LOCAL_SCAN_ABI_VERSION_MINOR
-
 /* Structure definitions that are documented as visible in the function. */
 
 typedef struct header_line {
@@ -180,8 +182,6 @@ extern BOOL    smtp_input;             /* TRUE if input is via SMTP */
 
 extern int     child_close(pid_t, int);
 extern pid_t   child_open(uschar **, uschar **, int, int *, int *, BOOL);
-extern pid_t   child_open_exim(int *);
-extern pid_t   child_open_exim2(int *, uschar *, uschar *);
 extern void    debug_printf(const char *, ...) PRINTF_FUNCTION(1,2);
 extern uschar *expand_string(uschar *);
 extern void    header_add(int, const char *, ...);
@@ -223,10 +223,14 @@ with the original name. */
 # define string_copy(s) string_copy_function(s)
 # define string_copyn(s, n) string_copyn_function((s), (n))
 # define string_copy_taint(s, t) string_copy_taint_function((s), (t))
+# define child_open_exim(p)        child_open_exim_function((p), US"from local_scan")
+# define child_open_exim2(p, s, a) child_open_exim2_function((p), (s), (a), US"from local_scan")
 
 extern uschar * string_copy_function(const uschar *);
 extern uschar * string_copyn_function(const uschar *, int n);
 extern uschar * string_copy_taint_function(const uschar *, BOOL tainted);
+extern pid_t    child_open_exim_function(int *, const uschar *);
+extern pid_t    child_open_exim2_function(int *, uschar *, uschar *, const uschar *);
 #endif
 
 /* End of local_scan.h */
index e2543a7..e80c177 100644 (file)
@@ -313,7 +313,7 @@ Returns:       a file descriptor, or < 0 on failure (errno set)
 int
 log_create_as_exim(uschar *name)
 {
-pid_t pid = fork();
+pid_t pid = exim_fork(US"logfile create");
 int status = 1;
 int fd = -1;
 
index 31d033c..51f5da5 100644 (file)
@@ -160,15 +160,16 @@ if (  ident == ERRMESS_DMARC_FORENSIC
    && (s2 = expand_string(string_sprintf("${address:%s}", s)))
    && *s2
    )
-  pid = child_open_exim2(&fd, s2, bounce_sender_authentication);
+  pid = child_open_exim2(&fd, s2, bounce_sender_authentication,
+               US"moan_send_message");
 else
   {
   s = NULL;
-  pid = child_open_exim(&fd);
+  pid = child_open_exim(&fd, US"moan_send_message");
   }
 
 #else
-pid = child_open_exim(&fd);
+pid = child_open_exim(&fd, US"moan_send_message");
 #endif
 
 if (pid < 0)
@@ -584,7 +585,7 @@ moan_tell_someone(uschar *who, address_item *addr,
 FILE *f;
 va_list ap;
 int fd;
-int pid = child_open_exim(&fd);
+int pid = child_open_exim(&fd, US"moan_tell_someone");
 
 if (pid < 0)
   {
@@ -820,7 +821,7 @@ if (!(s = expand_string(syntax_errors_to)))
 /* If we can't create a process to send the message, just forget about
 it. */
 
-pid = child_open_exim(&fd);
+pid = child_open_exim(&fd, US"moan_skipped_syntax_errors");
 
 if (pid < 0)
   {
index c9ac84b..2b64f52 100644 (file)
@@ -497,7 +497,7 @@ for (int i = queue_run_in_order ? -1 : 0;
       else
        for (i = 0; qpid[i]; ) i++;
       DEBUG(D_queue_run) debug_printf("q2stage forking\n");
-      if ((qpid[i] = fork()))
+      if ((qpid[i] = exim_fork(US"qrun phase one")))
        continue;       /* parent loops around */
       DEBUG(D_queue_run) debug_printf("q2stage child\n");
       }
@@ -651,7 +651,7 @@ for (int i = queue_run_in_order ? -1 : 0;
 #endif
 
 single_item_retry:
-    if ((pid = fork()) == 0)
+    if ((pid = exim_fork(US"qrun delivery")) == 0)
       {
       int rc;
       testharness_pause_ms(100);
index 547a8bf..85791c2 100644 (file)
@@ -615,7 +615,7 @@ with the parent process. */
 oldsignal = signal(SIGCHLD, SIG_DFL);
 search_tidyup();
 
-if ((pid = fork()) == 0)
+if ((pid = exim_fork(US"router interpret")) == 0)
   {
   header_line *waslast = header_last;   /* Save last header */
 
index fd3cb3e..6226b06 100644 (file)
@@ -736,7 +736,7 @@ while ((check = string_nextinlist(&listptr, &sep, buffer, sizeof(buffer))))
     otherwise. Save the old state for resetting on the wait. */
 
     oldsignal = signal(SIGCHLD, SIG_DFL);
-    pid = fork();
+    pid = exim_fork(US"require-files");
 
     /* If fork() fails, reinstate the original error and behave as if
     this block of code were not present. This is the same behaviour as happens
index 5e8d1e6..e07b7da 100644 (file)
@@ -3084,7 +3084,8 @@ while (*filter->pc)
             {
             int pid, fd;
 
-            if ((pid = child_open_exim2(&fd,envelope_from,envelope_from))>=1)
+            if ((pid = child_open_exim2(&fd, envelope_from, envelope_from,
+                       US"sieve-notify")) >= 1)
               {
               FILE *f;
               uschar *buffer;
@@ -3092,7 +3093,8 @@ while (*filter->pc)
 
               f = fdopen(fd, "wb");
               fprintf(f,"From: %s\n", from.length == -1
-               ? expand_string(US"$local_part_prefix$local_part$local_part_suffix@$domain") : from.character);
+               ? expand_string(US"$local_part_prefix$local_part$local_part_suffix@$domain")
+               : from.character);
               for (string_item * p = recipient; p; p=p->next)
                fprintf(f,"To: %s\n",p->text);
               fprintf(f,"Auto-Submitted: auto-notified; %s\n",filter->enotify_mailto_owner);
@@ -3103,9 +3105,11 @@ while (*filter->pc)
                 message.length=Ustrlen(message.character);
                 }
               /* Allocation is larger than necessary, but enough even for split MIME words */
-              buffer_capacity=32+4*message.length;
+              buffer_capacity = 32 + 4*message.length;
               buffer=store_get(buffer_capacity, TRUE);
-              if (message.length!=-1) fprintf(f,"Subject: %s\n",parse_quote_2047(message.character, message.length, US"utf-8", buffer, buffer_capacity, TRUE));
+              if (message.length != -1)
+               fprintf(f, "Subject: %s\n", parse_quote_2047(message.character,
+                 message.length, US"utf-8", buffer, buffer_capacity, TRUE));
               fprintf(f,"\n");
               if (body.length>0) fprintf(f,"%s\n",body.character);
               fflush(f);
@@ -3113,27 +3117,17 @@ while (*filter->pc)
               (void)child_close(pid, 0);
               }
             }
-          if ((filter_test != FTEST_NONE && debug_selector != 0) || (debug_selector & D_filter) != 0)
-            {
+          if ((filter_test != FTEST_NONE && debug_selector != 0) || debug_selector & D_filter)
             debug_printf("Notification to `%s': '%s'.\n",method.character,message.length!=-1 ? message.character : CUS "");
-            }
 #endif
           }
         else
-          {
-          if ((filter_test != FTEST_NONE && debug_selector != 0) || (debug_selector & D_filter) != 0)
-            {
+          if ((filter_test != FTEST_NONE && debug_selector != 0) || debug_selector & D_filter)
             debug_printf("Repeated notification to `%s' ignored.\n",method.character);
-            }
-          }
         }
       else
-        {
-        if ((filter_test != FTEST_NONE && debug_selector != 0) || (debug_selector & D_filter) != 0)
-          {
+        if ((filter_test != FTEST_NONE && debug_selector != 0) || debug_selector & D_filter)
           debug_printf("Ignoring notification, triggering message contains Auto-submitted: field.\n");
-          }
-        }
       }
     }
 #endif
index 66f752d..b5f44f5 100644 (file)
@@ -5759,7 +5759,7 @@ while (done <= 0)
 
       oldsignal = signal(SIGCHLD, SIG_IGN);
 
-      if ((pid = fork()) == 0)
+      if ((pid = exim_fork(US"etrn command")) == 0)
        {
        smtp_input = FALSE;       /* This process is not associated with the */
        (void)fclose(smtp_in);    /* SMTP call any more. */
@@ -5770,7 +5770,8 @@ while (done <= 0)
        /* If not serializing, do the exec right away. Otherwise, fork down
        into another process. */
 
-       if (!smtp_etrn_serialize || (pid = fork()) == 0)
+       if (  !smtp_etrn_serialize 
+          || (pid = exim_fork(US"etrn serialised command")) == 0)
          {
          DEBUG(D_exec) debug_print_argv(argv);
          exim_nullstd();                   /* Ensure std{in,out,err} exist */
index a0cfcbf..2f9faa3 100644 (file)
@@ -441,7 +441,7 @@ else if (!nowarn && !tls_certificate)
 oldsignal = signal(SIGCHLD, SIG_DFL);
 
 fflush(NULL);
-if ((pid = fork()) < 0)
+if ((pid = exim_fork(US"cipher validate")) < 0)
   log_write(0, LOG_MAIN|LOG_PANIC_DIE, "fork failed for TLS check");
 
 if (pid == 0)
index 3eb1c80..d92ad4c 100644 (file)
@@ -1248,7 +1248,7 @@ via a(nother) pipe. While writing to the filter, we do not do the CRLF,
 smtp dots, or check string processing. */
 
 if (pipe(pfd) != 0) goto TIDY_UP;      /* errno set */
-if ((write_pid = fork()) == 0)
+if ((write_pid = exim_fork(US"transport filter")) == 0)
   {
   BOOL rc;
   (void)close(fd_read);
@@ -1954,14 +1954,14 @@ int status;
 
 DEBUG(D_transport) debug_printf("transport_pass_socket entered\n");
 
-if ((pid = fork()) == 0)
+if ((pid = exim_fork(US"continued-transport interproc")) == 0)
   {
   /* Disconnect entirely from the parent process. If we are running in the
   test harness, wait for a bit to allow the previous process time to finish,
   write the log, etc., so that the output is always in the same order for
   automatic comparison. */
 
-  if ((pid = fork()) != 0)
+  if ((pid = exim_fork(US"continued-transport")) != 0)
     {
     DEBUG(D_transport) debug_printf("transport_pass_socket succeeded (final-pid %d)\n", pid);
     _exit(EXIT_SUCCESS);
index 4b5ef8e..2b487b4 100644 (file)
@@ -567,12 +567,10 @@ if (file)
 
 /* Make a subprocess to send the message */
 
-pid = child_open_exim(&fd);
-
-/* Creation of child failed; defer this delivery. */
-
-if (pid < 0)
+if ((pid = child_open_exim(&fd, US"autoreply")) < 0)
   {
+  /* Creation of child failed; defer this delivery. */
+
   addr->transport_return = DEFER;
   addr->basic_errno = errno;
   addr->message = string_sprintf("Failed to create child process to send "
index ca22f26..83272d8 100644 (file)
@@ -737,7 +737,7 @@ tctx.u.fd = fd_in;
 
 /* Now fork a process to handle the output that comes down the pipe. */
 
-if ((outpid = fork()) < 0)
+if ((outpid = exim_fork(US"pipe-transport output")) < 0)
   {
   addr->basic_errno = errno;
   addr->transport_return = DEFER;
index 6f99909..459110b 100644 (file)
@@ -3284,7 +3284,7 @@ int max_fd = MAX(pfd[0], tls_out.active.sock) + 1;
 int rc, i;
 
 close(pfd[1]);
-if ((rc = fork()))
+if ((rc = exim_fork(US"tls proxy")))
   {
   DEBUG(D_transport) debug_printf("proxy-proc final-pid %d\n", rc);
   _exit(rc < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
@@ -4279,7 +4279,7 @@ propagate it from the initial
 #ifndef DISABLE_TLS
        if (tls_out.active.sock >= 0)
          {
-         int pid = fork();
+         int pid = exim_fork(US"tls proxy interproc");
          if (pid == 0)         /* child; fork again to disconnect totally */
            {
            testharness_pause_ms(100); /* let parent debug out */