Avoid modifying global errno when raising event
[exim.git] / src / src / deliver.c
index 4594c4a1d95a6703856e7f498f1b6edbaa0912c5..2ced28e9a70baa44a3cc0d69e640e7825c04eb95 100644 (file)
@@ -74,6 +74,7 @@ static BOOL update_spool;
 static BOOL remove_journal;
 static int  parcount = 0;
 static pardata *parlist = NULL;
+static struct pollfd *parpoll;
 static int  return_count;
 static uschar *frozen_info = US"";
 static uschar *used_return_path = NULL;
@@ -853,8 +854,18 @@ return g;
 
 
 #ifndef DISABLE_EVENT
+/* Distribute a named event to any listeners.
+
+Args:  action  config option specifying listener
+       event   name of the event
+       ev_data associated data for the event
+       errnop  pointer to errno for modification, or null
+
+Return: string expansion from listener, or NULL
+*/
+
 uschar *
-event_raise(uschar * action, const uschar * event, uschar * ev_data)
+event_raise(uschar * action, const uschar * event, uschar * ev_data, int * errnop)
 {
 uschar * s;
 if (action)
@@ -881,7 +892,8 @@ if (action)
     {
     DEBUG(D_deliver)
       debug_printf("Event(%s): event_action returned \"%s\"\n", event, s);
-    errno = ERRNO_EVENT;
+    if (errnop)
+      *errnop = ERRNO_EVENT;
     return s;
     }
   }
@@ -910,7 +922,7 @@ if (!addr->transport)
      a filter was used which triggered a fail command (in such a case
      a transport isn't needed).  Convert it to an internal fail event. */
 
-    (void) event_raise(event_action, US"msg:fail:internal", addr->message);
+    (void) event_raise(event_action, US"msg:fail:internal", addr->message, NULL);
     }
   }
 else
@@ -922,7 +934,8 @@ else
            || Ustrcmp(addr->transport->driver_name, "smtp") == 0
            || Ustrcmp(addr->transport->driver_name, "lmtp") == 0
            || Ustrcmp(addr->transport->driver_name, "autoreply") == 0
-          ? addr->message : NULL);
+          ? addr->message : NULL,
+          NULL);
   }
 
 deliver_host_port =    save_port;
@@ -2412,13 +2425,13 @@ if ((pid = exim_fork(US"delivery-local")) == 0)
     uschar *s;
     int ret;
 
-    if(  (ret = write(pfd[pipe_write], &addr2->transport_return, sizeof(int))) != sizeof(int)
+    if(  (i = addr2->transport_return, (ret = write(pfd[pipe_write], &i, sizeof(int))) != sizeof(int))
       || (ret = write(pfd[pipe_write], &transport_count, sizeof(transport_count))) != sizeof(transport_count)
       || (ret = write(pfd[pipe_write], &addr2->flags, sizeof(addr2->flags))) != sizeof(addr2->flags)
       || (ret = write(pfd[pipe_write], &addr2->basic_errno,    sizeof(int))) != sizeof(int)
       || (ret = write(pfd[pipe_write], &addr2->more_errno,     sizeof(int))) != sizeof(int)
       || (ret = write(pfd[pipe_write], &addr2->delivery_time,  sizeof(struct timeval))) != sizeof(struct timeval)
-      || (ret = write(pfd[pipe_write], &addr2->special_action, sizeof(int))) != sizeof(int)
+      || (i = addr2->special_action, (ret = write(pfd[pipe_write], &i, sizeof(int))) != sizeof(int))
       || (ret = write(pfd[pipe_write], &addr2->transport,
         sizeof(transport_instance *))) != sizeof(transport_instance *)
 
@@ -2486,7 +2499,7 @@ for (addr2 = addr; addr2; addr2 = addr2->next)
     len = read(pfd[pipe_read], &addr2->basic_errno,    sizeof(int));
     len = read(pfd[pipe_read], &addr2->more_errno,     sizeof(int));
     len = read(pfd[pipe_read], &addr2->delivery_time,  sizeof(struct timeval));
-    len = read(pfd[pipe_read], &addr2->special_action, sizeof(int));
+    len = read(pfd[pipe_read], &i, sizeof(int)); addr2->special_action = i;
     len = read(pfd[pipe_read], &addr2->transport,
       sizeof(transport_instance *));
 
@@ -3306,7 +3319,7 @@ BOOL done = p->done;
 
 /* Loop through all items, reading from the pipe when necessary. The pipe
 used to be non-blocking. But I do not see a reason for using non-blocking I/O
-here, as the preceding select() tells us, if data is available for reading.
+here, as the preceding poll() tells us, if data is available for reading.
 
 A read() on a "selected" handle should never block, but(!) it may return
 less data then we expected. (The buffer size we pass to read() shouldn't be
@@ -3840,7 +3853,7 @@ static address_item *
 par_wait(void)
 {
 int poffset, status;
-address_item *addr, *addrlist;
+address_item * addr, * addrlist;
 pid_t pid;
 
 set_process_info("delivering %s: waiting for a remote delivery subprocess "
@@ -3850,18 +3863,18 @@ set_process_info("delivering %s: waiting for a remote delivery subprocess "
 existence - in which case give an error return. We cannot proceed just by
 waiting for a completion, because a subprocess may have filled up its pipe, and
 be waiting for it to be emptied. Therefore, if no processes have finished, we
-wait for one of the pipes to acquire some data by calling select(), with a
+wait for one of the pipes to acquire some data by calling poll(), with a
 timeout just in case.
 
 The simple approach is just to iterate after reading data from a ready pipe.
 This leads to non-ideal behaviour when the subprocess has written its final Z
 item, closed the pipe, and is in the process of exiting (the common case). A
-call to waitpid() yields nothing completed, but select() shows the pipe ready -
+call to waitpid() yields nothing completed, but poll() shows the pipe ready -
 reading it yields EOF, so you end up with busy-waiting until the subprocess has
 actually finished.
 
 To avoid this, if all the data that is needed has been read from a subprocess
-after select(), an explicit wait() for it is done. We know that all it is doing
+after poll(), an explicit wait() for it is done. We know that all it is doing
 is writing to the pipe and then exiting, so the wait should not be long.
 
 The non-blocking waitpid() is to some extent just insurance; if we could
@@ -3881,9 +3894,7 @@ for (;;)   /* Normally we do not repeat this loop */
   {
   while ((pid = waitpid(-1, &status, WNOHANG)) <= 0)
     {
-    struct timeval tv;
-    fd_set select_pipes;
-    int maxpipe, readycount;
+    int readycount;
 
     /* A return value of -1 can mean several things. If errno != ECHILD, it
     either means invalid options (which we discount), or that this process was
@@ -3907,7 +3918,7 @@ for (;;)   /* Normally we do not repeat this loop */
     subprocesses are still in existence. If kill() gives an OK return, we know
     it must be for one of our processes - it can't be for a re-use of the pid,
     because if our process had finished, waitpid() would have found it. If any
-    of our subprocesses are in existence, we proceed to use select() as if
+    of our subprocesses are in existence, we proceed to use poll() as if
     waitpid() had returned zero. I think this is safe. */
 
     if (pid < 0)
@@ -3931,7 +3942,7 @@ for (;;)   /* Normally we do not repeat this loop */
       if (poffset >= remote_max_parallel)
         {
         DEBUG(D_deliver) debug_printf("*** no delivery children found\n");
-        return NULL;   /* This is the error return */
+       return NULL;    /* This is the error return */
         }
       }
 
@@ -3940,28 +3951,23 @@ for (;;)   /* Normally we do not repeat this loop */
     subprocess, but there are no completed subprocesses. See if any pipes are
     ready with any data for reading. */
 
-    DEBUG(D_deliver) debug_printf("selecting on subprocess pipes\n");
+    DEBUG(D_deliver) debug_printf("polling subprocess pipes\n");
 
-    maxpipe = 0;
-    FD_ZERO(&select_pipes);
     for (poffset = 0; poffset < remote_max_parallel; poffset++)
       if (parlist[poffset].pid != 0)
-        {
-        int fd = parlist[poffset].fd;
-        FD_SET(fd, &select_pipes);
-        if (fd > maxpipe) maxpipe = fd;
-        }
+       {
+       parpoll[poffset].fd = parlist[poffset].fd;
+       parpoll[poffset].events = POLLIN;
+       }
+      else
+       parpoll[poffset].fd = -1;
 
     /* Stick in a 60-second timeout, just in case. */
 
-    tv.tv_sec = 60;
-    tv.tv_usec = 0;
-
-    readycount = select(maxpipe + 1, (SELECT_ARG2_TYPE *)&select_pipes,
-         NULL, NULL, &tv);
+    readycount = poll(parpoll, remote_max_parallel, 60 * 1000);
 
     /* Scan through the pipes and read any that are ready; use the count
-    returned by select() to stop when there are no more. Select() can return
+    returned by poll() to stop when there are no more. Select() can return
     with no processes (e.g. if interrupted). This shouldn't matter.
 
     If par_read_pipe() returns TRUE, it means that either the terminating Z was
@@ -3978,7 +3984,7 @@ for (;;)   /* Normally we do not repeat this loop */
          poffset++)
       {
       if (  (pid = parlist[poffset].pid) != 0
-         && FD_ISSET(parlist[poffset].fd, &select_pipes)
+        && parpoll[poffset].revents
         )
         {
         readycount--;
@@ -4016,7 +4022,7 @@ for (;;)   /* Normally we do not repeat this loop */
     "transport process list", pid);
   }  /* End of the "for" loop */
 
-/* Come here when all the data was completely read after a select(), and
+/* Come here when all the data was completely read after a poll(), and
 the process in pid has been wait()ed for. */
 
 PROCESS_DONE:
@@ -4051,7 +4057,7 @@ if ((status & 0xffff) != 0)
     "%s %d",
     addrlist->transport->driver_name,
     status,
-    (msb == 0)? "terminated by signal" : "exit code",
+    msb == 0 ? "terminated by signal" : "exit code",
     code);
 
   if (msb != 0 || (code != SIGTERM && code != SIGKILL && code != SIGQUIT))
@@ -4069,7 +4075,8 @@ if ((status & 0xffff) != 0)
 /* Else complete reading the pipe to get the result of the delivery, if all
 the data has not yet been obtained. */
 
-else if (!parlist[poffset].done) (void)par_read_pipe(poffset, TRUE);
+else if (!parlist[poffset].done)
+  (void) par_read_pipe(poffset, TRUE);
 
 /* Put the data count and return path into globals, mark the data slot unused,
 decrement the count of subprocesses, and return the address chain. */
@@ -4218,6 +4225,7 @@ if (!parlist)
   parlist = store_get(remote_max_parallel * sizeof(pardata), FALSE);
   for (poffset = 0; poffset < remote_max_parallel; poffset++)
     parlist[poffset].pid = 0;
+  parpoll = store_get(remote_max_parallel * sizeof(struct pollfd), FALSE);
   }
 
 /* Now loop for each remote delivery */
@@ -4613,7 +4621,7 @@ nonmatch domains
     that it can use either of them, though it prefers O_NONBLOCK, which
     distinguishes between EOF and no-more-data. */
 
-/* The data appears in a timely manner and we already did a select on
+/* The data appears in a timely manner and we already did a poll on
 all pipes, so I do not see a reason to use non-blocking IO here
 
 #ifdef O_NONBLOCK
@@ -6345,7 +6353,7 @@ if (process_recipients != RECIP_IGNORE)
            string_copyn(addr+start, dom ? (dom-1) - start : end - start);
          deliver_domain = dom ? CUS string_copyn(addr+dom, end - dom) : CUS"";
 
-         event_raise(event_action, US"msg:fail:internal", new->message);
+         (void) event_raise(event_action, US"msg:fail:internal", new->message, NULL);
 
          deliver_localpart = save_local;
          deliver_domain = save_domain;
@@ -8096,7 +8104,7 @@ if (!addr_defer)
   f.deliver_freeze = FALSE;
 
 #ifndef DISABLE_EVENT
-  (void) event_raise(event_action, US"msg:complete", NULL);
+  (void) event_raise(event_action, US"msg:complete", NULL, NULL);
 #endif
   }