mirror of
https://github.com/vdukhovni/postfix
synced 2025-08-31 22:25:24 +00:00
snapshot-20010524
This commit is contained in:
committed by
Viktor Dukhovni
parent
92370560ec
commit
ca0dd40ea2
@@ -5187,13 +5187,18 @@ Apologies for any names omitted.
|
|||||||
|
|
||||||
20010522
|
20010522
|
||||||
|
|
||||||
Feature: "postsuper -r queueID" re-queues a message. The
|
Feature: "postsuper -r queueID" re-queues a message, and
|
||||||
message is moved to the maildrop queue so that the pickup
|
"postsuper -R" re-queues all mail. The message is moved to
|
||||||
daemon will copy it to a new file with the "right" name
|
the maildrop queue so that the pickup daemon will copy it
|
||||||
that matches the queue file inode number, and so that
|
to a new queue file, and so that address rewriting will be
|
||||||
address rewriting will be done again. This is useful after
|
done again. This is useful after changes of address rewriting
|
||||||
changes of address rewriting or virtual mappings.
|
or virtual mappings.
|
||||||
|
|
||||||
Feature: "postsuper -R" re-queues all mail. This is useful
|
20010523
|
||||||
after restoring a Postfix queue from another machine, or
|
|
||||||
from backup.
|
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.
|
||||||
|
@@ -12,20 +12,22 @@ server state just like RSET. This behavior cannot be disabled.
|
|||||||
Major changes with snapshot-20010522
|
Major changes with snapshot-20010522
|
||||||
====================================
|
====================================
|
||||||
|
|
||||||
Revision of some fine details in the light of the new RFC 2821 and
|
This release contains revisions of some fine details in the light
|
||||||
RFC 2822 standards. Changes that may affect interoperability are
|
of the new RFC 2821 and RFC 2822 standards. Changes that may affect
|
||||||
listed above under "incompatible changes".
|
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
|
The postsuper queue maintenance tool was extended with options to
|
||||||
read queue IDs from standard input (which makes it easier to drive
|
read queue IDs from standard input. This makes the tool easier to
|
||||||
the tool from scripts).
|
drive from scripts.
|
||||||
|
|
||||||
The postsuper queue maintenance tool has a new -r (requeue) option
|
The postsuper queue maintenance tool has a new -r (requeue) option
|
||||||
for subjecting queue files to another iteration of address rewriting.
|
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
|
Major changes with snapshot-20010502
|
||||||
====================================
|
====================================
|
||||||
|
|
||||||
|
@@ -174,9 +174,6 @@ check)
|
|||||||
\( -perm -020 -o -perm -002 \) \
|
\( -perm -020 -o -perm -002 \) \
|
||||||
-exec $WARN group or other writable: {} \;
|
-exec $WARN group or other writable: {} \;
|
||||||
|
|
||||||
find $queue_directory/* $config_directory/* -name '*core' \
|
|
||||||
-exec $WARN core file: {} \; 2>/dev/null
|
|
||||||
|
|
||||||
test -d maildrop || {
|
test -d maildrop || {
|
||||||
$WARN creating missing Postfix maildrop directory
|
$WARN creating missing Postfix maildrop directory
|
||||||
mkdir maildrop || exit 1
|
mkdir maildrop || exit 1
|
||||||
@@ -254,10 +251,11 @@ EOF
|
|||||||
$command_directory/postconf -e hash_queue_names="$found$missing"
|
$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 || exit 1
|
||||||
$command_directory/postsuper &
|
|
||||||
|
|
||||||
find corrupt -type f -exec $WARN damaged message: {} \;
|
find corrupt -type f -exec $WARN damaged message: {} \;
|
||||||
|
|
||||||
|
@@ -174,9 +174,6 @@ check)
|
|||||||
\( -perm -020 -o -perm -002 \) \
|
\( -perm -020 -o -perm -002 \) \
|
||||||
-exec $WARN group or other writable: {} \;
|
-exec $WARN group or other writable: {} \;
|
||||||
|
|
||||||
find $queue_directory/* $config_directory/* -name '*core' \
|
|
||||||
-exec $WARN core file: {} \; 2>/dev/null
|
|
||||||
|
|
||||||
test -d maildrop || {
|
test -d maildrop || {
|
||||||
$WARN creating missing Postfix maildrop directory
|
$WARN creating missing Postfix maildrop directory
|
||||||
mkdir maildrop || exit 1
|
mkdir maildrop || exit 1
|
||||||
@@ -255,10 +252,11 @@ EOF
|
|||||||
$command_directory/postconf -e hash_queue_names="$found$missing"
|
$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 || exit 1
|
||||||
$command_directory/postsuper &
|
|
||||||
|
|
||||||
find corrupt -type f -exec $WARN damaged message: {} \;
|
find corrupt -type f -exec $WARN damaged message: {} \;
|
||||||
|
|
||||||
|
@@ -3063,13 +3063,61 @@ that the file name will collide with another queue file.
|
|||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
|
||||||
To avoid queue file name collisions when copying queue files,
|
<ul>
|
||||||
restore the incoming, active and deferred queue files under the
|
|
||||||
maildrop directory instead.
|
<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>
|
<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
|
ABCDEF is stored as A/B/ABCDEF), so you need an additional step to
|
||||||
move files down from their subdirectories.
|
move files down from their subdirectories.
|
||||||
|
|
||||||
@@ -3083,15 +3131,15 @@ move files down from their subdirectories.
|
|||||||
# postfix start
|
# postfix start
|
||||||
</pre>
|
</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>
|
<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.
|
maildrop directory and will give them proper queue file names.
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
<hr>
|
<hr>
|
||||||
|
|
||||||
<a name="bind"><h3>Undefined symbols: ___dn_expand, ___res_init etc.</h3></a>
|
<a name="bind"><h3>Undefined symbols: ___dn_expand, ___res_init etc.</h3></a>
|
||||||
|
@@ -13,52 +13,52 @@ POSTSUPER(1) POSTSUPER(1)
|
|||||||
<i>...</i>]
|
<i>...</i>]
|
||||||
|
|
||||||
<b>DESCRIPTION</b>
|
<b>DESCRIPTION</b>
|
||||||
The <b>postsuper</b> command does small maintenance jobs. Use of
|
The <b>postsuper</b> command does maintenance jobs on the Postfix
|
||||||
the command is restricted to the super-user.
|
queue. Use of the command is restricted to the super-user.
|
||||||
|
|
||||||
By default, <b>postsuper</b> performs the operations requested
|
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-
|
with the <b>-s</b> and <b>-p</b> command-line options on all Postfix
|
||||||
fix queue directories (default: all). Directory names are
|
queue directories - this includes the <b>incoming</b>, <b>active</b> and
|
||||||
relative to the Postfix top-level queue directory.
|
<b>deferred</b> directories with mail files and the <b>bounce</b>, <b>defer</b>
|
||||||
|
and <b>flush</b> directories with log files.
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
|
|
||||||
<b>-d</b> This option ignores any <i>directory</i> argument(s).
|
<b>-d</b> <i>queue_id</i>
|
||||||
Delete one message queue file with the named queue
|
Delete one message with the named queue ID from the
|
||||||
ID. Specify multiple <b>-d</b> options to delete multiple
|
named mail queue(s) (default: <b>incoming</b>, <b>active</b> and
|
||||||
queue files by name.
|
<b>deferred</b>). If a <i>queue_id</i> of <b>-</b> is specified, the
|
||||||
|
|
||||||
Alternatively, if a <i>queue_id</i> of <b>-</b> is specified, the
|
|
||||||
program reads queue IDs from standard input.
|
program reads queue IDs from standard input.
|
||||||
|
|
||||||
The <b>postsuper</b> exit status is non-zero when no mes-
|
Specify <b>-d</b> <b>ALL</b> to remove all messages; for example,
|
||||||
sage queue file was deleted.
|
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>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>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>small</b> <b>possibility</b> <b>that</b> <b>postsuper</b> <b>deletes</b> <b>the</b> <b>wrong</b>
|
||||||
<b>while</b> <b>the</b> <b>Postfix</b> <b>mail</b> <b>system</b> <b>is</b> <b>running.</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:
|
The scenario is as follows:
|
||||||
|
|
||||||
<b>o</b> The Postfix queue manager deletes the file
|
1) The Postfix queue manager deletes the mes-
|
||||||
that <b>postsuper</b> was supposed to delete,
|
sage that <b>postsuper</b> is supposed to delete,
|
||||||
because Postfix was finished with the mes-
|
because Postfix is finished with the mes-
|
||||||
sage.
|
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
|
given the same queue ID as the message that
|
||||||
<b>postsuper</b> was supposed to delete. The prob-
|
<b>postsuper</b> is supposed to delete. The proba-
|
||||||
ability for reusing a deleted queue ID is
|
bility for reusing a deleted queue ID is
|
||||||
about 1 in 2**15 (the number of different
|
about 1 in 2**15 (the number of different
|
||||||
microsecond values that the system clock can
|
microsecond values that the system clock can
|
||||||
distinguish within a second).
|
distinguish within a second).
|
||||||
|
|
||||||
<b>o</b> <b>postsuper</b> deletes the new message file,
|
3) <b>postsuper</b> deletes the new message, instead
|
||||||
instead of the old file that should have
|
of the old message that it should have
|
||||||
been deleted.
|
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)
|
POSTSUPER(1) POSTSUPER(1)
|
||||||
|
|
||||||
|
|
||||||
ID. Specify multiple <b>-r</b> options to requeue multi-
|
<b>-p</b> Purge old temporary files that are left over after
|
||||||
ple queue files by name.
|
system or software crashes.
|
||||||
|
|
||||||
Alternatively, if a <i>queue_id</i> of <b>-</b> is specified, the
|
<b>-r</b> <i>queue_id</i>
|
||||||
program reads queue IDs from standard input.
|
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
|
Specify <b>-r</b> <b>ALL</b> to requeue all messages. As a safety
|
||||||
where it is copied by the pickup daemon to a new
|
measure, the word <b>ALL</b> must be specified in upper
|
||||||
file whose name is guaranteed to match the queue
|
case.
|
||||||
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.
|
|
||||||
|
|
||||||
The <b>postsuper</b> exit status is non-zero when no mes-
|
A requeued message is moved to the <b>maildrop</b> queue,
|
||||||
sage queue file was requeued.
|
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
|
Postfix queue IDs are reused. There is a very
|
||||||
wrong place in the file system hierarchy and remove
|
small possibility that <b>postsuper</b> requeues the wrong
|
||||||
subdirectories that are no longer needed. File
|
message file when it is executed while the Postfix
|
||||||
rearrangements are necessary after a change in the
|
mail system is running, but no harm should be done.
|
||||||
<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.
|
|
||||||
|
|
||||||
<b>-p</b> Purge stale files (files that are left over after
|
<b>-s</b> Structure check and structure repair. It is highly
|
||||||
system or software crashes).
|
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-
|
<b>-v</b> Enable verbose logging for debugging purposes. Mul-
|
||||||
tiple <b>-v</b> options make the software increasingly
|
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
|
Problems are reported to the standard error stream and to
|
||||||
<b>syslogd</b>.
|
<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>
|
<b>CONFIGURATION</b> <b>PARAMETERS</b>
|
||||||
See the Postfix <b>main.cf</b> file for syntax details and for
|
See the Postfix <b>main.cf</b> file for syntax details and for
|
||||||
default values.
|
default values.
|
||||||
@@ -125,18 +159,6 @@ POSTSUPER(1) POSTSUPER(1)
|
|||||||
<b>AUTHOR(S)</b>
|
<b>AUTHOR(S)</b>
|
||||||
Wietse Venema
|
Wietse Venema
|
||||||
IBM T.J. Watson Research
|
IBM T.J. Watson Research
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
2
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
POSTSUPER(1) POSTSUPER(1)
|
|
||||||
|
|
||||||
|
|
||||||
P.O. Box 704
|
P.O. Box 704
|
||||||
Yorktown Heights, NY 10598, USA
|
Yorktown Heights, NY 10598, USA
|
||||||
|
|
||||||
@@ -151,28 +173,6 @@ POSTSUPER(1) POSTSUPER(1)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@@ -14,27 +14,30 @@ Postfix super intendent
|
|||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
.ad
|
.ad
|
||||||
.fi
|
.fi
|
||||||
The \fBpostsuper\fR command does small maintenance jobs. Use of
|
The \fBpostsuper\fR command does maintenance jobs on the Postfix
|
||||||
the command is restricted to the super-user.
|
queue. Use of the command is restricted to the super-user.
|
||||||
|
|
||||||
By default, \fBpostsuper\fR performs the operations requested with the
|
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
|
\fB-s\fR and \fB-p\fR command-line options on all Postfix queue
|
||||||
directories (default: all).
|
directories - this includes the \fBincoming\fR, \fBactive\fR and
|
||||||
Directory names are relative to the Postfix top-level queue directory.
|
\fBdeferred\fR directories with mail files and the \fBbounce\fR,
|
||||||
|
\fBdefer\fR and \fBflush\fR directories with log files.
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
.IP \fB-d \fIqueue_id\fR
|
.IP "\fB-d \fIqueue_id\fR"
|
||||||
This option ignores any \fIdirectory\fR argument(s).
|
Delete one message with the named queue ID from the named
|
||||||
Delete one message queue file with the named queue ID. Specify
|
mail queue(s) (default: \fBincoming\fR, \fBactive\fR and
|
||||||
multiple \fB-d\fR options to delete multiple queue files by name.
|
\fBdeferred\fR).
|
||||||
|
If a \fIqueue_id\fR of \fB-\fR is specified, the program reads
|
||||||
|
queue IDs from standard input.
|
||||||
.sp
|
.sp
|
||||||
Alternatively, if a \fIqueue_id\fR of \fB-\fR is specified, the
|
Specify \fB-d ALL\fR to remove all messages; for example, specify
|
||||||
program reads queue IDs from standard input.
|
\fB-d ALL deferred\fR to delete mail in the \fBdeferred\fR queue.
|
||||||
.sp
|
As a safety measure, the word \fBALL\fR must be specified in upper
|
||||||
The \fBpostsuper\fR exit status is non-zero when no message queue
|
case.
|
||||||
file was deleted.
|
|
||||||
.sp
|
.sp
|
||||||
.ft B
|
.ft B
|
||||||
|
Postfix queue IDs are reused.
|
||||||
There is a very small possibility that postsuper deletes the
|
There is a very small possibility that postsuper deletes the
|
||||||
wrong message file when it is executed while the Postfix mail
|
wrong message file when it is executed while the Postfix mail
|
||||||
system is running.
|
system is running.
|
||||||
@@ -42,47 +45,61 @@ system is running.
|
|||||||
.sp
|
.sp
|
||||||
The scenario is as follows:
|
The scenario is as follows:
|
||||||
.RS
|
.RS
|
||||||
.IP \(bu
|
.IP 1)
|
||||||
The Postfix queue manager deletes the file that \fBpostsuper\fR
|
The Postfix queue manager deletes the message that \fBpostsuper\fR
|
||||||
was supposed to delete, because Postfix was finished with the
|
is supposed to delete, because Postfix is finished with the
|
||||||
message.
|
message.
|
||||||
.IP \(bu
|
.IP 2)
|
||||||
New mail arrives, and the new message is given the same queue ID
|
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 probability for reusing a deleted queue ID is about 1 in 2**15
|
||||||
(the number of different microsecond values that the system clock
|
(the number of different microsecond values that the system clock
|
||||||
can distinguish within a second).
|
can distinguish within a second).
|
||||||
.IP \(bu
|
.IP 3)
|
||||||
\fBpostsuper\fR deletes the new message file, instead of the
|
\fBpostsuper\fR deletes the new message, instead of the old
|
||||||
old file that should have been deleted.
|
message that it should have deleted.
|
||||||
.RE
|
.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
|
.IP \fB-p\fR
|
||||||
Purge stale files (files that are left over after system or
|
Purge old temporary files that are left over after system or
|
||||||
software crashes).
|
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
|
.IP \fB-v\fR
|
||||||
Enable verbose logging for debugging purposes. Multiple \fB-v\fR
|
Enable verbose logging for debugging purposes. Multiple \fB-v\fR
|
||||||
options make the software increasingly verbose.
|
options make the software increasingly verbose.
|
||||||
@@ -91,6 +108,11 @@ options make the software increasingly verbose.
|
|||||||
.fi
|
.fi
|
||||||
Problems are reported to the standard error stream and to
|
Problems are reported to the standard error stream and to
|
||||||
\fBsyslogd\fR.
|
\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
|
.SH CONFIGURATION PARAMETERS
|
||||||
.na
|
.na
|
||||||
.nf
|
.nf
|
||||||
|
@@ -65,7 +65,7 @@ const char *get_file_id(int fd)
|
|||||||
result = vstring_alloc(1);
|
result = vstring_alloc(1);
|
||||||
if (fstat(fd, &st) < 0)
|
if (fstat(fd, &st) < 0)
|
||||||
msg_fatal("fstat: %m");
|
msg_fatal("fstat: %m");
|
||||||
vstring_sprintf(result, "%X", (int) st.st_ino);
|
vstring_sprintf(result, "%lX", (long) st.st_ino);
|
||||||
return (vstring_str(result));
|
return (vstring_str(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -388,11 +388,13 @@ VSTREAM *mail_queue_enter(const char *queue_name, int mode)
|
|||||||
for (count = 0;; count++) {
|
for (count = 0;; count++) {
|
||||||
vstring_sprintf(id_buf, "%05X%s", (int) tv.tv_usec, file_id);
|
vstring_sprintf(id_buf, "%05X%s", (int) tv.tv_usec, file_id);
|
||||||
mail_queue_path(path_buf, queue_name, STR(id_buf));
|
mail_queue_path(path_buf, queue_name, STR(id_buf));
|
||||||
|
#if 0
|
||||||
if (access(STR(path_buf), X_OK) == 0) { /* collision. */
|
if (access(STR(path_buf), X_OK) == 0) { /* collision. */
|
||||||
if ((int) ++tv.tv_usec < 0)
|
if ((int) ++tv.tv_usec < 0)
|
||||||
tv.tv_usec = 0;
|
tv.tv_usec = 0;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
if (sane_rename(STR(temp_path), STR(path_buf)) == 0) /* success */
|
if (sane_rename(STR(temp_path), STR(path_buf)) == 0) /* success */
|
||||||
break;
|
break;
|
||||||
if (errno == EPERM || errno == EISDIR) {/* collision. weird. */
|
if (errno == EPERM || errno == EISDIR) {/* collision. weird. */
|
||||||
|
@@ -15,7 +15,7 @@
|
|||||||
* Version of this program.
|
* Version of this program.
|
||||||
*/
|
*/
|
||||||
#define VAR_MAIL_VERSION "mail_version"
|
#define VAR_MAIL_VERSION "mail_version"
|
||||||
#define DEF_MAIL_VERSION "Snapshot-20010522"
|
#define DEF_MAIL_VERSION "Snapshot-20010524"
|
||||||
extern char *var_mail_version;
|
extern char *var_mail_version;
|
||||||
|
|
||||||
/* LICENSE
|
/* LICENSE
|
||||||
|
@@ -5,30 +5,33 @@
|
|||||||
/* Postfix superintendent
|
/* Postfix superintendent
|
||||||
/* SYNOPSIS
|
/* SYNOPSIS
|
||||||
/* .fi
|
/* .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]
|
/* [\fB-r \fIqueue_id\fR] [\fIdirectory ...\fR]
|
||||||
/* DESCRIPTION
|
/* DESCRIPTION
|
||||||
/* The \fBpostsuper\fR command does small maintenance jobs. Use of
|
/* The \fBpostsuper\fR command does maintenance jobs on the Postfix
|
||||||
/* the command is restricted to the super-user.
|
/* queue. Use of the command is restricted to the super-user.
|
||||||
/*
|
/*
|
||||||
/* By default, \fBpostsuper\fR performs the operations requested with the
|
/* 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
|
/* \fB-s\fR and \fB-p\fR command-line options on all Postfix queue
|
||||||
/* directories (default: all).
|
/* directories - this includes the \fBincoming\fR, \fBactive\fR and
|
||||||
/* Directory names are relative to the Postfix top-level queue directory.
|
/* \fBdeferred\fR directories with mail files and the \fBbounce\fR,
|
||||||
|
/* \fBdefer\fR and \fBflush\fR directories with log files.
|
||||||
/*
|
/*
|
||||||
/* Options:
|
/* Options:
|
||||||
/* .IP \fB-d \fIqueue_id\fR
|
/* .IP "\fB-d \fIqueue_id\fR"
|
||||||
/* This option ignores any \fIdirectory\fR argument(s).
|
/* Delete one message with the named queue ID from the named
|
||||||
/* Delete one message queue file with the named queue ID. Specify
|
/* mail queue(s) (default: \fBincoming\fR, \fBactive\fR and
|
||||||
/* multiple \fB-d\fR options to delete multiple queue files by name.
|
/* \fBdeferred\fR).
|
||||||
|
/* If a \fIqueue_id\fR of \fB-\fR is specified, the program reads
|
||||||
|
/* queue IDs from standard input.
|
||||||
/* .sp
|
/* .sp
|
||||||
/* Alternatively, if a \fIqueue_id\fR of \fB-\fR is specified, the
|
/* Specify \fB-d ALL\fR to remove all messages; for example, specify
|
||||||
/* program reads queue IDs from standard input.
|
/* \fB-d ALL deferred\fR to delete mail in the \fBdeferred\fR queue.
|
||||||
/* .sp
|
/* As a safety measure, the word \fBALL\fR must be specified in upper
|
||||||
/* The \fBpostsuper\fR exit status is non-zero when no message queue
|
/* case.
|
||||||
/* file was deleted.
|
|
||||||
/* .sp
|
/* .sp
|
||||||
/* .ft B
|
/* .ft B
|
||||||
|
/* Postfix queue IDs are reused.
|
||||||
/* There is a very small possibility that postsuper deletes the
|
/* There is a very small possibility that postsuper deletes the
|
||||||
/* wrong message file when it is executed while the Postfix mail
|
/* wrong message file when it is executed while the Postfix mail
|
||||||
/* system is running.
|
/* system is running.
|
||||||
@@ -36,64 +39,72 @@
|
|||||||
/* .sp
|
/* .sp
|
||||||
/* The scenario is as follows:
|
/* The scenario is as follows:
|
||||||
/* .RS
|
/* .RS
|
||||||
/* .IP \(bu
|
/* .IP 1)
|
||||||
/* The Postfix queue manager deletes the file that \fBpostsuper\fR
|
/* The Postfix queue manager deletes the message that \fBpostsuper\fR
|
||||||
/* was supposed to delete, because Postfix was finished with the
|
/* is supposed to delete, because Postfix is finished with the
|
||||||
/* message.
|
/* message.
|
||||||
/* .IP \(bu
|
/* .IP 2)
|
||||||
/* New mail arrives, and the new message is given the same queue ID
|
/* 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 probability for reusing a deleted queue ID is about 1 in 2**15
|
||||||
/* (the number of different microsecond values that the system clock
|
/* (the number of different microsecond values that the system clock
|
||||||
/* can distinguish within a second).
|
/* can distinguish within a second).
|
||||||
/* .IP \(bu
|
/* .IP 3)
|
||||||
/* \fBpostsuper\fR deletes the new message file, instead of the
|
/* \fBpostsuper\fR deletes the new message, instead of the old
|
||||||
/* old file that should have been deleted.
|
/* message that it should have deleted.
|
||||||
/* .RE
|
/* .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
|
/* .IP \fB-p\fR
|
||||||
/* Purge stale files (files that are left over after system or
|
/* Purge old temporary files that are left over after system or
|
||||||
/* software crashes).
|
/* 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
|
/* .IP \fB-v\fR
|
||||||
/* Enable verbose logging for debugging purposes. Multiple \fB-v\fR
|
/* Enable verbose logging for debugging purposes. Multiple \fB-v\fR
|
||||||
/* options make the software increasingly verbose.
|
/* options make the software increasingly verbose.
|
||||||
/* DIAGNOSTICS
|
/* DIAGNOSTICS
|
||||||
/* Problems are reported to the standard error stream and to
|
/* Problems are reported to the standard error stream and to
|
||||||
/* \fBsyslogd\fR.
|
/* \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
|
/* CONFIGURATION PARAMETERS
|
||||||
/* .ad
|
/* .ad
|
||||||
/* .fi
|
/* .fi
|
||||||
@@ -123,6 +134,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <signal.h>
|
||||||
#include <stdio.h> /* remove() */
|
#include <stdio.h> /* remove() */
|
||||||
|
|
||||||
/* Utility library. */
|
/* Utility library. */
|
||||||
@@ -155,9 +167,10 @@
|
|||||||
|
|
||||||
#define ACTION_STRUCT (1<<0) /* fix file organization */
|
#define ACTION_STRUCT (1<<0) /* fix file organization */
|
||||||
#define ACTION_PURGE (1<<1) /* purge old temp files */
|
#define ACTION_PURGE (1<<1) /* purge old temp files */
|
||||||
#define ACTION_DELETE (1<<2) /* delete named queue file(s) */
|
#define ACTION_DELETE_ONE (1<<2) /* delete named queue file(s) */
|
||||||
#define ACTION_REQUEUE (1<<3) /* requeue named queue file(s) */
|
#define ACTION_DELETE_ALL (1<<3) /* delete all queue file(s) */
|
||||||
#define ACTION_REQUEUE_ALL (1<<4) /* requeue 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)
|
#define ACTION_DEFAULT (ACTION_STRUCT | ACTION_PURGE)
|
||||||
|
|
||||||
@@ -188,78 +201,144 @@ static struct queue_info queue_info[] = {
|
|||||||
0,
|
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;
|
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);
|
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);
|
return (ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* postrename - rename file with prejudice */
|
/* postrename - rename file with extreme prejudice */
|
||||||
|
|
||||||
static int postrename(const char *old, const char *new)
|
static int postrename(const char *old, const char *new)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if ((ret = sane_rename(old, new)) == 0) {
|
if ((ret = sane_rename(old, new)) < 0) {
|
||||||
msg_info("requeued file %s as %s", old, new);
|
if (errno != ENOENT
|
||||||
} else if (errno != ENOENT) {
|
|| mail_queue_mkdirs(new) < 0
|
||||||
msg_warn("requeue file %s as %s: %m", old, new);
|
|| sane_rename(old, new) < 0)
|
||||||
} else if (msg_verbose) {
|
if (errno != ENOENT)
|
||||||
msg_info("requeue file %s as %s: %m", old, new);
|
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);
|
return (ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* delete_one - delete one message instance and all its associated files */
|
/* 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;
|
struct stat st;
|
||||||
const char **msg_qpp;
|
const char **msg_qpp;
|
||||||
const char **log_qpp;
|
const char **log_qpp;
|
||||||
const char *msg_path;
|
const char *msg_path;
|
||||||
VSTRING *log_path_buf = vstring_alloc(100);
|
VSTRING *log_path_buf;
|
||||||
int found = 0;
|
int found;
|
||||||
|
int tries;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Delete defer or bounce logfiles before deleting the corresponding
|
* Sanity check. No early returns beyond this point.
|
||||||
* 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 (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)
|
if (mail_open_ok(*msg_qpp, queue_id, &st, &msg_path) != MAIL_OPEN_YES)
|
||||||
continue;
|
continue;
|
||||||
for (log_qpp = log_queue_names; *log_qpp != 0; log_qpp++)
|
for (log_qpp = log_queue_names; *log_qpp != 0; log_qpp++)
|
||||||
postunlink(mail_queue_path(log_path_buf, *log_qpp, queue_id));
|
postremove(mail_queue_path(log_path_buf, *log_qpp, queue_id));
|
||||||
if (postunlink(msg_path) == 0) {
|
if (postremove(msg_path) == 0) {
|
||||||
found = 1;
|
found = 1;
|
||||||
break;
|
break;
|
||||||
} /* else: lost a race */
|
} /* else: maybe lost a race */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
vstring_free(log_path_buf);
|
vstring_free(log_path_buf);
|
||||||
return (found);
|
return (found);
|
||||||
@@ -267,35 +346,44 @@ static int delete_one(const char *queue_id)
|
|||||||
|
|
||||||
/* requeue_one - requeue one message instance and delete its logfiles */
|
/* 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;
|
struct stat st;
|
||||||
const char **msg_qpp;
|
const char **msg_qpp;
|
||||||
const char *old_path;
|
const char *old_path;
|
||||||
VSTRING *new_path_buf = vstring_alloc(100);
|
VSTRING *new_path_buf;
|
||||||
int found = 0;
|
int found;
|
||||||
|
int tries;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Do not delete defer or bounce logfiles, to avoid losing a race where
|
* Sanity check. No early returns beyond this point.
|
||||||
* the queue manager decides to bounce mail after all recipients have
|
|
||||||
* been tried.
|
|
||||||
*/
|
*/
|
||||||
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)
|
if (mail_open_ok(*msg_qpp, queue_id, &st, &old_path) != MAIL_OPEN_YES)
|
||||||
continue;
|
continue;
|
||||||
(void) mail_queue_path(new_path_buf, MAIL_QUEUE_MAILDROP, queue_id);
|
(void) mail_queue_path(new_path_buf, MAIL_QUEUE_MAILDROP, queue_id);
|
||||||
if (postrename(old_path, STR(new_path_buf)) == 0) {
|
if (postrename(old_path, STR(new_path_buf)) == 0) {
|
||||||
found = 1;
|
found = 1;
|
||||||
break;
|
break;
|
||||||
} /* else: lost a race */
|
} /* else: maybe lost a race */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
vstring_free(new_path_buf);
|
vstring_free(new_path_buf);
|
||||||
return (found);
|
return (found);
|
||||||
@@ -303,33 +391,84 @@ static int requeue_one(const char *queue_id)
|
|||||||
|
|
||||||
/* operate_stream - operate on queue IDs given on stream */
|
/* 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);
|
VSTRING *buf = vstring_alloc(20);
|
||||||
int found = 0;
|
int found = 0;
|
||||||
|
|
||||||
while (vstring_get_nonl(buf, fp) != VSTREAM_EOF)
|
while (vstring_get_nonl(buf, fp) != VSTREAM_EOF)
|
||||||
found |= operator(STR(buf));
|
found += operator(queues, STR(buf));
|
||||||
|
|
||||||
vstring_free(buf);
|
vstring_free(buf);
|
||||||
return (found);
|
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,");
|
ARGV *hash_queue_names = argv_split(var_hash_queue_names, " \t\r\n,");
|
||||||
VSTRING *actual_path = vstring_alloc(10);
|
VSTRING *actual_path = vstring_alloc(10);
|
||||||
VSTRING *wanted_path = vstring_alloc(10);
|
VSTRING *wanted_path = vstring_alloc(10);
|
||||||
struct stat st;
|
struct stat st;
|
||||||
char *queue_name;
|
const char *queue_name;
|
||||||
SCAN_DIR *info;
|
SCAN_DIR *info;
|
||||||
char *path;
|
char *path;
|
||||||
int actual_depth;
|
int actual_depth;
|
||||||
int wanted_depth;
|
int wanted_depth;
|
||||||
char **cpp;
|
char **cpp;
|
||||||
struct queue_info *qp;
|
struct queue_info *qp;
|
||||||
|
unsigned long inum;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make sure every file is in the right place, clean out stale files, and
|
* 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
|
* file permissions to look for, and whether or not it is desirable
|
||||||
* to step into subdirectories.
|
* to step into subdirectories.
|
||||||
*/
|
*/
|
||||||
for (qp = queue_info; /* void */ ; qp++) {
|
qp = find_queue_info(queue_name);
|
||||||
if (qp->name == 0)
|
|
||||||
msg_fatal("unknown queue name: %s", queue_name);
|
|
||||||
if (strcmp(qp->name, queue_name) == 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
for (cpp = hash_queue_names->argv; /* void */ ; cpp++) {
|
for (cpp = hash_queue_names->argv; /* void */ ; cpp++) {
|
||||||
if (*cpp == 0) {
|
if (*cpp == 0) {
|
||||||
wanted_depth = 0;
|
wanted_depth = 0;
|
||||||
@@ -383,12 +517,8 @@ static void super(char **queues, int action)
|
|||||||
if ((path = scan_dir_next(info)) == 0) {
|
if ((path = scan_dir_next(info)) == 0) {
|
||||||
if (actual_depth == 0)
|
if (actual_depth == 0)
|
||||||
break;
|
break;
|
||||||
if (actual_depth > wanted_depth) {
|
if (actual_depth > wanted_depth)
|
||||||
if (rmdir(scan_dir_path(info)) < 0 && errno != ENOENT)
|
postrmdir(scan_dir_path(info));
|
||||||
msg_warn("remove %s: %m", scan_dir_path(info));
|
|
||||||
else if (msg_verbose)
|
|
||||||
msg_info("remove %s", scan_dir_path(info));
|
|
||||||
}
|
|
||||||
scan_dir_pop(info);
|
scan_dir_pop(info);
|
||||||
actual_depth--;
|
actual_depth--;
|
||||||
continue;
|
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
|
* From here on we need to keep track of operations that
|
||||||
* careful not to delete bounce or defer logs just because they
|
* invalidate or revalidate the actual_path and path variables,
|
||||||
* are more than a couple days old.
|
* otherwise we can hit the wrong files.
|
||||||
*/
|
*/
|
||||||
vstring_sprintf(actual_path, "%s/%s", scan_dir_path(info), path);
|
vstring_sprintf(actual_path, "%s/%s", scan_dir_path(info), path);
|
||||||
if (stat(STR(actual_path), &st) < 0)
|
if (stat(STR(actual_path), &st) < 0)
|
||||||
continue;
|
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 (S_ISDIR(st.st_mode)) {
|
||||||
if (rmdir(STR(actual_path)) < 0 && errno != ENOENT)
|
if (rmdir(STR(actual_path)) < 0) {
|
||||||
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 (errno != ENOENT)
|
if (errno != ENOENT)
|
||||||
msg_fatal("rename %s to %s: %m", STR(actual_path),
|
msg_warn("remove subdirectory %s: %m", STR(actual_path));
|
||||||
STR(wanted_path));
|
|
||||||
} else {
|
} else {
|
||||||
if (msg_verbose)
|
if (msg_verbose)
|
||||||
msg_info("rename %s to %s", STR(actual_path),
|
msg_info("remove subdirectory %s", STR(actual_path));
|
||||||
STR(wanted_path));
|
|
||||||
}
|
}
|
||||||
|
/* No further work on this object is possible. */
|
||||||
continue;
|
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
|
* See if this file sits in the right place in the file system
|
||||||
* hierarchy. Its place may be wrong after a change to the
|
* hierarchy. Its place may be wrong after a change to the
|
||||||
* hash_queue_{names,depth} parameter settings. The implied
|
* hash_queue_{names,depth} parameter settings.
|
||||||
* 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.
|
|
||||||
*/
|
*/
|
||||||
if (action & ACTION_STRUCT) {
|
if (action & ACTION_STRUCT) {
|
||||||
(void) mail_queue_path(wanted_path, queue_name, path);
|
(void) mail_queue_path(wanted_path, queue_name, path);
|
||||||
if (strcmp(STR(actual_path), STR(wanted_path)) != 0) {
|
if (strcmp(STR(actual_path), STR(wanted_path)) != 0) {
|
||||||
if (rename(STR(actual_path), STR(wanted_path)) < 0)
|
position_mismatch++; /* before we fix */
|
||||||
if (errno != ENOENT
|
(void) postrename(STR(actual_path), STR(wanted_path));
|
||||||
|| mail_queue_mkdirs(STR(wanted_path)) < 0
|
/* At this point, path and actual_path are invalidated. */
|
||||||
|| rename(STR(actual_path), STR(wanted_path)) < 0)
|
continue;
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -497,27 +718,43 @@ static void super(char **queues, int action)
|
|||||||
argv_free(hash_queue_names);
|
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 main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
char *slash;
|
char *slash;
|
||||||
int debug_me = 0;
|
|
||||||
int action = 0;
|
int action = 0;
|
||||||
char **queues;
|
const char **queues;
|
||||||
int c;
|
int c;
|
||||||
int found = 0;
|
ARGV *requeue_names = 0;
|
||||||
|
ARGV *delete_names = 0;
|
||||||
|
char **cpp;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Defaults.
|
* Defaults.
|
||||||
*/
|
*/
|
||||||
static char *default_queues[] = {
|
static char *default_queues[] = {
|
||||||
|
MAIL_QUEUE_DEFER, /* before message directories */
|
||||||
|
MAIL_QUEUE_BOUNCE, /* before message directories */
|
||||||
MAIL_QUEUE_MAILDROP,
|
MAIL_QUEUE_MAILDROP,
|
||||||
MAIL_QUEUE_INCOMING,
|
MAIL_QUEUE_INCOMING,
|
||||||
MAIL_QUEUE_ACTIVE,
|
MAIL_QUEUE_ACTIVE,
|
||||||
MAIL_QUEUE_DEFERRED,
|
MAIL_QUEUE_DEFERRED,
|
||||||
MAIL_QUEUE_DEFER,
|
|
||||||
MAIL_QUEUE_BOUNCE,
|
|
||||||
MAIL_QUEUE_FLUSH,
|
MAIL_QUEUE_FLUSH,
|
||||||
0,
|
0,
|
||||||
};
|
};
|
||||||
@@ -544,8 +781,6 @@ int main(int argc, char **argv)
|
|||||||
*/
|
*/
|
||||||
if (safe_getenv(CONF_ENV_VERB))
|
if (safe_getenv(CONF_ENV_VERB))
|
||||||
msg_verbose = 1;
|
msg_verbose = 1;
|
||||||
if (safe_getenv(CONF_ENV_DEBUG))
|
|
||||||
debug_me = 1;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize. Set up logging, read the global configuration file and
|
* 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))
|
if (chdir(var_queue_dir))
|
||||||
msg_fatal("chdir %s: %m", 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
|
* All file/directory updates must be done as the mail system owner. This
|
||||||
* is because Postfix daemons manipulate the queue with those same
|
* is because Postfix daemons manipulate the queue with those same
|
||||||
@@ -579,30 +825,27 @@ int main(int argc, char **argv)
|
|||||||
/*
|
/*
|
||||||
* Parse JCL.
|
* Parse JCL.
|
||||||
*/
|
*/
|
||||||
while ((c = GETOPT(argc, argv, "d:spv")) > 0) {
|
while ((c = GETOPT(argc, argv, "d:pr:sv")) > 0) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
default:
|
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]);
|
argv[0]);
|
||||||
case 'd':
|
case 'd':
|
||||||
if (strcmp(optarg, "-") == 0)
|
if (delete_names == 0)
|
||||||
found |= operate_stream(VSTREAM_IN, delete_one);
|
delete_names = argv_alloc(1);
|
||||||
else
|
argv_add(delete_names, optarg, (char *) 0);
|
||||||
found |= delete_one(optarg);
|
action |= (strcmp(optarg, "ALL") == 0 ?
|
||||||
action |= ACTION_DELETE;
|
ACTION_DELETE_ALL : ACTION_DELETE_ONE);
|
||||||
break;
|
break;
|
||||||
case 'p':
|
case 'p':
|
||||||
action |= ACTION_PURGE;
|
action |= ACTION_PURGE;
|
||||||
break;
|
break;
|
||||||
case 'r':
|
case 'r':
|
||||||
if (strcmp(optarg, "-") == 0)
|
if (requeue_names == 0)
|
||||||
found |= operate_stream(VSTREAM_IN, requeue_one);
|
requeue_names = argv_alloc(1);
|
||||||
else
|
argv_add(requeue_names, optarg, (char *) 0);
|
||||||
found |= requeue_one(optarg);
|
action |= (strcmp(optarg, "ALL") == 0 ?
|
||||||
action |= ACTION_REQUEUE;
|
ACTION_REQUEUE_ALL : ACTION_REQUEUE_ONE);
|
||||||
break;
|
|
||||||
case 'R':
|
|
||||||
action |= ACTION_REQUEUE_ALL;
|
|
||||||
break;
|
break;
|
||||||
case 's':
|
case 's':
|
||||||
action |= ACTION_STRUCT;
|
action |= ACTION_STRUCT;
|
||||||
@@ -616,17 +859,94 @@ int main(int argc, char **argv)
|
|||||||
/*
|
/*
|
||||||
* Execute the explicitly specified (or default) action, on the
|
* Execute the explicitly specified (or default) action, on the
|
||||||
* explicitly specified (or default) queues.
|
* explicitly specified (or default) queues.
|
||||||
|
*
|
||||||
|
* XXX Work around gcc const brain damage.
|
||||||
*/
|
*/
|
||||||
if (action == 0)
|
if (action == 0)
|
||||||
action = ACTION_DEFAULT;
|
action = ACTION_DEFAULT;
|
||||||
if (argv[optind] == 0)
|
if (argv[optind] == 0)
|
||||||
queues = default_queues;
|
queues = (const char **) default_queues;
|
||||||
else
|
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);
|
* Basic queue maintenance, as well as mass deletion, mass requeuing, and
|
||||||
exit((action & ACTIONS_ON_THE_FLY) ? !found : 0);
|
* 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);
|
||||||
}
|
}
|
||||||
|
@@ -584,6 +584,8 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
|
|||||||
ldap_msgfree(res);
|
ldap_msgfree(res);
|
||||||
if (filter_buf != 0)
|
if (filter_buf != 0)
|
||||||
vstring_free(filter_buf);
|
vstring_free(filter_buf);
|
||||||
|
if (escaped_name != 0)
|
||||||
|
vstring_free(escaped_name);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we had an error, return nothing, Otherwise, return the result, if
|
* If we had an error, return nothing, Otherwise, return the result, if
|
||||||
|
Reference in New Issue
Block a user