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