Feature: "postsuper -d queueID" deletes one message queue
file; "postsuper -d -" reads zero or more queue IDs from
- standard input. In order to make this operation usable
- with a running Postfix mail system, some routines were made
- more tolerant for sudden queue file disappearances. Files:
- postsuper/postsuper.c, global/deliver_request.c,
- *qmgr/qmgr_move.c.
+ standard input, and deletes one instance of each file.
+ File: postsuper/postsuper.c.
+
+ Code cleanup: in order to make postsuper -d safe with a
+ running Postfix mail system, some routines had to be made
+ tolerant for sudden queue file disappearances. Files:
+ global/deliver_request.c, *qmgr/qmgr_move.c.
+
+ Code cleanup: in order to make postsuper -d more usable,
+ the showq command was extended to safely list the possibly
+ world-writable maildrop directory. File: showq/showq.c.
+Major changes with snapshot-20010502
+====================================
+
+This snapshot release incorporates all the bugfixes of patch 02
+for the official Postfix release 20010228, and adds a few minor
+features.
+
+The Postfix SMTP client now by default randomly shuffles destination
+IP addresses of equal preference (whether obtained via MX lookup
+or otherwise). Reportedly, this is needed for sites that use
+Bernstein's dnscache program. Specify "smtp_randomize_addresses =
+no" to disable this behavior. Based on shuffling code by Aleph1.
+
+"postmap -q -" and "postmap -d -" read key values from standard
+input, which makes it easier to drive them from another program.
+The same feature was added to the postalias command.
+
+The postsuper command now has an option to delete queue files. In
+principle this command can be used while Postfix is running, but
+there is a possibility of deleting the wrong queue file when Postfix
+deletes a queue file and reuses the queue ID for a new message.
+In that case, postsuper will delete the new message.
+
Incompatible changes with snapshot-20010329
===========================================
Major changes with snapshot-20010128
====================================
-Updated nqmgr (experimental queue manager with clever queueing
+Updated nqmgr (experimental queue manager with clever queuing
strategy) by Patrik Rak. This code is still new. Once it stops
changing (for a long time!) it will become part of the non-beta
release.
My Postfix server is too slow. When I telnet to the SMTP port
(<tt>telnet hostname 25</tt>), the response comes after 40 seconds.
-On the other hand, when I telnet to the the POP port (<tt>telnet
+On the other hand, when I telnet to the POP port (<tt>telnet
hostname 110</tt>) the response comes with no delay.
</blockquote>
users are restricted in where they can send mail, and the other
table defines what destinations are local. It is left as an exercise
for the reader to change this into a scheme where only some users
-have permission to send send mail to off-site destinations, and
+have permission to send mail to off-site destinations, and
where most users are restricted.
<p>
<p>
<li>Execute the command <b>postmap /etc/postfix/virtual</b> whenever
-you edit the the <b>virtual</b> table.
+you edit the <b>virtual</b> table.
<p>
<a name="deleting"><h3>Deleting a message from the Postfix queue</h3></a>
-To delete ONE message with queue id ABCDEF (e.g., from <b>mailq</b>
-output) from the Postfix queue, it is not necessary to stop Postfix.
+As of Postfix version 20010502, the <b>postsuper</b> command
+has an option to delete Postfix message queue files. To delete
+the message with queue id ABCDEF, perhaps obtained from <b>mailq</b>
+output, one would use:
<p>
+<blockquote>
<pre>
- # cd /var/spool/postfix
- # find incoming active deferred -name ABCDEF -print | sed 1q | xargs rm
+# postsuper -d ABCDEF
</pre>
+</blockquote>
<p>
-The above command is safe because it deletes at most one file.
-There is no risk of deleting newly arrived mail that happens to get
-the same queue file name.
+To delete a large number of files one would use:
<p>
-If you have to delete a large amount of mail, you must stop Postfix
-first.
-
-<p>
+<blockquote>
<pre>
- # postfix stop
- # cd /var/spool/postfix
- # find incoming active deferred defer -type f -print |
- fgrep -xf /file/with/queue-ids | xargs rm
- # postfix start
+# postsuper -d - < <i>filename-with-queue-ids</i>
</pre>
+</blockquote>
+
+<p>
+
+It is usually safe to do this while the Postfix system is running.
+However, there is a small chance of deleting the wrong queue
+file. The scenario goes like this:
<p>
-Do not use the above <b>find</b> command on a running Postfix
-system, because it can delete files that belong to new mail that
-arrives while you are deleting queue files.
+<ul>
+
+<li>The Postfix queue manager deletes the file that <b>postsuper</b>
+was supposed to delete, because Postfix was finished with the
+message.
+
+<p>
+
+<li>New mail arrives, and the new message is given the same queue
+ID as the message that <b>postsuper</b> was supposed to delete.
+The probability for reusing a deleted queue ID is about 1 in
+2<sup>15</sup> (the number of different microsecond values that
+the system clock can distinguish).
+
+<p>
+
+<li><b>postsuper</b> deletes the new message file, instead of the
+old file that should have been deleted.
+
+</ul>
<hr>
<b>postsuper</b> [<b>-d</b> <i>queue_id</i>] [<b>-p</b>] [<b>-s</b>] [<b>-v</b>] [<i>directory</i> <i>...</i>]
<b>DESCRIPTION</b>
- The <b>postsuper</b> command does small maintenance jobs on the
- named Postfix queue directories (default: all). Directory
- names are relative to the Postfix top-level queue direc-
- tory.
+ The <b>postsuper</b> command does small maintenance jobs. Use of
+ the command is restricted to the super-user.
By default, <b>postsuper</b> performs the operations requested
- with the <b>-s</b> and <b>-p</b> command-line options. <b>postsuper</b> always
- tries to remove objects that are neither files nor direc-
- tories. Use of this command is restricted to the super-
- user.
+ with the <b>-s</b> and <b>-p</b> command-line options on the named Post-
+ fix queue directories (default: all). Directory names are
+ relative to the Postfix top-level queue directory.
Options:
- <b>-d</b> Delete one message queue file with the named queue
+ <b>-d</b> This option ignores any <i>directory</i> argument(s).
+ Delete one message queue file with the named queue
ID. Specify multiple <b>-d</b> options to delete multiple
queue files by name.
Alternatively, if a <i>queue_id</i> of <b>-</b> is specified, the
program reads queue IDs from standard input.
- This operation can be performed safely while the
- mail system is running, although the queue manager
- may issue warnings when a file suddenly disappears.
- The exit status is zero if at least one of the
- named message queue files was found.
+ The <b>postsuper</b> exit status is non-zero when no mes-
+ sage queue file was deleted.
+
+ <b>There</b> <b>is</b> <b>a</b> <b>very</b> <b>small</b> <b>possibility</b> <b>that</b> <b>postsuper</b>
+ <b>deletes</b> <b>the</b> <b>wrong</b> <b>message</b> <b>file</b> <b>when</b> <b>it</b> <b>is</b> <b>executed</b>
+ <b>while</b> <b>the</b> <b>Postfix</b> <b>mail</b> <b>system</b> <b>is</b> <b>running.</b>
+
+ The scenario is as follows:
+
+ <b>o</b> The Postfix queue manager deletes the file
+ that <b>postsuper</b> was supposed to delete,
+ because Postfix was finished with the mes-
+ sage.
+
+ <b>o</b> New mail arrives, and the new message is
+ given the same queue ID as the message that
+ <b>postsuper</b> was supposed to delete. The prob-
+ ability for reusing a deleted queue ID is
+ about 1 in 2**15 (the number of different
+ microsecond values that the system clock can
+ distinguish).
+
+ <b>o</b> <b>postsuper</b> deletes the new message file,
+ instead of the old file that should have
+ been deleted.
<b>-s</b> Structure check. Move queue files that are in the
wrong place in the file system hierarchy and remove
subdirectories that are no longer needed. File
+
+
+
+ 1
+
+
+
+
+
+POSTSUPER(1) POSTSUPER(1)
+
+
rearrangements are necessary after a change in the
<b>hash</b><i>_</i><b>queue</b><i>_</i><b>names</b> and/or <b>hash</b><i>_</i><b>queue</b><i>_</i><b>depth</b> configura-
tion parameters. It is highly recommended to run
<b>CONFIGURATION</b> <b>PARAMETERS</b>
See the Postfix <b>main.cf</b> file for syntax details and for
-
-
-
- 1
-
-
-
-
-
-POSTSUPER(1) POSTSUPER(1)
-
-
default values.
<b>hash</b><i>_</i><b>queue</b><i>_</i><b>depth</b>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.SH DESCRIPTION
.ad
.fi
-The \fBpostsuper\fR command does small maintenance jobs on the named
-Postfix queue directories (default: all).
-Directory names are relative to the Postfix top-level queue directory.
+The \fBpostsuper\fR command does small maintenance jobs. Use of
+the command is restricted to the super-user.
By default, \fBpostsuper\fR performs the operations requested with the
-\fB-s\fR and \fB-p\fR command-line options.
-\fBpostsuper\fR always tries to remove objects that are neither files
-nor directories. Use of this command is restricted to the super-user.
+\fB-s\fR and \fB-p\fR command-line options on the named Postfix queue
+directories (default: all).
+Directory names are relative to the Postfix top-level queue directory.
Options:
.IP \fB-d \fIqueue_id\fR
+This option ignores any \fIdirectory\fR argument(s).
Delete one message queue file with the named queue ID. Specify
multiple \fB-d\fR options to delete multiple queue files by name.
.sp
Alternatively, if a \fIqueue_id\fR of \fB-\fR is specified, the
program reads queue IDs from standard input.
.sp
-This operation can be performed safely while the mail system is
-running, although the queue manager may issue warnings when a
-file suddenly disappears. The exit status is zero if at least one
-of the named message queue files was found.
+The \fBpostsuper\fR exit status is non-zero when no message queue
+file was deleted.
+.sp
+.ft B
+There is a very small possibility that postsuper deletes the
+wrong message file when it is executed while the Postfix mail
+system is running.
+.ft R
+.sp
+The scenario is as follows:
+.RS
+.IP \(bu
+The Postfix queue manager deletes the file that \fBpostsuper\fR
+was supposed to delete, because Postfix was finished with the
+message.
+.IP \(bu
+New mail arrives, and the new message is given the same queue ID
+as the message that \fBpostsuper\fR was supposed to delete.
+The probability for reusing a deleted queue ID is about 1 in 2**15
+(the number of different microsecond values that the system clock
+can distinguish).
+.IP \(bu
+\fBpostsuper\fR deletes the new message file, instead of the
+old file that should have been deleted.
+.RE
.IP \fB-s\fR
Structure check. Move queue files that are in the wrong place
in the file system hierarchy and remove subdirectories that are
/*
* Allocate and read the queue manager's delivery request.
*/
+#define XXX_DEFER_STATUS -1
+
request = deliver_request_alloc();
if (deliver_request_get(stream, request) < 0) {
- deliver_request_free(request);
+ deliver_request_done(stream, request, XXX_DEFER_STATUS);
request = 0;
}
return (request);
* Version of this program.
*/
#define VAR_MAIL_VERSION "mail_version"
-#define DEF_MAIL_VERSION "Snapshot-20010501"
+#define DEF_MAIL_VERSION "Snapshot-20010502"
extern char *var_mail_version;
/* LICENSE
/* \fBpostsuper\fR [\fB-d \fIqueue_id\fR] [\fB-p\fR]
/* [\fB-s\fR] [\fB-v\fR] [\fIdirectory ...\fR]
/* DESCRIPTION
-/* The \fBpostsuper\fR command does small maintenance jobs on the named
-/* Postfix queue directories (default: all).
-/* Directory names are relative to the Postfix top-level queue directory.
+/* The \fBpostsuper\fR command does small maintenance jobs. Use of
+/* the command is restricted to the super-user.
/*
/* By default, \fBpostsuper\fR performs the operations requested with the
-/* \fB-s\fR and \fB-p\fR command-line options.
-/* \fBpostsuper\fR always tries to remove objects that are neither files
-/* nor directories. Use of this command is restricted to the super-user.
+/* \fB-s\fR and \fB-p\fR command-line options on the named Postfix queue
+/* directories (default: all).
+/* Directory names are relative to the Postfix top-level queue directory.
/*
/* Options:
/* .IP \fB-d \fIqueue_id\fR
+/* This option ignores any \fIdirectory\fR argument(s).
/* Delete one message queue file with the named queue ID. Specify
/* multiple \fB-d\fR options to delete multiple queue files by name.
/* .sp
/* Alternatively, if a \fIqueue_id\fR of \fB-\fR is specified, the
/* program reads queue IDs from standard input.
/* .sp
-/* This operation can be performed safely while the mail system is
-/* running, although the queue manager may issue warnings when a
-/* file suddenly disappears. The exit status is zero if at least one
-/* of the named message queue files was found.
+/* The \fBpostsuper\fR exit status is non-zero when no message queue
+/* file was deleted.
+/* .sp
+/* .ft B
+/* There is a very small possibility that postsuper deletes the
+/* wrong message file when it is executed while the Postfix mail
+/* system is running.
+/* .ft R
+/* .sp
+/* The scenario is as follows:
+/* .RS
+/* .IP \(bu
+/* The Postfix queue manager deletes the file that \fBpostsuper\fR
+/* was supposed to delete, because Postfix was finished with the
+/* message.
+/* .IP \(bu
+/* New mail arrives, and the new message is given the same queue ID
+/* as the message that \fBpostsuper\fR was supposed to delete.
+/* The probability for reusing a deleted queue ID is about 1 in 2**15
+/* (the number of different microsecond values that the system clock
+/* can distinguish).
+/* .IP \(bu
+/* \fBpostsuper\fR deletes the new message file, instead of the
+/* old file that should have been deleted.
+/* .RE
/* .IP \fB-s\fR
/* Structure check. Move queue files that are in the wrong place
/* in the file system hierarchy and remove subdirectories that are
#include <mail_conf.h>
#include <mail_params.h>
#include <mail_queue.h>
+#include <mail_open_ok.h>
/* Application-specific. */
static int delete_one(const char *queue_id)
{
const char *msg_queue_names[] = {
+ MAIL_QUEUE_MAILDROP,
MAIL_QUEUE_INCOMING, /* twice, to avoid */
MAIL_QUEUE_ACTIVE, /* missing a file while */
MAIL_QUEUE_DEFERRED, /* it is being renamed */
MAIL_QUEUE_INCOMING, /* this is not 100% */
MAIL_QUEUE_ACTIVE, /* foolproof but adequate */
- MAIL_QUEUE_DEFERRED,
0,
};
+ struct stat st;
const char **cpp;
- VSTRING *msg_path = vstring_alloc(100);
+ const char *path;
int found = 0;
/*
* ID.
*/
for (cpp = msg_queue_names; *cpp != 0; cpp++) {
- (void) mail_queue_path(msg_path, *cpp, queue_id);
- if (unlink(STR(msg_path)) == 0) {
+ if (!mail_open_ok(*cpp, queue_id, &st, &path)) {
+ continue;
+ } else if (unlink(path) == 0) {
found = 1;
- if (msg_verbose)
- msg_info("removed file %s", STR(msg_path));
+ msg_info("removed file %s", path);
break;
} else if (errno != ENOENT) {
- msg_warn("remove file %s: %m", STR(msg_path));
+ msg_warn("remove file %s: %m", path);
+ } else if (msg_verbose) {
+ msg_info("remove file %s: %m", path);
}
}
- vstring_free(msg_path);
return (found);
}
* a non-root user limits the damage to the already compromised mail
* owner.
*/
+ if (getuid())
+ msg_fatal("use of this command is reserved for the super-user");
set_ugid(var_owner_uid, var_owner_gid);
/*
#define STRING_FORMAT "%-10s %8s %-20s %s\n"
#define DATA_FORMAT "%-10s%c%8ld %20.20s %s\n"
+#define DROP_FORMAT "%-10s%c%8ld %20.20s (maildrop queue, sender UID %d)\n"
static void showq_reasons(VSTREAM *, BOUNCE_LOG *, HTABLE *);
static void showq_service(VSTREAM *client, char *unused_service, char **argv)
{
- char **queue;
VSTREAM *qfile;
const char *path;
int status;
int file_count;
unsigned long queue_size = 0;
struct stat st;
- char *queue_names[] = { /* XXX configurable */
- MAIL_QUEUE_INCOMING,
- MAIL_QUEUE_ACTIVE,
- MAIL_QUEUE_DEFERRED,
- /* No maildrop until we can disable recursive scans. */
+ struct queue_info {
+ char *name; /* queue name */
+ char *(*scan_next) (SCAN_DIR *); /* flat or recursive */
+ };
+ struct queue_info *qp;
+
+ static struct queue_info queue_info[] = {
+ MAIL_QUEUE_MAILDROP, scan_dir_next,
+ MAIL_QUEUE_INCOMING, mail_scan_dir_next,
+ MAIL_QUEUE_ACTIVE, mail_scan_dir_next,
+ MAIL_QUEUE_DEFERRED, mail_scan_dir_next,
0,
};
* mis-configured, and force backoff by raising a fatal error.
*/
file_count = 0;
- for (queue = queue_names; *queue != 0; queue++) {
- SCAN_DIR *scan = scan_dir_open(*queue);
+ for (qp = queue_info; qp->name != 0; qp++) {
+ SCAN_DIR *scan = scan_dir_open(qp->name);
char *saved_id = 0;
- while ((id = mail_scan_dir_next(scan)) != 0) {
+ while ((id = qp->scan_next(scan)) != 0) {
/*
* XXX I have seen showq loop on the same queue id. That would be
*/
if (saved_id) {
if (strcmp(saved_id, id) == 0) {
- msg_warn("readdir loop on queue %s id %s", *queue, id);
+ msg_warn("readdir loop on queue %s id %s", qp->name, id);
break;
}
myfree(saved_id);
}
saved_id = mystrdup(id);
- status = mail_open_ok(*queue, id, &st, &path);
+ status = mail_open_ok(qp->name, id, &st, &path);
if (status == MAIL_OPEN_YES) {
if (file_count == 0)
vstream_fprintf(client, STRING_FORMAT,
"-Sender/Recipient-------");
else
vstream_fprintf(client, "\n");
- if ((qfile = mail_queue_open(*queue, id, O_RDONLY, 0)) != 0) {
+ if ((qfile = mail_queue_open(qp->name, id, O_RDONLY, 0)) != 0) {
queue_size += st.st_size;
- showq_report(client, *queue, id, qfile, (long) st.st_size);
+ showq_report(client, qp->name, id, qfile, (long) st.st_size);
if (vstream_fclose(qfile))
- msg_warn("close file %s %s: %m", *queue, id);
- } else if (strcmp(*queue, MAIL_QUEUE_MAILDROP) == 0) {
+ msg_warn("close file %s %s: %m", qp->name, id);
+ } else if (strcmp(qp->name, MAIL_QUEUE_MAILDROP) == 0) {
queue_size += st.st_size;
- vstream_fprintf(client, DATA_FORMAT, id, ' ',
+ vstream_fprintf(client, DROP_FORMAT, id, ' ',
(long) st.st_size,
asctime(localtime(&st.st_mtime)),
- "(to be determined)");
+ st.st_uid);
} else if (errno != ENOENT)
- msg_fatal("open %s %s: %m", *queue, id);
+ msg_fatal("open %s %s: %m", qp->name, id);
file_count++;
vstream_fflush(client);
}
/* int myrand()
/* DESCRIPTION
/* This module implements a wrapper for the portable, pseudo-random
-/* number generator.
+/* number generator. The wrapper adds automatic initialization.
/*
/* mysrand() performs initialization. This call may be skipped.
/*