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