build: use pkg-config for i18n
[exim.git] / src / src / daemon.c
index b0533c28f41701a0bcc4af6249574e5acfb91379..20e6bc05d40e13fe766526a007fbd5bf8b6b510c 100644 (file)
@@ -2,8 +2,8 @@
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
-/* Copyright (c) The Exim Maintainers 2020 - 2022 */
-/* Copyright (c) University of Cambridge 1995 - 2023 */
+/* Copyright (c) The Exim Maintainers 2020 - 2024 */
+/* Copyright (c) University of Cambridge 1995 - 2018 */
 /* See the file NOTICE for conditions of use and distribution. */
 /* SPDX-License-Identifier: GPL-2.0-or-later */
 
@@ -128,7 +128,7 @@ never_error(uschar *log_msg, uschar *smtp_msg, int was_errno)
 uschar *emsg = was_errno <= 0
   ? US"" : string_sprintf(": %s", strerror(was_errno));
 log_write(0, LOG_MAIN|LOG_PANIC, "%s%s", log_msg, emsg);
-if (smtp_out) smtp_printf("421 %s\r\n", FALSE, smtp_msg);
+if (smtp_out) smtp_printf("421 %s\r\n", SP_NO_MORE, smtp_msg);
 }
 
 
@@ -181,7 +181,7 @@ Returns:            nothing
 */
 
 static void
-handle_smtp_call(struct pollfd *fd_polls, int listen_socket_count,
+handle_smtp_call(struct pollfd * fd_polls, int listen_socket_count,
   int accept_socket, struct sockaddr *accepted)
 {
 pid_t pid;
@@ -233,7 +233,7 @@ if (getsockname(accept_socket, (struct sockaddr *)(&interface_sockaddr),
   {
   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", FALSE);
+  smtp_printf("421 Local problem: getsockname() failed; please try again later\r\n", SP_NO_MORE);
   goto ERROR_RETURN;
   }
 
@@ -254,8 +254,6 @@ if (LOGGING(incoming_interface))
   whofrom = string_fmt_append(whofrom, " I=[%s]:%d",
     interface_address, interface_port);
 
-(void) string_from_gstring(whofrom);    /* Terminate the newly-built string */
-
 /* Check maximum number of connections. We do not check for reserved
 connections or unacceptable hosts here. That is done in the subprocess because
 it might take some time. */
@@ -265,10 +263,10 @@ if (smtp_accept_max > 0 && smtp_accept_count >= smtp_accept_max)
   DEBUG(D_any) debug_printf("rejecting SMTP connection: count=%d max=%d\n",
     smtp_accept_count, smtp_accept_max);
   smtp_printf("421 Too many concurrent SMTP connections; "
-    "please try again later.\r\n", FALSE);
+    "please try again later.\r\n", SP_NO_MORE);
   log_write(L_connection_reject,
-            LOG_MAIN, "Connection from %s refused: too many connections",
-    whofrom->s);
+            LOG_MAIN, "Connection from %Y refused: too many connections",
+    whofrom);
   goto ERROR_RETURN;
   }
 
@@ -284,10 +282,10 @@ if (smtp_load_reserve >= 0)
     {
     DEBUG(D_any) debug_printf("rejecting SMTP connection: load average = %.2f\n",
       (double)load_average/1000.0);
-    smtp_printf("421 Too much load; please try again later.\r\n", FALSE);
+    smtp_printf("421 Too much load; please try again later.\r\n", SP_NO_MORE);
     log_write(L_connection_reject,
-              LOG_MAIN, "Connection from %s refused: load average = %.2f",
-      whofrom->s, (double)load_average/1000.0);
+              LOG_MAIN, "Connection from %Y refused: load average = %.2f",
+      whofrom, (double)load_average/1000.0);
     goto ERROR_RETURN;
     }
   }
