Bug in checkinstall regarding conffiles

There's a very handy utility called CheckInstall. It let's you easily pack a custom compiled program into a package and install+remove it like it was part of the distribution. Makes life a lot easier if you've to remove something that you had to install from source (via make install).
I've found a bug regarding the Debian packaging part and the handling of files that get installed into /etc.

In a Debian package one of the control files is called conffiles. It's a list of configuration files (usually placed in /etc) that the package management system will not overwrite when the package is upgraded. However checkinstall uses the following command to generate conffiles:
# Tag files in /etc to be conffiles
find $BUILD_DIR/etc 2> /dev/null | sed -e "s,$BUILD_DIR,," | \
        grep -v '^/etc$' > $BUILD_DIR/DEBIAN/conffiles

The problem is that this listing might contain directories too (if the install process created directories in /etc) and during the installation of the deb package (that you created with checkinstall) the creation of the configfiles inside that directory will fail, because dpkg skips the parent directory (because the directory is listed in conffiles).
Eg. let's assume that your program's make install would create the following directories and files in /etc:
/etc/demo/
/etc/demo/listener.cfg
/etc/demo/myconfig.cfg

Checkinstall creates a conffiles with the following content:
/etc/demo
/etc/demo/listener.cfg
/etc/demo/myconfig.cfg

And during the installation of the generated deb package you'll receive an error message like this:
dpkg: error processing demo_1.0.0-1_i386.deb (--install):
unable to create `./etc/demo/listener.cfg': No such file or directory

And this pretty much prevents you from installing the package.

The problem is caused by the missing /etc/demo directory. If you run dpkg in debug mode, you'll see that the /etc/demo directory is created (or at least so it seems):
D000100: setupvnamevbs main=`/etc/demo' tmp=`/etc/demo.dpkg-tmp' new=`/etc/demo.dpkg-new'
D000100: tarobject nonexistent
D000010: ensure_pathname_nonexisting `/etc/demo.dpkg-new'
D000010: ensure_pathname_nonexisting `/etc/demo.dpkg-tmp'
D000100: tarobject Directory creating

But actually only /etc/demo.dpkg-new is created and since the directory is listed in conffiles, the *-new dir is not renamed to the /etc/demo final name.

To solve the problem we've to patch checkinstall to not include directories in conffiles. Here's a diff for the currently available latest checkinstall from Ubuntu (it's v1.6.1-8):
--- checkinstall        2009-01-14 21:24:21.000000000 +0100
+++ checkinstall.new    2009-01-14 21:24:47.000000000 +0100
@@ -2444,8 +2444,8 @@
fi

# Tag files in /etc to be conffiles
-find $BUILD_DIR/etc 2> /dev/null | sed -e "s,$BUILD_DIR,," | \
-       grep -v '^/etc$' > $BUILD_DIR/DEBIAN/conffiles
+find $BUILD_DIR/etc ! -type d 2> /dev/null | sed -e "s,$BUILD_DIR,," | \
+       > $BUILD_DIR/DEBIAN/conffiles

# The package will be saved here:
DEBPKG="${DIRECTORIO_FUENTE}/${NAME}_${VERSION}-${RELEASE}_${ARCHITECTURE}.deb"

Rebuild your deb package with the patched checkinstall and the deb installation should complete successfully (supposing there're no other problems with your package Smile ).

Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

Patching and building checkinstall in Karmic and later

The maintainers of checkinstall decided it is time to introduce a patch system in their workflow. They opted for Quilt. You can read a nice intro on using Quilt here. There's a nice example at the respective Ubuntu Wiki page too.

As described here, I had difficulties building the checkinstall package with a simple dpkg-buildpackage command.
Here's what worked for me (I went straight for the "cutting edge" Smile by using the checkinstall package from Maverick):
wget 'http://archive.ubuntu.com/ubuntu/pool/universe/c/checkinstall/checkinstall_1.6.2.orig.tar.gz'
wget 'http://archive.ubuntu.com/ubuntu/pool/universe/c/checkinstall/checkinstall_1.6.2-1.debian.tar.gz'
wget 'http://archive.ubuntu.com/ubuntu/pool/universe/c/checkinstall/checkinstall_1.6.2-1.dsc'
dpkg-source -x checkinstall_1.6.2-1.dsc
# note in the output of the above step that patches were already applied and thus the build process depends on this!
cd checkinstall-1.6.2
export QUILT_PATCHES=debian/patches
quilt new fix-etc.diff
quilt add checkinstall
###
# here I edited the contents of the checkinstall file as described in my original post
###
quilt refresh
debuild -uc -us -b

Please report to upstream BTS

Hello, someone reported this bug in the Debian BTS, would you please report your findings and patch to the upstream BTS found here: http://bugtrack.izto.org/ ?

Thanks Smile

Re: Please report to upstream BTS

Hi Andreas!

I'll try and do my best. Smile I was all for reporting bugs too, but unfortunately I had a few bad experiences. On many occasions my bugreports were simply ignored (sometimes along with reports from dozen other guys/girls) and in some cases I was told to go and RTFM (or read some faq on how to post a bug). In the last few years I simply post my findings on my blog and if somebody googles for the right keywords, it'll come up. Smile

As for your email: of course my checkinstall patch can be licensed via GPL (or whatever license checkinstall comes with). The generic CC license message in the footer of my blog is there so people won't be allowed to just grab any idea/code from my blog and get rich by selling/using it. Wink Not that there's anything on my blog worth "stealing". Smile

Re: Please report to upstream BTS

Just for reference ... I've submitted the following bugreport in CheckInstall's BTS:
Directories in /etc are incorrectly included in debian/conffiles

When building a DEB package with CheckInstall, the directories in /etc are incorrectly marked as "config files". Ie. they're put into debian/conffiles in the DEB package.

Let's assume you're building a DEB package for an app that installed these files:
/etc/demo/listener.cfg
/etc/demo/myconfig.cfg

Now the problem is that if you package this app via CheckInstall, it'll create a DEB package with a debian/conffiles that will contain these entries:
/etc/demo
/etc/demo/listener.cfg
/etc/demo/myconfig.cfg

If you try to install the CheckInstall-created DEB package, you get this error:

dpkg: error processing demo_1.0.0-1_i386.deb (--install):
unable to create `./etc/demo/listener.cfg': No such file or directory

If you run "dpkg -i -D000110 demo_1.0.0-1_i386.deb" (ie. turn on some debug output), then you'll get this:

D000100: setupvnamevbs main=`/etc/demo' tmp=`/etc/demo.dpkg-tmp' new=`/etc/demo.dpkg-new'
D000100: tarobject nonexistent
D000010: ensure_pathname_nonexisting `/etc/demo.dpkg-new'
D000010: ensure_pathname_nonexisting `/etc/demo.dpkg-tmp'
D000100: tarobject Directory creating

You can see that /etc/demo is created as /etc/demo.new, but since /etc/demo is in debian/conffiles, the /etc/demo.new is not renamed to /etc/demo.

The problem is with these lines in the 1.6.2 (latest released version) checkinstall script:

-------------------
# Tag files in /etc to be conffiles
find $BUILD_DIR/etc 2> /dev/null | sed -e "s,$BUILD_DIR,," | \
grep -v '^/etc$' > $BUILD_DIR/DEBIAN/conffiles
-------------------

The fix is simple:

-------------------
# Tag files in /etc to be conffiles
find $BUILD_DIR/etc ! -type d 2> /dev/null | sed -e "s,$BUILD_DIR,," | \
> $BUILD_DIR/DEBIAN/conffiles
-------------------

I've downloaded the code from your GIT repo and it contains a fix, but I think it's flawed.

The code in your GIT is:
-------------------
# Tag files in /etc to be conffiles
find $BUILD_DIR/etc -type f 2> /dev/null | sed -e "s,$BUILD_DIR,," | \
grep -v '^/etc$' > $BUILD_DIR/DEBIAN/conffiles
-------------------

This fix puts only regular files in debian/conffiles. If there're any symbolic links in /etc, they will be skipped. My patch seems to be better since it skips only directories (as I think it should). On the other hand, if the "find" command would include symbolic links, then the script probably should check whether the symlink points to a file or a directory and only include files.

So the proper fix seems to be:
-------------------
# Tag files in /etc to be conffiles
find -L $BUILD_DIR/etc -type f 2> /dev/null | sed -e "s,$BUILD_DIR,," | \
> $BUILD_DIR/DEBIAN/conffiles
-------------------

If you use "-L", then "-type f" and "! -type d" become logically equivalent, but of course the former is a bit faster.

Moreover if the script filters for just files, then the "grep -v '^/etc$'" filtering is unnecessary since /etc is a directory and thus it'll never be included in the result of find.

This bugreport is described in detail on my blog too (except the problem with the fix in GIT is not mentioned):
http://muzso.hu/node/4489

A few days ago somebody reported the same problem in the Debian bug tracking system as well.
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=655453

Let me know if you need any further input.
The bug was reproduced with CheckInstall v1.6.2 on a Debian Squeeze (fully updated) system.

And the ticket in Debian's BTS is here.