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