summaryrefslogtreecommitdiff
path: root/apt-pkg
diff options
context:
space:
mode:
Diffstat (limited to 'apt-pkg')
-rw-r--r--apt-pkg/aptconfiguration.cc61
-rw-r--r--apt-pkg/aptconfiguration.h7
-rw-r--r--apt-pkg/cacheiterators.h14
-rw-r--r--apt-pkg/deb/deblistparser.cc7
-rw-r--r--apt-pkg/pkgcache.h12
-rw-r--r--apt-pkg/pkgcachegen.cc4
-rw-r--r--apt-pkg/policy.cc48
-rw-r--r--apt-pkg/policy.h3
-rw-r--r--apt-pkg/tagfile-keys.list1
9 files changed, 152 insertions, 5 deletions
diff --git a/apt-pkg/aptconfiguration.cc b/apt-pkg/aptconfiguration.cc
index 61e53ec3a..b3b423fdc 100644
--- a/apt-pkg/aptconfiguration.cc
+++ b/apt-pkg/aptconfiguration.cc
@@ -480,4 +480,65 @@ std::string const Configuration::getBuildProfilesString() {
return list;
}
/*}}}*/
+
+// getMachineID - supported data.tar extensions /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+std::string const Configuration::getMachineID()
+{
+ std::string id = _config->Find("APT::Machine-ID");
+
+ if (id.empty())
+ {
+ std::string file = _config->FindFile("Dir::Etc::machine-id");
+
+ if (file.empty())
+ {
+ file = flCombine(_config->FindDir("Dir::Etc"), "../machine-id");
+ }
+ FileFd fd;
+ _error->PushToStack();
+
+ if (not OpenConfigurationFileFd(file, fd) || not fd.ReadLine(id))
+ {
+ if (_config->FindB("Debug::Phasing", false))
+ {
+ _error->DumpErrors(std::clog);
+ }
+ }
+
+ _error->RevertToStack();
+ }
+
+ return id;
+}
+ /*}}}*/
+// isChroot - whether we are inside a chroot /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool Configuration::isChroot()
+{
+ static struct once
+ {
+ bool res = false;
+ once()
+ {
+ pid_t child = ExecFork();
+ if (child == 0)
+ {
+ auto binary = _config->FindFile("Dir::Bin::ischroot", "/usr/bin/ischroot");
+ const char *const Args[] = {
+ binary.c_str(),
+ nullptr};
+ execvp(Args[0], const_cast<char **>(Args));
+ _exit(127);
+ }
+
+ res = ExecWait(child, "ischroot", true);
+ }
+ } once;
+
+ return once.res;
+}
+ /*}}}*/
}
diff --git a/apt-pkg/aptconfiguration.h b/apt-pkg/aptconfiguration.h
index 2cb2d823a..bbeb156b9 100644
--- a/apt-pkg/aptconfiguration.h
+++ b/apt-pkg/aptconfiguration.h
@@ -122,7 +122,12 @@ namespace Configuration { /*{{{*/
APT_PUBLIC std::vector<std::string> const getBuildProfiles();
/** \return Return a comma-separated list of enabled build profile specifications */
APT_PUBLIC std::string const getBuildProfilesString();
- /*}}}*/
+
+ std::string const getMachineID();
+
+ /** \return Whether we are running in a chroot */
+ bool isChroot();
+ /*}}}*/
}
/*}}}*/
}
diff --git a/apt-pkg/cacheiterators.h b/apt-pkg/cacheiterators.h
index 1b049b6e5..6261b5089 100644
--- a/apt-pkg/cacheiterators.h
+++ b/apt-pkg/cacheiterators.h
@@ -242,6 +242,20 @@ class APT_PUBLIC pkgCache::VerIterator : public Iterator<Version, VerIterator> {
bool Automatic() const;
VerFileIterator NewestFile() const;
+#ifdef APT_COMPILING_APT
+ inline unsigned int PhasedUpdatePercentage() const
+ {
+ return (static_cast<Version::Extra *>(Owner->Map.Data()) + S->d)->PhasedUpdatePercentage;
+ }
+ inline bool PhasedUpdatePercentage(unsigned int percentage)
+ {
+ if (percentage > 100)
+ return false;
+ (static_cast<Version::Extra *>(Owner->Map.Data()) + S->d)->PhasedUpdatePercentage = static_cast<uint8_t>(percentage);
+ return true;
+ }
+#endif
+
inline VerIterator(pkgCache &Owner,Version *Trg = 0) : Iterator<Version, VerIterator>(Owner, Trg) {
if (S == 0)
S = OwnerPointer();
diff --git a/apt-pkg/deb/deblistparser.cc b/apt-pkg/deb/deblistparser.cc
index 95f6f6fc8..b5c9c066e 100644
--- a/apt-pkg/deb/deblistparser.cc
+++ b/apt-pkg/deb/deblistparser.cc
@@ -338,6 +338,13 @@ bool debListParser::UsePackage(pkgCache::PkgIterator &Pkg,
else if (std::find(forceImportant.begin(), forceImportant.end(), Pkg.Name()) != forceImportant.end())
Pkg->Flags |= pkgCache::Flag::Important;
+ auto phased = Section.FindULL(pkgTagSection::Key::Phased_Update_Percentage, 100);
+ if (phased != 100)
+ {
+ if (not Ver.PhasedUpdatePercentage(phased))
+ _error->Warning("Ignoring invalid Phased-Update-Percentage value");
+ }
+
if (ParseStatus(Pkg,Ver) == false)
return false;
return true;
diff --git a/apt-pkg/pkgcache.h b/apt-pkg/pkgcache.h
index 6c6a4664e..55baa3cef 100644
--- a/apt-pkg/pkgcache.h
+++ b/apt-pkg/pkgcache.h
@@ -623,6 +623,8 @@ struct pkgCache::DescFile
or handled as separate versions based on the Hash value. */
struct pkgCache::Version
{
+ struct Extra;
+
/** \brief complete version string */
map_stringitem_t VerStr;
/** \brief section this version is filled in */
@@ -688,8 +690,16 @@ struct pkgCache::Version
map_pointer<Version> NextInSource;
/** \brief Private pointer */
- map_pointer<void> d;
+ map_pointer<Extra> d;
};
+
+#ifdef APT_COMPILING_APT
+/// \brief Extra information for packages. APT-internal use only.
+struct pkgCache::Version::Extra
+{
+ uint8_t PhasedUpdatePercentage;
+};
+#endif
/*}}}*/
// Description structure /*{{{*/
/** \brief datamember of a linked list of available description for a version */
diff --git a/apt-pkg/pkgcachegen.cc b/apt-pkg/pkgcachegen.cc
index d02c49f03..bd81ca0f5 100644
--- a/apt-pkg/pkgcachegen.cc
+++ b/apt-pkg/pkgcachegen.cc
@@ -873,6 +873,10 @@ map_pointer<pkgCache::Version> pkgCacheGenerator::NewVersion(pkgCache::VerIterat
// Fill it in
Ver = pkgCache::VerIterator(Cache,Cache.VerP + Version);
+ Ver->d = AllocateInMap<pkgCache::Version::Extra>();
+ if (not Ver.PhasedUpdatePercentage(100))
+ abort();
+
//Dynamic<pkgCache::VerIterator> DynV(Ver); // caller MergeListVersion already takes care of it
Ver->NextVer = Next;
Ver->ParentPkg = ParentPkg;
diff --git a/apt-pkg/policy.cc b/apt-pkg/policy.cc
index 761a6ede1..39879f754 100644
--- a/apt-pkg/policy.cc
+++ b/apt-pkg/policy.cc
@@ -14,6 +14,7 @@
// Include Files /*{{{*/
#include <config.h>
+#include <apt-pkg/aptconfiguration.h>
#include <apt-pkg/cachefilter.h>
#include <apt-pkg/configuration.h>
#include <apt-pkg/error.h>
@@ -26,6 +27,7 @@
#include <apt-pkg/versionmatch.h>
#include <iostream>
+#include <random>
#include <sstream>
#include <string>
#include <vector>
@@ -40,12 +42,17 @@ using namespace std;
constexpr short NEVER_PIN = std::numeric_limits<short>::min();
+struct pkgPolicy::Private
+{
+ std::string machineID;
+};
+
// Policy::Init - Startup and bind to a cache /*{{{*/
// ---------------------------------------------------------------------
/* Set the defaults for operation. The default mode with no loaded policy
file matches the V0 policy engine. */
pkgPolicy::pkgPolicy(pkgCache *Owner) : VerPins(nullptr),
- PFPriority(nullptr), Cache(Owner), d(NULL)
+ PFPriority(nullptr), Cache(Owner), d(new Private)
{
if (Owner == 0)
return;
@@ -77,6 +84,8 @@ pkgPolicy::pkgPolicy(pkgCache *Owner) : VerPins(nullptr),
CreatePin(pkgVersionMatch::Release,"",DefRel,990);
}
InitDefaults();
+
+ d->machineID = APT::Configuration::getMachineID();
}
/*}}}*/
// Policy::InitDefaults - Compute the default selections /*{{{*/
@@ -274,8 +283,38 @@ void pkgPolicy::CreatePin(pkgVersionMatch::MatchType Type,string Name,
// Policy::GetPriority - Get the priority of the package pin /*{{{*/
// ---------------------------------------------------------------------
/* */
+// Returns true if this update is excluded by phasing.
+static inline bool ExcludePhased(std::string machineID, pkgCache::VerIterator const &Ver)
+{
+ // The order and fallbacks for the always/never checks come from update-manager and exist
+ // to preserve compatibility.
+ if (_config->FindB("APT::Get::Always-Include-Phased-Updates",
+ _config->FindB("Update-Manager::Always-Include-Phased-Updates", false)))
+ return false;
+
+ if (_config->FindB("APT::Get::Never-Include-Phased-Updates",
+ _config->FindB("Update-Manager::Never-Include-Phased-Updates", false)))
+ return true;
+
+ if (machineID.empty() // no machine-id
+ || getenv("SOURCE_DATE_EPOCH") != nullptr // reproducible build - always include
+ || APT::Configuration::isChroot())
+ return false;
+
+ std::string seedStr = std::string(Ver.SourcePkgName()) + "-" + Ver.SourceVerStr() + "-" + machineID;
+ std::seed_seq seed(seedStr.begin(), seedStr.end());
+ std::minstd_rand rand(seed);
+ std::uniform_int_distribution<unsigned int> dist(0, 100);
+
+ return dist(rand) > Ver.PhasedUpdatePercentage();
+}
APT_PURE signed short pkgPolicy::GetPriority(pkgCache::VerIterator const &Ver, bool ConsiderFiles)
{
+ if (Ver.ParentPkg()->CurrentVer && Ver.PhasedUpdatePercentage() != 100)
+ {
+ if (ExcludePhased(d->machineID, Ver))
+ return 1;
+ }
if (VerPins[Ver->ID].Type != pkgVersionMatch::None)
{
// If all sources are never pins, the never pin wins.
@@ -454,4 +493,9 @@ bool ReadPinFile(pkgPolicy &Plcy,string File)
}
/*}}}*/
-pkgPolicy::~pkgPolicy() {delete [] PFPriority; delete [] VerPins; }
+pkgPolicy::~pkgPolicy()
+{
+ delete[] PFPriority;
+ delete[] VerPins;
+ delete d;
+}
diff --git a/apt-pkg/policy.h b/apt-pkg/policy.h
index 7f30d40ed..589cebcde 100644
--- a/apt-pkg/policy.h
+++ b/apt-pkg/policy.h
@@ -83,7 +83,8 @@ class APT_PUBLIC pkgPolicy : public pkgDepCache::Policy
explicit pkgPolicy(pkgCache *Owner);
virtual ~pkgPolicy();
private:
- void * const d;
+ struct Private;
+ Private *const d;
};
APT_PUBLIC bool ReadPinFile(pkgPolicy &Plcy, std::string File = "");
diff --git a/apt-pkg/tagfile-keys.list b/apt-pkg/tagfile-keys.list
index a16bc686a..b5cc2f1a4 100644
--- a/apt-pkg/tagfile-keys.list
+++ b/apt-pkg/tagfile-keys.list
@@ -46,6 +46,7 @@ Package-List
Package_Revision
Package-Revision
Package-Type
+Phased-Update-Percentage
Pre-Depends
Priority
Protected