-. $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"
.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
-$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
-------------------------------------------
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.
-/* $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 *
}
}
-/* 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)
{
-/* $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 *
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);