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