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