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