queue-repair

February 6, 2020 by Roberto Puzzanghera 3 comments

A toolkit for dealing with the qmail queue directory structure; it can create a new queue, move and properly rename a queue, dynamically change the conf-split value, convert big-todo queues to non-big-todo and vice versa, and repair a corrupted queue.

In case you damage the qmail queue by accident, you will say thanks to this software! But I wish you will never have to use it :-)

If you followed the 'quick configuration' based on the config-all script, qmHandle has been installed for you. If it wasn't like that, download, patch and install as follows. The patch applied (tx Tony Fung) will get the program python3 compliant.

wget http://pyropus.ca/software/queue-repair/queue-repair-0.9.0.tar.gz
tar xzf queue-repair-0.9.0.tar.gz
cd queue-repair-0.9.0
chown -R root:root .
wget https://notes.sagredo.eu/files/qmail/patches/queue_repair.patch
patch < queue_repair.patch
cp queue_repair.py /usr/local/bin/queue-repair

Usage

Don't forget to stop qmail before using.

# qmailctl stop
# queue_repair --help

queue_repair.py v. 0.9.0
Copyright (C) 2001 Charles Cazabon 
Licensed under the GNU General Public License version 2


Usage:  queue_repair.py [options] [conf-qmail]

Options:
  conf-qmail                    (default:  /var/qmail)
  -t   or --test                Test only; do not modify the filesystem
  -r   or --repair              Repair errors found        (default: test)
  -b   or --bigtodo             Force use of big-todo      (default: auto)
  -n   or --no-bigtodo          Force non-use of big-todo  (default: auto)
  -s N or --split N             Force conf-split of N      (default: auto)
  -c   or --create              Force creation of queue    (default: no)
  --i-want-a-broken-conf-split  Force non-prime conf-split (default: no)
  -h   or --help                This text

Comments

queue-repair run by Python 3

Hi Roberto,Since Python 2 shall be retired by April 2020 and the original queue-repair cannot run by Python 3.  I created a patch to make it works and tested to run by Python 3.6.8 on CentOS 8 successfully.  Hope the patch is helpful.

--- queue_repair.py 2003-10-22 23:54:13.000000000 +0800
+++ queue_repair.py.new 2020-01-17 18:21:18.834455813 +0800
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/bin/python3
 '''queue_repair.py - qmail tools in Python.
 Copyright (C) 2001 Charles Cazabon
 
@@ -66,24 +66,24 @@
     #   key: pathname - all paths are relative to conf-qmail
     #   data: (user, group, mode, split)
     #       split is:  0 : no, 1 : yes, -1 : only with big-todo
-    'queue' :           ('qmailq', 'qmail', 0750, 0),
-    'queue/bounce' :    ('qmails', 'qmail', 0700, 0),
-    'queue/info' :      ('qmails', 'qmail', 0700, 1),
-    'queue/intd' :      ('qmailq', 'qmail', 0700, -1),
-    'queue/local' :     ('qmails', 'qmail', 0700, 1),
-    'queue/lock' :      ('qmailq', 'qmail', 0750, 0),
-    'queue/mess' :      ('qmailq', 'qmail', 0750, 1),
-    'queue/pid' :       ('qmailq', 'qmail', 0700, 0),
-    'queue/remote' :    ('qmails', 'qmail', 0700, 1),
-    'queue/todo' :      ('qmailq', 'qmail', 0750, -1),
+    'queue' :           ('qmailq', 'qmail', 0o750, 0),
+    'queue/bounce' :    ('qmails', 'qmail', 0o700, 0),
+    'queue/info' :      ('qmails', 'qmail', 0o700, 1),
+    'queue/intd' :      ('qmailq', 'qmail', 0o700, -1),
+    'queue/local' :     ('qmails', 'qmail', 0o700, 1),
+    'queue/lock' :      ('qmailq', 'qmail', 0o750, 0),
+    'queue/mess' :      ('qmailq', 'qmail', 0o750, 1),
+    'queue/pid' :       ('qmailq', 'qmail', 0o700, 0),
+    'queue/remote' :    ('qmails', 'qmail', 0o700, 1),
+    'queue/todo' :      ('qmailq', 'qmail', 0o750, -1),
 }
 
 nondirs = {
     # Files to check; format is:
     #   key: pathname - all paths are relative to conf-qmail
     #   data: (user, group, mode)
-    'queue/lock/sendmutex' :    ('qmails', 'qmail', 0600),
-    'queue/lock/tcpto' :        ('qmailr', 'qmail', 0644),
+    'queue/lock/sendmutex' :    ('qmails', 'qmail', 0o600),
+    'queue/lock/tcpto' :        ('qmailr', 'qmail', 0o644),
 }
 
 
@@ -105,7 +105,7 @@
     while i <= max:
         for p in primelist:
             if (i % p == 0) or (p * p > i): break
-        if (i % p <> 0):
+        if (i % p != 0):
             primelist.append(i)
             if i >= min:
                 result.append(i)
@@ -151,8 +151,8 @@
     '''
     global users, groups
     msg('finding qmail UIDs/GIDs...')
-    us = users.keys()
-    gs = groups.keys()
+    us = list(users.keys())
+    gs = list(groups.keys())
     for u in us:
         if users[u]:
             # Handle case of someone else determining UIDs for us
@@ -182,7 +182,7 @@
     that it has octal mode mode.  If testmode is set, create path if it
     doesn't exist.
     '''
-    if checked_dir.has_key(path):
+    if path in checked_dir:
         return
     msg('  checking directory %s...' % path)
     if not os.path.exists(path):
@@ -208,7 +208,7 @@
 
     Verify path is owned by user:group, and make it so if testmode is not set.
     '''
-    if checked_owner.has_key(path):
+    if path in checked_owner:
         return
     uid = users[user]
     gid = groups[group]
@@ -223,7 +223,7 @@
                 msg('  fixed, %s ownership %i:%i' % (path, s[ST_UID], s[ST_GID]))
             else:
                 msg('  testmode, not fixing')
-    except OSError, o:
+    except OSError as o:
         err(o or '[no error message]')
     checked_owner[path] = None
 
@@ -233,7 +233,7 @@
 
     Verify path has mode mode, and make it so if testmode is not set.
     '''
-    if checked_mode.has_key(path):
+    if path in checked_mode:
         return
     try:
         s = os.stat(path)
@@ -247,7 +247,7 @@
                 msg('  changed %s mode to %o' % (path, newmode))
             else:
                 msg('  testmode, not fixing')
-    except OSError, o:
+    except OSError as o:
         err(o or '[no error message]')
     checked_mode[path] = None
 
@@ -259,7 +259,7 @@
     '''
     splits = []
     msg('determining conf-split...')
-    for (path, (user, group, mode, is_split)) in dirs.items():
+    for (path, (user, group, mode, is_split)) in list(dirs.items()):
         if is_split != 1:
             continue
         highest = 0
@@ -311,7 +311,7 @@
         else:
             msg('  found unexpected direntry %s' % p)
 
-    if splits == range(split):
+    if splits == list(range(split)):
         # big-todo apparently in use
         bigtodo = 1
         msg('  big-todo found')
@@ -330,14 +330,14 @@
     Verify ownership, mode, and contents of each queue directory in paths.
     '''
     msg('checking main queue directories...')
-    _dirs = paths.keys()
+    _dirs = list(paths.keys())
     _dirs.sort()
     for path in _dirs:
         (user, group, mode, is_split) = paths[path]
         check_dir(path, user, group, mode)
 
     msg('checking split sub-directories...')
-    for (path, (user, group, mode, is_split)) in paths.items():
+    for (path, (user, group, mode, is_split)) in list(paths.items()):
         if path in ('queue', 'queue/lock'):
             # Nothing in these directories to check at this point
             continue
@@ -345,7 +345,7 @@
         if not this_split:
             splits = []
         else:
-            splits = range(split)
+            splits = list(range(split))
             for i in splits:
                 splitpath = os.path.join(path, str(i))
                 check_dir(splitpath, user, group, mode)
@@ -428,7 +428,7 @@
     Verify ownership and mode of each queue file in paths.
     '''
     msg('checking files...')
-    for (path, (user, group, mode)) in paths.items():
+    for (path, (user, group, mode)) in list(paths.items()):
         if os.path.exists(path):
             if not os.path.isfile(path):
                 msg('  %s is not a file' % path)
@@ -467,7 +467,7 @@
     if not os.path.exists(path) and not testmode:
         os.mkfifo(path)
     chown(path, user, group)
-    chmod(path, 0622)
+    chmod(path, 0o622)
 
 #######################################
 def check_messages(path, split):
@@ -516,7 +516,7 @@
     check_messages().  Correct split sub-directory location as well.
     '''
     msg('fixing misnamed messages...')
-    for (path, (user, junk, junk, is_split)) in paths.items():
+    for (path, (user, junk, junk, is_split)) in list(paths.items()):
         for (oldhash, oldno, newno) in misnamed:
             if not is_splitdir(is_split, bigtodo):
                 old_p = os.path.join(path, str(oldno))
@@ -544,17 +544,17 @@
     of all files found.
     '''
     msg('checking split locations...')
-    for (path, (user, group, junk, is_split)) in paths.items():
+    for (path, (user, group, junk, is_split)) in list(paths.items()):
         if path in ('queue', 'queue/lock'):
             # Nothing in these directories to check at this point
             continue
         elif path in ('queue/mess', 'queue/todo'):
-            mode = 0644
+            mode = 0o644
         else:
-            mode = 0600
+            mode = 0o600
         this_split = is_splitdir(is_split, bigtodo)
         if this_split:
-            splits = range(split)
+            splits = list(range(split))
         else:
             splits = ['']
         for splitval in splits:
@@ -635,7 +635,7 @@
     wd = os.getcwd()
     try:
         os.chdir(qmaildir)
-    except StandardError:
+    except Exception:
         err('failed to chdir to %s' % qmaildir)
 
     if testmode:
@@ -747,7 +747,7 @@
                     if force_split < 1:
                         raise ValueError
                 except ValueError:
-                    raise getopt.error, 'split value must be a positive integer (%s)' % value
+                    raise getopt.error('split value must be a positive integer (%s)' % value)
             elif option in ('-n', '--no-bigtodo'):
                 force_bigtodo = -1
             elif option in ('-b', '--bigtodo'):
@@ -765,10 +765,10 @@
                 create = 1
         if args:
             if len(args) > 1:
-                raise getopt.error, 'conf-qmail must be a single argument (%s)' % string.join(args)
+                raise getopt.error('conf-qmail must be a single argument (%s)' % string.join(args))
             qmaildir = args[0]
 
-    except getopt.error, o:
+    except getopt.error as o:
         err('Error:  %s' % o, showhelp=1)
 
     check_queue(qmaildir, test, force_split, force_bigtodo, create, mathishard)
@@ -776,3 +776,4 @@
 #######################################
 if __name__ == '__main__':
     main()
+

 

Reply |

queue-repair run by Python 3

It seems to work with both v.2 and v.3 of python. Applied! Thank you.

Reply |

queue-repair run by Python 3

Thank you. Very much appreciated. I'll check it out

Reply |

Recent comments
Recent posts

RSS feeds