@@ -300,32 +298,34 @@ to provide host-specific limits according to $sender_host address, but because
 this is in the daemon mainline, only fast expansions (such as inline address
 checks) should be used. The documentation is full of warnings. */
 
+GET_OPTION("smtp_accept_max_per_host");
 if (smtp_accept_max_per_host)
   {
-  uschar *expanded = expand_string(smtp_accept_max_per_host);
+  uschar * expanded = expand_string(smtp_accept_max_per_host);
   if (!expanded)
     {
     if (!f.expand_string_forcedfail)
       log_write(0, LOG_MAIN|LOG_PANIC, "expansion of smtp_accept_max_per_host "
-        "failed for %s: %s", whofrom->s, expand_string_message);
+        "failed for %Y: %s", whofrom, expand_string_message);
     }
   /* For speed, interpret a decimal number inline here */
   else
     {
-    uschar *s = expanded;
+    uschar * s = expanded;
     while (isdigit(*s))
       max_for_this_host = max_for_this_host * 10 + *s++ - '0';
     if (*s)
       log_write(0, LOG_MAIN|LOG_PANIC, "expansion of smtp_accept_max_per_host "
-        "for %s contains non-digit: %s", whofrom->s, expanded);
+        "for %Y contains non-digit: %s", whofrom, expanded);
     }
   }
 
-/* If we have fewer connections than max_for_this_host, we can skip the tedious
-per host_address checks. Note that at this stage smtp_accept_count contains the
-count of *other* connections, not including this one. */
+/* If we have fewer total connections than max_for_this_host, we can skip the
+tedious per host_address checks. Note that at this stage smtp_accept_count
+contains the count of *other* connections, not including this one. */
 
-if (max_for_this_host > 0 && smtp_accept_count >= max_for_this_host)
+if (  smtp_slots
+   && max_for_this_host > 0 && smtp_accept_count >= max_for_this_host)
   {
   int host_accept_count = 0;
   int other_host_count = 0;    /* keep a count of non matches to optimise */
@@ -353,40 +353,17 @@ if (max_for_this_host > 0 && smtp_accept_count >= max_for_this_host)
       "IP address: count=%d max=%d\n",
       host_accept_count, max_for_this_host);
     smtp_printf("421 Too many concurrent SMTP connections "
-      "from this IP address; please try again later.\r\n", FALSE);
+      "from this IP address; please try again later.\r\n", SP_NO_MORE);
     log_write(L_connection_reject,
-              LOG_MAIN, "Connection from %s refused: too many connections "
-      "from that IP address", whofrom->s);
+              LOG_MAIN, "Connection from %Y refused: too many connections "
+      "from that IP address", whofrom);
     search_tidyup();
     goto ERROR_RETURN;
     }
   }
 
-/* OK, the connection count checks have been passed. Before we can fork the
-accepting process, we must first log the connection if requested. This logging
-used to happen in the subprocess, but doing that means that the value of
-smtp_accept_count can be out of step by the time it is logged. So we have to do
-the logging here and accept the performance cost. Note that smtp_accept_count
-hasn't yet been incremented to take account of this connection.
-
-In order to minimize the cost (because this is going to happen for every
-connection), do a preliminary selector test here. This saves ploughing through
-the generalized logging code each time when the selector is false. If the
-selector is set, check whether the host is on the list for logging. If not,
-arrange to unset the selector in the subprocess. */
-
-if (LOGGING(smtp_connection))
-  {
-  uschar *list = hosts_connection_nolog;
-  memset(sender_host_cache, 0, sizeof(sender_host_cache));
-  if (list && verify_check_host(&list) == OK)
-    save_log_selector &= ~L_smtp_connection;
-  else
-    log_write(L_smtp_connection, LOG_MAIN, "SMTP connection from %s "
-      "(TCP/IP connection count = %d)", whofrom->s, smtp_accept_count + 1);
-  }
-
-/* Now we can fork the accepting process; do a lookup tidy, just in case any
+/* OK, the connection count checks have been passed.
+Now we can fork the accepting process; do a lookup tidy, just in case any
 expansion above did a lookup. */
 
 search_tidyup();
@@ -406,6 +383,34 @@ if (pid == 0)
 #endif
 
   smtp_accept_count++;    /* So that it includes this process */
+  set_connection_id();
+
+  /* Log the connection if requested.
+  In order to minimize the cost (because this is going to happen for every
+  connection), do a preliminary selector test here. This saves ploughing through
+  the generalized logging code each time when the selector is false. If the
+  selector is set, check whether the host is on the list for logging. If not,
+  arrange to unset the selector in the subprocess.
+
+  jgh 2023/08/08 :- moved this logging in from the parent process, just
+  pre-fork.  There was a claim back from 4.21 (when it was moved from
+  smtp_start_session()) that smtp_accept_count could have become out-of-date by
+  the time the child could log it, and I can't see how that could happen. */
+
+  if (LOGGING(smtp_connection))
+    {
+    uschar * list = hosts_connection_nolog;
+    memset(sender_host_cache, 0, sizeof(sender_host_cache));
+    if (list && verify_check_host(&list) == OK)
+      save_log_selector &= ~L_smtp_connection;
+    else if (LOGGING(connection_id))
+      log_write(L_smtp_connection, LOG_MAIN, "SMTP connection from %Y "
+       "Ci=%s (TCP/IP connection count = %d)",
+       whofrom, connection_id, smtp_accept_count);
+    else
+      log_write(L_smtp_connection, LOG_MAIN, "SMTP connection from %Y "
+       "(TCP/IP connection count = %d)", whofrom, smtp_accept_count);
+    }
 
   /* If the listen backlog was over the monitoring level, log it. */
 
@@ -432,6 +437,7 @@ if (pid == 0)
   likely what it depends on.) */
 
   smtp_active_hostname = primary_hostname;
+  GET_OPTION("smtp_active_hostname");
   if (raw_active_hostname)
     {
     uschar * nah = expand_string(raw_active_hostname);
@@ -443,7 +449,7 @@ if (pid == 0)
           "(smtp_active_hostname): %s", raw_active_hostname,
           expand_string_message);
         smtp_printf("421 Local configuration error; "
-          "please try again later.\r\n", FALSE);
+          "please try again later.\r\n", SP_NO_MORE);
         mac_smtp_fflush();
         search_tidyup();
         exim_underbar_exit(EXIT_FAILURE);
@@ -564,7 +570,7 @@ if (pid == 0)
         smtp_log_no_mail();               /* Log no mail if configured */
         exim_underbar_exit(EXIT_SUCCESS);
         }
-      if (message_id[0] == 0) continue;   /* No message was accepted */
+      if (!message_id[0]) continue;    /* No message was accepted */
       }
     else                               /* bad smtp_setup_msg() */
       {
@@ -748,7 +754,7 @@ remember the pid for ticking off when the child completes. */
 
 if (pid < 0)
   never_error(US"daemon: accept process fork failed", US"Fork failed", errno);
-else
+else if (smtp_slots)
   {
   for (int i = 0; i < smtp_accept_max; ++i)
     if (smtp_slots[i].pid <= 0)
@@ -892,7 +898,7 @@ while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
   {
   DEBUG(D_any)
     {
-    debug_printf("child %d ended: status=0x%x\n", (int)pid, status);
+    debug_printf("child %ld ended: status=0x%x\n", (long)pid, status);
 #ifdef WCOREDUMP
     if (WIFEXITED(status))
       debug_printf("  normal exit, %d\n", WEXITSTATUS(status));
@@ -908,15 +914,16 @@ while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
   if (smtp_slots)
     {
     int i;
-    for (i = 0; i < smtp_accept_max; i++)
-      if (smtp_slots[i].pid == pid)
+    smtp_slot * sp;
+    for (i = 0, sp = smtp_slots; i < smtp_accept_max; i++, sp++)
+      if (sp->pid == pid)
         {
-        if (smtp_slots[i].host_address)
-          store_free(smtp_slots[i].host_address);
-        smtp_slots[i] = empty_smtp_slot;
+        if (sp->host_address)
+          store_free(sp->host_address);
+        *sp = empty_smtp_slot;
         if (--smtp_accept_count < 0) smtp_accept_count = 0;
         DEBUG(D_any) debug_printf("%d SMTP accept process%s now running\n",
-          smtp_accept_count, (smtp_accept_count == 1)? "" : "es");
+          smtp_accept_count, smtp_accept_count == 1 ? "" : "es");
         break;
         }
     if (i < smtp_accept_max) continue;  /* Found an accepting process */
@@ -979,7 +986,7 @@ static BOOL
 operate_on_pid_file(const enum pid_op operation, const pid_t pid)
 {
 char pid_line[sizeof(int) * 3 + 2];
-const int pid_len = snprintf(pid_line, sizeof(pid_line), "%d\n", (int)pid);
+const int pid_len = snprintf(pid_line, sizeof(pid_line), "%ld\n", (long)pid);
 BOOL lines_match = FALSE;
 uschar * path, * base, * dir;
 
@@ -1109,7 +1116,7 @@ since we may require privs for the containing directory */
 static void
 daemon_die(void)
 {
-int pid;
+pid_t pid;
 
 DEBUG(D_any) debug_printf("SIGTERM/SIGINT seen\n");
 #if !defined(DISABLE_TLS) && (defined(EXIM_HAVE_INOTIFY) || defined(EXIM_HAVE_KEVENT))
@@ -1163,6 +1170,7 @@ return offsetof(struct sockaddr_un, sun_path)
 ssize_t
 daemon_notifier_sockname(struct sockaddr_un * sup)
 {
+GET_OPTION("notifier_socket");
 #ifdef EXIM_HAVE_ABSTRACT_UNIX_SOCKETS
 sup->sun_path[0] = 0;  /* Abstract local socket addr - Linux-specific? */
 return offsetof(struct sockaddr_un, sun_path) + 1
@@ -1256,10 +1264,9 @@ static const uschar * queuerun_msg_qname;
 
 /* The notifier socket has something to read. Pull the message from it, decode
 and do the action.
+*/
 
-Return TRUE if a sigalrm should be emulated */
-
-static BOOL
+static void
 daemon_notification(void)
 {
 uschar buf[256], cbuf[256];
@@ -1275,8 +1282,8 @@ struct msghdr msg = { .msg_name = &sa_un,
 ssize_t sz;
 
 buf[sizeof(buf)-1] = 0;
-if ((sz = recvmsg(daemon_notifier_fd, &msg, 0)) <= 0) return FALSE;
-if (sz >= sizeof(buf)) return FALSE;
+if ((sz = recvmsg(daemon_notifier_fd, &msg, 0)) <= 0) return;
+if (sz >= sizeof(buf)) return;
 
 #ifdef notdef
 debug_printf("addrlen %d\n", msg.msg_namelen);
@@ -1317,8 +1324,8 @@ for (struct cmsghdr * cp = CMSG_FIRSTHDR(&msg);
   struct ucred * cr = (struct ucred *) CMSG_DATA(cp);
   if (cr->uid && cr->uid != exim_uid)
     {
-    DEBUG(D_queue_run) debug_printf("%s: sender creds pid %d uid %d gid %d\n",
-      __FUNCTION__, (int)cr->pid, (int)cr->uid, (int)cr->gid);
+    DEBUG(D_queue_run) debug_printf("%s: sender creds pid %ld uid %d gid %d\n",
+      __FUNCTION__, (long)cr->pid, (int)cr->uid, (int)cr->gid);
     }
 # elif defined(LOCAL_CREDS)                            /* BSD-ish */
   struct sockcred * cr = (struct sockcred *) CMSG_DATA(cp);
@@ -1344,9 +1351,12 @@ switch (buf[0])
     memcpy(queuerun_msgid, buf+1, MESSAGE_ID_LENGTH+1);
 
     for (qrunner * q = qrunners; q; q = q->next)
-      if (Ustrcmp(q->name, buf+1+MESSAGE_ID_LENGTH+1) == 0)
+      if (q->name
+         ? Ustrcmp(q->name, buf+1+MESSAGE_ID_LENGTH+1) == 0
+         : !buf[1+MESSAGE_ID_LENGTH+1]
+        )
        { queuerun_msg_qname = q->name; break; }
-    return TRUE;
+    return;
 #endif
 
   case NOTIFY_QUEUE_SIZE_REQ:
@@ -1368,7 +1378,7 @@ switch (buf[0])
     regex_at_daemon(buf);
     break;
   }
-return FALSE;
+return;
 }
 
 
@@ -1427,7 +1437,7 @@ for (qrunner * q = qrunners, * next; q; q = next)
   if (sorted)
     {
     qrunner ** p = &sorted;
-    for (qrunner * qq; qq = *p; p = &(qq->next))
+    for (qrunner * qq; qq = *p; p = &qq->next)
       if (  q->next_tick < qq->next_tick
         || q->next_tick == qq->next_tick && q->interval < qq->interval
         )
@@ -1446,6 +1456,13 @@ qrunners = sorted;
 return qrunners ? qrunners->next_tick - time(NULL) : 0;
 }
 
+/* See if we can do a queue run.  If policy limit permit, kick one off.
+If both notification and timer events are present, handle the former
+and leave the timer outstanding.
+
+Return the number of seconds until the next due runner.
+*/
+
 static int
 daemon_qrun(int local_queue_run_max, struct pollfd * fd_polls, int listen_socket_count)
 {
@@ -1459,13 +1476,16 @@ DEBUG(D_any) debug_printf("%s received\n",
 enough queue runners on the go. If we are not running as root, a re-exec is
 required. In the calling process, restart the alamr timer for the next run.  */
 
-if (is_multiple_qrun())
+if (is_multiple_qrun())                                /* we are managing periodic runs */
   if (local_queue_run_max <= 0 || queue_run_count < local_queue_run_max)
     {
     qrunner * q = NULL;
 
 #ifndef DISABLE_QUEUE_RAMP
-    if (*queuerun_msgid)       /* See if we can start another runner for this queue */
+    /* If this is a triggered run for a specific message, see if we can start
+    another runner for this queue. */
+
+    if (*queuerun_msgid)
       {
       for (qrunner * qq = qrunners; qq; qq = qq->next)
        if (qq->name == queuerun_msg_qname)
@@ -1476,13 +1496,13 @@ if (is_multiple_qrun())
       }
     else
 #endif
-      /* In order of run priority, find the first queue for which we can start
-      a runner */
+      /* Normal periodic run: in order of run priority, find the first queue
+      for which we can start a runner */
 
       for (q = qrunners; q; q = q->next)
        if (q->run_count < q->run_max) break;
 
-    if (q)
+    if (q)                                     /* found a queue to run */
       {
       pid_t pid;
 
@@ -1614,19 +1634,23 @@ if (is_multiple_qrun())
       }
     }
 
-sigalrm_seen = FALSE;
+/* The queue run has been initiated (unless we were already running enough) */
+
 #ifndef DISABLE_QUEUE_RAMP
-if (*queuerun_msgid)           /* it was a fast-ramp kick */
+if (*queuerun_msgid)           /* it was a fast-ramp kick; dealt with */
   *queuerun_msgid = 0;
 else                           /* periodic or one-time queue run */
 #endif
-  {            /* Impose a minimum 1s tick, even when a run was outstanding */
+  /* Set up next timer callback. Impose a minimum 1s tick,
+  even when a run was outstanding */
+  {
   int interval = next_qrunner_interval();
   if (interval <= 0) interval = 1;
 
+  sigalrm_seen = FALSE;
   if (qrunners)                        /* there are still periodic qrunners */
     {
-    ALARM(interval);
+    ALARM(interval);           /* set up next qrun tick */
     return interval;
     }
   }
@@ -1636,7 +1660,7 @@ return 0;
 
 
 
-const uschar *
+static const uschar *
 describe_queue_runners(void)
 {
 gstring * g = NULL;
@@ -1646,6 +1670,7 @@ if (!is_multiple_qrun()) return US"no queue runs";
 for (qrunner * q = qrunners; q; q = q->next)
   {
   g = string_catn(g, US"-q", 2);
+  if (q->queue_2stage) g = string_catn(g, US"q", 1);
   if (q->name) g = string_append(g, 3, US"G", q->name, US"/");
   g = string_cat(g, readconf_printtime(q->interval));
   g = string_catn(g, US" ", 1);
@@ -1688,15 +1713,15 @@ int listen_socket_count = 0, poll_fd_count;
 ip_address_item * addresses = NULL;
 time_t last_connection_time = (time_t)0;
 int local_queue_run_max = 0;
-BOOL queue_run_max_has_dollar;
 
 if (is_multiple_qrun())
-
+  {
   /* Nuber of runner-tracking structs needed:  If the option queue_run_max has
   no expandable elements then it is the overall maximum; else we assume it
   depends on the queue name, and add them up to get the maximum.
   Evaluate both that and the individual limits. */
 
+  GET_OPTION("queue_run_max");
   if (Ustrchr(queue_run_max, '$') != NULL)
     {
     for (qrunner * q = qrunners; q; q = q->next)
@@ -1713,6 +1738,7 @@ if (is_multiple_qrun())
     for (qrunner * q = qrunners; q; q = q->next)
       q->run_max = local_queue_run_max;
     }
+  }
 
 process_purpose = US"daemon";
 
@@ -1950,16 +1976,17 @@ if (f.daemon_listen && !f.inetd_wait_mode)
       tls_in.on_connect_ports = NULL;
       sep = 0;
       while ((s = string_nextinlist(&list, &sep, big_buffer, big_buffer_size)))
-       {
-        if (!isdigit(*s))
+        if (isdigit(*s))
+         g = string_append_listele(g, ':', s);
+       else
          {
          struct servent * smtp_service = getservbyname(CS s, "tcp");
          if (!smtp_service)
            log_write(0, LOG_PANIC_DIE|LOG_CONFIG, "TCP port \"%s\" not found", s);
-         s = string_sprintf("%d", (int)ntohs(smtp_service->s_port));
+         g = string_append_listele_fmt(g, ':', FALSE, "%d",
+                                             (int)ntohs(smtp_service->s_port));
          }
-       g = string_append_listele(g, ':', s);
-       }
+
       if (g)
        tls_in.on_connect_ports = g->s;
       break;
@@ -2134,7 +2161,7 @@ if (f.background_daemon)
     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 */
+    if (pid > 0) exim_exit(EXIT_SUCCESS); /* in parent process, just exit */
     (void)setsid();                       /* release controlling terminal */
     f.daemon_listen = daemon_listen;
     }
@@ -2409,7 +2436,7 @@ if (f.inetd_wait_mode)
     sprintf(CS p, "with no wait timeout");
 
   log_write(0, LOG_MAIN,
-    "exim %s daemon started: pid=%d, launched with listening socket, %s",
+    "exim %s daemon started: pid=%ld, launched with listening socket, %s",
     version_string, getpid(), big_buffer);
   set_process_info("daemon(%s): pre-listening socket", version_string);
 
@@ -2515,7 +2542,7 @@ else if (f.daemon_listen)
     }
 
   log_write(0, LOG_MAIN,
-    "exim %s daemon started: pid=%d, %s, listening for %s",
+    "exim %s daemon started: pid=%ld, %s, listening for %s",
     version_string, getpid(), qinfo, big_buffer);
   set_process_info("daemon(%s): %s, listening for %s",
     version_string, qinfo, big_buffer);
@@ -2525,7 +2552,7 @@ else      /* no listening sockets, only queue-runs */
   {
   const uschar * s = describe_queue_runners();
   log_write(0, LOG_MAIN,
-    "exim %s daemon started: pid=%d, %s, not listening for SMTP",
+    "exim %s daemon started: pid=%ld, %s, not listening for SMTP",
     version_string, getpid(), s);
   set_process_info("daemon(%s): %s, not listening", version_string, s);
   }
@@ -2536,25 +2563,9 @@ else     /* no listening sockets, only queue-runs */
 dns_pattern_init();
 smtp_deliver_init();   /* Used for callouts */
 
-#ifndef DISABLE_DKIM
-  {
-# ifdef MEASURE_TIMING
-  struct timeval t0;
-  gettimeofday(&t0, NULL);
-# endif
-  dkim_exim_init();
-# ifdef MEASURE_TIMING
-  report_time_since(&t0, US"dkim_exim_init (delta)");
-# endif
-  }
-#endif
-
 #ifdef WITH_CONTENT_SCAN
 malware_init();
 #endif
-#ifdef SUPPORT_SPF
-spf_init();
-#endif
 #ifndef DISABLE_TLS
 tls_daemon_init();
 #endif
@@ -2608,7 +2619,7 @@ for (;;)
 
   The other option is that we have an inetd wait timeout specified to -bw. */
 
-  if (sigalrm_seen)
+  if (sigalrm_seen || *queuerun_msgid)
     if (inetd_wait_timeout > 0)
       daemon_inetd_wtimeout(last_connection_time);     /* Might not return */
     else
@@ -2637,7 +2648,9 @@ for (;;)
     select() was interrupted so that we reap the child. This might still leave
     a small window when a SIGCHLD could get lost. However, since we use SIGCHLD
     only to do the reaping more quickly, it shouldn't result in anything other
-    than a delay until something else causes a wake-up. */
+    than a delay until something else causes a wake-up.
+    For the normal case, wait for either a pollable fd (eg. new connection) or
+    or a SIGALRM (for a periodic queue run) */
 
     if (sigchld_seen)
       {
@@ -2702,10 +2715,13 @@ for (;;)
          break;        /* to top of daemon loop */
          }
 #endif
+       /* Handle the daemon-notifier socket.  If it was a fast-ramp
+       notification then queuerun_msgid will have a nonzerolength string. */
+
        if (dnotify_poll && dnotify_poll->revents & POLLIN)
          {
          dnotify_poll->revents = 0;
-         sigalrm_seen = daemon_notification();
+         daemon_notification();
          break;        /* to top of daemon loop */
          }
        for (struct pollfd * p = fd_polls; p < fd_polls + listen_socket_count;
@@ -2841,7 +2857,7 @@ for (;;)
 
   if (sighup_seen)
     {
-    log_write(0, LOG_MAIN, "pid %d: SIGHUP received: re-exec daemon",
+    log_write(0, LOG_MAIN, "pid %ld: SIGHUP received: re-exec daemon",
       getpid());
     close_daemon_sockets(daemon_notifier_fd, fd_polls, listen_socket_count);
     unlink_notifier_socket();
@@ -2850,7 +2866,7 @@ for (;;)
     sighup_argv[0] = exim_path;
     exim_nullstd();
     execv(CS exim_path, (char *const *)sighup_argv);
-    log_write(0, LOG_MAIN|LOG_PANIC_DIE, "pid %d: exec of %s failed: %s",
+    log_write(0, LOG_MAIN|LOG_PANIC_DIE, "pid %ld: exec of %s failed: %s",
       getpid(), exim_path, strerror(errno));
     log_close_all();
     }