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