Browse Source

implement a public pkgSystem::MultiArchSupported

Some codepaths need to check if the system (in our case usually dpkg)
supports MultiArch or not. We had copy-pasted the check so far into
these paths, but having it as a system check is better for reusability.
debian/1.8.y
David Kalnischkies 7 years ago
parent
commit
8d6d3f00b1
  1. 93
      apt-pkg/deb/debsystem.cc
  2. 5
      apt-pkg/deb/debsystem.h
  3. 92
      apt-pkg/deb/dpkgpm.cc
  4. 9
      apt-pkg/pkgsystem.cc
  5. 13
      apt-pkg/pkgsystem.h
  6. 37
      cmdline/apt-mark.cc

93
apt-pkg/deb/debsystem.cc

@ -22,6 +22,8 @@
#include <apt-pkg/pkgcache.h>
#include <apt-pkg/cacheiterators.h>
#include <algorithm>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
@ -30,6 +32,10 @@
#include <unistd.h>
#include <dirent.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <apti18n.h>
/*}}}*/
@ -250,3 +256,90 @@ bool debSystem::FindIndex(pkgCache::PkgFileIterator File,
return false;
}
/*}}}*/
std::string debSystem::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;
}
/*}}}*/
std::vector<std::string> debSystem::GetDpkgBaseCommand() /*{{{*/
{
// Generate the base argument list for dpkg
std::vector<std::string> Args = { GetDpkgExecutable() };
// 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);
}
}
return Args;
}
/*}}}*/
void debSystem::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);
if (chdir("/") != 0)
_exit(100);
}
/*}}}*/
bool debSystem::SupportsMultiArch() /*{{{*/
{
// Generate the base argument list for dpkg
std::vector<std::string> const Args = GetDpkgBaseCommand();
std::vector<const char *> cArgs(Args.size(), NULL);
std::transform(Args.begin(), Args.end(), cArgs.begin(), [](std::string const &s) { return s.c_str(); });
// we need to detect if we can qualify packages with the architecture or not
cArgs.push_back("--assert-multi-arch");
cArgs.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(cArgs[0], (char**) &cArgs[0]);
_error->WarningE("dpkgGo", "Can't detect if dpkg supports multi-arch!");
_exit(2);
}
if (dpkgAssertMultiArch > 0)
{
int Status = 0;
while (waitpid(dpkgAssertMultiArch, &Status, 0) != dpkgAssertMultiArch)
{
if (errno == EINTR)
continue;
_error->WarningE("dpkgGo", _("Waited for %s but it wasn't there"), "dpkg --assert-multi-arch");
break;
}
if (WIFEXITED(Status) == true && WEXITSTATUS(Status) == 0)
return true;
}
return false;
}
/*}}}*/

5
apt-pkg/deb/debsystem.h

@ -45,6 +45,11 @@ class debSystem : public pkgSystem
debSystem();
virtual ~debSystem();
APT_HIDDEN static std::string GetDpkgExecutable();
APT_HIDDEN static std::vector<std::string> GetDpkgBaseCommand();
APT_HIDDEN static void DpkgChrootDirectory();
APT_HIDDEN static bool SupportsMultiArch();
};
extern debSystem debSys;

92
apt-pkg/deb/dpkgpm.cc

