Bug#592575: `yes '' | apt-get dist-upgrade' hangs
Package: apt
Version: 0.7.20.2+lenny2
Severity: normal
Tags: patch
#apt-get -s dist-upgrade
Reading package lists... Done
Building dependency tree
Reading state information... Done
Calculating upgrade... Done
The following packages have been kept back:
acroread-debian-files fvwm gdk-imlib11 gtk-engines-lighthouseblue libgtk1.2
lvm2
The following packages will be upgraded:
gzip
1 upgraded, 0 newly installed, 0 to remove and 6 not upgraded.
Inst gzip [1.3.12-6+lenny] (1.3.12-6+lenny1 Debian:5.0.5/stable, Debian-Security:5.0/stable)
Conf gzip (1.3.12-6+lenny1 Debian:5.0.5/stable, Debian-Security:5.0/stable)
`yes '' | apt-get dist-upgrade' causes apt-get to block in write(2) because
nobody reads (or even has open) the pseudoterminal it writes to (since its
child, dpkg, is a zombie already).
Please see the patch for details. Thanks.
-- Package-specific info:
-- apt-config dump --
APT "";
APT::Architecture "i386";
APT::Build-Essential "";
APT::Build-Essential:: "build-essential";
APT::Install-Recommends "1";
APT::Install-Suggests "0";
APT::Acquire "";
APT::Acquire::Translation "environment";
APT::NeverAutoRemove "";
APT::NeverAutoRemove:: "^linux-image.*";
APT::NeverAutoRemove:: "^linux-restricted-modules.*";
APT::Cache-Limit "16777216";
Dir "/";
Dir::State "var/lib/apt/";
Dir::State::lists "lists/";
Dir::State::cdroms "cdroms.list";
Dir::State::userstatus "status.user";
Dir::State::status "/var/lib/dpkg/status";
Dir::Cache "var/cache/apt/";
Dir::Cache::archives "archives/";
Dir::Cache::srcpkgcache "srcpkgcache.bin";
Dir::Cache::pkgcache "pkgcache.bin";
Dir::Etc "etc/apt/";
Dir::Etc::sourcelist "sources.list";
Dir::Etc::sourceparts "sources.list.d";
Dir::Etc::vendorlist "vendors.list";
Dir::Etc::vendorparts "vendors.list.d";
Dir::Etc::main "apt.conf";
Dir::Etc::parts "apt.conf.d";
Dir::Etc::preferences "preferences";
Dir::Bin "";
Dir::Bin::methods "/usr/lib/apt/methods";
Dir::Bin::dpkg "/usr/bin/dpkg";
Dir::Log "var/log/apt";
Dir::Log::Terminal "term.log";
DPkg "";
DPkg::Pre-Install-Pkgs "";
DPkg::Pre-Install-Pkgs:: "/usr/sbin/dpkg-preconfigure --apt || true";
DPkg::Post-Invoke "";
DPkg::Post-Invoke:: "if [ -x /usr/bin/debsums ]; then /usr/bin/debsums --generate=nocheck -sp /var/cache/apt/archives; fi";
DPkg::Post-Invoke:: "test -f /var/run/junior-config.usermenu && if [ -x /usr/sbin/cdd-update-usermenus ] ; then /usr/sbin/cdd-update-usermenus junior ; fi ; rm -f /var/run/junior-config.usermenu";
-- /etc/apt/preferences --
Package: *
Pin: release a=stable
Pin-Priority: 600
Package: *
Pin: release a=oldstable
Pin-Priority: 50
-- (/etc/apt/sources.list present, but not submitted) --
-- System Information:
Debian Release: 5.0.5
APT prefers stable
APT policy: (600, 'stable')
Architecture: i386 (i686)
Kernel: Linux 2.6.26-1-686 (SMP w/1 CPU core)
Locale: LANG=ru_RU.UTF-8, LC_CTYPE=ru_RU.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/bash
Versions of packages apt depends on:
ii debian-archive-keyring 2009.01.31 GnuPG archive keys of the Debian a
ii libc6 2.7-18lenny4 GNU C Library: Shared libraries
ii libgcc1 1:4.3.2-1.1 GCC support library
ii libstdc++6 4.3.2-1.1 The GNU Standard C++ Library v3
apt recommends no packages.
Versions of packages apt suggests:
pn apt-doc <none> (no description available)
ii aptitude 0.4.11.11-1~lenny1 terminal-based package manager
ii bzip2 1.0.5-1 high-quality block-sorting file co
ii dpkg-dev 1.14.29 Debian package development tools
ii lzma 4.43-14 Compression method of 7z format in
ii python-apt 0.7.7.1+nmu1 Python interface to libapt-pkg
-- no debconf information
`yes '' | apt-get dist-upgrade' causes apt-get to block in write because nobody
reads (or even has open) the pseudoterminal it writes to (since its child, dpkg,
is a zombie already).
Also, this patch fixes the follwing problems:
* If write(2) in DoStdin writes not the whole input_buf (or interrupted), the
rest of input_buf would be lost.
* If read(2) in DoStdin fails, write(2) would be called with a negative
`count' argument.
--
/Dmitry Maksyoma <dmaksema@allot.com>
diff -ru apt-0.7.20.2+lenny2/apt-pkg/deb/dpkgpm.cc /home/dmaks/devel/6.0/apt/apt-0.7.20.2+lenny2/apt-pkg/deb/dpkgpm.cc
--- apt-0.7.20.2+lenny2/apt-pkg/deb/dpkgpm.cc 2009-02-08 04:09:35.000000000 +1300
+++ /home/dmaks/devel/6.0/apt/apt-0.7.20.2+lenny2/apt-pkg/deb/dpkgpm.cc 2010-08-11 16:56:03.000000000 +1200
@@ -81,6 +81,7 @@
: pkgPackageManager(Cache), dpkgbuf_pos(0),
term_out(NULL), PackagesDone(0), PackagesTotal(0)
{
+ stdin_buf_start = stdin_buf_end = 0;
}
/*}}}*/
// DPkgPM::pkgDPkgPM - Destructor /*{{{*/
@@ -314,12 +315,39 @@
*/
void pkgDPkgPM::DoStdin(int master)
{
- unsigned char input_buf[256] = {0,};
- ssize_t len = read(0, input_buf, sizeof(input_buf));
- if (len)
- write(master, input_buf, len);
- else
- stdin_is_dev_null = true;
+ ssize_t to_write_len = stdin_buf_end - stdin_buf_start;
+
+ // Read from stdin only if there's nothing in the stdin_buf.
+ if (to_write_len == 0) {
+ ssize_t len;
+ while ((len = read(0, stdin_buf, sizeof(stdin_buf))) == EINTR);
+ if (len <= 0) {
+ // Stop reading from stdin when end of file was reached or there are
+ // problems with rd.
+ stdin_is_dev_null = true;
+ return;
+ }
+
+ to_write_len = len;
+ stdin_buf_start = 0;
+ stdin_buf_end = len;
+ }
+
+ if (master != -1 && to_write_len) {
+ ssize_t wrote_len;
+ while ((wrote_len =
+ write(master, &stdin_buf[stdin_buf_start], to_write_len)) == EINTR);
+
+ if (wrote_len < 0) {
+ perror("write");
+ return;
+ }
+
+ if (wrote_len == to_write_len)
+ stdin_buf_start = stdin_buf_end = 0;
+ else
+ stdin_buf_start += wrote_len;
+ }
}
/*}}}*/
// DPkgPM::DoTerminalPty - Read the terminal pty and write log /*{{{*/
@@ -866,6 +894,7 @@
// setups fds
fd_set rfds;
+ fd_set wfds;
struct timespec tv;
sigset_t sigmask;
sigset_t original_sigmask;
@@ -890,17 +919,20 @@
// wait for input or output here
FD_ZERO(&rfds);
- if (!stdin_is_dev_null)
+ if (!stdin_is_dev_null && stdin_buf_end == 0)
FD_SET(0, &rfds);
FD_SET(_dpkgin, &rfds);
if(master >= 0)
FD_SET(master, &rfds);
+ FD_ZERO(&wfds);
+ if(master >= 0)
+ FD_SET(master, &wfds);
tv.tv_sec = 1;
tv.tv_nsec = 0;
- select_ret = pselect(max(master, _dpkgin)+1, &rfds, NULL, NULL,
+ select_ret = pselect(max(master, _dpkgin)+1, &rfds, &wfds, NULL,
&tv, &original_sigmask);
if (select_ret < 0 && (errno == EINVAL || errno == ENOSYS))
- select_ret = racy_pselect(max(master, _dpkgin)+1, &rfds, NULL,
+ select_ret = racy_pselect(max(master, _dpkgin)+1, &rfds, &wfds,
NULL, &tv, &original_sigmask);
if (select_ret == 0)
continue;
@@ -914,8 +946,8 @@
if(master >= 0 && FD_ISSET(master, &rfds))
DoTerminalPty(master);
- if(master >= 0 && FD_ISSET(0, &rfds))
- DoStdin(master);
+ if(master >= 0 && (stdin_buf_end > 0 || FD_ISSET(0, &rfds)))
+ DoStdin(FD_ISSET(master, &wfds) ? master : -1);
if(FD_ISSET(_dpkgin, &rfds))
DoDpkgStatusFd(_dpkgin, OutStatusFd);
}
diff -ru apt-0.7.20.2+lenny2/apt-pkg/deb/dpkgpm.h /home/dmaks/devel/6.0/apt/apt-0.7.20.2+lenny2/apt-pkg/deb/dpkgpm.h
--- apt-0.7.20.2+lenny2/apt-pkg/deb/dpkgpm.h 2009-02-08 04:09:35.000000000 +1300
+++ /home/dmaks/devel/6.0/apt/apt-0.7.20.2+lenny2/apt-pkg/deb/dpkgpm.h 2010-08-11 12:53:48.000000000 +1200
@@ -29,6 +29,11 @@
char dpkgbuf[1024];
int dpkgbuf_pos;
FILE *term_out;
+
+ // the buffer for reading stdin
+ unsigned char stdin_buf[256];
+ unsigned int stdin_buf_start;
+ unsigned int stdin_buf_end;
protected:
Reply to: