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 time
import urlparse
import errno
# From_ mangling regex.
from_re = re.compile(r'^From ', re.MULTILINE)
@ -410,21 +411,41 @@ class Mbox(mailbox.UnixMailbox):
def procmail_lock(self):
"""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
attempt = 0
while os.path.isfile(lock_name):
vprint("lockfile '%s' exists - sleeping..." % lock_name)
time.sleep(options.lockfile_sleep)
attempt = attempt + 1
if (attempt >= options.lockfile_attempts):
unexpected_error("Giving up waiting for procmail lock '%s'"
% lock_name)
vprint("writing lockfile '%s'" % lock_name)
old_umask = os.umask(022) # is this dodgy?
lock = open(lock_name, "w")
try:
while True:
attempt = attempt + 1
try:
os.link(prelock_name, lock_name)
# We've got the lock.
break
except OSError, e:
if os.fstat(plfd)[stat.ST_NLINK] == 2:
# 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
lock.close()
old_umask = os.umask(old_umask)
vprint("acquired lockfile '%s'" % lock_name)
def procmail_unlock(self):
"""Delete the procmail lockfile on the 'mbox' mailbox"""