summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Kalnischkies <david@kalnischkies.de>2018-09-09 19:45:42 +0200
committerDavid Kalnischkies <david@kalnischkies.de>2018-09-11 13:08:58 +0200
commit2295de2c97e6d1290a86e0b160885212411510a5 (patch)
tree24f48e6e4a8966144019139556a7da68c6e32286
parenta5953d914488c80c28fba6b59d2f0be461cd9f03 (diff)
Process status-fd completely before finishing dpkg call
Exiting the processing loop as soon as the dpkg process finishes might leave status-fd lines unprocessed which wasn't much of a problem in the past as the progress would just be slightly off, but now that we us the information also for skipping already done tasks and generate warnings if we didn't see all expected messages we should make sure we seem them all. We still need to exit "early" if dpkg exited unsuccessfully/crashed through as the (remaining) status lines we get could be incomplete.
-rw-r--r--apt-pkg/deb/dpkgpm.cc51
1 files changed, 36 insertions, 15 deletions
diff --git a/apt-pkg/deb/dpkgpm.cc b/apt-pkg/deb/dpkgpm.cc
index 790019b98..68674fa02 100644
--- a/apt-pkg/deb/dpkgpm.cc
+++ b/apt-pkg/deb/dpkgpm.cc
@@ -102,8 +102,8 @@ APT_PURE static unsigned int EnvironmentSize() /*{{{*/
class pkgDPkgPMPrivate /*{{{*/
{
public:
- pkgDPkgPMPrivate() : stdin_is_dev_null(false), dpkgbuf_pos(0),
- term_out(NULL), history_out(NULL),
+ pkgDPkgPMPrivate() : stdin_is_dev_null(false), status_fd_reached_end_of_file(false),
+ dpkgbuf_pos(0), term_out(NULL), history_out(NULL),
progress(NULL), tt_is_valid(false), master(-1),
slave(NULL), protect_slave_from_dying(-1),
direct_stdin(false)
@@ -114,6 +114,7 @@ public:
{
}
bool stdin_is_dev_null;
+ bool status_fd_reached_end_of_file;
// the buffer we use for the dpkg status-fd reading
char dpkgbuf[1024];
size_t dpkgbuf_pos;
@@ -958,11 +959,19 @@ void pkgDPkgPM::handleCrossUpgradeAction(string const &pkgname) /*{{{*/
// DPkgPM::DoDpkgStatusFd /*{{{*/
void pkgDPkgPM::DoDpkgStatusFd(int statusfd)
{
- ssize_t const len = read(statusfd, &d->dpkgbuf[d->dpkgbuf_pos],
- (sizeof(d->dpkgbuf)/sizeof(d->dpkgbuf[0])) - d->dpkgbuf_pos);
- if(len <= 0)
- return;
- d->dpkgbuf_pos += (len / sizeof(d->dpkgbuf[0]));
+ auto const remainingBuffer = (sizeof(d->dpkgbuf) / sizeof(d->dpkgbuf[0])) - d->dpkgbuf_pos;
+ if (likely(remainingBuffer > 0) && d->status_fd_reached_end_of_file == false)
+ {
+ auto const len = read(statusfd, &d->dpkgbuf[d->dpkgbuf_pos], remainingBuffer);
+ if (len < 0)
+ return;
+ else if (len == 0 && d->dpkgbuf_pos == 0)
+ {
+ d->status_fd_reached_end_of_file = true;
+ return;
+ }
+ d->dpkgbuf_pos += (len / sizeof(d->dpkgbuf[0]));
+ }
// process line by line from the buffer
char *p = d->dpkgbuf, *q = nullptr;
@@ -2022,6 +2031,7 @@ bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress)
// we read from dpkg here
int const _dpkgin = fd[0];
close(fd[1]); // close the write end of the pipe
+ d->status_fd_reached_end_of_file = false;
// apply ionice
if (_config->FindB("DPkg::UseIoNice", false) == true)
@@ -2041,14 +2051,24 @@ bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress)
int Status = 0;
int res;
bool waitpid_failure = false;
- while ((res=waitpid(Child,&Status, WNOHANG)) != Child) {
- if(res < 0) {
- // error handling, waitpid returned -1
- if (errno == EINTR)
- continue;
- waitpid_failure = true;
- break;
+ bool dpkg_finished = false;
+ do
+ {
+ if (dpkg_finished == false)
+ {
+ if ((res = waitpid(Child, &Status, WNOHANG)) == Child)
+ dpkg_finished = true;
+ else if (res < 0)
+ {
+ // error handling, waitpid returned -1
+ if (errno == EINTR)
+ continue;
+ waitpid_failure = true;
+ break;
+ }
}
+ if (dpkg_finished && d->status_fd_reached_end_of_file)
+ break;
// wait for input or output here
FD_ZERO(&rfds);
@@ -2078,7 +2098,8 @@ bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress)
DoStdin(d->master);
if(FD_ISSET(_dpkgin, &rfds))
DoDpkgStatusFd(_dpkgin);
- }
+
+ } while (true);
close(_dpkgin);
// Restore sig int/quit