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