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