Subject: Re: [Debconf-devel] Bug#439763: debconf: hangs on puppet installs on preseed install

From: Colin Watson <[email-masked]>
Date: Tue, 18 Dec 2007 17:16:03 +0000

[Sorry for the delay in replying to this.]

On Mon, Aug 27, 2007 at 10:42:41AM +0100, Adrian Bridgett wrote:
> (Mostly cloned from #425397 at the request of Joey Hess.  I've been
> running puppet in the d-i/late-command part of the install to get these
> problems, if it helps I'll try and trim it down (I suspect a preseeded
> postfix install might be sufficient))
> 
> I'm using puppet at the end of a preseeded install and some packages
> keep hanging (sysstat and postfix namely).  I suspect it's the
> preseeding that's causing the problem.  
> 
> What I see is dpkg-preconfigure running /tmp/postfix.config.12345
> (sometimes with a zombie'd process in the middle).  dpkg-preconfigure
> is reading from FD8 (which is FD1 from the postfix.config),  the
> postfix-config in turn is reading from FD0 (which is FD7 from the
> dpkg-preconfigure).  Deadlock ensues :-(

I'm not entirely sure that this is the same thing (I'd probably need to
peruse a full strace -f -s 4096 or so to be sure), but I wonder if this
might be related to
https://bugs.launchpad.net/ubuntu/+source/tasksel/+bug/141601, which
Søren Hansen tracked down to a debconf-apt-progress bug recently. Could
you possibly try r2249 from debconf's Subversion repository? I've
attached the patch for your convenience.

postfix spawns a daemon from its postinst but I don't think sysstat does
(however, it does do other weird stuff from its postinst). Thus, it
would be particularly interesting if this patch fixed one but not the
other.

> When postfix.config runs /usr/share/debconf/confmodules, at line 45 it
> complains that FD3 is a bad file descriptor.  Listing /proc/$$/fd
> shows that FD3 doesn't exist.  FD2 points to the overall stderr, FD1
> is a pipe back to FD8 of dpkg-preconfigure.  FD0 is FD7 from
> dpkg-preconfigure.
> 
> FD3 exists and DEBCONF_REDIR is set when ConfModule::startup() is
> called, however it looks like FD3 does not persist into the open2()
> call.

On the other hand, it might be something completely different. I note
that both sysstat and postfix call db_stop. I don't think this should
actually break the cdebconf instance way down at the bottom of the
stack, but it's possible that it will confuse the debconf running
debconf-apt-progress. If you could run the whole install under
DEBCONF_DEBUG=developer (you did something like this earlier), then this
might shed some light on exactly which debconf frontend is seeing what
commands.

> As a gross hack workaround (which might break god knows what else)
> I've edited /usr/share/debconf/confmodule to unset DEBCONF_REDIR if
> /proc/$$/fd/3 does not exist.

I'm, er, not exactly sure what that will do. :-) I think I'd rather
figure out the underlying problem. It may be that we need to ignore
db_stop in some circumstances.

Cheers,

-- 
Colin Watson                                       [[email-masked]]
Index: debian/changelog
===================================================================
--- debian/changelog	(revision 2248)
+++ debian/changelog	(revision 2249)
@@ -1,3 +1,13 @@
+debconf (1.5.18) UNRELEASED; urgency=low
+
+  [ Søren Hansen ]
+  * debconf-apt-progress sometimes gets captured by buggy daemons, causing
+    tasksel to hang because $debconf_command_eof never becomes true.
+    STATUS_READ should be the last fd to close, so checking $status_eof is
+    sufficient (LP: #141601).
+
+ -- Colin Watson <[email-masked]>  Tue, 04 Dec 2007 17:09:43 +0000
+
 debconf (1.5.17) unstable; urgency=low
 
   * Partial support for cancelable progress bars. While the dialog frontend
Index: debconf-apt-progress
===================================================================
--- debconf-apt-progress	(revision 2248)
+++ debconf-apt-progress	(revision 2249)
@@ -409,11 +409,13 @@
 	my $status_buf = '';
 	my $debconf_command_buf = '';
 
-	while (not $status_eof or not $debconf_command_eof) {
+	# STATUS_READ should be the last fd to close. DEBCONF_COMMAND_WRITE
+	# may end up captured by buggy daemons, so terminate the loop even
+	# if we haven't hit $debconf_command_eof.
+	while (not $status_eof) {
 		my $rin = '';
 		my $rout;
-		vec($rin, fileno(STATUS_READ), 1) = 1
-			unless $status_eof;
+		vec($rin, fileno(STATUS_READ), 1) = 1;
 		vec($rin, fileno(DEBCONF_COMMAND_READ), 1) = 1
 			unless $debconf_command_eof;
 		my $sel = select($rout = $rin, undef, undef, undef);