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