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