summaryrefslogtreecommitdiff
path: root/src/leap/platform_init
diff options
context:
space:
mode:
authorKali Kaneko <kali@leap.se>2013-08-12 13:25:44 +0200
committerKali Kaneko <kali@leap.se>2013-08-12 13:25:44 +0200
commit6da8d09846db4d2eed01e488bc6a6f5ba48b959f (patch)
tree3b82e8c4e14b1730ff292b6eb632c145dafb332a /src/leap/platform_init
parent00d98a47c60764475d97df1c2eb847e20a77cae5 (diff)
move everything into bitmask namespace
Diffstat (limited to 'src/leap/platform_init')
-rw-r--r--src/leap/platform_init/__init__.py28
-rw-r--r--src/leap/platform_init/initializers.py409
-rw-r--r--src/leap/platform_init/locks.py405
3 files changed, 0 insertions, 842 deletions
diff --git a/src/leap/platform_init/__init__.py b/src/leap/platform_init/__init__.py
deleted file mode 100644
index 2a262a30..00000000
--- a/src/leap/platform_init/__init__.py
+++ /dev/null
@@ -1,28 +0,0 @@
-# -*- coding: utf-8 -*-
-# __init__.py
-# Copyright (C) 2013 LEAP
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-"""
-System constants
-"""
-import platform
-
-_system = platform.system()
-
-IS_WIN = True if _system == "Windows" else False
-IS_MAC = True if _system == "Darwin" else False
-IS_LINUX = True if _system == "Linux" else False
-IS_UNIX = IS_MAC or IS_LINUX
diff --git a/src/leap/platform_init/initializers.py b/src/leap/platform_init/initializers.py
deleted file mode 100644
index 46488250..00000000
--- a/src/leap/platform_init/initializers.py
+++ /dev/null
@@ -1,409 +0,0 @@
-# -*- coding: utf-8 -*-
-# initializers.py
-# Copyright (C) 2013 LEAP
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-"""
-Platform dependant initializing code
-"""
-
-import logging
-import os
-import platform
-import stat
-import subprocess
-import tempfile
-
-from PySide import QtGui
-
-from leap.config.leapsettings import LeapSettings
-from leap.services.eip import vpnlaunchers
-from leap.util import first
-from leap.util import privilege_policies
-
-
-logger = logging.getLogger(__name__)
-
-# NOTE we could use a deferToThread here, but should
-# be aware of this bug: http://www.themacaque.com/?p=1067
-
-__all__ = ["init_platform"]
-
-_system = platform.system()
-
-
-def init_platform():
- """
- Returns the right initializer for the platform we are running in, or
- None if no proper initializer is found
- """
- initializer = None
- try:
- initializer = globals()[_system + "Initializer"]
- except:
- pass
- if initializer:
- logger.debug("Running initializer for %s" % (platform.system(),))
- initializer()
- else:
- logger.debug("Initializer not found for %s" % (platform.system(),))
-
-
-#
-# common utils
-#
-
-NOTFOUND_MSG = ("Tried to install %s, but %s "
- "not found inside this bundle.")
-BADEXEC_MSG = ("Tried to install %s, but %s "
- "failed to %s.")
-
-UPDOWN_NOTFOUND_MSG = NOTFOUND_MSG % (
- "updown scripts", "those were")
-UPDOWN_BADEXEC_MSG = BADEXEC_MSG % (
- "updown scripts", "they", "be copied")
-
-
-def get_missing_updown_dialog():
- """
- Creates a dialog for notifying of missing updown scripts.
- Returns that dialog.
-
- :rtype: QtGui.QMessageBox instance
- """
- WE_NEED_POWERS = ("To better protect your privacy, "
- "Bitmask needs administrative privileges "
- "to install helper files. "
- "Do you want to proceed?")
- msg = QtGui.QMessageBox()
- msg.setWindowTitle(msg.tr("Missing up/down scripts"))
- msg.setText(msg.tr(WE_NEED_POWERS))
- # but maybe the user really deserve to know more
- #msg.setInformativeText(msg.tr(BECAUSE))
- msg.setStandardButtons(QtGui.QMessageBox.Yes | QtGui.QMessageBox.No)
- msg.addButton("No, don't ask again", QtGui.QMessageBox.RejectRole)
- msg.setDefaultButton(QtGui.QMessageBox.Yes)
- return msg
-
-
-def check_missing():
- """
- Checks for the need of installing missing scripts, and
- raises a dialog to ask user for permission to do it.
- """
- config = LeapSettings()
- alert_missing = config.get_alert_missing_scripts()
-
- launcher = vpnlaunchers.get_platform_launcher()
- missing_scripts = launcher.missing_updown_scripts
- missing_other = launcher.missing_other_files
-
- if alert_missing and (missing_scripts() or missing_other()):
- msg = get_missing_updown_dialog()
- ret = msg.exec_()
-
- if ret == QtGui.QMessageBox.Yes:
- install_missing_fun = globals().get(
- "_%s_install_missing_scripts" % (_system.lower(),),
- None)
- if not install_missing_fun:
- logger.warning(
- "Installer not found for platform %s." % (_system,))
- return
-
- # XXX maybe move constants to fun
- ok = install_missing_fun(UPDOWN_BADEXEC_MSG, UPDOWN_NOTFOUND_MSG)
- if not ok:
- msg = QtGui.QMessageBox()
- msg.setWindowTitle(msg.tr("Problem installing files"))
- msg.setText(msg.tr('Some of the files could not be copied.'))
- msg.setIcon(QtGui.QMessageBox.Warning)
- msg.exec_()
-
- elif ret == QtGui.QMessageBox.No:
- logger.debug("Not installing missing scripts, "
- "user decided to ignore our warning.")
-
- elif ret == QtGui.QMessageBox.Rejected:
- logger.debug(
- "Setting alert_missing_scripts to False, we will not "
- "ask again")
- config.set_alert_missing_scripts(False)
-#
-# windows initializers
-#
-
-
-def _windows_has_tap_device():
- """
- Loops over the windows registry trying to find if the tap0901 tap driver
- has been installed on this machine.
- """
- import _winreg as reg
-
- adapter_key = 'SYSTEM\CurrentControlSet\Control\Class' \
- '\{4D36E972-E325-11CE-BFC1-08002BE10318}'
- with reg.OpenKey(reg.HKEY_LOCAL_MACHINE, adapter_key) as adapters:
- try:
- for i in xrange(10000):
- key_name = reg.EnumKey(adapters, i)
- with reg.OpenKey(adapters, key_name) as adapter:
- try:
- component_id = reg.QueryValueEx(adapter,
- 'ComponentId')[0]
- if component_id.startswith("tap0901"):
- return True
- except WindowsError:
- pass
- except WindowsError:
- pass
- return False
-
-
-def WindowsInitializer():
- """
- Raises a dialog in case that the windows tap driver has not been found
- in the registry, asking the user for permission to install the driver
- """
- if not _windows_has_tap_device():
- msg = QtGui.QMessageBox()
- msg.setWindowTitle(msg.tr("TAP Driver"))
- msg.setText(msg.tr("Bitmask needs to install the necessary drivers "
- "for Encrypted Internet to work. Would you like to "
- "proceed?"))
- msg.setInformativeText(msg.tr("Encrypted Internet uses VPN, which "
- "needs a TAP device installed and none "
- "has been found. This will ask for "
- "administrative privileges."))
- msg.setStandardButtons(QtGui.QMessageBox.Yes | QtGui.QMessageBox.No)
- msg.setDefaultButton(QtGui.QMessageBox.Yes)
- ret = msg.exec_()
-
- if ret == QtGui.QMessageBox.Yes:
- # XXX should do this only if executed inside bundle.
- # Let's assume it's the only way it's gonna be executed under win
- # by now.
- driver_path = os.path.join(os.getcwd(),
- "apps",
- "eip",
- "tap_driver")
- dev_installer = os.path.join(driver_path,
- "devcon.exe")
- if os.path.isfile(dev_installer) and \
- stat.S_IXUSR & os.stat(dev_installer)[stat.ST_MODE] != 0:
- inf_path = os.path.join(driver_path,
- "OemWin2k.inf")
- cmd = [dev_installer, "install", inf_path, "tap0901"]
- ret = subprocess.call(cmd, stdout=subprocess.PIPE, shell=True)
- else:
- logger.error("Tried to install TAP driver, but the installer "
- "is not found or not executable")
-
-#
-# Darwin initializer functions
-#
-
-
-def _darwin_has_tun_kext():
- """
- Returns True only if we found a directory under the system kext folder
- containing a kext named tun.kext, AND we found a startup item named 'tun'
- """
- # XXX we should be smarter here and use kextstats output.
-
- has_kext = os.path.isdir("/System/Library/Extensions/tun.kext")
- has_startup = os.path.isdir("/System/Library/StartupItems/tun")
- has_tun_and_startup = has_kext and has_startup
- logger.debug(
- 'platform initializer check: has tun_and_startup = %s' %
- (has_tun_and_startup,))
- return has_tun_and_startup
-
-
-def _darwin_install_missing_scripts(badexec, notfound):
- """
- Tries to install the missing up/down scripts.
-
- :param badexec: error for notifying execution error during command.
- :type badexec: str
- :param notfound: error for notifying missing path.
- :type notfound: str
- :returns: True if the files could be copied successfully.
- :rtype: bool
- """
- # We expect to execute this from some way of bundle, since
- # the up/down scripts should be put in place by the installer.
- success = False
- installer_path = os.path.join(
- os.getcwd(),
- "..",
- "Resources",
- "openvpn")
- launcher = vpnlaunchers.DarwinVPNLauncher
-
- if os.path.isdir(installer_path):
- fd, tempscript = tempfile.mkstemp(prefix="leap_installer-")
- try:
- scriptlines = launcher.cmd_for_missing_scripts(installer_path)
- with os.fdopen(fd, 'w') as f:
- f.write(scriptlines)
- st = os.stat(tempscript)
- os.chmod(tempscript, st.st_mode | stat.S_IEXEC | stat.S_IXUSR |
- stat.S_IXGRP | stat.S_IXOTH)
-
- cmd, args = launcher().get_cocoasudo_installmissing_cmd()
- args.append(tempscript)
- cmdline = " ".join([cmd] + args)
- ret = subprocess.call(
- cmdline, stdout=subprocess.PIPE,
- shell=True)
- success = ret == 0
- if not success:
- logger.error("Install missing scripts failed.")
- except Exception as exc:
- logger.error(badexec)
- logger.error("Error was: %r" % (exc,))
- finally:
- try:
- os.remove(tempscript)
- except OSError as exc:
- logger.error("%r" % (exc,))
- else:
- logger.error(notfound)
- logger.debug('path searched: %s' % (installer_path,))
-
- return success
-
-
-def DarwinInitializer():
- """
- Raises a dialog in case that the osx tuntap driver has not been found
- in the registry, asking the user for permission to install the driver
- """
- # XXX split this function into several
-
- TUNTAP_NOTFOUND_MSG = NOTFOUND_MSG % (
- "tuntaposx kext", "the installer")
- TUNTAP_BADEXEC_MSG = BADEXEC_MSG % (
- "tuntaposx kext", "the installer", "be launched")
-
- # TODO DRY this with other cases, and
- # factor out to _should_install() function.
- # Leave the dialog as a more generic thing.
-
- if not _darwin_has_tun_kext():
- msg = QtGui.QMessageBox()
- msg.setWindowTitle(msg.tr("TUN Driver"))
- msg.setText(msg.tr("Bitmask needs to install the necessary drivers "
- "for Encrypted Internet to work. Would you like to "
- "proceed?"))
- msg.setInformativeText(msg.tr("Encrypted Internet uses VPN, which "
- "needs a kernel extension for a TUN "
- "device installed, and none "
- "has been found. This will ask for "
- "administrative privileges."))
- msg.setStandardButtons(QtGui.QMessageBox.Yes | QtGui.QMessageBox.No)
- msg.setDefaultButton(QtGui.QMessageBox.Yes)
- ret = msg.exec_()
-
- if ret == QtGui.QMessageBox.Yes:
- installer_path = os.path.abspath(
- os.path.join(
- os.getcwd(),
- "..",
- "Resources",
- "tuntap-installer.app"))
- if os.path.isdir(installer_path):
- cmd = ["open '%s'" % (installer_path,)]
- try:
- ret = subprocess.call(
- cmd, stdout=subprocess.PIPE,
- shell=True)
- except:
- logger.error(TUNTAP_BADEXEC_MSG)
- else:
- logger.error(TUNTAP_NOTFOUND_MSG)
-
- # Second check, for missing scripts.
- check_missing()
-
-
-#
-# Linux initializers
-#
-def _linux_install_missing_scripts(badexec, notfound):
- """
- Tries to install the missing up/down scripts.
-
- :param badexec: error for notifying execution error during command.
- :type badexec: str
- :param notfound: error for notifying missing path.
- :type notfound: str
- :returns: True if the files could be copied successfully.
- :rtype: bool
- """
- success = False
- installer_path = os.path.join(os.getcwd(), "apps", "eip", "files")
- launcher = vpnlaunchers.LinuxVPNLauncher
-
- # XXX refactor with darwin, same block.
-
- if os.path.isdir(installer_path):
- fd, tempscript = tempfile.mkstemp(prefix="leap_installer-")
- polfd, pol_tempfile = tempfile.mkstemp(prefix="leap_installer-")
- try:
- path = launcher.OPENVPN_BIN_PATH
- policy_contents = privilege_policies.get_policy_contents(path)
-
- with os.fdopen(polfd, 'w') as f:
- f.write(policy_contents)
-
- pkexec = first(launcher.maybe_pkexec())
- scriptlines = launcher.cmd_for_missing_scripts(installer_path,
- pol_tempfile)
- with os.fdopen(fd, 'w') as f:
- f.write(scriptlines)
-
- st = os.stat(tempscript)
- os.chmod(tempscript, st.st_mode | stat.S_IEXEC | stat.S_IXUSR |
- stat.S_IXGRP | stat.S_IXOTH)
- cmdline = ["%s %s" % (pkexec, tempscript)]
- ret = subprocess.call(
- cmdline, stdout=subprocess.PIPE,
- shell=True)
- success = ret == 0
- if not success:
- logger.error("Install missing scripts failed.")
- except Exception as exc:
- logger.error(badexec)
- logger.error("Error was: %r" % (exc,))
- finally:
- try:
- os.remove(tempscript)
- except OSError as exc:
- logger.error("%r" % (exc,))
- else:
- logger.error(notfound)
- logger.debug('path searched: %s' % (installer_path,))
-
- return success
-
-
-def LinuxInitializer():
- """
- Raises a dialog in case that either updown scripts or policykit file
- are missing or they have incorrect permissions.
- """
- check_missing()
diff --git a/src/leap/platform_init/locks.py b/src/leap/platform_init/locks.py
deleted file mode 100644
index 39b18648..00000000
--- a/src/leap/platform_init/locks.py
+++ /dev/null
@@ -1,405 +0,0 @@
-# -*- coding: utf-8 -*-
-# locks.py
-# Copyright (C) 2013 LEAP
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-"""
-Utilities for handling multi-platform file locking mechanisms
-"""
-import logging
-import errno
-import os
-import platform
-
-from leap.common.events import signal as signal_event
-from leap.common.events import events_pb2 as proto
-from leap import platform_init
-
-if platform_init.IS_UNIX:
- from fcntl import flock, LOCK_EX, LOCK_NB
-else: # WINDOWS
- import datetime
- import glob
- import shutil
- import time
-
- from tempfile import gettempdir
-
- from leap.util import get_modification_ts, update_modification_ts
-
-logger = logging.getLogger(__name__)
-
-if platform_init.IS_UNIX:
-
- class UnixLock(object):
- """
- Uses flock to get an exclusive lock over a file.
- See man 2 flock
- """
-
- def __init__(self, path):
- """
- iniializes t he UnixLock with the path of the
- desired lockfile
- """
-
- self._fd = None
- self.path = path
-
- def get_lock(self):
- """
- Tries to get a lock, and writes the running pid there if successful
- """
- gotit, pid = self._get_lock_and_pid()
- return gotit
-
- def get_pid(self):
- """
- Returns the pid of the locking process
- """
- gotit, pid = self._get_lock_and_pid()
- return pid
-
- def _get_lock(self):
- """
- Tries to get a lock, returning True if successful
-
- :rtype: bool
- """
- self._fd = os.open(self.path, os.O_CREAT | os.O_RDWR)
-
- try:
- flock(self._fd, LOCK_EX | LOCK_NB)
- except IOError as exc:
- # could not get the lock
- #import ipdb; ipdb.set_trace()
-
- if exc.args[0] in (errno.EDEADLK, errno.EAGAIN):
- # errno 11 or 35
- # Resource temporarily unavailable
- return False
- else:
- raise
- return True
-
- @property
- def locked_by_us(self):
- """
- Returns True if the pid in the pidfile
- is ours.
-
- :rtype: bool
- """
- gotit, pid = self._get_lock_and_pid()
- return pid == os.getpid()
-
- def _get_lock_and_pid(self):
- """
- Tries to get a lock over the file.
- Returns (locked, pid) tuple.
-
- :rtype: tuple
- """
-
- if self._get_lock():
- self._write_to_pidfile()
- return True, None
-
- return False, self._read_from_pidfile()
-
- def _read_from_pidfile(self):
- """
- Tries to read pid from the pidfile,
- returns False if no content found.
- """
-
- pidfile = os.read(
- self._fd, 16)
- if not pidfile:
- return False
-
- try:
- return int(pidfile.strip())
- except Exception as exc:
- exc.args += (pidfile, self.lock_file)
- raise
-
- def _write_to_pidfile(self):
- """
- Writes the pid of the running process
- to the pidfile
- """
- fd = self._fd
- os.ftruncate(fd, 0)
- os.write(fd, '%d\n' % os.getpid())
- os.fsync(fd)
-
-
-if platform_init.IS_WIN:
-
- # Time to wait (in secs) before assuming a raise window signal has not been
- # ack-ed.
-
- RAISE_WINDOW_TIMEOUT = 2
-
- # How many steps to do while checking lockfile ts update.
-
- RAISE_WINDOW_WAIT_STEPS = 10
-
- def _release_lock(name):
- """
- Tries to remove a folder path.
-
- :param name: folder lock to remove
- :type name: str
- """
- try:
- shutil.rmtree(name)
- return True
- except WindowsError as exc:
- if exc.errno in (errno.EPIPE, errno.ENOENT,
- errno.ESRCH, errno.EACCES):
- logger.warning(
- 'exception while trying to remove the lockfile dir')
- logger.warning('errno %s: %s' % (exc.errno, exc.args[1]))
- # path does not exist
- return False
- else:
- logger.debug('errno = %s' % (exc.errno,))
- # we did not foresee this error, better add it explicitely
- raise
-
- class WindowsLock(object):
- """
- Creates a lock based on the atomic nature of mkdir on Windows
- system calls.
- """
- LOCKBASE = os.path.join(gettempdir(), "leap-client-lock")
-
- def __init__(self):
- """
- Initializes the lock.
- Sets the lock name to basename plus the process pid.
- """
- self._fd = None
- pid = os.getpid()
- self.name = "%s-%s" % (self.LOCKBASE, pid)
- self.pid = pid
-
- def get_lock(self):
- """
- Tries to get a lock, and writes the running pid there if successful
- """
- gotit = self._get_lock()
- return gotit
-
- def _get_lock(self):
- """
- Tries to write to a file with the current pid as part of the name
- """
- try:
- self._fd = os.makedirs(self.name)
- except OSError as exc:
- # could not create the dir
- if exc.args[0] == 183:
- logger.debug('cannot create dir')
- # cannot create dir with existing name
- return False
- else:
- raise
- return self._is_one_pidfile()[0]
-
- def _is_one_pidfile(self):
- """
- Returns True, pid if there is only one pidfile with the expected
- base path
-
- :rtype: tuple
- """
- pidfiles = glob.glob(self.LOCKBASE + '-*')
- if len(pidfiles) == 1:
- pid = pidfiles[0].split('-')[-1]
- return True, int(pid)
- else:
- return False, None
-
- def get_pid(self):
- """
- Returns the pid of the locking process.
-
- :rtype: int
- """
- # XXX assert there is only one?
- _, pid = self._is_one_pidfile()
- return pid
-
- def get_locking_path(self):
- """
- Returns the pid path of the locking process.
-
- :rtype: str
- """
- pid = self.get_pid()
- if pid:
- return "%s-%s" % (self.LOCKBASE, pid)
-
- def release_lock(self, name=None):
- """
- Releases the pidfile dir for this process, by removing it.
- """
- if not name:
- name = self.name
- _release_lock(name)
-
- @classmethod
- def release_all_locks(self):
- """
- Releases all locks. Used for clean shutdown.
- """
- for lockdir in glob.glob("%s-%s" % (self.LOCKBASE, '*')):
- _release_lock(lockdir)
-
- @property
- def locked_by_us(self):
- """
- Returns True if the pid in the pidfile
- is ours.
-
- :rtype: bool
- """
- _, pid = self._is_one_pidfile()
- return pid == self.pid
-
- def update_ts(self):
- """
- Updates the timestamp of the lock.
- """
- if self.locked_by_us:
- update_modification_ts(self.name)
-
- def write_port(self, port):
- """
- Writes the port for windows control to the pidfile folder
- Returns True if successful.
-
- :rtype: bool
- """
- if not self.locked_by_us:
- logger.warning("Tried to write control port to a "
- "non-unique pidfile folder")
- return False
- port_file = os.path.join(self.name, "port")
- with open(port_file, 'w') as f:
- f.write("%s" % port)
- return True
-
- def get_control_port(self):
- """
- Reads control port of the main instance from the port file
- in the pidfile dir
-
- :rtype: int
- """
- pid = self.get_pid()
- port_file = os.path.join(self.LOCKBASE + "-%s" % pid, "port")
- port = None
- try:
- with open(port_file) as f:
- port_str = f.read()
- port = int(port_str.strip())
- except IOError as exc:
- if exc.errno == errno.ENOENT:
- logger.error("Tried to read port from non-existent file")
- else:
- # we did not know explicitely about this error
- raise
- return port
-
- def raise_window_ack():
- """
- This function is called from the windows callback that is registered
- with the raise_window event. It just updates the modification time
- of the lock file so we can signal an ack to the instance that tried
- to raise the window.
- """
- lock = WindowsLock()
- lock.update_ts()
-
-
-def we_are_the_one_and_only():
- """
- Returns True if we are the only instance running, False otherwise.
- If we came later, send a raise signal to the main instance of the
- application.
-
- Under windows we are not using flock magic, so we wait during
- RAISE_WINDOW_TIMEOUT time, if not ack is
- received, we assume it was a stalled lock, so we remove it and continue
- with initialization.
-
- :rtype: bool
- """
- _sys = platform.system()
-
- if _sys in ("Linux", "Darwin"):
- locker = UnixLock('/tmp/leap-client.lock')
- locker.get_lock()
- we_are_the_one = locker.locked_by_us
- if not we_are_the_one:
- signal_event(proto.RAISE_WINDOW)
- return we_are_the_one
-
- elif _sys == "Windows":
- locker = WindowsLock()
- locker.get_lock()
- we_are_the_one = locker.locked_by_us
-
- if not we_are_the_one:
- locker.release_lock()
- lock_path = locker.get_locking_path()
- ts = get_modification_ts(lock_path)
-
- nowfun = datetime.datetime.now
- t0 = nowfun()
- pause = RAISE_WINDOW_TIMEOUT / float(RAISE_WINDOW_WAIT_STEPS)
- timeout_delta = datetime.timedelta(0, RAISE_WINDOW_TIMEOUT)
- check_interval = lambda: nowfun() - t0 < timeout_delta
-
- # let's assume it's a stalled lock
- we_are_the_one = True
- signal_event(proto.RAISE_WINDOW)
-
- while check_interval():
- if get_modification_ts(lock_path) > ts:
- # yay! someone claimed their control over the lock.
- # so the lock is alive
- logger.debug('Raise window ACK-ed')
- we_are_the_one = False
- break
- else:
- time.sleep(pause)
-
- if we_are_the_one:
- # ok, it really was a stalled lock. let's remove all
- # that is left, and put only ours there.
- WindowsLock.release_all_locks()
- WindowsLock().get_lock()
-
- return we_are_the_one
-
- else:
- logger.warning("Multi-instance checker "
- "not implemented for %s" % (_sys))
- # lies, lies, lies...
- return True