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