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