The Debian policy dictates that package upgrades must take care of preserving user changes to configuration files. This article will explain you how most packages ensure this. This is important knowledge for anyone who has to manage upgrades: knowing how it works lets you easily automate most of it and deal correctly with the fallout.
How dpkg manages configuration files
Most packages rely on dpkg to properly install configuration files. Dpkg keeps a checksum of the last installed version of configuration file. When it must install a new version, it calculates the checksum of the currently installed file and if it doesn’t match anymore, it knows that the user has edited the file. In that case, instead of overwriting the configuration file, it asks the user what to do. You probably already have seen those questions, they look like this:
Configuration file `/etc/bash.bashrc' ==> Modified (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 : start a shell to examine the situation The default action is to keep your current version. *** bash.bashrc (Y/I/N/O/D/Z) [default=N] ?
In this specific example, if you answer “Y” or “I” (for “yes” or “install”), dpkg will install the new version of /etc/bash.bashrc
but it will also backup the current version in /etc/bash.bashrc.dpkg-old
. If you answer “N” or “O” (for “no” or “old”), dpkg will install the new version in /etc/bash.bashrc.dpkg-dist
and /etc/bash.bashrc
is left untouched. The two other answers allow you to examine the differences before taking a decision. Note that if you choose to start a shell, the new version is currently available as /etc/bash.bashrc.dpkg-new
(and since Squeeze there are convenient environment variables $DPKG_CONFFILE_OLD and $DPKG_CONFFILE_NEW in case you want to create a custom review script).
All configurations files managed by dpkg are called “conffiles” because that’s the name of the field where they are recorded in the dpkg database. You can display the list of conffiles for any package:
$ dpkg --status bash [...] Conffiles: /etc/skel/.profile ecb6d3479ac3823f1da7f314d871989b /etc/skel/.bashrc 2afdd6c53990f2387a7ef9989af0bc07 /etc/skel/.bash_logout 22bfb8c1dd94b5f3813a2b25da67463f /etc/bash.bashrc 5b3c3bc73d236e4e1b6f9b6c1ed5964e [...]
The command “dpkg-query --showformat='${Conffiles}\n' --show bash
” can give you the same information if you need to retrieve only that field. The 32 characters after the filename are the MD5 checksum of the original configuration file provided by the package.
Avoiding the conffile prompt
Every time that dpkg must install a new conffile that you have modified (and a removed file is only a particular case of a modified file in dpkg’s eyes), it will stop the upgrade and wait your answer. This can be particularly annoying for major upgrades. That’s why you can give predefined answers to dpkg with the help of multiple --force-conf*
options:
--force-confold
: do not modify the current configuration file, the new version is installed with a.dpkg-dist
suffix. With this option alone, even configuration files that you have not modified are left untouched. You need to combine it with--force-confdef
to let dpkg overwrite configuration files that you have not modified.--force-confnew
: always install the new version of the configuration file, the current version is kept in a file with the.dpkg-old
suffix.--force-confdef
: ask dpkg to decide alone when it can and prompt otherwise. This is the default behavior of dpkg and this option is mainly useful in combination with--force-confold
.--force-confmiss
: ask dpkg to install the configuration file if it’s currently missing (for example because you have removed the file by mistake).
If you use Apt, you can pass options to dpkg with a command-line like this:
$ apt-get -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" dist-upgrade
You can also make those options permanent by creating /etc/apt/apt.conf.d/local
:
Dpkg::Options { "--force-confdef"; "--force-confold"; }
Bringing up the conffile prompt at any time
The conffile prompt is only displayed when dpkg detects that the package provides an new version of the conffile. Thus reinstalling the same package will not bring up the prompt. But you can instruct dpkg to ask nevertheless with the --force-confask
option. This is a new feature in Debian Squeeze. It will only ask for files that are locally modified.
If you want to read more articles like this one, click here to subscribe to my free newsletter. You can also follow me on Identi.ca, Twitter and Facebook.
Mathieu Parent says
Thanks for this doc. Is there a way to specify on which file those –force-conf* options apply? Like –force-confold=/etc/samba/smb.conf.
Raphaël Hertzog says
Unfortunately no. In most cases, dpkg is configured to install unmodified configuration files and those that were already modified are managed by an external tool like puppet or cfengine anyway.
tlo says
Thanks for this article! If you build a debian package, is there a way to specify which files are handled as conffiles?
Raphaël Hertzog says
It depends on the tools that you use for your packaging. But with debhelper (97% of the packages use that), all files installed in /etc/ are automatically registered as conffiles.
Under the hood, what matters is that the files are listed in DEBIAN/conffiles in the tree passed to “dpkg-deb -b”.
ThorstenS says
nice post! very valuable hints for the new squeeze options!
beside using /etc/apt/apt.conf.d/local it is also possible to write dpkg`s option in /etc/dpkg/dpkg.cfg or /etc/dpkg/dpkg.cfg.d/[0-9a-zA-Z_-]*
thanks
/thorsten
Alexander E. Patrakov says
Conffiles can be also generated in postinst and updated via ucf. See, for example, foomatic-filters. The bonus point is that one sees a ncurses-based dialog about the updated configuration file, and also can do a three-way merge of the local modifications into the updated default configuration file.
Now the question: can dpkg (or ucf?) be configured to do the same things (ncurses-based dialog, three-way merge) with all configuration files?
Raphaël Hertzog says
Alexander: Right now, no. But there are many wishlist bug reports asking this, and there’s preliminary code doing this. Sean Finney wrote the code, but it has never been completed/merged due to lack of response from Guillem Jover. 🙁
See http://bugs.debian.org/32877
jonny rocket says
too bad it wasn’t easier to use.