Rewrote Mbox.procmail_lock() to fix locking race condition. Should now also be

NFS-safe.
This commit is contained in:
Nikolaus Schulz 2006-10-30 19:29:15 +00:00
parent 700bce69b4
commit 697c22daac
1 changed files with 33 additions and 12 deletions

View File

@ -67,6 +67,7 @@ import string
import tempfile import tempfile
import time import time
import urlparse import urlparse
import errno
# From_ mangling regex. # From_ mangling regex.
from_re = re.compile(r'^From ', re.MULTILINE) from_re = re.compile(r'^From ', re.MULTILINE)
@ -410,21 +411,41 @@ class Mbox(mailbox.UnixMailbox):
def procmail_lock(self): def procmail_lock(self):
"""Create a procmail lockfile on the 'mbox' mailbox""" """Create a procmail lockfile on the 'mbox' mailbox"""
import socket
hostname = socket.gethostname()
pid = os.getpid()
box_dir, prelock_prefix = os.path.split(self.mbox_file_name)
prelock_suffix = ".%s.%s%s" % (hostname, pid, options.lockfile_extension)
plfd, prelock_name = tempfile.mkstemp(prelock_suffix, prelock_prefix,
dir=box_dir)
lock_name = self.mbox_file_name + options.lockfile_extension lock_name = self.mbox_file_name + options.lockfile_extension
attempt = 0 attempt = 0
while os.path.isfile(lock_name): try:
vprint("lockfile '%s' exists - sleeping..." % lock_name) while True:
time.sleep(options.lockfile_sleep) attempt = attempt + 1
attempt = attempt + 1 try:
if (attempt >= options.lockfile_attempts): os.link(prelock_name, lock_name)
unexpected_error("Giving up waiting for procmail lock '%s'" # We've got the lock.
% lock_name) break
vprint("writing lockfile '%s'" % lock_name) except OSError, e:
old_umask = os.umask(022) # is this dodgy? if os.fstat(plfd)[stat.ST_NLINK] == 2:
lock = open(lock_name, "w") # The Linux man page for open(2) claims that in this
# case we have actually succeeded to create the link,
# and this assumption seems to be folklore.
# So we've got the lock.
break
if e.errno != errno.EEXIST: raise
# Lockfile already existed, someone else has the lock.
if (attempt >= options.lockfile_attempts):
unexpected_error("Giving up waiting for "
"procmail lock '%s'" % lock_name)
vprint("lockfile '%s' exists - sleeping..." % lock_name)
time.sleep(options.lockfile_sleep)
finally:
os.close(plfd)
os.unlink(prelock_name)
_stale.procmail_lock = lock_name _stale.procmail_lock = lock_name
lock.close() vprint("acquired lockfile '%s'" % lock_name)
old_umask = os.umask(old_umask)
def procmail_unlock(self): def procmail_unlock(self):
"""Delete the procmail lockfile on the 'mbox' mailbox""" """Delete the procmail lockfile on the 'mbox' mailbox"""