Hurd: errno really uses more than a short-sized value. Bug 2476
[exim.git] / src / src / child.c
index 11a971fb58f4e90a1f8bcd1fb8ebbcaed096e79c..d3cd88201d46c5422588e11e894a10d4996af718 100644 (file)
@@ -1,10 +1,8 @@
-/* $Cambridge: exim/src/src/child.c,v 1.11 2007/01/08 10:50:17 ph10 Exp $ */
-
 /*************************************************
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
-/* Copyright (c) University of Cambridge 1995 - 2007 */
+/* Copyright (c) University of Cambridge 1995 - 2015 */
 /* See the file NOTICE for conditions of use and distribution. */
 
 
@@ -74,9 +72,10 @@ child_exec_exim(int exec_type, BOOL kill_v, int *pcount, BOOL minimal,
 {
 int first_special = -1;
 int n = 0;
-int extra = (pcount != NULL)? *pcount : 0;
-uschar **argv =
-  store_get((extra + acount + MAX_CLMACROS + 16) * sizeof(char *));
+int extra = pcount ? *pcount : 0;
+uschar **argv;
+
+argv = store_get((extra + acount + MAX_CLMACROS + 18) * sizeof(char *), FALSE);
 
 /* In all case, the list starts out with the path, any macros, and a changed
 config file. */
@@ -87,7 +86,7 @@ if (clmacro_count > 0)
   memcpy(argv + n, clmacros, clmacro_count * sizeof(uschar *));
   n += clmacro_count;
   }
-if (config_changed)
+if (f.config_changed)
   {
   argv[n++] = US"-C";
   argv[n++] = config_main_filename;
@@ -110,11 +109,16 @@ if (!minimal)
     if (debug_selector != 0)
       argv[n++] = string_sprintf("-d=0x%x", debug_selector);
     }
-  if (dont_deliver) argv[n++] = US"-N";
-  if (queue_smtp) argv[n++] = US"-odqs";
-  if (synchronous_delivery) argv[n++] = US"-odi";
+  if (f.dont_deliver) argv[n++] = US"-N";
+  if (f.queue_smtp) argv[n++] = US"-odqs";
+  if (f.synchronous_delivery) argv[n++] = US"-odi";
   if (connection_max_messages >= 0)
     argv[n++] = string_sprintf("-oB%d", connection_max_messages);
+  if (*queue_name)
+    {
+    argv[n++] = US"-MCG";
+    argv[n++] = queue_name;
+    }
   }
 
 /* Now add in any others that are in the call. Remember which they were,
@@ -143,7 +147,7 @@ if (exec_type == CEE_RETURN_ARGV)
 failure. We know that there will always be at least one extra option in the
 call when exec() is done here, so it can be used to add to the panic data. */
 
-DEBUG(D_exec) debug_print_argv(argv);
+DEBUG(D_exec) debug_print_argv(CUSS argv);
 exim_nullstd();                            /* Make sure std{in,out,err} exist */
 execv(CS argv[0], (char *const *)argv);
 
@@ -219,7 +223,7 @@ pid = fork();
 
 /* 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
-Exim with appropriat options. In the test harness, use -odi unless queue_only
+Exim with appropriate options. In the test harness, use -odi unless queue_only
 is set, so that the bounce is fully delivered before returning. Failure is
 signalled with EX_EXECFAILED (specified by CEE_EXEC_EXIT), but this shouldn't
 occur. */
@@ -229,7 +233,7 @@ if (pid == 0)
   force_fd(pfd[pipe_read], 0);
   (void)close(pfd[pipe_write]);
   if (debug_fd > 0) force_fd(debug_fd, 2);
-  if (running_in_test_harness && !queue_only)
+  if (f.running_in_test_harness && !queue_only)
     {
     if (sender_authentication != NULL)
       child_exec_exim(CEE_EXEC_EXIT, FALSE, NULL, FALSE, 9,
@@ -309,8 +313,9 @@ Returns:      the pid of the created process or -1 if anything has gone wrong
 */
 
 pid_t
-child_open_uid(uschar **argv, uschar **envp, int newumask, uid_t *newuid,
-  gid_t *newgid, int *infdptr, int *outfdptr, uschar *wd, BOOL make_leader)
+child_open_uid(const uschar **argv, const uschar **envp, int newumask,
+  uid_t *newuid, gid_t *newgid, int *infdptr, int *outfdptr, uschar *wd,
+  BOOL make_leader)
 {
 int save_errno;
 int inpfd[2], outpfd[2];
@@ -340,6 +345,7 @@ output when things go wrong. */
 if (pid == 0)
   {
   signal(SIGUSR1, SIG_IGN);
+  signal(SIGPIPE, SIG_DFL);
 
   if (newgid != NULL && setgid(*newgid) < 0)
     {
@@ -388,7 +394,7 @@ if (pid == 0)
   /* Now do the exec */
 
   if (envp == NULL) execv(CS argv[0], (char *const *)argv);
-    else execve(CS argv[0], (char *const *)argv, (char *const *)envp);
+  else execve(CS argv[0], (char *const *)argv, (char *const *)envp);
 
   /* Failed to execv. Signal this failure using EX_EXECFAILED. We are
   losing the actual errno we got back, because there is no way to return
@@ -451,8 +457,8 @@ pid_t
 child_open(uschar **argv, uschar **envp, int newumask, int *infdptr,
   int *outfdptr, BOOL make_leader)
 {
-return child_open_uid(argv, envp, newumask, NULL, NULL, infdptr, outfdptr,
-  NULL, make_leader);
+return child_open_uid(CUSS argv, CUSS envp, newumask, NULL, NULL,
+  infdptr, outfdptr, NULL, make_leader);
 }
 
 
@@ -485,7 +491,7 @@ int yield;
 if (timeout > 0)
   {
   sigalrm_seen = FALSE;
-  alarm(timeout);
+  ALARM(timeout);
   }
 
 for(;;)
@@ -495,18 +501,23 @@ for(;;)
   if (rc == pid)
     {
     int lowbyte = status & 255;
-    if (lowbyte == 0) yield = (status >> 8) & 255;
-      else yield = -lowbyte;
+    yield = lowbyte == 0 ? (status >> 8) & 255 : -lowbyte;
     break;
     }
   if (rc < 0)
     {
-    yield = (errno == EINTR && sigalrm_seen)? -256 : -257;
+    /* This "shouldn't happen" test does happen on MacOS: for some reason
+    I do not understand we seems to get an alarm signal despite not having
+    an active alarm set. There seems to be only one, so just go round again. */
+
+    if (errno == EINTR && sigalrm_seen && timeout <= 0) continue;
+
+    yield = (errno == EINTR && sigalrm_seen) ? -256 : -257;
     break;
     }
   }
 
-if (timeout > 0) alarm(0);
+if (timeout > 0) ALARM_CLR(0);
 
 signal(SIGCHLD, oldsignal);   /* restore */
 return yield;