class pkgDPkgPMPrivate
{
public:
- pkgDPkgPMPrivate() : dpkgbuf_pos(0), term_out(NULL), history_out(NULL)
+ pkgDPkgPMPrivate() : stdin_is_dev_null(false), dpkgbuf_pos(0),
+ term_out(NULL), history_out(NULL)
{
+ dpkgbuf[0] = '\0';
}
bool stdin_is_dev_null;
// the buffer we use for the dpkg status-fd reading
{
if (!FileExists("/usr/bin/ionice"))
return false;
- pid_t Process = ExecFork();
+ pid_t Process = ExecFork();
if (Process == 0)
{
char buf[32];
return ExecWait(Process, "ionice");
}
+// dpkgChrootDirectory - chrooting for dpkg if needed /*{{{*/
+static void dpkgChrootDirectory()
+{
+ std::string const chrootDir = _config->FindDir("DPkg::Chroot-Directory");
+ if (chrootDir == "/")
+ return;
+ std::cerr << "Chrooting into " << chrootDir << std::endl;
+ if (chroot(chrootDir.c_str()) != 0)
+ _exit(100);
+}
+ /*}}}*/
+
+
+// FindNowVersion - Helper to find a Version in "now" state /*{{{*/
+// ---------------------------------------------------------------------
+/* This is helpful when a package is no longer installed but has residual
+ * config files
+ */
+static
+pkgCache::VerIterator FindNowVersion(const pkgCache::PkgIterator &Pkg)
+{
+ pkgCache::VerIterator Ver;
+ for (Ver = Pkg.VersionList(); Ver.end() == false; Ver++)
+ {
+ pkgCache::VerFileIterator Vf = Ver.FileList();
+ pkgCache::PkgFileIterator F = Vf.File();
+ for (F = Vf.File(); F.end() == false; F++)
+ {
+ if (F && F.Archive())
+ {
+ if (strcmp(F.Archive(), "now"))
+ return Ver;
+ }
+ }
+ }
+ return Ver;
+}
+ /*}}}*/
+static ssize_t
+retry_write(int fd, const void *buf, size_t count)
+{
+ int Res;
+ ssize_t i = 0;
+ errno = 0;
+ do
+ {
+ Res = write(fd, buf, count);
+ if (Res < 0 && errno == EINTR)
+ continue;
+ if (Res < 0)
+ break;
+ buf = (char *)buf + Res;
+ count -= Res;
+ i += Res;
+ }
+ while (Res > 0 && count > 0);
+ return i;
+}
+
// DPkgPM::pkgDPkgPM - Constructor /*{{{*/
// ---------------------------------------------------------------------
/* */
SetCloseExec(STDIN_FILENO,false);
SetCloseExec(STDERR_FILENO,false);
- if (_config->FindDir("DPkg::Chroot-Directory","/") != "/")
- {
- std::cerr << "Chrooting into "
- << _config->FindDir("DPkg::Chroot-Directory")
- << std::endl;
- if (chroot(_config->FindDir("DPkg::Chroot-Directory","/").c_str()) != 0)
- _exit(100);
- }
-
+ dpkgChrootDirectory();
const char *Args[4];
Args[0] = "/bin/sh";
Args[1] = "-c";
unsigned char input_buf[256] = {0,};
ssize_t len = read(0, input_buf, sizeof(input_buf));
if (len)
- write(master, input_buf, len);
+ retry_write(master, input_buf, len);
else
d->stdin_is_dev_null = true;
}
}
if(len <= 0)
return;
- write(1, term_buf, len);
+ retry_write(1, term_buf, len);
if(d->term_out)
fwrite(term_buf, len, sizeof(char), d->term_out);
}
<< ":" << s
<< endl;
if(OutStatusFd > 0)
- write(OutStatusFd, status.str().c_str(), status.str().size());
+ retry_write(OutStatusFd, status.str().c_str(), status.str().size());
if (Debug == true)
std::clog << "send: '" << status.str() << "'" << endl;
<< ":" << list[3]
<< endl;
if(OutStatusFd > 0)
- write(OutStatusFd, status.str().c_str(), status.str().size());
+ retry_write(OutStatusFd, status.str().c_str(), status.str().size());
if (Debug == true)
std::clog << "send: '" << status.str() << "'" << endl;
pkgFailures++;
<< ":" << list[3]
<< endl;
if(OutStatusFd > 0)
- write(OutStatusFd, status.str().c_str(), status.str().size());
+ retry_write(OutStatusFd, status.str().c_str(), status.str().size());
if (Debug == true)
std::clog << "send: '" << status.str() << "'" << endl;
return;
<< ":" << s
<< endl;
if(OutStatusFd > 0)
- write(OutStatusFd, status.str().c_str(), status.str().size());
+ retry_write(OutStatusFd, status.str().c_str(), status.str().size());
if (Debug == true)
std::clog << "send: '" << status.str() << "'" << endl;
}
*/
bool pkgDPkgPM::Go(int OutStatusFd)
{
+ pkgPackageManager::SigINTStop = false;
+
+ // Generate the base argument list for dpkg
+ std::vector<const char *> 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();
+
+ // Stick in any custom dpkg options
+ Configuration::Item const *Opts = _config->Tree("DPkg::Options");
+ if (Opts != 0)
+ {
+ Opts = Opts->Child;
+ for (; Opts != 0; Opts = Opts->Next)
+ {
+ if (Opts->Value.empty() == true)
+ continue;
+ Args.push_back(Opts->Value.c_str());
+ StartSize += Opts->Value.length();
+ }
+ }
+
+ size_t const BaseArgs = Args.size();
+ // we need to detect if we can qualify packages with the architecture or not
+ Args.push_back("--assert-multi-arch");
+ Args.push_back(NULL);
+
+ pid_t dpkgAssertMultiArch = ExecFork();
+ if (dpkgAssertMultiArch == 0)
+ {
+ dpkgChrootDirectory();
+ // redirect everything to the ultimate sink as we only need the exit-status
+ int const nullfd = open("/dev/null", O_RDONLY);
+ dup2(nullfd, STDIN_FILENO);
+ dup2(nullfd, STDOUT_FILENO);
+ dup2(nullfd, STDERR_FILENO);
+ execvp(Args[0], (char**) &Args[0]);
+ _error->WarningE("dpkgGo", "Can't detect if dpkg supports multi-arch!");
+ _exit(2);
+ }
+
fd_set rfds;
struct timespec tv;
sigset_t sigmask;
// create log
OpenLog();
- // Generate the base argument list for dpkg
- std::vector<const char *> Args;
- unsigned long StartSize = 0;
- string const Tmp = _config->Find("Dir::Bin::dpkg","dpkg");
- Args.push_back(Tmp.c_str());
- StartSize += Tmp.length();
-
- // Stick in any custom dpkg options
- Configuration::Item const *Opts = _config->Tree("DPkg::Options");
- if (Opts != 0)
+ bool dpkgMultiArch = false;
+ if (dpkgAssertMultiArch > 0)
{
- Opts = Opts->Child;
- for (; Opts != 0; Opts = Opts->Next)
+ int Status = 0;
+ while (waitpid(dpkgAssertMultiArch, &Status, 0) != dpkgAssertMultiArch)
{
- if (Opts->Value.empty() == true)
+ if (errno == EINTR)
continue;
- Args.push_back(Opts->Value.c_str());
- StartSize += Opts->Value.length();
+ _error->WarningE("dpkgGo", _("Waited for %s but it wasn't there"), "dpkg --assert-multi-arch");
+ break;
}
+ if (WIFEXITED(Status) == true && WEXITSTATUS(Status) == 0)
+ dpkgMultiArch = true;
}
- size_t const BaseArgs = Args.size();
// this loop is runs once per operation
for (vector<Item>::const_iterator I = List.begin(); I != List.end();)
if (J - I > (signed)MaxArgs)
{
J = I + MaxArgs;
- Args.reserve(MaxArgs + 10);
+ unsigned long const size = MaxArgs + 10;
+ Args.reserve(size);
+ Packages.reserve(size);
}
else
{
- Args.reserve((J - I) + 10);
+ unsigned long const size = (J - I) + 10;
+ Args.reserve(size);
+ Packages.reserve(size);
}
-
int fd[2];
- pipe(fd);
+ if (pipe(fd) != 0)
+ return _error->Errno("pipe","Failed to create IPC pipe to dpkg");
#define ADDARG(X) Args.push_back(X); Size += strlen(X)
#define ADDARGC(X) Args.push_back(X); Size += sizeof(X) - 1
char status_fd_buf[20];
snprintf(status_fd_buf,sizeof(status_fd_buf),"%i", fd[1]);
ADDARG(status_fd_buf);
-
unsigned long const Op = I->Op;
switch (I->Op)
continue;
if (I->Op == Item::Configure && disappearedPkgs.find(I->Pkg.Name()) != disappearedPkgs.end())
continue;
- if (I->Pkg.Arch() == nativeArch || !strcmp(I->Pkg.Arch(), "all"))
+ // We keep this here to allow "smooth" transitions from e.g. multiarch dpkg/ubuntu to dpkg/debian
+ if (dpkgMultiArch == false && (I->Pkg.Arch() == nativeArch || !strcmp(I->Pkg.Arch(), "all")))
{
char const * const name = I->Pkg.Name();
ADDARG(name);
}
else
{
- char * const fullname = strdup(I->Pkg.FullName(false).c_str());
+ pkgCache::VerIterator PkgVer;
+ std::string name = I->Pkg.Name();
+ if (Op == Item::Remove || Op == Item::Purge)
+ {
+ PkgVer = I->Pkg.CurrentVer();
+ if(PkgVer.end() == true)
+ PkgVer = FindNowVersion(I->Pkg);
+ }
+ else
+ PkgVer = Cache[I->Pkg].InstVerIter(Cache);
+ if (PkgVer.end() == false)
+ name.append(":").append(PkgVer.Arch());
+ else
+ _error->Warning("Can not find PkgVer for '%s'", name.c_str());
+ char * const fullname = strdup(name.c_str());
Packages.push_back(fullname);
ADDARG(fullname);
}
<< (PackagesDone/float(PackagesTotal)*100.0)
<< ":" << _("Running dpkg")
<< endl;
- write(OutStatusFd, status.str().c_str(), status.str().size());
+ retry_write(OutStatusFd, status.str().c_str(), status.str().size());
}
Child = ExecFork();
}
close(fd[0]); // close the read end of the pipe
- if (_config->FindDir("DPkg::Chroot-Directory","/") != "/")
- {
- std::cerr << "Chrooting into "
- << _config->FindDir("DPkg::Chroot-Directory")
- << std::endl;
- if (chroot(_config->FindDir("DPkg::Chroot-Directory","/").c_str()) != 0)
- _exit(100);
- }
+ dpkgChrootDirectory();
if (chdir(_config->FindDir("DPkg::Run-Directory","/").c_str()) != 0)
_exit(100);
}
void SigINT(int sig) {
- if (_config->FindB("APT::Immediate-Configure-All",false))
- pkgPackageManager::SigINTStop = true;
-}
+ pkgPackageManager::SigINTStop = true;
+}
/*}}}*/
// pkgDpkgPM::Reset - Dump the contents of the command list /*{{{*/
// ---------------------------------------------------------------------
/* */
void pkgDPkgPM::WriteApportReport(const char *pkgpath, const char *errormsg)
{
+ // If apport doesn't exist or isn't installed do nothing
+ // This e.g. prevents messages in 'universes' without apport
+ pkgCache::PkgIterator apportPkg = Cache.FindPkg("apport");
+ if (apportPkg.end() == true || apportPkg->CurrentVer == 0)
+ return;
+
string pkgname, reportfile, srcpkgname, pkgver, arch;
string::size_type pos;
FILE *report;
if(strstr(strbuf,"Package:") == strbuf)
{
char pkgname[255], version[255];
- if(sscanf(strbuf, "Package: %s %s", pkgname, version) == 2)
+ if(sscanf(strbuf, "Package: %254s %254s", pkgname, version) == 2)
if(strcmp(pkgver.c_str(), version) == 0)
{
fclose(report);