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