X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/6b46ecc6a8f5e3ab97c62451646a6d6045205bb1..3203e7baa4148a7068bc69caef3b63dcb3971b92:/src/src/queue.c diff --git a/src/src/queue.c b/src/src/queue.c index 7648f47ca..3ae2a70a9 100644 --- a/src/src/queue.c +++ b/src/src/queue.c @@ -2,7 +2,7 @@ * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2015 */ +/* Copyright (c) University of Cambridge 1995 - 2018 */ /* See the file NOTICE for conditions of use and distribution. */ /* Functions that operate on the input queue. */ @@ -12,20 +12,22 @@ -/* Routines with knowlege of spool layout */ +/* Routines with knowledge of spool layout */ +#ifndef COMPILE_UTILITY static void spool_pname_buf(uschar * buf, int len) { snprintf(CS buf, len, "%s/%s/input", spool_directory, queue_name); } -static uschar * +uschar * spool_dname(const uschar * purpose, uschar * subdir) { return string_sprintf("%s/%s/%s/%s", spool_directory, queue_name, purpose, subdir); } +#endif uschar * spool_sname(const uschar * purpose, uschar * subdir) @@ -37,7 +39,8 @@ return string_sprintf("%s%s%s%s%s", } uschar * -spool_fname(const uschar * purpose, uschar * subdir, uschar * fname, uschar * suffix) +spool_fname(const uschar * purpose, const uschar * subdir, const uschar * fname, + const uschar * suffix) { return string_sprintf("%s/%s/%s/%s/%s%s", spool_directory, queue_name, purpose, subdir, fname, suffix); @@ -76,9 +79,12 @@ merge_queue_lists(queue_filename *a, queue_filename *b) queue_filename *first = NULL; queue_filename **append = &first; -while (a != NULL && b != NULL) +while (a && b) { - if (Ustrcmp(a->text, b->text) < 0) + int d; + if ((d = Ustrncmp(a->text, b->text, 6)) == 0) + d = Ustrcmp(a->text + 14, b->text + 14); + if (d < 0) { *append = a; append= &a->next; @@ -92,7 +98,7 @@ while (a != NULL && b != NULL) } } -*append=((a != NULL)? a : b); +*append = a ? a : b; return first; } @@ -161,8 +167,11 @@ according to the bits of the flags variable. Get a collection of bits from the current time. Use the bottom 16 and just keep re-using them if necessary. When not randomizing, initialize the sublists for the bottom-up merge sort. */ -if (randomize) resetflags = time(NULL) & 0xFFFF; - else for (i = 0; i < LOG2_MAXNODES; i++) root[i] = NULL; +if (randomize) + resetflags = time(NULL) & 0xFFFF; +else + for (i = 0; i < LOG2_MAXNODES; i++) + root[i] = NULL; /* If processing the full queue, or just the top-level, start at the base directory, and initialize the first subdirectory name (as none). Otherwise, @@ -174,7 +183,8 @@ if (subdiroffset <= 0) subdirs[0] = 0; *subcount = 0; } -else i = subdiroffset; +else + i = subdiroffset; /* Set up prototype for the directory name. */ @@ -204,7 +214,7 @@ for (; i <= *subcount; i++) /* Now scan the directory. */ - while ((ent = readdir(dd)) != NULL) + while ((ent = readdir(dd))) { uschar *name = US ent->d_name; int len = Ustrlen(name); @@ -240,15 +250,15 @@ for (; i <= *subcount; i++) to store the number with each item. */ if (randomize) - { - if (yield == NULL) + if (!yield) { next->next = NULL; yield = last = next; } else { - if (flags == 0) flags = resetflags; + if (flags == 0) + flags = resetflags; if ((flags & 1) == 0) { next->next = yield; @@ -262,7 +272,6 @@ for (; i <= *subcount; i++) } flags = flags >> 1; } - } /* Otherwise do a bottom-up merge sort based on the name. */ @@ -271,18 +280,16 @@ for (; i <= *subcount; i++) int j; next->next = NULL; for (j = 0; j < LOG2_MAXNODES; j++) - { - if (root[j] != NULL) + if (root[j]) { next = merge_queue_lists(next, root[j]); - root[j] = (j == LOG2_MAXNODES - 1)? next : NULL; + root[j] = j == LOG2_MAXNODES - 1 ? next : NULL; } else { root[j] = next; break; } - } } } } @@ -314,10 +321,8 @@ for (; i <= *subcount; i++) /* If we have just scanned the base directory, and subdiroffset is 0, we do not want to continue scanning the sub-directories. */ - else - { - if (subdiroffset == 0) break; - } + else if (subdiroffset == 0) + break; } /* Loop for multiple subdirectories */ /* When using a bottom-up merge sort, do the final merging of the sublists. @@ -405,28 +410,18 @@ if (!recurse) *p = 0; p = big_buffer; - sprintf(CS p, "pid=%d", (int)queue_run_pid); - while (*p != 0) p++; + p += sprintf(CS p, "pid=%d", (int)queue_run_pid); if (extras[0] != 0) - { - sprintf(CS p, " -q%s", extras); - while (*p != 0) p++; - } + p += sprintf(CS p, " -q%s", extras); - if (deliver_selectstring != NULL) - { - sprintf(CS p, " -R%s %s", deliver_selectstring_regex? "r" : "", + if (deliver_selectstring) + p += sprintf(CS p, " -R%s %s", deliver_selectstring_regex? "r" : "", deliver_selectstring); - while (*p != 0) p++; - } - if (deliver_selectstring_sender != NULL) - { - sprintf(CS p, " -S%s %s", deliver_selectstring_sender_regex? "r" : "", + if (deliver_selectstring_sender) + p += sprintf(CS p, " -S%s %s", deliver_selectstring_sender_regex? "r" : "", deliver_selectstring_sender); - while (*p != 0) p++; - } log_detail = string_copy(big_buffer); if (*queue_name) @@ -438,10 +433,10 @@ if (!recurse) /* If deliver_selectstring is a regex, compile it. */ -if (deliver_selectstring != NULL && deliver_selectstring_regex) +if (deliver_selectstring && deliver_selectstring_regex) selectstring_regex = regex_must_compile(deliver_selectstring, TRUE, FALSE); -if (deliver_selectstring_sender != NULL && deliver_selectstring_sender_regex) +if (deliver_selectstring_sender && deliver_selectstring_sender_regex) selectstring_regex_sender = regex_must_compile(deliver_selectstring_sender, TRUE, FALSE); @@ -455,13 +450,13 @@ any messages therein), and then repeats for any subdirectories that were found. When the first argument of queue_get_spool_list() is 0, it scans the top directory, fills in subdirs, and sets subcount. The order of the directories is then randomized after the first time through, before they are scanned in -subsqeuent iterations. +subsequent iterations. When the first argument of queue_get_spool_list() is -1 (for queue_run_in_ order), it scans all directories and makes a single message list. */ -for (i = (queue_run_in_order? -1 : 0); - i <= (queue_run_in_order? -1 : subcount); +for (i = queue_run_in_order ? -1 : 0; + i <= (queue_run_in_order ? -1 : subcount); i++) { queue_filename *f; @@ -478,7 +473,7 @@ for (i = (queue_run_in_order? -1 : 0); } for (f = queue_get_spool_list(i, subdirs, &subcount, !queue_run_in_order); - f != NULL; + f; f = f->next) { pid_t pid; @@ -491,9 +486,7 @@ for (i = (queue_run_in_order? -1 : 0); check that the load average is low enough to permit deliveries. */ if (!queue_run_force && deliver_queue_load_max >= 0) - { - load_average = os_getloadavg(); - if (load_average > deliver_queue_load_max) + if ((load_average = os_getloadavg()) > deliver_queue_load_max) { log_write(L_queue_run, LOG_MAIN, "Abandon queue run: %s (load %.2f, max %.2f)", log_detail, @@ -503,18 +496,15 @@ for (i = (queue_run_in_order? -1 : 0); break; } else - { DEBUG(D_load) debug_printf("load average = %.2f max = %.2f\n", (double)load_average/1000.0, (double)deliver_queue_load_max/1000.0); - } - } /* Skip this message unless it's within the ID limits */ - if (stop_id != NULL && Ustrncmp(f->text, stop_id, MESSAGE_ID_LENGTH) > 0) + if (stop_id && Ustrncmp(f->text, stop_id, MESSAGE_ID_LENGTH) > 0) continue; - if (start_id != NULL && Ustrncmp(f->text, start_id, MESSAGE_ID_LENGTH) < 0) + if (start_id && Ustrncmp(f->text, start_id, MESSAGE_ID_LENGTH) < 0) continue; /* Check that the message still exists */ @@ -529,7 +519,7 @@ for (i = (queue_run_in_order? -1 : 0); delivering, but it's cheaper than forking a delivery process for each message when many are not going to be delivered. */ - if (deliver_selectstring != NULL || deliver_selectstring_sender != NULL || + if (deliver_selectstring || deliver_selectstring_sender || queue_run_first_delivery) { BOOL wanted = TRUE; @@ -562,19 +552,20 @@ for (i = (queue_run_in_order? -1 : 0); wanted = FALSE; } - /* Check for a matching address if deliver_selectstring[_sender} is set. + /* Check for a matching address if deliver_selectstring[_sender] is set. If so, we do a fully delivery - don't want to omit other addresses since their routing might trigger re-writing etc. */ /* Sender matching */ - else if (deliver_selectstring_sender != NULL && - !(deliver_selectstring_sender_regex? - (pcre_exec(selectstring_regex_sender, NULL, CS sender_address, - Ustrlen(sender_address), 0, PCRE_EOPT, NULL, 0) >= 0) - : - (strstric(sender_address, deliver_selectstring_sender, FALSE) - != NULL))) + else if ( deliver_selectstring_sender + && !(deliver_selectstring_sender_regex + ? (pcre_exec(selectstring_regex_sender, NULL, + CS sender_address, Ustrlen(sender_address), 0, PCRE_EOPT, + NULL, 0) >= 0) + : (strstric(sender_address, deliver_selectstring_sender, FALSE) + != NULL) + ) ) { DEBUG(D_queue_run) debug_printf("%s: sender address did not match %s\n", f->text, deliver_selectstring_sender); @@ -583,19 +574,19 @@ for (i = (queue_run_in_order? -1 : 0); /* Recipient matching */ - else if (deliver_selectstring != NULL) + else if (deliver_selectstring) { int i; for (i = 0; i < recipients_count; i++) { uschar *address = recipients_list[i].address; - if ((deliver_selectstring_regex? - (pcre_exec(selectstring_regex, NULL, CS address, - Ustrlen(address), 0, PCRE_EOPT, NULL, 0) >= 0) - : - (strstric(address, deliver_selectstring, FALSE) != NULL)) - && - tree_search(tree_nonrecipients, address) == NULL) + if ( (deliver_selectstring_regex + ? (pcre_exec(selectstring_regex, NULL, CS address, + Ustrlen(address), 0, PCRE_EOPT, NULL, 0) >= 0) + : (strstric(address, deliver_selectstring, FALSE) != NULL) + ) + && tree_search(tree_nonrecipients, address) == NULL + ) break; } @@ -610,6 +601,7 @@ for (i = (queue_run_in_order? -1 : 0); /* Recover store used when reading the header */ + spool_clear_header_globals(); store_reset(reset_point2); if (!wanted) continue; /* With next message */ } @@ -624,10 +616,8 @@ for (i = (queue_run_in_order? -1 : 0); pretty cheap. */ if (pipe(pfd) < 0) - { log_write(0, LOG_MAIN|LOG_PANIC_DIE, "failed to create pipe in queue " "runner process %d: %s", queue_run_pid, strerror(errno)); - } queue_run_pipe = pfd[pipe_write]; /* To ensure it gets passed on. */ /* Make sure it isn't stdin. This seems unlikely, but just to be on the @@ -681,11 +671,9 @@ for (i = (queue_run_in_order? -1 : 0); /* If the process crashed, tell somebody */ else if ((status & 0x00ff) != 0) - { log_write(0, LOG_MAIN|LOG_PANIC, "queue run: process %d crashed with signal %d while delivering %s", (int)pid, status & 0x00ff, f->text); - } /* 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 @@ -693,8 +681,9 @@ for (i = (queue_run_in_order? -1 : 0); the mere fact that read() unblocks is enough. */ set_process_info("running queue: waiting for children of %d", pid); - if (read(pfd[pipe_read], buffer, sizeof(buffer)) > 0) - log_write(0, LOG_MAIN|LOG_PANIC, "queue run: unexpected data on pipe"); + if ((status = read(pfd[pipe_read], buffer, sizeof(buffer))) != 0) + log_write(0, LOG_MAIN|LOG_PANIC, "queue run: %s on pipe", + status > 0 ? "unexpected data" : "error"); (void)close(pfd[pipe_read]); set_process_info("running queue"); @@ -708,6 +697,7 @@ for (i = (queue_run_in_order? -1 : 0); } } /* End loop for list of messages */ + tree_nonrecipients = NULL; store_reset(reset_point1); /* Scavenge list of messages */ /* If this was the first time through for random order processing, and @@ -715,18 +705,15 @@ for (i = (queue_run_in_order? -1 : 0); if (i == 0 && subcount > 1 && !queue_run_in_order) { - int j; + int j, r; for (j = 1; j <= subcount; j++) - { - int r = random_number(100); - if (r >= 50) + if ((r = random_number(100)) >= 50) { int k = (r % subcount) + 1; int x = subdirs[j]; subdirs[j] = subdirs[k]; subdirs[k] = x; } - } } } /* End loop for multiple directories */ @@ -867,19 +854,20 @@ if (option >= 8) option -= 8; /* Now scan the chain and print information, resetting store used each time. */ -reset_point = store_get(0); - -for (; f != NULL; f = f->next) +for (reset_point = store_get(0); + f; + spool_clear_header_globals(), store_reset(reset_point), f = f->next + ) { int rc, save_errno; int size = 0; BOOL env_read; - store_reset(reset_point); message_size = 0; message_subdir[0] = f->dir_uschar; rc = spool_read_header(f->text, FALSE, count <= 0); - if (rc == spool_read_notopen && errno == ENOENT && count <= 0) continue; + if (rc == spool_read_notopen && errno == ENOENT && count <= 0) + continue; save_errno = errno; env_read = (rc == spool_read_OK || rc == spool_read_hdrerror); @@ -900,7 +888,7 @@ for (; f != NULL; f = f->next) if (Ustat(fname, &statbuf) == 0) size = message_size + statbuf.st_size - SPOOL_DATA_START_OFFSET + 1; - i = (now - received_time)/60; /* minutes on queue */ + i = (now - received_time.tv_sec)/60; /* minutes on queue */ if (i > 90) { i = (i + 30)/60; @@ -911,8 +899,7 @@ for (; f != NULL; f = f->next) /* Collect delivered addresses from any J file */ fname[ptr] = 'J'; - jread = Ufopen(fname, "rb"); - if (jread != NULL) + if ((jread = Ufopen(fname, "rb"))) { while (Ufgets(big_buffer, big_buffer_size, jread) != NULL) { @@ -927,7 +914,7 @@ for (; f != NULL; f = f->next) fprintf(stdout, "%s ", string_format_size(size, big_buffer)); for (i = 0; i < 16; i++) fputc(f->text[i], stdout); - if (env_read && sender_address != NULL) + if (env_read && sender_address) { printf(" <%s>", sender_address); if (sender_set_untrusted) printf(" (%s)", originator_login); @@ -958,18 +945,18 @@ for (; f != NULL; f = f->next) printf("\n"); - if (recipients_list != NULL) + if (recipients_list) { for (i = 0; i < recipients_count; i++) { tree_node *delivered = tree_search(tree_nonrecipients, recipients_list[i].address); if (!delivered || option != 1) - printf(" %s %s\n", (delivered != NULL)? "D":" ", - recipients_list[i].address); - if (delivered != NULL) delivered->data.val = TRUE; + printf(" %s %s\n", + delivered ? "D" : " ", recipients_list[i].address); + if (delivered) delivered->data.val = TRUE; } - if (option == 2 && tree_nonrecipients != NULL) + if (option == 2 && tree_nonrecipients) queue_list_extras(tree_nonrecipients); printf("\n"); } @@ -1143,10 +1130,14 @@ if (action != MSG_SHOW_COPY) printf("Message %s ", id); switch(action) { case MSG_SHOW_COPY: - deliver_in_buffer = store_malloc(DELIVER_IN_BUFFER_SIZE); - deliver_out_buffer = store_malloc(DELIVER_OUT_BUFFER_SIZE); - transport_write_message(1, NULL, 0); - break; + { + transport_ctx tctx = {{0}}; + deliver_in_buffer = store_malloc(DELIVER_IN_BUFFER_SIZE); + deliver_out_buffer = store_malloc(DELIVER_OUT_BUFFER_SIZE); + tctx.u.fd = 1; + transport_write_message(&tctx, 0); + break; + } case MSG_FREEZE: