2
0
mirror of https://github.com/vdukhovni/postfix synced 2025-08-30 21:55:20 +00:00

snapshot-20010524

This commit is contained in:
Wietse Venema
2001-05-24 00:00:00 -05:00
committed by Viktor Dukhovni
parent 92370560ec
commit ca0dd40ea2
12 changed files with 805 additions and 408 deletions

View File

@@ -5187,13 +5187,18 @@ Apologies for any names omitted.
20010522
Feature: "postsuper -r queueID" re-queues a message. The
message is moved to the maildrop queue so that the pickup
daemon will copy it to a new file with the "right" name
that matches the queue file inode number, and so that
address rewriting will be done again. This is useful after
changes of address rewriting or virtual mappings.
Feature: "postsuper -r queueID" re-queues a message, and
"postsuper -R" re-queues all mail. The message is moved to
the maildrop queue so that the pickup daemon will copy it
to a new queue file, and so that address rewriting will be
done again. This is useful after changes of address rewriting
or virtual mappings.
Feature: "postsuper -R" re-queues all mail. This is useful
after restoring a Postfix queue from another machine, or
from backup.
20010523
Feature: "postsuper -s" (which is done by default) renames
queue files whose queue ID does not match the message file
inode number.
Bugfix: memory leak in the LDAP client module. Alain
Thivillon,France Teaser - Groupe Firstream.

View File

@@ -12,20 +12,22 @@ server state just like RSET. This behavior cannot be disabled.
Major changes with snapshot-20010522
====================================
Revision of some fine details in the light of the new RFC 2821 and
RFC 2822 standards. Changes that may affect interoperability are
listed above under "incompatible changes".
This release contains revisions of some fine details in the light
of the new RFC 2821 and RFC 2822 standards. Changes that may affect
interoperability are listed above under "incompatible changes".
The postsuper tool can rename files whose queue ID does not match
the queue file inode number. This is necessary when a Postfix mail
queue is restored from another machine or from backups. The feature
is selected with the -s option, which is the default.
The postsuper queue maintenance tool was extended with options to
read queue IDs from standard input (which makes it easier to drive
the tool from scripts).
read queue IDs from standard input. This makes the tool easier to
drive from scripts.
The postsuper queue maintenance tool has a new -r (requeue) option
for subjecting queue files to another iteration of address rewriting.
The postsuper -R option requeues all mail. This is necessary after
restoring Postfix queues from another machine or from backups.
Major changes with snapshot-20010502
====================================

View File

@@ -174,9 +174,6 @@ check)
\( -perm -020 -o -perm -002 \) \
-exec $WARN group or other writable: {} \;
find $queue_directory/* $config_directory/* -name '*core' \
-exec $WARN core file: {} \; 2>/dev/null
test -d maildrop || {
$WARN creating missing Postfix maildrop directory
mkdir maildrop || exit 1
@@ -254,10 +251,11 @@ EOF
$command_directory/postconf -e hash_queue_names="$found$missing"
}
# See if all queue files are in the right place.
# See if all queue files are in the right place. This is slow.
# We must scan all queues for mis-named queue files before the
# mail system can run.
$command_directory/postsuper active
$command_directory/postsuper &
$command_directory/postsuper || exit 1
find corrupt -type f -exec $WARN damaged message: {} \;

View File

@@ -174,9 +174,6 @@ check)
\( -perm -020 -o -perm -002 \) \
-exec $WARN group or other writable: {} \;
find $queue_directory/* $config_directory/* -name '*core' \
-exec $WARN core file: {} \; 2>/dev/null
test -d maildrop || {
$WARN creating missing Postfix maildrop directory
mkdir maildrop || exit 1
@@ -255,10 +252,11 @@ EOF
$command_directory/postconf -e hash_queue_names="$found$missing"
}
# See if all queue files are in the right place.
# See if all queue files are in the right place. This is slow.
# We must scan all queues for mis-named queue files before the
# mail system can run.
$command_directory/postsuper active
$command_directory/postsuper &
$command_directory/postsuper || exit 1
find corrupt -type f -exec $WARN damaged message: {} \;

View File

@@ -3063,13 +3063,61 @@ that the file name will collide with another queue file.
<p>
To avoid queue file name collisions when copying queue files,
restore the incoming, active and deferred queue files under the
maildrop directory instead.
<ul>
<li>If your Postfix queue is empty, and if you run a Postfix release
after 20010524, you can use this procedure to copy a Postfix
queue from another machine or to restore it from backup.
<p>
As of late 2000, Postfix queues are all hashed (for example, file
<ul>
<li> Stop Postfix, if it was running.
<p>
<li> Execute the <b>mailq</b> command. If there is any output, do
not complete this procedure, but use the second procedure instead.
<p>
<li> Copy or restore the queue to the usual place.
<p>
<li> Run the <b>postsuper</b> command. This command will rename
queue files so that the name matches the message file inode number.
</ul>
<p>
<li> If your Postfix queue is not empty, or if you are running a
Postfix release prior to 20010524, use the following procedure
instead.
<p>
<ul>
<li>Stop Postfix, if it was running.
<p>
<li> To avoid queue file name collisions when restoring queue files,
copy or restore the incoming, active and deferred queue files under
the maildrop directory instead.
<p>
<li>While the next step is going on, don't submit new mail locally,
because that could collide with the files you are restoring under
the maildrop directory.
<p>
<li>As of late 2000, Postfix queues are all hashed (for example, file
ABCDEF is stored as A/B/ABCDEF), so you need an additional step to
move files down from their subdirectories.
@@ -3083,15 +3131,15 @@ move files down from their subdirectories.
# postfix start
</pre>
While all this is going on, don't submit new mail locally, because
that could collide with the files you are restoring under the
maildrop directory.
<p>
When Postfix is started, it will pick up queue files from the
<li>When Postfix is started, it will pick up queue files from the
maildrop directory and will give them proper queue file names.
</ul>
</ul>
<hr>
<a name="bind"><h3>Undefined symbols: ___dn_expand, ___res_init etc.</h3></a>

View File

@@ -13,52 +13,52 @@ POSTSUPER(1) POSTSUPER(1)
<i>...</i>]
<b>DESCRIPTION</b>
The <b>postsuper</b> command does small maintenance jobs. Use of
the command is restricted to the super-user.
The <b>postsuper</b> command does maintenance jobs on the Postfix
queue. 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 on the named Post-
fix queue directories (default: all). Directory names are
relative to the Postfix top-level queue directory.
with the <b>-s</b> and <b>-p</b> command-line options on all Postfix
queue directories - this includes the <b>incoming</b>, <b>active</b> and
<b>deferred</b> directories with mail files and the <b>bounce</b>, <b>defer</b>
and <b>flush</b> directories with log files.
Options:
<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
<b>-d</b> <i>queue_id</i>
Delete one message with the named queue ID from the
named mail queue(s) (default: <b>incoming</b>, <b>active</b> and
<b>deferred</b>). If a <i>queue_id</i> of <b>-</b> is specified, the
program reads queue IDs from standard input.
The <b>postsuper</b> exit status is non-zero when no mes-
sage queue file was deleted.
Specify <b>-d</b> <b>ALL</b> to remove all messages; for example,
specify <b>-d</b> <b>ALL</b> <b>deferred</b> to delete mail in the
<b>deferred</b> queue. As a safety measure, the word <b>ALL</b>
must be specified in upper case.
<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>
<b>Postfix</b> <b>queue</b> <b>IDs</b> <b>are</b> <b>reused.</b> <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-
1) The Postfix queue manager deletes the mes-
sage that <b>postsuper</b> is supposed to delete,
because Postfix is finished with the mes-
sage.
<b>o</b> New mail arrives, and the new message is
2) 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
<b>postsuper</b> is supposed to delete. The proba-
bility for reusing a deleted queue ID is
about 1 in 2**15 (the number of different
microsecond values that the system clock can
distinguish within a second).
<b>o</b> <b>postsuper</b> deletes the new message file,
instead of the old file that should have
been deleted.
3) <b>postsuper</b> deletes the new message, instead
of the old message that it should have
deleted.
<b>-r</b> This option ignores any <i>directory</i> argument(s).
Requeue one message queue file with the named queue
@@ -71,33 +71,49 @@ POSTSUPER(1) POSTSUPER(1)
POSTSUPER(1) POSTSUPER(1)
ID. Specify multiple <b>-r</b> options to requeue multi-
ple queue files by name.
<b>-p</b> Purge old temporary files that are left over after
system or software crashes.
Alternatively, if a <i>queue_id</i> of <b>-</b> is specified, the
program reads queue IDs from standard input.
<b>-r</b> <i>queue_id</i>
Requeue the message with the named queue ID from
the named mail queue(s) (default: <b>incoming</b>, <b>active</b>
and <b>deferred</b>). To requeue multiple messages, spec-
ify multiple <b>-r</b> command-line options. Alterna-
tively, if a <i>queue_id</i> of <b>-</b> is specified, the pro-
gram reads queue IDs from standard input.
The queue file is moved to the maildrop queue, from
where it is copied by the pickup daemon to a new
file whose name is guaranteed to match the queue
file inode number. This feature is useful for queue
files from another machine or for files restored
from backup. The new queue file is subjected again
to address rewriting and substitution.
Specify <b>-r</b> <b>ALL</b> to requeue all messages. As a safety
measure, the word <b>ALL</b> must be specified in upper
case.
The <b>postsuper</b> exit status is non-zero when no mes-
sage queue file was requeued.
A requeued message is moved to the <b>maildrop</b> queue,
from where it is copied by the pickup daemon to a
new file whose name is guaranteed to match the new
queue file inode number. The new queue file is sub-
jected again to mail address rewriting and substi-
tution. This is useful when rewriting rules or vir-
tual mappings have changed.
<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
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
this check once before Postfix startup.
Postfix queue IDs are reused. There is a very
small possibility that <b>postsuper</b> requeues the wrong
message file when it is executed while the Postfix
mail system is running, but no harm should be done.
<b>-p</b> Purge stale files (files that are left over after
system or software crashes).
<b>-s</b> Structure check and structure repair. It is highly
recommended to perform this operation once before
Postfix startup.
<b>o</b> Rename files whose name does not match the
message file inode number. This operation is
necessary after restoring a mail queue from
a different machine, or from backup media.
<b>o</b> Move queue files that are in the wrong place
in the file system hierarchy and remove sub-
directories that are no longer needed. File
position 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> configuration parameters.
<b>-v</b> Enable verbose logging for debugging purposes. Mul-
tiple <b>-v</b> options make the software increasingly
@@ -107,6 +123,24 @@ POSTSUPER(1) POSTSUPER(1)
Problems are reported to the standard error stream and to
<b>syslogd</b>.
<b>postsuper</b> reports the number of messages deleted with <b>-d</b>,
the number of messages requeued with <b>-r</b>, and the number of
2
POSTSUPER(1) POSTSUPER(1)
messages whose queue file name was fixed with <b>-s</b>. The
report is written to the standard error stream and to <b>sys-</b>
<b>logd</b>.
<b>CONFIGURATION</b> <b>PARAMETERS</b>
See the Postfix <b>main.cf</b> file for syntax details and for
default values.
@@ -125,18 +159,6 @@ POSTSUPER(1) POSTSUPER(1)
<b>AUTHOR(S)</b>
Wietse Venema
IBM T.J. Watson Research
2
POSTSUPER(1) POSTSUPER(1)
P.O. Box 704
Yorktown Heights, NY 10598, USA
@@ -151,28 +173,6 @@ POSTSUPER(1) POSTSUPER(1)

View File

@@ -14,27 +14,30 @@ Postfix super intendent
.SH DESCRIPTION
.ad
.fi
The \fBpostsuper\fR command does small maintenance jobs. Use of
the command is restricted to the super-user.
The \fBpostsuper\fR command does maintenance jobs on the Postfix
queue. 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 on the named Postfix queue
directories (default: all).
Directory names are relative to the Postfix top-level queue directory.
\fB-s\fR and \fB-p\fR command-line options on all Postfix queue
directories - this includes the \fBincoming\fR, \fBactive\fR and
\fBdeferred\fR directories with mail files and the \fBbounce\fR,
\fBdefer\fR and \fBflush\fR directories with log files.
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.
.IP "\fB-d \fIqueue_id\fR"
Delete one message with the named queue ID from the named
mail queue(s) (default: \fBincoming\fR, \fBactive\fR and
\fBdeferred\fR).
If a \fIqueue_id\fR of \fB-\fR is specified, the program reads
queue IDs from standard input.
.sp
Alternatively, if a \fIqueue_id\fR of \fB-\fR is specified, the
program reads queue IDs from standard input.
.sp
The \fBpostsuper\fR exit status is non-zero when no message queue
file was deleted.
Specify \fB-d ALL\fR to remove all messages; for example, specify
\fB-d ALL deferred\fR to delete mail in the \fBdeferred\fR queue.
As a safety measure, the word \fBALL\fR must be specified in upper
case.
.sp
.ft B
Postfix queue IDs are reused.
There is a very small possibility that postsuper deletes the
wrong message file when it is executed while the Postfix mail
system is running.
@@ -42,47 +45,61 @@ system is running.
.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
.IP 1)
The Postfix queue manager deletes the message that \fBpostsuper\fR
is supposed to delete, because Postfix is finished with the
message.
.IP \(bu
.IP 2)
New mail arrives, and the new message is given the same queue ID
as the message that \fBpostsuper\fR was supposed to delete.
as the message that \fBpostsuper\fR is 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 within a second).
.IP \(bu
\fBpostsuper\fR deletes the new message file, instead of the
old file that should have been deleted.
.IP 3)
\fBpostsuper\fR deletes the new message, instead of the old
message that it should have deleted.
.RE
.IP \fB-r \fIqueue_id\fR
This option ignores any \fIdirectory\fR argument(s).
Requeue one message queue file with the named queue ID. Specify
multiple \fB-r\fR options to requeue 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
The queue file is moved to the maildrop queue, from where
it is copied by the pickup daemon to a new file whose name
is guaranteed to match the queue file inode number. This
feature is useful for queue files from another machine or
for files restored from backup. The new queue file is
subjected again to address rewriting and substitution.
.sp
The \fBpostsuper\fR exit status is non-zero when no message queue
file was requeued.
.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
no longer needed. File rearrangements are necessary after a change
in the \fBhash_queue_names\fR and/or \fBhash_queue_depth\fR
configuration parameters. It is highly recommended to run this
check once before Postfix startup.
.IP \fB-p\fR
Purge stale files (files that are left over after system or
software crashes).
Purge old temporary files that are left over after system or
software crashes.
.IP "\fB-r \fIqueue_id\fR"
Requeue the message with the named queue ID from the named
mail queue(s) (default: \fBincoming\fR, \fBactive\fR and
\fBdeferred\fR).
To requeue multiple messages, specify multiple \fB-r\fR
command-line options.
Alternatively, if a \fIqueue_id\fR of \fB-\fR is specified,
the program reads queue IDs from standard input.
.sp
Specify \fB-r ALL\fR to requeue all messages. As a safety
measure, the word \fBALL\fR must be specified in upper case.
.sp
A requeued message is moved to the \fBmaildrop\fR queue, from
where it is copied by the pickup daemon to a new file whose name
is guaranteed to match the new queue file inode number. The
new queue file is subjected again to mail address rewriting and
substitution. This is useful when rewriting rules or virtual
mappings have changed.
.sp
Postfix queue IDs are reused.
There is a very small possibility that \fBpostsuper\fR requeues
the wrong message file when it is executed while the Postfix mail
system is running, but no harm should be done.
.IP \fB-s\fR
Structure check and structure repair. It is highly recommended
to perform this operation once before Postfix startup.
.RS
.IP \(bu
Rename files whose name does not match the message file inode
number. This operation is necessary after restoring a mail queue
from a different machine, or from backup media.
.IP \(bu
Move queue files that are in the wrong place in the file system
hierarchy and remove subdirectories that are no longer needed.
File position rearrangements are necessary after a change in the
\fBhash_queue_names\fR and/or \fBhash_queue_depth\fR
configuration parameters.
.RE
.IP \fB-v\fR
Enable verbose logging for debugging purposes. Multiple \fB-v\fR
options make the software increasingly verbose.
@@ -91,6 +108,11 @@ options make the software increasingly verbose.
.fi
Problems are reported to the standard error stream and to
\fBsyslogd\fR.
\fBpostsuper\fR reports the number of messages deleted with \fB-d\fR,
the number of messages requeued with \fB-r\fR, and the number of
messages whose queue file name was fixed with \fB-s\fR. The report
is written to the standard error stream and to \fBsyslogd\fR.
.SH CONFIGURATION PARAMETERS
.na
.nf

View File

@@ -65,7 +65,7 @@ const char *get_file_id(int fd)
result = vstring_alloc(1);
if (fstat(fd, &st) < 0)
msg_fatal("fstat: %m");
vstring_sprintf(result, "%X", (int) st.st_ino);
vstring_sprintf(result, "%lX", (long) st.st_ino);
return (vstring_str(result));
}

View File

@@ -388,11 +388,13 @@ VSTREAM *mail_queue_enter(const char *queue_name, int mode)
for (count = 0;; count++) {
vstring_sprintf(id_buf, "%05X%s", (int) tv.tv_usec, file_id);
mail_queue_path(path_buf, queue_name, STR(id_buf));
#if 0
if (access(STR(path_buf), X_OK) == 0) { /* collision. */
if ((int) ++tv.tv_usec < 0)
tv.tv_usec = 0;
continue;
}
#endif
if (sane_rename(STR(temp_path), STR(path_buf)) == 0) /* success */
break;
if (errno == EPERM || errno == EISDIR) {/* collision. weird. */

View File

@@ -15,7 +15,7 @@
* Version of this program.
*/
#define VAR_MAIL_VERSION "mail_version"
#define DEF_MAIL_VERSION "Snapshot-20010522"
#define DEF_MAIL_VERSION "Snapshot-20010524"
extern char *var_mail_version;
/* LICENSE

View File

@@ -5,30 +5,33 @@
/* Postfix superintendent
/* SYNOPSIS
/* .fi
/* \fBpostsuper\fR [\fB-Rpsv\fR] [\fB-d \fIqueue_id\fR]
/* \fBpostsuper\fR [\fB-psv\fR] [\fB-d \fIqueue_id\fR]
/* [\fB-r \fIqueue_id\fR] [\fIdirectory ...\fR]
/* DESCRIPTION
/* The \fBpostsuper\fR command does small maintenance jobs. Use of
/* the command is restricted to the super-user.
/* The \fBpostsuper\fR command does maintenance jobs on the Postfix
/* queue. 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 on the named Postfix queue
/* directories (default: all).
/* Directory names are relative to the Postfix top-level queue directory.
/* \fB-s\fR and \fB-p\fR command-line options on all Postfix queue
/* directories - this includes the \fBincoming\fR, \fBactive\fR and
/* \fBdeferred\fR directories with mail files and the \fBbounce\fR,
/* \fBdefer\fR and \fBflush\fR directories with log files.
/*
/* 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.
/* .IP "\fB-d \fIqueue_id\fR"
/* Delete one message with the named queue ID from the named
/* mail queue(s) (default: \fBincoming\fR, \fBactive\fR and
/* \fBdeferred\fR).
/* If a \fIqueue_id\fR of \fB-\fR is specified, the program reads
/* queue IDs from standard input.
/* .sp
/* Alternatively, if a \fIqueue_id\fR of \fB-\fR is specified, the
/* program reads queue IDs from standard input.
/* .sp
/* The \fBpostsuper\fR exit status is non-zero when no message queue
/* file was deleted.
/* Specify \fB-d ALL\fR to remove all messages; for example, specify
/* \fB-d ALL deferred\fR to delete mail in the \fBdeferred\fR queue.
/* As a safety measure, the word \fBALL\fR must be specified in upper
/* case.
/* .sp
/* .ft B
/* Postfix queue IDs are reused.
/* There is a very small possibility that postsuper deletes the
/* wrong message file when it is executed while the Postfix mail
/* system is running.
@@ -36,64 +39,72 @@
/* .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
/* .IP 1)
/* The Postfix queue manager deletes the message that \fBpostsuper\fR
/* is supposed to delete, because Postfix is finished with the
/* message.
/* .IP \(bu
/* .IP 2)
/* New mail arrives, and the new message is given the same queue ID
/* as the message that \fBpostsuper\fR was supposed to delete.
/* as the message that \fBpostsuper\fR is 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 within a second).
/* .IP \(bu
/* \fBpostsuper\fR deletes the new message file, instead of the
/* old file that should have been deleted.
/* .IP 3)
/* \fBpostsuper\fR deletes the new message, instead of the old
/* message that it should have deleted.
/* .RE
/* .IP \fB-R\fR
/* This option ignores any \fIdirectory\fR argument(s).
/* Requeue all message queue files. This option is useful for
/* restoring a Postfix queue from another machine or from backup.
/* .sp
/* Each queue file is moved to the maildrop queue, from where
/* it is copied by the pickup daemon to a new file whose name
/* is guaranteed to match the queue file inode number. The
/* new queue file is subjected again to address rewriting and
/* substitution. This is useful when rewriting rules or virtual
/* mappings have changed.
/* .IP \fB-r \fIqueue_id\fR
/* This option ignores any \fIdirectory\fR argument(s).
/* Requeue one message queue file with the named queue ID. Specify
/* multiple \fB-r\fR options to requeue 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
/* The queue file is moved to the maildrop queue, from where
/* it is copied by the pickup daemon to a new file whose name
/* is guaranteed to match the queue file inode number. The
/* new queue file is subjected again to address rewriting and
/* substitution. This is useful when rewriting rules or virtual
/* mappings have changed.
/* .sp
/* The \fBpostsuper\fR exit status is non-zero when no message queue
/* file was requeued.
/* .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
/* no longer needed. File rearrangements are necessary after a change
/* in the \fBhash_queue_names\fR and/or \fBhash_queue_depth\fR
/* configuration parameters. It is highly recommended to run this
/* check once before Postfix startup.
/* .IP \fB-p\fR
/* Purge stale files (files that are left over after system or
/* software crashes).
/* Purge old temporary files that are left over after system or
/* software crashes.
/* .IP "\fB-r \fIqueue_id\fR"
/* Requeue the message with the named queue ID from the named
/* mail queue(s) (default: \fBincoming\fR, \fBactive\fR and
/* \fBdeferred\fR).
/* To requeue multiple messages, specify multiple \fB-r\fR
/* command-line options.
/* Alternatively, if a \fIqueue_id\fR of \fB-\fR is specified,
/* the program reads queue IDs from standard input.
/* .sp
/* Specify \fB-r ALL\fR to requeue all messages. As a safety
/* measure, the word \fBALL\fR must be specified in upper case.
/* .sp
/* A requeued message is moved to the \fBmaildrop\fR queue, from
/* where it is copied by the pickup daemon to a new file whose name
/* is guaranteed to match the new queue file inode number. The
/* new queue file is subjected again to mail address rewriting and
/* substitution. This is useful when rewriting rules or virtual
/* mappings have changed.
/* .sp
/* Postfix queue IDs are reused.
/* There is a very small possibility that \fBpostsuper\fR requeues
/* the wrong message file when it is executed while the Postfix mail
/* system is running, but no harm should be done.
/* .IP \fB-s\fR
/* Structure check and structure repair. It is highly recommended
/* to perform this operation once before Postfix startup.
/* .RS
/* .IP \(bu
/* Rename files whose name does not match the message file inode
/* number. This operation is necessary after restoring a mail queue
/* from a different machine, or from backup media.
/* .IP \(bu
/* Move queue files that are in the wrong place in the file system
/* hierarchy and remove subdirectories that are no longer needed.
/* File position rearrangements are necessary after a change in the
/* \fBhash_queue_names\fR and/or \fBhash_queue_depth\fR
/* configuration parameters.
/* .RE
/* .IP \fB-v\fR
/* Enable verbose logging for debugging purposes. Multiple \fB-v\fR
/* options make the software increasingly verbose.
/* DIAGNOSTICS
/* Problems are reported to the standard error stream and to
/* \fBsyslogd\fR.
/*
/* \fBpostsuper\fR reports the number of messages deleted with \fB-d\fR,
/* the number of messages requeued with \fB-r\fR, and the number of
/* messages whose queue file name was fixed with \fB-s\fR. The report
/* is written to the standard error stream and to \fBsyslogd\fR.
/* CONFIGURATION PARAMETERS
/* .ad
/* .fi
@@ -123,6 +134,7 @@
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#include <stdio.h> /* remove() */
/* Utility library. */
@@ -155,9 +167,10 @@
#define ACTION_STRUCT (1<<0) /* fix file organization */
#define ACTION_PURGE (1<<1) /* purge old temp files */
#define ACTION_DELETE (1<<2) /* delete named queue file(s) */
#define ACTION_REQUEUE (1<<3) /* requeue named queue file(s) */
#define ACTION_REQUEUE_ALL (1<<4) /* requeue all queue file(s) */
#define ACTION_DELETE_ONE (1<<2) /* delete named queue file(s) */
#define ACTION_DELETE_ALL (1<<3) /* delete all queue file(s) */
#define ACTION_REQUEUE_ONE (1<<4) /* requeue named queue file(s) */
#define ACTION_REQUEUE_ALL (1<<5) /* requeue all queue file(s) */
#define ACTION_DEFAULT (ACTION_STRUCT | ACTION_PURGE)
@@ -188,78 +201,144 @@ static struct queue_info queue_info[] = {
0,
};
/* postunlink - remove file with prejudice */
/*
* Directories with per-message meta files.
*/
const char *log_queue_names[] = {
MAIL_QUEUE_BOUNCE,
MAIL_QUEUE_DEFER,
0,
};
static int postunlink(const char *path)
/*
* Cruft that we append to a file name when a queue ID is named after the
* message file inode number. This cruft must not pass mail_queue_id_ok() so
* that the queue manager will ignore it, should people be so unwise as to
* run this operation on a live mail system.
*/
#define SUFFIX "#FIX"
#define SUFFIX_LEN 4
/*
* Grr. These counters are global, because C only has clumsy ways to return
* multiple results from a function.
*/
static int message_requeued = 0; /* requeued messages */
static int message_deleted = 0; /* deleted messages */
static int inode_fixed = 0; /* queue id matched to inode number */
static int inode_mismatch = 0; /* queue id inode mismatch */
static int position_mismatch = 0; /* file position mismatch */
/*
* Silly little macros. These translate arcane expressions into something
* more at a conceptual level.
*/
#define MESSAGE_QUEUE(qp) ((qp)->perms == MAIL_QUEUE_STAT_READY)
#define READY_MESSAGE(st) (((st).st_mode & S_IRWXU) == MAIL_QUEUE_STAT_READY)
/* find_queue_info - look up expected permissions field by queue name */
static struct queue_info *find_queue_info(const char *queue_name)
{
struct queue_info *qp;
for (qp = queue_info; qp->name; qp++)
if (strcmp(queue_name, qp->name) == 0)
return (qp);
msg_fatal("invalid directory name: %s", queue_name);
}
/* postremove - remove file with extreme prejudice */
static int postremove(const char *path)
{
int ret;
if ((ret = unlink(path)) == 0) {
if ((ret = remove(path)) < 0) {
if (errno != ENOENT)
msg_fatal("remove file %s: %m", path);
} else {
if (msg_verbose)
msg_info("removed file %s", path);
} else if (errno != ENOENT) {
msg_warn("remove file %s: %m", path);
} else if (msg_verbose) {
msg_info("remove file %s: %m", path);
}
return (ret);
}
/* postrename - rename file with prejudice */
/* postrename - rename file with extreme prejudice */
static int postrename(const char *old, const char *new)
{
int ret;
if ((ret = sane_rename(old, new)) == 0) {
msg_info("requeued file %s as %s", old, new);
} else if (errno != ENOENT) {
msg_warn("requeue file %s as %s: %m", old, new);
} else if (msg_verbose) {
msg_info("requeue file %s as %s: %m", old, new);
if ((ret = sane_rename(old, new)) < 0) {
if (errno != ENOENT
|| mail_queue_mkdirs(new) < 0
|| sane_rename(old, new) < 0)
if (errno != ENOENT)
msg_fatal("rename file %s as %s: %m", old, new);
} else {
if (msg_verbose)
msg_info("renamed file %s as %s", old, new);
}
return (ret);
}
/* postrmdir - remove directory with extreme prejudice */
static int postrmdir(const char *path)
{
int ret;
if ((ret = rmdir(path)) < 0) {
if (errno != ENOENT)
msg_fatal("remove directory %s: %m", path);
} else {
if (msg_verbose)
msg_info("remove directory %s", path);
}
return (ret);
}
/* delete_one - delete one message instance and all its associated files */
static int delete_one(const char *queue_id)
static int delete_one(const char **queue_names, 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 */
0,
};
const char *log_queue_names[] = {
MAIL_QUEUE_BOUNCE,
MAIL_QUEUE_DEFER,
0,
};
struct stat st;
const char **msg_qpp;
const char **log_qpp;
const char *msg_path;
VSTRING *log_path_buf = vstring_alloc(100);
int found = 0;
VSTRING *log_path_buf;
int found;
int tries;
/*
* Delete defer or bounce logfiles before deleting the corresponding
* message file, and only if the message file exists. This minimizes but
* does not eliminate a race condition with queue ID reuse which results
* in deleting the wrong files.
* Sanity check. No early returns beyond this point.
*/
for (msg_qpp = msg_queue_names; *msg_qpp != 0; msg_qpp++) {
if (!mail_queue_id_ok(queue_id)) {
msg_warn("invalid mail queue id: %s", queue_id);
return (0);
}
log_path_buf = vstring_alloc(100);
/*
* Skip meta file directories. Delete defer or bounce logfiles before
* deleting the corresponding message file, and only if the message file
* exists. This minimizes but does not eliminate a race condition with
* queue ID reuse which results in deleting the wrong files.
*/
for (found = 0, tries = 0; found == 0 && tries < 2; tries++) {
for (msg_qpp = queue_names; *msg_qpp != 0; msg_qpp++) {
if (!MESSAGE_QUEUE(find_queue_info(*msg_qpp)))
continue;
if (mail_open_ok(*msg_qpp, queue_id, &st, &msg_path) != MAIL_OPEN_YES)
continue;
for (log_qpp = log_queue_names; *log_qpp != 0; log_qpp++)
postunlink(mail_queue_path(log_path_buf, *log_qpp, queue_id));
if (postunlink(msg_path) == 0) {
postremove(mail_queue_path(log_path_buf, *log_qpp, queue_id));
if (postremove(msg_path) == 0) {
found = 1;
break;
} /* else: lost a race */
} /* else: maybe lost a race */
}
}
vstring_free(log_path_buf);
return (found);
@@ -267,35 +346,44 @@ static int delete_one(const char *queue_id)
/* requeue_one - requeue one message instance and delete its logfiles */
static int requeue_one(const char *queue_id)
static int requeue_one(const char **queue_names, const char *queue_id)
{
const char *msg_queue_names[] = {
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 */
0,
};
struct stat st;
const char **msg_qpp;
const char *old_path;
VSTRING *new_path_buf = vstring_alloc(100);
int found = 0;
VSTRING *new_path_buf;
int found;
int tries;
/*
* Do not delete defer or bounce logfiles, to avoid losing a race where
* the queue manager decides to bounce mail after all recipients have
* been tried.
* Sanity check. No early returns beyond this point.
*/
for (msg_qpp = msg_queue_names; *msg_qpp != 0; msg_qpp++) {
if (!mail_queue_id_ok(queue_id)) {
msg_warn("invalid mail queue id: %s", queue_id);
return (0);
}
new_path_buf = vstring_alloc(100);
/*
* Skip meta file directories. Like the mass requeue operation, we not
* delete defer or bounce logfiles, to avoid losing a race where the
* queue manager decides to bounce mail after all recipients have been
* tried.
*/
for (found = 0, tries = 0; found == 0 && tries < 2; tries++) {
for (msg_qpp = queue_names; *msg_qpp != 0; msg_qpp++) {
if (strcmp(*msg_qpp, MAIL_QUEUE_MAILDROP) == 0)
continue;
if (!MESSAGE_QUEUE(find_queue_info(*msg_qpp)))
continue;
if (mail_open_ok(*msg_qpp, queue_id, &st, &old_path) != MAIL_OPEN_YES)
continue;
(void) mail_queue_path(new_path_buf, MAIL_QUEUE_MAILDROP, queue_id);
if (postrename(old_path, STR(new_path_buf)) == 0) {
found = 1;
break;
} /* else: lost a race */
} /* else: maybe lost a race */
}
}
vstring_free(new_path_buf);
return (found);
@@ -303,33 +391,84 @@ static int requeue_one(const char *queue_id)
/* operate_stream - operate on queue IDs given on stream */
static int operate_stream(VSTREAM *fp, int (*operator) (const char *))
static int operate_stream(VSTREAM *fp,
int (*operator) (const char **, const char *),
const char **queues)
{
VSTRING *buf = vstring_alloc(20);
int found = 0;
while (vstring_get_nonl(buf, fp) != VSTREAM_EOF)
found |= operator(STR(buf));
found += operator(queues, STR(buf));
vstring_free(buf);
return (found);
}
/* super - check queue file location and clean up */
/* fix_queue_id - make message queue ID match inode number */
static void super(char **queues, int action)
static int fix_queue_id(const char *actual_path, const char *actual_queue,
const char *actual_id, ino_t inum)
{
VSTRING *old_path = vstring_alloc(10);
VSTRING *new_path = vstring_alloc(10);
VSTRING *new_id = vstring_alloc(10);
const char **log_qpp;
int ret;
/*
* Create the new queue ID from the existing time digits and from the new
* inode number. Since we are renaming multiple files, the new name must
* be deterministic so that we can recover even when the renaming
* operation is interrupted in the middle.
*/
vstring_sprintf(new_id, "%.5s%lX", actual_id, (unsigned long) inum);
/*
* Rename logfiles before renaming the message file, so that we can
* recover when a previous attempt was interrupted.
*/
for (log_qpp = log_queue_names; *log_qpp; log_qpp++) {
mail_queue_path(old_path, *log_qpp, actual_id);
mail_queue_path(new_path, *log_qpp, STR(new_id));
vstring_strcat(new_path, SUFFIX);
postrename(STR(old_path), STR(new_path));
}
/*
* Rename the message file last, so that we know that we are done with
* this message and with all its logfiles.
*/
mail_queue_path(new_path, actual_queue, STR(new_id));
vstring_strcat(new_path, SUFFIX);
ret = postrename(actual_path, STR(new_path));
/*
* Clean up.
*/
vstring_free(old_path);
vstring_free(new_path);
vstring_free(new_id);
return (ret);
}
/* super - check queue structure, clean up, do wild-card operations */
static void super(const char **queues, int action)
{
ARGV *hash_queue_names = argv_split(var_hash_queue_names, " \t\r\n,");
VSTRING *actual_path = vstring_alloc(10);
VSTRING *wanted_path = vstring_alloc(10);
struct stat st;
char *queue_name;
const char *queue_name;
SCAN_DIR *info;
char *path;
int actual_depth;
int wanted_depth;
char **cpp;
struct queue_info *qp;
unsigned long inum;
/*
* Make sure every file is in the right place, clean out stale files, and
@@ -345,12 +484,7 @@ static void super(char **queues, int action)
* file permissions to look for, and whether or not it is desirable
* to step into subdirectories.
*/
for (qp = queue_info; /* void */ ; qp++) {
if (qp->name == 0)
msg_fatal("unknown queue name: %s", queue_name);
if (strcmp(qp->name, queue_name) == 0)
break;
}
qp = find_queue_info(queue_name);
for (cpp = hash_queue_names->argv; /* void */ ; cpp++) {
if (*cpp == 0) {
wanted_depth = 0;
@@ -383,12 +517,8 @@ static void super(char **queues, int action)
if ((path = scan_dir_next(info)) == 0) {
if (actual_depth == 0)
break;
if (actual_depth > wanted_depth) {
if (rmdir(scan_dir_path(info)) < 0 && errno != ENOENT)
msg_warn("remove %s: %m", scan_dir_path(info));
else if (msg_verbose)
msg_info("remove %s", scan_dir_path(info));
}
if (actual_depth > wanted_depth)
postrmdir(scan_dir_path(info));
scan_dir_pop(info);
actual_depth--;
continue;
@@ -406,83 +536,174 @@ static void super(char **queues, int action)
}
/*
* See if this is a stale file or some non-file object. Be
* careful not to delete bounce or defer logs just because they
* are more than a couple days old.
* From here on we need to keep track of operations that
* invalidate or revalidate the actual_path and path variables,
* otherwise we can hit the wrong files.
*/
vstring_sprintf(actual_path, "%s/%s", scan_dir_path(info), path);
if (stat(STR(actual_path), &st) < 0)
continue;
/*
* Remove alien directories. If maildrop is world writable, then
* we cannot abort just because we cannot remove someone's
* directory.
*/
if (S_ISDIR(st.st_mode)) {
if (rmdir(STR(actual_path)) < 0 && errno != ENOENT)
msg_warn("remove subdirectory %s: %m", STR(actual_path));
else if (msg_verbose)
msg_info("remove subdirectory %s", STR(actual_path));
continue;
}
if (!S_ISREG(st.st_mode)
|| ((action & ACTION_PURGE) != 0 &&
(st.st_mode & S_IRWXU) != qp->perms
&& time((time_t *) 0) > st.st_mtime + MAX_TEMP_AGE)) {
if (remove(STR(actual_path)) < 0 && errno != ENOENT)
msg_warn("remove %s: %m", STR(actual_path));
else if (msg_verbose)
msg_info("remove %s", STR(actual_path));
continue;
}
/*
* Skip temporary files that aren't old enough.
*/
if (mail_queue_id_ok(path) == 0)
continue;
/*
* Requeue this message. This means the pickup daemon will copy
* it to a new queue file, and that address rewriting is applied
* again. XXX Share more code with requeue_one(). Note, that this
* option is intended for large-scale mail queue restore
* operations so that at this stage, the queue file may not even
* be in the "right" place for the current machine. We therefore
* cannot rely on the mail_queue(3) API.()
*/
if ((action & ACTION_REQUEUE_ALL)
&& strcmp(queue_name, MAIL_QUEUE_MAILDROP) != 0) {
(void) mail_queue_path(wanted_path, MAIL_QUEUE_MAILDROP, path);
if (rename(STR(actual_path), STR(wanted_path)) < 0) {
if (rmdir(STR(actual_path)) < 0) {
if (errno != ENOENT)
msg_fatal("rename %s to %s: %m", STR(actual_path),
STR(wanted_path));
msg_warn("remove subdirectory %s: %m", STR(actual_path));
} else {
if (msg_verbose)
msg_info("rename %s to %s", STR(actual_path),
STR(wanted_path));
msg_info("remove subdirectory %s", STR(actual_path));
}
/* No further work on this object is possible. */
continue;
}
/*
* Mass deletion. We count the deletion of mail that this system
* has taken responsibility for. XXX This option does not use the
* mail_queue(3) API, so that it can be run on a queue that does
* not have files in the "right" place. It would be terribly
* inefficient to first have to rename files into place before
* deleting them.
*/
if (action & ACTION_DELETE_ALL) {
if (postremove(STR(actual_path)) == 0)
if (MESSAGE_QUEUE(qp) && READY_MESSAGE(st))
message_deleted++;
/* No further work on this object is possible. */
continue;
}
/*
* Remove non-file objects and old temporary files. Be careful
* not to delete bounce or defer logs just because they are more
* than a couple days old.
*/
if (!S_ISREG(st.st_mode)
|| ((action & ACTION_PURGE) != 0
&& MESSAGE_QUEUE(qp)
&& !READY_MESSAGE(st)
&& time((time_t *) 0) > st.st_mtime + MAX_TEMP_AGE)) {
(void) postremove(STR(actual_path));
/* No further work on this object is possible. */
continue;
}
/*
* Skip temporary message files that aren't old enough.
*/
if (MESSAGE_QUEUE(qp) && !READY_MESSAGE(st))
/* No further work on this object is possible. */
continue;
/*
* Fix queueid#FIX names that were left from a previous pass over
* the queue where message queue file names were matched to their
* inode number. This requires that the file is already in the
* proper directory so that we only have to strip the suffix.
* Make sure that the name minus suffix is well formed and that
* the name matches the file inode number.
*/
if (strcmp(path + (strlen(path) - SUFFIX_LEN), SUFFIX) == 0) {
path[strlen(path) - SUFFIX_LEN] = 0; /* XXX */
if (!mail_queue_id_ok(path)) {
msg_warn("bogus file name: %s", STR(actual_path));
continue;
}
if (MESSAGE_QUEUE(qp)) {
if (sscanf(path + 5, "%lx", &inum) != 1) {
msg_warn("bogus file name: %s", STR(actual_path));
continue;
}
if (inum != (unsigned long) st.st_ino) {
msg_warn("name/inode mismatch: %s", STR(actual_path));
continue;
}
}
vstring_strncpy(wanted_path, STR(actual_path),
strlen(STR(actual_path)) - SUFFIX_LEN);
if (postrename(STR(actual_path), STR(wanted_path)) < 0) {
/* No further work on this object is possible. */
continue;
} else {
if (MESSAGE_QUEUE(qp))
inode_fixed++;
vstring_strcpy(actual_path, STR(wanted_path));
/* At this point, path and actual_path are revalidated. */
}
}
/*
* Skip over files with illegal names. The library routines
* refuse to operate on them.
*/
if (!mail_queue_id_ok(path)) {
msg_warn("bogus file name: %s", STR(actual_path));
continue;
}
/*
* Mass requeuing. The pickup daemon will copy requeued mail to a
* new queue file, so that address rewriting is applied again.
* XXX This option does not use the mail_queue(3) API, so that it
* can be run on a queue that does not have the files in the
* "right" place. It would be terribly inefficient to first have
* to rename files into place before requeuing them. Like the
* requeue_one() routine, this code does not touch logfiles.
*/
if ((action & ACTION_REQUEUE_ALL)
&& MESSAGE_QUEUE(qp)
&& strcmp(queue_name, MAIL_QUEUE_MAILDROP) != 0) {
(void) mail_queue_path(wanted_path, MAIL_QUEUE_MAILDROP, path);
if (postrename(STR(actual_path), STR(wanted_path)) == 0)
message_requeued++;
/* At this point, path and actual_path are invalidated. */
continue;
}
/*
* See if the file name matches the file inode number. Skip meta
* file directories. This option requires that meta files be put
* into their proper place before queue files, so that we can
* rename queue files and meta files at the same time. Mis-named
* files are renamed to newqueueid#FIX on the first pass, and
* upon the second pass the #FIX is stripped off the name. Of
* course we have to be prepared that the program is interrupted
* before it completes, so any left-over newqueueid#FIX files
* have to be handled properly. XXX This option does not use the
* mail_queue(3) API for message queue files, so that it can be
* run on a queue that does not have message queue files in the
* "right" place. It would be terribly inefficient to first have
* to rename files into place before fixing the file names.
*/
if ((action & ACTION_STRUCT) != 0 && MESSAGE_QUEUE(qp)) {
if (sscanf(path + 5, "%lx", &inum) != 1) {
msg_warn("bogus file name: %s", STR(actual_path));
continue;
}
if (inum != (unsigned long) st.st_ino) {
inode_mismatch++; /* before we fix */
fix_queue_id(STR(actual_path), queue_name, path, st.st_ino);
/* At this point, path and actual_path are invalidated. */
continue;
}
}
/*
* See if this file sits in the right place in the file system
* hierarchy. Its place may be wrong after a change to the
* hash_queue_{names,depth} parameter settings. The implied
* mkdir() operation is the main reason for this command to run
* with postfix privilege. The mail_queue_mkdirs() routine could
* be fixed to use the "right" privilege, but it is a good idea
* to do everything with the postfix owner privileges regardless,
* in order to limit the amount of damage that we can do.
* hash_queue_{names,depth} parameter settings.
*/
if (action & ACTION_STRUCT) {
(void) mail_queue_path(wanted_path, queue_name, path);
if (strcmp(STR(actual_path), STR(wanted_path)) != 0) {
if (rename(STR(actual_path), STR(wanted_path)) < 0)
if (errno != ENOENT
|| mail_queue_mkdirs(STR(wanted_path)) < 0
|| rename(STR(actual_path), STR(wanted_path)) < 0)
msg_fatal("rename %s to %s: %m", STR(actual_path),
STR(wanted_path));
if (msg_verbose)
msg_info("rename %s to %s", STR(actual_path),
STR(wanted_path));
position_mismatch++; /* before we fix */
(void) postrename(STR(actual_path), STR(wanted_path));
/* At this point, path and actual_path are invalidated. */
continue;
}
}
}
@@ -497,27 +718,43 @@ static void super(char **queues, int action)
argv_free(hash_queue_names);
}
/* fatal_exit - print warning if queue fix is incomplete */
static void fatal_exit(void)
{
if (inode_mismatch > 0 || inode_fixed > 0 || position_mismatch > 0)
msg_fatal("OPERATION INCOMPLETE -- RERUN COMMAND TO FIX THE QUEUE FIRST");
}
/* interrupted - signal handler */
static void interrupted(int unused_sig)
{
fatal_exit();
}
int main(int argc, char **argv)
{
int fd;
struct stat st;
char *slash;
int debug_me = 0;
int action = 0;
char **queues;
const char **queues;
int c;
int found = 0;
ARGV *requeue_names = 0;
ARGV *delete_names = 0;
char **cpp;
/*
* Defaults.
*/
static char *default_queues[] = {
MAIL_QUEUE_DEFER, /* before message directories */
MAIL_QUEUE_BOUNCE, /* before message directories */
MAIL_QUEUE_MAILDROP,
MAIL_QUEUE_INCOMING,
MAIL_QUEUE_ACTIVE,
MAIL_QUEUE_DEFERRED,
MAIL_QUEUE_DEFER,
MAIL_QUEUE_BOUNCE,
MAIL_QUEUE_FLUSH,
0,
};
@@ -544,8 +781,6 @@ int main(int argc, char **argv)
*/
if (safe_getenv(CONF_ENV_VERB))
msg_verbose = 1;
if (safe_getenv(CONF_ENV_DEBUG))
debug_me = 1;
/*
* Initialize. Set up logging, read the global configuration file and
@@ -561,6 +796,17 @@ int main(int argc, char **argv)
if (chdir(var_queue_dir))
msg_fatal("chdir %s: %m", var_queue_dir);
/*
* Be sure to log a warning if we do not finish structural repair. Maybe
* we should have an fsck-style "clean" flag so Postfix will not start
* with a broken queue.
*/
signal(SIGHUP, interrupted);
signal(SIGINT, interrupted);
signal(SIGQUIT, interrupted);
signal(SIGTERM, interrupted);
msg_cleanup(fatal_exit);
/*
* All file/directory updates must be done as the mail system owner. This
* is because Postfix daemons manipulate the queue with those same
@@ -579,30 +825,27 @@ int main(int argc, char **argv)
/*
* Parse JCL.
*/
while ((c = GETOPT(argc, argv, "d:spv")) > 0) {
while ((c = GETOPT(argc, argv, "d:pr:sv")) > 0) {
switch (c) {
default:
msg_fatal("usage: %s [-d queue_id (delete message)] [-p (purge stale files)] [-r queue_id (requeue message)] [-R (requeue all)] [-s (fix structure)]",
msg_fatal("usage: %s [-d queue_id (delete)] [-p (purge temporary files)] [-r queue_id (requeue)] [-s (structure fix)]",
argv[0]);
case 'd':
if (strcmp(optarg, "-") == 0)
found |= operate_stream(VSTREAM_IN, delete_one);
else
found |= delete_one(optarg);
action |= ACTION_DELETE;
if (delete_names == 0)
delete_names = argv_alloc(1);
argv_add(delete_names, optarg, (char *) 0);
action |= (strcmp(optarg, "ALL") == 0 ?
ACTION_DELETE_ALL : ACTION_DELETE_ONE);
break;
case 'p':
action |= ACTION_PURGE;
break;
case 'r':
if (strcmp(optarg, "-") == 0)
found |= operate_stream(VSTREAM_IN, requeue_one);
else
found |= requeue_one(optarg);
action |= ACTION_REQUEUE;
break;
case 'R':
action |= ACTION_REQUEUE_ALL;
if (requeue_names == 0)
requeue_names = argv_alloc(1);
argv_add(requeue_names, optarg, (char *) 0);
action |= (strcmp(optarg, "ALL") == 0 ?
ACTION_REQUEUE_ALL : ACTION_REQUEUE_ONE);
break;
case 's':
action |= ACTION_STRUCT;
@@ -616,17 +859,94 @@ int main(int argc, char **argv)
/*
* Execute the explicitly specified (or default) action, on the
* explicitly specified (or default) queues.
*
* XXX Work around gcc const brain damage.
*/
if (action == 0)
action = ACTION_DEFAULT;
if (argv[optind] == 0)
queues = default_queues;
queues = (const char **) default_queues;
else
queues = argv + optind;
queues = (const char **) argv + optind;
#define ACTIONS_ON_THE_FLY (ACTION_DELETE | ACTION_REQUEUE)
#define ACTIONS_BY_QUEUE_ID (ACTION_DELETE_ONE | ACTION_REQUEUE_ONE)
if (action & ~ACTIONS_ON_THE_FLY)
super(queues, action & ~ACTIONS_ON_THE_FLY);
exit((action & ACTIONS_ON_THE_FLY) ? !found : 0);
/*
* Basic queue maintenance, as well as mass deletion, mass requeuing, and
* mass name-to-inode fixing. This ensures that queue files are in the
* right place before the queue file by name operations are done.
*/
if (action & ~ACTIONS_BY_QUEUE_ID)
super(queues, action & ~ACTIONS_BY_QUEUE_ID);
if (inode_mismatch > 0)
super(queues, 0);
/*
* Delete queue files by name. This must not be done when queue files
* have changed names as a result of the structure check, because we
* could be deleiting the wrong message.
*/
if (action & ACTION_DELETE_ONE) {
if (inode_mismatch > 0 || inode_fixed > 0) {
msg_error("QUEUE FILE NAMES WERE CHANGED TO MATCH INODE NUMBERS");
msg_fatal("CHECK YOUR QUEUE IDS AND RE-ISSUE THE COMMAND");
}
argv_terminate(delete_names);
for (cpp = delete_names->argv; *cpp; cpp++) {
if (strcmp(*cpp, "ALL") == 0)
continue;
if (strcmp(*cpp, "-") == 0)
message_deleted +=
operate_stream(VSTREAM_IN, delete_one, queues);
else
message_deleted += delete_one(queues, *cpp);
}
}
/*
* Requeue queue files by name. This must not be done when queue files
* have changed names as a result of the structure check, because we
* could be requeuing the wrong message.
*/
if (action & ACTION_REQUEUE_ONE) {
if (inode_mismatch > 0 || inode_fixed > 0) {
msg_error("QUEUE FILE NAMES WERE CHANGED TO MATCH INODE NUMBERS");
msg_fatal("CHECK YOUR QUEUE IDS AND RE-ISSUE THE COMMAND");
}
argv_terminate(requeue_names);
for (cpp = requeue_names->argv; *cpp; cpp++) {
if (strcmp(*cpp, "ALL") == 0)
continue;
if (strcmp(*cpp, "-") == 0)
message_requeued +=
operate_stream(VSTREAM_IN, requeue_one, queues);
else
message_requeued += requeue_one(queues, *cpp);
}
}
/*
* Report.
*/
if (message_requeued > 0)
msg_info("Requeued: %d message%s", message_requeued,
message_requeued > 1 ? "s" : "");
if (message_deleted > 0)
msg_info("Deleted: %d message%s", message_deleted,
message_deleted > 1 ? "s" : "");
if (inode_fixed > 0)
msg_info("Renamed to match inode number: %d message%s", inode_fixed,
inode_fixed > 1 ? "s" : "");
if (inode_mismatch > 0 || inode_fixed > 0)
msg_warn("QUEUE FILE NAMES WERE CHANGED TO MATCH INODE NUMBERS");
/*
* Clean up.
*/
if (requeue_names)
argv_free(requeue_names);
if (delete_names)
argv_free(delete_names);
exit(0);
}

View File

@@ -584,6 +584,8 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
ldap_msgfree(res);
if (filter_buf != 0)
vstring_free(filter_buf);
if (escaped_name != 0)
vstring_free(escaped_name);
/*
* If we had an error, return nothing, Otherwise, return the result, if