[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Moving conffiles between packages, redux



[debian-release: Read this if you care about the details. The executive
summary is to note that openssh 1:4.3p2-8 corrects an RC bug and should
be hinted into testing if its five days expire without any new RC bugs;
also that all other packages that have had to deal with moving conffiles
between packages may be affected by a similar problem depending on
whether they're upgraded with sarge's dpkg or etch's dpkg, and need to
be reviewed and corrected before release.]


I spent rather more time than I expected today cleaning up after my
initial attempt to fix bug #335276 (working around a bug in sarge's dpkg
with respect to conffile handling, fixed in etch's dpkg), which resulted
in bug #402804. Specifically, I had been moving a set of conffiles from
the old ssh package in sarge to the openssh-client and openssh-server
packages in etch for some time, and I was now also migrating the same
conffiles from the old ssh-krb5 package (which conflicted with ssh).

Initially, I was informed that it was good enough simply to remove the
conffiles in the preinst if their md5sums are identical to those
recorded by dpkg is sufficient, although unfortunately I didn't put the
effort in at the time to set up a proper test environment for this. How
wrong I was ...

I included a Replaces << the version of the package where I added the
move logic. However, as previously discussed on debian-devel, this
turned out not to be enough, since unlike all other files in a package
conffiles stick around after unpacking a new version of their package
without them at least until the new version is configured, so (when
using etch's dpkg, although apparently at least not always with sarge's)
Replaces << was ineffective. I decided the simplest approach here was
just to remove the versioning on the Replaces, since I never plan to
move the conffiles back.

Even after that, though, it turned out that removing the conffile is the
wrong approach. If you do that and happen to be using etch's dpkg rather
than sarge's dpkg, you get something like the following:

  root@cairhien:/# dpkg --unpack root/ssh-krb5_4.3p2-8_all.deb root/openssh-server_4.3p2-8_powerpc.deb root/openssh-client_4.3p2-8_powerpc.deb
  (Reading database ... 7701 files and directories currently installed.)
  Preparing to replace ssh-krb5 3.8.1p1-10 (using root/ssh-krb5_4.3p2-8_all.deb) ...
  Unpacking replacement ssh-krb5 ...
  dpkg: warning - unable to delete old directory `/etc/ssh': Directory not empty
  Selecting previously deselected package openssh-server.
  Unpacking openssh-server (from .../openssh-server_4.3p2-8_powerpc.deb) ...
  Transferring ownership of conffile /etc/default/ssh ...
  Transferring ownership of conffile /etc/pam.d/ssh ...
  Replacing files in old package ssh-krb5 ...
  Selecting previously deselected package openssh-client.
  Unpacking openssh-client (from .../openssh-client_4.3p2-8_powerpc.deb) ...
  Transferring ownership of conffile /etc/ssh/moduli ...
  Transferring ownership of conffile /etc/ssh/ssh_config ...
  Replacing files in old package ssh-krb5 ...
  root@cairhien:/# dpkg --configure -a
  Setting up openssh-client (4.3p2-8) ...
  
  Configuration file `/etc/ssh/ssh_config'
   ==> Deleted (by you or by a script) since installation.
   ==> Package distributor has shipped an updated version.
     What would you like to do about it ?  Your options are:
      Y or I  : install the package maintainer's version
      N or O  : keep your currently-installed version
        D     : show the differences between the versions
        Z     : background this process to examine the situation
   The default action is to keep your current version.

A conffile prompt - exactly what we were trying to avoid in the first
place! (Justin, your conf-owner-transfer test case exhibits this too
with etch's dpkg, along with the Replaces bug above.)

The only way to absolutely guarantee not to get a conffile prompt is to
make sure that the current file on disk is identical to either the old
or the new version of the conffile. When moving a conffile between
packages, I'm not sure that dpkg will allow the old version, and in any
case there's no easy way to retrieve it since all we have is the md5sum.
However, we do have the new version, although getting at it from the
preinst when the package hasn't been unpacked yet is rather fiddly. As
long as your conffile is textual, you can resort to the nasty hack of
duplicating it in the preinst script, and that's what I did in openssh.
This time I've actually tested this, so pending receipt of any more fun
upgrade bugs I believe it works.


I know that there are other packages that followed the recommendation to
remove the conffile in the preinst, so I would encourage maintainers of
those packages to review their code with reference to openssh 1:4.3p2-8
in order to avoid nasty lurking upgrade problems. The key points are:

  * Grab the old md5sum from dpkg in the preinst and check that it
    matches. If so, forcibly blat the new conffile into its place. (Yes,
    this is technically a policy violation, but the main reason for that
    part of policy is to avoid spurious conffile prompts when you didn't
    touch the file, and that's exactly what we're avoiding here too.
    Just remember to BE CAREFUL. The md5sum check should be enough.)
    openssh-client.preinst is about right here, taking care to avoid
    problems in case we run out of disk space while writing the new
    conffile, although it looks in /var/lib/dpkg/status directly rather
    than calling dpkg, which is a bug; I haven't got round to checking
    whether it's safe to fetch the conffile md5sum from 'dpkg -s ssh' in
    openssh-client's preinst.

  * Make sure to include rollback code in case the upgrade fails. This
    is something nearly everyone forgets in maintainer scripts, but this
    is all fragile enough that it's a particularly good idea here; just
    keep a copy of the old conffile at preinst time and either remove it
    at the end of the postinst if you succeed or put it back in the
    postrm if you fail. openssh-client.{preinst,postinst,postrm} should
    be usable as a model.

  * Replace all versions of the package you're moving the conffile from,
    not just the ones before the move. Making the Replaces tight just
    isn't worth the hassle.

  * You'll need a copy of the new conffile in the preinst script,
    substituted on the fly so that it never gets out of sync, and it
    needs to be quoted correctly for use in a shell variable.
    debian/substitute-conffile.pl in the openssh source package deals
    with this; run it over the preinst in the installation tree with
    'perl -i' and appropriate arguments after dh_installdeb or
    equivalent.

  * Test your upgrade procedure in both a chroot with sarge's dpkg
    installed and one with etch's dpkg installed. Really. This is
    horribly easy to get wrong, the behaviour is quite radically
    different between the two versions of dpkg, and the time needed to
    set up chroots is still way less than that taken to repeatedly
    upload until your users stop filing bugs.


Fortunately, all of this is only necessary for upgrades from sarge to
etch, and once we can expect everyone to have etch's dpkg installed we
can move conffiles between packages more or less like any other files.

Cheers,

-- 
Colin Watson                                       [cjwatson@debian.org]



Reply to: