X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/a29e5231ac02b045d8fdd5610abac3c38131366f..d502442ac32f8964f6cf86469869cecb035d12c0:/src/src/transports/pipe.c diff --git a/src/src/transports/pipe.c b/src/src/transports/pipe.c index 2464abd14..3366a6dcf 100644 --- a/src/src/transports/pipe.c +++ b/src/src/transports/pipe.c @@ -1,10 +1,8 @@ -/* $Cambridge: exim/src/src/transports/pipe.c,v 1.15 2010/06/05 10:04:44 pdp Exp $ */ - /************************************************* * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2009 */ +/* Copyright (c) University of Cambridge 1995 - 2014 */ /* See the file NOTICE for conditions of use and distribution. */ @@ -39,8 +37,12 @@ optionlist pipe_transport_options[] = { (void *)offsetof(pipe_transport_options_block, environment) }, { "escape_string", opt_stringptr, (void *)offsetof(pipe_transport_options_block, escape_string) }, + { "force_command", opt_bool, + (void *)offsetof(pipe_transport_options_block, force_command) }, { "freeze_exec_fail", opt_bool, (void *)offsetof(pipe_transport_options_block, freeze_exec_fail) }, + { "freeze_signal", opt_bool, + (void *)offsetof(pipe_transport_options_block, freeze_signal) }, { "ignore_status", opt_bool, (void *)offsetof(pipe_transport_options_block, ignore_status) }, { "log_defer_output", opt_bool | opt_public, @@ -110,7 +112,9 @@ pipe_transport_options_block pipe_transport_option_defaults = { 20480, /* max_output */ 60*60, /* timeout */ 0, /* options */ + FALSE, /* force_command */ FALSE, /* freeze_exec_fail */ + FALSE, /* freeze_signal */ FALSE, /* ignore_status */ FALSE, /* permit_coredump */ FALSE, /* restrict_to_path */ @@ -185,7 +189,7 @@ if (ob->permit_coredump) if (errno != ENOSYS && errno != ENOTSUP) #endif log_write(0, LOG_MAIN, - "delivery setrlimit(RLIMIT_CORE, RLIMI_INFINITY) failed: %s", + "delivery setrlimit(RLIMIT_CORE, RLIM_INFINITY) failed: %s", strerror(errno)); } } @@ -568,10 +572,21 @@ options. */ if (testflag(addr, af_pfr) && addr->local_part[0] == '|') { - cmd = addr->local_part + 1; - while (isspace(*cmd)) cmd++; - expand_arguments = testflag(addr, af_expand_pipe); - expand_fail = FAIL; + if (ob->force_command) + { + /* Enables expansion of $address_pipe into seperate arguments */ + setflag(addr, af_force_command); + cmd = ob->cmd; + expand_arguments = TRUE; + expand_fail = PANIC; + } + else + { + cmd = addr->local_part + 1; + while (isspace(*cmd)) cmd++; + expand_arguments = testflag(addr, af_expand_pipe); + expand_fail = FAIL; + } } else { @@ -580,9 +595,12 @@ else expand_fail = PANIC; } -/* If no command has been supplied, we are in trouble. */ +/* If no command has been supplied, we are in trouble. + * We also check for an empty string since it may be + * coming from addr->local_part[0] == '|' + */ -if (cmd == NULL) +if (cmd == NULL || *cmd == '\0') { addr->transport_return = DEFER; addr->message = string_sprintf("no command specified for %s transport", @@ -748,14 +766,19 @@ if (outpid == 0) while ((rc = read(fd_out, big_buffer, big_buffer_size)) > 0) { if (addr->return_file >= 0) - write(addr->return_file, big_buffer, rc); + if(write(addr->return_file, big_buffer, rc) != rc) + DEBUG(D_transport) debug_printf("Problem writing to return_file\n"); count += rc; if (count > ob->max_output) { - uschar *message = US"\n\n*** Too much output - remainder discarded ***\n"; DEBUG(D_transport) debug_printf("Too much output from pipe - killed\n"); if (addr->return_file >= 0) - write(addr->return_file, message, Ustrlen(message)); + { + uschar *message = US"\n\n*** Too much output - remainder discarded ***\n"; + rc = Ustrlen(message); + if(write(addr->return_file, message, rc) != rc) + DEBUG(D_transport) debug_printf("Problem writing to return_file\n"); + } killpg(pid, SIGKILL); break; } @@ -960,11 +983,20 @@ if ((rc = child_close(pid, timeout)) != 0) /* Either the process completed, but yielded a non-zero (necessarily positive) status, or the process was terminated by a signal (rc will contain the negation of the signal number). Treat killing by signal as failure unless - status is being ignored. */ + status is being ignored. By default, the message is bounced back, unless + freeze_signal is set, in which case it is frozen instead. */ else if (rc < 0) { - if (!ob->ignore_status) + if (ob->freeze_signal) + { + addr->transport_return = DEFER; + addr->special_action = SPECIAL_FREEZE; + addr->message = string_sprintf("Child process of %s transport (running " + "command \"%s\") was terminated by signal %d (%s)%s", tblock->name, cmd, + -rc, os_strsignal(-rc), tmsg); + } + else if (!ob->ignore_status) { addr->transport_return = FAIL; addr->message = string_sprintf("Child process of %s transport (running "