From: Michael Vogt Date: Thu, 31 Oct 2013 20:03:33 +0000 (+0100) Subject: move pty magic into its own functions X-Git-Tag: 0.9.13.exp1~5 X-Git-Url: https://git.saurik.com/apt.git/commitdiff_plain/177296dffd8bf7d9ce5870b135c412958aab3756?hp=-c move pty magic into its own functions --- 177296dffd8bf7d9ce5870b135c412958aab3756 diff --combined apt-pkg/deb/dpkgpm.cc index b252c02eb,ddfc7c04e..d1b11098c --- a/apt-pkg/deb/dpkgpm.cc +++ b/apt-pkg/deb/dpkgpm.cc @@@ -19,7 -19,6 +19,7 @@@ #include #include #include +#include #include #include @@@ -55,12 -54,16 +55,12 @@@ class pkgDPkgPMPrivat public: pkgDPkgPMPrivate() : stdin_is_dev_null(false), dpkgbuf_pos(0), term_out(NULL), history_out(NULL), - progress(NULL) - last_reported_progress(0.0), nr_terminal_rows(0), - fancy_progress_output(false), master(-1), slave(-1) ++ progress(NULL), master(-1), slave(-1) { dpkgbuf[0] = '\0'; - if(_config->FindB("Dpkg::Progress-Fancy", false) == true) - { - fancy_progress_output = true; - _config->Set("DpkgPM::Progress", true); - } - + } + ~pkgDPkgPMPrivate() + { } bool stdin_is_dev_null; // the buffer we use for the dpkg status-fd reading @@@ -69,7 -72,20 +69,17 @@@ FILE *term_out; FILE *history_out; string dpkg_error; - - float last_reported_progress; - int nr_terminal_rows; - bool fancy_progress_output; + APT::Progress::PackageManager *progress; + + // pty stuff + struct termios tt; + int master; + int slave; + + // signals + sigset_t sigmask; + sigset_t original_sigmask; + }; namespace @@@ -132,20 -148,6 +142,20 @@@ ionice(int PID return ExecWait(Process, "ionice"); } +static std::string getDpkgExecutable() +{ + string Tmp = _config->Find("Dir::Bin::dpkg","dpkg"); + string const dpkgChrootDir = _config->FindDir("DPkg::Chroot-Directory", "/"); + size_t dpkgChrootLen = dpkgChrootDir.length(); + if (dpkgChrootDir != "/" && Tmp.find(dpkgChrootDir) == 0) + { + if (dpkgChrootDir[dpkgChrootLen - 1] == '/') + --dpkgChrootLen; + Tmp = Tmp.substr(dpkgChrootLen); + } + return Tmp; +} + // dpkgChrootDirectory - chrooting for dpkg if needed /*{{{*/ static void dpkgChrootDirectory() { @@@ -522,7 -524,7 +532,7 @@@ void pkgDPkgPM::DoTerminalPty(int maste // --------------------------------------------------------------------- /* */ -void pkgDPkgPM::ProcessDpkgStatusLine(int OutStatusFd, char *line) +void pkgDPkgPM::ProcessDpkgStatusLine(char *line) { bool const Debug = _config->FindB("Debug::pkgDPkgProgressReporting",false); if (Debug == true) @@@ -564,6 -566,16 +574,6 @@@ { pkgname = APT::String::Strip(list[2]); action = APT::String::Strip(list[1]); - - // this is what we support in the processing stage - if(action != "install" && action != "configure" && - action != "remove" && action != "purge" && action != "purge") - { - if (Debug == true) - std::clog << "ignoring processing action: '" << action - << "'" << std::endl; - return; - } } // "status" has the form: "status: pkg: state" // with state in ["half-installed", "unpacked", "half-configured", @@@ -590,16 -602,28 +600,16 @@@ { if(action == "error") { - status << "pmerror:" << list[1] - << ":" << (PackagesDone/float(PackagesTotal)*100.0) - << ":" << list[3] - << endl; - if(OutStatusFd > 0) - FileFd::Write(OutStatusFd, status.str().c_str(), status.str().size()); - if (Debug == true) - std::clog << "send: '" << status.str() << "'" << endl; + d->progress->Error(list[1], PackagesDone, PackagesTotal, + list[3]); pkgFailures++; WriteApportReport(list[1].c_str(), list[3].c_str()); return; } else if(action == "conffile") { - status << "pmconffile:" << list[1] - << ":" << (PackagesDone/float(PackagesTotal)*100.0) - << ":" << list[3] - << endl; - if(OutStatusFd > 0) - FileFd::Write(OutStatusFd, status.str().c_str(), status.str().size()); - if (Debug == true) - std::clog << "send: '" << status.str() << "'" << endl; + d->progress->ConffilePrompt(list[1], PackagesDone, PackagesTotal, + list[3]); return; } } @@@ -652,8 -676,16 +662,8 @@@ return; } std::string msg; - strprintf(msg, _(iter->second), short_pkgname.c_str()); - - status << "pmstatus:" << short_pkgname - << ":" << (PackagesDone/float(PackagesTotal)*100.0) - << ":" << msg - << endl; - if(OutStatusFd > 0) - FileFd::Write(OutStatusFd, status.str().c_str(), status.str().size()); - if (Debug == true) - std::clog << "send: '" << status.str() << "'" << endl; + strprintf(msg, _(iter->second), i18n_pkgname.c_str()); + d->progress->StatusChanged(pkgname, PackagesDone, PackagesTotal, msg); // FIXME: this needs a muliarch testcase // FIXME2: is "pkgname" here reliable with dpkg only sending us @@@ -676,14 -708,23 +686,14 @@@ // action const char *translation = _(states[PackageOpsDone[pkg]].str); std::string msg; - strprintf(msg, translation, short_pkgname.c_str()); - + // we moved from one dpkg state to a new one, report that PackageOpsDone[pkg]++; PackagesDone++; - // build the status str - status << "pmstatus:" << short_pkgname - << ":" << (PackagesDone/float(PackagesTotal)*100.0) - << ":" << msg - << endl; - if(_config->FindB("DPkgPM::Progress", false) == true) - SendTerminalProgress(PackagesDone/float(PackagesTotal)*100.0); + + strprintf(msg, translation, i18n_pkgname.c_str()); + d->progress->StatusChanged(pkgname, PackagesDone, PackagesTotal, msg); - if(OutStatusFd > 0) - FileFd::Write(OutStatusFd, status.str().c_str(), status.str().size()); - if (Debug == true) - std::clog << "send: '" << status.str() << "'" << endl; } if (Debug == true) std::clog << "(parsed from dpkg) pkg: " << short_pkgname @@@ -694,13 -735,12 +704,13 @@@ // DPkgPM::handleDisappearAction /*{{{*/ void pkgDPkgPM::handleDisappearAction(string const &pkgname) { - // record the package name for display and stuff later - disappearedPkgs.insert(pkgname); - pkgCache::PkgIterator Pkg = Cache.FindPkg(pkgname); if (unlikely(Pkg.end() == true)) return; + + // record the package name for display and stuff later + disappearedPkgs.insert(Pkg.FullName(true)); + // the disappeared package was auto-installed - nothing to do if ((Cache[Pkg].Flags & pkgCache::Flag::Auto) == pkgCache::Flag::Auto) return; @@@ -743,7 -783,7 +753,7 @@@ // --------------------------------------------------------------------- /* */ -void pkgDPkgPM::DoDpkgStatusFd(int statusfd, int OutStatusFd) +void pkgDPkgPM::DoDpkgStatusFd(int statusfd) { char *p, *q; int len; @@@ -758,7 -798,7 +768,7 @@@ while((q=(char*)memchr(p, '\n', d->dpkgbuf+d->dpkgbuf_pos-p)) != NULL) { *q = 0; - ProcessDpkgStatusLine(OutStatusFd, p); + ProcessDpkgStatusLine(p); p=q+1; // continue with next line } @@@ -924,6 -964,50 +934,6 @@@ bool pkgDPkgPM::CloseLog( return true; } /*}}}*/ -// DPkgPM::SendTerminalProgress /*{{{*/ -// --------------------------------------------------------------------- -/* Send progress info to the terminal - */ -void pkgDPkgPM::SendTerminalProgress(float percentage) -{ - int reporting_steps = _config->FindI("DpkgPM::Reporting-Steps", 1); - - if(percentage < (d->last_reported_progress + reporting_steps)) - return; - - std::string progress_str; - strprintf(progress_str, _("Progress: [%3i%%]"), (int)percentage); - if (d->fancy_progress_output) - { - int row = d->nr_terminal_rows; - - static string save_cursor = "\033[s"; - static string restore_cursor = "\033[u"; - - static string set_bg_color = "\033[42m"; // green - static string set_fg_color = "\033[30m"; // black - - static string restore_bg = "\033[49m"; - static string restore_fg = "\033[39m"; - - std::cout << save_cursor - // move cursor position to last row - << "\033[" << row << ";0f" - << set_bg_color - << set_fg_color - << progress_str - << restore_cursor - << restore_bg - << restore_fg; - } - else - { - std::cout << progress_str << "\r\n"; - } - std::flush(std::cout); - - d->last_reported_progress = percentage; -} /*}}}*/ /*{{{*/ // This implements a racy version of pselect for those architectures @@@ -945,98 -1029,128 +955,150 @@@ static int racy_pselect(int nfds, fd_se sigprocmask(SIG_SETMASK, &origmask, 0); return retval; } -/*}}}*/ + /*}}}*/ -void pkgDPkgPM::SetupTerminalScrollArea(int nr_rows) +// DPkgPM::BuildPackagesProgressMap /*{{{*/ +void pkgDPkgPM::BuildPackagesProgressMap() { - if(!d->fancy_progress_output) - return; - - // scroll down a bit to avoid visual glitch when the screen - // area shrinks by one row - std::cout << "\n"; - - // save cursor - std::cout << "\033[s"; - - // set scroll region (this will place the cursor in the top left) - std::cout << "\033[1;" << nr_rows - 1 << "r"; - - // restore cursor but ensure its inside the scrolling area - std::cout << "\033[u"; - static const char *move_cursor_up = "\033[1A"; - std::cout << move_cursor_up; - std::flush(std::cout); -} + // map the dpkg states to the operations that are performed + // (this is sorted in the same way as Item::Ops) + static const struct DpkgState DpkgStatesOpMap[][7] = { + // Install operation + { + {"half-installed", N_("Preparing %s")}, + {"unpacked", N_("Unpacking %s") }, + {NULL, NULL} + }, + // Configure operation + { + {"unpacked",N_("Preparing to configure %s") }, + {"half-configured", N_("Configuring %s") }, + { "installed", N_("Installed %s")}, + {NULL, NULL} + }, + // Remove operation + { + {"half-configured", N_("Preparing for removal of %s")}, + {"half-installed", N_("Removing %s")}, + {"config-files", N_("Removed %s")}, + {NULL, NULL} + }, + // Purge operation + { + {"config-files", N_("Preparing to completely remove %s")}, + {"not-installed", N_("Completely removed %s")}, + {NULL, NULL} + }, + }; -void pkgDPkgPM::CleanupTerminal() -{ - // reset scroll area - SetupTerminalScrollArea(d->nr_terminal_rows + 1); - if(d->fancy_progress_output) + // init the PackageOps map, go over the list of packages that + // that will be [installed|configured|removed|purged] and add + // them to the PackageOps map (the dpkg states it goes through) + // and the PackageOpsTranslations (human readable strings) + for (vector::const_iterator I = List.begin(); I != List.end(); ++I) { - // override the progress line (sledgehammer) - static const char* clear_screen_below_cursor = "\033[J"; - std::cout << clear_screen_below_cursor; - std::flush(std::cout); + if((*I).Pkg.end() == true) + continue; + + string const name = (*I).Pkg.FullName(); + PackageOpsDone[name] = 0; + for(int i=0; (DpkgStatesOpMap[(*I).Op][i]).state != NULL; ++i) + { + PackageOps[name].push_back(DpkgStatesOpMap[(*I).Op][i]); + PackagesTotal++; + } } } + /*}}}*/ +#if (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR < 13) +bool pkgDPkgPM::Go(int StatusFd) +{ + APT::Progress::PackageManager *progress = NULL; + if (StatusFd == -1) + progress = APT::Progress::PackageManagerProgressFactory(); + else + progress = new APT::Progress::PackageManagerProgressFd(StatusFd); + + return GoNoABIBreak(progress); +} +#endif + void pkgDPkgPM::StartPtyMagic() + { + // setup the pty and stuff + struct winsize win; + + // if tcgetattr does not return zero there was a error + // and we do not do any pty magic + _error->PushToStack(); + if (tcgetattr(STDOUT_FILENO, &d->tt) == 0) + { + ioctl(1, TIOCGWINSZ, (char *)&win); - d->nr_terminal_rows = win.ws_row; + if (openpty(&d->master, &d->slave, NULL, &d->tt, &win) < 0) + { + _error->Errno("openpty", _("Can not write log (%s)"), _("Is /dev/pts mounted?")); + d->master = d->slave = -1; + } else { + struct termios rtt; + rtt = d->tt; + cfmakeraw(&rtt); + rtt.c_lflag &= ~ECHO; + rtt.c_lflag |= ISIG; + // block SIGTTOU during tcsetattr to prevent a hang if + // the process is a member of the background process group + // http://www.opengroup.org/onlinepubs/000095399/functions/tcsetattr.html + sigemptyset(&d->sigmask); + sigaddset(&d->sigmask, SIGTTOU); + sigprocmask(SIG_BLOCK,&d->sigmask, &d->original_sigmask); + tcsetattr(0, TCSAFLUSH, &rtt); + sigprocmask(SIG_SETMASK, &d->original_sigmask, 0); + } + } + // complain only if stdout is either a terminal (but still failed) or is an invalid + // descriptor otherwise we would complain about redirection to e.g. /dev/null as well. + else if (isatty(STDOUT_FILENO) == 1 || errno == EBADF) + _error->Errno("tcgetattr", _("Can not write log (%s)"), _("Is stdout a terminal?")); + + if (_error->PendingError() == true) + _error->DumpErrors(std::cerr); + _error->RevertToStack(); - - // setup terminal - SetupTerminalScrollArea(d->nr_terminal_rows); + } + + void pkgDPkgPM::StopPtyMagic() + { + if(d->slave > 0) + close(d->slave); + if(d->master >= 0) + { + tcsetattr(0, TCSAFLUSH, &d->tt); + close(d->master); + } + } + // DPkgPM::Go - Run the sequence /*{{{*/ // --------------------------------------------------------------------- /* This globs the operations and calls dpkg - * - * If it is called with "OutStatusFd" set to a valid file descriptor - * apt will report the install progress over this fd. It maps the - * dpkg states a package goes through to human readable (and i10n-able) + * + * If it is called with a progress object apt will report the install + * progress to this object. It maps the dpkg states a package goes + * through to human readable (and i10n-able) * names and calculates a percentage for each step. -*/ -bool pkgDPkgPM::Go(int OutStatusFd) + */ +#if (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR >= 13) +bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress) +#else +bool pkgDPkgPM::GoNoABIBreak(APT::Progress::PackageManager *progress) +#endif { pkgPackageManager::SigINTStop = false; + d->progress = progress; // Generate the base argument list for dpkg - std::vector Args; unsigned long StartSize = 0; - string Tmp = _config->Find("Dir::Bin::dpkg","dpkg"); - { - string const dpkgChrootDir = _config->FindDir("DPkg::Chroot-Directory", "/"); - size_t dpkgChrootLen = dpkgChrootDir.length(); - if (dpkgChrootDir != "/" && Tmp.find(dpkgChrootDir) == 0) - { - if (dpkgChrootDir[dpkgChrootLen - 1] == '/') - --dpkgChrootLen; - Tmp = Tmp.substr(dpkgChrootLen); - } - } - Args.push_back(Tmp.c_str()); - StartSize += Tmp.length(); + std::vector Args; + std::string DpkgExecutable = getDpkgExecutable(); + Args.push_back(DpkgExecutable.c_str()); + StartSize += DpkgExecutable.length(); // Stick in any custom dpkg options Configuration::Item const *Opts = _config->Tree("DPkg::Options"); @@@ -1073,8 -1187,6 +1135,6 @@@ fd_set rfds; struct timespec tv; - sigset_t sigmask; - sigset_t original_sigmask; unsigned int const MaxArgs = _config->FindI("Dpkg::MaxArgs",8*1024); unsigned int const MaxArgBytes = _config->FindI("Dpkg::MaxArgBytes",32*1024); @@@ -1093,8 -1205,54 +1153,8 @@@ if (_config->FindB("DPkg::ConfigurePending", SmartConf) == true) List.push_back(Item(Item::ConfigurePending, PkgIterator())); - // map the dpkg states to the operations that are performed - // (this is sorted in the same way as Item::Ops) - static const struct DpkgState DpkgStatesOpMap[][7] = { - // Install operation - { - {"half-installed", N_("Preparing %s")}, - {"unpacked", N_("Unpacking %s") }, - {NULL, NULL} - }, - // Configure operation - { - {"unpacked",N_("Preparing to configure %s") }, - {"half-configured", N_("Configuring %s") }, - { "installed", N_("Installed %s")}, - {NULL, NULL} - }, - // Remove operation - { - {"half-configured", N_("Preparing for removal of %s")}, - {"half-installed", N_("Removing %s")}, - {"config-files", N_("Removed %s")}, - {NULL, NULL} - }, - // Purge operation - { - {"config-files", N_("Preparing to completely remove %s")}, - {"not-installed", N_("Completely removed %s")}, - {NULL, NULL} - }, - }; - - // init the PackageOps map, go over the list of packages that - // that will be [installed|configured|removed|purged] and add - // them to the PackageOps map (the dpkg states it goes through) - // and the PackageOpsTranslations (human readable strings) - for (vector::const_iterator I = List.begin(); I != List.end(); ++I) - { - if((*I).Pkg.end() == true) - continue; - - string const name = (*I).Pkg.FullName(); - PackageOpsDone[name] = 0; - for(int i=0; (DpkgStatesOpMap[(*I).Op][i]).state != NULL; ++i) - { - PackageOps[name].push_back(DpkgStatesOpMap[(*I).Op][i]); - PackagesTotal++; - } - } + // for the progress + BuildPackagesProgressMap(); d->stdin_is_dev_null = false; @@@ -1116,7 -1274,10 +1176,13 @@@ dpkgMultiArch = true; } - // go over each item + // start pty magic before the loop + StartPtyMagic(); + ++ // Tell the progress that its starting and fork dpkg ++ d->progress->Start(); ++ + // this loop is runs once per dpkg operation vector::const_iterator I = List.begin(); while (I != List.end()) { @@@ -1239,7 -1400,7 +1305,7 @@@ { if((*I).Pkg.end() == true) continue; - if (I->Op == Item::Configure && disappearedPkgs.find(I->Pkg.Name()) != disappearedPkgs.end()) + if (I->Op == Item::Configure && disappearedPkgs.find(I->Pkg.FullName(true)) != disappearedPkgs.end()) continue; // We keep this here to allow "smooth" transitions from e.g. multiarch dpkg/ubuntu to dpkg/debian if (dpkgMultiArch == false && (I->Pkg.Arch() == nativeArch || @@@ -1309,67 -1470,33 +1375,20 @@@ // ignore SIGHUP as well (debian #463030) sighandler_t old_SIGHUP = signal(SIGHUP,SIG_IGN); - struct termios tt; - struct winsize win; - int master = -1; - int slave = -1; - - // if tcgetattr does not return zero there was a error - // and we do not do any pty magic - _error->PushToStack(); - if (tcgetattr(STDOUT_FILENO, &tt) == 0) - { - ioctl(STDOUT_FILENO, TIOCGWINSZ, (char *)&win); - if (openpty(&master, &slave, NULL, &tt, &win) < 0) - { - _error->Errno("openpty", _("Can not write log (%s)"), _("Is /dev/pts mounted?")); - master = slave = -1; - } else { - struct termios rtt; - rtt = tt; - cfmakeraw(&rtt); - rtt.c_lflag &= ~ECHO; - rtt.c_lflag |= ISIG; - // block SIGTTOU during tcsetattr to prevent a hang if - // the process is a member of the background process group - // http://www.opengroup.org/onlinepubs/000095399/functions/tcsetattr.html - sigemptyset(&sigmask); - sigaddset(&sigmask, SIGTTOU); - sigprocmask(SIG_BLOCK,&sigmask, &original_sigmask); - tcsetattr(0, TCSAFLUSH, &rtt); - sigprocmask(SIG_SETMASK, &original_sigmask, 0); - } - } - // complain only if stdout is either a terminal (but still failed) or is an invalid - // descriptor otherwise we would complain about redirection to e.g. /dev/null as well. - else if (isatty(STDOUT_FILENO) == 1 || errno == EBADF) - _error->Errno("tcgetattr", _("Can not write log (%s)"), _("Is stdout a terminal?")); - - if (_error->PendingError() == true) - _error->DumpErrors(std::cerr); - _error->RevertToStack(); - - // this is the dpkg status-fd, we need to keep it - // Fork dpkg - pid_t Child; -- _config->Set("APT::Keep-Fds::",fd[1]); - - // Tell the progress that its starting and fork dpkg - // FIXME: this is called once per dpkg run which is *too often* - d->progress->Start(); - // send status information that we are about to fork dpkg - if(OutStatusFd > 0) { - ostringstream status; - status << "pmstatus:dpkg-exec:" - << (PackagesDone/float(PackagesTotal)*100.0) - << ":" << _("Running dpkg") - << endl; - FileFd::Write(OutStatusFd, status.str().c_str(), status.str().size()); - } -- - Child = ExecFork(); + pid_t Child = ExecFork(); // This is the child if (Child == 0) { - if(slave >= 0 && master >= 0) + if(d->slave >= 0 && d->master >= 0) { setsid(); - ioctl(slave, TIOCSCTTY, 0); - close(master); - dup2(slave, 0); - dup2(slave, 1); - dup2(slave, 2); - close(slave); + ioctl(d->slave, TIOCSCTTY, 0); + close(d->master); + dup2(d->slave, 0); + dup2(d->slave, 1); + dup2(d->slave, 2); + close(d->slave); } close(fd[0]); // close the read end of the pipe @@@ -1393,6 -1520,7 +1412,7 @@@ if (fcntl(STDIN_FILENO,F_SETFL,Flags & (~(long)O_NONBLOCK)) < 0) _exit(100); } + /* No Job Control Stop Env is a magic dpkg var that prevents it from using sigstop */ putenv((char *)"DPKG_NO_TSTP=yes"); @@@ -1415,12 -1543,9 +1435,9 @@@ int const _dpkgin = fd[0]; close(fd[1]); // close the write end of the pipe - if(slave > 0) - close(slave); - // setups fds - sigemptyset(&sigmask); - sigprocmask(SIG_BLOCK,&sigmask,&original_sigmask); + sigemptyset(&d->sigmask); + sigprocmask(SIG_BLOCK,&d->sigmask,&d->original_sigmask); /* free vectors (and therefore memory) as we don't need the included data anymore */ for (std::vector::const_iterator p = Packages.begin(); @@@ -1449,21 -1574,18 +1466,18 @@@ // wait for input or output here FD_ZERO(&rfds); - if (master >= 0 && !d->stdin_is_dev_null) + if (d->master >= 0 && !d->stdin_is_dev_null) FD_SET(0, &rfds); FD_SET(_dpkgin, &rfds); - if(master >= 0) - FD_SET(master, &rfds); - tv.tv_sec = 0; - tv.tv_nsec = d->progress->GetPulseInterval(); - select_ret = pselect(max(master, _dpkgin)+1, &rfds, NULL, NULL, - &tv, &original_sigmask); + if(d->master >= 0) + FD_SET(d->master, &rfds); + tv.tv_sec = 1; + tv.tv_nsec = 0; + select_ret = pselect(max(d->master, _dpkgin)+1, &rfds, NULL, NULL, + &tv, &d->original_sigmask); if (select_ret < 0 && (errno == EINVAL || errno == ENOSYS)) - select_ret = racy_pselect(max(master, _dpkgin)+1, &rfds, NULL, - NULL, &tv, &original_sigmask); - - d->progress->Pulse(); - + select_ret = racy_pselect(max(d->master, _dpkgin)+1, &rfds, NULL, + NULL, &tv, &d->original_sigmask); if (select_ret == 0) continue; else if (select_ret < 0 && errno == EINTR) @@@ -1474,12 -1596,12 +1488,12 @@@ continue; } - if(master >= 0 && FD_ISSET(master, &rfds)) - DoTerminalPty(master); - if(master >= 0 && FD_ISSET(0, &rfds)) - DoStdin(master); + if(d->master >= 0 && FD_ISSET(d->master, &rfds)) + DoTerminalPty(d->master); + if(d->master >= 0 && FD_ISSET(0, &rfds)) + DoStdin(d->master); if(FD_ISSET(_dpkgin, &rfds)) - DoDpkgStatusFd(_dpkgin, OutStatusFd); + DoDpkgStatusFd(_dpkgin); } close(_dpkgin); @@@ -1488,13 -1610,6 +1502,6 @@@ signal(SIGINT,old_SIGINT); signal(SIGHUP,old_SIGHUP); - - if(master >= 0) - { - tcsetattr(0, TCSAFLUSH, &tt); - close(master); - } - // Check for an error code. if (WIFEXITED(Status) == 0 || WEXITSTATUS(Status) != 0) { @@@ -1519,15 -1634,19 +1526,15 @@@ if(stopOnError) { CloseLog(); - CleanupTerminal(); + d->progress->Stop(); return false; } } } -- CloseLog(); -- // dpkg is done at this point - if(_config->FindB("DPkgPM::Progress", false) == true) - SendTerminalProgress(100); - - CleanupTerminal(); + d->progress->Stop(); + StopPtyMagic(); ++ CloseLog(); if (pkgPackageManager::SigINTStop) _error->Warning(_("Operation was interrupted before it could finish")); diff --combined apt-pkg/deb/dpkgpm.h index 50b5d609b,5551b4383..06318d94f --- a/apt-pkg/deb/dpkgpm.h +++ b/apt-pkg/deb/dpkgpm.h @@@ -15,7 -15,6 +15,7 @@@ #include #include #include +#include #ifndef APT_8_CLEANER_HEADERS using std::vector; @@@ -24,7 -23,6 +24,7 @@@ using std::map class pkgDPkgPMPrivate; + class pkgDPkgPM : public pkgPackageManager { private: @@@ -85,12 -83,11 +85,12 @@@ __deprecated bool SendV2Pkgs(FILE *F); bool SendPkgsInfo(FILE * const F, unsigned int const &Version); void WriteHistoryTag(std::string const &tag, std::string value); + std::string ExpandShortPackageName(pkgDepCache &Cache, + const std::string &short_pkgname); // Terminal progress void SetupTerminalScrollArea(int nr_scrolled_rows); void SendTerminalProgress(float percentage); - void CleanupTerminal(); // apport integration void WriteApportReport(const char *pkgpath, const char *errormsg); @@@ -99,36 -96,20 +99,38 @@@ bool OpenLog(); bool CloseLog(); + // helper + void BuildPackagesProgressMap(); + void StartPtyMagic(); + void StopPtyMagic(); // input processing void DoStdin(int master); void DoTerminalPty(int master); - void DoDpkgStatusFd(int statusfd, int OutStatusFd); - void ProcessDpkgStatusLine(int OutStatusFd, char *line); + void DoDpkgStatusFd(int statusfd); + void ProcessDpkgStatusLine(char *line); +#if (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR < 13) + void DoDpkgStatusFd(int statusfd, int unused) { + DoDpkgStatusFd(statusfd); + } + void ProcessDpkgStatusLine(int unused, char *line) { + ProcessDpkgStatusLine(line); + } +#endif + // The Actuall installation implementation virtual bool Install(PkgIterator Pkg,std::string File); virtual bool Configure(PkgIterator Pkg); virtual bool Remove(PkgIterator Pkg,bool Purge = false); + +#if (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR >= 13) + virtual bool Go(APT::Progress::PackageManager *progress); +#else virtual bool Go(int StatusFd=-1); + bool GoNoABIBreak(APT::Progress::PackageManager *progress); +#endif + virtual void Reset(); public: