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