implement correct error reporting
[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;
ebfeeaed
DK
259 } else if (section.Exists("Error") == true) {
260 std::cerr << "The solver encountered an error of type: " << section.FindS("Error") << std::endl;
261 std::cerr << "The following information might help you to understand what is wrong:" << std::endl;
262 std::cerr << SubstVar(SubstVar(section.FindS("Message"), "\n .\n", "\n\n"), "\n ", "\n") << std::endl << std::endl;
263 break;
76d4aab0
DK
264 } else if (section.Exists("Autoremove") == true)
265 type = "Autoremove";
266 else
2029276f 267 continue;
29099cb6 268
2a33cb16
DK
269 size_t const id = section.FindULL(type.c_str(), VersionCount);
270 if (id == VersionCount) {
69a78835
DK
271 _error->Warning("Unable to parse %s request with id value '%s'!", type.c_str(), section.FindS(type.c_str()).c_str());
272 continue;
2a33cb16
DK
273 } else if (id > Cache.Head().VersionCount) {
274 _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());
275 continue;
69a78835 276 }
2029276f 277
2a33cb16 278 pkgCache::VerIterator Ver(Cache.GetCache(), Cache.GetCache().VerP + VerIdx[id]);
69a78835
DK
279 Cache.SetCandidateVersion(Ver);
280 if (type == "Install")
bda94cb8 281 Cache.MarkInstall(Ver.ParentPkg(), false, 0, false);
69a78835
DK
282 else if (type == "Remove")
283 Cache.MarkDelete(Ver.ParentPkg(), false);
76d4aab0
DK
284 else if (type == "Autoremove") {
285 Cache[Ver.ParentPkg()].Marked = false;
286 Cache[Ver.ParentPkg()].Garbage = true;
287 }
2029276f
DK
288 }
289 return true;
290}
291 /*}}}*/
6d5bd614
DK
292// EDSP::ReadLine - first line from the given file descriptor /*{{{*/
293// ---------------------------------------------------------------------
294/* Little helper method to read a complete line into a string. Similar to
295 fgets but we need to use the low-level read() here as otherwise the
296 listparser will be confused later on as mixing of fgets and read isn't
2029276f 297 a supported action according to the manpages and results are undefined */
6d5bd614
DK
298bool EDSP::ReadLine(int const input, std::string &line) {
299 char one;
300 ssize_t data = 0;
301 line.erase();
302 line.reserve(100);
303 while ((data = read(input, &one, sizeof(one))) != -1) {
304 if (data != 1)
305 continue;
306 if (one == '\n')
307 return true;
308 if (one == '\r')
309 continue;
310 if (line.empty() == true && isblank(one) != 0)
311 continue;
312 line += one;
313 }
314 return false;
315}
316 /*}}}*/
40795fca
DK
317// EDSP::StringToBool - convert yes/no to bool /*{{{*/
318// ---------------------------------------------------------------------
319/* we are not as lazy as we are in the global StringToBool as we really
320 only accept yes/no here - but we will ignore leading spaces */
321bool EDSP::StringToBool(char const *answer, bool const defValue) {
322 for (; isspace(*answer) != 0; ++answer);
323 if (strncasecmp(answer, "yes", 3) == 0)
324 return true;
325 else if (strncasecmp(answer, "no", 2) == 0)
326 return false;
327 else
328 _error->Warning("Value '%s' is not a boolean 'yes' or 'no'!", answer);
329 return defValue;
330}
331 /*}}}*/
6d5bd614
DK
332// EDSP::ReadRequest - first stanza from the given file descriptor /*{{{*/
333bool EDSP::ReadRequest(int const input, std::list<std::string> &install,
40795fca
DK
334 std::list<std::string> &remove, bool &upgrade,
335 bool &distUpgrade, bool &autoRemove)
6d5bd614 336{
40795fca
DK
337 install.clear();
338 remove.clear();
339 upgrade = false;
340 distUpgrade = false;
341 autoRemove = false;
6d5bd614
DK
342 std::string line;
343 while (ReadLine(input, line) == true)
344 {
345 // Skip empty lines before request
346 if (line.empty() == true)
347 continue;
348 // The first Tag must be a request, so search for it
40795fca 349 if (line.compare(0, 8, "Request:") != 0)
6d5bd614
DK
350 continue;
351
352 while (ReadLine(input, line) == true)
353 {
354 // empty lines are the end of the request
355 if (line.empty() == true)
356 return true;
357
358 std::list<std::string> *request = NULL;
40795fca 359 if (line.compare(0, 8, "Install:") == 0)
6d5bd614 360 {
40795fca 361 line.erase(0, 8);
6d5bd614
DK
362 request = &install;
363 }
40795fca 364 else if (line.compare(0, 7, "Remove:") == 0)
6d5bd614 365 {
40795fca 366 line.erase(0, 7);
6d5bd614
DK
367 request = &remove;
368 }
40795fca
DK
369 else if (line.compare(0, 8, "Upgrade:") == 0)
370 upgrade = EDSP::StringToBool(line.c_str() + 9, false);
371 else if (line.compare(0, 13, "Dist-Upgrade:") == 0)
372 distUpgrade = EDSP::StringToBool(line.c_str() + 14, false);
373 else if (line.compare(0, 11, "Autoremove:") == 0)
374 autoRemove = EDSP::StringToBool(line.c_str() + 12, false);
375 else
376 _error->Warning("Unknown line in EDSP Request stanza: %s", line.c_str());
377
6d5bd614
DK
378 if (request == NULL)
379 continue;
380 size_t end = line.length();
381 do {
382 size_t begin = line.rfind(' ');
383 if (begin == std::string::npos)
384 {
40795fca 385 request->push_back(line.substr(0, end));
6d5bd614
DK
386 break;
387 }
388 else if (begin < end)
389 request->push_back(line.substr(begin + 1, end));
390 line.erase(begin);
391 end = line.find_last_not_of(' ');
392 } while (end != std::string::npos);
393 }
394 }
395 return false;
396}
397 /*}}}*/
398// EDSP::ApplyRequest - first stanza from the given file descriptor /*{{{*/
c3b85126 399bool EDSP::ApplyRequest(std::list<std::string> const &install,
29099cb6
DK
400 std::list<std::string> const &remove,
401 pkgDepCache &Cache)
6d5bd614
DK
402{
403 for (std::list<std::string>::const_iterator i = install.begin();
d4f626ff
DK
404 i != install.end(); ++i) {
405 pkgCache::PkgIterator P = Cache.FindPkg(*i);
406 if (P.end() == true)
407 _error->Warning("Package %s is not known, so can't be installed", i->c_str());
408 else
409 Cache.MarkInstall(P, false);
410 }
6d5bd614
DK
411
412 for (std::list<std::string>::const_iterator i = remove.begin();
d4f626ff
DK
413 i != remove.end(); ++i) {
414 pkgCache::PkgIterator P = Cache.FindPkg(*i);
415 if (P.end() == true)
416 _error->Warning("Package %s is not known, so can't be installed", i->c_str());
417 else
418 Cache.MarkDelete(P);
419 }
6d5bd614
DK
420 return true;
421}
422 /*}}}*/
c3b85126
DK
423// EDSP::WriteSolution - to the given file descriptor /*{{{*/
424bool EDSP::WriteSolution(pkgDepCache &Cache, FILE* output)
e3674d91 425{
6d5bd614 426 bool const Debug = _config->FindB("Debug::EDSP::WriteSolution", false);
e3674d91
DK
427 for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; ++Pkg)
428 {
429 if (Cache[Pkg].Delete() == true)
d4f626ff
DK
430 {
431 fprintf(output, "Remove: %d\n", Pkg.CurrentVer()->ID);
432 if (Debug == true)
433 fprintf(output, "Package: %s\nVersion: %s\n", Pkg.FullName().c_str(), Pkg.CurrentVer().VerStr());
434 }
e3674d91 435 else if (Cache[Pkg].NewInstall() == true || Cache[Pkg].Upgrade() == true)
d4f626ff 436 {
e3674d91 437 fprintf(output, "Install: %d\n", Cache.GetCandidateVer(Pkg)->ID);
d4f626ff
DK
438 if (Debug == true)
439 fprintf(output, "Package: %s\nVersion: %s\n", Pkg.FullName().c_str(), Cache.GetCandidateVer(Pkg).VerStr());
440 }
76d4aab0
DK
441 else if (Cache[Pkg].Garbage == true)
442 {
443 fprintf(output, "Autoremove: %d\n", Pkg.CurrentVer()->ID);
444 if (Debug == true)
445 fprintf(output, "Package: %s\nVersion: %s\n", Pkg.FullName().c_str(), Pkg.CurrentVer().VerStr());
446 fprintf(stderr, "Autoremove: %s\nVersion: %s\n", Pkg.FullName().c_str(), Pkg.CurrentVer().VerStr());
447 }
e3674d91
DK
448 else
449 continue;
e3674d91
DK
450 fprintf(output, "\n");
451 }
452
6d38011b
DK
453 return true;
454}
455 /*}}}*/
e876223c
DK
456// EDSP::WriteProgess - pulse to the given file descriptor /*{{{*/
457bool EDSP::WriteProgress(unsigned short const percent, const char* const message, FILE* output) {
3d17b9ff
DK
458 fprintf(output, "Progress: %s\n", TimeRFC1123(time(NULL)).c_str());
459 fprintf(output, "Percentage: %d\n", percent);
460 fprintf(output, "Message: %s\n\n", message);
461 fflush(output);
e876223c
DK
462 return true;
463}
464 /*}}}*/
ebfeeaed
DK
465// EDSP::WriteError - format an error message to be send to file descriptor /*{{{*/
466bool EDSP::WriteError(char const * const uuid, std::string const &message, FILE* output) {
467 fprintf(output, "Error: %s\n", uuid);
468 fprintf(output, "Message: %s\n\n", SubstVar(SubstVar(message, "\n\n", "\n.\n"), "\n", "\n ").c_str());
469 return true;
470}
471 /*}}}*/
ac5fbff8
DK
472// EDSP::ExecuteSolver - fork requested solver and setup ipc pipes {{{*/
473bool EDSP::ExecuteSolver(const char* const solver, int *solver_in, int *solver_out) {
741b7da9
DK
474 std::vector<std::string> const solverDirs = _config->FindVector("Dir::Bin::Solvers");
475 std::string file;
476 for (std::vector<std::string>::const_iterator dir = solverDirs.begin();
477 dir != solverDirs.end(); ++dir) {
478 file = flCombine(*dir, solver);
479 if (RealFileExists(file.c_str()) == true)
480 break;
481 file.clear();
482 }
ac5fbff8 483
741b7da9
DK
484 if (file.empty() == true)
485 return _error->Error("Can't call external solver '%s' as it is not in a configured directory!", solver);
486 int external[4] = {-1, -1, -1, -1};
487 if (pipe(external) != 0 || pipe(external + 2) != 0)
488 return _error->Errno("Resolve", "Can't create needed IPC pipes for EDSP");
489 for (int i = 0; i < 4; ++i)
490 SetCloseExec(external[i], true);
ac5fbff8 491
741b7da9
DK
492 pid_t Solver = ExecFork();
493 if (Solver == 0) {
494 dup2(external[0], STDIN_FILENO);
495 dup2(external[3], STDOUT_FILENO);
496 const char* calling[2] = { file.c_str(), 0 };
497 execv(calling[0], (char**) calling);
498 std::cerr << "Failed to execute solver '" << solver << "'!" << std::endl;
499 _exit(100);
500 }
501 close(external[0]);
502 close(external[3]);
ac5fbff8 503
741b7da9
DK
504 if (WaitFd(external[1], true, 5) == false)
505 return _error->Errno("Resolve", "Timed out while Waiting on availability of solver stdin");
ac5fbff8 506
741b7da9
DK
507 *solver_in = external[1];
508 *solver_out = external[2];
509 return true;
510}
511 /*}}}*/
512// EDSP::ResolveExternal - resolve problems by asking external for help {{{*/
513bool EDSP::ResolveExternal(const char* const solver, pkgDepCache &Cache,
514 bool const upgrade, bool const distUpgrade,
515 bool const autoRemove) {
516 int solver_in, solver_out;
517 if (EDSP::ExecuteSolver(solver, &solver_in, &solver_out) == false)
518 return false;
519
520 FILE* output = fdopen(solver_in, "w");
521 if (output == NULL)
522 return _error->Errno("Resolve", "fdopen on solver stdin failed");
523 EDSP::WriteRequest(Cache, output, upgrade, distUpgrade, autoRemove);
524 EDSP::WriteScenario(Cache, output);
525 fclose(output);
526
527 if (EDSP::ReadResponse(solver_out, Cache) == false)
528 return _error->Error("Reading solver response failed");
529
530 return true;
ac5fbff8
DK
531}
532 /*}}}*/