edsp.cc 56 KB

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