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