Commit 5ea7432b authored by Daniel Armbruster's avatar Daniel Armbruster Committed by thomas.forbriger
Browse files

Working directory locking implemented. Not tested yet.

This is a legacy commit from before 2015-05-18.
It may be incomplete as well as inconsistent.
See COPYING.legacy and README.history for details.


SVN Path:     http://gpitrsvn.gpi.uni-karlsruhe.de/repos/TFSoftware/trunk
SVN Revision: 4388
SVN UUID:     67feda4a-a26e-11df-9d6e-31afc202ad0c
parent 600f5be1
...@@ -71,8 +71,7 @@ class Usage(Error): ...@@ -71,8 +71,7 @@ class Usage(Error):
"\n"+__subversion__+"\nAuthor: "+__author__+ """ "\n"+__subversion__+"\nAuthor: "+__author__+ """
Usage: csbackchk [-v|--verbose] [-e REGEX [-e REGEX [...]]] Usage: csbackchk [-v|--verbose] [-e REGEX [-e REGEX [...]]]
[-R|--notrecursive] [-d|--debug] [-f|--followlinks] [-R|--notrecursive] [-d|--debug] [-f|--followlinks]
[-t|--tolerant] [-l|--logging] [-a|--announce] [SOURCEPATH] [-t|--tolerant] [-l|--logging] [-L|--lock] [SOURCEPATH] PATH
PATH
or: csbackchk -h|--help\n""" or: csbackchk -h|--help\n"""
sys.stderr.write("csbackchk [line "+self.line+"]: "+self.msg+"\n") sys.stderr.write("csbackchk [line "+self.line+"]: "+self.msg+"\n")
sys.stderr.write(usage_text) sys.stderr.write(usage_text)
...@@ -86,8 +85,7 @@ def help(): ...@@ -86,8 +85,7 @@ def help():
__subversion__+"\nAuthor: "+__author__+""" __subversion__+"\nAuthor: "+__author__+"""
Usage: csbackchk [-v|--verbose] [-e REGEX [-e REGEX [...]]] Usage: csbackchk [-v|--verbose] [-e REGEX [-e REGEX [...]]]
[-R|--notrecursive] [-d|--debug] [-f|--followlinks] [-R|--notrecursive] [-d|--debug] [-f|--followlinks]
[-t|--tolerant] [-l|--logging] [-a|--announce] [SOURCEPATH] [-t|--tolerant] [-l|--logging] [-L|--lock] [SOURCEPATH] PATH
PATH
or: csbackchk -h|--help or: csbackchk -h|--help
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
-v|--verbose Be verbose. -v|--verbose Be verbose.
...@@ -105,10 +103,10 @@ def help(): ...@@ -105,10 +103,10 @@ def help():
e.g. as a ring buffer. e.g. as a ring buffer.
-l|--logging Switch on logging to files. Logfiles will be located in -l|--logging Switch on logging to files. Logfiles will be located in
~/.csback/log/. ~/.csback/log/.
-a|--announce Announce csbackchk to the csback pid lockfilehandler. This -L|--lock Lock the directories working at. This flag is useful in
flag is neccessary if several csback processes were run case csbackchk was run simultaneously with other csback
simultaneously and the '-l|--logging' option is enabled. processes working in the same directory. Setting this
Otherwise problems with the logging mechanism could option avoids checksumfile access problems which might
occur. occur.
SOURCEPATH Optional sourcepath for comparison with files backed up in SOURCEPATH Optional sourcepath for comparison with files backed up in
PATH. PATH and its subdirectories (if option '-R' had not PATH. PATH and its subdirectories (if option '-R' had not
...@@ -138,18 +136,18 @@ def main(argv=None): ...@@ -138,18 +136,18 @@ def main(argv=None):
argv = sys.argv argv = sys.argv
try: try:
try: try:
opts, args = getopt.getopt(argv[1:], "vhe:Rdftla", ["help", "verbose", \ opts, args = getopt.getopt(argv[1:], "vhe:RdftlL", ["help", "verbose", \
"notrecursive", "debug", "followlinks", "tolerant", "logging", \ "notrecursive", "debug", "followlinks", "tolerant", "logging", \
"announce"]) "lock"])
except getopt.GetoptError as err: except getopt.GetoptError as err:
raise Usage(145,err.msg) raise Usage(143,err.msg)
verbose = False verbose = False
debugMode = False debugMode = False
notRecursive = False notRecursive = False
followLinks = False followLinks = False
beTolerant = False beTolerant = False
regexes = [] regexes = []
pidAnnounce = False pidLock = False
# collect arguments # collect arguments
for opt, arg in opts: for opt, arg in opts:
if opt in ("-v", "--verbose"): if opt in ("-v", "--verbose"):
...@@ -171,10 +169,10 @@ def main(argv=None): ...@@ -171,10 +169,10 @@ def main(argv=None):
beTolerant = True beTolerant = True
elif opt in ("-l", "--logging"): elif opt in ("-l", "--logging"):
logger.configure() logger.configure()
elif opt in ("-a", "--announce"): elif opt in ("-L", "--lock"):
pidAnnounce = True pidLock = True
else: else:
raise Usage(177,"Unhandled option chosen.") raise Usage(175,"Unhandled option chosen.")
if verbose or debugMode: if verbose or debugMode:
logger.addHandler(console) logger.addHandler(console)
...@@ -191,12 +189,7 @@ def main(argv=None): ...@@ -191,12 +189,7 @@ def main(argv=None):
inputpath = str(args[1]).rstrip(os.sep)+os.sep inputpath = str(args[1]).rstrip(os.sep)+os.sep
inputDirs = [inputpath] inputDirs = [inputpath]
else: else:
raise Usage(194,"Invalid argument(s).") raise Usage(192,"Invalid argument(s).")
# announce to pidlock
if pidAnnounce:
pidhandler = pidlock.PidHandler()
pidhandler.announce(os.getpid())
# major part # major part
logger.getLogger().debug("Collecting subdirectories ...") logger.getLogger().debug("Collecting subdirectories ...")
...@@ -209,22 +202,29 @@ def main(argv=None): ...@@ -209,22 +202,29 @@ def main(argv=None):
csfile.getSubDirectories(inputpath, regexes, followLinks)) csfile.getSubDirectories(inputpath, regexes, followLinks))
if len(sourceDirs) != len(inputDirs): if len(sourceDirs) != len(inputDirs):
raise Error(212, \ raise Error(205, \
"Directory structure of inputpath and sourcepath different.") "Directory structure of inputpath and sourcepath different.")
if not csfile.hasCsFile(inputpath):
raise Error(216,"PATH does not contain a checksumfile.")
paths = list(zip(inputDirs, sourceDirs)) paths = list(zip(inputDirs, sourceDirs))
logger.getLogger().info("Start checking checksums ...") logger.getLogger().info("Start checking checksums ...")
for path in paths: for path in paths:
if not csfile.hasCsFile(path[0]):
raise Error(213,"PATH does not contain a checksumfile.")
lock = pidlock.PidLocker(path[0])
checksumfile = csfile.CsFile(path[0], path[1]) checksumfile = csfile.CsFile(path[0], path[1])
checksumfile.read() if lock.lockValid():
checksumfile.check(regexes, beTolerant) raise pidlock.PidLockError(-1, \
# remove from pidlock "Directory '{0}' locked.".format(path[0]))
if pidAnnounce: elif pidLock:
pidhandler.cancel(os.getpid()) lock.announce(os.getpid())
checksumfile.read()
checksumfile.check(regexes, beTolerant)
lock.cancel(os.getpid())
else:
checksumfile.read()
checksumfile.check(regexes, beTolerant)
except Usage as err: except Usage as err:
err.display() err.display()
return 2 return 2
......
...@@ -71,7 +71,7 @@ class Usage(Error): ...@@ -71,7 +71,7 @@ class Usage(Error):
Usage: csbackgen [-v|--verbose] [-e REGEX [-e REGEX [...]]] Usage: csbackgen [-v|--verbose] [-e REGEX [-e REGEX [...]]]
[-R|--notrecursive] [-d|--debug] [-f|--followlinks] [-R|--notrecursive] [-d|--debug] [-f|--followlinks]
[-t|--target DIR] [-l|--logging] [--hash ARG] [-t|--target DIR] [-l|--logging] [--hash ARG]
[-a|--announce] PATH [-L|--lock] PATH
or: csbackgen -h|--help\n""" or: csbackgen -h|--help\n"""
sys.stderr.write("csbackgen: " + self.msg + "\n") sys.stderr.write("csbackgen: " + self.msg + "\n")
sys.stderr.write(usage_text) sys.stderr.write(usage_text)
...@@ -86,7 +86,7 @@ def help(): ...@@ -86,7 +86,7 @@ def help():
Usage: csbackgen [-v|--verbose] [-e REGEX [-e REGEX [...]]] Usage: csbackgen [-v|--verbose] [-e REGEX [-e REGEX [...]]]
[-R|--notrecursive] [-d|--debug] [-f|--followlinks] [-R|--notrecursive] [-d|--debug] [-f|--followlinks]
[-t|--target ROOTDIR] [-l|--logging] [--hash ARG] [-t|--target ROOTDIR] [-l|--logging] [--hash ARG]
[-a|--announce] PATH [-L|--lock] PATH
or: csbackgen -h|--help or: csbackgen -h|--help
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
-v|--verbose Be verbose. -v|--verbose Be verbose.
...@@ -106,11 +106,11 @@ def help(): ...@@ -106,11 +106,11 @@ def help():
~/.csback/log/. ~/.csback/log/.
--hash ARG Set the hash function algorithm. Valid values are: --hash ARG Set the hash function algorithm. Valid values are:
sha224, sha256, sha384, sha512. (default: sha256) sha224, sha256, sha384, sha512. (default: sha256)
-a|--announce Announce csbackgen to the csback pid lockfilehandler. -L|--lock Lock the directories working at. This flag is useful in
This flag is neccessary if several csback processes were case csbackgen was run simultaneously with other csback
run simultaneously and the '-l|--logging' option is processes working in the same directory. Setting this
enabled. Otherwise problems with the logging mechanism option avoids checksumfile access problems which might
could occur. occur.
PATH Path to generate checksumfile(s) for including its PATH Path to generate checksumfile(s) for including its
subdirectories if option '-R' is not set. subdirectories if option '-R' is not set.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
...@@ -140,9 +140,9 @@ def main(argv=None): ...@@ -140,9 +140,9 @@ def main(argv=None):
argv = sys.argv argv = sys.argv
try: try:
try: try:
opts, args = getopt.getopt(argv[1:], "vhe:Rdft:la", ["help", "verbose", \ opts, args = getopt.getopt(argv[1:], "vhe:Rdft:lL", ["help", "verbose", \
"notrecursive", "debug", "followlinks", "target=", "logging", \ "notrecursive", "debug", "followlinks", "target=", "logging", \
"hash=", "announce"]) "hash=", "lock"])
except getopt.GetoptError as err: except getopt.GetoptError as err:
raise Usage(err.msg) raise Usage(err.msg)
verbose = False verbose = False
...@@ -153,7 +153,7 @@ def main(argv=None): ...@@ -153,7 +153,7 @@ def main(argv=None):
targetSet = False targetSet = False
enableLogging = False enableLogging = False
hashfunc = 'sha256' hashfunc = 'sha256'
pidAnnounce = False pidLock = False
for opt, arg in opts: for opt, arg in opts:
if opt in ("-v", "--verbose"): if opt in ("-v", "--verbose"):
verbose = True verbose = True
...@@ -179,8 +179,8 @@ def main(argv=None): ...@@ -179,8 +179,8 @@ def main(argv=None):
hashfunc = arg hashfunc = arg
else: else:
raise Usage("Invalid argument (hash).") raise Usage("Invalid argument (hash).")
elif opt in ("-a", "--announce"): elif opt in ("-L", "--lock"):
pidAnnounce = True pidLock = True
else: else:
raise Usage("Unhandled option chosen.") raise Usage("Unhandled option chosen.")
...@@ -195,9 +195,6 @@ def main(argv=None): ...@@ -195,9 +195,6 @@ def main(argv=None):
if not os.path.isdir(srcpath): if not os.path.isdir(srcpath):
raise Usage("PATH not a valid directory.") raise Usage("PATH not a valid directory.")
# announce to pidlock
if pidAnnounce:
pidhandler = pidlock.PidHandler()
pidhandler.announce(os.getpid()) pidhandler.announce(os.getpid())
# major part # major part
...@@ -225,17 +222,23 @@ def main(argv=None): ...@@ -225,17 +222,23 @@ def main(argv=None):
logger.getLogger().debug( \ logger.getLogger().debug( \
"Updating checksumfile in '{0}' with files from '{1}' ...".format( \ "Updating checksumfile in '{0}' with files from '{1}' ...".format( \
path[0], path[1])) path[0], path[1]))
csfile.CsFile(path[0], path[1], hashfunc=hashfunc).update(regexes) lock = pidlock.PidLocker(path[0])
checksumfile = csfile.CsFile(path[0], path[1], hashfunc=hashfunc)
if lock.lockValid():
raise pidlock.PidLockError(-1, \
"Directory '{0}' locked.".format(path[0]))
elif pidLock:
lock.announce(os.getpid())
checksumfile.update(regexes)
lock.cancel(os.getpid())
else:
checksumfile.update(regexes)
# remove from pidlock
if pidAnnounce:
pidhandler.cancel(os.getpid())
except Usage as err: except Usage as err:
err.display() err.display()
return 2 return 2
except pidlock.PidLockError as err: except pidlock.PidLockError as err:
logger.getLogger().error("{0}".format(err.msg)) logger.getLogger().critical("{0}".format(err.msg))
err.display() err.display()
return 2 return 2
except csfile.CsFileError as err: except csfile.CsFileError as err:
......
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
# 04/01/2012 V0.1.3 implemented a debug mode using the python logging module # 04/01/2012 V0.1.3 implemented a debug mode using the python logging module
# #
# ============================================================================= # =============================================================================
""" CsFile module to handle checksum files. """ """ CsFile module to handle checksumfiles. """
import os import os
import re import re
......
...@@ -37,12 +37,8 @@ Module to handle process IDs (pid) by using a lockfile mechanism. The module ...@@ -37,12 +37,8 @@ Module to handle process IDs (pid) by using a lockfile mechanism. The module
comes along with a PidHandler class. Additionally there is a Exception class comes along with a PidHandler class. Additionally there is a Exception class
PidLockError which might be caught while announcing a pid. PidLockError which might be caught while announcing a pid.
The path of the lockfile should be configured using the global variables. The name of the lockfile could be configured using the global variable
Default values are: lockfilename.
---
path = os.path.expanduser("~/.csback")
lockfilename = ".lock"
---
""" """
import os import os
...@@ -57,7 +53,7 @@ __copyright__ = "Copyright (c) 2012 by Daniel Armbruster" ...@@ -57,7 +53,7 @@ __copyright__ = "Copyright (c) 2012 by Daniel Armbruster"
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# variables # variables
path = os.path.expanduser("~/.csback")
lockfilename = ".lock" lockfilename = ".lock"
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
...@@ -71,10 +67,11 @@ class PidLockError(Exception): ...@@ -71,10 +67,11 @@ class PidLockError(Exception):
def display(self): def display(self):
sys.stderr.write("pidlock (ERROR): " + str(self.msg) + "\n") sys.stderr.write("pidlock (ERROR): " + str(self.msg) + "\n")
sys.stderr.write("triggered in line: " + str(self.line) + "\n") if -1 =! line:
sys.stderr.write("triggered in line: " + str(self.line) + "\n")
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
class PidHandler: class PidLocker:
""" """
Implements a handler for a pid. This handler uses a pidlockfile mechanism to Implements a handler for a pid. This handler uses a pidlockfile mechanism to
keep a log of the announced pids. Because of using a lockfile the handler keep a log of the announced pids. Because of using a lockfile the handler
...@@ -83,32 +80,25 @@ class PidHandler: ...@@ -83,32 +80,25 @@ class PidHandler:
Note that this handler does its work only on *nix platforms properly. Use Note that this handler does its work only on *nix platforms properly. Use
inheritance to overload the corresponding functions. inheritance to overload the corresponding functions.
""" """
def __init__(self): def __init__(self, directory):
self.path = os.path.join(path,lockfilename) self.path = os.path.join(directory,lockfilename)
self.notCanceled = True self.directory = directory
def announce(self, pid): def announce(self, pid):
""" """
Announce a process with pid to the handler. Announce a process with pid to the handler.
""" """
# create directories if not available
if not os.access(path, os.F_OK):
try:
os.makedirs(path, mode='0755')
except OSError:
pass
# remove file if pid not valid anymore # remove file if pid not valid anymore
if self.__access() and not self.__pidValid(): if not self.lockValid():
os.remove(self.path) os.remove(self.path)
# wait until pid is not valid anymore else:
while (self.__pidValid()): raise PidLockError(93, "Directory '{0}'locked.".format(self.directory))
pass
# create a new pidlockfile # create a new pidlockfile
try: try:
pidfile = open(self.path, 'w') pidfile = open(self.path, 'w')
pidfile.write("{0}".format(pid)) pidfile.write("{0}".format(pid))
except IOError as err: except IOError as err:
raise PidLockError(111, "[Errno "+str(err.errno)+"] "+err.strerror+": " \ raise PidLockError(100, "[Errno "+str(err.errno)+"] "+err.strerror+": " \
+err.filename) +err.filename)
else: else:
pidfile.close() pidfile.close()
...@@ -122,7 +112,7 @@ class PidHandler: ...@@ -122,7 +112,7 @@ class PidHandler:
if self.__getlockpid() == str(pid): if self.__getlockpid() == str(pid):
os.remove(self.path) os.remove(self.path)
def __pidValid(self): def lockValid(self):
""" """
Check if the process with the pid in the pid lockfile is still active. Check if the process with the pid in the pid lockfile is still active.
""" """
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment