edsp.cc 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523
  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 <apt-pkg/edsp.h>
  9. #include <apt-pkg/error.h>
  10. #include <apt-pkg/configuration.h>
  11. #include <apt-pkg/version.h>
  12. #include <apt-pkg/policy.h>
  13. #include <apt-pkg/tagfile.h>
  14. #include <apti18n.h>
  15. #include <limits>
  16. #include <stdio.h>
  17. /*}}}*/
  18. // we could use pkgCache::DepType and ::Priority, but these would be localized strings…
  19. const char * const EDSP::PrioMap[] = {0, "important", "required", "standard",
  20. "optional", "extra"};
  21. const char * const EDSP::DepMap[] = {"", "Depends", "PreDepends", "Suggests",
  22. "Recommends" , "Conflicts", "Replaces",
  23. "Obsoletes", "Breaks", "Enhances"};
  24. // EDSP::WriteScenario - to the given file descriptor /*{{{*/
  25. bool EDSP::WriteScenario(pkgDepCache &Cache, FILE* output)
  26. {
  27. for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; ++Pkg)
  28. for (pkgCache::VerIterator Ver = Pkg.VersionList(); Ver.end() == false; ++Ver)
  29. {
  30. WriteScenarioVersion(Cache, output, Pkg, Ver);
  31. WriteScenarioDependency(Cache, output, Pkg, Ver);
  32. fprintf(output, "\n");
  33. }
  34. return true;
  35. }
  36. /*}}}*/
  37. // EDSP::WriteLimitedScenario - to the given file descriptor /*{{{*/
  38. bool EDSP::WriteLimitedScenario(pkgDepCache &Cache, FILE* output,
  39. APT::PackageSet const &pkgset)
  40. {
  41. for (APT::PackageSet::const_iterator Pkg = pkgset.begin(); Pkg != pkgset.end(); ++Pkg)
  42. for (pkgCache::VerIterator Ver = Pkg.VersionList(); Ver.end() == false; ++Ver)
  43. {
  44. WriteScenarioVersion(Cache, output, Pkg, Ver);
  45. WriteScenarioLimitedDependency(Cache, output, Pkg, Ver, pkgset);
  46. fprintf(output, "\n");
  47. }
  48. return true;
  49. }
  50. /*}}}*/
  51. // EDSP::WriteScenarioVersion /*{{{*/
  52. void EDSP::WriteScenarioVersion(pkgDepCache &Cache, FILE* output, pkgCache::PkgIterator const &Pkg,
  53. pkgCache::VerIterator const &Ver)
  54. {
  55. fprintf(output, "Package: %s\n", Pkg.Name());
  56. fprintf(output, "Architecture: %s\n", Ver.Arch());
  57. fprintf(output, "Version: %s\n", Ver.VerStr());
  58. if (Pkg.CurrentVer() == Ver)
  59. fprintf(output, "Installed: yes\n");
  60. if (Pkg->SelectedState == pkgCache::State::Hold ||
  61. (Cache[Pkg].Keep() == true && Cache[Pkg].Protect() == true))
  62. fprintf(output, "Hold: yes\n");
  63. fprintf(output, "APT-ID: %d\n", Ver->ID);
  64. fprintf(output, "Priority: %s\n", PrioMap[Ver->Priority]);
  65. if ((Pkg->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential)
  66. fprintf(output, "Essential: yes\n");
  67. fprintf(output, "Section: %s\n", Ver.Section());
  68. if (Ver->MultiArch == pkgCache::Version::Allowed || Ver->MultiArch == pkgCache::Version::AllAllowed)
  69. fprintf(output, "Multi-Arch: allowed\n");
  70. else if (Ver->MultiArch == pkgCache::Version::Foreign || Ver->MultiArch == pkgCache::Version::AllForeign)
  71. fprintf(output, "Multi-Arch: foreign\n");
  72. else if (Ver->MultiArch == pkgCache::Version::Same)
  73. fprintf(output, "Multi-Arch: same\n");
  74. signed short Pin = std::numeric_limits<signed short>::min();
  75. for (pkgCache::VerFileIterator File = Ver.FileList(); File.end() == false; ++File) {
  76. signed short const p = Cache.GetPolicy().GetPriority(File.File());
  77. if (Pin < p)
  78. Pin = p;
  79. }
  80. fprintf(output, "APT-Pin: %d\n", Pin);
  81. if (Cache.GetCandidateVer(Pkg) == Ver)
  82. fprintf(output, "APT-Candidate: yes\n");
  83. if ((Cache[Pkg].Flags & pkgCache::Flag::Auto) == pkgCache::Flag::Auto)
  84. fprintf(output, "APT-Automatic: yes\n");
  85. }
  86. /*}}}*/
  87. // EDSP::WriteScenarioDependency /*{{{*/
  88. void EDSP::WriteScenarioDependency(pkgDepCache &Cache, FILE* output, pkgCache::PkgIterator const &Pkg,
  89. pkgCache::VerIterator const &Ver)
  90. {
  91. std::string dependencies[pkgCache::Dep::Enhances + 1];
  92. bool orGroup = false;
  93. for (pkgCache::DepIterator Dep = Ver.DependsList(); Dep.end() == false; ++Dep)
  94. {
  95. // Ignore implicit dependencies for multiarch here
  96. if (strcmp(Pkg.Arch(), Dep.TargetPkg().Arch()) != 0)
  97. continue;
  98. if (orGroup == false)
  99. dependencies[Dep->Type].append(", ");
  100. dependencies[Dep->Type].append(Dep.TargetPkg().Name());
  101. if (Dep->Version != 0)
  102. dependencies[Dep->Type].append(" (").append(pkgCache::CompTypeDeb(Dep->CompareOp)).append(" ").append(Dep.TargetVer()).append(")");
  103. if ((Dep->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or)
  104. {
  105. dependencies[Dep->Type].append(" | ");
  106. orGroup = true;
  107. }
  108. else
  109. orGroup = false;
  110. }
  111. for (int i = 1; i < pkgCache::Dep::Enhances + 1; ++i)
  112. if (dependencies[i].empty() == false)
  113. fprintf(output, "%s: %s\n", DepMap[i], dependencies[i].c_str()+2);
  114. string provides;
  115. for (pkgCache::PrvIterator Prv = Ver.ProvidesList(); Prv.end() == false; ++Prv)
  116. {
  117. // Ignore implicit provides for multiarch here
  118. if (strcmp(Pkg.Arch(), Prv.ParentPkg().Arch()) != 0 || strcmp(Pkg.Name(),Prv.Name()) == 0)
  119. continue;
  120. provides.append(", ").append(Prv.Name());
  121. }
  122. if (provides.empty() == false)
  123. fprintf(output, "Provides: %s\n", provides.c_str()+2);
  124. }
  125. /*}}}*/
  126. // EDSP::WriteScenarioLimitedDependency /*{{{*/
  127. void EDSP::WriteScenarioLimitedDependency(pkgDepCache &Cache, FILE* output,
  128. pkgCache::PkgIterator const &Pkg,
  129. pkgCache::VerIterator const &Ver,
  130. APT::PackageSet const &pkgset)
  131. {
  132. std::string dependencies[pkgCache::Dep::Enhances + 1];
  133. bool orGroup = false;
  134. for (pkgCache::DepIterator Dep = Ver.DependsList(); Dep.end() == false; ++Dep)
  135. {
  136. // Ignore implicit dependencies for multiarch here
  137. if (strcmp(Pkg.Arch(), Dep.TargetPkg().Arch()) != 0)
  138. continue;
  139. if (orGroup == false)
  140. {
  141. if (pkgset.find(Dep.TargetPkg()) == pkgset.end())
  142. continue;
  143. dependencies[Dep->Type].append(", ");
  144. }
  145. else if (pkgset.find(Dep.TargetPkg()) == pkgset.end())
  146. {
  147. if ((Dep->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or)
  148. continue;
  149. dependencies[Dep->Type].erase(dependencies[Dep->Type].end()-3, dependencies[Dep->Type].end());
  150. orGroup = false;
  151. continue;
  152. }
  153. dependencies[Dep->Type].append(Dep.TargetPkg().Name());
  154. if (Dep->Version != 0)
  155. dependencies[Dep->Type].append(" (").append(pkgCache::CompTypeDeb(Dep->CompareOp)).append(" ").append(Dep.TargetVer()).append(")");
  156. if ((Dep->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or)
  157. {
  158. dependencies[Dep->Type].append(" | ");
  159. orGroup = true;
  160. }
  161. else
  162. orGroup = false;
  163. }
  164. for (int i = 1; i < pkgCache::Dep::Enhances + 1; ++i)
  165. if (dependencies[i].empty() == false)
  166. fprintf(output, "%s: %s\n", DepMap[i], dependencies[i].c_str()+2);
  167. string provides;
  168. for (pkgCache::PrvIterator Prv = Ver.ProvidesList(); Prv.end() == false; ++Prv)
  169. {
  170. // Ignore implicit provides for multiarch here
  171. if (strcmp(Pkg.Arch(), Prv.ParentPkg().Arch()) != 0 || strcmp(Pkg.Name(),Prv.Name()) == 0)
  172. continue;
  173. if (pkgset.find(Prv.ParentPkg()) == pkgset.end())
  174. continue;
  175. provides.append(", ").append(Prv.Name());
  176. }
  177. if (provides.empty() == false)
  178. fprintf(output, "Provides: %s\n", provides.c_str()+2);
  179. }
  180. /*}}}*/
  181. // EDSP::WriteRequest - to the given file descriptor /*{{{*/
  182. bool EDSP::WriteRequest(pkgDepCache &Cache, FILE* output, bool const Upgrade,
  183. bool const DistUpgrade, bool const AutoRemove)
  184. {
  185. string del, inst;
  186. for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; ++Pkg)
  187. {
  188. string* req;
  189. if (Cache[Pkg].Delete() == true)
  190. req = &del;
  191. else if (Cache[Pkg].NewInstall() == true || Cache[Pkg].Upgrade() == true)
  192. req = &inst;
  193. else
  194. continue;
  195. req->append(" ").append(Pkg.FullName());
  196. }
  197. fprintf(output, "Request: EDSP 0.4\n");
  198. if (del.empty() == false)
  199. fprintf(output, "Remove: %s\n", del.c_str()+1);
  200. if (inst.empty() == false)
  201. fprintf(output, "Install: %s\n", inst.c_str()+1);
  202. if (Upgrade == true)
  203. fprintf(output, "Upgrade: yes\n");
  204. if (DistUpgrade == true)
  205. fprintf(output, "Dist-Upgrade: yes\n");
  206. if (AutoRemove == true)
  207. fprintf(output, "Autoremove: yes\n");
  208. if (_config->FindB("APT::Solver::Strict-Pinning", true) == false)
  209. fprintf(output, "Strict-Pinning: no\n");
  210. string solverpref("APT::Solver::");
  211. solverpref.append(_config->Find("APT::Solver::Name", "internal")).append("::Preferences");
  212. if (_config->Exists(solverpref) == true)
  213. fprintf(output, "Preferences: %s\n", _config->Find(solverpref,"").c_str());
  214. fprintf(output, "\n");
  215. return true;
  216. }
  217. /*}}}*/
  218. // EDSP::ReadResponse - from the given file descriptor /*{{{*/
  219. bool EDSP::ReadResponse(int const input, pkgDepCache &Cache) {
  220. /* We build an map id to mmap offset here
  221. In theory we could use the offset as ID, but then VersionCount
  222. couldn't be used to create other versionmappings anymore and it
  223. would be too easy for a (buggy) solver to segfault APT… */
  224. unsigned long long const VersionCount = Cache.Head().VersionCount;
  225. unsigned long VerIdx[VersionCount];
  226. for (pkgCache::PkgIterator P = Cache.PkgBegin(); P.end() == false; ++P) {
  227. for (pkgCache::VerIterator V = P.VersionList(); V.end() == false; ++V)
  228. VerIdx[V->ID] = V.Index();
  229. Cache[P].Marked = true;
  230. Cache[P].Garbage = false;
  231. }
  232. FileFd in;
  233. in.OpenDescriptor(input, FileFd::ReadOnly);
  234. pkgTagFile response(&in, 100);
  235. pkgTagSection section;
  236. while (response.Step(section) == true) {
  237. std::string type;
  238. if (section.Exists("Install") == true)
  239. type = "Install";
  240. else if (section.Exists("Remove") == true)
  241. type = "Remove";
  242. else if (section.Exists("Progress") == true) {
  243. std::clog << TimeRFC1123(time(NULL)) << " ";
  244. ioprintf(std::clog, "[ %3d%% ] ", section.FindI("Percentage", 0));
  245. std::clog << section.FindS("Progress") << " - ";
  246. string const msg = section.FindS("Message");
  247. if (msg.empty() == true)
  248. std::clog << "Solver is still working on the solution" << std::endl;
  249. else
  250. std::clog << msg << std::endl;
  251. continue;
  252. } else if (section.Exists("Autoremove") == true)
  253. type = "Autoremove";
  254. else
  255. continue;
  256. size_t const id = section.FindULL(type.c_str(), VersionCount);
  257. if (id == VersionCount) {
  258. _error->Warning("Unable to parse %s request with id value '%s'!", type.c_str(), section.FindS(type.c_str()).c_str());
  259. continue;
  260. } else if (id > Cache.Head().VersionCount) {
  261. _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());
  262. continue;
  263. }
  264. pkgCache::VerIterator Ver(Cache.GetCache(), Cache.GetCache().VerP + VerIdx[id]);
  265. Cache.SetCandidateVersion(Ver);
  266. if (type == "Install")
  267. Cache.MarkInstall(Ver.ParentPkg(), false, false);
  268. else if (type == "Remove")
  269. Cache.MarkDelete(Ver.ParentPkg(), false);
  270. else if (type == "Autoremove") {
  271. Cache[Ver.ParentPkg()].Marked = false;
  272. Cache[Ver.ParentPkg()].Garbage = true;
  273. }
  274. }
  275. return true;
  276. }
  277. /*}}}*/
  278. // EDSP::ReadLine - first line from the given file descriptor /*{{{*/
  279. // ---------------------------------------------------------------------
  280. /* Little helper method to read a complete line into a string. Similar to
  281. fgets but we need to use the low-level read() here as otherwise the
  282. listparser will be confused later on as mixing of fgets and read isn't
  283. a supported action according to the manpages and results are undefined */
  284. bool EDSP::ReadLine(int const input, std::string &line) {
  285. char one;
  286. ssize_t data = 0;
  287. line.erase();
  288. line.reserve(100);
  289. while ((data = read(input, &one, sizeof(one))) != -1) {
  290. if (data != 1)
  291. continue;
  292. if (one == '\n')
  293. return true;
  294. if (one == '\r')
  295. continue;
  296. if (line.empty() == true && isblank(one) != 0)
  297. continue;
  298. line += one;
  299. }
  300. return false;
  301. }
  302. /*}}}*/
  303. // EDSP::StringToBool - convert yes/no to bool /*{{{*/
  304. // ---------------------------------------------------------------------
  305. /* we are not as lazy as we are in the global StringToBool as we really
  306. only accept yes/no here - but we will ignore leading spaces */
  307. bool EDSP::StringToBool(char const *answer, bool const defValue) {
  308. for (; isspace(*answer) != 0; ++answer);
  309. if (strncasecmp(answer, "yes", 3) == 0)
  310. return true;
  311. else if (strncasecmp(answer, "no", 2) == 0)
  312. return false;
  313. else
  314. _error->Warning("Value '%s' is not a boolean 'yes' or 'no'!", answer);
  315. return defValue;
  316. }
  317. /*}}}*/
  318. // EDSP::ReadRequest - first stanza from the given file descriptor /*{{{*/
  319. bool EDSP::ReadRequest(int const input, std::list<std::string> &install,
  320. std::list<std::string> &remove, bool &upgrade,
  321. bool &distUpgrade, bool &autoRemove)
  322. {
  323. install.clear();
  324. remove.clear();
  325. upgrade = false;
  326. distUpgrade = false;
  327. autoRemove = false;
  328. std::string line;
  329. while (ReadLine(input, line) == true)
  330. {
  331. // Skip empty lines before request
  332. if (line.empty() == true)
  333. continue;
  334. // The first Tag must be a request, so search for it
  335. if (line.compare(0, 8, "Request:") != 0)
  336. continue;
  337. while (ReadLine(input, line) == true)
  338. {
  339. // empty lines are the end of the request
  340. if (line.empty() == true)
  341. return true;
  342. std::list<std::string> *request = NULL;
  343. if (line.compare(0, 8, "Install:") == 0)
  344. {
  345. line.erase(0, 8);
  346. request = &install;
  347. }
  348. else if (line.compare(0, 7, "Remove:") == 0)
  349. {
  350. line.erase(0, 7);
  351. request = &remove;
  352. }
  353. else if (line.compare(0, 8, "Upgrade:") == 0)
  354. upgrade = EDSP::StringToBool(line.c_str() + 9, false);
  355. else if (line.compare(0, 13, "Dist-Upgrade:") == 0)
  356. distUpgrade = EDSP::StringToBool(line.c_str() + 14, false);
  357. else if (line.compare(0, 11, "Autoremove:") == 0)
  358. autoRemove = EDSP::StringToBool(line.c_str() + 12, false);
  359. else
  360. _error->Warning("Unknown line in EDSP Request stanza: %s", line.c_str());
  361. if (request == NULL)
  362. continue;
  363. size_t end = line.length();
  364. do {
  365. size_t begin = line.rfind(' ');
  366. if (begin == std::string::npos)
  367. {
  368. request->push_back(line.substr(0, end));
  369. break;
  370. }
  371. else if (begin < end)
  372. request->push_back(line.substr(begin + 1, end));
  373. line.erase(begin);
  374. end = line.find_last_not_of(' ');
  375. } while (end != std::string::npos);
  376. }
  377. }
  378. return false;
  379. }
  380. /*}}}*/
  381. // EDSP::ApplyRequest - first stanza from the given file descriptor /*{{{*/
  382. bool EDSP::ApplyRequest(std::list<std::string> const &install,
  383. std::list<std::string> const &remove,
  384. pkgDepCache &Cache)
  385. {
  386. for (std::list<std::string>::const_iterator i = install.begin();
  387. i != install.end(); ++i) {
  388. pkgCache::PkgIterator P = Cache.FindPkg(*i);
  389. if (P.end() == true)
  390. _error->Warning("Package %s is not known, so can't be installed", i->c_str());
  391. else
  392. Cache.MarkInstall(P, false);
  393. }
  394. for (std::list<std::string>::const_iterator i = remove.begin();
  395. i != remove.end(); ++i) {
  396. pkgCache::PkgIterator P = Cache.FindPkg(*i);
  397. if (P.end() == true)
  398. _error->Warning("Package %s is not known, so can't be installed", i->c_str());
  399. else
  400. Cache.MarkDelete(P);
  401. }
  402. return true;
  403. }
  404. /*}}}*/
  405. // EDSP::WriteSolution - to the given file descriptor /*{{{*/
  406. bool EDSP::WriteSolution(pkgDepCache &Cache, FILE* output)
  407. {
  408. bool const Debug = _config->FindB("Debug::EDSP::WriteSolution", false);
  409. for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; ++Pkg)
  410. {
  411. if (Cache[Pkg].Delete() == true)
  412. {
  413. fprintf(output, "Remove: %d\n", Pkg.CurrentVer()->ID);
  414. if (Debug == true)
  415. fprintf(output, "Package: %s\nVersion: %s\n", Pkg.FullName().c_str(), Pkg.CurrentVer().VerStr());
  416. }
  417. else if (Cache[Pkg].NewInstall() == true || Cache[Pkg].Upgrade() == true)
  418. {
  419. fprintf(output, "Install: %d\n", Cache.GetCandidateVer(Pkg)->ID);
  420. if (Debug == true)
  421. fprintf(output, "Package: %s\nVersion: %s\n", Pkg.FullName().c_str(), Cache.GetCandidateVer(Pkg).VerStr());
  422. }
  423. else if (Cache[Pkg].Garbage == true)
  424. {
  425. fprintf(output, "Autoremove: %d\n", Pkg.CurrentVer()->ID);
  426. if (Debug == true)
  427. fprintf(output, "Package: %s\nVersion: %s\n", Pkg.FullName().c_str(), Pkg.CurrentVer().VerStr());
  428. fprintf(stderr, "Autoremove: %s\nVersion: %s\n", Pkg.FullName().c_str(), Pkg.CurrentVer().VerStr());
  429. }
  430. else
  431. continue;
  432. fprintf(output, "\n");
  433. }
  434. return true;
  435. }
  436. /*}}}*/
  437. // EDSP::WriteProgess - pulse to the given file descriptor /*{{{*/
  438. bool EDSP::WriteProgress(unsigned short const percent, const char* const message, FILE* output) {
  439. fprintf(output, "Progress: %s\n", TimeRFC1123(time(NULL)).c_str());
  440. fprintf(output, "Percentage: %d\n", percent);
  441. fprintf(output, "Message: %s\n\n", message);
  442. fflush(output);
  443. return true;
  444. }
  445. /*}}}*/
  446. bool EDSP::WriteError(std::string const &message, FILE* output) { return false; }
  447. // EDSP::ExecuteSolver - fork requested solver and setup ipc pipes {{{*/
  448. bool EDSP::ExecuteSolver(const char* const solver, int *solver_in, int *solver_out) {
  449. std::vector<std::string> const solverDirs = _config->FindVector("Dir::Bin::Solvers");
  450. std::string file;
  451. for (std::vector<std::string>::const_iterator dir = solverDirs.begin();
  452. dir != solverDirs.end(); ++dir) {
  453. file = flCombine(*dir, solver);
  454. if (RealFileExists(file.c_str()) == true)
  455. break;
  456. file.clear();
  457. }
  458. if (file.empty() == true)
  459. return _error->Error("Can't call external solver '%s' as it is not in a configured directory!", solver);
  460. int external[4] = {-1, -1, -1, -1};
  461. if (pipe(external) != 0 || pipe(external + 2) != 0)
  462. return _error->Errno("Resolve", "Can't create needed IPC pipes for EDSP");
  463. for (int i = 0; i < 4; ++i)
  464. SetCloseExec(external[i], true);
  465. pid_t Solver = ExecFork();
  466. if (Solver == 0) {
  467. dup2(external[0], STDIN_FILENO);
  468. dup2(external[3], STDOUT_FILENO);
  469. const char* calling[2] = { file.c_str(), 0 };
  470. execv(calling[0], (char**) calling);
  471. std::cerr << "Failed to execute solver '" << solver << "'!" << std::endl;
  472. _exit(100);
  473. }
  474. close(external[0]);
  475. close(external[3]);
  476. if (WaitFd(external[1], true, 5) == false)
  477. return _error->Errno("Resolve", "Timed out while Waiting on availability of solver stdin");
  478. *solver_in = external[1];
  479. *solver_out = external[2];
  480. return true;
  481. }
  482. /*}}}*/
  483. // EDSP::ResolveExternal - resolve problems by asking external for help {{{*/
  484. bool EDSP::ResolveExternal(const char* const solver, pkgDepCache &Cache,
  485. bool const upgrade, bool const distUpgrade,
  486. bool const autoRemove) {
  487. int solver_in, solver_out;
  488. if (EDSP::ExecuteSolver(solver, &solver_in, &solver_out) == false)
  489. return false;
  490. FILE* output = fdopen(solver_in, "w");
  491. if (output == NULL)
  492. return _error->Errno("Resolve", "fdopen on solver stdin failed");
  493. EDSP::WriteRequest(Cache, output, upgrade, distUpgrade, autoRemove);
  494. EDSP::WriteScenario(Cache, output);
  495. fclose(output);
  496. if (EDSP::ReadResponse(solver_out, Cache) == false)
  497. return _error->Error("Reading solver response failed");
  498. return true;
  499. }
  500. /*}}}*/