This is an automated email from the git hooks/post-receive script. guillem pushed a commit to branch master in repository dpkg.
commit 0615492cb4c79d1f552e49f4a10dbfc959f03b9c Author: Julian Andres Klode <j...@debian.org> Date: Sun Jan 29 13:46:09 2017 +0100 libdpkg: Introduce frontend locking Currently, in order to run dpkg, frontends have to release the database lock before invoking dpkg and re-acquire it afterwards, leaving a short time where the database is unlocked and a different dpkg process or frontend could lock it. Frontend locking addresses the problem by creating a "lock-frontend" file that is acquired by the frontend and not released for dpkg invocations. Thus, multiple frontends cannot race for the database lock. This change extends the frontend lock to dpkg itself, acquiring it whenever the variable DPKG_FRONTEND_LOCKED is not set, so that a user manually running dpkg or a frontend not supporting this protocol cannot interfere with a currently running frontend. [guil...@debian.org: - Add documentation. - Rename frontend lock file. - Fix error strings. ] Signed-off-by: Guillem Jover <guil...@debian.org> --- debian/changelog | 4 ++++ doc/frontend.txt | 22 +++++++++++----------- lib/dpkg/dbmodify.c | 21 +++++++++++++++++++++ lib/dpkg/dpkg.h | 1 + man/dpkg.man | 4 ++++ 5 files changed, 41 insertions(+), 11 deletions(-) diff --git a/debian/changelog b/debian/changelog index afe1d4a..3542c13 100644 --- a/debian/changelog +++ b/debian/changelog @@ -53,6 +53,10 @@ dpkg (1.19.1) UNRELEASED; urgency=medium * Warn when using dpkg-divert --rename on a file from an Essential package. * Use a single “struct filenamenode” definition for the entire code base. Closes: #746766 + * Add support for frontend locking. This makes it possible for frontends + using this new protocol, to safely lock the dpkg database w/o risk of + race conditions with other dpkg instances or frontends supporting the + same protocol. Thanks to Julian Andres Klode <j...@debian.org>. * Architecture support: - Add support for riscv64 CPU. Closes: #822914 Thanks to Manuel A. Fernandez Montecelo <m...@debian.org> diff --git a/doc/frontend.txt b/doc/frontend.txt index 6628086..9ea1e20 100644 --- a/doc/frontend.txt +++ b/doc/frontend.txt @@ -10,15 +10,15 @@ Database Locking ---------------- Any frontend needing to make sure no write operation is currently happening, -should lock the dpkg database by locking the file «<admindir>/lock» using -file record locks (i.e. fcntl(2) advisory locking). The whole file should -be locked, as that's the most portable way to perform this operation; this -can be achieved by using start=0, len=0 and whence=SEEK_SET. +and no other frontend is running should first acquire the frontend lock at +«<admindir>/lock-frontend», and then acquire the dpkg database lock at +«<admindir>/lock». When the frontend invokes dpkg, it should set the +environment variable DPKG_FRONTEND_LOCKED (to prevent dpkg from acquiring +the frontend lock), and then release the dpkg database lock, which will be +acquired by dpkg itself. This way no other frontend following this protocol +can race to perform operations while another one has one in progress. -Take into account there will be a race condition between the frontend -unlocking the database and the invoked dpkg locking it again, in which -another process could lock it. - -In the future this functionality will be available through a shared libdpkg -library, and all frontends will be expected to switch to that instead, -because this will fix the aforementioned race condition. +These locks must be file record locks (i.e. fcntl(2) advisory locking), and +the whole file should be locked, as that's the most portable way to perform +this operation; this can be achieved by using start=0, len=0 and +whence=SEEK_SET. diff --git a/lib/dpkg/dbmodify.c b/lib/dpkg/dbmodify.c index 9baa583..4e14574 100644 --- a/lib/dpkg/dbmodify.c +++ b/lib/dpkg/dbmodify.c @@ -50,6 +50,7 @@ static bool db_initialized; static enum modstatdb_rw cstatus=-1, cflags=0; static char *lockfile; +static char *frontendlockfile; static char *statusfile, *availablefile; static char *importanttmpfile=NULL; static FILE *importanttmp; @@ -139,6 +140,7 @@ static const struct fni { char **store; } fnis[] = { { LOCKFILE, &lockfile }, + { FRONTENDLOCKFILE, &frontendlockfile }, { STATUSFILE, &statusfile }, { AVAILFILE, &availablefile }, { UPDATESDIR, &updatesdir }, @@ -184,6 +186,7 @@ modstatdb_done(void) } static int dblockfd = -1; +static int frontendlockfd = -1; bool modstatdb_is_locked(void) @@ -215,6 +218,18 @@ modstatdb_can_lock(void) if (dblockfd >= 0) return true; + if (getenv("DPKG_FRONTEND_LOCKED") == NULL) { + frontendlockfd = open(frontendlockfile, O_RDWR | O_CREAT | O_TRUNC, 0660); + if (frontendlockfd == -1) { + if (errno == EACCES || errno == EPERM) + return false; + else + ohshite(_("unable to open/create frontend lockfile")); + } + } else { + frontendlockfd = -1; + } + dblockfd = open(lockfile, O_RDWR | O_CREAT | O_TRUNC, 0660); if (dblockfd == -1) { if (errno == EACCES || errno == EPERM) @@ -232,6 +247,9 @@ modstatdb_lock(void) if (!modstatdb_can_lock()) ohshit(_("you do not have permission to lock the dpkg status database")); + if (frontendlockfd != -1) + file_lock(&frontendlockfd, FILE_LOCK_NOWAIT, frontendlockfile, + _("dpkg frontend")); file_lock(&dblockfd, FILE_LOCK_NOWAIT, lockfile, _("dpkg status database")); } @@ -240,8 +258,11 @@ modstatdb_unlock(void) { /* Unlock. */ pop_cleanup(ehflag_normaltidy); + if (frontendlockfd != -1) + pop_cleanup(ehflag_normaltidy); dblockfd = -1; + frontendlockfd = -1; } enum modstatdb_rw diff --git a/lib/dpkg/dpkg.h b/lib/dpkg/dpkg.h index 19b7914..7bc3480 100644 --- a/lib/dpkg/dpkg.h +++ b/lib/dpkg/dpkg.h @@ -78,6 +78,7 @@ DPKG_BEGIN_DECLS #define STATUSFILE "status" #define AVAILFILE "available" #define LOCKFILE "lock" +#define FRONTENDLOCKFILE "lock-frontend" #define DIVERSIONSFILE "diversions" #define STATOVERRIDEFILE "statoverride" #define UPDATESDIR "updates/" diff --git a/man/dpkg.man b/man/dpkg.man index 4f6f14b..fdaa87b 100644 --- a/man/dpkg.man +++ b/man/dpkg.man @@ -888,6 +888,10 @@ Currently only used by \fB\-\-list\fP. Sets the color mode (since dpkg 1.18.5). The currently accepted values are: \fBauto\fP (default), \fBalways\fP and \fBnever\fP. +.TP +.B DPKG_FRONTEND_LOCKED +Set by a package manager frontend to notify dpkg that it should not acquire +the frontend lock (since dpkg 1.19.1). .SS Internal environment .TP .B DPKG_ROOT -- Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/dpkg/dpkg.git