aboutsummaryrefslogtreecommitdiffstats
path: root/bin/check_db
blob: 40fa0a2774626f4e70141d0b2a0f687df4adf977 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#! @PYTHON@
#
# Copyright (C) 1998,1999,2000,2001,2002 by the Free Software Foundation, Inc.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

"""Check a list's config database file for integrity.

All of the following files are checked:

    config.pck
    config.pck.last
    config.db
    config.db.last
    config.safety

It's okay if any of these are missing.  config.pck and config.pck.last are
pickled versions of the config database file for 2.1a3 and beyond.  config.db
and config.db.last are used in all earlier versions, and these are Python
marshals.  config.safety is a pickle written by 2.1a3 and beyond when the
primary config.pck file could not be read.

Usage: %(PROGRAM)s [options] [listname [listname ...]]

Options:

    --all / -a
        Check the databases for all lists.  Otherwise only the lists named on
        the command line are checked.

    --verbose / -v
        Verbose output.  The state of every tested file is printed.
        Otherwise only corrupt files are displayed.

    --help / -h
        Print this text and exit.
"""

import sys
import os
import errno
import getopt
import marshal
import cPickle

import paths
from Mailman import mm_cfg
from Mailman import Utils
from Mailman.MailList import MailList
from Mailman.i18n import C_

PROGRAM = sys.argv[0]



def usage(code, msg=''):
    if code:
        fd = sys.stderr
    else:
        fd = sys.stdout
    print >> fd, C_(__doc__)
    if msg:
        print >> fd, msg
    sys.exit(code)



def testfile(dbfile):
    if dbfile.endswith('.db') or dbfile.endswith('.db.last'):
        loadfunc = marshal.load
    elif dbfile.endswith('.pck') or dbfile.endswith('.pck.last'):
        loadfunc = cPickle.load
    else:
        assert 0
    fp = open(dbfile)
    try:
        loadfunc(fp)
    finally:
        fp.close()


def main():
    try:
        opts, args = getopt.getopt(sys.argv[1:], 'ahv',
                                   ['all', 'verbose', 'help'])
    except getopt.error, msg:
        usage(1, msg)

    verbose = 0
    listnames = args

    for opt, arg in opts:
        if opt in ('-h', '--help'):
            usage(0)
        elif opt in ('-v', '--verbose'):
            verbose = 1
        elif opt in ('-a', '--all'):
            listnames = Utils.list_names()

    listnames = [n.lower().strip() for n in listnames]
    if not listnames:
        print C_('Nothing to do.')
        sys.exit(0)

    for listname in listnames:
        if not Utils.list_exists(listname):
            print C_('No list named:'), listname
            continue
        mlist = MailList(listname, lock=0)
        pfile = os.path.join(mlist.fullpath(), 'config.pck')
        plast = pfile + '.last'
        dfile = os.path.join(mlist.fullpath(), 'config.db')
        dlast = dfile + '.last'

        if verbose:
            print C_('List:'), listname

        for file in (pfile, plast, dfile, dlast):
            status = 0
            try:
                testfile(file)
            except IOError, e:
                # Don't report ENOENT unless we're in verbose mode
                if verbose or e.errno <> errno.ENOENT:
                    status = e
            except Exception, e:
                status = e
            # Report errors
            if status:
                if isinstance(status, EnvironmentError):
                    # This already includes the file name
                    print '   ', status
                else:
                    print '    %s: %s' % (file, status)
            elif verbose:
                print C_('   %(file)s: okay')



if __name__ == '__main__':
    main()