Solaar/lib/solaar/appinstance.py

68 lines
1.7 KiB
Python

#
#
#
from __future__ import absolute_import, division, print_function, unicode_literals
#
#
#
import fcntl as _fcntl
import os.path as _path
import os as _os
from solaar import NAME
_program = NAME.lower()
del NAME
from logging import getLogger, DEBUG as _DEBUG
_log = getLogger(__name__)
del getLogger
def check():
"""Select a file lock location and try to acquire it.
Suitable locations are $XDG_RUNTIME_DIR, /run/lock, /var/lock, and $TMPDIR.
The first one found and writable is used.
"""
# ensure no more than a single instance runs at a time
lock_fd = None
for p in _os.environ.get('XDG_RUNTIME_DIR'), '/run/lock', '/var/lock', _os.environ.get('TMPDIR', '/tmp'):
# pick the first temporary writable folder
if p and _path.isdir(p) and _os.access(p, _os.W_OK):
lock_path = _path.join(p, _program + '.single-instance.' + str(_os.getuid()))
try:
lock_fd = open(lock_path, 'wb')
if _log.isEnabledFor(_DEBUG):
_log.debug("single-instance lock file is %s", lock_path)
break
except:
pass
if lock_fd:
try:
_fcntl.flock(lock_fd, _fcntl.LOCK_EX | _fcntl.LOCK_NB)
if _log.isEnabledFor(_DEBUG):
_log.debug("acquired single-instance lock %s", lock_fd)
return lock_fd
except IOError as e:
if e.errno == 11:
_log.warn("lock file is busy, %s already running: %s", _program, e)
import sys
sys.exit(_program + ": error: already running")
else:
raise
else:
import sys
print (_program + ": warning: no suitable location for the lockfile found; ignoring", file=sys.stderr)
def close(lock_fd):
"""Release a file lock."""
if lock_fd:
_fcntl.flock(lock_fd, _fcntl.LOCK_UN)
lock_fd.close()
if _log.isEnabledFor(_DEBUG):
_log.debug("released single-instance lock %s", lock_fd)