The following commit has been merged in the master branch:
commit d834b77b5d16e453b32bd36bbb5487c910e54280
Author: Raphaël Hertzog <[email protected]>
Date:   Fri Oct 21 16:21:56 2011 +0200

    dpkg-gencontrol, dpkg-distaddfile: protect update of debian/files with a 
lock
    
    The lock is taken on debian/control as this is a file that we know to
    always exist. Without this lock, it's possible that the file is updated
    concurrently by two processes when parallel building is enabled (leading
    to one of them failing unexpectedly).
    
    Reported-by: James Vega <[email protected]>

diff --git a/debian/changelog b/debian/changelog
index d173a50..f01bf02 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -32,6 +32,11 @@ dpkg (1.16.2) UNRELEASED; urgency=low
     too. Closes: #595144
   * Rewrite architecture.mk with explicit loops instead of duplicating many
     similar lines. Based on a patch by Thorsten Glaser <[email protected]>.
+  * Modify dpkg-gencontrol and dpkg-distaddfile to grab a write lock
+    on debian/control before updating debian/files to avoid simultaneous
+    updates. Closes: #642608
+    Add libfile-fcntllock-perl to dpkg-dev's Depends since we use this module
+    to handle the locking.
 
   [ Jonathan Nieder ]
   * Bump po4a version in Build-Depends to 0.41, since earlier versions do
diff --git a/debian/control b/debian/control
index 390d9f1..5ad1e92 100644
--- a/debian/control
+++ b/debian/control
@@ -49,7 +49,7 @@ Package: dpkg-dev
 Section: utils
 Priority: optional
 Architecture: all
-Depends: libdpkg-perl (= ${source:Version}), bzip2, xz-utils,
+Depends: libdpkg-perl (= ${source:Version}), libfile-fcntllock-perl, bzip2, 
xz-utils,
  patch, make, binutils, base-files (>= 5.0.0), ${misc:Depends}
 Recommends: gcc | c-compiler, build-essential, fakeroot, gnupg, gpgv, 
libalgorithm-merge-perl
 Suggests: debian-keyring
diff --git a/scripts/dpkg-distaddfile.pl b/scripts/dpkg-distaddfile.pl
index 566698e..7b5274e 100755
--- a/scripts/dpkg-distaddfile.pl
+++ b/scripts/dpkg-distaddfile.pl
@@ -18,6 +18,7 @@
 use strict;
 use warnings;
 
+use File::FcntlLock;
 use POSIX;
 use POSIX qw(:errno_h :signal_h);
 use Dpkg;
@@ -75,6 +76,15 @@ my ($file, $section, $priority) = @ARGV;
 ($file =~ m/\s/ || $section =~ m/\s/ || $priority =~ m/\s/) &&
     error(_g("filename, section and priority may contain no whitespace"));
 
+# Obtain a lock on debian/control to avoid simultaneous updates
+# of debian/files when parallel building is in use
+my $fs = File::FcntlLock->new(l_type => F_WRLCK);
+my $lockfh;
+sysopen($lockfh, "debian/control", O_WRONLY) ||
+    syserr(_g("cannot write %s"), "debian/control");
+$fs->lock($lockfh, F_SETLKW) ||
+    syserr(_("failed to get a write lock on %s"), "debian/control");
+
 $fileslistfile="./$fileslistfile" if $fileslistfile =~ m/^\s/;
 open(Y, "> $fileslistfile.new") || syserr(_g("open new files list file"));
 if (open(X,"< $fileslistfile")) {
@@ -91,3 +101,6 @@ print(Y "$file $section $priority\n")
 close(Y) || syserr(_g("close new files list file"));
 rename("$fileslistfile.new", $fileslistfile) ||
     syserr(_g("install new files list file"));
+
+# Release the lock
+close($lockfh) || syserr(_g("cannot close %s"), "debian/control");
diff --git a/scripts/dpkg-gencontrol.pl b/scripts/dpkg-gencontrol.pl
index 14d6e48..1cf6945 100755
--- a/scripts/dpkg-gencontrol.pl
+++ b/scripts/dpkg-gencontrol.pl
@@ -18,6 +18,7 @@
 use strict;
 use warnings;
 
+use File::FcntlLock;
 use POSIX;
 use POSIX qw(:errno_h);
 use Dpkg;
@@ -333,6 +334,15 @@ for my $f (keys %remove) {
     delete $fields->{$f};
 }
 
+# Obtain a lock on debian/control to avoid simultaneous updates
+# of debian/files when parallel building is in use
+my $fs = File::FcntlLock->new(l_type => F_WRLCK);
+my $lockfh;
+sysopen($lockfh, "debian/control", O_WRONLY) ||
+    syserr(_g("cannot write %s"), "debian/control");
+$fs->lock($lockfh, F_SETLKW) ||
+    syserr(_("failed to get a write lock on %s"), "debian/control");
+
 $fileslistfile="./$fileslistfile" if $fileslistfile =~ m/^\s/;
 open(Y, ">", "$fileslistfile.new") || syserr(_g("open new files list file"));
 binmode(Y);
@@ -363,6 +373,9 @@ print(Y $substvars->substvars(sprintf("%s %s %s\n", 
$forcefilename,
 close(Y) || syserr(_g("close new files list file"));
 rename("$fileslistfile.new", $fileslistfile) || syserr(_g("install new files 
list file"));
 
+# Release the lock
+close($lockfh) || syserr(_g("cannot close %s"), "debian/control");
+
 my $cf;
 my $fh_output;
 if (!$stdout) {

-- 
dpkg's main repository


-- 
To UNSUBSCRIBE, email to [email protected]
with a subject of "unsubscribe". Trouble? Contact [email protected]

Reply via email to