source: trunk/third/sendmail/contrib/re-mqueue.pl @ 12554

Revision 12554, 7.7 KB checked in by danw, 26 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r12553, which included commits to RCS files with non-trunk default branches.
Line 
1#!/usr/bin/perl
2#
3# re-mqueue -- requeue messages from queueA to queueB based on age.
4#
5#       Contributed by Paul Pomes <ppomes@Qualcomm.COM>.
6#               http://www.qualcomm.com/~ppomes/
7#
8# Usage: re-mqueue [-d] queueA queueB seconds
9#
10#  -d           enable debugging
11#  queueA       source directory
12#  queueB       destination directory
13#  seconds      select files older than this number of seconds
14#
15# Example: re-mqueue /var/spool/mqueue /var/spool/mqueue2 2700
16#
17# Moves the qf* and df* files for a message from /var/spool/mqueue to
18# /var/spool/mqueue2 if the df* file is over 2700 seconds old.
19#
20# The qf* file can't be used for age checking as it's partially re-written
21# with the results of the last queue run.
22#
23# Rationale: With a limited number of sendmail processes allowed to run,
24# messages that can't be delivered immediately slow down the ones that can.
25# This becomes especially important when messages are being queued instead
26# of delivered right away, or when the queue becomes excessively deep.
27# By putting messages that have already failed one or more delivery attempts
28# into another queue, the primary queue can be kept small and fast.
29#
30# On postoffice.cso.uiuc.edu, the primary sendmail daemon runs the queue
31# every thirty minutes.  Messages over 45 minutues old are moved to
32# /var/spool/mqueue2 where sendmail runs every hour.  Messages more than
33# 3.25 hours old are moved to /var/spool/mqueue3 where sendmail runs every
34# four hours.  Messages more than a day old are moved to /var/spool/mqueue4
35# where sendmail runs three times a day.  The idea is that a message is
36# tried at least twice in the first three queues before being moved to the
37# old-age ghetto.
38#
39# (Each must be re-formed into a single line before using in crontab)
40#
41# 08 * * * *    /usr/local/libexec/re-mqueue /var/spool/mqueue ##                                               /var/spool/mqueue2 2700
42# 11 * * * *    /usr/lib/sendmail -oQ/var/spool/mqueue2 -q > ##                                                 > /var/log/mqueue2 2>&1
43# 38 * * * *    /usr/local/libexec/re-mqueue /var/spool/mqueue2
44#                                       /var/spool/mqueue3 11700
45# 41 1,5,9,13,17,21 * * * /usr/lib/sendmail -oQ/var/spool/mqueue3 -q ##                                                 > /var/log/mqueue3 2>&1
46# 48 * * * *    /usr/local/libexec/re-mqueue /var/spool/mqueue3
47#                                       /var/spool/mqueue4 100000
48#53 3,11,19 * * * /usr/lib/sendmail -oQ/var/spool/mqueue4 -q > ##                                                       > /var/log/mqueue4 2>&1
49#
50#
51# N.B., the moves are done with link().  This has two effects: 1) the mqueue*
52# directories must all be on the same filesystem, and 2) the file modification
53# times are not changed.  All times must be cumulative from when the df*
54# file was created.
55#
56# Copyright (c) 1995 University of Illinois Board of Trustees and Paul Pomes
57# All rights reserved.
58#
59# Redistribution and use in source and binary forms, with or without
60# modification, are permitted provided that the following conditions
61# are met:
62# 1. Redistributions of source code must retain the above copyright
63#    notice, this list of conditions and the following disclaimer.
64# 2. Redistributions in binary form must reproduce the above copyright
65#    notice, this list of conditions and the following disclaimer in the
66#    documentation and/or other materials provided with the distribution.
67# 3. All advertising materials mentioning features or use of this software
68#    must display the following acknowledgement:
69#       This product includes software developed by the University of
70#       Illinois at Urbana and their contributors.
71# 4. Neither the name of the University nor the names of their contributors
72#    may be used to endorse or promote products derived from this software
73#    without specific prior written permission.
74#
75# THIS SOFTWARE IS PROVIDED BY THE TRUSTEES AND CONTRIBUTORS ``AS IS'' AND
76# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
77# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
78# ARE DISCLAIMED.  IN NO EVENT SHALL THE TRUSTEES OR CONTRIBUTORS BE LIABLE
79# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
80# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
81# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
82# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
83# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
84# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
85# SUCH DAMAGE.
86#
87# @(#)$Id: re-mqueue.pl,v 1.1.1.1 1999-02-23 21:42:21 danw Exp $
88
89require "syslog.pl";
90
91$LOCK_EX = 2;
92$LOCK_NB = 4;
93$LOCK_UN = 8;
94
95# Count arguments, exit if wrong in any way.
96die "Usage: $0 [-d] queueA queueB seconds\n" if ($#ARGV < 2);
97
98while ($_ = $ARGV[0], /^-/) {
99    shift;
100    last if /^--$/;
101    /^-d/ && $debug++;
102}
103
104$queueA = shift;
105$queueB = shift;
106$age = shift;
107
108die "$0: $queueA not a directory\n" if (! -d $queueA);
109die "$0: $queueB not a directory\n" if (! -d $queueB);
110die "$0: $age isn't a valid number of seconds for age\n" if ($age =~ /\D/);
111
112# chdir to $queueA and read the directory.  When a df* file is found, stat it.
113# If it's older than $age, lock the corresponding qf* file.  If the lock
114# fails, give up and move on.  Once the lock is obtained, verify that files
115# of the same name *don't* already exist in $queueB and move on if they do.
116# Otherwise re-link the qf* and df* files into $queueB then release the lock.
117
118chdir "$queueA" || die "$0: can't cd to $queueA: $!\n";
119opendir (QA, ".") || die "$0: can't open directory $queueA for reading: $!\n";
120@dfiles = grep(/^df/, readdir(QA));
121$now = time();
122($program = $0) =~ s,.*/,,;
123&openlog($program, 'pid', 'mail');
124
125# Loop through the dfiles
126while ($dfile = pop(@dfiles)) {
127    print "Checking $dfile\n" if ($debug);
128    ($qfile = $dfile) =~ s/^d/q/;
129    ($mfile = $dfile) =~ s/^df//;
130    if (! -e $dfile || -z $dfile) {
131        print "$dfile is gone or zero bytes - skipping\n" if ($debug);
132        next;
133    }
134    if (! -e $qfile || -z $qfile) {
135        print "$qfile is gone or zero bytes - skipping\n" if ($debug);
136        next;
137    }
138
139    $mtime = $now;
140    ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
141     $atime,$mtime,$ctime,$blksize,$blocks) = stat($dfile);
142
143    # Compare timestamps
144    if (($mtime + $age) > $now) {
145        printf ("%s is %d seconds old - skipping\n", $dfile, $now-$mtime) if ($debug);
146        next;
147    }
148
149    # See if files of the same name already exist in $queueB
150    if (-e "$queueB/$dfile") {
151        print "$queueb/$dfile already exists - skipping\n" if ($debug);
152        next;
153    }
154    if (-e "$queueB/$qfile") {
155        print "$queueb/$qfile already exists - skipping\n" if ($debug);
156        next;
157    }
158
159    # Try and lock qf* file
160    unless (open(QF, ">>$qfile")) {
161        print "$qfile: $!\n" if ($debug);
162        next;
163    }
164    $retval = flock(QF, $LOCK_EX|$LOCK_NB) || ($retval = -1);
165    if ($retval == -1) {
166        print "$qfile already flock()ed - skipping\n" if ($debug);
167        close(QF);
168        next;
169    }
170    print "$qfile now flock()ed\n" if ($debug);
171
172    # Show time!  Do the link()s
173    if (link("$dfile", "$queueB/$dfile") == 0) {
174        &syslog('err', 'link(%s, %s/%s): %m', $dfile, $queueB, $dfile);
175        print STDERR "$0: link($dfile, $queueB/$dfile): $!\n";
176        exit (1);
177    }
178    if (link("$qfile", "$queueB/$qfile") == 0) {
179        &syslog('err', 'link(%s, %s/%s): %m', $qfile, $queueB, $qfile);
180        print STDERR "$0: link($qfile, $queueB/$qfile): $!\n";
181        unlink("$queueB/$dfile");
182        exit (1);
183    }
184
185    # Links created successfully.  Unlink the original files, release the
186    # lock, and close the file.
187    print "links ok\n" if ($debug);
188    if (unlink($qfile) == 0) {
189        &syslog('err', 'unlink(%s): %m', $qfile);
190        print STDERR "$0: unlink($qfile): $!\n";
191        exit (1);
192    }
193    if (unlink($dfile) == 0) {
194        &syslog('err', 'unlink(%s): %m', $dfile);
195        print STDERR "$0: unlink($dfile): $!\n";
196        exit (1);
197    }
198    flock(QF, $LOCK_UN);
199    close(QF);
200    &syslog('info', '%s moved to %s', $mfile, $queueB);
201    print "Done with $dfile $qfile\n\n" if ($debug);
202}
203exit 0;
Note: See TracBrowser for help on using the repository browser.