Problem #3: How to find out what’s going on with debconf?

Slightly longer version: As reported in #679327, the grub prompt during the installation process is entitled “Configuring man-db”, which isn’t exactly great. Given man-db is a known dpkg trigger, I suspected this would be the reason for the broken title, and here’s how I debugged it.

For starters, using d-i basically means asking a lot of questions, which is implemented using the debconf mechanism. One should note that two implementations are available:

  1. the historic implementation, in Perl: debconf
  2. the C reimplementation: cdebconf

d-i uses cdebconf udebs, but joy begins when packages get installed in /target: debconf is used there. We’ll see why that matters.

Recipe #3: Set DEBCONF_DEBUG=developer and read logs!

  1. Both implementations support the DEBCONF_DEBUG environment variable. The installer supports passing that as a kernel parameter; example from the syslinux prompt: select the “Graphical install” entry, press “Tab”, remove -- quiet and put DEBCONF_DEBUG=developer there instead.

  2. Let’s look at /var/log/syslog; there’s a tail -f on it in VT4, but one can run grep and friends on it in VT2 or VT3. There, one can see what happens at the debconf level (the debconf protocol is documented in debconf-devel(7)). Tiny excerpt (timestamps removed for clarity):

    frontend: --> GET preseed/early_command
    frontend: <-- 0
    …
    frontend: --> GET debian-installer/framebuffer
    frontend: <-- 0 true
    …
    debconf: --> GET debconf/language
    debconf: <-- 0 en
    debconf: --> SET debconf/language en
    debconf: Setting debconf/language to en
    debconf: <-- 0 value set
    debconf: --> GET debconf/priority
    debconf: <-- 0 high
    debconf: --> GET rescue/enable
    debconf: <-- 0 false
    
  3. The interesting point was titles, right? So let’s look at the last TITLE occurrences:

    debconf: --> SETTITLE debian-installer/main-menu-title
    debconf: --> SETTITLE debian-installer/grub-installer/title
    in-target: debconf (developer): ----> TITLE Configuration de man-db
    debconf: --> TITLE Configuration de man-db
    in-target: debconf (developer): <-- TITLE Configuration de man-db
    in-target: debconf (developer): ----> TITLE Configuration de man-db
    in-target: debconf (developer): ----> TITLE Configuration de grub-pc
    debconf: --> TITLE Configuration de grub-pc
    in-target: debconf (developer): <-- TITLE Configuration de grub-pc
    in-target: debconf (developer): ----> TITLE Configuration de grub-pc
    in-target: debconf (developer): ----> TITLE Configuration de man-db
    debconf: --> TITLE Configuration de man-db
    in-target: debconf (developer): <-- TITLE Configuration de man-db
    in-target: debconf (developer): ----> TITLE Configuration de man-db
    in-target: debconf (developer): ----> TITLE Configuration de grub-pc
    debconf: --> TITLE Configuration de grub-pc
    in-target: debconf (developer): <-- TITLE Configuration de grub-pc
    in-target: debconf (developer): ----> TITLE Configuration de grub-pc
    debconf: --> SETTITLE debian-installer/grub-installer/title
    

    Bad news: the last one is about grub, so the title should be correct, right?

  4. At this point, it might be the Gtk frontend behaving strangely. It’s shipped in cdebconf-gtk-udeb, built from the cdebconf source. Let’s look:

    • src/modules/frontend/gtk/ui.c has cdebconf_gtk_update_frontend_title(), which does what the function name suggests.
    • src/modules/frontend/gtk/di.c has cdebconf_gtk_di_run_dialog(), which calls the first function.
    • src/modules/frontend/gtk/progress.c has cdebconf_gtk_show_progress() (also calls the first function), which comes with the following comments:

       /** Show the progress widgets.
         *
         * This will actually add the widgets to the corresponding containers.
         * The main title saved when starting the PROGRESS operation will be restored
         * from the value saved when START was called.  This is needed when GO is
         * called during a PROGRESS operation.
      

    Now that’s something! Even if the last entry is about grub, some previous value could be restored and could be the reason for the bad behaviour (that is easily confirmed by adding some debug_printf() calls on fe->title in cdebconf, thanks to an extra "debug.h" include). Maybe that’s what needs fixing!

  5. Now it’s time to take a step back. A d-i environment is nice, but testing things can easily become a burden. Taking a random wheezy or sid chroot, and installing/removing a tiny package shipping a manpage should be enough to run into the man-db trigger. Exporting DEBCONF_DEBUG=developer there too, let’s either install or remove x11-apps (the trigger does the same job, and the debconf trace is the same), here’s the output:

    Processing triggers for man-db ...
    debconf (developer): frontend started
    debconf (developer): frontend running, package name is man-db
    debconf (developer): starting /var/lib/dpkg/info/man-db.config configure /usr/share/man
    debconf (developer): <-- VERSION 2.0
    debconf (developer): --> 0 2.0
    debconf (developer): <-- INPUT medium man-db/install-setuid
    debconf (developer): --> 30 question skipped
    debconf (developer): <-- GO
    debconf (developer): --> 0 ok
    debconf (developer): starting /var/lib/dpkg/info/man-db.postinst triggered /usr/share/man
    debconf (developer): <-- VERSION 2.0
    debconf (developer): --> 0 2.0
    debconf (developer): <-- GET man-db/auto-update
    debconf (developer): --> 0 true
    

    Even if one didn’t know about the cdebconf/debconf thing, the frontend started bit in the d-i syslog would have been the key: it’s only found in debconf, in the frontend script. That one has several ways to determine the package being acted on, and it finally calls:

    debug developer => "frontend running, package name is $package";
    $frontend->default_title($package) if length $package;
    

    Tada, that’s likely to be the issue.

  6. Tweaking that frontend script, it’s easy to make sure that the code path for this use case is:

    elsif ($ARGV[0]=~m!^.*/(.*?)\.(?:postinst|postrm|prerm)$!) {
            $package=$1;
    }
    

    Since $ARGV[1] is the action being passed to the maintainer script, one can intercept the triggered action, and avoid emitting a title update in this case; I’ve therefore reassigned #679327 to the debconf package, and proposed a patch implementing that, which Joey Hess seems to find reasonable.

In my message to the bug report I wrote I actually tested it in a d-i environment, and made sure the issue had gone away. How I did that will likely be described in the next d-i hacking recipe.