apt  2.2.4
About: Apt (Advanced Package Tool) is a management system for software packages (Debian/Ubuntu). Release series 2.2.
  Fossies Dox: apt-2.2.4.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

edsp.cc
Go to the documentation of this file.
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 /* ######################################################################
4  Set of methods to help writing and reading everything needed for EDSP
5  ##################################################################### */
6  /*}}}*/
7 // Include Files /*{{{*/
8 #include <config.h>
9 
10 #include <apt-pkg/algorithms.h>
11 #include <apt-pkg/cacheset.h>
12 #include <apt-pkg/depcache.h>
13 #include <apt-pkg/edsp.h>
14 #include <apt-pkg/error.h>
15 #include <apt-pkg/fileutl.h>
16 #include <apt-pkg/packagemanager.h>
17 #include <apt-pkg/pkgcache.h>
18 #include <apt-pkg/pkgsystem.h>
19 #include <apt-pkg/prettyprinters.h>
20 #include <apt-pkg/progress.h>
21 #include <apt-pkg/string_view.h>
22 #include <apt-pkg/strutl.h>
23 #include <apt-pkg/tagfile.h>
24 
25 #include <ctype.h>
26 #include <stddef.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <sys/stat.h>
30 #include <unistd.h>
31 
32 #include <algorithm>
33 #include <array>
34 #include <limits>
35 #include <sstream>
36 #include <string>
37 
38 #include <apti18n.h>
39  /*}}}*/
40 
41 using std::string;
42 
43 // we could use pkgCache::DepType and ::Priority, but these would be localized strings…
44 constexpr char const * const PrioMap[] = {
45  nullptr, "important", "required", "standard",
46  "optional", "extra"
47 };
48 constexpr char const * const DepMap[] = {
49  nullptr, "Depends", "Pre-Depends", "Suggests",
50  "Recommends" , "Conflicts", "Replaces",
51  "Obsoletes", "Breaks", "Enhances"
52 };
53 
54 // WriteOkay - varaidic helper to easily Write to a FileFd /*{{{*/
55 static bool WriteOkay_fn(FileFd &) { return true; }
56 template<typename... Tail> static bool WriteOkay_fn(FileFd &output, APT::StringView data, Tail... more_data)
57 {
58  return likely(output.Write(data.data(), data.length()) && WriteOkay_fn(output, more_data...));
59 }
60 template<typename... Tail> static bool WriteOkay_fn(FileFd &output, unsigned int data, Tail... more_data)
61 {
62  std::string number;
63  strprintf(number, "%d", data);
64  return likely(output.Write(number.data(), number.length()) && WriteOkay_fn(output, more_data...));
65 }
66 template<typename... Data> static bool WriteOkay(bool &Okay, FileFd &output, Data&&... data)
67 {
68  Okay = likely(Okay && WriteOkay_fn(output, std::forward<Data>(data)...));
69  return Okay;
70 }
71 template<typename... Data> static bool WriteOkay(FileFd &output, Data&&... data)
72 {
73  bool Okay = likely(output.Failed() == false);
74  return WriteOkay(Okay, output, std::forward<Data>(data)...);
75 }
76  /*}}}*/
77 // WriteScenarioVersion /*{{{*/
78 static bool WriteScenarioVersion(FileFd &output, pkgCache::PkgIterator const &Pkg,
79  pkgCache::VerIterator const &Ver)
80 {
81  bool Okay = WriteOkay(output, "Package: ", Pkg.Name(),
82  "\nArchitecture: ", Ver.Arch(),
83  "\nVersion: ", Ver.VerStr());
84  WriteOkay(Okay, output, "\nAPT-ID: ", Ver->ID);
86  WriteOkay(Okay, output, "\nEssential: yes");
88  WriteOkay(Okay, output, "\nMulti-Arch: allowed");
89  else if ((Ver->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign)
90  WriteOkay(Okay, output, "\nMulti-Arch: foreign");
91  else if ((Ver->MultiArch & pkgCache::Version::Same) == pkgCache::Version::Same)
92  WriteOkay(Okay, output, "\nMulti-Arch: same");
93  return Okay;
94 }
95  /*}}}*/
96 // WriteScenarioDependency /*{{{*/
97 static bool WriteScenarioDependency(FileFd &output, pkgCache::VerIterator const &Ver, bool const OnlyCritical)
98 {
99  std::array<std::string, APT_ARRAY_SIZE(DepMap)> dependencies;
100  bool orGroup = false;
101  for (pkgCache::DepIterator Dep = Ver.DependsList(); Dep.end() == false; ++Dep)
102  {
103  if (Dep.IsImplicit() == true)
104  continue;
105  if (OnlyCritical && Dep.IsCritical() == false)
106  continue;
107  if (orGroup == false && dependencies[Dep->Type].empty() == false)
108  dependencies[Dep->Type].append(", ");
109  dependencies[Dep->Type].append(Dep.TargetPkg().Name());
110  if (Dep->Version != 0)
111  dependencies[Dep->Type].append(" (").append(pkgCache::CompTypeDeb(Dep->CompareOp)).append(" ").append(Dep.TargetVer()).append(")");
112  if ((Dep->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or)
113  {
114  dependencies[Dep->Type].append(" | ");
115  orGroup = true;
116  }
117  else
118  orGroup = false;
119  }
120  bool Okay = output.Failed() == false;
121  for (size_t i = 1; i < dependencies.size(); ++i)
122  if (dependencies[i].empty() == false)
123  WriteOkay(Okay, output, "\n", DepMap[i], ": ", dependencies[i]);
124  std::vector<std::string> provides;
125  for (auto Prv = Ver.ProvidesList(); not Prv.end(); ++Prv)
126  {
127  if (Prv.IsMultiArchImplicit())
128  continue;
129  std::string provide = Prv.Name();
130  if (Prv->ProvideVersion != 0)
131  provide.append(" (= ").append(Prv.ProvideVersion()).append(")");
132  if ((Ver->MultiArch & pkgCache::Version::Foreign) != 0 && std::find(provides.cbegin(), provides.cend(), provide) != provides.cend())
133  continue;
134  provides.emplace_back(std::move(provide));
135  }
136  if (not provides.empty())
137  {
138  std::ostringstream out;
139  std::copy(provides.begin(), provides.end() - 1, std::ostream_iterator<std::string>(out, ", "));
140  out << provides.back();
141  WriteOkay(Okay, output, "\nProvides: ", out.str());
142  }
143  return WriteOkay(Okay, output, "\n");
144 }
145  /*}}}*/
146 // WriteScenarioLimitedDependency /*{{{*/
148  pkgCache::VerIterator const &Ver,
149  std::vector<bool> const &pkgset,
150  bool const OnlyCritical)
151 {
152  std::array<std::string, APT_ARRAY_SIZE(DepMap)> dependencies;
153  bool orGroup = false;
154  for (pkgCache::DepIterator Dep = Ver.DependsList(); Dep.end() == false; ++Dep)
155  {
156  if (Dep.IsImplicit() == true)
157  continue;
158  if (OnlyCritical && Dep.IsCritical() == false)
159  continue;
160  if (orGroup == false)
161  {
162  if (pkgset[Dep.TargetPkg()->ID] == false)
163  continue;
164  if (dependencies[Dep->Type].empty() == false)
165  dependencies[Dep->Type].append(", ");
166  }
167  else if (pkgset[Dep.TargetPkg()->ID] == false)
168  {
169  if ((Dep->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or)
170  continue;
171  dependencies[Dep->Type].erase(dependencies[Dep->Type].end()-3, dependencies[Dep->Type].end());
172  orGroup = false;
173  continue;
174  }
175  dependencies[Dep->Type].append(Dep.TargetPkg().Name());
176  if (Dep->Version != 0)
177  dependencies[Dep->Type].append(" (").append(pkgCache::CompTypeDeb(Dep->CompareOp)).append(" ").append(Dep.TargetVer()).append(")");
178  if ((Dep->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or)
179  {
180  dependencies[Dep->Type].append(" | ");
181  orGroup = true;
182  }
183  else
184  orGroup = false;
185  }
186  bool Okay = output.Failed() == false;
187  for (size_t i = 1; i < dependencies.size(); ++i)
188  if (dependencies[i].empty() == false)
189  WriteOkay(Okay, output, "\n", DepMap[i], ": ", dependencies[i]);
190  string provides;
191  for (pkgCache::PrvIterator Prv = Ver.ProvidesList(); Prv.end() == false; ++Prv)
192  {
193  if (Prv.IsMultiArchImplicit() == true)
194  continue;
195  if (pkgset[Prv.ParentPkg()->ID] == false)
196  continue;
197  if (provides.empty() == false)
198  provides.append(", ");
199  provides.append(Prv.Name());
200  if (Prv->ProvideVersion != 0)
201  provides.append(" (= ").append(Prv.ProvideVersion()).append(")");
202  }
203  if (provides.empty() == false)
204  WriteOkay(Okay, output, "\nProvides: ", provides);
205  return WriteOkay(Okay, output, "\n");
206 }
207  /*}}}*/
208 static bool SkipUnavailableVersions(pkgDepCache &Cache, pkgCache::PkgIterator const &Pkg, pkgCache::VerIterator const &Ver)/*{{{*/
209 {
210  /* versions which aren't current and aren't available in
211  any "online" source file are bad, expect if they are the chosen
212  candidate: The exception is for build-dep implementation as it creates
213  such pseudo (package) versions and removes them later on again.
214  We filter out versions at all so packages in 'rc' state only available
215  in dpkg/status aren't passed to solvers as they can't be installed. */
216  if (Pkg->CurrentVer != 0)
217  return false;
218  if (Cache.GetCandidateVersion(Pkg) == Ver)
219  return false;
220  for (pkgCache::VerFileIterator I = Ver.FileList(); I.end() == false; ++I)
221  if (I.File().Flagged(pkgCache::Flag::NotSource) == false)
222  return false;
223  return true;
224 }
225  /*}}}*/
226 static bool WriteScenarioEDSPVersion(pkgDepCache &Cache, FileFd &output, pkgCache::PkgIterator const &Pkg,/*{{{*/
227  pkgCache::VerIterator const &Ver)
228 {
229  bool Okay = WriteOkay(output, "\nSource: ", Ver.SourcePkgName(),
230  "\nSource-Version: ", Ver.SourceVerStr());
231  if (PrioMap[Ver->Priority] != nullptr)
232  WriteOkay(Okay, output, "\nPriority: ", PrioMap[Ver->Priority]);
233  if (Ver->Section != 0)
234  WriteOkay(Okay, output, "\nSection: ", Ver.Section());
235  if (Pkg.CurrentVer() == Ver)
236  WriteOkay(Okay, output, "\nInstalled: yes");
237  if (Pkg->SelectedState == pkgCache::State::Hold ||
238  (Cache[Pkg].Keep() == true && Cache[Pkg].Protect() == true))
239  WriteOkay(Okay, output, "\nHold: yes");
240  std::set<string> Releases;
241  for (pkgCache::VerFileIterator I = Ver.FileList(); I.end() == false; ++I) {
242  pkgCache::PkgFileIterator File = I.File();
243  if (File.Flagged(pkgCache::Flag::NotSource) == false) {
244  string Release = File.RelStr();
245  if (!Release.empty())
246  Releases.insert(Release);
247  }
248  }
249  if (!Releases.empty()) {
250  WriteOkay(Okay, output, "\nAPT-Release:");
251  for (std::set<string>::iterator R = Releases.begin(); R != Releases.end(); ++R)
252  WriteOkay(Okay, output, "\n ", *R);
253  }
254  WriteOkay(Okay, output, "\nAPT-Pin: ", Cache.GetPolicy().GetPriority(Ver));
255  if (Cache.GetCandidateVersion(Pkg) == Ver)
256  WriteOkay(Okay, output, "\nAPT-Candidate: yes");
257  if ((Cache[Pkg].Flags & pkgCache::Flag::Auto) == pkgCache::Flag::Auto)
258  WriteOkay(Okay, output, "\nAPT-Automatic: yes");
259  return Okay;
260 }
261  /*}}}*/
262 // EDSP::WriteScenario - to the given file descriptor /*{{{*/
263 bool EDSP::WriteScenario(pkgDepCache &Cache, FileFd &output, OpProgress *Progress)
264 {
265  if (Progress != NULL)
266  Progress->SubProgress(Cache.Head().VersionCount, _("Send scenario to solver"));
267  decltype(Cache.Head().VersionCount) p = 0;
268  bool Okay = output.Failed() == false;
269  std::vector<std::string> archs = APT::Configuration::getArchitectures();
270  for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false && likely(Okay); ++Pkg)
271  {
272  std::string const arch = Pkg.Arch();
273  if (Pkg->CurrentVer == 0 && std::find(archs.begin(), archs.end(), arch) == archs.end())
274  continue;
275  for (pkgCache::VerIterator Ver = Pkg.VersionList(); Ver.end() == false && likely(Okay); ++Ver, ++p)
276  {
277  if (SkipUnavailableVersions(Cache, Pkg, Ver))
278  continue;
279  Okay &= WriteScenarioVersion(output, Pkg, Ver);
280  Okay &= WriteScenarioEDSPVersion(Cache, output, Pkg, Ver);
281  Okay &= WriteScenarioDependency(output, Ver, false);
282  WriteOkay(Okay, output, "\n");
283  if (Progress != NULL && p % 100 == 0)
284  Progress->Progress(p);
285  }
286  }
287  return Okay;
288 }
289  /*}}}*/
290 // EDSP::WriteLimitedScenario - to the given file descriptor /*{{{*/
292  std::vector<bool> const &pkgset,
293  OpProgress *Progress)
294 {
295  if (Progress != NULL)
296  Progress->SubProgress(Cache.Head().VersionCount, _("Send scenario to solver"));
297  decltype(Cache.Head().PackageCount) p = 0;
298  bool Okay = output.Failed() == false;
299  for (auto Pkg = Cache.PkgBegin(); Pkg.end() == false && likely(Okay); ++Pkg, ++p)
300  {
301  if (pkgset[Pkg->ID] == false)
302  continue;
303  for (pkgCache::VerIterator Ver = Pkg.VersionList(); Ver.end() == false && likely(Okay); ++Ver)
304  {
305  if (SkipUnavailableVersions(Cache, Pkg, Ver))
306  continue;
307  Okay &= WriteScenarioVersion(output, Pkg, Ver);
308  Okay &= WriteScenarioEDSPVersion(Cache, output, Pkg, Ver);
309  Okay &= WriteScenarioLimitedDependency(output, Ver, pkgset, false);
310  WriteOkay(Okay, output, "\n");
311  if (Progress != NULL && p % 100 == 0)
312  Progress->Progress(p);
313  }
314  }
315  if (Progress != NULL)
316  Progress->Done();
317  return Okay;
318 }
319  /*}}}*/
320 // EDSP::WriteRequest - to the given file descriptor /*{{{*/
321 bool EDSP::WriteRequest(pkgDepCache &Cache, FileFd &output,
322  unsigned int const flags,
323  OpProgress *Progress)
324 {
325  if (Progress != NULL)
326  Progress->SubProgress(Cache.Head().PackageCount, _("Send request to solver"));
327  decltype(Cache.Head().PackageCount) p = 0;
328  string del, inst;
329  for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; ++Pkg, ++p)
330  {
331  if (Progress != NULL && p % 100 == 0)
332  Progress->Progress(p);
333  string* req;
334  pkgDepCache::StateCache &P = Cache[Pkg];
335  if (P.Delete() == true)
336  req = &del;
337  else if (P.NewInstall() == true || P.Upgrade() == true || P.ReInstall() == true ||
339  req = &inst;
340  else
341  continue;
342  req->append(" ").append(Pkg.FullName());
343  }
344  bool Okay = WriteOkay(output, "Request: EDSP 0.5\n");
345 
346  std::vector<string> archs = APT::Configuration::getArchitectures();
347  WriteOkay(Okay, output, "Architecture: ", _config->Find("APT::Architecture").c_str(), "\n",
348  "Architectures:");
349  for (std::vector<string>::const_iterator a = archs.begin(); a != archs.end(); ++a)
350  WriteOkay(Okay, output, " ", *a);
351  WriteOkay(Okay, output, "\n");
352 
353  if (del.empty() == false)
354  WriteOkay(Okay, output, "Remove:", del, "\n");
355  if (inst.empty() == false)
356  WriteOkay(Okay, output, "Install:", inst, "\n");
357  if (flags & Request::AUTOREMOVE)
358  WriteOkay(Okay, output, "Autoremove: yes\n");
359  if (flags & Request::UPGRADE_ALL)
360  {
361  WriteOkay(Okay, output, "Upgrade-All: yes\n");
363  WriteOkay(Okay, output, "Upgrade: yes\n");
364  else
365  WriteOkay(Okay, output, "Dist-Upgrade: yes\n");
366  }
367  if (flags & Request::FORBID_NEW_INSTALL)
368  WriteOkay(Okay, output, "Forbid-New-Install: yes\n");
369  if (flags & Request::FORBID_REMOVE)
370  WriteOkay(Okay, output, "Forbid-Remove: yes\n");
371  auto const solver = _config->Find("APT::Solver", "internal");
372  WriteOkay(Okay, output, "Solver: ", solver, "\n");
373  if (_config->FindB("APT::Solver::Strict-Pinning", true) == false)
374  WriteOkay(Okay, output, "Strict-Pinning: no\n");
375  string solverpref("APT::Solver::");
376  solverpref.append(solver).append("::Preferences");
377  if (_config->Exists(solverpref) == true)
378  WriteOkay(Okay, output, "Preferences: ", _config->Find(solverpref,""), "\n");
379  return WriteOkay(Okay, output, "\n");
380 }
381  /*}}}*/
382 // EDSP::ReadResponse - from the given file descriptor /*{{{*/
383 bool EDSP::ReadResponse(int const input, pkgDepCache &Cache, OpProgress *Progress) {
384  /* We build an map id to mmap offset here
385  In theory we could use the offset as ID, but then VersionCount
386  couldn't be used to create other versionmappings anymore and it
387  would be too easy for a (buggy) solver to segfault APT… */
388  auto VersionCount = Cache.Head().VersionCount;
389  decltype(VersionCount) VerIdx[VersionCount];
390  for (pkgCache::PkgIterator P = Cache.PkgBegin(); P.end() == false; ++P) {
391  for (pkgCache::VerIterator V = P.VersionList(); V.end() == false; ++V)
392  VerIdx[V->ID] = V.Index();
393  Cache[P].Marked = true;
394  Cache[P].Garbage = false;
395  }
396 
397  FileFd in;
398  in.OpenDescriptor(input, FileFd::ReadOnly, true);
399  pkgTagFile response(&in, 100);
400  pkgTagSection section;
401 
402  std::set<decltype(Cache.PkgBegin()->ID)> seenOnce;
403  while (response.Step(section) == true) {
404  std::string type;
405  if (section.Exists("Install") == true)
406  type = "Install";
407  else if (section.Exists("Remove") == true)
408  type = "Remove";
409  else if (section.Exists("Progress") == true) {
410  if (Progress != NULL) {
411  string msg = section.FindS("Message");
412  if (msg.empty() == true)
413  msg = _("Prepare for receiving solution");
414  Progress->SubProgress(100, msg, section.FindI("Percentage", 0));
415  }
416  continue;
417  } else if (section.Exists("Error") == true) {
418  if (_error->PendingError()) {
419  if (Progress != nullptr)
420  Progress->Done();
421  Progress = nullptr;
422  _error->DumpErrors(std::cerr, GlobalError::DEBUG, false);
423  }
424  std::string msg = SubstVar(SubstVar(section.FindS("Message"), "\n .\n", "\n\n"), "\n ", "\n");
425  if (msg.empty() == true) {
426  msg = _("External solver failed without a proper error message");
427  _error->Error("%s", msg.c_str());
428  } else
429  _error->Error("External solver failed with: %s", msg.substr(0,msg.find('\n')).c_str());
430  if (Progress != nullptr)
431  Progress->Done();
432  std::cerr << "The solver encountered an error of type: " << section.FindS("Error") << std::endl;
433  std::cerr << "The following information might help you to understand what is wrong:" << std::endl;
434  std::cerr << msg << std::endl << std::endl;
435  return false;
436  } else if (section.Exists("Autoremove") == true)
437  type = "Autoremove";
438  else {
439  char const *Start, *End;
440  section.GetSection(Start, End);
441  _error->Warning("Encountered an unexpected section with %d fields: %s", section.Count(), std::string(Start, End).c_str());
442  continue;
443  }
444 
445  decltype(VersionCount) const id = section.FindULL(type.c_str(), VersionCount);
446  if (id == VersionCount) {
447  _error->Warning("Unable to parse %s request with id value '%s'!", type.c_str(), section.FindS(type.c_str()).c_str());
448  continue;
449  } else if (id > VersionCount) {
450  _error->Warning("ID value '%s' in %s request stanza is to high to refer to a known version!", section.FindS(type.c_str()).c_str(), type.c_str());
451  continue;
452  }
453 
454  pkgCache::VerIterator Ver(Cache.GetCache(), Cache.GetCache().VerP + VerIdx[id]);
455  auto const Pkg = Ver.ParentPkg();
456  if (type == "Autoremove") {
457  Cache[Pkg].Marked = false;
458  Cache[Pkg].Garbage = true;
459  } else if (seenOnce.emplace(Pkg->ID).second == false) {
460  _error->Warning("Ignoring %s stanza received for package %s which already had a previous stanza effecting it!", type.c_str(), Pkg.FullName(false).c_str());
461  } else if (type == "Install") {
462  if (Pkg.CurrentVer() == Ver) {
463  _error->Warning("Ignoring Install stanza received for version %s of package %s which is already installed!",
464  Ver.VerStr(), Pkg.FullName(false).c_str());
465  } else {
466  Cache.SetCandidateVersion(Ver);
467  Cache.MarkInstall(Pkg, false, 0, false);
468  }
469  } else if (type == "Remove") {
470  if (Pkg->CurrentVer == 0)
471  _error->Warning("Ignoring Remove stanza received for version %s of package %s which isn't installed!",
472  Ver.VerStr(), Pkg.FullName(false).c_str());
473  else if (Pkg.CurrentVer() != Ver)
474  _error->Warning("Ignoring Remove stanza received for version %s of package %s which isn't the installed version %s!",
475  Ver.VerStr(), Pkg.FullName(false).c_str(), Pkg.CurrentVer().VerStr());
476  else
477  Cache.MarkDelete(Ver.ParentPkg(), false);
478  }
479  }
480  return true;
481 }
482  /*}}}*/
483 // ReadLine - first line from the given file descriptor /*{{{*/
484 // ---------------------------------------------------------------------
485 /* Little helper method to read a complete line into a string. Similar to
486  fgets but we need to use the low-level read() here as otherwise the
487  listparser will be confused later on as mixing of fgets and read isn't
488  a supported action according to the manpages and results are undefined */
489 static bool ReadLine(int const input, std::string &line) {
490  char one;
491  ssize_t data = 0;
492  line.erase();
493  line.reserve(100);
494  while ((data = read(input, &one, sizeof(one))) != -1) {
495  if (data != 1)
496  continue;
497  if (one == '\n')
498  return true;
499  if (one == '\r')
500  continue;
501  if (line.empty() == true && isblank(one) != 0)
502  continue;
503  line += one;
504  }
505  return false;
506 }
507  /*}}}*/
508 // StringToBool - convert yes/no to bool /*{{{*/
509 // ---------------------------------------------------------------------
510 /* we are not as lazy as we are in the global StringToBool as we really
511  only accept yes/no here */
512 static bool localStringToBool(std::string answer, bool const defValue) {
513  std::transform(answer.begin(), answer.end(), answer.begin(), ::tolower);
514  if (answer == "yes")
515  return true;
516  else if (answer == "no")
517  return false;
518  else
519  _error->Warning("Value '%s' is not a boolean 'yes' or 'no'!", answer.c_str());
520  return defValue;
521 }
522  /*}}}*/
523 static bool LineStartsWithAndStrip(std::string &line, APT::StringView const with)/*{{{*/
524 {
525  if (line.compare(0, with.size(), with.data()) != 0)
526  return false;
527  line = APT::String::Strip(line.substr(with.length()));
528  return true;
529 }
530  /*}}}*/
531 static bool ReadFlag(unsigned int &flags, std::string &line, APT::StringView const name, unsigned int const setflag)/*{{{*/
532 {
533  if (LineStartsWithAndStrip(line, name) == false)
534  return false;
535  if (localStringToBool(line, false))
536  flags |= setflag;
537  else
538  flags &= ~~setflag;
539  return true;
540 }
541  /*}}}*/
542 // EDSP::ReadRequest - first stanza from the given file descriptor /*{{{*/
543 bool EDSP::ReadRequest(int const input, std::list<std::string> &install,
544  std::list<std::string> &remove, unsigned int &flags)
545 {
546  install.clear();
547  remove.clear();
548  flags = 0;
549  std::string line;
550  while (ReadLine(input, line) == true)
551  {
552  // Skip empty lines before request
553  if (line.empty() == true)
554  continue;
555  // The first Tag must be a request, so search for it
556  if (LineStartsWithAndStrip(line, "Request:"))
557  continue;
558 
559  while (ReadLine(input, line) == true)
560  {
561  // empty lines are the end of the request
562  if (line.empty() == true)
563  return true;
564 
565  std::list<std::string> *request = NULL;
566  if (LineStartsWithAndStrip(line, "Install:"))
567  request = &install;
568  else if (LineStartsWithAndStrip(line, "Remove:"))
569  request = &remove;
570  else if (ReadFlag(flags, line, "Upgrade:", (Request::UPGRADE_ALL | Request::FORBID_REMOVE | Request::FORBID_NEW_INSTALL)) ||
571  ReadFlag(flags, line, "Dist-Upgrade:", Request::UPGRADE_ALL) ||
572  ReadFlag(flags, line, "Upgrade-All:", Request::UPGRADE_ALL) ||
573  ReadFlag(flags, line, "Forbid-New-Install:", Request::FORBID_NEW_INSTALL) ||
574  ReadFlag(flags, line, "Forbid-Remove:", Request::FORBID_REMOVE) ||
575  ReadFlag(flags, line, "Autoremove:", Request::AUTOREMOVE))
576  ;
577  else if (LineStartsWithAndStrip(line, "Architecture:"))
578  _config->Set("APT::Architecture", line);
579  else if (LineStartsWithAndStrip(line, "Architectures:"))
580  _config->Set("APT::Architectures", SubstVar(line, " ", ","));
581  else if (LineStartsWithAndStrip(line, "Solver:"))
582  ; // purely informational line
583  else
584  _error->Warning("Unknown line in EDSP Request stanza: %s", line.c_str());
585 
586  if (request == NULL)
587  continue;
588  auto const pkgs = VectorizeString(line, ' ');
589  std::move(pkgs.begin(), pkgs.end(), std::back_inserter(*request));
590  }
591  }
592  return false;
593 } /*}}}*/
594 // EDSP::ApplyRequest - first stanza from the given file descriptor /*{{{*/
595 bool EDSP::ApplyRequest(std::list<std::string> const &install,
596  std::list<std::string> const &remove,
597  pkgDepCache &Cache)
598 {
599  for (std::list<std::string>::const_iterator i = install.begin();
600  i != install.end(); ++i) {
601  pkgCache::PkgIterator P = Cache.FindPkg(*i);
602  if (P.end() == true)
603  _error->Warning("Package %s is not known, so can't be installed", i->c_str());
604  else
605  Cache.MarkInstall(P, false);
606  }
607 
608  for (std::list<std::string>::const_iterator i = remove.begin();
609  i != remove.end(); ++i) {
610  pkgCache::PkgIterator P = Cache.FindPkg(*i);
611  if (P.end() == true)
612  _error->Warning("Package %s is not known, so can't be installed", i->c_str());
613  else
614  Cache.MarkDelete(P);
615  }
616  return true;
617 }
618  /*}}}*/
619 // EDSP::WriteSolutionStanza - to the given file descriptor /*{{{*/
620 bool EDSP::WriteSolutionStanza(FileFd &output, char const * const Type, pkgCache::VerIterator const &Ver)
621 {
622  bool Okay = output.Failed() == false;
623  WriteOkay(Okay, output, Type, ": ", _system->GetVersionMapping(Ver->ID));
624  if (_config->FindB("Debug::EDSP::WriteSolution", false) == true)
625  WriteOkay(Okay, output, "\nPackage: ", Ver.ParentPkg().FullName(), "\nVersion: ", Ver.VerStr());
626  return WriteOkay(Okay, output, "\n\n");
627 }
628  /*}}}*/
629 // EDSP::WriteProgess - pulse to the given file descriptor /*{{{*/
630 bool EDSP::WriteProgress(unsigned short const percent, const char* const message, FileFd &output) {
631  return WriteOkay(output, "Progress: ", TimeRFC1123(time(NULL), true), "\n",
632  "Percentage: ", percent, "\n",
633  "Message: ", message, "\n\n") && output.Flush();
634 }
635  /*}}}*/
636 // EDSP::WriteError - format an error message to be send to file descriptor /*{{{*/
637 static std::string formatMessage(std::string const &msg)
638 {
639  return SubstVar(SubstVar(APT::String::Strip(msg), "\n\n", "\n.\n"), "\n", "\n ");
640 }
641 bool EDSP::WriteError(char const * const uuid, std::string const &message, FileFd &output) {
642  return WriteOkay(output, "Error: ", uuid, "\n",
643  "Message: ", formatMessage(message),
644  "\n\n");
645 }
646  /*}}}*/
647 static std::string findExecutable(std::vector<std::string> const &dirs, char const * const binary) {/*{{{*/
648  for (auto && dir : dirs) {
649  std::string const file = flCombine(dir, binary);
650  if (RealFileExists(file) == true)
651  return file;
652  }
653  return "";
654 }
655  /*}}}*/
656 static pid_t ExecuteExternal(char const* const type, char const * const binary, char const * const configdir, int * const solver_in, int * const solver_out) {/*{{{*/
657  auto const solverDirs = _config->FindVector(configdir);
658  auto const file = findExecutable(solverDirs, binary);
659  std::string dumper;
660  {
661  dumper = findExecutable(solverDirs, "apt-dump-solver");
662  if (dumper.empty())
663  dumper = findExecutable(solverDirs, "dump");
664  }
665 
666  if (file.empty() == true)
667  {
668  _error->Error("Can't call external %s '%s' as it is not in a configured directory!", type, binary);
669  return 0;
670  }
671  int external[4] = {-1, -1, -1, -1};
672  if (pipe(external) != 0 || pipe(external + 2) != 0)
673  {
674  _error->Errno("Resolve", "Can't create needed IPC pipes for EDSP");
675  return 0;
676  }
677  for (int i = 0; i < 4; ++i)
678  SetCloseExec(external[i], true);
679 
680  pid_t Solver = ExecFork();
681  if (Solver == 0) {
682  dup2(external[0], STDIN_FILENO);
683  dup2(external[3], STDOUT_FILENO);
684  auto const dumpfile = _config->FindFile((std::string("Dir::Log::") + type).c_str());
685  auto const dumpdir = flNotFile(dumpfile);
686  auto const runasuser = _config->Find(std::string("APT::") + type + "::" + binary + "::RunAsUser",
687  _config->Find(std::string("APT::") + type + "::RunAsUser",
688  _config->Find("APT::Sandbox::User")));
689  if (dumper.empty() || dumpfile.empty() || dumper == file || CreateAPTDirectoryIfNeeded(dumpdir, dumpdir) == false)
690  {
691  _config->Set("APT::Sandbox::User", runasuser);
692  DropPrivileges();
693  char const * const calling[] = { file.c_str(), nullptr };
694  execv(calling[0], const_cast<char**>(calling));
695  }
696  else
697  {
698  char const * const calling[] = { dumper.c_str(), "--user", runasuser.c_str(), dumpfile.c_str(), file.c_str(), nullptr };
699  execv(calling[0], const_cast<char**>(calling));
700  }
701  std::cerr << "Failed to execute " << type << " '" << binary << "'!" << std::endl;
702  _exit(100);
703  }
704  close(external[0]);
705  close(external[3]);
706 
707  if (WaitFd(external[1], true, 5) == false)
708  {
709  _error->Errno("Resolve", "Timed out while Waiting on availability of %s stdin", type);
710  return 0;
711  }
712 
713  *solver_in = external[1];
714  *solver_out = external[2];
715  return Solver;
716 }
717  /*}}}*/
718 // EDSP::ExecuteSolver - fork requested solver and setup ipc pipes {{{*/
719 pid_t EDSP::ExecuteSolver(const char* const solver, int * const solver_in, int * const solver_out, bool) {
720  return ExecuteExternal("solver", solver, "Dir::Bin::Solvers", solver_in, solver_out);
721 }
722  /*}}}*/
723 static bool CreateDumpFile(char const * const id, char const * const type, FileFd &output)/*{{{*/
724 {
725  auto const dumpfile = _config->FindFile((std::string("Dir::Log::") + type).c_str());
726  if (dumpfile.empty())
727  return false;
728  auto const dumpdir = flNotFile(dumpfile);
729  _error->PushToStack();
730  bool errored_out = CreateAPTDirectoryIfNeeded(dumpdir, dumpdir) == false ||
731  output.Open(dumpfile, FileFd::WriteOnly | FileFd::Exclusive | FileFd::Create, FileFd::Extension, 0644) == false;
732  std::vector<std::string> downgrademsgs;
733  while (_error->empty() == false)
734  {
735  std::string msg;
736  _error->PopMessage(msg);
737  downgrademsgs.emplace_back(std::move(msg));
738  }
739  _error->RevertToStack();
740  for (auto && msg : downgrademsgs)
741  _error->Warning("%s", msg.c_str());
742  if (errored_out)
743  return _error->WarningE(id, _("Could not open file '%s'"), dumpfile.c_str());
744  return true;
745 }
746  /*}}}*/
747 // EDSP::ResolveExternal - resolve problems by asking external for help {{{*/
748 bool EDSP::ResolveExternal(const char* const solver, pkgDepCache &Cache,
749  unsigned int const flags, OpProgress *Progress) {
750  if (strcmp(solver, "internal") == 0)
751  {
752  FileFd output;
753  bool Okay = CreateDumpFile("EDSP::Resolve", "solver", output);
754  Okay &= EDSP::WriteRequest(Cache, output, flags, nullptr);
755  return Okay && EDSP::WriteScenario(Cache, output, nullptr);
756  }
757  _error->PushToStack();
758  int solver_in, solver_out;
759  pid_t const solver_pid = ExecuteSolver(solver, &solver_in, &solver_out, true);
760  if (solver_pid == 0)
761  return false;
762 
763  FileFd output;
764  if (output.OpenDescriptor(solver_in, FileFd::WriteOnly | FileFd::BufferedWrite, true) == false)
765  return _error->Errno("ResolveExternal", "Opening solver %s stdin on fd %d for writing failed", solver, solver_in);
766 
767  bool Okay = output.Failed() == false;
768  if (Okay && Progress != NULL)
769  Progress->OverallProgress(0, 100, 5, _("Execute external solver"));
770  Okay &= EDSP::WriteRequest(Cache, output, flags, Progress);
771  if (Okay && Progress != NULL)
772  Progress->OverallProgress(5, 100, 20, _("Execute external solver"));
773  Okay &= EDSP::WriteScenario(Cache, output, Progress);
774  output.Close();
775 
776  if (Okay && Progress != NULL)
777  Progress->OverallProgress(25, 100, 75, _("Execute external solver"));
778  bool const ret = EDSP::ReadResponse(solver_out, Cache, Progress);
779  _error->MergeWithStack();
780  if (ExecWait(solver_pid, solver))
781  return ret;
782  return false;
783 } /*}}}*/
784 
785 bool EIPP::OrderInstall(char const * const solver, pkgPackageManager * const PM, /*{{{*/
786  unsigned int const flags, OpProgress * const Progress)
787 {
788  if (strcmp(solver, "internal") == 0)
789  {
790  FileFd output;
791  _error->PushToStack();
792  bool Okay = CreateDumpFile("EIPP::OrderInstall", "planner", output);
793  if (Okay == false && dynamic_cast<pkgSimulate*>(PM) != nullptr)
794  {
795  _error->RevertToStack();
796  return false;
797  }
798  _error->MergeWithStack();
799  Okay &= EIPP::WriteRequest(PM->Cache, output, flags, nullptr);
800  return Okay && EIPP::WriteScenario(PM->Cache, output, nullptr);
801  }
802  _error->PushToStack();
803  int solver_in, solver_out;
804  pid_t const solver_pid = ExecuteExternal("planner", solver, "Dir::Bin::Planners", &solver_in, &solver_out);
805  if (solver_pid == 0)
806  return false;
807 
808  FileFd output;
809  if (output.OpenDescriptor(solver_in, FileFd::WriteOnly | FileFd::BufferedWrite, true) == false)
810  return _error->Errno("EIPP::OrderInstall", "Opening planner %s stdin on fd %d for writing failed", solver, solver_in);
811 
812  bool Okay = output.Failed() == false;
813  if (Okay && Progress != NULL)
814  Progress->OverallProgress(0, 100, 5, _("Execute external planner"));
815  Okay &= EIPP::WriteRequest(PM->Cache, output, flags, Progress);
816  if (Okay && Progress != NULL)
817  Progress->OverallProgress(5, 100, 20, _("Execute external planner"));
818  Okay &= EIPP::WriteScenario(PM->Cache, output, Progress);
819  output.Close();
820 
821  if (Okay)
822  {
823  if (Progress != nullptr)
824  Progress->OverallProgress(25, 100, 75, _("Execute external planner"));
825 
826  // we don't tell the external planners about boring things
827  for (auto Pkg = PM->Cache.PkgBegin(); Pkg.end() == false; ++Pkg)
828  {
829  if (Pkg->CurrentState == pkgCache::State::ConfigFiles && PM->Cache[Pkg].Purge() == true)
830  PM->Remove(Pkg, true);
831  }
832  }
833  bool const ret = EIPP::ReadResponse(solver_out, PM, Progress);
834  _error->MergeWithStack();
835  if (ExecWait(solver_pid, solver))
836  return ret;
837  return false;
838 }
839  /*}}}*/
840 bool EIPP::WriteRequest(pkgDepCache &Cache, FileFd &output, /*{{{*/
841  unsigned int const flags,
842  OpProgress * const Progress)
843 {
844  if (Progress != NULL)
845  Progress->SubProgress(Cache.Head().PackageCount, _("Send request to planner"));
846  decltype(Cache.Head().PackageCount) p = 0;
847  string del, inst, reinst;
848  for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; ++Pkg, ++p)
849  {
850  if (Progress != NULL && p % 100 == 0)
851  Progress->Progress(p);
852  string* req;
853  pkgDepCache::StateCache &P = Cache[Pkg];
854  if (P.Purge() == true && Pkg->CurrentState == pkgCache::State::ConfigFiles)
855  continue;
856  if (P.Delete() == true)
857  req = &del;
858  else if (P.NewInstall() == true || P.Upgrade() == true || P.Downgrade() == true)
859  req = &inst;
860  else if (P.ReInstall() == true)
861  req = &reinst;
862  else
863  continue;
864  req->append(" ").append(Pkg.FullName());
865  }
866  bool Okay = WriteOkay(output, "Request: EIPP 0.1\n");
867 
868  std::vector<string> archs = APT::Configuration::getArchitectures();
869  WriteOkay(Okay, output, "Architecture: ", _config->Find("APT::Architecture").c_str(), "\n",
870  "Architectures:");
871  for (std::vector<string>::const_iterator a = archs.begin(); a != archs.end(); ++a)
872  WriteOkay(Okay, output, " ", *a);
873  WriteOkay(Okay, output, "\n");
874 
875  if (del.empty() == false)
876  WriteOkay(Okay, output, "Remove:", del, "\n");
877  if (inst.empty() == false)
878  WriteOkay(Okay, output, "Install:", inst, "\n");
879  if (reinst.empty() == false)
880  WriteOkay(Okay, output, "ReInstall:", reinst, "\n");
881  WriteOkay(Okay, output, "Planner: ", _config->Find("APT::Planner", "internal"), "\n");
882  if ((flags & Request::IMMEDIATE_CONFIGURATION_ALL) != 0)
883  WriteOkay(Okay, output, "Immediate-Configuration: yes\n");
884  else if ((flags & Request::NO_IMMEDIATE_CONFIGURATION) != 0)
885  WriteOkay(Okay, output, "Immediate-Configuration: no\n");
886  else if ((flags & Request::ALLOW_TEMPORARY_REMOVE_OF_ESSENTIALS) != 0)
887  WriteOkay(Okay, output, "Allow-Temporary-Remove-of-Essentials: yes\n");
888  return WriteOkay(Okay, output, "\n");
889 }
890  /*}}}*/
891 static bool WriteScenarioEIPPVersion(pkgDepCache &, FileFd &output, pkgCache::PkgIterator const &Pkg,/*{{{*/
892  pkgCache::VerIterator const &Ver)
893 {
894  bool Okay = true;
895  if (Pkg.CurrentVer() == Ver)
896  switch (Pkg->CurrentState)
897  {
898  case pkgCache::State::NotInstalled: WriteOkay(Okay, output, "\nStatus: not-installed"); break;
899  case pkgCache::State::ConfigFiles: WriteOkay(Okay, output, "\nStatus: config-files"); break;
900  case pkgCache::State::HalfInstalled: WriteOkay(Okay, output, "\nStatus: half-installed"); break;
901  case pkgCache::State::UnPacked: WriteOkay(Okay, output, "\nStatus: unpacked"); break;
902  case pkgCache::State::HalfConfigured: WriteOkay(Okay, output, "\nStatus: half-configured"); break;
903  case pkgCache::State::TriggersAwaited: WriteOkay(Okay, output, "\nStatus: triggers-awaited"); break;
904  case pkgCache::State::TriggersPending: WriteOkay(Okay, output, "\nStatus: triggers-pending"); break;
905  case pkgCache::State::Installed: WriteOkay(Okay, output, "\nStatus: installed"); break;
906  }
907  return Okay;
908 }
909  /*}}}*/
910 // EIPP::WriteScenario - to the given file descriptor /*{{{*/
911 template<typename forVersion> void forAllInterestingVersions(pkgDepCache &Cache, pkgCache::PkgIterator const &Pkg, forVersion const &func)
912 {
913  if (Pkg->CurrentState == pkgCache::State::NotInstalled)
914  {
915  auto P = Cache[Pkg];
916  if (P.Install() == false)
917  return;
918  func(Pkg, P.InstVerIter(Cache));
919  }
920  else
921  {
922  if (Pkg->CurrentVer != 0)
923  func(Pkg, Pkg.CurrentVer());
924  auto P = Cache[Pkg];
925  auto const V = P.InstVerIter(Cache);
926  if (P.Delete() == false && Pkg.CurrentVer() != V)
927  func(Pkg, V);
928  }
929 }
930 
931 bool EIPP::WriteScenario(pkgDepCache &Cache, FileFd &output, OpProgress * const Progress)
932 {
933  if (Progress != NULL)
934  Progress->SubProgress(Cache.Head().PackageCount, _("Send scenario to planner"));
935  decltype(Cache.Head().PackageCount) p = 0;
936  bool Okay = output.Failed() == false;
937  std::vector<std::string> archs = APT::Configuration::getArchitectures();
938  std::vector<bool> pkgset(Cache.Head().PackageCount, false);
939  auto const MarkVersion = [&](pkgCache::PkgIterator const &Pkg, pkgCache::VerIterator const &Ver) {
940  pkgset[Pkg->ID] = true;
941  for (auto D = Ver.DependsList(); D.end() == false; ++D)
942  {
943  if (D.IsCritical() == false)
944  continue;
945  auto const P = D.TargetPkg();
946  for (auto Prv = P.ProvidesList(); Prv.end() == false; ++Prv)
947  {
948  auto const V = Prv.OwnerVer();
949  auto const PV = V.ParentPkg();
950  if (V == PV.CurrentVer() || V == Cache[PV].InstVerIter(Cache))
951  pkgset[PV->ID] = true;
952  }
953  pkgset[P->ID] = true;
954  if (strcmp(P.Arch(), "any") == 0)
955  {
956  APT::StringView const pkgname(P.Name());
957  auto const idxColon = pkgname.find(':');
958  if (idxColon != APT::StringView::npos)
959  {
961  if (pkgname.substr(idxColon + 1) == "any")
962  {
963  auto const GA = Cache.FindGrp(pkgname.substr(0, idxColon).to_string());
964  for (auto PA = GA.PackageList(); PA.end() == false; PA = GA.NextPkg(PA))
965  {
966  pkgset[PA->ID] = true;
967  }
968  }
969  else
970  {
971  auto const PA = Cache.FindPkg(pkgname.to_string());
972  if (PA.end() == false)
973  pkgset[PA->ID] = true;
974  }
975  }
976  }
977  else
978  {
979  auto const PA = Cache.FindPkg(P.FullName(false), "any");
980  if (PA.end() == false)
981  pkgset[PA->ID] = true;
982  }
983  }
984  };
985  for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; ++Pkg)
986  forAllInterestingVersions(Cache, Pkg, MarkVersion);
987  auto const WriteVersion = [&](pkgCache::PkgIterator const &Pkg, pkgCache::VerIterator const &Ver) {
988  Okay &= WriteScenarioVersion(output, Pkg, Ver);
989  Okay &= WriteScenarioEIPPVersion(Cache, output, Pkg, Ver);
990  Okay &= WriteScenarioLimitedDependency(output, Ver, pkgset, true);
991  WriteOkay(Okay, output, "\n");
992  if (Progress != NULL && p % 100 == 0)
993  Progress->Progress(p);
994  };
995  for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false && likely(Okay); ++Pkg, ++p)
996  {
997  if (pkgset[Pkg->ID] == false || Pkg->VersionList == 0)
998  continue;
999  forAllInterestingVersions(Cache, Pkg, WriteVersion);
1000  }
1001  return Okay;
1002 }
1003  /*}}}*/
1004 // EIPP::ReadResponse - from the given file descriptor /*{{{*/
1005 bool EIPP::ReadResponse(int const input, pkgPackageManager * const PM, OpProgress *Progress) {
1006  /* We build an map id to mmap offset here
1007  In theory we could use the offset as ID, but then VersionCount
1008  couldn't be used to create other versionmappings anymore and it
1009  would be too easy for a (buggy) solver to segfault APT… */
1010  auto VersionCount = PM->Cache.Head().VersionCount;
1011  decltype(VersionCount) VerIdx[VersionCount];
1012  for (pkgCache::PkgIterator P = PM->Cache.PkgBegin(); P.end() == false; ++P) {
1013  for (pkgCache::VerIterator V = P.VersionList(); V.end() == false; ++V)
1014  VerIdx[V->ID] = V.Index();
1015  }
1016 
1017  FileFd in;
1018  in.OpenDescriptor(input, FileFd::ReadOnly);
1019  pkgTagFile response(&in, 100);
1020  pkgTagSection section;
1021 
1022  while (response.Step(section) == true) {
1023  char const * type = nullptr;
1024  if (section.Exists("Progress") == true) {
1025  if (Progress != NULL) {
1026  string msg = section.FindS("Message");
1027  if (msg.empty() == true)
1028  msg = _("Prepare for receiving solution");
1029  Progress->SubProgress(100, msg, section.FindI("Percentage", 0));
1030  }
1031  continue;
1032  } else if (section.Exists("Error") == true) {
1033  if (_error->PendingError()) {
1034  if (Progress != nullptr)
1035  Progress->Done();
1036  Progress = nullptr;
1037  _error->DumpErrors(std::cerr, GlobalError::DEBUG, false);
1038  }
1039  std::string msg = SubstVar(SubstVar(section.FindS("Message"), "\n .\n", "\n\n"), "\n ", "\n");
1040  if (msg.empty() == true) {
1041  msg = _("External planner failed without a proper error message");
1042  _error->Error("%s", msg.c_str());
1043  } else
1044  _error->Error("External planner failed with: %s", msg.substr(0,msg.find('\n')).c_str());
1045  if (Progress != nullptr)
1046  Progress->Done();
1047  std::cerr << "The planner encountered an error of type: " << section.FindS("Error") << std::endl;
1048  std::cerr << "The following information might help you to understand what is wrong:" << std::endl;
1049  std::cerr << msg << std::endl << std::endl;
1050  return false;
1051  } else if (section.Exists("Unpack") == true)
1052  type = "Unpack";
1053  else if (section.Exists("Configure") == true)
1054  type = "Configure";
1055  else if (section.Exists("Remove") == true)
1056  type = "Remove";
1057  else {
1058  char const *Start, *End;
1059  section.GetSection(Start, End);
1060  _error->Warning("Encountered an unexpected section with %d fields: %s", section.Count(), std::string(Start, End).c_str());
1061  continue;
1062  }
1063 
1064  if (type == nullptr)
1065  continue;
1066  decltype(VersionCount) const id = section.FindULL(type, VersionCount);
1067  if (id == VersionCount) {
1068  _error->Warning("Unable to parse %s request with id value '%s'!", type, section.FindS(type).c_str());
1069  continue;
1070  } else if (id > VersionCount) {
1071  _error->Warning("ID value '%s' in %s request stanza is to high to refer to a known version!", section.FindS(type).c_str(), type);
1072  continue;
1073  }
1074 
1075  pkgCache::VerIterator Ver(PM->Cache.GetCache(), PM->Cache.GetCache().VerP + VerIdx[id]);
1076  auto const Pkg = Ver.ParentPkg();
1077  if (strcmp(type, "Unpack") == 0)
1078  PM->Install(Pkg, PM->FileNames[Pkg->ID]);
1079  else if (strcmp(type, "Configure") == 0)
1080  PM->Configure(Pkg);
1081  else if (strcmp(type, "Remove") == 0)
1082  PM->Remove(Pkg, PM->Cache[Pkg].Purge());
1083  }
1084  return in.Failed() == false;
1085 }
1086  /*}}}*/
1087 bool EIPP::ReadRequest(int const input, std::list<std::pair<std::string,PKG_ACTION>> &actions,/*{{{*/
1088  unsigned int &flags)
1089 {
1090  actions.clear();
1091  flags = 0;
1092  std::string line;
1093  while (ReadLine(input, line) == true)
1094  {
1095  // Skip empty lines before request
1096  if (line.empty() == true)
1097  continue;
1098  // The first Tag must be a request, so search for it
1099  if (line.compare(0, 8, "Request:") != 0)
1100  continue;
1101 
1102  while (ReadLine(input, line) == true)
1103  {
1104  // empty lines are the end of the request
1105  if (line.empty() == true)
1106  return true;
1107 
1108  PKG_ACTION pkgact = PKG_ACTION::NOOP;
1109  if (LineStartsWithAndStrip(line, "Install:"))
1110  pkgact = PKG_ACTION::INSTALL;
1111  else if (LineStartsWithAndStrip(line, "ReInstall:"))
1112  pkgact = PKG_ACTION::REINSTALL;
1113  else if (LineStartsWithAndStrip(line, "Remove:"))
1114  pkgact = PKG_ACTION::REMOVE;
1115  else if (LineStartsWithAndStrip(line, "Architecture:"))
1116  _config->Set("APT::Architecture", line);
1117  else if (LineStartsWithAndStrip(line, "Architectures:"))
1118  _config->Set("APT::Architectures", SubstVar(line, " ", ","));
1119  else if (LineStartsWithAndStrip(line, "Planner:"))
1120  ; // purely informational line
1121  else if (LineStartsWithAndStrip(line, "Immediate-Configuration:"))
1122  {
1123  if (localStringToBool(line, true))
1125  else
1127  }
1128  else if (ReadFlag(flags, line, "Allow-Temporary-Remove-of-Essentials:", Request::ALLOW_TEMPORARY_REMOVE_OF_ESSENTIALS))
1129  ;
1130  else
1131  _error->Warning("Unknown line in EIPP Request stanza: %s", line.c_str());
1132 
1133  if (pkgact == PKG_ACTION::NOOP)
1134  continue;
1135  for (auto && p: VectorizeString(line, ' '))
1136  actions.emplace_back(std::move(p), pkgact);
1137  }
1138  }
1139  return false;
1140 }
1141  /*}}}*/
1142 bool EIPP::ApplyRequest(std::list<std::pair<std::string,PKG_ACTION>> &actions,/*{{{*/
1143  pkgDepCache &Cache)
1144 {
1145  for (auto Pkg = Cache.PkgBegin(); Pkg.end() == false; ++Pkg)
1146  {
1147  short versions = 0;
1148  for (auto Ver = Pkg.VersionList(); Ver.end() == false; ++Ver)
1149  {
1150  ++versions;
1151  if (Pkg.CurrentVer() == Ver)
1152  continue;
1153  Cache.SetCandidateVersion(Ver);
1154  }
1155  if (unlikely(versions > 2))
1156  _error->Warning("Package %s has %d versions, but should have at most 2!", Pkg.FullName().c_str(), versions);
1157  }
1158  for (auto && a: actions)
1159  {
1160  pkgCache::PkgIterator P = Cache.FindPkg(a.first);
1161  if (P.end() == true)
1162  {
1163  _error->Warning("Package %s is not known, so can't be acted on", a.first.c_str());
1164  continue;
1165  }
1166  switch (a.second)
1167  {
1168  case PKG_ACTION::NOOP:
1169  _error->Warning("Package %s has NOOP as action?!?", a.first.c_str());
1170  break;
1171  case PKG_ACTION::INSTALL:
1172  Cache.MarkInstall(P, false);
1173  break;
1174  case PKG_ACTION::REINSTALL:
1175  Cache.MarkInstall(P, false);
1176  Cache.SetReInstall(P, true);
1177  break;
1178  case PKG_ACTION::REMOVE:
1179  Cache.MarkDelete(P);
1180  break;
1181  }
1182  }
1183  return true;
1184 }
1185  /*}}}*/
strprintf(m, msg, repo.c_str())
static bool std::string const metaIndex const *const pkgAcqMetaClearSig *const pkgAcquire::Item *const I
static char const *const msg
Simple subset of std::string_view from C++17.
Definition: string_view.h:27
constexpr StringView substr(size_t pos, size_t n=npos) const
Definition: string_view.h:48
static constexpr size_t npos
Definition: string_view.h:32
constexpr size_t length() const
Definition: string_view.h:138
constexpr const char * data() const
Definition: string_view.h:133
std::string to_string() const
Definition: string_view.h:106
constexpr size_t size() const
Definition: string_view.h:137
size_t find(int c, size_t pos) const
Definition: string_view.h:52
bool Exists(const std::string &Name) const
Definition: configuration.h:98
void Set(const std::string &Name, const std::string &Value)
Definition: configuration.h:92
std::vector< std::string > FindVector(const char *Name, std::string const &Default="", bool const Keys=false) const
std::string Find(const char *Name, const char *Default=0) const
bool FindB(const char *Name, bool const &Default=false) const
std::string FindFile(const char *Name, const char *Default=0) const
Definition: fileutl.h:39
bool OpenDescriptor(int Fd, unsigned int const Mode, CompressMode Compress, bool AutoClose=false)
Definition: fileutl.cc:2572
@ Extension
Definition: fileutl.h:80
@ WriteOnly
Definition: fileutl.h:60
@ BufferedWrite
Definition: fileutl.h:67
@ Exclusive
Definition: fileutl.h:64
@ Create
Definition: fileutl.h:63
@ ReadOnly
Definition: fileutl.h:59
bool Flush()
Definition: fileutl.cc:2808
bool Write(const void *From, unsigned long long Size)
Definition: fileutl.cc:2819
bool Failed()
Definition: fileutl.h:151
bool Open(std::string FileName, unsigned int const Mode, CompressMode Compress, unsigned long const AccessMode=0666)
Definition: fileutl.cc:2415
bool Close()
Definition: fileutl.cc:2977
std::string & Name()
Definition: fileutl.h:156
@ DEBUG
for developers only in areas it is hard to print something directly
Definition: error.h:66
virtual void Done()
Definition: progress.h:60
void OverallProgress(unsigned long long Current, unsigned long long Total, unsigned long long Size, const std::string &Op)
Definition: progress.cc:55
void Progress(unsigned long long Current)
Definition: progress.cc:43
void SubProgress(unsigned long long SubTotal, const std::string &Op="", float const Percent=-1)
Definition: progress.cc:73
Version * VerP
Definition: pkgcache.h:228
static const char * CompTypeDeb(unsigned char Comp) APT_PURE
Definition: pkgcache.cc:317
virtual signed short GetPriority(PkgIterator const &Pkg)
Definition: depcache.cc:2168
PkgIterator FindPkg(APT::StringView Name)
Definition: depcache.h:358
Policy & GetPolicy()
Definition: depcache.h:365
GrpIterator FindGrp(APT::StringView Name)
Definition: depcache.h:357
void SetReInstall(PkgIterator const &Pkg, bool To)
Definition: depcache.cc:1826
pkgCache::VerIterator GetCandidateVersion(pkgCache::PkgIterator const &Pkg)
Definition: depcache.cc:1863
void SetCandidateVersion(VerIterator TargetVer)
Definition: depcache.cc:1871
bool MarkInstall(PkgIterator const &Pkg, bool AutoInst=true, unsigned long Depth=0, bool FromUser=true, bool ForceImportantDeps=false)
Definition: depcache.cc:1560
PkgIterator PkgBegin()
Definition: depcache.h:356
pkgCache & GetCache()
Definition: depcache.h:361
bool MarkDelete(PkgIterator const &Pkg, bool MarkPurge=false, unsigned long Depth=0, bool FromUser=true)
Definition: depcache.cc:991
Header & Head()
Definition: depcache.h:354
std::string * FileNames
pkgDepCache & Cache
virtual bool Configure(PkgIterator)
virtual bool Remove(PkgIterator, bool=false)
virtual bool Install(PkgIterator, std::string)
APT_HIDDEN map_id_t GetVersionMapping(map_id_t const in) const
Definition: pkgsystem.cc:66
bool Step(pkgTagSection &Section)
Definition: tagfile.cc:204
void GetSection(const char *&Start, const char *&Stop) const
Definition: tagfile.h:135
std::string FindS(APT::StringView sv) const
Definition: tagfile.h:70
APT_HIDDEN bool Exists(Key key) const
unsigned int Count() const
amount of Tags in the current section
Definition: tagfile.cc:942
APT_HIDDEN signed int FindI(Key key, signed long Default=0) const
Definition: tagfile.cc:776
APT_HIDDEN unsigned long long FindULL(Key key, unsigned long long const &Default=0) const
Definition: tagfile.cc:812
Configuration * _config
static bool WriteOkay_fn(FileFd &)
Definition: edsp.cc:55
constexpr char const *const PrioMap[]
Definition: edsp.cc:44
static bool WriteScenarioDependency(FileFd &output, pkgCache::VerIterator const &Ver, bool const OnlyCritical)
Definition: edsp.cc:97
static bool LineStartsWithAndStrip(std::string &line, APT::StringView const with)
Definition: edsp.cc:523
static bool CreateDumpFile(char const *const id, char const *const type, FileFd &output)
Definition: edsp.cc:723
static std::string formatMessage(std::string const &msg)
Definition: edsp.cc:637
constexpr char const *const DepMap[]
Definition: edsp.cc:48
static bool WriteScenarioLimitedDependency(FileFd &output, pkgCache::VerIterator const &Ver, std::vector< bool > const &pkgset, bool const OnlyCritical)
Definition: edsp.cc:147
static bool WriteScenarioEDSPVersion(pkgDepCache &Cache, FileFd &output, pkgCache::PkgIterator const &Pkg, pkgCache::VerIterator const &Ver)
Definition: edsp.cc:226
static bool SkipUnavailableVersions(pkgDepCache &Cache, pkgCache::PkgIterator const &Pkg, pkgCache::VerIterator const &Ver)
Definition: edsp.cc:208
static bool WriteOkay(bool &Okay, FileFd &output, Data &&... data)
Definition: edsp.cc:66
void forAllInterestingVersions(pkgDepCache &Cache, pkgCache::PkgIterator const &Pkg, forVersion const &func)
Definition: edsp.cc:911
static bool localStringToBool(std::string answer, bool const defValue)
Definition: edsp.cc:512
static std::string findExecutable(std::vector< std::string > const &dirs, char const *const binary)
Definition: edsp.cc:647
static bool ReadFlag(unsigned int &flags, std::string &line, APT::StringView const name, unsigned int const setflag)
Definition: edsp.cc:531
static bool WriteScenarioEIPPVersion(pkgDepCache &, FileFd &output, pkgCache::PkgIterator const &Pkg, pkgCache::VerIterator const &Ver)
Definition: edsp.cc:891
static bool WriteScenarioVersion(FileFd &output, pkgCache::PkgIterator const &Pkg, pkgCache::VerIterator const &Ver)
Definition: edsp.cc:78
static pid_t ExecuteExternal(char const *const type, char const *const binary, char const *const configdir, int *const solver_in, int *const solver_out)
Definition: edsp.cc:656
static bool ReadLine(int const input, std::string &line)
Definition: edsp.cc:489
void SetCloseExec(int Fd, bool Close)
Definition: fileutl.cc:792
string flNotFile(string File)
Definition: fileutl.cc:676
bool ExecWait(pid_t Pid, const char *Name, bool Reap)
Definition: fileutl.cc:942
bool CreateAPTDirectoryIfNeeded(string const &Parent, string const &Path)
Ensure the existence of the given Path.
Definition: fileutl.cc:400
bool WaitFd(int Fd, bool write, unsigned long timeout)
Definition: fileutl.cc:819
bool DropPrivileges()
Drop privileges.
Definition: fileutl.cc:3260
string flCombine(string Dir, string File)
Definition: fileutl.cc:740
bool RealFileExists(string File)
Definition: fileutl.cc:337
pid_t ExecFork()
Definition: fileutl.cc:881
#define APT_ARRAY_SIZE(a)
Definition: macros.h:18
APT_PUBLIC std::vector< std::string > const getArchitectures(bool const &Cached=true)
Returns a vector of Architectures we support.
std::string Strip(const std::string &str)
Definition: strutl.cc:55
@ AUTOREMOVE
Definition: edsp.h:32
@ FORBID_REMOVE
Definition: edsp.h:35
@ FORBID_NEW_INSTALL
Definition: edsp.h:34
@ UPGRADE_ALL
Definition: edsp.h:33
APT_PUBLIC bool ResolveExternal(const char *const solver, pkgDepCache &Cache, unsigned int const flags=0, OpProgress *Progress=NULL)
call an external resolver to handle the request
Definition: edsp.cc:748
APT_PUBLIC bool ReadResponse(int const input, pkgDepCache &Cache, OpProgress *Progress=NULL)
waits and acts on the information returned from the solver
Definition: edsp.cc:383
APT_PUBLIC bool WriteRequest(pkgDepCache &Cache, FileFd &output, unsigned int const flags=0, OpProgress *Progress=NULL)
creates the EDSP request stanza
Definition: edsp.cc:321
APT_PUBLIC bool ApplyRequest(std::list< std::string > const &install, std::list< std::string > const &remove, pkgDepCache &Cache)
takes the request lists and applies it on the cache
Definition: edsp.cc:595
APT_PUBLIC bool WriteSolutionStanza(FileFd &output, char const *const Type, pkgCache::VerIterator const &Ver)
formats a solution stanza for the given version
Definition: edsp.cc:620
APT_PUBLIC bool ReadRequest(int const input, std::list< std::string > &install, std::list< std::string > &remove, unsigned int &flags)
search and read the request stanza for action later
Definition: edsp.cc:543
APT_PUBLIC pid_t ExecuteSolver(const char *const solver, int *const solver_in, int *const solver_out, bool)
executes the given solver and returns the pipe ends
Definition: edsp.cc:719
APT_PUBLIC bool WriteLimitedScenario(pkgDepCache &Cache, FileFd &output, std::vector< bool > const &pkgset, OpProgress *Progress=NULL)
creates a limited scenario representing the package universe
Definition: edsp.cc:291
APT_PUBLIC bool WriteProgress(unsigned short const percent, const char *const message, FileFd &output)
sends a progress report
Definition: edsp.cc:630
APT_PUBLIC bool WriteScenario(pkgDepCache &Cache, FileFd &output, OpProgress *Progress=NULL)
creates the scenario representing the package universe
Definition: edsp.cc:263
APT_PUBLIC bool WriteError(char const *const uuid, std::string const &message, FileFd &output)
sends an error report
Definition: edsp.cc:641
@ NO_IMMEDIATE_CONFIGURATION
Definition: edsp.h:223
@ ALLOW_TEMPORARY_REMOVE_OF_ESSENTIALS
Definition: edsp.h:224
@ IMMEDIATE_CONFIGURATION_ALL
Definition: edsp.h:222
PKG_ACTION
Definition: edsp.h:239
APT_HIDDEN bool ReadResponse(int const input, pkgPackageManager *const PM, OpProgress *const Progress)
Definition: edsp.cc:1005
APT_HIDDEN bool WriteScenario(pkgDepCache &Cache, FileFd &output, OpProgress *const Progress)
Definition: edsp.cc:931
APT_PUBLIC bool ReadRequest(int const input, std::list< std::pair< std::string, PKG_ACTION >> &actions, unsigned int &flags)
APT_PUBLIC bool ApplyRequest(std::list< std::pair< std::string, PKG_ACTION >> &actions, pkgDepCache &Cache)
APT_HIDDEN bool WriteRequest(pkgDepCache &Cache, FileFd &output, unsigned int const flags, OpProgress *const Progress)
Definition: edsp.cc:840
APT_HIDDEN bool OrderInstall(char const *const planner, pkgPackageManager *const PM, unsigned int const version, OpProgress *const Progress)
Definition: edsp.cc:785
pkgCache - Structure definitions for the cache file
pkgSystem * _system
Definition: pkgsystem.cc:24
map_id_t VersionCount
Definition: pkgcache.h:336
map_id_t PackageCount
Definition: pkgcache.h:335
unsigned char Mode
Definition: depcache.h:240
bool NewInstall() const
Definition: depcache.h:247
bool Delete() const
Definition: depcache.h:248
bool ReInstall() const
Definition: depcache.h:261
bool Downgrade() const
Definition: depcache.h:254
unsigned short iFlags
Definition: depcache.h:225
bool Purge() const
Definition: depcache.h:249
bool Upgrade() const
Definition: depcache.h:252
string SubstVar(const string &Str, const string &Subst, const string &Contents)
Definition: strutl.cc:502
vector< string > VectorizeString(string const &haystack, char const &split)
Definition: strutl.cc:1308
string TimeRFC1123(time_t Date, bool const NumericTimezone)
Definition: strutl.cc:853