I am writing a script to do some apt commands, but I am running into potential issues of the apt/dpkg databases being locked so my script bails. I want to check the lock files (i.e. /var/lib/dpkg/lock) before doing anything just like apt does when it runs it's command, but I can't figure out how apt is performing the lock.

The lock file is always there, and apt-get is not doing a flock on the file. How else would it be checking to see if it is in use? From an strace I see that apt-get opens the file, but that is it. In my script, I can open the file while apt-get has it open as well.

Why can't you just catch the error and return an understandable error code before bailing? You didn't say what language you are using, but all script languages that I know of would let you do this, including ksh, Ruby, Perl and almost certainly Python as well.
–
MeiJan 13 '11 at 21:57

Let me add: the scripting languages (Perl, Ruby, Python) should also have function libraries to interface with APT: could those help?
–
MeiJan 13 '11 at 21:58

I'm using ruby, but come to find out ruby doesn't fully implement fcntl. I'd rather look for the lock the same way as apt instead of wasting time to let apt start and fail.
–
gondoiJan 14 '11 at 14:56

I found out that apt is using a fcntl. Since I am using Ruby for the scripting language, I had to create my own function to look for lock. The reason for this, is because Ruby does not implement the fcntl function entirely. It only provides the function call and constants. The ability to build flock structs and how to pass them is left out or not documented.

I came here looking for a solution similar to what gondoi ended up using but written in Python instead of Ruby. The following seems to work well:

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