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