MIME structures in the message body. Victor Duchovni. File:
smtp/smtp_proto.c.
+20061210
+
+ Cleanup: streamline the signal handler reentrancy protections,
+ and document under what conditions these protections work,
+ with REENTRANCY sections in the relevant man pages. Files:
+ util/vbuf.c. util/msg.c, util/msg_output.c.
+
Wish list:
Update MILTER_README with Martinec info.
Incompatible changes with Postfix snapshot 20061209
===================================================
+The Postfix installation procedure no longer updates main.cf with
+"unknown_local_recipient_reject_code = 450". Four years after the
+introduction of mandatory recipient validation, this transitional
+tool is no longer neeed.
+
After upgrading Postfix you MUST execute "postfix reload", otherwise
the queue manager may log a warnings with:
followed by "postfix reload".
Small changes were made to the default bounce message templates,
-to prevent HTML-aware software from hiding or removing "<postmaster>"
-and producing really misleading text.
+to prevent HTML-aware software from hiding or removing the text
+"<postmaster>", and producing misleading text.
Major changes with Postfix snapshot 20061209
============================================
Better interoperability with non-conforming SMTP servers that reply
-and disconnect before Postfix has sent the end-of-data.
-
-Improved worst-case queue manager performance when deferring or
-bouncing lots of mail. Instead of talking to the bounce or defer
-service directly, this work is now done in the background by the
-error or retry service. The retry service is new.
-
-Improved worst-case queue manager performance when delivering
-multi-recipient mail. The queue manager now more agressively reloads
-recipients from the queue file as soon as slots become available,
-instead of waiting for slow deliveries to complete.
+and disconnect before Postfix has sent the complete message content.
+
+Improved worst-case (old and new) queue manager performance when
+deferring or bouncing large amounts of mail. Instead of talking to
+the bounce or defer service synchronously, this work is now done
+in the background by the error or retry service.
+
+Improved worst-case (new) queue manager performance when delivering
+multi-recipient mail. The queue manager now proactively reads
+recipients from the queue file, instead of waiting for the slowest
+deliveries to complete before reading in new recipients. This
+introduces two parameters: default_recipient_refill_limit (how many
+recipient slots to refill at a time) and default_recipient_refill_delay
+(how long to wait between refill operations). These two parameters
+act as defaults for optional per-transport settings.
Incompatible changes with Postfix snapshot 20061006
===================================================
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
-#define MAIL_RELEASE_DATE "20061209"
+#define MAIL_RELEASE_DATE "20061210"
#define MAIL_VERSION_NUMBER "2.4"
#ifdef SNAPSHOT
/* name must have been set by calling one of the msg_XXX_init()
/* functions (see the SEE ALSO section).
/*
-/* The aforementioned logging routines are protected against
-/* ordinary recursive calls and against re-entry by a signal
-/* handler.
-/*
-/* Protection against re-entry by signal handlers requires
-/* that:
-/* .IP \(bu
-/* The signal handler must never return. In other words, the
-/* signal handler must either call _exit(), kill itself with
-/* a signal, or do both.
-/* .IP \(bu
-/* The signal handler must not execute before the msg_XXX_init()
-/* functions complete initialization.
-/* .PP
-/* When re-entrancy is detected, the requested logging and
-/* optional cleanup operations are skipped. Skipping the logging
-/* operation prevents deadlock on Linux releases that use
-/* mutexes within system library routines such as syslog().
-/*
/* msg_error() reports a recoverable error and increments the error
/* counter. When the error count exceeds a pre-set limit (default: 13)
/* the program terminates by calling msg_fatal().
/* current function pointer. Specify a null argument to disable
/* this feature.
/*
-/* Note: each msg_cleanup() call-back function, and each Postfix
-/* or system function called by that call-back function, either
-/* protects itself against recursive calls and re-entry by a
-/* terminating signal handler, or is called exclusively by
-/* functions in the msg(3) module.
-/*
/* msg_error_limit() sets the error message count limit, and returns.
/* the old limit.
/*
/* msg_verbose is a global flag that can be set to make software
/* more verbose about what it is doing. By default the flag is zero.
/* By convention, a larger value means more noise.
+/* REENTRANCY
+/* .ad
+/* .fi
+/* The msg_info() etc. output routines are protected against
+/* ordinary recursive calls and against re-entry by signal
+/* handlers.
+/*
+/* Protection against re-entry by signal handlers is subject
+/* to the following limitations:
+/* .IP \(bu
+/* The signal handlers must never return. In other words, the
+/* signal handlers must do one or more of the following: call
+/* _exit(), kill the process with a signal, and permanently block
+/* the process.
+/* .IP \(bu
+/* The signal handlers must invoke msg_info() etc. not until
+/* after the msg_XXX_init() functions complete initialization,
+/* and not until after the first formatted output to a VSTRING
+/* or VSTREAM.
+/* .IP \(bu
+/* Each msg_cleanup() call-back function, and each Postfix or
+/* system function invoked by that call-back function, either
+/* protects itself against recursive calls and re-entry by a
+/* terminating signal handler, or is called exclusively by the
+/* msg(3) module.
+/* .PP
+/* When re-entrancy is detected, the requested output and
+/* optional cleanup operations are skipped. Skipping the output
+/* operations prevents memory corruption of VSTREAM_ERR data
+/* structures, and prevents deadlock on Linux releases that
+/* use mutexes within system library routines such as syslog().
+/* This protection exists under the condition that these
+/* specific resources are accessed exclusively via the msg_info()
+/* etc. functions.
/* SEE ALSO
/* msg_output(3) specify diagnostics disposition
/* msg_stdio(3) direct diagnostics to standard I/O stream
static int msg_error_bound = 13;
/*
- * Global scope, to discourage the compiler from doing smart things.
+ * The msg_exiting flag prevents us from recursively reporting an error with
+ * msg_fatal*() or msg_panic(), and provides a first-level safety net for
+ * optional cleanup actions against signal handler re-entry problems. Note
+ * that msg_vprintf() implements its own guard against re-entry.
+ *
+ * XXX We specify global scope, to discourage the compiler from doing smart
+ * things.
*/
volatile int msg_exiting = 0;
{
va_list ap;
- BEGIN_PROTECT_AGAINST_RECURSION_OR_TERMINATING_SIGNAL_HANDLER(msg_exiting);
va_start(ap, fmt);
msg_vprintf(MSG_INFO, fmt, ap);
va_end(ap);
- END_PROTECT_AGAINST_RECURSION_OR_TERMINATING_SIGNAL_HANDLER(msg_exiting);
}
/* msg_warn - report warning message */
{
va_list ap;
- BEGIN_PROTECT_AGAINST_RECURSION_OR_TERMINATING_SIGNAL_HANDLER(msg_exiting);
va_start(ap, fmt);
msg_vprintf(MSG_WARN, fmt, ap);
va_end(ap);
- END_PROTECT_AGAINST_RECURSION_OR_TERMINATING_SIGNAL_HANDLER(msg_exiting);
}
/* msg_error - report recoverable error */
{
va_list ap;
- BEGIN_PROTECT_AGAINST_RECURSION_OR_TERMINATING_SIGNAL_HANDLER(msg_exiting);
va_start(ap, fmt);
msg_vprintf(MSG_ERROR, fmt, ap);
va_end(ap);
- END_PROTECT_AGAINST_RECURSION_OR_TERMINATING_SIGNAL_HANDLER(msg_exiting);
if (++msg_error_count >= msg_error_bound)
msg_fatal("too many errors - program terminated");
}
{
va_list ap;
- BEGIN_PROTECT_AGAINST_RECURSION_OR_TERMINATING_SIGNAL_HANDLER(msg_exiting);
- va_start(ap, fmt);
- msg_vprintf(MSG_FATAL, fmt, ap);
- va_end(ap);
- if (msg_cleanup_fn)
- msg_cleanup_fn();
- END_PROTECT_AGAINST_RECURSION_OR_TERMINATING_SIGNAL_HANDLER(msg_exiting);
+ if (msg_exiting++ == 0) {
+ va_start(ap, fmt);
+ msg_vprintf(MSG_FATAL, fmt, ap);
+ va_end(ap);
+ if (msg_cleanup_fn)
+ msg_cleanup_fn();
+ }
sleep(1);
/* In case we're running as a signal handler. */
_exit(1);
{
va_list ap;
- BEGIN_PROTECT_AGAINST_RECURSION_OR_TERMINATING_SIGNAL_HANDLER(msg_exiting);
- va_start(ap, fmt);
- msg_vprintf(MSG_FATAL, fmt, ap);
- va_end(ap);
- if (msg_cleanup_fn)
- msg_cleanup_fn();
- END_PROTECT_AGAINST_RECURSION_OR_TERMINATING_SIGNAL_HANDLER(msg_exiting);
+ if (msg_exiting++ == 0) {
+ va_start(ap, fmt);
+ msg_vprintf(MSG_FATAL, fmt, ap);
+ va_end(ap);
+ if (msg_cleanup_fn)
+ msg_cleanup_fn();
+ }
sleep(1);
/* In case we're running as a signal handler. */
_exit(status);
{
va_list ap;
- BEGIN_PROTECT_AGAINST_RECURSION_OR_TERMINATING_SIGNAL_HANDLER(msg_exiting);
- va_start(ap, fmt);
- msg_vprintf(MSG_PANIC, fmt, ap);
- va_end(ap);
- END_PROTECT_AGAINST_RECURSION_OR_TERMINATING_SIGNAL_HANDLER(msg_exiting);
+ if (msg_exiting++ == 0) {
+ va_start(ap, fmt);
+ msg_vprintf(MSG_PANIC, fmt, ap);
+ va_end(ap);
+ }
sleep(1);
abort(); /* Die! */
/* In case we're running as a signal handler. */
/* const char *text;
/* DESCRIPTION
/* This module implements low-level output management for the
-/* msg(3) diagnostics interface. The output routines are
-/* protected against ordinary recursive calls and against
-/* re-entry by a signal handler.
-/*
-/* Protection against re-entry by a signal handler requires
-/* that:
-/* .IP \(bu
-/* The signal handler never returns.
-/* .IP \(bu
-/* The signal handler does not execute before msg_output()
-/* completes initialization.
-/* .IP \(bu
-/* Each msg_output() call-back function, and each Postfix or
-/* system function called by that call-back function, either
-/* protects itself against recursive calls and re-entry by a
-/* terminating signal handler, or is called exclusively by
-/* functions in the msg_output(3) module.
-/* .PP
-/* When re-entrancy is detected, the requested output operation
-/* is skipped. This prevents deadlock on Linux releases that
-/* use mutexes within system library routines such as syslog().
+/* msg(3) diagnostics interface.
/*
/* msg_output() registers an output handler for the diagnostics
/* interface. An application can register multiple output handlers.
/*
/* msg_text() copies a pre-formatted text, sanitizes the result, and
/* calls the output handlers registered with msg_output().
+/* REENTRANCY
+/* .ad
+/* .fi
+/* The above output routines are protected against ordinary
+/* recursive calls and against re-entry by signal
+/* handlers, with the following limitations:
+/* .IP \(bu
+/* The signal handlers must never return. In other words, the
+/* signal handlers must do one or more of the following: call
+/* _exit(), kill the process with a signal, and permanently
+/* block the process.
+/* .IP \(bu
+/* The signal handlers must call the above output routines not
+/* until after msg_output() completes initialization, and not
+/* until after the first formatted output to a VSTRING or
+/* VSTREAM.
+/* .IP \(bu
+/* Each msg_output() call-back function, and each Postfix or
+/* system function called by that call-back function, either
+/* must protect itself against recursive calls and re-entry
+/* by a terminating signal handler, or it must be called
+/* exclusively by functions in the msg_output(3) module.
+/* .PP
+/* When re-entrancy is detected, the requested output operation
+/* is skipped. This prevents memory corruption of VSTREAM_ERR
+/* data structures, and prevents deadlock on Linux releases
+/* that use mutexes within system library routines such as
+/* syslog(). This protection exists under the condition that
+/* these specific resources are accessed exclusively via
+/* msg_output() call-back functions.
/* LICENSE
/* .ad
/* .fi
/*
* Global scope, to discourage the compiler from doing smart things.
*/
-volatile int msg_vp_lock;
-volatile int msg_txt_lock;
+volatile int msg_vprintf_lock;
+volatile int msg_text_lock;
/*
* Private state.
void msg_vprintf(int level, const char *format, va_list ap)
{
- BEGIN_PROTECT_AGAINST_RECURSION_OR_TERMINATING_SIGNAL_HANDLER(msg_vp_lock);
- vstring_vsprintf(msg_buffer, percentm(format, errno), ap);
- msg_text(level, vstring_str(msg_buffer));
- END_PROTECT_AGAINST_RECURSION_OR_TERMINATING_SIGNAL_HANDLER(msg_vp_lock);
+ if (msg_vprintf_lock == 0) {
+ msg_vprintf_lock = 1;
+ /* OK if terminating signal handler hijacks control before next stmt. */
+ vstring_vsprintf(msg_buffer, percentm(format, errno), ap);
+ msg_text(level, vstring_str(msg_buffer));
+ msg_vprintf_lock = 0;
+ }
}
/* msg_text - sanitize and log pre-formatted text */
/*
* Sanitize the text. Use a private copy if necessary.
*/
- BEGIN_PROTECT_AGAINST_RECURSION_OR_TERMINATING_SIGNAL_HANDLER(msg_txt_lock);
- if (text != vstring_str(msg_buffer))
- vstring_strcpy(msg_buffer, text);
- printable(vstring_str(msg_buffer), '?');
- /* On-the-fly initialization for debugging test programs only. */
- if (msg_output_fn_count == 0)
- msg_vstream_init("unknown", VSTREAM_ERR);
- for (i = 0; i < msg_output_fn_count; i++)
- msg_output_fn[i] (level, vstring_str(msg_buffer));
- END_PROTECT_AGAINST_RECURSION_OR_TERMINATING_SIGNAL_HANDLER(msg_txt_lock);
+ if (msg_text_lock == 0) {
+ msg_text_lock = 1;
+ /* OK if terminating signal handler hijacks control before next stmt. */
+ if (text != vstring_str(msg_buffer))
+ vstring_strcpy(msg_buffer, text);
+ printable(vstring_str(msg_buffer), '?');
+ /* On-the-fly initialization for debugging test programs only. */
+ if (msg_output_fn_count == 0)
+ msg_vstream_init("unknown", VSTREAM_ERR);
+ for (i = 0; i < msg_output_fn_count; i++)
+ msg_output_fn[i] (level, vstring_str(msg_buffer));
+ msg_text_lock = 0;
+ }
}
*/
extern int REMOVE(const char *);
- /*
- * Enter, or skip, a critical region. This is used in fatal run-time error
- * handlers.
- *
- * It is OK if a terminating signal handler hijacks control before the next
- * statement executes. The interrupted thread will never be resumed; when
- * the signal handler leaves the critical region, the state of the
- * "critical" variable can safely be left in an inconsistent state. We
- * explicitly give the critical variable global scope, to discourage the
- * compiler from trying to do clever things.
- */
-#define BEGIN_PROTECT_AGAINST_RECURSION_OR_TERMINATING_SIGNAL_HANDLER(name) \
- if (name == 0) { \
- name = 1;
-
- /*
- * Leave critical region.
- */
-#define END_PROTECT_AGAINST_RECURSION_OR_TERMINATING_SIGNAL_HANDLER(name) \
- name = 0; \
- }
-
/* LICENSE
/* .ad
/* .fi
/* In addition, vbuf_print() recognizes the %m format specifier
/* and expands it to the error message corresponding to the current
/* value of the global \fIerrno\fR variable.
+/* REENTRANCY
+/* .ad
+/* .fi
+/* vbuf_print() allocates a static buffer. After completion
+/* of the first vbuf_print() call, this buffer is safe for
+/* reentrant vbuf_print() calls by (asynchronous) terminating
+/* signal handlers or by (synchronous) terminating error
+/* handlers. vbuf_print() initialization typically happens
+/* upon the first formatted output to a VSTRING or VSTREAM.
+/*
+/* However, it is up to the caller to ensure that the destination
+/* VSTREAM or VSTRING buffer is protected against reentrant usage.
/* LICENSE
/* .ad
/* .fi