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