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