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