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