我正在编写一个脚本来执行一些apt
命令,但我遇到了apt/dpkg
数据库被锁定的潜在问题,因此我的脚本被释放。我想在执行任何操作之前检查锁定文件(即/var/lib/dpkg/lock
),就像apt
在运行命令时一样,但我不知道如何apt
执行锁定。
锁定文件始终存在,并且apt-get
不会对文件进行锁定。否则,它如何检查是否正在使用?从strace
我看到的文件中可以看到apt-get
文件已打开,但仅此而已。在我的脚本中,我可以在打开文件的同时apt-get
打开它。
答案1
好吧,我以为这里有一个简单的答案,但我什么也找不到。首先,你 100% 确定锁文件始终存在吗?尝试运行
lsof /var/lib/dpkg/lock
以 root 身份查看是否有任何进程已打开它。
据我所知,apt-get 会执行 fcntl 锁定,但我还没有查看代码来验证。我想这可以解释为什么文件一直在那里,apt 只是在需要时才锁定它。
如果脚本运行时只检查进程列表,如果 apt 同时运行,则退出,这样行吗?这样能满足您的使用要求吗?
好像这个人走了和你同样的路,但没有取得多大成功。
答案2
我来这里是为了寻找一个类似于 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
答案3
从 shell 脚本(参见羊群(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
答案4
我发现 apt 正在使用 fcntl。由于我使用 Ruby 作为脚本语言,因此我必须创建自己的函数来查找 lock。原因是 Ruby 并未完全实现 fcntl 函数。它仅提供函数调用和常量。构建 flock 结构以及如何传递它们的能力被遗漏或未记录。
这里是列表我发现有人在谈论那件事。
这是我最终编写的函数:
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