1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
|
import os
import time
from ZeekControl import config
lockCount = 0
# Return: 0 if no lock, >0 for PID of lock, or -1 on error
def _break_lock(cmdout):
from ZeekControl import execute
try:
# Check whether lock is stale.
with open(config.Config.lockfile, "r") as f:
pid = f.readline().strip()
except (OSError, IOError) as err:
cmdout.error("failed to read lock file: %s" % err)
return -1
success, output = execute.run_localcmd("%s %s" % (os.path.join(config.Config.helperdir, "check-pid"), pid))
if success and output.strip() == "running":
# Process still exists.
try:
return int(pid)
except ValueError:
return -1
cmdout.info("removing stale lock")
try:
# Break lock.
os.unlink(config.Config.lockfile)
except (OSError, IOError) as err:
cmdout.error("failed to remove lock file: %s" % err)
return -1
return 0
# Return: 0 if lock is acquired, or if failed to acquire lock return >0 for
# PID of lock, or -1 on error
def _acquire_lock(cmdout):
lockpid = -1
pid = str(os.getpid())
tmpfile = config.Config.lockfile + "." + pid
lockdir = os.path.dirname(config.Config.lockfile)
if not os.path.exists(lockdir):
cmdout.info("creating directory for lock file: %s" % lockdir)
os.makedirs(lockdir)
try:
try:
# This should be NFS-safe.
with open(tmpfile, "w") as f:
f.write("%s\n" % pid)
n = os.stat(tmpfile)[3]
os.link(tmpfile, config.Config.lockfile)
m = os.stat(tmpfile)[3]
if n == m-1:
return 0
# File is locked.
lockpid = _break_lock(cmdout)
if lockpid == 0:
return _acquire_lock(cmdout)
except OSError:
# File is already locked.
lockpid = _break_lock(cmdout)
if lockpid == 0:
return _acquire_lock(cmdout)
except IOError as e:
cmdout.error("cannot acquire lock: %s" % e)
return lockpid
finally:
try:
os.unlink(tmpfile)
except (OSError, IOError):
pass
return lockpid
def _release_lock(cmdout):
try:
os.unlink(config.Config.lockfile)
except OSError as e:
cmdout.error("cannot remove lock file: %s" % e)
def lock(cmdout, showwait=True):
global lockCount
if lockCount > 0:
# Already locked.
lockCount += 1
return True
lockpid = _acquire_lock(cmdout)
if lockpid < 0:
return False
if lockpid:
if showwait:
cmdout.info("waiting for lock (owned by PID %d) ..." % lockpid)
count = 0
while _acquire_lock(cmdout) != 0:
time.sleep(1)
count += 1
if count > 30:
return False
lockCount = 1
return True
def unlock(cmdout):
global lockCount
if lockCount == 0:
cmdout.error("mismatched lock/unlock")
return
if lockCount > 1:
# Still locked.
lockCount -= 1
return
_release_lock(cmdout)
lockCount = 0
|