]> git.saurik.com Git - apt.git/blame - apt-pkg/edsp.cc
dpkgpm: Convert users of localtime() to localtime_r()
[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")
9777639e
DK
346 {
347 pkgCache::PkgIterator const P = Ver.ParentPkg();
348 if (Cache[P].Mode != pkgDepCache::ModeInstall)
349 Cache.MarkInstall(P, false, 0, false);
350 }
69a78835
DK
351 else if (type == "Remove")
352 Cache.MarkDelete(Ver.ParentPkg(), false);
76d4aab0
DK
353 else if (type == "Autoremove") {
354 Cache[Ver.ParentPkg()].Marked = false;
355 Cache[Ver.ParentPkg()].Garbage = true;
356 }
2029276f
DK
357 }
358 return true;
359}
360 /*}}}*/
c8a4ce6c 361// ReadLine - first line from the given file descriptor /*{{{*/
6d5bd614
DK
362// ---------------------------------------------------------------------
363/* Little helper method to read a complete line into a string. Similar to
364 fgets but we need to use the low-level read() here as otherwise the
365 listparser will be confused later on as mixing of fgets and read isn't
2029276f 366 a supported action according to the manpages and results are undefined */
c8a4ce6c 367static bool ReadLine(int const input, std::string &line) {
6d5bd614
DK
368 char one;
369 ssize_t data = 0;
370 line.erase();
371 line.reserve(100);
372 while ((data = read(input, &one, sizeof(one))) != -1) {
373 if (data != 1)
374 continue;
375 if (one == '\n')
376 return true;
377 if (one == '\r')
378 continue;
379 if (line.empty() == true && isblank(one) != 0)
380 continue;
381 line += one;
382 }
383 return false;
384}
385 /*}}}*/
c8a4ce6c 386// StringToBool - convert yes/no to bool /*{{{*/
40795fca
DK
387// ---------------------------------------------------------------------
388/* we are not as lazy as we are in the global StringToBool as we really
389 only accept yes/no here - but we will ignore leading spaces */
c8a4ce6c 390static bool StringToBool(char const *answer, bool const defValue) {
40795fca
DK
391 for (; isspace(*answer) != 0; ++answer);
392 if (strncasecmp(answer, "yes", 3) == 0)
393 return true;
394 else if (strncasecmp(answer, "no", 2) == 0)
395 return false;
396 else
397 _error->Warning("Value '%s' is not a boolean 'yes' or 'no'!", answer);
398 return defValue;
399}
400 /*}}}*/
6d5bd614
DK
401// EDSP::ReadRequest - first stanza from the given file descriptor /*{{{*/
402bool EDSP::ReadRequest(int const input, std::list<std::string> &install,
40795fca
DK
403 std::list<std::string> &remove, bool &upgrade,
404 bool &distUpgrade, bool &autoRemove)
6d5bd614 405{
40795fca
DK
406 install.clear();
407 remove.clear();
408 upgrade = false;
409 distUpgrade = false;
410 autoRemove = false;
6d5bd614
DK
411 std::string line;
412 while (ReadLine(input, line) == true)
413 {
414 // Skip empty lines before request
415 if (line.empty() == true)
416 continue;
417 // The first Tag must be a request, so search for it
40795fca 418 if (line.compare(0, 8, "Request:") != 0)
6d5bd614
DK
419 continue;
420
421 while (ReadLine(input, line) == true)
422 {
423 // empty lines are the end of the request
424 if (line.empty() == true)
425 return true;
426
427 std::list<std::string> *request = NULL;
40795fca 428 if (line.compare(0, 8, "Install:") == 0)
6d5bd614 429 {
40795fca 430 line.erase(0, 8);
6d5bd614
DK
431 request = &install;
432 }
40795fca 433 else if (line.compare(0, 7, "Remove:") == 0)
6d5bd614 434 {
40795fca 435 line.erase(0, 7);
6d5bd614
DK
436 request = &remove;
437 }
40795fca 438 else if (line.compare(0, 8, "Upgrade:") == 0)
c8a4ce6c 439 upgrade = StringToBool(line.c_str() + 9, false);
40795fca 440 else if (line.compare(0, 13, "Dist-Upgrade:") == 0)
c8a4ce6c 441 distUpgrade = StringToBool(line.c_str() + 14, false);
40795fca 442 else if (line.compare(0, 11, "Autoremove:") == 0)
c8a4ce6c 443 autoRemove = StringToBool(line.c_str() + 12, false);
1f6cf9e7
DK
444 else if (line.compare(0, 13, "Architecture:") == 0)
445 _config->Set("APT::Architecture", line.c_str() + 14);
446 else if (line.compare(0, 14, "Architectures:") == 0)
447 {
448 std::string const archs = line.c_str() + 15;
449 _config->Set("APT::Architectures", SubstVar(archs, " ", ","));
450 }
40795fca
DK
451 else
452 _error->Warning("Unknown line in EDSP Request stanza: %s", line.c_str());
453
6d5bd614
DK
454 if (request == NULL)
455 continue;
456 size_t end = line.length();
457 do {
458 size_t begin = line.rfind(' ');
459 if (begin == std::string::npos)
460 {
40795fca 461 request->push_back(line.substr(0, end));
6d5bd614
DK
462 break;
463 }
464 else if (begin < end)
465 request->push_back(line.substr(begin + 1, end));
466 line.erase(begin);
467 end = line.find_last_not_of(' ');
468 } while (end != std::string::npos);
469 }
470 }
471 return false;
472}
473 /*}}}*/
474// EDSP::ApplyRequest - first stanza from the given file descriptor /*{{{*/
c3b85126 475bool EDSP::ApplyRequest(std::list<std::string> const &install,
29099cb6
DK
476 std::list<std::string> const &remove,
477 pkgDepCache &Cache)
6d5bd614
DK
478{
479 for (std::list<std::string>::const_iterator i = install.begin();
d4f626ff
DK
480 i != install.end(); ++i) {
481 pkgCache::PkgIterator P = Cache.FindPkg(*i);
482 if (P.end() == true)
483 _error->Warning("Package %s is not known, so can't be installed", i->c_str());
484 else
485 Cache.MarkInstall(P, false);
486 }
6d5bd614
DK
487
488 for (std::list<std::string>::const_iterator i = remove.begin();
d4f626ff
DK
489 i != remove.end(); ++i) {
490 pkgCache::PkgIterator P = Cache.FindPkg(*i);
491 if (P.end() == true)
492 _error->Warning("Package %s is not known, so can't be installed", i->c_str());
493 else
494 Cache.MarkDelete(P);
495 }
6d5bd614
DK
496 return true;
497}
498 /*}}}*/
c3b85126
DK
499// EDSP::WriteSolution - to the given file descriptor /*{{{*/
500bool EDSP::WriteSolution(pkgDepCache &Cache, FILE* output)
e3674d91 501{
6d5bd614 502 bool const Debug = _config->FindB("Debug::EDSP::WriteSolution", false);
e3674d91
DK
503 for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; ++Pkg)
504 {
505 if (Cache[Pkg].Delete() == true)
d4f626ff
DK
506 {
507 fprintf(output, "Remove: %d\n", Pkg.CurrentVer()->ID);
508 if (Debug == true)
509 fprintf(output, "Package: %s\nVersion: %s\n", Pkg.FullName().c_str(), Pkg.CurrentVer().VerStr());
510 }
e3674d91 511 else if (Cache[Pkg].NewInstall() == true || Cache[Pkg].Upgrade() == true)
d4f626ff 512 {
e3674d91 513 fprintf(output, "Install: %d\n", Cache.GetCandidateVer(Pkg)->ID);
d4f626ff
DK
514 if (Debug == true)
515 fprintf(output, "Package: %s\nVersion: %s\n", Pkg.FullName().c_str(), Cache.GetCandidateVer(Pkg).VerStr());
516 }
76d4aab0
DK
517 else if (Cache[Pkg].Garbage == true)
518 {
519 fprintf(output, "Autoremove: %d\n", Pkg.CurrentVer()->ID);
520 if (Debug == true)
521 fprintf(output, "Package: %s\nVersion: %s\n", Pkg.FullName().c_str(), Pkg.CurrentVer().VerStr());
76d4aab0 522 }
e3674d91
DK
523 else
524 continue;
e3674d91
DK
525 fprintf(output, "\n");
526 }
527
6d38011b
DK
528 return true;
529}
530 /*}}}*/
e876223c
DK
531// EDSP::WriteProgess - pulse to the given file descriptor /*{{{*/
532bool EDSP::WriteProgress(unsigned short const percent, const char* const message, FILE* output) {
3d17b9ff
DK
533 fprintf(output, "Progress: %s\n", TimeRFC1123(time(NULL)).c_str());
534 fprintf(output, "Percentage: %d\n", percent);
535 fprintf(output, "Message: %s\n\n", message);
536 fflush(output);
e876223c
DK
537 return true;
538}
539 /*}}}*/
ebfeeaed
DK
540// EDSP::WriteError - format an error message to be send to file descriptor /*{{{*/
541bool EDSP::WriteError(char const * const uuid, std::string const &message, FILE* output) {
542 fprintf(output, "Error: %s\n", uuid);
543 fprintf(output, "Message: %s\n\n", SubstVar(SubstVar(message, "\n\n", "\n.\n"), "\n", "\n ").c_str());
544 return true;
545}
546 /*}}}*/
ac5fbff8 547// EDSP::ExecuteSolver - fork requested solver and setup ipc pipes {{{*/
5681b3fc 548pid_t EDSP::ExecuteSolver(const char* const solver, int * const solver_in, int * const solver_out, bool) {
741b7da9
DK
549 std::vector<std::string> const solverDirs = _config->FindVector("Dir::Bin::Solvers");
550 std::string file;
551 for (std::vector<std::string>::const_iterator dir = solverDirs.begin();
552 dir != solverDirs.end(); ++dir) {
553 file = flCombine(*dir, solver);
554 if (RealFileExists(file.c_str()) == true)
555 break;
556 file.clear();
557 }
ac5fbff8 558
741b7da9 559 if (file.empty() == true)
5681b3fc
DK
560 {
561 _error->Error("Can't call external solver '%s' as it is not in a configured directory!", solver);
562 return 0;
563 }
741b7da9
DK
564 int external[4] = {-1, -1, -1, -1};
565 if (pipe(external) != 0 || pipe(external + 2) != 0)
5681b3fc
DK
566 {
567 _error->Errno("Resolve", "Can't create needed IPC pipes for EDSP");
568 return 0;
569 }
741b7da9
DK
570 for (int i = 0; i < 4; ++i)
571 SetCloseExec(external[i], true);
ac5fbff8 572
741b7da9
DK
573 pid_t Solver = ExecFork();
574 if (Solver == 0) {
575 dup2(external[0], STDIN_FILENO);
576 dup2(external[3], STDOUT_FILENO);
577 const char* calling[2] = { file.c_str(), 0 };
578 execv(calling[0], (char**) calling);
579 std::cerr << "Failed to execute solver '" << solver << "'!" << std::endl;
580 _exit(100);
581 }
582 close(external[0]);
583 close(external[3]);
ac5fbff8 584
741b7da9 585 if (WaitFd(external[1], true, 5) == false)
5681b3fc
DK
586 {
587 _error->Errno("Resolve", "Timed out while Waiting on availability of solver stdin");
588 return 0;
589 }
ac5fbff8 590
741b7da9
DK
591 *solver_in = external[1];
592 *solver_out = external[2];
5681b3fc
DK
593 return Solver;
594}
595bool EDSP::ExecuteSolver(const char* const solver, int *solver_in, int *solver_out) {
596 if (ExecuteSolver(solver, solver_in, solver_out, true) == 0)
597 return false;
598 return true;
741b7da9
DK
599}
600 /*}}}*/
601// EDSP::ResolveExternal - resolve problems by asking external for help {{{*/
602bool EDSP::ResolveExternal(const char* const solver, pkgDepCache &Cache,
603 bool const upgrade, bool const distUpgrade,
b57c0e35 604 bool const autoRemove, OpProgress *Progress) {
741b7da9 605 int solver_in, solver_out;
5681b3fc
DK
606 pid_t const solver_pid = EDSP::ExecuteSolver(solver, &solver_in, &solver_out, true);
607 if (solver_pid == 0)
741b7da9
DK
608 return false;
609
610 FILE* output = fdopen(solver_in, "w");
611 if (output == NULL)
612 return _error->Errno("Resolve", "fdopen on solver stdin failed");
b57c0e35
DK
613
614 if (Progress != NULL)
615 Progress->OverallProgress(0, 100, 5, _("Execute external solver"));
616 EDSP::WriteRequest(Cache, output, upgrade, distUpgrade, autoRemove, Progress);
617 if (Progress != NULL)
618 Progress->OverallProgress(5, 100, 20, _("Execute external solver"));
619 EDSP::WriteScenario(Cache, output, Progress);
741b7da9
DK
620 fclose(output);
621
b57c0e35
DK
622 if (Progress != NULL)
623 Progress->OverallProgress(25, 100, 75, _("Execute external solver"));
624 if (EDSP::ReadResponse(solver_out, Cache, Progress) == false)
27c69dd0 625 return false;
741b7da9 626
5681b3fc 627 return ExecWait(solver_pid, solver);
ac5fbff8
DK
628}
629 /*}}}*/