@ -14,6 +14,7 @@
#include <apt-pkg/configuration.h>
#include <apt-pkg/depcache.h>
#include <apt-pkg/dpkgpm.h>
#include <apt-pkg/debsystem.h>
#include <apt-pkg/error.h>
#include <apt-pkg/fileutl.h>
#include <apt-pkg/install-progress.h>
@ -162,35 +163,6 @@ 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()
{
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);
if (chdir("/") != 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
@ -466,7 +438,7 @@ bool pkgDPkgPM::RunScriptsWithPkgs(const char *Cnf)
strprintf(hookfd, "%d", InfoFD);
setenv("APT_HOOK_INFO_FD", hookfd.c_str(), 1);
dpkgChrootDirectory();
debSystem::DpkgChrootDirectory();
const char *Args[4];
Args[0] = "/bin/sh";
Args[1] = "-c";
@ -1225,44 +1197,13 @@ bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress)
d->progress = progress;
// Generate the base argument list for dpkg
unsigned long StartSize = 0;
std::vector<const char *> 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");
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();
}
}
std::vector<std::string> const sArgs = debSystem::GetDpkgBaseCommand();
std::vector<const char *> Args(sArgs.size(), NULL);
std::transform(sArgs.begin(), sArgs.end(), Args.begin(),
[](std::string const &s) { return s.c_str(); });
unsigned long long const StartSize = std::accumulate(sArgs.begin(), sArgs.end(), 0,
[](unsigned long long const i, std::string const &s) { return i + s.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;
@ -1298,20 +1239,7 @@ bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress)
// create log
OpenLog();
bool dpkgMultiArch = false;
if (dpkgAssertMultiArch > 0)
{
int Status = 0;
while (waitpid(dpkgAssertMultiArch, &Status, 0) != dpkgAssertMultiArch)
{
if (errno == EINTR)
continue;
_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;
}
bool dpkgMultiArch = debSystem::SupportsMultiArch();
// start pty magic before the loop
StartPtyMagic();
@ -1528,7 +1456,7 @@ bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress)
SetupSlavePtyMagic();
close(fd[0]); // close the read end of the pipe
dpkgChrootDirectory();
debSystem::DpkgChrootDirectory();
if (chdir(_config->FindDir("DPkg::Run-Directory","/").c_str()) != 0)
_exit(100);

9
apt-pkg/pkgsystem.cc

@ -12,6 +12,7 @@
// Include Files /*{{{*/
#include<config.h>
#include <apt-pkg/debsystem.h>
#include <apt-pkg/pkgsystem.h>
#include <apt-pkg/macros.h>
@ -46,5 +47,13 @@ APT_PURE pkgSystem *pkgSystem::GetSystem(const char *Label)
return 0;
}
/*}}}*/
bool pkgSystem::MultiArchSupported() const /*{{{*/
{
debSystem const * const deb = dynamic_cast<debSystem const *>(this);
if (deb != NULL)
return deb->SupportsMultiArch();
return true;
}
/*}}}*/
pkgSystem::~pkgSystem() {}

13
apt-pkg/pkgsystem.h

@ -92,6 +92,19 @@ class pkgSystem
return 0;
};
//FIXME: these methods should be virtual
/** does this system has support for MultiArch?
*
* Systems supporting only single arch (not systems which are single arch)
* are considered legacy systems and support for it will likely degrade over
* time.
*
* The default implementation returns always \b true.
*
* @return \b true if the system supports MultiArch, \b false if not.
*/
bool MultiArchSupported() const;
pkgSystem(char const * const Label, pkgVersioningSystem * const VS);
virtual ~pkgSystem();
private:

37
cmdline/apt-mark.cc

@ -201,28 +201,7 @@ static bool DoHold(CommandLine &CmdL)
Args.push_back(Opts->Value.c_str());
}
}
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)
{
std::string const chrootDir = _config->FindDir("DPkg::Chroot-Directory");
// 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);
if (chrootDir != "/" && chroot(chrootDir.c_str()) != 0 && chdir("/") != 0)
_error->WarningE("getArchitecture", "Couldn't chroot into %s for dpkg --assert-multi-arch", chrootDir.c_str());
execvp(Args[0], (char**) &Args[0]);
_error->WarningE("dpkgGo", "Can't detect if dpkg supports multi-arch!");
_exit(2);
}
APT::PackageList pkgset = APT::PackageList::FromCommandLine(CacheFile, CmdL.FileList + 1);
if (pkgset.empty() == true)
@ -244,21 +223,6 @@ static bool DoHold(CommandLine &CmdL)
++Pkg;
}
bool dpkgMultiArch = false;
if (dpkgAssertMultiArch > 0)
{
int Status = 0;
while (waitpid(dpkgAssertMultiArch, &Status, 0) != dpkgAssertMultiArch)
{
if (errno == EINTR)
continue;
_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;
}
if (pkgset.empty() == true)
return true;
@ -359,6 +323,7 @@ static bool DoHold(CommandLine &CmdL)
_exit(2);
}
bool const dpkgMultiArch = _system->MultiArchSupported();
FILE* dpkg = fdopen(external[1], "w");
for (APT::PackageList::iterator Pkg = pkgset.begin(); Pkg != pkgset.end(); ++Pkg)
{

Loading…
Cancel
Save