0

On a Debian-based system I have a scheduled job (e.g. cron job, or systemd timer/service) which runs every 30 minutes. However, I don’t want that to happen concurrently with packages are being installed or updated.

Package installation can happen manually or on a schedule, but in the latter case there is a considerable randomized delay. I could adapt the schedule for my job to not interfere with a potential package update (whether something is actually installed or not), and remember to disable the job when installing packages manually, and remember to enable it afterwards – but that is not really satisfactory.

So I am looking for a reliable way to tell package installation is in progress, so my job can check for it and exit (or delay execution) if that is the case. If repository information is being updated or packages are being downloaded in the background concurrently with my job, that is not really an issue, but my job should not run while installation is happening (copying of files, configuration, pre/post-install scripts and similar).

On OPNsense (which is FreeBSD based) the system updater acquires a lock on a particular file, so I have wrapped my job inside flock. If an update is in progress, my job would be skipped. If an upgrade were to be triggered while my job is running, presumably the upgrade would fail with a message indicating another update is in progress.

I am wondering if apt on Debian has something similar, such as a lock file that I can check on. If so – is that mechanism exclusive to a particular package management frontend or would it work with all of the standard tools for .deb packages (e.g. dpkg, apt, aptitude, synaptic and the like)?

I see that when Synaptic is open and I try to run sudo apt-get upgrade, I get:

E: Could not get lock /var/lib/dpkg/lock-frontend. It is held by process 1234 (synaptic)
N: Be aware that removing the lock file is not a solution and may break your system.
E: Unable to acquire the dpkg frontend lock (/var/lib/dpkg/lock-frontend), is another process using it?

However, sudo flock -n /var/lib/dpkg/lock-frontend sleep 10 || echo File is locked succeeds (i.e. flock returns true, indicating that I have obtained the lock, sleep executes while echo does not) even while Synaptic is running (though not currently installing anything). Same behavior with /var/lib/dpkg/lock.

So how can I obtain a “lock on package installation”?

10
  • Check in script if dpkg is running Commented May 26 at 11:37
  • @RomeoNinov dpkg might start while the job is already running, thus obtaining an actual lock (which inhibits the package manager as long as it is held by another process) would be the better solution.
    – user149408
    Commented May 26 at 14:47
  • What if the lock appear when the job is already run? Commented May 26 at 16:33
  • @RomeoNinov The job would acquire the lock upon starting and hold it until it is finished. During that time the package manager would be unable to acquire the lock.
    – user149408
    Commented May 26 at 16:51
  • The purpose of the lock file is to prevent package collision. Anytime any app that uses apt is open, whether processing changes or sitting idle, the lock file is active, i.e "even while Synaptic is running (though not currently installing anything)" will return true as intended, even when idle, because APT is waiting for input. If APT shouldn't be running, test for either lock file mentioned. If the test is true, delay the service until the test is false, or test for false and start the service.
    – eyoung100
    Commented May 28 at 19:47

1 Answer 1

0

Package managers on Debian – judging by my test results this is true for apt frontends as well as dpkg – lock two files, /var/lib/dpkg/lock and /var/lib/dpkg/lock-frontend. According to my tests, Synaptic locks both files as soon as the GUI comes up, and holds them until it exits.

However, there are different kinds of locks on Linux, which are not guaranteed to be compatible with each other, thus both methods may acquire an exclusive lock on the same file at the same time:

As detailed in this answer, dpkg uses and has always used fcntl(2) internally. Unfortunately, while flock(2) comes with a command-line wrapper that is available on most Debian systems, I haven’t been able to find an equivalent for fcntl(2). Your options are either to install chiark-utils-bin, which gives you with-lock-ex(1), or write some Python code. The following has worked for me, to the degree that it reports the file as locked when Synaptic is running but reports success when no apt tools are running:

fname = '/var/lib/dpkg/lock'

try:
    f = open(fname, 'w')
    fcntl.lockf(f, fcntl.LOCK_EX | fcntl.LOCK_NB)
    print('Successfully locked {}'.format(fname))
    input('Press Enter to continue...')
except IOError as e:
    # e.errno == errno.EAGAIN indicates the file is locked,
    # everything else indicates another error (e.g. permission denied)
    print('Unable to lock {}: {}'.format(fname, os.strerror(e.errno)))

After testing I can confirm that this prevents concurrent execution of the Python program in question and the package manager – whoever attempts to acquire the lock first gets it, other processes have to retry later. Software Updater displays Waiting for python3 to finish if the Python program holds the lock; the Python program will display the error message if Synaptic is running or Update Manager is installing updates.

There is no need to explicitly release the lock – this automatically happens when the process that holds it exits.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .