[PATCH 07/17] Rework lock/pidfile. Make ui class var of OfflineImap
Sebastian Spaeth
Sebastian at SSpaeth.de
Mon Nov 29 16:02:15 GMT 2010
Remove lock and pid files after running offlineimap.
Make the ui a class variable of OfflineImap.
Use a different lock file than the 'original' offlineimap
The old offlineimap never ever deleted the lock file, so our new offlineimap fails thinking it is still being locked. Use a different lock file location. NEVER RUN the old and the new offlineimap at the same time now.
Signed-off-by: Sebastian Spaeth <Sebastian at SSpaeth.de>
---
offlineimap/init.py | 133 +++++++++++++++++++++++++++++----------------------
1 files changed, 76 insertions(+), 57 deletions(-)
diff --git a/offlineimap/init.py b/offlineimap/init.py
index 56667ce..70db2a2 100644
--- a/offlineimap/init.py
+++ b/offlineimap/init.py
@@ -29,30 +29,47 @@ from optparse import OptionParser
import signal
import logging
-try:
- import fcntl
- hasfcntl = 1
-except:
- hasfcntl = 0
-
-lockfd = None
class OfflineImap:
+ """Main class that is being run when invoking OfflineImap"""
+ ui = None
+ """class variable, holding the used ui"""
def __init__(self):
+ self._lockfile = None # lockfile path when locked
+ self._pidfile = None # pidfile path when locked
self.parse_commandline()
- def lock(self, config, ui):
- global lockfd, hasfcntl
- if not hasfcntl:
- return
- lockfd = open(config.getmetadatadir() + "/lock", "w")
+
+ def lock(self):
+ """Create lock file and exit if not possible"""
+ lockfile = os.path.join(self._config.getmetadatadir(), "locked")
try:
- fcntl.flock(lockfd, fcntl.LOCK_EX | fcntl.LOCK_NB)
- except IOError:
- ui.locked()
- ui.terminate(1)
-
+ lockfd = os.open( lockfile, os.O_CREAT|os.O_EXCL)
+ os.close(lockfd)
+ self._lockfile = lockfile
+ except OSError as e:
+ if e.errno == 17:
+ #File exists
+ OfflineImap.ui.locked()
+ OfflineImap.ui.terminate(1)
+
+ def unlock(self):
+ """Delete lockfile if existing."""
+ if self._lockfile:
+ os.unlink(self._lockfile)
+
+ def write_pidfile(self, pidfile):
+ """Write the current process pid into a pidfile"""
+ pidfd = open(pidfile, "aw")
+ pidfd.write(str(os.getpid()) + "\n")
+ pidfd.close()
+ self._pidfile = pidfile
+
+ def delete_pidfile(self):
+ """Delete the current pid pidfile if existing."""
+ os.unlink(self._pidfile)
+
def parse_commandline(self):
"""Parse the commandline and invoke everything"""
@@ -155,12 +172,12 @@ class OfflineImap:
#read in configuration file
configfilename = os.path.expanduser(options.configfile)
- config = ConfigParser()
+ self._config = ConfigParser()
if not os.path.exists(configfilename):
logging.error(" *** Config file '%s' does not exist; aborting!" %
configfilename)
sys.exit(1)
- config.read(configfilename)
+ self._config.read(configfilename)
#profile mode chosen?
if options.profiledir:
@@ -182,54 +199,58 @@ class OfflineImap:
section = secname.replace("_", " ")
else:
section = "general"
- config.set(section, key, value)
+ self._config.set(section, key, value)
#init the ui, and set up additional log files
- ui = offlineimap.ui.detector.findUI(config, options.interface)
- offlineimap.ui.UIBase.setglobalui(ui)
+ OfflineImap.ui = offlineimap.ui.detector.findUI(
+ self._config,
+ options.interface)
+ offlineimap.ui.UIBase.setglobalui(OfflineImap.ui)
if options.logfile:
- ui.setlogfd(open(options.logfile, 'wt'))
+ OfflineImap.ui.setlogfd(open(options.logfile, 'wt'))
#welcome blurb
- ui.init_banner()
+ OfflineImap.ui.init_banner()
+ #debugging active?
+ #FIXME: thread debugging currently dies!
if options.debugtype:
if options.debugtype.lower() == 'all':
options.debugtype = 'imap,maildir,thread'
for type in options.debugtype.split(','):
type = type.strip()
- ui.add_debug(type)
+ OfflineImap.ui.add_debug(type)
if type.lower() == 'imap':
imaplib.Debug = 5
if type.lower() == 'thread':
threading._VERBOSE = 1
if options.runonce:
- # FIXME: maybe need a better
- for section in accounts.getaccountlist(config):
- config.remove_option('Account ' + section, "autorefresh")
+ for section in accounts.getaccountlist(self._config):
+ self._config.remove_option('Account ' + section, "autorefresh")
if options.quick:
- for section in accounts.getaccountlist(config):
- config.set('Account ' + section, "quick", '-1')
+ for section in accounts.getaccountlist(self._config):
+ self._config.set('Account ' + section, "quick", '-1')
if options.folders:
foldernames = options.folders.replace(" ", "").split(",")
folderfilter = "lambda f: f in %s" % foldernames
folderincludes = "[]"
- for accountname in accounts.getaccountlist(config):
+ for accountname in accounts.getaccountlist(self._config):
account_section = 'Account ' + accountname
remote_repo_section = 'Repository ' + \
- config.get(account_section, 'remoterepository')
+ self._config.get(account_section, 'remoterepository')
local_repo_section = 'Repository ' + \
- config.get(account_section, 'localrepository')
+ self._config.get(account_section, 'localrepository')
for section in [remote_repo_section, local_repo_section]:
- config.set(section, "folderfilter", folderfilter)
- config.set(section, "folderincludes", folderincludes)
-
- self.lock(config, ui)
+ self._config.set(section, "folderfilter", folderfilter)
+ self._config.set(section, "folderincludes", folderincludes)
+ self.lock()
+ self.write_pidfile(
+ os.path.join(self._config.getmetadatadir(), "pid"))
def sigterm_handler(self, signum, frame):
# die immediately
@@ -237,28 +258,21 @@ class OfflineImap:
ui.terminate(errormsg="terminating...")
signal.signal(signal.SIGTERM,sigterm_handler)
-
- try:
- pidfd = open(config.getmetadatadir() + "/pid", "w")
- pidfd.write(str(os.getpid()) + "\n")
- pidfd.close()
- except:
- pass
-
+
try:
if options.logfile:
- sys.stderr = ui.logfile
+ sys.stderr = OfflineImap.ui.logfile
- socktimeout = config.getdefaultint("general", "socktimeout", 0)
+ socktimeout = self._config.getdefaultint("general", "socktimeout", 0)
if socktimeout > 0:
socket.setdefaulttimeout(socktimeout)
- activeaccounts = config.get("general", "accounts")
+ activeaccounts = self._config.get("general", "accounts")
if options.accounts:
activeaccounts = options.accounts
activeaccounts = activeaccounts.replace(" ", "")
activeaccounts = activeaccounts.split(",")
- allaccounts = accounts.AccountHashGenerator(config)
+ allaccounts = accounts.AccountHashGenerator(self._config)
syncaccounts = []
for account in activeaccounts:
@@ -269,7 +283,7 @@ class OfflineImap:
errormsg = 'The account "%s" does not exist. Valid accounts are:'%account
for name in allaccounts.keys():
errormsg += '\n%s'%name
- ui.terminate(1, errortitle = 'Unknown Account "%s"'%account, errormsg = errormsg)
+ OfflineImap.ui.terminate(1, errortitle = 'Unknown Account "%s"'%account, errormsg = errormsg)
if account not in syncaccounts:
syncaccounts.append(account)
@@ -281,17 +295,18 @@ class OfflineImap:
threadutil.initInstanceLimit("ACCOUNTLIMIT", 1)
else:
threadutil.initInstanceLimit("ACCOUNTLIMIT",
- config.getdefaultint("general", "maxsyncaccounts", 1))
+ self._config.getdefaultint("general", "maxsyncaccounts", 1))
- for reposname in config.getsectionlist('Repository'):
+ for reposname in self._config.getsectionlist('Repository'):
for instancename in ["FOLDER_" + reposname,
"MSGCOPY_" + reposname]:
if options.singlethreading:
threadutil.initInstanceLimit(instancename, 1)
else:
threadutil.initInstanceLimit(instancename,
- config.getdefaultint('Repository ' + reposname, "maxconnections", 1))
+ self._config.getdefaultint('Repository ' + reposname, "maxconnections", 1))
siglisteners = []
+
def sig_handler(signum, frame):
if signum == signal.SIGUSR1:
# tell each account to do a full sync asap
@@ -314,18 +329,22 @@ class OfflineImap:
t = ExitNotifyThread(target=syncmaster.syncitall,
name='Sync Runner',
kwargs = {'accounts': syncaccounts,
- 'config': config,
+ 'config': self._config,
'siglisteners': siglisteners})
t.setDaemon(1)
t.start()
except:
- ui.mainException()
+ OfflineImap.ui.mainException()
try:
threadutil.exitnotifymonitorloop(threadutil.threadexited)
except SystemExit:
raise
except:
- ui.mainException() # Also expected to terminate.
-
+ OfflineImap.ui.mainException() # Also expected to terminate.
+ finally:
+ # remove lockfile
+ # TODO: also remove on SIGTERM and SIGKILL
+ self.unlock()
+ self.delete_pidfile()
--
1.7.1
More information about the OfflineIMAP-project
mailing list