csbackchk.py 7.13 KB
Newer Older
1
2
#!/usr/bin/env python
## @file csbackchk.py
3
# @brief Check checksums or rather integrity of corresponding files. 
4
5
6
7
8
# 
# -----------------------------------------------------------------------------
# 
# $Id$
# @author Daniel Armbruster
9
# \date 03/01/2012
10
# 
11
# Purpose: Check checksums or rather integrity of corresponding files.
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#
# ----
# This file is part of csback.
#
# csback 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 3 of the License, or
# (at your option) any later version.
# 
# csback 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 csback.  If not, see <http://www.gnu.org/licenses/>.
# ----
# 
30
# Copyright (c) 2012 by Daniel Armbruster
31
32
# 
# REVISIONS and CHANGES 
33
# 03/01/2012  V0.1  Daniel Armbruster
34
35
36
# 
# =============================================================================
 
37
38
39
40
41
42
import getopt
import os
import sys
import pwd
import logging
import csfile
43
import csbacklog
44

45
46
47
48
49
__version__ = "V0.1"
__subversion__ = "$Id$"
__license__ = "GPLv2"
__author__ = "Daniel Armbruster"
__copyright__ = "Copyright (c) 2012 by Daniel Armbruster"
50

51
52
53
# -----------------------------------------------------------------------------
class Error(Exception):

54
55
  def __init__(self, line, msg):
    self.line = str(line)
56
57
58
59
    self.msg = msg

  def display(self):
    sys.stderr.write("csbackchk (ERROR): " + self.msg + "\n")
60
    sys.stderr.write("triggered in line: " + self.line + "\n")
61
62
63
64
65
66
67
68
69


class Usage(Error):

  def display(self):
    usage_text = "Version: "+__version__+"\nLicense: "+__license__+ \
      "\n"+__subversion__+"\nAuthor: "+__author__+ """
 Usage: csbackchk [-v|--verbose] [-e REGEX [-e REGEX [...]]]
                  [-R|--notrecursive] [-d|--debug] [-f|--followlinks] 
70
                  [-t|--tolerant] [-l|--logging] [SOURCEPATH] PATH
71
    or: csbackchk -h|--help\n"""
72
    sys.stderr.write("csbackchk [line "+self.line+"]: "+self.msg+"\n")
73
74
75
76
77
78
79
80
81
82
83
    sys.stderr.write(usage_text)

# -----------------------------------------------------------------------------
def help():
  """
  Printing helptext to stdout.
  """
  help_text = "Version: "+__version__+"\nLicense: "+__license__+"\n"+ \
    __subversion__+"\nAuthor: "+__author__+"""
 Usage: csbackchk [-v|--verbose] [-e REGEX [-e REGEX [...]]]
                  [-R|--notrecursive] [-d|--debug] [-f|--followlinks]
84
                  [-t|--tolerant] [-l|--logging] [SOURCEPATH] PATH
85
86
87
88
    or: csbackchk -h|--help
-------------------------------------------------------------------------------
 -v|--verbose       Be verbose.
 -h|--help          Display this help.
Daniel Armbruster's avatar
Daniel Armbruster committed
89
90
 -e REGEX           While checking a checksumfile exclude files if their pathes
                    are matching REGEX(s).
91
92
93
94
95
96
97
98
99
 -R|--notrecursive  Do not search in subdirectories of PATH.
 -d|--debug         Debug mode. Be really verbose.
 -f|--followlinks   Follow symbolic links. Only available if option -R is not
                    set. Note that this option can lead to infinite recursion.
 -t|--tolerant      Be tolerant.
                    While checking don't report anything if a file listed in
                    the checksumfile is missing. This flag is useful if a test
                    of a directory is executed but this directory is realized
                    e.g. as a ring buffer.
100
101
 -l|--logging       Switch on logging to files. Logfiles will be located in
                    ~/.csback/log/.
102
 SOURCEPATH         Optional sourcepath for comparison with files backed up in
103
                    PATH. PATH must contain the csback checksumfile.
104
                    Note that the directory structure (if option '-R' is not
105
106
                    set) bellow SOURCEPATH should be equal to those in PATH
                    because otherwise the files can not be found.
107
108
109
110
111
                    If SOURCEPATH is not passed a check of files located in
                    PATH with its checksumfiles will be performed.
 PATH               Path to perform check for.
"""
  sys.stdout.write(help_text)
112
113

# -----------------------------------------------------------------------------
114
115
def main(argv=None):
  # configure logger
116
117
  logger = csbacklog.CsbackLog('csbackchk')
  
118
  console = logging.StreamHandler()
119
120
  console.setFormatter(logging.Formatter( \
    '%(name)-8s [%(lineno)d]: %(levelname)-8s %(message)s'))
121

122
  # fetch arguments
123
124
125
126
  if argv is None:
    argv = sys.argv
  try:
    try:
127
128
      opts, args = getopt.getopt(argv[1:], "vhe:Rdftl", ["help", "verbose", \
        "notrecursive", "debug", "followlinks", "tolerant", "logging"])
129
    except getopt.GetoptError as err:
130
      raise Usage(130,err.msg)
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
    verbose = False
    debugMode = False
    notRecursive = False
    followLinks = False
    beTolerant = False
    regexes = []
    # collect arguments
    for opt, arg in opts:
      if opt in ("-v", "--verbose"):
        verbose = True
        console.setLevel(logging.INFO)
      elif opt in ("-h", "--help"):
        sys.exit(help())
        return 0
      elif opt in ("-R", "--notrecursive"):
        notRecursive = True
      elif opt in ("-e"):
        regexes.append(arg)
      elif opt in ("-d", "--debug"):
        debugMode = True
        console.setLevel(logging.DEBUG)
      elif opt in ("-f", "--followlinks"):
        followLinks = True
      elif opt in ("-t", "--tolerant"):
        beTolerant = True
156
157
      elif opt in ("-l", "--logging"):
        logger.configure()
158
      else:
159
        raise Usage(159,"Unhandled option chosen.")
160
161

    if verbose or debugMode:
162
      logger.addHandler(console)
163
164
165
166
167
168
169
170

    if 1 == len(args):
      sourcepath = str(args[0]).rstrip(os.sep)+os.sep
      inputpath = sourcepath 
    elif 2 == len(args):
      sourcepath = str(args[0]).rstrip(os.sep)+os.sep 
      inputpath = str(args[1]).rstrip(os.sep)+os.sep 
    else:
171
      raise Usage(171,"Invalid argument(s).")
172
173

    # major part
174
    logger.getLogger().info("Start checking checksums ...")
175
    if not csfile.hasCsFile(inputpath):
176
      raise Error(175,"PATH does not contain a checksumfile.")
177
178
    
    if notRecursive:
179
180
      logger.getLogger().debug("Fetching subdirectories for regexes in %s", \
        inputpath)
181
      subdirs = csfile.getSubDirectories(inputpath, regexes, followLinks) 
Daniel Armbruster's avatar
Daniel Armbruster committed
182
      subdirs = [subdir+"*" for subdir in subdirs]
183
184
185
186
187
188
189
      regexes.extend(subdirs)

    checksumfile = csfile.CsFile(inputpath, sourcepath)
    checksumfile.read()
    checksumfile.check(regexes, beTolerant)
    checksumfile.write()

190
191
192
  except Usage as err:
    err.display()
    return 2
193
  except Error as err:
194
    logger.getLogger().error("message: %s [line %s]", err.msg, err.line)
195
196
    err.display()
    return 2
197
  except csfile.CsFileError as err:
198
    logger.getLogger().error("message: %s [line %s]", err.msg, err.line)
199
200
201
    err.display()
    return 2
  else:
202
    logger.getLogger().info("Checks performed.")
203
204
205
206
207
208
209
    return 0
    
# -----------------------------------------------------------------------------
if __name__ == "__main__":
  sys.exit(main())

# ----- END OF csbackchk.py -----