You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

443 lines
15 KiB

  1. // -*- mode: cpp; mode: fold -*-
  2. // Description /*{{{*/
  3. /* ######################################################################
  4. Package Version Policy implementation
  5. This is just a really simple wrapper around pkgVersionMatch with
  6. some added goodies to manage the list of things..
  7. See man apt_preferences for what value means what.
  8. ##################################################################### */
  9. /*}}}*/
  10. // Include Files /*{{{*/
  11. #include <config.h>
  12. #include <apt-pkg/cachefilter.h>
  13. #include <apt-pkg/configuration.h>
  14. #include <apt-pkg/error.h>
  15. #include <apt-pkg/fileutl.h>
  16. #include <apt-pkg/netrc.h>
  17. #include <apt-pkg/pkgcache.h>
  18. #include <apt-pkg/policy.h>
  19. #include <apt-pkg/strutl.h>
  20. #include <apt-pkg/tagfile.h>
  21. #include <apt-pkg/version.h>
  22. #include <apt-pkg/versionmatch.h>
  23. #include <iostream>
  24. #include <sstream>
  25. #include <string>
  26. #include <vector>
  27. #include <ctype.h>
  28. #include <stddef.h>
  29. #include <string.h>
  30. #include <apti18n.h>
  31. /*}}}*/
  32. using namespace std;
  33. constexpr short NEVER_PIN = std::numeric_limits<short>::min();
  34. // Policy::Init - Startup and bind to a cache /*{{{*/
  35. // ---------------------------------------------------------------------
  36. /* Set the defaults for operation. The default mode with no loaded policy
  37. file matches the V0 policy engine. */
  38. pkgPolicy::pkgPolicy(pkgCache *Owner) : Pins(nullptr), VerPins(nullptr),
  39. PFPriority(nullptr), Cache(Owner), d(NULL)
  40. {
  41. if (Owner == 0)
  42. return;
  43. PFPriority = new signed short[Owner->Head().PackageFileCount];
  44. auto PackageCount = Owner->Head().PackageCount;
  45. Pins = new Pin[PackageCount];
  46. VerPins = new Pin[Owner->Head().VersionCount];
  47. for (decltype(PackageCount) I = 0; I != PackageCount; ++I)
  48. Pins[I].Type = pkgVersionMatch::None;
  49. auto VersionCount = Owner->Head().VersionCount;
  50. for (decltype(VersionCount) I = 0; I != VersionCount; ++I)
  51. VerPins[I].Type = pkgVersionMatch::None;
  52. // The config file has a master override.
  53. string DefRel = _config->Find("APT::Default-Release");
  54. if (DefRel.empty() == false)
  55. {
  56. bool found = false;
  57. // FIXME: make ExpressionMatches static to use it here easily
  58. pkgVersionMatch vm("", pkgVersionMatch::None);
  59. for (pkgCache::PkgFileIterator F = Cache->FileBegin(); F != Cache->FileEnd(); ++F)
  60. {
  61. if (vm.ExpressionMatches(DefRel, F.Archive()) ||
  62. vm.ExpressionMatches(DefRel, F.Codename()) ||
  63. vm.ExpressionMatches(DefRel, F.Version()) ||
  64. (DefRel.length() > 2 && DefRel[1] == '='))
  65. found = true;
  66. }
  67. if (found == false)
  68. _error->Error(_("The value '%s' is invalid for APT::Default-Release as such a release is not available in the sources"), DefRel.c_str());
  69. else
  70. CreatePin(pkgVersionMatch::Release,"",DefRel,990);
  71. }
  72. InitDefaults();
  73. }
  74. /*}}}*/
  75. // Policy::InitDefaults - Compute the default selections /*{{{*/
  76. // ---------------------------------------------------------------------
  77. /* */
  78. bool pkgPolicy::InitDefaults()
  79. {
  80. std::vector<std::unique_ptr<FileFd>> authconfs;
  81. // Initialize the priorities based on the status of the package file
  82. for (pkgCache::PkgFileIterator I = Cache->FileBegin(); I != Cache->FileEnd(); ++I)
  83. {
  84. PFPriority[I->ID] = 500;
  85. if (I.Flagged(pkgCache::Flag::NotSource))
  86. PFPriority[I->ID] = 100;
  87. else if (I.Flagged(pkgCache::Flag::ButAutomaticUpgrades))
  88. PFPriority[I->ID] = 100;
  89. else if (I.Flagged(pkgCache::Flag::NotAutomatic))
  90. PFPriority[I->ID] = 1;
  91. if (I.Flagged(pkgCache::Flag::PackagesRequireAuthorization) && !IsAuthorized(I, authconfs))
  92. PFPriority[I->ID] = NEVER_PIN;
  93. }
  94. // Apply the defaults..
  95. std::unique_ptr<bool[]> Fixed(new bool[Cache->HeaderP->PackageFileCount]);
  96. memset(Fixed.get(),0,sizeof(Fixed[0])*Cache->HeaderP->PackageFileCount);
  97. StatusOverride = false;
  98. for (vector<Pin>::const_iterator I = Defaults.begin(); I != Defaults.end(); ++I)
  99. {
  100. pkgVersionMatch Match(I->Data,I->Type);
  101. for (pkgCache::PkgFileIterator F = Cache->FileBegin(); F != Cache->FileEnd(); ++F)
  102. {
  103. if ((Fixed[F->ID] == false || I->Priority == NEVER_PIN) && PFPriority[F->ID] != NEVER_PIN && Match.FileMatch(F) == true)
  104. {
  105. PFPriority[F->ID] = I->Priority;
  106. if (PFPriority[F->ID] >= 1000)
  107. StatusOverride = true;
  108. Fixed[F->ID] = true;
  109. }
  110. }
  111. }
  112. if (_config->FindB("Debug::pkgPolicy",false) == true)
  113. for (pkgCache::PkgFileIterator F = Cache->FileBegin(); F != Cache->FileEnd(); ++F)
  114. std::clog << "Prio of " << F.FileName() << ' ' << PFPriority[F->ID] << std::endl;
  115. return true;
  116. }
  117. /*}}}*/
  118. // Policy::GetCandidateVer - Get the candidate install version /*{{{*/
  119. // ---------------------------------------------------------------------
  120. /* Evaluate the package pins and the default list to deteremine what the
  121. best package is. */
  122. pkgCache::VerIterator pkgPolicy::GetCandidateVer(pkgCache::PkgIterator const &Pkg)
  123. {
  124. pkgCache::VerIterator cand;
  125. pkgCache::VerIterator cur = Pkg.CurrentVer();
  126. int candPriority = -1;
  127. pkgVersioningSystem *vs = Cache->VS;
  128. for (pkgCache::VerIterator ver = Pkg.VersionList(); ver.end() == false; ++ver) {
  129. int priority = GetPriority(ver, true);
  130. if (priority == 0 || priority <= candPriority)
  131. continue;
  132. // TODO: Maybe optimize to not compare versions
  133. if (!cur.end() && priority < 1000
  134. && (vs->CmpVersion(ver.VerStr(), cur.VerStr()) < 0))
  135. continue;
  136. candPriority = priority;
  137. cand = ver;
  138. }
  139. return cand;
  140. }
  141. /*}}}*/
  142. // Policy::CreatePin - Create an entry in the pin table.. /*{{{*/
  143. // ---------------------------------------------------------------------
  144. /* For performance we have 3 tables, the default table, the main cache
  145. table (hashed to the cache). A blank package name indicates the pin
  146. belongs to the default table. Order of insertion matters here, the
  147. earlier defaults override later ones. */
  148. void pkgPolicy::CreatePin(pkgVersionMatch::MatchType Type,string Name,
  149. string Data,signed short Priority)
  150. {
  151. if (Name.empty() == true)
  152. {
  153. Pin *P = &*Defaults.insert(Defaults.end(),Pin());
  154. P->Type = Type;
  155. P->Priority = Priority;
  156. P->Data = Data;
  157. return;
  158. }
  159. size_t found = Name.rfind(':');
  160. string Arch;
  161. if (found != string::npos) {
  162. Arch = Name.substr(found+1);
  163. Name.erase(found);
  164. }
  165. // Allow pinning by wildcards - beware of package names looking like wildcards!
  166. // TODO: Maybe we should always prefer specific pins over non-specific ones.
  167. if ((Name[0] == '/' && Name[Name.length() - 1] == '/') || Name.find_first_of("*[?") != string::npos)
  168. {
  169. pkgVersionMatch match(Data, Type);
  170. for (pkgCache::GrpIterator G = Cache->GrpBegin(); G.end() != true; ++G)
  171. if (Name != G.Name() && match.ExpressionMatches(Name, G.Name()))
  172. {
  173. if (Arch.empty() == false)
  174. CreatePin(Type, string(G.Name()).append(":").append(Arch), Data, Priority);
  175. else
  176. CreatePin(Type, G.Name(), Data, Priority);
  177. }
  178. return;
  179. }
  180. // find the package (group) this pin applies to
  181. pkgCache::GrpIterator Grp = Cache->FindGrp(Name);
  182. bool matched = false;
  183. if (Grp.end() == false)
  184. {
  185. std::string MatchingArch;
  186. if (Arch.empty() == true)
  187. MatchingArch = Cache->NativeArch();
  188. else
  189. MatchingArch = Arch;
  190. APT::CacheFilter::PackageArchitectureMatchesSpecification pams(MatchingArch);
  191. for (pkgCache::PkgIterator Pkg = Grp.PackageList(); Pkg.end() != true; Pkg = Grp.NextPkg(Pkg))
  192. {
  193. if (pams(Pkg.Arch()) == false)
  194. continue;
  195. Pin *P = Pins + Pkg->ID;
  196. // the first specific stanza for a package is the ruler,
  197. // all others need to be ignored
  198. if (P->Type != pkgVersionMatch::None)
  199. P = &*Unmatched.insert(Unmatched.end(),PkgPin(Pkg.FullName()));
  200. P->Type = Type;
  201. P->Priority = Priority;
  202. P->Data = Data;
  203. matched = true;
  204. // Find matching version(s) and copy the pin into it
  205. pkgVersionMatch Match(P->Data,P->Type);
  206. for (pkgCache::VerIterator Ver = Pkg.VersionList(); Ver.end() != true; ++Ver)
  207. {
  208. if (Match.VersionMatches(Ver)) {
  209. Pin *VP = VerPins + Ver->ID;
  210. if (VP->Type == pkgVersionMatch::None)
  211. *VP = *P;
  212. }
  213. }
  214. }
  215. }
  216. if (matched == false)
  217. {
  218. PkgPin *P = &*Unmatched.insert(Unmatched.end(),PkgPin(Name));
  219. if (Arch.empty() == false)
  220. P->Pkg.append(":").append(Arch);
  221. P->Type = Type;
  222. P->Priority = Priority;
  223. P->Data = Data;
  224. return;
  225. }
  226. }
  227. /*}}}*/
  228. // Policy::GetMatch - Get the matching version for a package pin /*{{{*/
  229. // ---------------------------------------------------------------------
  230. /* */
  231. pkgCache::VerIterator pkgPolicy::GetMatch(pkgCache::PkgIterator const &Pkg)
  232. {
  233. const Pin &PPkg = Pins[Pkg->ID];
  234. if (PPkg.Type == pkgVersionMatch::None)
  235. return pkgCache::VerIterator(*Pkg.Cache());
  236. pkgVersionMatch Match(PPkg.Data,PPkg.Type);
  237. return Match.Find(Pkg);
  238. }
  239. /*}}}*/
  240. // Policy::GetPriority - Get the priority of the package pin /*{{{*/
  241. // ---------------------------------------------------------------------
  242. /* */
  243. APT_PURE signed short pkgPolicy::GetPriority(pkgCache::PkgIterator const &Pkg)
  244. {
  245. if (Pins[Pkg->ID].Type != pkgVersionMatch::None)
  246. return Pins[Pkg->ID].Priority;
  247. return 0;
  248. }
  249. APT_PURE signed short pkgPolicy::GetPriority(pkgCache::VerIterator const &Ver, bool ConsiderFiles)
  250. {
  251. if (VerPins[Ver->ID].Type != pkgVersionMatch::None)
  252. {
  253. // If all sources are never pins, the never pin wins.
  254. if (VerPins[Ver->ID].Priority == NEVER_PIN)
  255. return NEVER_PIN;
  256. for (pkgCache::VerFileIterator file = Ver.FileList(); file.end() == false; file++)
  257. if (GetPriority(file.File()) != NEVER_PIN)
  258. return VerPins[Ver->ID].Priority;
  259. }
  260. if (!ConsiderFiles)
  261. return 0;
  262. // priorities are short ints, but we want to pick a value outside the valid range here
  263. auto priority = std::numeric_limits<signed int>::min();
  264. for (pkgCache::VerFileIterator file = Ver.FileList(); file.end() == false; file++)
  265. {
  266. /* If this is the status file, and the current version is not the
  267. version in the status file (ie it is not installed, or somesuch)
  268. then it is not a candidate for installation, ever. This weeds
  269. out bogus entries that may be due to config-file states, or
  270. other. */
  271. if (file.File().Flagged(pkgCache::Flag::NotSource) && Ver.ParentPkg().CurrentVer() != Ver)
  272. priority = std::max(priority, static_cast<decltype(priority)>(-1));
  273. else
  274. priority = std::max(priority, static_cast<decltype(priority)>(GetPriority(file.File())));
  275. }
  276. return priority == std::numeric_limits<decltype(priority)>::min() ? 0 : priority;
  277. }
  278. APT_PURE signed short pkgPolicy::GetPriority(pkgCache::PkgFileIterator const &File)
  279. {
  280. return PFPriority[File->ID];
  281. }
  282. /*}}}*/
  283. // ReadPinDir - Load the pin files from this dir into a Policy /*{{{*/
  284. // ---------------------------------------------------------------------
  285. /* This will load each pin file in the given dir into a Policy. If the
  286. given dir is empty the dir set in Dir::Etc::PreferencesParts is used.
  287. Note also that this method will issue a warning if the dir does not
  288. exists but it will return true in this case! */
  289. bool ReadPinDir(pkgPolicy &Plcy,string Dir)
  290. {
  291. if (Dir.empty() == true)
  292. Dir = _config->FindDir("Dir::Etc::PreferencesParts", "/dev/null");
  293. if (DirectoryExists(Dir) == false)
  294. {
  295. if (APT::String::Endswith(Dir, "/dev/null") == false)
  296. _error->WarningE("DirectoryExists",_("Unable to read %s"),Dir.c_str());
  297. return true;
  298. }
  299. _error->PushToStack();
  300. vector<string> const List = GetListOfFilesInDir(Dir, "pref", true, true);
  301. bool const PendingErrors = _error->PendingError();
  302. _error->MergeWithStack();
  303. if (PendingErrors)
  304. return false;
  305. // Read the files
  306. bool good = true;
  307. for (vector<string>::const_iterator I = List.begin(); I != List.end(); ++I)
  308. good = ReadPinFile(Plcy, *I) && good;
  309. return good;
  310. }
  311. /*}}}*/
  312. // ReadPinFile - Load the pin file into a Policy /*{{{*/
  313. // ---------------------------------------------------------------------
  314. /* I'd like to see the preferences file store more than just pin information
  315. but right now that is the only stuff I have to store. Later there will
  316. have to be some kind of combined super parser to get the data into all
  317. the right classes.. */
  318. bool ReadPinFile(pkgPolicy &Plcy,string File)
  319. {
  320. if (File.empty() == true)
  321. File = _config->FindFile("Dir::Etc::Preferences");
  322. if (RealFileExists(File) == false)
  323. return true;
  324. FileFd Fd;
  325. if (OpenConfigurationFileFd(File, Fd) == false)
  326. return false;
  327. pkgTagFile TF(&Fd, pkgTagFile::SUPPORT_COMMENTS);
  328. if (Fd.IsOpen() == false || Fd.Failed())
  329. return false;
  330. pkgTagSection Tags;
  331. while (TF.Step(Tags) == true)
  332. {
  333. // can happen when there are only comments in a record
  334. if (Tags.Count() == 0)
  335. continue;
  336. string Name = Tags.FindS("Package");
  337. if (Name.empty() == true)
  338. return _error->Error(_("Invalid record in the preferences file %s, no Package header"), File.c_str());
  339. if (Name == "*")
  340. Name = string();
  341. const char *Start;
  342. const char *End;
  343. if (Tags.Find("Pin",Start,End) == false)
  344. continue;
  345. const char *Word = Start;
  346. for (; Word != End && isspace(*Word) == 0; Word++);
  347. // Parse the type..
  348. pkgVersionMatch::MatchType Type;
  349. if (stringcasecmp(Start,Word,"version") == 0 && Name.empty() == false)
  350. Type = pkgVersionMatch::Version;
  351. else if (stringcasecmp(Start,Word,"release") == 0)
  352. Type = pkgVersionMatch::Release;
  353. else if (stringcasecmp(Start,Word,"origin") == 0)
  354. Type = pkgVersionMatch::Origin;
  355. else
  356. {
  357. _error->Warning(_("Did not understand pin type %s"),string(Start,Word).c_str());
  358. continue;
  359. }
  360. for (; Word != End && isspace(*Word) != 0; Word++);
  361. _error->PushToStack();
  362. std::string sPriority = Tags.FindS("Pin-Priority");
  363. int priority = sPriority == "never" ? NEVER_PIN : Tags.FindI("Pin-Priority", 0);
  364. bool const newError = _error->PendingError();
  365. _error->MergeWithStack();
  366. if (sPriority == "never" && not Name.empty())
  367. return _error->Error(_("%s: The special 'Pin-Priority: %s' can only be used for 'Package: *' records"), File.c_str(), "never");
  368. // Silently clamp the never pin to never pin + 1
  369. if (priority == NEVER_PIN && sPriority != "never")
  370. priority = NEVER_PIN + 1;
  371. if (priority < std::numeric_limits<short>::min() ||
  372. priority > std::numeric_limits<short>::max() ||
  373. newError) {
  374. return _error->Error(_("%s: Value %s is outside the range of valid pin priorities (%d to %d)"),
  375. File.c_str(), Tags.FindS("Pin-Priority").c_str(),
  376. std::numeric_limits<short>::min(),
  377. std::numeric_limits<short>::max());
  378. }
  379. if (priority == 0)
  380. {
  381. return _error->Error(_("No priority (or zero) specified for pin"));
  382. }
  383. istringstream s(Name);
  384. string pkg;
  385. while(!s.eof())
  386. {
  387. s >> pkg;
  388. Plcy.CreatePin(Type, pkg, string(Word,End),priority);
  389. };
  390. }
  391. Plcy.InitDefaults();
  392. return true;
  393. }
  394. /*}}}*/
  395. pkgPolicy::~pkgPolicy() {delete [] PFPriority; delete [] Pins; delete [] VerPins; }