From 76a2d7bad2f69787569f842d9d154524c4758ce3 Mon Sep 17 00:00:00 2001 From: Philip Hazel Date: Thu, 27 Jan 2005 15:00:38 +0000 Subject: [PATCH] Arrange for output from Perl's "warn" to go to the mainlog by default. --- doc/doc-src/spec.src | 38 +++++++++++++++++++++++--------------- doc/doc-txt/ChangeLog | 12 +++++++++++- src/src/daemon.c | 35 ++++++++++++++++++++++------------- src/src/perl.c | 17 ++++++++++++++++- 4 files changed, 72 insertions(+), 30 deletions(-) diff --git a/doc/doc-src/spec.src b/doc/doc-src/spec.src index 5ecbd9e9e..69ebca07d 100644 --- a/doc/doc-src/spec.src +++ b/doc/doc-src/spec.src @@ -1,4 +1,4 @@ -. $Cambridge: exim/doc/doc-src/spec.src,v 1.5 2005/01/27 10:25:35 ph10 Exp $ +. $Cambridge: exim/doc/doc-src/spec.src,v 1.6 2005/01/27 15:00:38 ph10 Exp $ . .set version "4.50" .set previousversion "4.40" @@ -10673,21 +10673,29 @@ terminating newline. .em .section Use of standard output and error by Perl +.index Perl||standard output and error You should not write to the standard error or output streams from within your -Perl code, as it is not defined how these are set up. In versions of Exim up to -at least 4.50, it is possible for the standard output or error to refer to the -SMTP connection during message reception. Writing to this stream is likely to -cause chaos. Something may be done about this in later releases. - -Unfortunately, the Perl \warn\ statment writes to the standard error stream, -and this may be embedded in Perl modules that you use, but over which you have -no control. One way round this is to ensure that the following Perl magic is -obeyed before \warn\ is used: -.display asis -$SIG{__WARN__} = sub { Exim::log_write($_[0]) }; -.endd -This causes the output of the \warn\ statement to be written to Exim's log -file. +Perl code, as it is not defined how these are set up. In versions of Exim +before 4.50, it is possible for the standard output or error to refer to the +SMTP connection during message reception via the daemon. Writing to this stream +is certain to cause chaos. From Exim 4.50 onwards, the standard output and +error streams are connected to \(/dev/null)\ in the daemon. The chaos is +avoided, but the output is lost. + +.index Perl||\warn\, use of +The Perl \warn\ statement writes to the standard error stream by default. Calls +to \warn\ may be embedded in Perl modules that you use, but over which you have +no control. When Exim starts up the Perl interpreter, it arranges for output +from the \warn\ statement to be written to the Exim main log. You can change +this by including appropriate Perl magic somewhere in your Perl code. For +example, to discard \warn\ output completely, you need this: +.display asis +$SIG{__WARN__} = sub { }; +.endd +Whenever a \warn\ is obeyed, the anonymous subroutine is called. In this +example, the code for the subroutine is empty, so it does nothing, but you can +include any Perl code that you like. The text of the \warn\ message is passed +as the first subroutine argument. .nem diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog index 799999e70..eaec31c78 100644 --- a/doc/doc-txt/ChangeLog +++ b/doc/doc-txt/ChangeLog @@ -1,4 +1,4 @@ -$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.75 2005/01/27 10:26:14 ph10 Exp $ +$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.76 2005/01/27 15:00:39 ph10 Exp $ Change log file for Exim from version 4.21 ------------------------------------------- @@ -351,6 +351,16 @@ Exim version 4.50 verify = header_sender/callout=defer_ok +75. A backgrounded daemon closed stdin/stdout/stderr on entry; this meant that + those file descriptors could be used for SMTP connections. If anything + wrote to stderr (the example that came up was "warn" in embedded Perl), it + could be sent to the SMTP client, causing chaos. The daemon now opens + stdin, stdout, and stderr to /dev/null when it puts itself into the + background. + +76. Arrange for output from Perl's "warn" command to be written to Exim's main + log by default. The user can override this with suitable Perl magic. + ---------------------------------------------------- See the note above about the 4.44 and 4.50 releases. diff --git a/src/src/daemon.c b/src/src/daemon.c index 1c274d732..88dd69d21 100644 --- a/src/src/daemon.c +++ b/src/src/daemon.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/daemon.c,v 1.5 2005/01/04 10:37:55 ph10 Exp $ */ +/* $Cambridge: exim/src/src/daemon.c,v 1.6 2005/01/27 15:00:39 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -1124,26 +1124,35 @@ if (daemon_listen) } } -/* We now close all open file descriptors that we know about, and disconnect -from the controlling terminal, unless background_daemon is unset. This is -always unset when debugging, but can also be forced. Most modern Unixes seem to -have setsid() for getting rid of the controlling terminal. For any OS that -doesn't, setsid() can be #defined as a no-op, or as something else. */ +/* The variable background_daemon is always false when debugging, but +can also be forced false in order to keep a non-debugging daemon in the +foreground. If background_daemon is true, close all open file descriptors that +we know about, but then re-open stdin, stdout, and stderr to /dev/null. + +This is protection against any called functions (in libraries, or in +Perl, or whatever) that think they can write to stderr (or stdout). Before this +was added, it was quite likely that an SMTP connection would use one of these +file descriptors, in which case writing random stuff to it caused chaos. + +Then disconnect from the controlling terminal, Most modern Unixes seem to have +setsid() for getting rid of the controlling terminal. For any OS that doesn't, +setsid() can be #defined as a no-op, or as something else. */ if (background_daemon) { - log_close_all(); /* Just in case anything was logged earlier */ - search_tidyup(); /* Just in case any were used in reading the config. */ - close(0); /* Get rid of stdin/stdout/stderr */ + log_close_all(); /* Just in case anything was logged earlier */ + search_tidyup(); /* Just in case any were used in reading the config. */ + close(0); /* Get rid of stdin/stdout/stderr */ close(1); close(2); + exim_nullstd(); /* Connect stdin/stdout/stderr to /dev/null */ log_stderr = NULL; /* So no attempt to copy paniclog output */ /* If the parent process of this one has pid == 1, we are re-initializing the - daemon as the result of a SIGHUP. In this case, there is no need to do any - forking, because the controlling terminal has long gone. Otherwise, fork, - in case current process is a process group leader (see 'man setsid' for an - explanation). */ + daemon as the result of a SIGHUP. In this case, there is no need to do + anything, because the controlling terminal has long gone. Otherwise, fork, in + case current process is a process group leader (see 'man setsid' for an + explanation) before calling setsid(). */ if (getppid() != 1) { diff --git a/src/src/perl.c b/src/src/perl.c index a22fe6f40..5bb7ad360 100644 --- a/src/src/perl.c +++ b/src/src/perl.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/perl.c,v 1.2 2004/12/20 11:46:21 ph10 Exp $ */ +/* $Cambridge: exim/src/src/perl.c,v 1.3 2005/01/27 15:00:39 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -109,6 +109,21 @@ init_perl(uschar *startup_code) perl_run(interp_perl); { dSP; + + /*********************************************************************/ + /* These lines by PH added to make "warn" output go to the Exim log; I + hope this doesn't break anything. */ + + sv = newSVpv( + "$SIG{__WARN__} = sub { my($s) = $_[0];" + "$s =~ s/\\n$//;" + "Exim::log_write($s) };", 0); + PUSHMARK(SP); + perl_eval_sv(sv, G_SCALAR|G_DISCARD|G_KEEPERR); + SvREFCNT_dec(sv); + if (SvTRUE(ERRSV)) return US SvPV(ERRSV, len); + /*********************************************************************/ + sv = newSVpv(CS startup_code, 0); PUSHMARK(SP); perl_eval_sv(sv, G_SCALAR|G_DISCARD|G_KEEPERR); -- 2.30.2