diff options
author | Michael Vogt <michael.vogt@ubuntu.com> | 2005-08-19 15:30:19 +0000 |
---|---|---|
committer | Michael Vogt <michael.vogt@ubuntu.com> | 2005-08-19 15:30:19 +0000 |
commit | 16176b647e76f316ec98f31f6dd806a49d7b8a77 (patch) | |
tree | 442d538ff8e0b54ba8ae60fe95733b0dc56a9576 /apt-pkg/deb/dpkgpm.cc | |
parent | 4a0a786f45a78eb8631c0e2d39d804ab9fdea214 (diff) |
* merged with mainline
Patches applied:
* andrelop@debian.org/apt--translation--0--base-0
tag of apt@packages.debian.org/apt--main--0--patch-79
* andrelop@debian.org/apt--translation--0--patch-1
Sync with Matt version.
* andrelop@debian.org/apt--translation--0--patch-2
Update pt_BR translation
* andrelop@debian.org/apt--translation--0--patch-3
Sync with bubulle's branch.
* apt@packages.debian.org/apt--main--0--patch-88
Change debian/bugscript to use #!/bin/bash (Closes: #313402)
* apt@packages.debian.org/apt--main--0--patch-89
Branch for Debian
* apt@packages.debian.org/apt--main--0--patch-90
Update version in configure
* apt@packages.debian.org/apt--main--0--patch-91
Fix French man page build
* apt@packages.debian.org/apt--main--0--patch-92
Add the current Debian archive signing key
* apt@packages.debian.org/apt--main--0--patch-93
Merge with mvo
* apt@packages.debian.org/apt--main--0--patch-94
Update changelog
* apt@packages.debian.org/apt--main--0--patch-95
Merge Christian's branch
* apt@packages.debian.org/apt--main--0--patch-96
Update changelog
* apt@packages.debian.org/apt--main--0--patch-97
Update priority of apt-utils to important, to match the override file
* apt@packages.debian.org/apt--main--0--patch-98
Install only one keyring on each branch (Closes: #316119)
* apt@packages.debian.org/apt--main--0--patch-99
Finalize 0.6.39
* apt@packages.debian.org/apt--main--0--patch-100
Use debian.org address in mainline
* apt@packages.debian.org/apt--main--0--patch-101
Update pot file
* apt@packages.debian.org/apt--main--0--patch-102
Open 0.6.40
* apt@packages.debian.org/apt--main--0--patch-103
Patch from Jordi Mallach to mark some additional strings for translation
* apt@packages.debian.org/apt--main--0--patch-104
Updated Catalan translation from Jordi Mallach
* apt@packages.debian.org/apt--main--0--patch-105
Merge from bubulle@debian.org--2005/apt--main--0
* apt@packages.debian.org/apt--main--0--patch-106
Restore lost changelog entries
* apt@packages.debian.org/apt--main--0--patch-107
Merge michael.vogt@ubuntu.com--2005/apt--progress-reporting--0
* apt@packages.debian.org/apt--main--0--patch-108
Merge michael.vogt@ubuntu.com--2005/apt--progress-reporting--0
* apt@packages.debian.org/apt--main--0--patch-109
Merge michael.vogt@ubuntu.com--2005/apt--progress-reporting--0
* apt@packages.debian.org/apt--main--0--patch-110
Merge michael.vogt@ubuntu.com--2005/apt--progress-reporting--0
* bubulle@debian.org--2005/apt--main--0--patch-82
Fix permissions
* bubulle@debian.org--2005/apt--main--0--patch-83
French translation spellchecked
* bubulle@debian.org--2005/apt--main--0--patch-84
Spell corrections in German translations
* bubulle@debian.org--2005/apt--main--0--patch-85
Correct some file permissions
* bubulle@debian.org--2005/apt--main--0--patch-86
Correct Hebrew translation
* bubulle@debian.org--2005/apt--main--0--patch-87
Sync Portuguese translation with the POT file
* bubulle@debian.org--2005/apt--main--0--patch-88
Updated Danish translation (not yet complete)
* bubulle@debian.org--2005/apt--main--0--patch-89
Sync with Andre Luis Lopes and Otavio branches
* bubulle@debian.org--2005/apt--main--0--patch-90
Merge with Matt
* bubulle@debian.org--2005/apt--main--0--patch-91
Updated Slovak translation
* bubulle@debian.org--2005/apt--main--0--patch-92
Add apt-key French man page
* bubulle@debian.org--2005/apt--main--0--patch-93
Update Greek translations
* bubulle@debian.org--2005/apt--main--0--patch-94
Merge with Matt
* bubulle@debian.org--2005/apt--main--0--patch-95
Sync PO files with the POT file/French translation update
* michael.vogt@ubuntu.com--2005/apt--mvo--0--patch-22
* added myself to uploaders, changelog is signed with mvo@debian.org and in sync with the debian/experimental upload
* michael.vogt@ubuntu.com--2005/apt--mvo--0--patch-23
* apt-cache show <virtual-pkg> shows all virtual packages instead of nothing (thanks to otavio)
* michael.vogt@ubuntu.com--2005/apt--mvo--0--patch-24
* changelog updated
* michael.vogt@ubuntu.com--2005/apt--mvo--0--patch-25
* make pinning on component work again (we just use the section, as apt-0.6 don't use per-section Release files anymore)
* michael.vogt@ubuntu.com--2005/apt--mvo--0--patch-27
* updated the changelog
* michael.vogt@ubuntu.com--2005/apt--mvo--0--patch-28
* merged with my apt--fixes--0 branch
* michael.vogt@ubuntu.com--2005/apt--mvo--0--patch-29
* added a missing OpProgress::Done() in depCache::Init(), removed the show-virtual-packages patch in apt-cache because matt does not like him :/
* michael.vogt@ubuntu.com--2005/apt--mvo--0--patch-30
* fix a stupid bug in the depcache::Init() code
* michael.vogt@ubuntu.com--2005/apt--mvo--0--patch-31
* merged/removed conflicts with apt--main--0
* michael.vogt@ubuntu.com--2005/apt--mvo--0--patch-32
* merged apt--main and make sure that the po files come from apt--main (because they are more recent)
* michael.vogt@ubuntu.com--2005/apt--progress-reporting--0--base-0
tag of apt@packages.debian.org/apt--main--0--patch-85
* michael.vogt@ubuntu.com--2005/apt--progress-reporting--0--patch-1
* inital proof of concept code, understands what dpkg tells it already
* michael.vogt@ubuntu.com--2005/apt--progress-reporting--0--patch-2
* progress reporting works now
* michael.vogt@ubuntu.com--2005/apt--progress-reporting--0--patch-3
* added "APT::Status-Fd" variable
* michael.vogt@ubuntu.com--2005/apt--progress-reporting--0--patch-4
* do i18n now too
* michael.vogt@ubuntu.com--2005/apt--progress-reporting--0--patch-5
* define N_(x) if it is not defined already
* michael.vogt@ubuntu.com--2005/apt--progress-reporting--0--patch-6
* PackageManager::DoInstall(int status_fd) added (does not break the ABI)
* michael.vogt@ubuntu.com--2005/apt--progress-reporting--0--patch-7
* merged with apt--fixes--0 to make it build again
* michael.vogt@ubuntu.com--2005/apt--progress-reporting--0--patch-8
* added support for "error" and "conffile-prompt" messages from dpkg
* michael.vogt@ubuntu.com--2005/apt--progress-reporting--0--patch-9
merge with main
* michael.vogt@ubuntu.com--2005/apt--progress-reporting--0--patch-10
* use sizeof() for all snprintf() uses; fix a potential line break problem in the status reading code; changed the N_() to _() calls
* michael.vogt@ubuntu.com--2005/apt--progress-reporting--0--patch-11
* added APT::KeepFDs configuration list for file descriptors that apt should leave open (needed for various frontends like debconf, synaptic)
* michael.vogt@ubuntu.com--2005/apt--progress-reporting--0--patch-12
* fixed a API breakage
* michael.vogt@ubuntu.com--2005/apt--progress-reporting--0--patch-13
* doc added, should be releasable now
* michael.vogt@ubuntu.com--2005/apt--progress-reporting--0--patch-14
* merged with apt--main--0
* michael.vogt@ubuntu.com--2005/apt--progress-reporting--0--patch-15
* more source comments, added Debug::DpkgPM debug code to inspect the dpkg<->apt communication, broke the abi (ok with matt)
* michael.vogt@ubuntu.com--2005/apt--progress-reporting--0--patch-16
* the progress reporting has it's own "Debug::pkgDPkgProgressReporting" debug variable now
* michael.vogt@ubuntu.com--2005/apt--progress-reporting--0--patch-17
* merged PackageOps and TranslatedPackageOps into a single Map with the new DpkgState struct
* michael.vogt@ubuntu.com--2005/apt--progress-reporting--0--patch-18
* clear the APT::Keep-Fds configuration when it's no longer needed
* michael.vogt@ubuntu.com--2005/apt--progress-reporting--0--patch-19
* rewrote the reading from dpkg so that it never blocks
* michael.vogt@ubuntu.com--2005/apt--progress-reporting--0--patch-20
* merged the two status arrays into one
* michael.vogt@ubuntu.com--2005/apt--progress-reporting--0--patch-21
* added support for download progress reporting too (for Kamion and base-config)
* michael.vogt@ubuntu.com--2005/apt--progress-reporting--0--patch-22
* ABI break; added Configuration::Clear(string List, {int,string} value) added (to remove a single Value from a list); test/conf_clear.cc added
* michael.vogt@ubuntu.com--2005/apt--progress-reporting--0--patch-23
* remvoed a debug string
* michael.vogt@ubuntu.com--2005/apt--progress-reporting--0--patch-24
* soname changed, fixed a bug in the parsing code when dpkg send the same state more than once (at the end)
* michael.vogt@ubuntu.com--2005/apt--progress-reporting--0--patch-25
* merged with apt@packages.debian.org/apt--main--0, added changelog entry for the 0.6.40.1 upload
* michael.vogt@ubuntu.com--2005/apt--progress-reporting--0--patch-26
* fix a bug when out-of-order states are send from dpkg
* michael.vogt@ubuntu.com--2005/apt--progress-reporting--0--patch-27
* changelog update
* michael.vogt@ubuntu.com--2005/apt--progress-reporting--0--patch-28
* a real changelog entry now
* michael.vogt@ubuntu.com--2005/apt--progress-reporting--0--patch-29
* changelog finalized
* michael.vogt@ubuntu.com--2005/apt--progress-reporting--0--patch-30
* propper (and sane) support for pmerror and pmconffile added
Diffstat (limited to 'apt-pkg/deb/dpkgpm.cc')
-rw-r--r-- | apt-pkg/deb/dpkgpm.cc | 242 |
1 files changed, 216 insertions, 26 deletions
diff --git a/apt-pkg/deb/dpkgpm.cc b/apt-pkg/deb/dpkgpm.cc index 61c48dcbb..fe8fbca74 100644 --- a/apt-pkg/deb/dpkgpm.cc +++ b/apt-pkg/deb/dpkgpm.cc @@ -25,7 +25,11 @@ #include <signal.h> #include <errno.h> #include <stdio.h> -#include <iostream> +#include <sstream> +#include <map> + +#include <config.h> +#include <apti18n.h> /*}}}*/ using namespace std; @@ -325,8 +329,14 @@ bool pkgDPkgPM::RunScriptsWithPkgs(const char *Cnf) /*}}}*/ // DPkgPM::Go - Run the sequence /*{{{*/ // --------------------------------------------------------------------- -/* This globs the operations and calls dpkg */ -bool pkgDPkgPM::Go(int status_fd) +/* 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) + * names and calculates a percentage for each step. +*/ +bool pkgDPkgPM::Go(int OutStatusFd) { unsigned int MaxArgs = _config->FindI("Dpkg::MaxArgs",8*1024); unsigned int MaxArgBytes = _config->FindI("Dpkg::MaxArgBytes",32*1024); @@ -336,7 +346,66 @@ bool pkgDPkgPM::Go(int status_fd) if (RunScriptsWithPkgs("DPkg::Pre-Install-Pkgs") == false) return false; + + // prepare the progress reporting + int Done = 0; + int Total = 0; + // 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[][5] = { + // Install operation + { + {"half-installed", _("Preparing %s")}, + {"unpacked", _("Unpacking %s") }, + {NULL, NULL} + }, + // Configure operation + { + {"unpacked",_("Preparing to configure %s") }, + {"half-configured", _("Configuring %s") }, + { "installed", _("Installed %s")}, + {NULL, NULL} + }, + // Remove operation + { + {"half-configured", _("Preparing for removal of %s")}, + {"half-installed", _("Removing %s")}, + {"config-files", _("Removed %s")}, + {NULL, NULL} + }, + // Purge operation + { + {"config-files", _("Preparing for remove with config %s")}, + {"not-installed", _("Removed with config %s")}, + {NULL, NULL} + }, + }; + // the dpkg states that the pkg will run through, the string is + // the package, the vector contains the dpkg states that the package + // will go through + map<string,vector<struct DpkgState> > PackageOps; + // the dpkg states that are already done; the string is the package + // the int is the state that is already done (e.g. a package that is + // going to be install is already in state "half-installed") + map<string,int> PackageOpsDone; + + // 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<Item>::iterator I = List.begin(); I != List.end();I++) + { + string name = (*I).Pkg.Name(); + PackageOpsDone[name] = 0; + for(int i=0; (DpkgStatesOpMap[(*I).Op][i]).state != NULL; i++) + { + PackageOps[name].push_back(DpkgStatesOpMap[(*I).Op][i]); + Total++; + } + } + + // this loop is runs once per operation for (vector<Item>::iterator I = List.begin(); I != List.end();) { vector<Item>::iterator J = I; @@ -367,16 +436,15 @@ bool pkgDPkgPM::Go(int status_fd) } } - // if we got a status_fd argument, we pass it to apt char status_fd_buf[20]; - if(status_fd > 0) - { - Args[n++] = "--status-fd"; - Size += strlen(Args[n-1]); - snprintf(status_fd_buf,20,"%i",status_fd); - Args[n++] = status_fd_buf; - Size += strlen(Args[n-1]); - } + int fd[2]; + pipe(fd); + + Args[n++] = "--status-fd"; + Size += strlen(Args[n-1]); + snprintf(status_fd_buf,sizeof(status_fd_buf),"%i", fd[1]); + Args[n++] = status_fd_buf; + Size += strlen(Args[n-1]); switch (I->Op) { @@ -449,17 +517,17 @@ bool pkgDPkgPM::Go(int status_fd) it doesn't die but we do! So we must also ignore it */ sighandler_t old_SIGQUIT = signal(SIGQUIT,SIG_IGN); sighandler_t old_SIGINT = signal(SIGINT,SIG_IGN); - - // Fork dpkg + + // Fork dpkg pid_t Child; - if(status_fd > 0) - Child = ExecFork(status_fd); - else - Child = ExecFork(); + _config->Set("APT::Keep-Fds::",fd[1]); + Child = ExecFork(); // This is the child if (Child == 0) { + close(fd[0]); // close the read end of the pipe + if (chdir(_config->FindDir("DPkg::Run-Directory","/").c_str()) != 0) _exit(100); @@ -487,19 +555,141 @@ bool pkgDPkgPM::Go(int status_fd) _exit(100); } + // clear the Keep-Fd again + _config->Clear("APT::Keep-Fds",fd[1]); + // Wait for dpkg int Status = 0; - while (waitpid(Child,&Status,0) != Child) - { - if (errno == EINTR) + + // we read from dpkg here + int _dpkgin = fd[0]; + fcntl(_dpkgin, F_SETFL, O_NONBLOCK); + close(fd[1]); // close the write end of the pipe + + // the read buffers for the communication with dpkg + char line[1024] = {0,}; + char buf[2] = {0,0}; + + // the result of the waitpid call + int res; + + while ((res=waitpid(Child,&Status, WNOHANG)) != Child) { + if(res < 0) { + // FIXME: move this to a function or something, looks ugly here + // error handling, waitpid returned -1 + if (errno == EINTR) + continue; + RunScripts("DPkg::Post-Invoke"); + + // Restore sig int/quit + signal(SIGQUIT,old_SIGQUIT); + signal(SIGINT,old_SIGINT); + return _error->Errno("waitpid","Couldn't wait for subprocess"); + } + + // read a single char, make sure that the read can't block + // (otherwise we may leave zombies) + int len = read(_dpkgin, buf, 1); + + // nothing to read, wait a bit for more + if(len <= 0) + { + usleep(1000); continue; - RunScripts("DPkg::Post-Invoke"); + } + + // sanity check (should never happen) + if(strlen(line) >= sizeof(line)-10) + { + _error->Error("got a overlong line from dpkg: '%s'",line); + line[0]=0; + } + // append to line, check if we got a complete line + strcat(line, buf); + if(buf[0] != '\n') + continue; + + if (_config->FindB("Debug::pkgDPkgProgressReporting",false) == true) + std::clog << "got from dpkg '" << line << "'" << std::endl; + + // the status we output + ostringstream status; + + /* dpkg sends strings like this: + 'status: <pkg>: <pkg qstate>' + errors look like this: + 'status: /var/cache/apt/archives/krecipes_0.8.1-0ubuntu1_i386.deb : error : trying to overwrite `/usr/share/doc/kde/HTML/en/krecipes/krectip.png', which is also in package krecipes-data + and conffile-prompt like this + 'status: conffile-prompt: conffile : 'current-conffile' 'new-conffile' useredited distedited + + */ + char* list[4]; + TokSplitString(':', line, list, 5); + char *pkg = list[1]; + char *action = _strstrip(list[2]); + + if(strncmp(action,"error",strlen("error")) == 0) + { + status << "pmerror:" << list[1] + << ":" << (Done/float(Total)*100.0) + << ":" << list[3] + << endl; + if(OutStatusFd > 0) + write(OutStatusFd, status.str().c_str(), status.str().size()); + line[0]=0; + if (_config->FindB("Debug::pkgDPkgProgressReporting",false) == true) + std::clog << "send: '" << status.str() << "'" << endl; + continue; + } + if(strncmp(action,"conffile",strlen("conffile")) == 0) + { + status << "pmconffile:" << list[1] + << ":" << (Done/float(Total)*100.0) + << ":" << list[3] + << endl; + if(OutStatusFd > 0) + write(OutStatusFd, status.str().c_str(), status.str().size()); + line[0]=0; + if (_config->FindB("Debug::pkgDPkgProgressReporting",false) == true) + std::clog << "send: '" << status.str() << "'" << endl; + continue; + } + + vector<struct DpkgState> &states = PackageOps[pkg]; + const char *next_action = NULL; + if(PackageOpsDone[pkg] < states.size()) + next_action = states[PackageOpsDone[pkg]].state; + // check if the package moved to the next dpkg state + if(next_action && (strcmp(action, next_action) == 0)) + { + // only read the translation if there is actually a next + // action + const char *translation = states[PackageOpsDone[pkg]].str; + char s[200]; + snprintf(s, sizeof(s), translation, pkg); + + // we moved from one dpkg state to a new one, report that + PackageOpsDone[pkg]++; + Done++; + // build the status str + status << "pmstatus:" << pkg + << ":" << (Done/float(Total)*100.0) + << ":" << s + << endl; + if(OutStatusFd > 0) + write(OutStatusFd, status.str().c_str(), status.str().size()); + if (_config->FindB("Debug::pkgDPkgProgressReporting",false) == true) + std::clog << "send: '" << status.str() << "'" << endl; + + } + if (_config->FindB("Debug::pkgDPkgProgressReporting",false) == true) + std::clog << "(parsed from dpkg) pkg: " << pkg + << " action: " << action << endl; - // Restore sig int/quit - signal(SIGQUIT,old_SIGQUIT); - signal(SIGINT,old_SIGINT); - return _error->Errno("waitpid","Couldn't wait for subprocess"); + // reset the line buffer + line[0]=0; } + close(_dpkgin); // Restore sig int/quit signal(SIGQUIT,old_SIGQUIT); |