実行中のスクリプト
#!/bin/bash
(
flock 9
# ... commands executed under lock ...
fuser -v /var/lib/dpkg/lock
apt-get -f --assume-no install
) 9>/var/lib/dpkg/lock
スーパーユーザーはエラーメッセージを表示しません。しかし、例えばsynaptic
実行中、apt-get
はエラーメッセージを表示します:「E:ロックを取得できませんでした/ var/lib/dpkg/lock-オープン(11:リソースが一時的に利用不可)」。
dpkg
(およびapt)は、ロックにflock(2)
を使用しません。関連するシステムコールをチェックすると、 fcntl(2)
を使用しているようです。
$ Sudo strace -f -e trace=desc apt install foo |& grep -B2 F_SETLK
close(4) = 0
open("/var/lib/dpkg/lock", O_RDWR|O_CREAT|O_NOFOLLOW, 0640) = 4
fcntl(4, F_SETFD, FD_CLOEXEC) = 0
fcntl(4, F_SETLK, {l_type=F_WRLCK, l_whence=SEEK_SET, l_start=0, l_len=0}) = -1 EAGAIN (Resource temporarily unavailable)
close(4) = 0
そして this SO post :から
Linuxでは、
lockf()
はfcntl()
の単なるラッパーですが、flock()
ロックは独立しています(また、NFSマウントではなく、ローカルファイルシステムでのみ機能します)。つまり、1つのプロセスがファイルに対してアドバイザリーの排他的なflock()
ロックを持ち、別のプロセスがその同じファイルに対してアドバイザリーの排他的なfcntl()
ロックを持ちます。どちらもアドバイザリロックですが、相互作用しません。
したがって、flock
は、他のパッケージ管理コマンドに対してロックするのに効果的ではありません。 (考えてみてください...もしそうなら、その後のapt-get
はとにかく失敗するでしょう。)
私が考えることができる最も簡単な方法は、タスクの期間中に不変の/var/lib/dpkg/lock
ファイルを作成することです。
touch /var/lib/dpkg/lock
chattr +i /var/lib/dpkg/lock
または、fcntl
を使用してdpkgのようにロックする短いCプログラム(またはfcntl
への簡単なインターフェースを提供する任意の言語)を作成できます。