Package: dpkg
Version: 1.17.27
Followup-For: Bug #837051

Dear Maintainer,

find attached a patch to fix the mentioned bug.
The patch still applied to master=1.18.8.

To reproducte this:
        tar xf 41965_dpkg-divert.tar.xz
        cd bug41965.1 && dpkg-buildpackage -uc -us -b
        cd bug41965.2 && dpkg-buildpackage -uc -us -b
        dpkg -i bug41965-a_1_all.deb
        dpkg-divert --local --rename --divert /etc/bug41965/compat.moved --add 
/etc/bug41965/compat
        dpkg -i bug41965-?_2_all.deb

-- System Information:
Debian Release: 8.6
  APT prefers stable-updates
  APT policy: (500, 'stable-updates'), (500, 'stable'), (90, 'testing')
Architecture: amd64 (x86_64)

Kernel: Linux 3.16.0-4-amd64 (SMP w/4 CPU cores)
Locale: LANG=de_DE.UTF-8, LC_CTYPE=de_DE.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash
Init: systemd (via /run/systemd/system)

Versions of packages dpkg depends on:
ii  libbz2-1.0   1.0.6-7+b3
ii  libc6        2.24-5
ii  liblzma5     5.1.1alpha+20120614-2+b3
ii  libselinux1  2.3-2
ii  tar          1.27.1-2+deb8u1
ii  zlib1g       1:1.2.8.dfsg-2+b1

dpkg recommends no packages.

Versions of packages dpkg suggests:
ii  apt  1.0.9.8.3

-- no debconf information
>From 557ad2681c947515cc52f933158473f440d65ee9 Mon Sep 17 00:00:00 2001
Message-Id: 
<557ad2681c947515cc52f933158473f440d65ee9.1481286674.git.h...@univention.de>
From: Philipp Hahn <h...@univention.de>
Date: Fri, 9 Dec 2016 13:11:59 +0100
Subject: [PATCH] Fix update of diverted conffile moved between packages
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Organization: Univention GmbH, Bremen, Germany

If a conffile is diverted and it gets moved from one package to another,
dpkg still considers it owned by the original package and aborts the
upgrade:
> Unpacking libpython2.7-minimal:amd64 (from 
> libpython2.7-minimal_2.7.9-2_amd64.deb) ...
> dpkg: error processing libpython2.7-minimal_2.7.9-2_amd64.deb (--install):
>  trying to overwrite '/etc/python2.7/sitecustomize.py', which is also in 
> package python2.7-minimal 2.7.9-2

Running dpkg with --debug=03773 shows this difference (using an
artificial package for testing) - left is diverted, right side not:
> tarobject ti->name='./etc/bug41965/compat' mode=100644 owner=0.0 type=48(-) 
> ti->linkname='' name…| tarobject ti->name='./etc/bug41965/compat' mode=100644 
> owner=0.0 type=48(-) ti->linkname='' namenode='/etc/b…
> namenodetouse namenode='/etc/bug41965/compat' pkg=bug41965-b:all              
>                    | 
> -------------------------------------------------------------------------------------------------------------
> namenodetouse ... useinstead=/etc/bug41965/compat.moved camefrom=<none> 
> pkg=<none> return /etc/b…| 
> -------------------------------------------------------------------------------------------------------------
>                                                                               
>                    |
> conffderef in='etc/bug41965/compat.moved' current 
> working='/etc/bug41965/compat.moved'           | conffderef 
> in='etc/bug41965/compat' current working='/etc/bug41965/compat'
> conffderef in='etc/bug41965/compat.moved' result='/etc/bug41965/compat.moved' 
>                    | conffderef in='etc/bug41965/compat' 
> result='/etc/bug41965/compat'
> tarobject fnnf_new_conff deref='etc/bug41965/compat.moved'                    
>                    | tarobject fnnf_new_conff deref='etc/bug41965/compat'
> setupvnamevbs main='/etc/bug41965/compat.moved' 
> tmp='/etc/bug41965/compat.moved.dpkg-tmp' new='/…| setupvnamevbs 
> main='/etc/bug41965/compat' tmp='/etc/bug41965/compat.dpkg-tmp' 
> new='/etc/bug41965/compat.dpkg…
> tarobject already exists                                                      
>                    | tarobject already exists
> tarobject ... found in bug41965-a:all                                         
>                    | tarobject ... found in bug41965-a:all
> tarobject ... diverted, divpkgset=<none>                                      
>                    | tarobject other's obsolete conffile

In the un-diverted case (right side) you see the message from
src/archives.c:911, which is missing in the diverted case (left side),
finally leading to the package being rejected:

>       /* Is the file an obsolete conffile in the other package
>        * and a conffile in the new package? */
>       if ((nifd->namenode->flags & fnnf_new_conff) &&
>           !statr && S_ISREG(stab.st_mode)) {
>         for (conff = otherpkg->installed.conffiles;
>              conff;
>              conff = conff->next) {
>           if (!conff->obsolete)
>             continue;
>           if (stat(conff->name, &stabtmp)) {

Here conff->name='./etc/bug41965/compat' is the original file name, not
the diverted one; So it stat()s *my* alternative file and not the
diverted file, ...

>             if (errno == ENOENT || errno == ENOTDIR || errno == ELOOP)
>               continue;
>             else
>               ohshite(_("cannot stat file '%s'"), conff->name);
>           }
>           if (stabtmp.st_dev == stab.st_dev &&
>               stabtmp.st_ino == stab.st_ino)
>             break;

... so the loop is not aborted ...

>         }
>         if (conff) {
>           debug(dbg_eachfiledetail, "tarobject other's obsolete conffile");
>           /* process_archive() will have copied its hash already. */
>           continue;

... and that case is not detected.

>         }
>       }

Instead of always checking the original file, we switch to use the
diverted file if ...
>           confname = (
>             nifd->namenode->divert && nifd->namenode->divert->useinstead &&

we are currently processing a diverted conffile

>             strcmp(conff->name, nifd->namenode->name) == 0 &&

whose name matches the conffile of the other-packages conffile

>             divpkgset != otherpkg->set

where that package is not the diverting package

>           ) ? nifd->namenode->divert->useinstead->name : conff->name;

Signed-off-by: Philipp Hahn <h...@univention.de>
---
 src/archives.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/src/archives.c b/src/archives.c
index d05a589..d858bf0 100644
--- a/src/archives.c
+++ b/src/archives.c
@@ -915,13 +915,19 @@ tarobject(void *ctx, struct tar_entry *ti)
         for (conff = otherpkg->installed.conffiles;
              conff;
              conff = conff->next) {
+          char *confname;
           if (!conff->obsolete)
             continue;
-          if (stat(conff->name, &stabtmp)) {
+          confname = (
+            nifd->namenode->divert && nifd->namenode->divert->useinstead &&
+            strcmp(conff->name, nifd->namenode->name) == 0 &&
+            divpkgset != otherpkg->set
+          ) ? nifd->namenode->divert->useinstead->name : conff->name;
+          if (stat(confname, &stabtmp)) {
             if (errno == ENOENT || errno == ENOTDIR || errno == ELOOP)
               continue;
             else
-              ohshite(_("cannot stat file '%s'"), conff->name);
+              ohshite(_("cannot stat file '%s'"), confname);
           }
           if (stabtmp.st_dev == stab.st_dev &&
               stabtmp.st_ino == stab.st_ino)
-- 
2.1.4

Attachment: 41965_dpkg-divert.tar.xz
Description: application/xz

Reply via email to