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