summaryrefslogtreecommitdiff
path: root/apt-pkg/deb
diff options
context:
space:
mode:
Diffstat (limited to 'apt-pkg/deb')
-rw-r--r--apt-pkg/deb/dpkgpm.cc102
1 files changed, 95 insertions, 7 deletions
diff --git a/apt-pkg/deb/dpkgpm.cc b/apt-pkg/deb/dpkgpm.cc
index 8938cb3d4..c82a09b09 100644
--- a/apt-pkg/deb/dpkgpm.cc
+++ b/apt-pkg/deb/dpkgpm.cc
@@ -22,6 +22,7 @@
#include <apt-pkg/cacheiterators.h>
#include <apt-pkg/macros.h>
#include <apt-pkg/pkgcache.h>
+#include <apt-pkg/version.h>
#include <errno.h>
#include <fcntl.h>
@@ -36,6 +37,8 @@
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/wait.h>
+#include <sys/types.h>
+#include <dirent.h>
#include <termios.h>
#include <time.h>
#include <unistd.h>
@@ -1221,6 +1224,34 @@ void pkgDPkgPM::StopPtyMagic() /*{{{*/
d->master = -1;
}
}
+ /*}}}*/
+static void cleanUpTmpDir(char * const tmpdir) /*{{{*/
+{
+ if (tmpdir == nullptr)
+ return;
+ DIR * const D = opendir(tmpdir);
+ if (D == nullptr)
+ _error->Errno("opendir", _("Unable to read %s"), tmpdir);
+ else
+ {
+ auto const dfd = dirfd(D);
+ for (struct dirent *Ent = readdir(D); Ent != nullptr; Ent = readdir(D))
+ {
+ if (Ent->d_name[0] == '.')
+ continue;
+#ifdef _DIRENT_HAVE_D_TYPE
+ if (unlikely(Ent->d_type != DT_LNK && Ent->d_type != DT_UNKNOWN))
+ continue;
+#endif
+ if (unlikely(unlinkat(dfd, Ent->d_name, 0) != 0))
+ break;
+ }
+ closedir(D);
+ rmdir(tmpdir);
+ }
+ free(tmpdir);
+}
+ /*}}}*/
// DPkgPM::Go - Run the sequence /*{{{*/
// ---------------------------------------------------------------------
@@ -1276,6 +1307,19 @@ bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress)
if (noopDPkgInvocation == false)
Cache.writeStateFile(NULL);
+ bool dpkg_recursive_install = _config->FindB("dpkg::install::recursive", false);
+ if (_config->FindB("dpkg::install::recursive::force", false) == false)
+ {
+ // dpkg uses a sorted treewalk since that version which enables the workaround to work
+ auto const dpkgpkg = Cache.FindPkg("dpkg");
+ if (likely(dpkgpkg.end() == false && dpkgpkg->CurrentVer != 0))
+ dpkg_recursive_install = Cache.VS().CmpVersion("1.18.5", dpkgpkg.CurrentVer().VerStr()) <= 0;
+ }
+ // no point in doing this dance for a handful of packages only
+ unsigned int const dpkg_recursive_install_min = _config->FindB("dpkg::install::recursive::minimum", 5);
+ // FIXME: workaround for dpkg bug, see our ./test-bug-740843-versioned-up-down-breaks test
+ bool const dpkg_recursive_install_numbered = _config->FindB("dpkg::install::recursive::numbered", true);
+
decltype(List)::const_iterator::difference_type const notconfidx =
_config->FindB("Dpkg::ExplicitLastConfigure", false) ? std::numeric_limits<decltype(notconfidx)>::max() :
std::distance(List.cbegin(), std::find_if_not(List.crbegin(), List.crend(), [](Item const &i) { return i.Op == Item::Configure; }).base());
@@ -1396,17 +1440,47 @@ bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress)
{
ADDARGC("--no-triggers");
}
-#undef ADDARGC
+ char * tmpdir_to_free = nullptr;
// Write in the file or package names
if (I->Op == Item::Install)
{
- for (;I != J && Size < MaxArgBytes; ++I)
+ auto const installsToDo = J - I;
+ if (dpkg_recursive_install == true && dpkg_recursive_install_min < installsToDo)
{
- if (I->File[0] != '/')
- return _error->Error("Internal Error, Pathname to install is not absolute '%s'",I->File.c_str());
- Args.push_back(I->File.c_str());
- Size += I->File.length();
+ std::string tmpdir;
+ strprintf(tmpdir, "%s/apt-dpkg-install-XXXXXX", GetTempDir().c_str());
+ tmpdir_to_free = strndup(tmpdir.data(), tmpdir.length());
+ if (mkdtemp(tmpdir_to_free) == nullptr)
+ return _error->Errno("DPkg::Go", "mkdtemp of %s failed in preparation of calling dpkg unpack", tmpdir_to_free);
+
+ char p = 1;
+ for (auto c = installsToDo - 1; (c = c/10) != 0; ++p);
+ for (unsigned long n = 0; I != J; ++n, ++I)
+ {
+ if (I->File[0] != '/')
+ return _error->Error("Internal Error, Pathname to install is not absolute '%s'",I->File.c_str());
+ auto const file = flNotDir(I->File);
+ std::string linkpath;
+ if (dpkg_recursive_install_numbered)
+ strprintf(linkpath, "%s/%.*lu-%s", tmpdir_to_free, p, n, file.c_str());
+ else
+ strprintf(linkpath, "%s/%s", tmpdir_to_free, file.c_str());
+ if (symlink(I->File.c_str(), linkpath.c_str()) != 0)
+ return _error->Errno("DPkg::Go", "Symlinking %s to %s failed!", I->File.c_str(), linkpath.c_str());
+ }
+ ADDARGC("--recursive");
+ ADDARG(tmpdir_to_free);
+ }
+ else
+ {
+ for (;I != J && Size < MaxArgBytes; ++I)
+ {
+ if (I->File[0] != '/')
+ return _error->Error("Internal Error, Pathname to install is not absolute '%s'",I->File.c_str());
+ Args.push_back(I->File.c_str());
+ Size += I->File.length();
+ }
}
}
else
@@ -1454,6 +1528,7 @@ bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress)
if (oldSize == Size)
continue;
}
+#undef ADDARGC
#undef ADDARG
J = I;
@@ -1470,6 +1545,7 @@ bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress)
Packages.clear();
close(fd[0]);
close(fd[1]);
+ cleanUpTmpDir(tmpdir_to_free);
continue;
}
Args.push_back(NULL);
@@ -1605,6 +1681,8 @@ bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress)
signal(SIGINT,old_SIGINT);
signal(SIGHUP,old_SIGHUP);
+ cleanUpTmpDir(tmpdir_to_free);
+
if (waitpid_failure == true)
{
strprintf(d->dpkg_error, "Sub-process %s couldn't be waited for.",Args[0]);
@@ -1775,7 +1853,17 @@ void pkgDPkgPM::WriteApportReport(const char *pkgpath, const char *errormsg)
// find the package version and source package name
pkgCache::PkgIterator Pkg = Cache.FindPkg(pkgname);
if (Pkg.end() == true)
- return;
+ {
+ if (pos == std::string::npos || _config->FindB("dpkg::install::recursive::numbered", true) == false)
+ return;
+ auto const dash = pkgname.find_first_not_of("0123456789");
+ if (dash == std::string::npos || pkgname[dash] != '-')
+ return;
+ pkgname.erase(0, dash + 1);
+ Pkg = Cache.FindPkg(pkgname);
+ if (Pkg.end() == true)
+ return;
+ }
pkgCache::VerIterator Ver = Cache.GetCandidateVersion(Pkg);
if (Ver.end() == true)
return;