X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/ecf0514306dd9c0baf94c43932cf77bd25fd8df0..a85c067ba6c6940512cf57ec213277a370d87e70:/src/src/queue.c diff --git a/src/src/queue.c b/src/src/queue.c index 53dc6e026..fd84d303f 100644 --- a/src/src/queue.c +++ b/src/src/queue.c @@ -2,8 +2,10 @@ * Exim - an Internet mail transport agent * *************************************************/ +/* Copyright (c) The Exim Maintainers 2020 - 2022 */ /* Copyright (c) University of Cambridge 1995 - 2018 */ /* See the file NOTICE for conditions of use and distribution. */ +/* SPDX-License-Identifier: GPL-2.0-only */ /* Functions that operate on the input queue. */ @@ -25,6 +27,9 @@ Michael Haardt. */ #define LOG2_MAXNODES 32 +#ifndef DISABLE_TLS +static BOOL queue_tls_init = FALSE; +#endif /************************************************* * Helper sort function for queue_get_spool_list * @@ -125,8 +130,6 @@ int resetflags = -1; int subptr; queue_filename *yield = NULL; queue_filename *last = NULL; -struct dirent *ent; -DIR *dd; uschar buffer[256]; queue_filename *root[LOG2_MAXNODES]; @@ -171,6 +174,7 @@ for (; i <= *subcount; i++) { int count = 0; int subdirchar = subdirs[i]; /* 0 for main directory */ + DIR *dd; if (subdirchar != 0) { @@ -179,12 +183,12 @@ for (; i <= *subcount; i++) } DEBUG(D_queue_run) debug_printf("looking in %s\n", buffer); - if (!(dd = opendir(CS buffer))) + if (!(dd = exim_opendir(buffer))) continue; /* Now scan the directory. */ - while ((ent = readdir(dd))) + for (struct dirent *ent; ent = readdir(dd); ) { uschar *name = US ent->d_name; int len = Ustrlen(name); @@ -211,8 +215,8 @@ for (; i <= *subcount; i++) (*pcount)++; else { - queue_filename *next = - store_get(sizeof(queue_filename) + Ustrlen(name), is_tainted(name)); + queue_filename * next = + store_get(sizeof(queue_filename) + Ustrlen(name), name); Ustrcpy(next->text, name); next->dir_uschar = subdirchar; @@ -347,12 +351,13 @@ queue_run(uschar *start_id, uschar *stop_id, BOOL recurse) { BOOL force_delivery = f.queue_run_force || deliver_selectstring != NULL || deliver_selectstring_sender != NULL; -const pcre *selectstring_regex = NULL; -const pcre *selectstring_regex_sender = NULL; +const pcre2_code *selectstring_regex = NULL; +const pcre2_code *selectstring_regex_sender = NULL; uschar *log_detail = NULL; int subcount = 0; uschar subdirs[64]; pid_t qpid[4] = {0}; /* Parallelism factor for q2stage 1st phase */ +BOOL single_id = FALSE; #ifdef MEASURE_TIMING report_time_since(×tamp_startup, US"queue_run start"); @@ -392,12 +397,18 @@ if (!recurse) p += sprintf(CS p, " -q%s", extras); if (deliver_selectstring) - p += sprintf(CS p, " -R%s %s", f.deliver_selectstring_regex? "r" : "", - deliver_selectstring); + { + snprintf(CS p, big_buffer_size - (p - big_buffer), " -R%s %s", + f.deliver_selectstring_regex? "r" : "", deliver_selectstring); + p += Ustrlen(CCS p); + } if (deliver_selectstring_sender) - p += sprintf(CS p, " -S%s %s", f.deliver_selectstring_sender_regex? "r" : "", - deliver_selectstring_sender); + { + snprintf(CS p, big_buffer_size - (p - big_buffer), " -S%s %s", + f.deliver_selectstring_sender_regex? "r" : "", deliver_selectstring_sender); + p += Ustrlen(CCS p); + } log_detail = string_copy(big_buffer); if (*queue_name) @@ -405,16 +416,19 @@ if (!recurse) queue_name, log_detail); else log_write(L_queue_run, LOG_MAIN, "Start queue run: %s", log_detail); + + single_id = start_id && stop_id && !f.queue_2stage + && Ustrcmp(start_id, stop_id) == 0; } /* If deliver_selectstring is a regex, compile it. */ if (deliver_selectstring && f.deliver_selectstring_regex) - selectstring_regex = regex_must_compile(deliver_selectstring, TRUE, FALSE); + selectstring_regex = regex_must_compile(deliver_selectstring, MCS_CASELESS, FALSE); if (deliver_selectstring_sender && f.deliver_selectstring_sender_regex) selectstring_regex_sender = - regex_must_compile(deliver_selectstring_sender, TRUE, FALSE); + regex_must_compile(deliver_selectstring_sender, MCS_CASELESS, FALSE); /* If the spool is split into subdirectories, we want to process it one directory at a time, so as to spread out the directory scanning and the @@ -492,10 +506,8 @@ 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"); } /* Skip this message unless it's within the ID limits */ @@ -558,9 +570,7 @@ for (int i = queue_run_in_order ? -1 : 0; else if ( deliver_selectstring_sender && !(f.deliver_selectstring_sender_regex - ? (pcre_exec(selectstring_regex_sender, NULL, - CS sender_address, Ustrlen(sender_address), 0, PCRE_EOPT, - NULL, 0) >= 0) + ? regex_match(selectstring_regex_sender, sender_address, -1, NULL) : (strstric(sender_address, deliver_selectstring_sender, FALSE) != NULL) ) ) @@ -579,8 +589,7 @@ for (int i = queue_run_in_order ? -1 : 0; { uschar *address = recipients_list[i].address; if ( (f.deliver_selectstring_regex - ? (pcre_exec(selectstring_regex, NULL, CS address, - Ustrlen(address), 0, PCRE_EOPT, NULL, 0) >= 0) + ? regex_match(selectstring_regex, address, -1, NULL) : (strstric(address, deliver_selectstring, FALSE) != NULL) ) && tree_search(tree_nonrecipients, address) == NULL @@ -646,13 +655,24 @@ for (int i = queue_run_in_order ? -1 : 0; report_time_since(×tamp_startup, US"queue msg selected"); #endif - if ((pid = fork()) == 0) +#ifndef DISABLE_TLS + if (!queue_tls_init) + { + queue_tls_init = TRUE; + /* Preload TLS library info for smtp transports. Once, and only if we + have a delivery to do. */ + tls_client_creds_reload(FALSE); + } +#endif + +single_item_retry: + if ((pid = exim_fork(US"qrun-delivery")) == 0) { int rc; - testharness_pause_ms(100); (void)close(pfd[pipe_read]); rc = deliver_message(fq->text, force_delivery, FALSE); - exim_underbar_exit(rc == DELIVER_NOT_ATTEMPTED); + exim_underbar_exit(rc == DELIVER_NOT_ATTEMPTED + ? EXIT_FAILURE : EXIT_SUCCESS); } if (pid < 0) log_write(0, LOG_MAIN|LOG_PANIC_DIE, "fork of delivery process from " @@ -677,6 +697,18 @@ for (int i = queue_run_in_order ? -1 : 0; "queue run: process %d crashed with signal %d while delivering %s", (int)pid, status & 0x00ff, fq->text); + /* If single-item delivery was untried (likely due to locking) + retry once after a delay */ + + if (status & 0xff00 && single_id) + { + single_id = FALSE; + DEBUG(D_queue_run) debug_printf("qrun single-item pause before retry\n"); + millisleep(500); + DEBUG(D_queue_run) debug_printf("qrun single-item retry after pause\n"); + goto single_item_retry; + } + /* Before continuing, wait till the pipe gets closed at the far end. This tells us that any children created by the delivery to re-use any SMTP channels have all finished. Since no process actually writes to the pipe, @@ -692,7 +724,7 @@ for (int i = queue_run_in_order ? -1 : 0; /* If initial of a 2-phase run, we are a child - so just exit */ if (f.queue_2stage && !queue_run_in_order) - exim_exit(EXIT_SUCCESS, US"2-phase child"); + exim_exit(EXIT_SUCCESS); /* If we are in the test harness, and this is not the first of a 2-stage queue run, update fudged queue times. */ @@ -709,7 +741,7 @@ for (int i = queue_run_in_order ? -1 : 0; go_around: /* If initial of a 2-phase run, we are a child - so just exit */ if (f.queue_2stage && !queue_run_in_order) - exim_exit(EXIT_SUCCESS, US"2-phase child"); + exim_exit(EXIT_SUCCESS); } /* End loop for list of messages */ tree_nonrecipients = NULL; @@ -870,8 +902,8 @@ if (count > 0) queue_filename *last = NULL; for (int i = 0; i < count; i++) { - queue_filename *next = - store_get(sizeof(queue_filename) + Ustrlen(list[i]) + 2, is_tainted(list[i])); + queue_filename * next = + store_get(sizeof(queue_filename) + Ustrlen(list[i]) + 2, list[i]); sprintf(CS next->text, "%s-H", list[i]); next->dir_uschar = '*'; next->next = NULL; @@ -1317,15 +1349,15 @@ switch(action) deliver_domain = dom ? CUS string_copyn(addr+dom, end - dom) : CUS""; - event_raise(event_action, US"msg:fail:internal", - string_sprintf("message removed by %s", username)); + (void) event_raise(event_action, US"msg:fail:internal", + string_sprintf("message removed by %s", username), NULL); deliver_localpart = save_local; deliver_domain = save_domain; } } } - (void) event_raise(event_action, US"msg:complete", NULL); + (void) event_raise(event_action, US"msg:complete", NULL, NULL); #endif log_write(0, LOG_MAIN, "removed by %s", username); log_write(0, LOG_MAIN, "Completed"); @@ -1395,13 +1427,13 @@ switch(action) parse_extract_address(argv[recipients_arg], &errmess, &start, &end, &domain, (action == MSG_EDIT_SENDER)); - if (recipient == NULL) + if (!recipient) { yield = FALSE; printf("- error while %s:\n bad address %s: %s\n", doing, argv[recipients_arg], errmess); } - else if (recipient[0] != 0 && domain == 0) + else if (*recipient && domain == 0) { yield = FALSE; printf("- error while %s:\n bad address %s: " @@ -1516,7 +1548,7 @@ if (s) /******************************************************************************/ /******************************************************************************/ -#ifdef EXPERIMENTAL_QUEUE_RAMP +#ifndef DISABLE_QUEUE_RAMP void queue_notify_daemon(const uschar * msgid) { @@ -1531,20 +1563,9 @@ memcpy(buf+1, msgid, MESSAGE_ID_LENGTH+1); if ((fd = socket(AF_UNIX, SOCK_DGRAM, 0)) >= 0) { struct sockaddr_un sa_un = {.sun_family = AF_UNIX}; - int slen; - -#ifdef EXIM_HAVE_ABSTRACT_UNIX_SOCKETS - int len = offsetof(struct sockaddr_un, sun_path) + 1 - + snprintf(sa_un.sun_path+1, sizeof(sa_un.sun_path)-1, "%s", - NOTIFIER_SOCKET_NAME); - sa_un.sun_path[0] = 0; -#else - int len = offsetof(struct sockaddr_un, sun_path) - + snprintf(sa_un.sun_path, sizeof(sa_un.sun_path), "%s/%s", - spool_directory, NOTIFIER_SOCKET_NAME); -#endif + ssize_t len = daemon_notifier_sockname(&sa_un); - if (sendto(fd, buf, sizeof(buf), 0, (struct sockaddr *)&sa_un, len) < 0) + if (sendto(fd, buf, sizeof(buf), 0, (struct sockaddr *)&sa_un, (socklen_t)len) < 0) DEBUG(D_queue_run) debug_printf("%s: sendto %s\n", __FUNCTION__, strerror(errno)); close(fd);