Я пишу сценарий, чтобы 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