X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/65e061b76867a9ea7aeeb535341b790b90ae6c21..9bfb7e1bec2b3b6022c2e7b42df9ac606693dcfd:/src/src/exim.c diff --git a/src/src/exim.c b/src/src/exim.c index 88e119778..5a1437c3b 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -212,8 +212,7 @@ int fd; os_restarting_signal(sig, usr1_handler); -fd = Uopen(process_log_path, O_APPEND|O_WRONLY, LOG_MODE); -if (fd < 0) +if ((fd = Uopen(process_log_path, O_APPEND|O_WRONLY, LOG_MODE)) < 0) { /* If we are already running as the Exim user, try to create it in the current process (assuming spool_directory exists). Otherwise, if we are @@ -345,7 +344,7 @@ Arguments: Returns: -1, 0, or +1 */ -int +static int exim_tvcmp(struct timeval *t1, struct timeval *t2) { if (t1->tv_sec > t2->tv_sec) return +1; @@ -659,12 +658,13 @@ Returns: does not return */ void -exim_exit(int rc) +exim_exit(int rc, const uschar * process) { search_tidyup(); DEBUG(D_any) - debug_printf(">>>>>>>>>>>>>>>> Exim pid=%d terminating with rc=%d " - ">>>>>>>>>>>>>>>>\n", (int)getpid(), rc); + debug_printf(">>>>>>>>>>>>>>>> Exim pid=%d %s%s%sterminating with rc=%d " + ">>>>>>>>>>>>>>>>\n", (int)getpid(), + process ? "(" : "", process, process ? ") " : "", rc); exit(rc); } @@ -841,7 +841,8 @@ fprintf(f, "Support for:"); fprintf(f, " SOCKS"); #endif #ifdef TCP_FASTOPEN - fprintf(f, " TCP_Fast_Open"); + deliver_init(); + if (tcp_fastopen_ok) fprintf(f, " TCP_Fast_Open"); #endif #ifdef EXPERIMENTAL_LMDB fprintf(f, " Experimental_LMDB"); @@ -1150,8 +1151,7 @@ uschar * local_part_quote(uschar *lpart) { BOOL needs_quote = FALSE; -int size, ptr; -uschar *yield; +gstring * g; uschar *t; for (t = lpart; !needs_quote && *t != 0; t++) @@ -1162,26 +1162,24 @@ for (t = lpart; !needs_quote && *t != 0; t++) if (!needs_quote) return lpart; -size = ptr = 0; -yield = string_catn(NULL, &size, &ptr, US"\"", 1); +g = string_catn(NULL, US"\"", 1); for (;;) { uschar *nq = US Ustrpbrk(lpart, "\\\""); if (nq == NULL) { - yield = string_cat(yield, &size, &ptr, lpart); + g = string_cat(g, lpart); break; } - yield = string_catn(yield, &size, &ptr, lpart, nq - lpart); - yield = string_catn(yield, &size, &ptr, US"\\", 1); - yield = string_catn(yield, &size, &ptr, nq, 1); + g = string_catn(g, lpart, nq - lpart); + g = string_catn(g, US"\\", 1); + g = string_catn(g, nq, 1); lpart = nq + 1; } -yield = string_catn(yield, &size, &ptr, US"\"", 1); -yield[ptr] = 0; -return yield; +g = string_catn(g, US"\"", 1); +return string_from_gstring(g); } @@ -1254,11 +1252,9 @@ static uschar * get_stdinput(char *(*fn_readline)(const char *), void(*fn_addhist)(const char *)) { int i; -int size = 0; -int ptr = 0; -uschar *yield = NULL; +gstring * g = NULL; -if (fn_readline == NULL) { printf("> "); fflush(stdout); } +if (!fn_readline) { printf("> "); fflush(stdout); } for (i = 0;; i++) { @@ -1293,23 +1289,22 @@ for (i = 0;; i++) while (p < ss && isspace(*p)) p++; /* leading space after cont */ } - yield = string_catn(yield, &size, &ptr, p, ss - p); + g = string_catn(g, p, ss - p); #ifdef USE_READLINE - if (fn_readline != NULL) free(readline_line); + if (fn_readline) free(readline_line); #endif - /* yield can only be NULL if ss==p */ - if (ss == p || yield[ptr-1] != '\\') - { - if (yield) yield[ptr] = 0; + /* g can only be NULL if ss==p */ + if (ss == p || g->s[g->ptr-1] != '\\') break; - } - yield[--ptr] = 0; + + --g->ptr; + (void) string_from_gstring(g); } -if (yield == NULL) printf("\n"); -return yield; +if (!g) printf("\n"); +return string_from_gstring(g); } @@ -1443,10 +1438,9 @@ for (m = macros; m; m = m->next) if (m->command_line) } if (!found) return FALSE; - if (m->replacement == NULL) + if (!m->replacement) continue; - len = Ustrlen(m->replacement); - if (len == 0) + if ((len = m->replen) == 0) continue; n = pcre_exec(regex_whitelisted_macro, NULL, CS m->replacement, len, 0, PCRE_EOPT, NULL, 0); @@ -2457,7 +2451,7 @@ for (i = 1; i < argc; i++) exit(EXIT_FAILURE); } - m = macro_create(name, s, TRUE, FALSE); + m = macro_create(string_copy(name), string_copy(s), TRUE); if (clmacro_count >= MAX_CLMACROS) { @@ -2739,7 +2733,7 @@ for (i = 1; i < argc; i++) /* -MCD: set the smtp_use_dsn flag; this indicates that the host that exim is connected to supports the esmtp extension DSN */ - case 'D': smtp_peer_options |= PEER_OFFERED_DSN; break; + case 'D': smtp_peer_options |= OPTION_DSN; break; /* -MCG: set the queue name, to a non-default value */ @@ -2749,12 +2743,12 @@ for (i = 1; i < argc; i++) /* -MCK: the peer offered CHUNKING. Must precede -MC */ - case 'K': smtp_peer_options |= PEER_OFFERED_CHUNKING; break; + case 'K': smtp_peer_options |= OPTION_CHUNKING; break; /* -MCP: set the smtp_use_pipelining flag; this is useful only when it preceded -MC (see above) */ - case 'P': smtp_peer_options |= PEER_OFFERED_PIPE; break; + case 'P': smtp_peer_options |= OPTION_PIPE; break; /* -MCQ: pass on the pid of the queue-running process that started this chain of deliveries and the fd of its synchronizing pipe; this @@ -2769,7 +2763,7 @@ for (i = 1; i < argc; i++) /* -MCS: set the smtp_use_size flag; this is useful only when it precedes -MC (see above) */ - case 'S': smtp_peer_options |= PEER_OFFERED_SIZE; break; + case 'S': smtp_peer_options |= OPTION_SIZE; break; #ifdef SUPPORT_TLS /* -MCt: similar to -MCT below but the connection is still open @@ -2789,7 +2783,7 @@ for (i = 1; i < argc; i++) precedes -MC (see above). The flag indicates that the host to which Exim is connected has offered TLS support. */ - case 'T': smtp_peer_options |= PEER_OFFERED_TLS; break; + case 'T': smtp_peer_options |= OPTION_TLS; break; #endif default: badarg = TRUE; break; @@ -4133,9 +4127,8 @@ if (((debug_selector & D_any) != 0 || LOGGING(arguments)) quote = US""; while (*pp != 0) if (isspace(*pp++)) { quote = US"\""; break; } } - sprintf(CS p, " %s%.*s%s", quote, (int)(big_buffer_size - + p += sprintf(CS p, " %s%.*s%s", quote, (int)(big_buffer_size - (p - big_buffer) - 4), printing, quote); - while (*p) p++; } if (LOGGING(arguments)) @@ -4156,6 +4149,7 @@ if (Uchdir(spool_directory) != 0) int dummy; (void)directory_make(spool_directory, US"", SPOOL_DIRECTORY_MODE, FALSE); dummy = /* quieten compiler */ Uchdir(spool_directory); + dummy = dummy; /* yet more compiler quietening, sigh */ } /* Handle calls with the -bi option. This is a sendmail option to rebuild *the* @@ -4490,7 +4484,7 @@ if (test_retry_arg >= 0) if (test_retry_arg >= argc) { printf("-brt needs a domain or address argument\n"); - exim_exit(EXIT_FAILURE); + exim_exit(EXIT_FAILURE, US"main"); } s1 = argv[test_retry_arg++]; s2 = NULL; @@ -4539,8 +4533,9 @@ if (test_retry_arg >= 0) } } - yield = retry_find_config(s1, s2, basic_errno, more_errno); - if (yield == NULL) printf("No retry information found\n"); else + if (!(yield = retry_find_config(s1, s2, basic_errno, more_errno))) + printf("No retry information found\n"); + else { retry_rule *r; more_errno = yield->more_errno; @@ -4572,7 +4567,7 @@ if (test_retry_arg >= 0) printf("auth_failed "); else printf("* "); - for (r = yield->rules; r != NULL; r = r->next) + for (r = yield->rules; r; r = r->next) { printf("%c,%s", r->rule, readconf_printtime(r->timeout)); /* Do not */ printf(",%s", readconf_printtime(r->p1)); /* amalgamate */ @@ -4595,7 +4590,7 @@ if (test_retry_arg >= 0) printf("\n"); } - exim_exit(EXIT_SUCCESS); + exim_exit(EXIT_SUCCESS, US"main"); } /* Handle a request to list one or more configuration options */ @@ -4619,14 +4614,14 @@ if (list_options) } else readconf_print(argv[i], NULL, flag_n); } - exim_exit(EXIT_SUCCESS); + exim_exit(EXIT_SUCCESS, US"main"); } if (list_config) { set_process_info("listing config"); readconf_print(US"config", NULL, flag_n); - exim_exit(EXIT_SUCCESS); + exim_exit(EXIT_SUCCESS, US"main"); } @@ -4655,7 +4650,7 @@ if (msg_action_arg > 0 && msg_action != MSG_LOAD) if (prod_requires_admin && !admin_user) { fprintf(stderr, "exim: Permission denied\n"); - exim_exit(EXIT_FAILURE); + exim_exit(EXIT_FAILURE, US"main"); } set_process_info("delivering specified messages"); if (deliver_give_up) forced_delivery = deliver_force_thaw = TRUE; @@ -4674,11 +4669,11 @@ if (msg_action_arg > 0 && msg_action != MSG_LOAD) { fprintf(stderr, "failed to fork delivery process for %s: %s\n", argv[i], strerror(errno)); - exim_exit(EXIT_FAILURE); + exim_exit(EXIT_FAILURE, US"main"); } else wait(&status); } - exim_exit(EXIT_SUCCESS); + exim_exit(EXIT_SUCCESS, US"main"); } @@ -4697,7 +4692,7 @@ if (queue_interval == 0 && !daemon_listen) else set_process_info("running the queue (single queue run)"); queue_run(start_queue_run_id, stop_queue_run_id, FALSE); - exim_exit(EXIT_SUCCESS); + exim_exit(EXIT_SUCCESS, US"main"); } @@ -4720,10 +4715,9 @@ for (i = 0;;) /* If user name has not been set by -F, set it from the passwd entry unless -f has been used to set the sender address by a trusted user. */ - if (originator_name == NULL) + if (!originator_name) { - if (sender_address == NULL || - (!trusted_caller && filter_test == FTEST_NONE)) + if (!sender_address || (!trusted_caller && filter_test == FTEST_NONE)) { uschar *name = US pw->pw_gecos; uschar *amp = Ustrchr(name, '&'); @@ -4733,11 +4727,11 @@ for (i = 0;;) replaced by a copy of the login name, and some even specify that the first character should be upper cased, so that's what we do. */ - if (amp != NULL) + if (amp) { int loffset; string_format(buffer, sizeof(buffer), "%.*s%n%s%s", - amp - name, name, &loffset, originator_login, amp + 1); + (int)(amp - name), name, &loffset, originator_login, amp + 1); buffer[loffset] = toupper(buffer[loffset]); name = buffer; } @@ -4745,7 +4739,7 @@ for (i = 0;;) /* If a pattern for matching the gecos field was supplied, apply it and then expand the name string. */ - if (gecos_pattern != NULL && gecos_name != NULL) + if (gecos_pattern && gecos_name) { const pcre *re; re = regex_must_compile(gecos_pattern, FALSE, TRUE); /* Use malloc */ @@ -4754,7 +4748,7 @@ for (i = 0;;) { uschar *new_name = expand_string(gecos_name); expand_nmax = -1; - if (new_name != NULL) + if (new_name) { DEBUG(D_receive) debug_printf("user name \"%s\" extracted from " "gecos field \"%s\"\n", new_name, name); @@ -4851,10 +4845,10 @@ if (test_rewrite_arg >= 0) if (test_rewrite_arg >= argc) { printf("-brw needs an address argument\n"); - exim_exit(EXIT_FAILURE); + exim_exit(EXIT_FAILURE, US"main"); } rewrite_test(argv[test_rewrite_arg]); - exim_exit(EXIT_SUCCESS); + exim_exit(EXIT_SUCCESS, US"main"); } /* A locally-supplied message is considered to be coming from a local user @@ -4969,7 +4963,7 @@ if (verify_address_mode || address_test_mode) } route_tidyup(); - exim_exit(exit_value); + exim_exit(exit_value, US"main"); } /* Handle expansion checking. Either expand items on the command line, or read @@ -5071,7 +5065,7 @@ if (expansion_test) deliver_datafile = -1; } - exim_exit(EXIT_SUCCESS); + exim_exit(EXIT_SUCCESS, US"main"); } @@ -5165,7 +5159,7 @@ if (host_checking) } smtp_log_no_mail(); } - exim_exit(EXIT_SUCCESS); + exim_exit(EXIT_SUCCESS, US"main"); } @@ -5329,7 +5323,7 @@ if (smtp_input) if (!smtp_start_session()) { mac_smtp_fflush(); - exim_exit(EXIT_SUCCESS); + exim_exit(EXIT_SUCCESS, US"smtp_start toplevel"); } } @@ -5444,14 +5438,14 @@ while (more) cancel_cutthrough_connection(TRUE, US"receive dropped"); if (more) goto moreloop; smtp_log_no_mail(); /* Log no mail if configured */ - exim_exit(EXIT_FAILURE); + exim_exit(EXIT_FAILURE, US"receive toplevel"); } } else { cancel_cutthrough_connection(TRUE, US"message setup dropped"); smtp_log_no_mail(); /* Log no mail if configured */ - exim_exit((rc == 0)? EXIT_SUCCESS : EXIT_FAILURE); + exim_exit(rc ? EXIT_FAILURE : EXIT_SUCCESS, US"msg setup toplevel"); } } @@ -5502,14 +5496,12 @@ while (more) if (error_handling == ERRORS_STDERR) { fprintf(stderr, "exim: too many recipients\n"); - exim_exit(EXIT_FAILURE); + exim_exit(EXIT_FAILURE, US"main"); } else - { return moan_to_sender(ERRMESS_TOOMANYRECIP, NULL, NULL, stdin, TRUE)? errors_sender_rc : EXIT_FAILURE; - } #ifdef SUPPORT_I18N { @@ -5538,7 +5530,7 @@ while (more) { fprintf(stderr, "exim: bad recipient address \"%s\": %s\n", string_printing(list[i]), errmess); - exim_exit(EXIT_FAILURE); + exim_exit(EXIT_FAILURE, US"main"); } else { @@ -5593,7 +5585,7 @@ while (more) if (!receive_timeout) { - struct timeval t = { 30*60, 0 }; /* 30 minutes */ + struct timeval t = { .tv_sec = 30*60, .tv_usec = 0 }; /* 30 minutes */ fd_set r; FD_ZERO(&r); FD_SET(0, &r); @@ -5611,7 +5603,7 @@ while (more) for real; when reading the headers of a message for filter testing, it is TRUE if the headers were terminated by '.' and FALSE otherwise. */ - if (message_id[0] == 0) exim_exit(EXIT_FAILURE); + if (message_id[0] == 0) exim_exit(EXIT_FAILURE, US"main"); } /* Non-SMTP message reception */ /* If this is a filter testing run, there are headers in store, but @@ -5656,7 +5648,7 @@ while (more) if (chdir("/")) /* Get away from wherever the user is running this from */ { DEBUG(D_receive) debug_printf("chdir(\"/\") failed\n"); - exim_exit(EXIT_FAILURE); + exim_exit(EXIT_FAILURE, US"main"); } /* Now we run either a system filter test, or a user filter test, or both. @@ -5665,20 +5657,16 @@ while (more) explicitly. */ if ((filter_test & FTEST_SYSTEM) != 0) - { if (!filter_runtest(filter_sfd, filter_test_sfile, TRUE, more)) - exim_exit(EXIT_FAILURE); - } + exim_exit(EXIT_FAILURE, US"main"); memcpy(filter_sn, filter_n, sizeof(filter_sn)); if ((filter_test & FTEST_USER) != 0) - { if (!filter_runtest(filter_ufd, filter_test_ufile, FALSE, more)) - exim_exit(EXIT_FAILURE); - } + exim_exit(EXIT_FAILURE, US"main"); - exim_exit(EXIT_SUCCESS); + exim_exit(EXIT_SUCCESS, US"main"); } /* Else act on the result of message reception. We should not get here unless @@ -5804,7 +5792,7 @@ while (more) log_write(0, LOG_MAIN|LOG_PANIC, "process %d crashed with signal %d while delivering %s", (int)pid, status & 0x00ff, message_id); - if (mua_wrapper && (status & 0xffff) != 0) exim_exit(EXIT_FAILURE); + if (mua_wrapper && (status & 0xffff) != 0) exim_exit(EXIT_FAILURE, US"main"); } } } @@ -5836,8 +5824,54 @@ moreloop: store_reset(reset_point); } -exim_exit(EXIT_SUCCESS); /* Never returns */ +exim_exit(EXIT_SUCCESS, US"main"); /* Never returns */ return 0; /* To stop compiler warning */ } +/************************************************* +* read as much as requested * +*************************************************/ + +/* The syscall read(2) doesn't always returns as much as we want. For +several reasons it might get less. (Not talking about signals, as syscalls +are restartable). When reading from a network or pipe connection the sender +might send in smaller chunks, with delays between these chunks. The read(2) +may return such a chunk. + +The more the writer writes and the smaller the pipe between write and read is, +the more we get the chance of reading leass than requested. (See bug 2130) + +This function read(2)s until we got all the data we *requested*. + +Note: This function may block. Use it only if you're sure about the +amount of data you will get. + +Argument: + fd the file descriptor to read from + buffer pointer to a buffer of size len + len the requested(!) amount of bytes + +Returns: the amount of bytes read +*/ +ssize_t +readn(int fd, void *buffer, size_t len) +{ + void *next = buffer; + void *end = buffer + len; + + while (next < end) + { + ssize_t got = read(fd, next, end - next); + + /* I'm not sure if there are signals that can interrupt us, + for now I assume the worst */ + if (got == -1 && errno == EINTR) continue; + if (got <= 0) return next - buffer; + next += got; + } + + return len; +} + + /* End of exim.c */