Назад | Перейти на главную страницу

Как мне проверить, не заблокирован ли подходящий файл блокировки?

Я пишу сценарий, чтобы apt команд, но я сталкиваюсь с потенциальными проблемами apt/dpkg базы данных заблокированы, поэтому мой скрипт отключается. Я хочу проверить файлы блокировки (т.е. /var/lib/dpkg/lock) перед тем, как делать что-нибудь вроде apt делает, когда запускает свою команду, но я не могу понять, как apt выполняет блокировку.

Файл блокировки всегда есть, и apt-get не делает стайку по файлу. Как еще можно было бы проверить, используется ли он? Из strace я вижу это apt-get открывает файл, но это все. В моем скрипте я могу открыть файл, пока apt-get он тоже открыт.

Ну, я думал, что здесь будет простой ответ, но я ничего не могу найти. Во-первых, вы на 100% уверены, что файл блокировки всегда там? Попробуйте бежать

lsof /var/lib/dpkg/lock

как root, чтобы узнать, открыт ли какой-либо процесс.

Из того, что я прочитал, apt-get выполняет блокировку fcntl, но я не смотрел код для проверки. Я предполагаю, что это объяснит, почему файл существует все время, apt просто блокирует его по мере необходимости.

Как насчет того, чтобы просто проверить список процессов при запуске сценария и выйти, если одновременно работает apt? Достаточно ли этого для вашего использования?

Выглядит как этот человек пошел по тому же пути, что и вы, без особого успеха.

Я пришел сюда в поисках решения, похожего на то, что в конечном итоге использовал gondoi, но написанного на Python вместо Ruby. Следующее, кажется, работает хорошо:

import fcntl

def is_dpkg_active():
    """
    Check whether ``apt-get`` or ``dpkg`` is currently active.

    This works by checking whether the lock file ``/var/lib/dpkg/lock`` is
    locked by an ``apt-get`` or ``dpkg`` process, which in turn is done by
    momentarily trying to acquire the lock. This means that the current process
    needs to have sufficient privileges.

    :returns: ``True`` when the lock is already taken (``apt-get`` or ``dpkg``
              is running), ``False`` otherwise.
    :raises: :py:exc:`exceptions.IOError` if the required privileges are not
             available.

    .. note:: ``apt-get`` doesn't acquire this lock until it needs it, for
              example an ``apt-get update`` run consists of two phases (first
              fetching updated package lists and then updating the local
              package index) and only the second phase claims the lock (because
              the second phase writes the local package index which is also
              read from and written to by ``dpkg``).
    """
    with open('/var/lib/dpkg/lock', 'w') as handle:
        try:
            fcntl.lockf(handle, fcntl.LOCK_EX | fcntl.LOCK_NB)
            return False
        except IOError:
            return True

Из сценария оболочки (см. стадо (1)):

flock --timeout 60 --exclusive --close /var/lib/dpkg/lock apt-get -y -o Dpkg::Options::="--force-confold" upgrade
if [ $? -ne 0 ]; then
  echo "Another process has f-locked /var/lib/dpkg/lock" 1>&2
  exit 1
fi

Я узнал, что apt использует файл fcntl. Поскольку я использую Ruby в качестве языка сценариев, мне пришлось создать свою собственную функцию для поиска блокировки. Причина этого в том, что Ruby не полностью реализует функцию fcntl. Он предоставляет только вызов функции и константы. Возможность создавать структуры из стаи и способы их передачи упущены или не задокументированы.

Здесь список Я нашел разговоры об этом.

Вот функция, которую я написал:

def flocked? &block
  flockstruct = [Fcntl::F_RDLCK, 0, 0, 0, 0].pack("ssqqi")
  fcntl Fcntl::F_GETLK, flockstruct
  status = flockstruct.unpack("ssqqi")[0]
  case status
    when Fcntl::F_UNLCK
      return false 
    when Fcntl::F_WRLCK|Fcntl::F_RDLCK
      return true
    else
      raise SystemCallError, status
  end
end