edsp.cc 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980
  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/error.h>
  10. #include <apt-pkg/cacheset.h>
  11. #include <apt-pkg/depcache.h>
  12. #include <apt-pkg/pkgcache.h>
  13. #include <apt-pkg/cacheiterators.h>
  14. #include <apt-pkg/progress.h>
  15. #include <apt-pkg/fileutl.h>
  16. #include <apt-pkg/edsp.h>
  17. #include <apt-pkg/tagfile.h>
  18. #include <apt-pkg/strutl.h>
  19. #include <ctype.h>
  20. #include <stddef.h>
  21. #include <string.h>
  22. #include <unistd.h>
  23. #include <stdio.h>
  24. #include <iostream>
  25. #include <limits>
  26. #include <string>
  27. #include <apti18n.h>
  28. /*}}}*/
  29. using std::string;
  30. // we could use pkgCache::DepType and ::Priority, but these would be localized strings…
  31. const char * const PrioMap[] = {0, "important", "required", "standard",
  32. "optional", "extra"};
  33. const char * const DepMap[] = {"", "Depends", "Pre-Depends", "Suggests",
  34. "Recommends" , "Conflicts", "Replaces",
  35. "Obsoletes", "Breaks", "Enhances"};
  36. // WriteOkay - varaidic helper to easily Write to a FileFd /*{{{*/
  37. static bool WriteOkay_fn(FileFd &) { return true; }
  38. template<typename... Tail> static bool WriteOkay_fn(FileFd &output, APT::StringView data, Tail... more_data)
  39. {
  40. return likely(output.Write(data.data(), data.length()) && WriteOkay_fn(output, more_data...));
  41. }
  42. template<typename... Tail> static bool WriteOkay_fn(FileFd &output, unsigned int data, Tail... more_data)
  43. {
  44. std::string number;
  45. strprintf(number, "%d", data);
  46. return likely(output.Write(number.data(), number.length()) && WriteOkay_fn(output, more_data...));
  47. }
  48. template<typename... Data> static bool WriteOkay(bool &Okay, FileFd &output, Data&&... data)
  49. {
  50. Okay = likely(Okay && WriteOkay_fn(output, std::forward<Data>(data)...));
  51. return Okay;
  52. }
  53. template<typename... Data> static bool WriteOkay(FileFd &output, Data&&... data)
  54. {
  55. bool Okay = likely(output.Failed() == false);
  56. return WriteOkay(Okay, output, std::forward<Data>(data)...);
  57. }
  58. /*}}}*/
  59. // WriteScenarioVersion /*{{{*/
  60. static void WriteScenarioVersion(pkgDepCache &Cache, FILE* output, pkgCache::PkgIterator const &Pkg,
  61. pkgCache::VerIterator const &Ver)
  62. {
  63. fprintf(output, "Package: %s\n", Pkg.Name());
  64. fprintf(output, "Source: %s\n", Ver.SourcePkgName());
  65. fprintf(output, "Architecture: %s\n", Ver.Arch());
  66. fprintf(output, "Version: %s\n", Ver.VerStr());
  67. fprintf(output, "Source-Version: %s\n", Ver.SourceVerStr());
  68. if (Pkg.CurrentVer() == Ver)
  69. fprintf(output, "Installed: yes\n");
  70. if (Pkg->SelectedState == pkgCache::State::Hold ||
  71. (Cache[Pkg].Keep() == true && Cache[Pkg].Protect() == true))
  72. fprintf(output, "Hold: yes\n");
  73. fprintf(output, "APT-ID: %d\n", Ver->ID);
  74. if (PrioMap[Ver->Priority] != nullptr)
  75. fprintf(output, "Priority: %s\n", PrioMap[Ver->Priority]);
  76. if ((Pkg->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential)
  77. fprintf(output, "Essential: yes\n");
  78. if (Ver->Section != 0)
  79. fprintf(output, "Section: %s\n", Ver.Section());
  80. if ((Ver->MultiArch & pkgCache::Version::Allowed) == pkgCache::Version::Allowed)
  81. fprintf(output, "Multi-Arch: allowed\n");
  82. else if ((Ver->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign)
  83. fprintf(output, "Multi-Arch: foreign\n");
  84. else if ((Ver->MultiArch & pkgCache::Version::Same) == pkgCache::Version::Same)
  85. fprintf(output, "Multi-Arch: same\n");
  86. std::set<string> Releases;
  87. for (pkgCache::VerFileIterator I = Ver.FileList(); I.end() == false; ++I) {
  88. pkgCache::PkgFileIterator File = I.File();
  89. if (File.Flagged(pkgCache::Flag::NotSource) == false) {
  90. string Release = File.RelStr();
  91. if (!Release.empty())
  92. Releases.insert(Release);
  93. }
  94. }
  95. if (!Releases.empty()) {
  96. fprintf(output, "APT-Release:\n");
  97. for (std::set<string>::iterator R = Releases.begin(); R != Releases.end(); ++R)
  98. fprintf(output, " %s\n", R->c_str());
  99. }
  100. fprintf(output, "APT-Pin: %d\n", Cache.GetPolicy().GetPriority(Ver));
  101. if (Cache.GetCandidateVersion(Pkg) == Ver)
  102. fprintf(output, "APT-Candidate: yes\n");
  103. if ((Cache[Pkg].Flags & pkgCache::Flag::Auto) == pkgCache::Flag::Auto)
  104. fprintf(output, "APT-Automatic: yes\n");
  105. }
  106. static bool WriteScenarioVersion(pkgDepCache &Cache, FileFd &output, pkgCache::PkgIterator const &Pkg,
  107. pkgCache::VerIterator const &Ver)
  108. {
  109. bool Okay = WriteOkay(output, "Package: ", Pkg.Name(),
  110. "\nSource: ", Ver.SourcePkgName(),
  111. "\nArchitecture: ", Ver.Arch(),
  112. "\nVersion: ", Ver.VerStr(),
  113. "\nSource-Version: ", Ver.SourceVerStr());
  114. if (Pkg.CurrentVer() == Ver)
  115. WriteOkay(Okay, output, "\nInstalled: yes");
  116. if (Pkg->SelectedState == pkgCache::State::Hold ||
  117. (Cache[Pkg].Keep() == true && Cache[Pkg].Protect() == true))
  118. WriteOkay(Okay, output, "\nHold: yes");
  119. WriteOkay(Okay, output, "\nAPT-ID: ", Ver->ID);
  120. if (PrioMap[Ver->Priority] != nullptr)
  121. WriteOkay(Okay, output, "\nPriority: ", PrioMap[Ver->Priority]);
  122. if ((Pkg->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential)
  123. WriteOkay(Okay, output, "\nEssential: yes");
  124. if (Ver->Section != 0)
  125. WriteOkay(Okay, output, "\nSection: ", Ver.Section());
  126. if ((Ver->MultiArch & pkgCache::Version::Allowed) == pkgCache::Version::Allowed)
  127. WriteOkay(Okay, output, "\nMulti-Arch: allowed");
  128. else if ((Ver->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign)
  129. WriteOkay(Okay, output, "\nMulti-Arch: foreign");
  130. else if ((Ver->MultiArch & pkgCache::Version::Same) == pkgCache::Version::Same)
  131. WriteOkay(Okay, output, "\nMulti-Arch: same");
  132. std::set<string> Releases;
  133. for (pkgCache::VerFileIterator I = Ver.FileList(); I.end() == false; ++I) {
  134. pkgCache::PkgFileIterator File = I.File();
  135. if (File.Flagged(pkgCache::Flag::NotSource) == false) {
  136. string Release = File.RelStr();
  137. if (!Release.empty())
  138. Releases.insert(Release);
  139. }
  140. }
  141. if (!Releases.empty()) {
  142. WriteOkay(Okay, output, "\nAPT-Release:");
  143. for (std::set<string>::iterator R = Releases.begin(); R != Releases.end(); ++R)
  144. WriteOkay(Okay, output, "\n ", *R);
  145. }
  146. WriteOkay(Okay, output, "\nAPT-Pin: ", Cache.GetPolicy().GetPriority(Ver));
  147. if (Cache.GetCandidateVersion(Pkg) == Ver)
  148. WriteOkay(Okay, output, "\nAPT-Candidate: yes");
  149. if ((Cache[Pkg].Flags & pkgCache::Flag::Auto) == pkgCache::Flag::Auto)
  150. WriteOkay(Okay, output, "\nAPT-Automatic: yes");
  151. return Okay;
  152. }
  153. /*}}}*/
  154. // WriteScenarioDependency /*{{{*/
  155. static void WriteScenarioDependency( FILE* output, pkgCache::VerIterator const &Ver)
  156. {
  157. std::string dependencies[pkgCache::Dep::Enhances + 1];
  158. bool orGroup = false;
  159. for (pkgCache::DepIterator Dep = Ver.DependsList(); Dep.end() == false; ++Dep)
  160. {
  161. if (Dep.IsImplicit() == true)
  162. continue;
  163. if (orGroup == false)
  164. dependencies[Dep->Type].append(", ");
  165. dependencies[Dep->Type].append(Dep.TargetPkg().Name());
  166. if (Dep->Version != 0)
  167. dependencies[Dep->Type].append(" (").append(pkgCache::CompTypeDeb(Dep->CompareOp)).append(" ").append(Dep.TargetVer()).append(")");
  168. if ((Dep->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or)
  169. {
  170. dependencies[Dep->Type].append(" | ");
  171. orGroup = true;
  172. }
  173. else
  174. orGroup = false;
  175. }
  176. for (int i = 1; i < pkgCache::Dep::Enhances + 1; ++i)
  177. if (dependencies[i].empty() == false)
  178. fprintf(output, "%s: %s\n", DepMap[i], dependencies[i].c_str()+2);
  179. string provides;
  180. for (pkgCache::PrvIterator Prv = Ver.ProvidesList(); Prv.end() == false; ++Prv)
  181. {
  182. if (Prv.IsMultiArchImplicit() == true)
  183. continue;
  184. if (provides.empty() == false)
  185. provides.append(", ");
  186. provides.append(Prv.Name());
  187. if (Prv->ProvideVersion != 0)
  188. provides.append(" (= ").append(Prv.ProvideVersion()).append(")");
  189. }
  190. if (provides.empty() == false)
  191. fprintf(output, "Provides: %s\n", provides.c_str());
  192. }
  193. static bool WriteScenarioDependency(FileFd &output, pkgCache::VerIterator const &Ver)
  194. {
  195. std::string dependencies[pkgCache::Dep::Enhances + 1];
  196. bool orGroup = false;
  197. for (pkgCache::DepIterator Dep = Ver.DependsList(); Dep.end() == false; ++Dep)
  198. {
  199. if (Dep.IsImplicit() == true)
  200. continue;
  201. if (orGroup == false && dependencies[Dep->Type].empty() == false)
  202. dependencies[Dep->Type].append(", ");
  203. dependencies[Dep->Type].append(Dep.TargetPkg().Name());
  204. if (Dep->Version != 0)
  205. dependencies[Dep->Type].append(" (").append(pkgCache::CompTypeDeb(Dep->CompareOp)).append(" ").append(Dep.TargetVer()).append(")");
  206. if ((Dep->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or)
  207. {
  208. dependencies[Dep->Type].append(" | ");
  209. orGroup = true;
  210. }
  211. else
  212. orGroup = false;
  213. }
  214. bool Okay = output.Failed() == false;
  215. for (int i = 1; i < pkgCache::Dep::Enhances + 1; ++i)
  216. if (dependencies[i].empty() == false)
  217. WriteOkay(Okay, output, "\n", DepMap[i], ": ", dependencies[i]);
  218. string provides;
  219. for (pkgCache::PrvIterator Prv = Ver.ProvidesList(); Prv.end() == false; ++Prv)
  220. {
  221. if (Prv.IsMultiArchImplicit() == true)
  222. continue;
  223. if (provides.empty() == false)
  224. provides.append(", ");
  225. provides.append(Prv.Name());
  226. if (Prv->ProvideVersion != 0)
  227. provides.append(" (= ").append(Prv.ProvideVersion()).append(")");
  228. }
  229. if (provides.empty() == false)
  230. WriteOkay(Okay, output, "\nProvides: ", provides);
  231. return WriteOkay(Okay, output, "\n");
  232. }
  233. /*}}}*/
  234. // WriteScenarioLimitedDependency /*{{{*/
  235. static void WriteScenarioLimitedDependency(FILE* output,
  236. pkgCache::VerIterator const &Ver,
  237. APT::PackageSet const &pkgset)
  238. {
  239. std::string dependencies[pkgCache::Dep::Enhances + 1];
  240. bool orGroup = false;
  241. for (pkgCache::DepIterator Dep = Ver.DependsList(); Dep.end() == false; ++Dep)
  242. {
  243. if (Dep.IsImplicit() == true)
  244. continue;
  245. if (orGroup == false)
  246. {
  247. if (pkgset.find(Dep.TargetPkg()) == pkgset.end())
  248. continue;
  249. if (dependencies[Dep->Type].empty() == false)
  250. dependencies[Dep->Type].append(", ");
  251. }
  252. else if (pkgset.find(Dep.TargetPkg()) == pkgset.end())
  253. {
  254. if ((Dep->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or)
  255. continue;
  256. dependencies[Dep->Type].erase(dependencies[Dep->Type].end()-3, dependencies[Dep->Type].end());
  257. orGroup = false;
  258. continue;
  259. }
  260. dependencies[Dep->Type].append(Dep.TargetPkg().Name());
  261. if (Dep->Version != 0)
  262. dependencies[Dep->Type].append(" (").append(pkgCache::CompTypeDeb(Dep->CompareOp)).append(" ").append(Dep.TargetVer()).append(")");
  263. if ((Dep->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or)
  264. {
  265. dependencies[Dep->Type].append(" | ");
  266. orGroup = true;
  267. }
  268. else
  269. orGroup = false;
  270. }
  271. for (int i = 1; i < pkgCache::Dep::Enhances + 1; ++i)
  272. if (dependencies[i].empty() == false)
  273. fprintf(output, "%s: %s\n", DepMap[i], dependencies[i].c_str());
  274. string provides;
  275. for (pkgCache::PrvIterator Prv = Ver.ProvidesList(); Prv.end() == false; ++Prv)
  276. {
  277. if (Prv.IsMultiArchImplicit() == true)
  278. continue;
  279. if (pkgset.find(Prv.ParentPkg()) == pkgset.end())
  280. continue;
  281. if (provides.empty() == false)
  282. provides.append(", ");
  283. provides.append(Prv.Name());
  284. if (Prv->ProvideVersion != 0)
  285. provides.append(" (= ").append(Prv.ProvideVersion()).append(")");
  286. }
  287. if (provides.empty() == false)
  288. fprintf(output, "Provides: %s\n", provides.c_str());
  289. }
  290. static bool WriteScenarioLimitedDependency(FileFd &output,
  291. pkgCache::VerIterator const &Ver,
  292. APT::PackageSet const &pkgset)
  293. {
  294. std::string dependencies[pkgCache::Dep::Enhances + 1];
  295. bool orGroup = false;
  296. for (pkgCache::DepIterator Dep = Ver.DependsList(); Dep.end() == false; ++Dep)
  297. {
  298. if (Dep.IsImplicit() == true)
  299. continue;
  300. if (orGroup == false)
  301. {
  302. if (pkgset.find(Dep.TargetPkg()) == pkgset.end())
  303. continue;
  304. if (dependencies[Dep->Type].empty() == false)
  305. dependencies[Dep->Type].append(", ");
  306. }
  307. else if (pkgset.find(Dep.TargetPkg()) == pkgset.end())
  308. {
  309. if ((Dep->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or)
  310. continue;
  311. dependencies[Dep->Type].erase(dependencies[Dep->Type].end()-3, dependencies[Dep->Type].end());
  312. orGroup = false;
  313. continue;
  314. }
  315. dependencies[Dep->Type].append(Dep.TargetPkg().Name());
  316. if (Dep->Version != 0)
  317. dependencies[Dep->Type].append(" (").append(pkgCache::CompTypeDeb(Dep->CompareOp)).append(" ").append(Dep.TargetVer()).append(")");
  318. if ((Dep->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or)
  319. {
  320. dependencies[Dep->Type].append(" | ");
  321. orGroup = true;
  322. }
  323. else
  324. orGroup = false;
  325. }
  326. bool Okay = output.Failed() == false;
  327. for (int i = 1; i < pkgCache::Dep::Enhances + 1; ++i)
  328. if (dependencies[i].empty() == false)
  329. WriteOkay(Okay, output, "\n", DepMap[i], ": ", dependencies[i]);
  330. string provides;
  331. for (pkgCache::PrvIterator Prv = Ver.ProvidesList(); Prv.end() == false; ++Prv)
  332. {
  333. if (Prv.IsMultiArchImplicit() == true)
  334. continue;
  335. if (pkgset.find(Prv.ParentPkg()) == pkgset.end())
  336. continue;
  337. if (provides.empty() == false)
  338. provides.append(", ");
  339. provides.append(Prv.Name());
  340. if (Prv->ProvideVersion != 0)
  341. provides.append(" (= ").append(Prv.ProvideVersion()).append(")");
  342. }
  343. if (provides.empty() == false)
  344. WriteOkay(Okay, output, "\nProvides: ", provides);
  345. return WriteOkay(Okay, output, "\n");
  346. }
  347. /*}}}*/
  348. static bool SkipUnavailableVersions(pkgDepCache &Cache, pkgCache::PkgIterator const &Pkg, pkgCache::VerIterator const &Ver)/*{{{*/
  349. {
  350. /* versions which aren't current and aren't available in
  351. any "online" source file are bad, expect if they are the choosen
  352. candidate: The exception is for build-dep implementation as it creates
  353. such pseudo (package) versions and removes them later on again.
  354. We filter out versions at all so packages in 'rc' state only available
  355. in dpkg/status aren't passed to solvers as they can't be installed. */
  356. if (Pkg->CurrentVer != 0)
  357. return false;
  358. if (Cache.GetCandidateVersion(Pkg) == Ver)
  359. return false;
  360. for (pkgCache::VerFileIterator I = Ver.FileList(); I.end() == false; ++I)
  361. if (I.File().Flagged(pkgCache::Flag::NotSource) == false)
  362. return false;
  363. return true;
  364. }
  365. /*}}}*/
  366. // EDSP::WriteScenario - to the given file descriptor /*{{{*/
  367. bool EDSP::WriteScenario(pkgDepCache &Cache, FILE* output, OpProgress *Progress)
  368. {
  369. if (Progress != NULL)
  370. Progress->SubProgress(Cache.Head().VersionCount, _("Send scenario to solver"));
  371. unsigned long p = 0;
  372. std::vector<std::string> archs = APT::Configuration::getArchitectures();
  373. for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; ++Pkg)
  374. {
  375. std::string const arch = Pkg.Arch();
  376. if (std::find(archs.begin(), archs.end(), arch) == archs.end())
  377. continue;
  378. for (pkgCache::VerIterator Ver = Pkg.VersionList(); Ver.end() == false; ++Ver, ++p)
  379. {
  380. if (SkipUnavailableVersions(Cache, Pkg, Ver))
  381. continue;
  382. WriteScenarioVersion(Cache, output, Pkg, Ver);
  383. WriteScenarioDependency(output, Ver);
  384. fprintf(output, "\n");
  385. if (Progress != NULL && p % 100 == 0)
  386. Progress->Progress(p);
  387. }
  388. }
  389. return true;
  390. }
  391. bool EDSP::WriteScenario(pkgDepCache &Cache, FileFd &output, OpProgress *Progress)
  392. {
  393. if (Progress != NULL)
  394. Progress->SubProgress(Cache.Head().VersionCount, _("Send scenario to solver"));
  395. unsigned long p = 0;
  396. bool Okay = output.Failed() == false;
  397. std::vector<std::string> archs = APT::Configuration::getArchitectures();
  398. for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false && likely(Okay); ++Pkg)
  399. {
  400. std::string const arch = Pkg.Arch();
  401. if (std::find(archs.begin(), archs.end(), arch) == archs.end())
  402. continue;
  403. for (pkgCache::VerIterator Ver = Pkg.VersionList(); Ver.end() == false && likely(Okay); ++Ver, ++p)
  404. {
  405. if (SkipUnavailableVersions(Cache, Pkg, Ver))
  406. continue;
  407. Okay &= WriteScenarioVersion(Cache, output, Pkg, Ver);
  408. Okay &= WriteScenarioDependency(output, Ver);
  409. WriteOkay(Okay, output, "\n");
  410. if (Progress != NULL && p % 100 == 0)
  411. Progress->Progress(p);
  412. }
  413. }
  414. return true;
  415. }
  416. /*}}}*/
  417. // EDSP::WriteLimitedScenario - to the given file descriptor /*{{{*/
  418. bool EDSP::WriteLimitedScenario(pkgDepCache &Cache, FILE* output,
  419. APT::PackageSet const &pkgset,
  420. OpProgress *Progress)
  421. {
  422. if (Progress != NULL)
  423. Progress->SubProgress(Cache.Head().VersionCount, _("Send scenario to solver"));
  424. unsigned long p = 0;
  425. for (APT::PackageSet::const_iterator Pkg = pkgset.begin(); Pkg != pkgset.end(); ++Pkg, ++p)
  426. for (pkgCache::VerIterator Ver = Pkg.VersionList(); Ver.end() == false; ++Ver)
  427. {
  428. if (SkipUnavailableVersions(Cache, Pkg, Ver))
  429. continue;
  430. WriteScenarioVersion(Cache, output, Pkg, Ver);
  431. WriteScenarioLimitedDependency(output, Ver, pkgset);
  432. fprintf(output, "\n");
  433. if (Progress != NULL && p % 100 == 0)
  434. Progress->Progress(p);
  435. }
  436. if (Progress != NULL)
  437. Progress->Done();
  438. return true;
  439. }
  440. bool EDSP::WriteLimitedScenario(pkgDepCache &Cache, FileFd &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. bool Okay = output.Failed() == false;
  448. for (APT::PackageSet::const_iterator Pkg = pkgset.begin(); Pkg != pkgset.end() && likely(Okay); ++Pkg, ++p)
  449. for (pkgCache::VerIterator Ver = Pkg.VersionList(); Ver.end() == false && likely(Okay); ++Ver)
  450. {
  451. if (SkipUnavailableVersions(Cache, Pkg, Ver))
  452. continue;
  453. Okay &= WriteScenarioVersion(Cache, output, Pkg, Ver);
  454. Okay &= WriteScenarioLimitedDependency(output, Ver, pkgset);
  455. WriteOkay(Okay, output, "\n");
  456. if (Progress != NULL && p % 100 == 0)
  457. Progress->Progress(p);
  458. }
  459. if (Progress != NULL)
  460. Progress->Done();
  461. return Okay;
  462. }
  463. /*}}}*/
  464. // EDSP::WriteRequest - to the given file descriptor /*{{{*/
  465. bool EDSP::WriteRequest(pkgDepCache &Cache, FILE* output, bool const Upgrade,
  466. bool const DistUpgrade, bool const AutoRemove,
  467. OpProgress *Progress)
  468. {
  469. if (Progress != NULL)
  470. Progress->SubProgress(Cache.Head().PackageCount, _("Send request to solver"));
  471. unsigned long p = 0;
  472. string del, inst;
  473. for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; ++Pkg, ++p)
  474. {
  475. if (Progress != NULL && p % 100 == 0)
  476. Progress->Progress(p);
  477. string* req;
  478. pkgDepCache::StateCache &P = Cache[Pkg];
  479. if (P.Delete() == true)
  480. req = &del;
  481. else if (P.NewInstall() == true || P.Upgrade() == true || P.ReInstall() == true ||
  482. (P.Mode == pkgDepCache::ModeKeep && (P.iFlags & pkgDepCache::Protected) == pkgDepCache::Protected))
  483. req = &inst;
  484. else
  485. continue;
  486. req->append(" ").append(Pkg.FullName());
  487. }
  488. fprintf(output, "Request: EDSP 0.5\n");
  489. const char *arch = _config->Find("APT::Architecture").c_str();
  490. std::vector<string> archs = APT::Configuration::getArchitectures();
  491. fprintf(output, "Architecture: %s\n", arch);
  492. fprintf(output, "Architectures:");
  493. for (std::vector<string>::const_iterator a = archs.begin(); a != archs.end(); ++a)
  494. fprintf(output, " %s", a->c_str());
  495. fprintf(output, "\n");
  496. if (del.empty() == false)
  497. fprintf(output, "Remove: %s\n", del.c_str()+1);
  498. if (inst.empty() == false)
  499. fprintf(output, "Install: %s\n", inst.c_str()+1);
  500. if (Upgrade == true)
  501. fprintf(output, "Upgrade: yes\n");
  502. if (DistUpgrade == true)
  503. fprintf(output, "Dist-Upgrade: yes\n");
  504. if (AutoRemove == true)
  505. fprintf(output, "Autoremove: yes\n");
  506. auto const solver = _config->Find("APT::Solver", "internal");
  507. fprintf(output, "Solver: %s\n", solver.c_str());
  508. auto const solverconf = std::string("APT::Solver::") + solver + "::";
  509. if (_config->FindB(solverconf + "Strict-Pinning", _config->FindB("APT::Solver::Strict-Pinning", true)) == false)
  510. fprintf(output, "Strict-Pinning: no\n");
  511. auto const solverpref = _config->Find(solverconf + "Preferences", _config->Find("APT::Solver::Preferences", ""));
  512. if (solverpref.empty() == false)
  513. fprintf(output, "Preferences: %s\n", solverpref.c_str());
  514. fprintf(output, "\n");
  515. return true;
  516. }
  517. bool EDSP::WriteRequest(pkgDepCache &Cache, FileFd &output, bool const Upgrade,
  518. bool const DistUpgrade, bool const AutoRemove,
  519. OpProgress *Progress)
  520. {
  521. if (Progress != NULL)
  522. Progress->SubProgress(Cache.Head().PackageCount, _("Send request to solver"));
  523. unsigned long p = 0;
  524. string del, inst;
  525. for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; ++Pkg, ++p)
  526. {
  527. if (Progress != NULL && p % 100 == 0)
  528. Progress->Progress(p);
  529. string* req;
  530. pkgDepCache::StateCache &P = Cache[Pkg];
  531. if (P.Delete() == true)
  532. req = &del;
  533. else if (P.NewInstall() == true || P.Upgrade() == true || P.ReInstall() == true ||
  534. (P.Mode == pkgDepCache::ModeKeep && (P.iFlags & pkgDepCache::Protected) == pkgDepCache::Protected))
  535. req = &inst;
  536. else
  537. continue;
  538. req->append(" ").append(Pkg.FullName());
  539. }
  540. bool Okay = WriteOkay(output, "Request: EDSP 0.5\n");
  541. const char *arch = _config->Find("APT::Architecture").c_str();
  542. std::vector<string> archs = APT::Configuration::getArchitectures();
  543. WriteOkay(Okay, output, "Architecture: ", arch, "\n",
  544. "Architectures:");
  545. for (std::vector<string>::const_iterator a = archs.begin(); a != archs.end(); ++a)
  546. WriteOkay(Okay, output, " ", *a);
  547. WriteOkay(Okay, output, "\n");
  548. if (del.empty() == false)
  549. WriteOkay(Okay, output, "Remove:", del, "\n");
  550. if (inst.empty() == false)
  551. WriteOkay(Okay, output, "Install:", inst, "\n");
  552. if (Upgrade == true)
  553. WriteOkay(Okay, output, "Upgrade: yes\n");
  554. if (DistUpgrade == true)
  555. WriteOkay(Okay, output, "Dist-Upgrade: yes\n");
  556. if (AutoRemove == true)
  557. WriteOkay(Okay, output, "Autoremove: yes\n");
  558. if (_config->FindB("APT::Solver::Strict-Pinning", true) == false)
  559. WriteOkay(Okay, output, "Strict-Pinning: no\n");
  560. string solverpref("APT::Solver::");
  561. solverpref.append(_config->Find("APT::Solver", "internal")).append("::Preferences");
  562. if (_config->Exists(solverpref) == true)
  563. WriteOkay(Okay, output, "Preferences: ", _config->Find(solverpref,""), "\n");
  564. return WriteOkay(Okay, output, "\n");
  565. }
  566. /*}}}*/
  567. // EDSP::ReadResponse - from the given file descriptor /*{{{*/
  568. bool EDSP::ReadResponse(int const input, pkgDepCache &Cache, OpProgress *Progress) {
  569. /* We build an map id to mmap offset here
  570. In theory we could use the offset as ID, but then VersionCount
  571. couldn't be used to create other versionmappings anymore and it
  572. would be too easy for a (buggy) solver to segfault APT… */
  573. unsigned long long const VersionCount = Cache.Head().VersionCount;
  574. unsigned long VerIdx[VersionCount];
  575. for (pkgCache::PkgIterator P = Cache.PkgBegin(); P.end() == false; ++P) {
  576. for (pkgCache::VerIterator V = P.VersionList(); V.end() == false; ++V)
  577. VerIdx[V->ID] = V.Index();
  578. Cache[P].Marked = true;
  579. Cache[P].Garbage = false;
  580. }
  581. FileFd in;
  582. in.OpenDescriptor(input, FileFd::ReadOnly);
  583. pkgTagFile response(&in, 100);
  584. pkgTagSection section;
  585. std::set<decltype(Cache.PkgBegin()->ID)> seenOnce;
  586. while (response.Step(section) == true) {
  587. std::string type;
  588. if (section.Exists("Install") == true)
  589. type = "Install";
  590. else if (section.Exists("Remove") == true)
  591. type = "Remove";
  592. else if (section.Exists("Progress") == true) {
  593. if (Progress != NULL) {
  594. string msg = section.FindS("Message");
  595. if (msg.empty() == true)
  596. msg = _("Prepare for receiving solution");
  597. Progress->SubProgress(100, msg, section.FindI("Percentage", 0));
  598. }
  599. continue;
  600. } else if (section.Exists("Error") == true) {
  601. std::string msg = SubstVar(SubstVar(section.FindS("Message"), "\n .\n", "\n\n"), "\n ", "\n");
  602. if (msg.empty() == true) {
  603. msg = _("External solver failed without a proper error message");
  604. _error->Error("%s", msg.c_str());
  605. } else
  606. _error->Error("External solver failed with: %s", msg.substr(0,msg.find('\n')).c_str());
  607. if (Progress != NULL)
  608. Progress->Done();
  609. std::cerr << "The solver encountered an error of type: " << section.FindS("Error") << std::endl;
  610. std::cerr << "The following information might help you to understand what is wrong:" << std::endl;
  611. std::cerr << msg << std::endl << std::endl;
  612. return false;
  613. } else if (section.Exists("Autoremove") == true)
  614. type = "Autoremove";
  615. else
  616. continue;
  617. size_t const id = section.FindULL(type.c_str(), VersionCount);
  618. if (id == VersionCount) {
  619. _error->Warning("Unable to parse %s request with id value '%s'!", type.c_str(), section.FindS(type.c_str()).c_str());
  620. continue;
  621. } else if (id > Cache.Head().VersionCount) {
  622. _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());
  623. continue;
  624. }
  625. pkgCache::VerIterator Ver(Cache.GetCache(), Cache.GetCache().VerP + VerIdx[id]);
  626. auto const Pkg = Ver.ParentPkg();
  627. if (type == "Autoremove") {
  628. Cache[Pkg].Marked = false;
  629. Cache[Pkg].Garbage = true;
  630. } else if (seenOnce.emplace(Pkg->ID).second == false) {
  631. _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());
  632. } else if (type == "Install") {
  633. if (Pkg.CurrentVer() == Ver) {
  634. _error->Warning("Ignoring Install stanza received for version %s of package %s which is already installed!",
  635. Ver.VerStr(), Pkg.FullName(false).c_str());
  636. } else {
  637. Cache.SetCandidateVersion(Ver);
  638. Cache.MarkInstall(Pkg, false, 0, false);
  639. }
  640. } else if (type == "Remove") {
  641. if (Pkg->CurrentVer == 0)
  642. _error->Warning("Ignoring Remove stanza received for version %s of package %s which isn't installed!",
  643. Ver.VerStr(), Pkg.FullName(false).c_str());
  644. else if (Pkg.CurrentVer() != Ver)
  645. _error->Warning("Ignoring Remove stanza received for version %s of package %s which isn't the installed version %s!",
  646. Ver.VerStr(), Pkg.FullName(false).c_str(), Pkg.CurrentVer().VerStr());
  647. else
  648. Cache.MarkDelete(Ver.ParentPkg(), false);
  649. }
  650. }
  651. return true;
  652. }
  653. /*}}}*/
  654. // ReadLine - first line from the given file descriptor /*{{{*/
  655. // ---------------------------------------------------------------------
  656. /* Little helper method to read a complete line into a string. Similar to
  657. fgets but we need to use the low-level read() here as otherwise the
  658. listparser will be confused later on as mixing of fgets and read isn't
  659. a supported action according to the manpages and results are undefined */
  660. static bool ReadLine(int const input, std::string &line) {
  661. char one;
  662. ssize_t data = 0;
  663. line.erase();
  664. line.reserve(100);
  665. while ((data = read(input, &one, sizeof(one))) != -1) {
  666. if (data != 1)
  667. continue;
  668. if (one == '\n')
  669. return true;
  670. if (one == '\r')
  671. continue;
  672. if (line.empty() == true && isblank(one) != 0)
  673. continue;
  674. line += one;
  675. }
  676. return false;
  677. }
  678. /*}}}*/
  679. // StringToBool - convert yes/no to bool /*{{{*/
  680. // ---------------------------------------------------------------------
  681. /* we are not as lazy as we are in the global StringToBool as we really
  682. only accept yes/no here - but we will ignore leading spaces */
  683. static bool StringToBool(char const *answer, bool const defValue) {
  684. for (; isspace(*answer) != 0; ++answer);
  685. if (strncasecmp(answer, "yes", 3) == 0)
  686. return true;
  687. else if (strncasecmp(answer, "no", 2) == 0)
  688. return false;
  689. else
  690. _error->Warning("Value '%s' is not a boolean 'yes' or 'no'!", answer);
  691. return defValue;
  692. }
  693. /*}}}*/
  694. // EDSP::ReadRequest - first stanza from the given file descriptor /*{{{*/
  695. bool EDSP::ReadRequest(int const input, std::list<std::string> &install,
  696. std::list<std::string> &remove, bool &upgrade,
  697. bool &distUpgrade, bool &autoRemove)
  698. {
  699. install.clear();
  700. remove.clear();
  701. upgrade = false;
  702. distUpgrade = false;
  703. autoRemove = false;
  704. std::string line;
  705. while (ReadLine(input, line) == true)
  706. {
  707. // Skip empty lines before request
  708. if (line.empty() == true)
  709. continue;
  710. // The first Tag must be a request, so search for it
  711. if (line.compare(0, 8, "Request:") != 0)
  712. continue;
  713. while (ReadLine(input, line) == true)
  714. {
  715. // empty lines are the end of the request
  716. if (line.empty() == true)
  717. return true;
  718. std::list<std::string> *request = NULL;
  719. if (line.compare(0, 8, "Install:") == 0)
  720. {
  721. line.erase(0, 8);
  722. request = &install;
  723. }
  724. else if (line.compare(0, 7, "Remove:") == 0)
  725. {
  726. line.erase(0, 7);
  727. request = &remove;
  728. }
  729. else if (line.compare(0, 8, "Upgrade:") == 0)
  730. upgrade = StringToBool(line.c_str() + 9, false);
  731. else if (line.compare(0, 13, "Dist-Upgrade:") == 0)
  732. distUpgrade = StringToBool(line.c_str() + 14, false);
  733. else if (line.compare(0, 11, "Autoremove:") == 0)
  734. autoRemove = StringToBool(line.c_str() + 12, false);
  735. else if (line.compare(0, 13, "Architecture:") == 0)
  736. _config->Set("APT::Architecture", line.c_str() + 14);
  737. else if (line.compare(0, 14, "Architectures:") == 0)
  738. {
  739. std::string const archs = line.c_str() + 15;
  740. _config->Set("APT::Architectures", SubstVar(archs, " ", ","));
  741. }
  742. else if (line.compare(0, 7, "Solver:") == 0)
  743. ; // purely informational line
  744. else
  745. _error->Warning("Unknown line in EDSP Request stanza: %s", line.c_str());
  746. if (request == NULL)
  747. continue;
  748. size_t end = line.length();
  749. do {
  750. size_t begin = line.rfind(' ');
  751. if (begin == std::string::npos)
  752. {
  753. request->push_back(line.substr(0, end));
  754. break;
  755. }
  756. else if (begin < end)
  757. request->push_back(line.substr(begin + 1, end));
  758. line.erase(begin);
  759. end = line.find_last_not_of(' ');
  760. } while (end != std::string::npos);
  761. }
  762. }
  763. return false;
  764. }
  765. /*}}}*/
  766. // EDSP::ApplyRequest - first stanza from the given file descriptor /*{{{*/
  767. bool EDSP::ApplyRequest(std::list<std::string> const &install,
  768. std::list<std::string> const &remove,
  769. pkgDepCache &Cache)
  770. {
  771. for (std::list<std::string>::const_iterator i = install.begin();
  772. i != install.end(); ++i) {
  773. pkgCache::PkgIterator P = Cache.FindPkg(*i);
  774. if (P.end() == true)
  775. _error->Warning("Package %s is not known, so can't be installed", i->c_str());
  776. else
  777. Cache.MarkInstall(P, false);
  778. }
  779. for (std::list<std::string>::const_iterator i = remove.begin();
  780. i != remove.end(); ++i) {
  781. pkgCache::PkgIterator P = Cache.FindPkg(*i);
  782. if (P.end() == true)
  783. _error->Warning("Package %s is not known, so can't be installed", i->c_str());
  784. else
  785. Cache.MarkDelete(P);
  786. }
  787. return true;
  788. }
  789. /*}}}*/
  790. // EDSP::WriteSolution - to the given file descriptor /*{{{*/
  791. bool EDSP::WriteSolution(pkgDepCache &Cache, FILE* output)
  792. {
  793. bool const Debug = _config->FindB("Debug::EDSP::WriteSolution", false);
  794. for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; ++Pkg)
  795. {
  796. if (Cache[Pkg].Delete() == true)
  797. {
  798. fprintf(output, "Remove: %d\n", Pkg.CurrentVer()->ID);
  799. if (Debug == true)
  800. fprintf(output, "Package: %s\nVersion: %s\n", Pkg.FullName().c_str(), Pkg.CurrentVer().VerStr());
  801. }
  802. else if (Cache[Pkg].NewInstall() == true || Cache[Pkg].Upgrade() == true)
  803. {
  804. pkgCache::VerIterator const CandVer = Cache.GetCandidateVersion(Pkg);
  805. fprintf(output, "Install: %d\n", CandVer->ID);
  806. if (Debug == true)
  807. fprintf(output, "Package: %s\nVersion: %s\n", Pkg.FullName().c_str(), CandVer.VerStr());
  808. }
  809. else if (Cache[Pkg].Garbage == true)
  810. {
  811. fprintf(output, "Autoremove: %d\n", Pkg.CurrentVer()->ID);
  812. if (Debug == true)
  813. fprintf(output, "Package: %s\nVersion: %s\n", Pkg.FullName().c_str(), Pkg.CurrentVer().VerStr());
  814. }
  815. else
  816. continue;
  817. fprintf(output, "\n");
  818. }
  819. return true;
  820. }
  821. bool EDSP::WriteSolution(pkgDepCache &Cache, FileFd &output)
  822. {
  823. bool const Debug = _config->FindB("Debug::EDSP::WriteSolution", false);
  824. bool Okay = output.Failed() == false;
  825. for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false && likely(Okay); ++Pkg)
  826. {
  827. std::string action;
  828. if (Cache[Pkg].Delete() == true)
  829. WriteOkay(Okay, output, "Remove: ", Pkg.CurrentVer()->ID, "\n");
  830. else if (Cache[Pkg].NewInstall() == true || Cache[Pkg].Upgrade() == true)
  831. WriteOkay(Okay, output, "Install: ", Cache.GetCandidateVersion(Pkg)->ID, "\n");
  832. else if (Cache[Pkg].Garbage == true)
  833. WriteOkay(Okay, output, "Autoremove: ", Pkg.CurrentVer()->ID, "\n");
  834. else
  835. continue;
  836. if (Debug)
  837. {
  838. WriteOkay(Okay, output, "Package: ", Pkg.FullName(), "\nVersion: ");
  839. if (Cache[Pkg].Delete() == true || Cache[Pkg].Garbage == true)
  840. WriteOkay(Okay, output, Pkg.CurrentVer().VerStr(), "\n\n");
  841. else
  842. WriteOkay(Okay, output, Cache.GetCandidateVersion(Pkg).VerStr(), "\n\n");
  843. }
  844. else
  845. WriteOkay(Okay, output, "\n");
  846. }
  847. return Okay;
  848. }
  849. /*}}}*/
  850. // EDSP::WriteProgess - pulse to the given file descriptor /*{{{*/
  851. bool EDSP::WriteProgress(unsigned short const percent, const char* const message, FILE* output) {
  852. fprintf(output, "Progress: %s\n", TimeRFC1123(time(NULL)).c_str());
  853. fprintf(output, "Percentage: %d\n", percent);
  854. fprintf(output, "Message: %s\n\n", message);
  855. fflush(output);
  856. return true;
  857. }
  858. bool EDSP::WriteProgress(unsigned short const percent, const char* const message, FileFd &output) {
  859. return WriteOkay(output, "Progress: ", TimeRFC1123(time(NULL)), "\n",
  860. "Percentage: ", percent, "\n",
  861. "Message: ", message, "\n\n") && output.Flush();
  862. }
  863. /*}}}*/
  864. // EDSP::WriteError - format an error message to be send to file descriptor /*{{{*/
  865. bool EDSP::WriteError(char const * const uuid, std::string const &message, FILE* output) {
  866. fprintf(output, "Error: %s\n", uuid);
  867. fprintf(output, "Message: %s\n\n", SubstVar(SubstVar(message, "\n\n", "\n.\n"), "\n", "\n ").c_str());
  868. return true;
  869. }
  870. bool EDSP::WriteError(char const * const uuid, std::string const &message, FileFd &output) {
  871. return WriteOkay(output, "Error: ", uuid, "\n",
  872. "Message: ", SubstVar(SubstVar(message, "\n\n", "\n.\n"), "\n", "\n "),
  873. "\n\n");
  874. }
  875. /*}}}*/
  876. // EDSP::ExecuteSolver - fork requested solver and setup ipc pipes {{{*/
  877. pid_t EDSP::ExecuteSolver(const char* const solver, int * const solver_in, int * const solver_out, bool) {
  878. std::vector<std::string> const solverDirs = _config->FindVector("Dir::Bin::Solvers");
  879. std::string file;
  880. for (std::vector<std::string>::const_iterator dir = solverDirs.begin();
  881. dir != solverDirs.end(); ++dir) {
  882. file = flCombine(*dir, solver);
  883. if (RealFileExists(file.c_str()) == true)
  884. break;
  885. file.clear();
  886. }
  887. if (file.empty() == true)
  888. {
  889. _error->Error("Can't call external solver '%s' as it is not in a configured directory!", solver);
  890. return 0;
  891. }
  892. int external[4] = {-1, -1, -1, -1};
  893. if (pipe(external) != 0 || pipe(external + 2) != 0)
  894. {
  895. _error->Errno("Resolve", "Can't create needed IPC pipes for EDSP");
  896. return 0;
  897. }
  898. for (int i = 0; i < 4; ++i)
  899. SetCloseExec(external[i], true);
  900. pid_t Solver = ExecFork();
  901. if (Solver == 0) {
  902. dup2(external[0], STDIN_FILENO);
  903. dup2(external[3], STDOUT_FILENO);
  904. const char* calling[2] = { file.c_str(), 0 };
  905. execv(calling[0], (char**) calling);
  906. std::cerr << "Failed to execute solver '" << solver << "'!" << std::endl;
  907. _exit(100);
  908. }
  909. close(external[0]);
  910. close(external[3]);
  911. if (WaitFd(external[1], true, 5) == false)
  912. {
  913. _error->Errno("Resolve", "Timed out while Waiting on availability of solver stdin");
  914. return 0;
  915. }
  916. *solver_in = external[1];
  917. *solver_out = external[2];
  918. return Solver;
  919. }
  920. bool EDSP::ExecuteSolver(const char* const solver, int *solver_in, int *solver_out) {
  921. if (ExecuteSolver(solver, solver_in, solver_out, true) == 0)
  922. return false;
  923. return true;
  924. }
  925. /*}}}*/
  926. // EDSP::ResolveExternal - resolve problems by asking external for help {{{*/
  927. bool EDSP::ResolveExternal(const char* const solver, pkgDepCache &Cache,
  928. bool const upgrade, bool const distUpgrade,
  929. bool const autoRemove, OpProgress *Progress) {
  930. int solver_in, solver_out;
  931. pid_t const solver_pid = EDSP::ExecuteSolver(solver, &solver_in, &solver_out, true);
  932. if (solver_pid == 0)
  933. return false;
  934. FileFd output;
  935. if (output.OpenDescriptor(solver_in, FileFd::WriteOnly | FileFd::BufferedWrite, true) == false)
  936. return _error->Errno("ResolveExternal", "Opening solver %s stdin on fd %d for writing failed", solver, solver_in);
  937. bool Okay = output.Failed() == false;
  938. if (Progress != NULL)
  939. Progress->OverallProgress(0, 100, 5, _("Execute external solver"));
  940. Okay &= EDSP::WriteRequest(Cache, output, upgrade, distUpgrade, autoRemove, Progress);
  941. if (Progress != NULL)
  942. Progress->OverallProgress(5, 100, 20, _("Execute external solver"));
  943. Okay &= EDSP::WriteScenario(Cache, output, Progress);
  944. output.Close();
  945. if (Progress != NULL)
  946. Progress->OverallProgress(25, 100, 75, _("Execute external solver"));
  947. if (Okay && EDSP::ReadResponse(solver_out, Cache, Progress) == false)
  948. return false;
  949. return ExecWait(solver_pid, solver);
  950. }
  951. /*}}}*/