]> git.saurik.com Git - apt.git/blame - apt-pkg/edsp.cc
edsp: try harder to not generate unneeded error messages
[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
4e92b116
DK
42// WriteOkay - varaidic helper to easily Write to a FileFd /*{{{*/
43static bool WriteOkay_fn(FileFd &) { return true; }
44template<typename... Tail> static bool WriteOkay_fn(FileFd &output, APT::StringView data, Tail... more_data)
45{
46 return likely(output.Write(data.data(), data.length()) && WriteOkay_fn(output, more_data...));
47}
48template<typename... Tail> static bool WriteOkay_fn(FileFd &output, unsigned int data, Tail... more_data)
49{
50 std::string number;
51 strprintf(number, "%d", data);
52 return likely(output.Write(number.data(), number.length()) && WriteOkay_fn(output, more_data...));
53}
54template<typename... Data> static bool WriteOkay(bool &Okay, FileFd &output, Data&&... data)
55{
56 Okay = likely(Okay && WriteOkay_fn(output, std::forward<Data>(data)...));
57 return Okay;
58}
59template<typename... Data> static bool WriteOkay(FileFd &output, Data&&... data)
60{
61 bool Okay = likely(output.Failed() == false);
62 return WriteOkay(Okay, output, std::forward<Data>(data)...);
63}
64 /*}}}*/
c8a4ce6c
DK
65// WriteScenarioVersion /*{{{*/
66static void WriteScenarioVersion(pkgDepCache &Cache, FILE* output, pkgCache::PkgIterator const &Pkg,
d4f626ff
DK
67 pkgCache::VerIterator const &Ver)
68{
69 fprintf(output, "Package: %s\n", Pkg.Name());
a221efc3 70 fprintf(output, "Source: %s\n", Ver.SourcePkgName());
d4f626ff
DK
71 fprintf(output, "Architecture: %s\n", Ver.Arch());
72 fprintf(output, "Version: %s\n", Ver.VerStr());
eed4639e 73 fprintf(output, "Source-Version: %s\n", Ver.SourceVerStr());
d4f626ff
DK
74 if (Pkg.CurrentVer() == Ver)
75 fprintf(output, "Installed: yes\n");
cbc702ea
DK
76 if (Pkg->SelectedState == pkgCache::State::Hold ||
77 (Cache[Pkg].Keep() == true && Cache[Pkg].Protect() == true))
d4f626ff
DK
78 fprintf(output, "Hold: yes\n");
79 fprintf(output, "APT-ID: %d\n", Ver->ID);
ef00bd7a
DK
80 if (PrioMap[Ver->Priority] != nullptr)
81 fprintf(output, "Priority: %s\n", PrioMap[Ver->Priority]);
d4f626ff
DK
82 if ((Pkg->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential)
83 fprintf(output, "Essential: yes\n");
ef00bd7a
DK
84 if (Ver->Section != 0)
85 fprintf(output, "Section: %s\n", Ver.Section());
894d672e 86 if ((Ver->MultiArch & pkgCache::Version::Allowed) == pkgCache::Version::Allowed)
d4f626ff 87 fprintf(output, "Multi-Arch: allowed\n");
894d672e 88 else if ((Ver->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign)
d4f626ff 89 fprintf(output, "Multi-Arch: foreign\n");
894d672e 90 else if ((Ver->MultiArch & pkgCache::Version::Same) == pkgCache::Version::Same)
d4f626ff 91 fprintf(output, "Multi-Arch: same\n");
b5ea5d4a
SZ
92 std::set<string> Releases;
93 for (pkgCache::VerFileIterator I = Ver.FileList(); I.end() == false; ++I) {
94 pkgCache::PkgFileIterator File = I.File();
b07aeb1a 95 if (File.Flagged(pkgCache::Flag::NotSource) == false) {
b5ea5d4a
SZ
96 string Release = File.RelStr();
97 if (!Release.empty())
98 Releases.insert(Release);
99 }
100 }
101 if (!Releases.empty()) {
102 fprintf(output, "APT-Release:\n");
103 for (std::set<string>::iterator R = Releases.begin(); R != Releases.end(); ++R)
104 fprintf(output, " %s\n", R->c_str());
d4f626ff 105 }
3c7567a5 106 fprintf(output, "APT-Pin: %d\n", Cache.GetPolicy().GetPriority(Ver));
294a8020 107 if (Cache.GetCandidateVersion(Pkg) == Ver)
d4f626ff
DK
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");
ef00bd7a
DK
111}
112static bool WriteScenarioVersion(pkgDepCache &Cache, FileFd &output, pkgCache::PkgIterator const &Pkg,
113 pkgCache::VerIterator const &Ver)
114{
4e92b116
DK
115 bool Okay = WriteOkay(output, "Package: ", Pkg.Name(),
116 "\nSource: ", Ver.SourcePkgName(),
117 "\nArchitecture: ", Ver.Arch(),
118 "\nVersion: ", Ver.VerStr(),
119 "\nSource-Version: ", Ver.SourceVerStr());
ef00bd7a 120 if (Pkg.CurrentVer() == Ver)
4e92b116 121 WriteOkay(Okay, output, "\nInstalled: yes");
ef00bd7a
DK
122 if (Pkg->SelectedState == pkgCache::State::Hold ||
123 (Cache[Pkg].Keep() == true && Cache[Pkg].Protect() == true))
4e92b116
DK
124 WriteOkay(Okay, output, "\nHold: yes");
125 WriteOkay(Okay, output, "\nAPT-ID: ", Ver->ID);
ef00bd7a 126 if (PrioMap[Ver->Priority] != nullptr)
4e92b116 127 WriteOkay(Okay, output, "\nPriority: ", PrioMap[Ver->Priority]);
ef00bd7a 128 if ((Pkg->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential)
4e92b116 129 WriteOkay(Okay, output, "\nEssential: yes");
ef00bd7a 130 if (Ver->Section != 0)
4e92b116 131 WriteOkay(Okay, output, "\nSection: ", Ver.Section());
ef00bd7a 132 if ((Ver->MultiArch & pkgCache::Version::Allowed) == pkgCache::Version::Allowed)
4e92b116 133 WriteOkay(Okay, output, "\nMulti-Arch: allowed");
ef00bd7a 134 else if ((Ver->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign)
4e92b116 135 WriteOkay(Okay, output, "\nMulti-Arch: foreign");
ef00bd7a 136 else if ((Ver->MultiArch & pkgCache::Version::Same) == pkgCache::Version::Same)
4e92b116 137 WriteOkay(Okay, output, "\nMulti-Arch: same");
ef00bd7a
DK
138 std::set<string> Releases;
139 for (pkgCache::VerFileIterator I = Ver.FileList(); I.end() == false; ++I) {
140 pkgCache::PkgFileIterator File = I.File();
141 if (File.Flagged(pkgCache::Flag::NotSource) == false) {
142 string Release = File.RelStr();
143 if (!Release.empty())
144 Releases.insert(Release);
145 }
146 }
147 if (!Releases.empty()) {
4e92b116 148 WriteOkay(Okay, output, "\nAPT-Release:");
ef00bd7a 149 for (std::set<string>::iterator R = Releases.begin(); R != Releases.end(); ++R)
4e92b116 150 WriteOkay(Okay, output, "\n ", *R);
ef00bd7a 151 }
4e92b116 152 WriteOkay(Okay, output, "\nAPT-Pin: ", Cache.GetPolicy().GetPriority(Ver));
ef00bd7a 153 if (Cache.GetCandidateVersion(Pkg) == Ver)
4e92b116 154 WriteOkay(Okay, output, "\nAPT-Candidate: yes");
ef00bd7a 155 if ((Cache[Pkg].Flags & pkgCache::Flag::Auto) == pkgCache::Flag::Auto)
4e92b116 156 WriteOkay(Okay, output, "\nAPT-Automatic: yes");
ef00bd7a 157 return Okay;
d4f626ff
DK
158}
159 /*}}}*/
c8a4ce6c
DK
160// WriteScenarioDependency /*{{{*/
161static void WriteScenarioDependency( FILE* output, pkgCache::VerIterator const &Ver)
d4f626ff
DK
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 {
8c7af4d4 167 if (Dep.IsImplicit() == true)
d4f626ff
DK
168 continue;
169 if (orGroup == false)
170 dependencies[Dep->Type].append(", ");
3addaba1 171 dependencies[Dep->Type].append(Dep.TargetPkg().Name());
d4f626ff
DK
172 if (Dep->Version != 0)
173 dependencies[Dep->Type].append(" (").append(pkgCache::CompTypeDeb(Dep->CompareOp)).append(" ").append(Dep.TargetVer()).append(")");
174 if ((Dep->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or)
175 {
176 dependencies[Dep->Type].append(" | ");
177 orGroup = true;
178 }
179 else
180 orGroup = false;
181 }
182 for (int i = 1; i < pkgCache::Dep::Enhances + 1; ++i)
183 if (dependencies[i].empty() == false)
184 fprintf(output, "%s: %s\n", DepMap[i], dependencies[i].c_str()+2);
185 string provides;
186 for (pkgCache::PrvIterator Prv = Ver.ProvidesList(); Prv.end() == false; ++Prv)
187 {
d5648746 188 if (Prv.IsMultiArchImplicit() == true)
d4f626ff 189 continue;
ef00bd7a
DK
190 if (provides.empty() == false)
191 provides.append(", ");
192 provides.append(Prv.Name());
2c53226b
DK
193 if (Prv->ProvideVersion != 0)
194 provides.append(" (= ").append(Prv.ProvideVersion()).append(")");
d4f626ff
DK
195 }
196 if (provides.empty() == false)
ef00bd7a
DK
197 fprintf(output, "Provides: %s\n", provides.c_str());
198}
199static bool WriteScenarioDependency(FileFd &output, pkgCache::VerIterator const &Ver)
200{
201 std::string dependencies[pkgCache::Dep::Enhances + 1];
202 bool orGroup = false;
203 for (pkgCache::DepIterator Dep = Ver.DependsList(); Dep.end() == false; ++Dep)
204 {
205 if (Dep.IsImplicit() == true)
206 continue;
207 if (orGroup == false && dependencies[Dep->Type].empty() == false)
208 dependencies[Dep->Type].append(", ");
209 dependencies[Dep->Type].append(Dep.TargetPkg().Name());
210 if (Dep->Version != 0)
211 dependencies[Dep->Type].append(" (").append(pkgCache::CompTypeDeb(Dep->CompareOp)).append(" ").append(Dep.TargetVer()).append(")");
212 if ((Dep->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or)
213 {
214 dependencies[Dep->Type].append(" | ");
215 orGroup = true;
216 }
217 else
218 orGroup = false;
219 }
4e92b116 220 bool Okay = output.Failed() == false;
ef00bd7a
DK
221 for (int i = 1; i < pkgCache::Dep::Enhances + 1; ++i)
222 if (dependencies[i].empty() == false)
4e92b116 223 WriteOkay(Okay, output, "\n", DepMap[i], ": ", dependencies[i]);
ef00bd7a
DK
224 string provides;
225 for (pkgCache::PrvIterator Prv = Ver.ProvidesList(); Prv.end() == false; ++Prv)
226 {
227 if (Prv.IsMultiArchImplicit() == true)
228 continue;
229 if (provides.empty() == false)
230 provides.append(", ");
231 provides.append(Prv.Name());
232 if (Prv->ProvideVersion != 0)
233 provides.append(" (= ").append(Prv.ProvideVersion()).append(")");
234 }
235 if (provides.empty() == false)
4e92b116
DK
236 WriteOkay(Okay, output, "\nProvides: ", provides);
237 return WriteOkay(Okay, output, "\n");
d4f626ff
DK
238}
239 /*}}}*/
c8a4ce6c
DK
240// WriteScenarioLimitedDependency /*{{{*/
241static void WriteScenarioLimitedDependency(FILE* output,
d4f626ff
DK
242 pkgCache::VerIterator const &Ver,
243 APT::PackageSet const &pkgset)
244{
245 std::string dependencies[pkgCache::Dep::Enhances + 1];
246 bool orGroup = false;
247 for (pkgCache::DepIterator Dep = Ver.DependsList(); Dep.end() == false; ++Dep)
248 {
8c7af4d4 249 if (Dep.IsImplicit() == true)
d4f626ff
DK
250 continue;
251 if (orGroup == false)
252 {
253 if (pkgset.find(Dep.TargetPkg()) == pkgset.end())
254 continue;
ef00bd7a
DK
255 if (dependencies[Dep->Type].empty() == false)
256 dependencies[Dep->Type].append(", ");
d4f626ff
DK
257 }
258 else if (pkgset.find(Dep.TargetPkg()) == pkgset.end())
259 {
260 if ((Dep->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or)
261 continue;
262 dependencies[Dep->Type].erase(dependencies[Dep->Type].end()-3, dependencies[Dep->Type].end());
263 orGroup = false;
264 continue;
265 }
3addaba1 266 dependencies[Dep->Type].append(Dep.TargetPkg().Name());
d4f626ff
DK
267 if (Dep->Version != 0)
268 dependencies[Dep->Type].append(" (").append(pkgCache::CompTypeDeb(Dep->CompareOp)).append(" ").append(Dep.TargetVer()).append(")");
269 if ((Dep->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or)
270 {
271 dependencies[Dep->Type].append(" | ");
272 orGroup = true;
273 }
274 else
275 orGroup = false;
276 }
277 for (int i = 1; i < pkgCache::Dep::Enhances + 1; ++i)
278 if (dependencies[i].empty() == false)
ef00bd7a 279 fprintf(output, "%s: %s\n", DepMap[i], dependencies[i].c_str());
d4f626ff
DK
280 string provides;
281 for (pkgCache::PrvIterator Prv = Ver.ProvidesList(); Prv.end() == false; ++Prv)
282 {
d5648746 283 if (Prv.IsMultiArchImplicit() == true)
d4f626ff
DK
284 continue;
285 if (pkgset.find(Prv.ParentPkg()) == pkgset.end())
286 continue;
ef00bd7a
DK
287 if (provides.empty() == false)
288 provides.append(", ");
289 provides.append(Prv.Name());
290 if (Prv->ProvideVersion != 0)
291 provides.append(" (= ").append(Prv.ProvideVersion()).append(")");
d4f626ff
DK
292 }
293 if (provides.empty() == false)
ef00bd7a
DK
294 fprintf(output, "Provides: %s\n", provides.c_str());
295}
296static bool WriteScenarioLimitedDependency(FileFd &output,
297 pkgCache::VerIterator const &Ver,
298 APT::PackageSet const &pkgset)
299{
300 std::string dependencies[pkgCache::Dep::Enhances + 1];
301 bool orGroup = false;
302 for (pkgCache::DepIterator Dep = Ver.DependsList(); Dep.end() == false; ++Dep)
303 {
304 if (Dep.IsImplicit() == true)
305 continue;
306 if (orGroup == false)
307 {
308 if (pkgset.find(Dep.TargetPkg()) == pkgset.end())
309 continue;
310 if (dependencies[Dep->Type].empty() == false)
311 dependencies[Dep->Type].append(", ");
312 }
313 else if (pkgset.find(Dep.TargetPkg()) == pkgset.end())
314 {
315 if ((Dep->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or)
316 continue;
317 dependencies[Dep->Type].erase(dependencies[Dep->Type].end()-3, dependencies[Dep->Type].end());
318 orGroup = false;
319 continue;
320 }
321 dependencies[Dep->Type].append(Dep.TargetPkg().Name());
322 if (Dep->Version != 0)
323 dependencies[Dep->Type].append(" (").append(pkgCache::CompTypeDeb(Dep->CompareOp)).append(" ").append(Dep.TargetVer()).append(")");
324 if ((Dep->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or)
325 {
326 dependencies[Dep->Type].append(" | ");
327 orGroup = true;
328 }
329 else
330 orGroup = false;
331 }
4e92b116 332 bool Okay = output.Failed() == false;
ef00bd7a
DK
333 for (int i = 1; i < pkgCache::Dep::Enhances + 1; ++i)
334 if (dependencies[i].empty() == false)
4e92b116 335 WriteOkay(Okay, output, "\n", DepMap[i], ": ", dependencies[i]);
ef00bd7a
DK
336 string provides;
337 for (pkgCache::PrvIterator Prv = Ver.ProvidesList(); Prv.end() == false; ++Prv)
338 {
339 if (Prv.IsMultiArchImplicit() == true)
340 continue;
341 if (pkgset.find(Prv.ParentPkg()) == pkgset.end())
342 continue;
343 if (provides.empty() == false)
344 provides.append(", ");
345 provides.append(Prv.Name());
346 if (Prv->ProvideVersion != 0)
347 provides.append(" (= ").append(Prv.ProvideVersion()).append(")");
348 }
349 if (provides.empty() == false)
4e92b116
DK
350 WriteOkay(Okay, output, "\nProvides: ", provides);
351 return WriteOkay(Okay, output, "\n");
d4f626ff
DK
352}
353 /*}}}*/
33190fe3
DK
354static bool SkipUnavailableVersions(pkgDepCache &Cache, pkgCache::PkgIterator const &Pkg, pkgCache::VerIterator const &Ver)/*{{{*/
355{
356 /* versions which aren't current and aren't available in
357 any "online" source file are bad, expect if they are the choosen
358 candidate: The exception is for build-dep implementation as it creates
359 such pseudo (package) versions and removes them later on again.
360 We filter out versions at all so packages in 'rc' state only available
361 in dpkg/status aren't passed to solvers as they can't be installed. */
362 if (Pkg->CurrentVer != 0)
363 return false;
364 if (Cache.GetCandidateVersion(Pkg) == Ver)
365 return false;
366 for (pkgCache::VerFileIterator I = Ver.FileList(); I.end() == false; ++I)
367 if (I.File().Flagged(pkgCache::Flag::NotSource) == false)
368 return false;
369 return true;
370}
371 /*}}}*/
c8a4ce6c
DK
372// EDSP::WriteScenario - to the given file descriptor /*{{{*/
373bool EDSP::WriteScenario(pkgDepCache &Cache, FILE* output, OpProgress *Progress)
374{
375 if (Progress != NULL)
376 Progress->SubProgress(Cache.Head().VersionCount, _("Send scenario to solver"));
377 unsigned long p = 0;
378 std::vector<std::string> archs = APT::Configuration::getArchitectures();
379 for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; ++Pkg)
380 {
381 std::string const arch = Pkg.Arch();
382 if (std::find(archs.begin(), archs.end(), arch) == archs.end())
383 continue;
384 for (pkgCache::VerIterator Ver = Pkg.VersionList(); Ver.end() == false; ++Ver, ++p)
385 {
33190fe3
DK
386 if (SkipUnavailableVersions(Cache, Pkg, Ver))
387 continue;
c8a4ce6c
DK
388 WriteScenarioVersion(Cache, output, Pkg, Ver);
389 WriteScenarioDependency(output, Ver);
390 fprintf(output, "\n");
391 if (Progress != NULL && p % 100 == 0)
392 Progress->Progress(p);
393 }
394 }
395 return true;
ef00bd7a
DK
396}
397bool EDSP::WriteScenario(pkgDepCache &Cache, FileFd &output, OpProgress *Progress)
398{
399 if (Progress != NULL)
400 Progress->SubProgress(Cache.Head().VersionCount, _("Send scenario to solver"));
401 unsigned long p = 0;
4e92b116 402 bool Okay = output.Failed() == false;
ef00bd7a 403 std::vector<std::string> archs = APT::Configuration::getArchitectures();
4e92b116 404 for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false && likely(Okay); ++Pkg)
ef00bd7a
DK
405 {
406 std::string const arch = Pkg.Arch();
407 if (std::find(archs.begin(), archs.end(), arch) == archs.end())
408 continue;
4e92b116 409 for (pkgCache::VerIterator Ver = Pkg.VersionList(); Ver.end() == false && likely(Okay); ++Ver, ++p)
ef00bd7a
DK
410 {
411 if (SkipUnavailableVersions(Cache, Pkg, Ver))
412 continue;
413 Okay &= WriteScenarioVersion(Cache, output, Pkg, Ver);
414 Okay &= WriteScenarioDependency(output, Ver);
4e92b116 415 WriteOkay(Okay, output, "\n");
ef00bd7a
DK
416 if (Progress != NULL && p % 100 == 0)
417 Progress->Progress(p);
418 }
419 }
420 return true;
c8a4ce6c
DK
421}
422 /*}}}*/
423// EDSP::WriteLimitedScenario - to the given file descriptor /*{{{*/
424bool EDSP::WriteLimitedScenario(pkgDepCache &Cache, FILE* output,
425 APT::PackageSet const &pkgset,
426 OpProgress *Progress)
427{
428 if (Progress != NULL)
429 Progress->SubProgress(Cache.Head().VersionCount, _("Send scenario to solver"));
430 unsigned long p = 0;
431 for (APT::PackageSet::const_iterator Pkg = pkgset.begin(); Pkg != pkgset.end(); ++Pkg, ++p)
432 for (pkgCache::VerIterator Ver = Pkg.VersionList(); Ver.end() == false; ++Ver)
433 {
33190fe3
DK
434 if (SkipUnavailableVersions(Cache, Pkg, Ver))
435 continue;
c8a4ce6c
DK
436 WriteScenarioVersion(Cache, output, Pkg, Ver);
437 WriteScenarioLimitedDependency(output, Ver, pkgset);
438 fprintf(output, "\n");
439 if (Progress != NULL && p % 100 == 0)
440 Progress->Progress(p);
441 }
442 if (Progress != NULL)
443 Progress->Done();
444 return true;
ef00bd7a
DK
445}
446bool EDSP::WriteLimitedScenario(pkgDepCache &Cache, FileFd &output,
447 APT::PackageSet const &pkgset,
448 OpProgress *Progress)
449{
450 if (Progress != NULL)
451 Progress->SubProgress(Cache.Head().VersionCount, _("Send scenario to solver"));
452 unsigned long p = 0;
4e92b116
DK
453 bool Okay = output.Failed() == false;
454 for (APT::PackageSet::const_iterator Pkg = pkgset.begin(); Pkg != pkgset.end() && likely(Okay); ++Pkg, ++p)
455 for (pkgCache::VerIterator Ver = Pkg.VersionList(); Ver.end() == false && likely(Okay); ++Ver)
ef00bd7a
DK
456 {
457 if (SkipUnavailableVersions(Cache, Pkg, Ver))
458 continue;
459 Okay &= WriteScenarioVersion(Cache, output, Pkg, Ver);
460 Okay &= WriteScenarioLimitedDependency(output, Ver, pkgset);
4e92b116 461 WriteOkay(Okay, output, "\n");
ef00bd7a
DK
462 if (Progress != NULL && p % 100 == 0)
463 Progress->Progress(p);
464 }
465 if (Progress != NULL)
466 Progress->Done();
467 return Okay;
c8a4ce6c
DK
468}
469 /*}}}*/
c3b85126 470// EDSP::WriteRequest - to the given file descriptor /*{{{*/
93794bc9 471bool EDSP::WriteRequest(pkgDepCache &Cache, FILE* output, bool const Upgrade,
b57c0e35
DK
472 bool const DistUpgrade, bool const AutoRemove,
473 OpProgress *Progress)
6d38011b 474{
b57c0e35
DK
475 if (Progress != NULL)
476 Progress->SubProgress(Cache.Head().PackageCount, _("Send request to solver"));
477 unsigned long p = 0;
93794bc9 478 string del, inst;
b57c0e35 479 for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; ++Pkg, ++p)
6d38011b 480 {
b57c0e35
DK
481 if (Progress != NULL && p % 100 == 0)
482 Progress->Progress(p);
6d38011b 483 string* req;
036eb012
DK
484 pkgDepCache::StateCache &P = Cache[Pkg];
485 if (P.Delete() == true)
6d38011b 486 req = &del;
036eb012
DK
487 else if (P.NewInstall() == true || P.Upgrade() == true || P.ReInstall() == true ||
488 (P.Mode == pkgDepCache::ModeKeep && (P.iFlags & pkgDepCache::Protected) == pkgDepCache::Protected))
6d38011b 489 req = &inst;
6d38011b
DK
490 else
491 continue;
6d5bd614 492 req->append(" ").append(Pkg.FullName());
6d38011b 493 }
25252738 494 fprintf(output, "Request: EDSP 0.5\n");
caa32793
SZ
495
496 const char *arch = _config->Find("APT::Architecture").c_str();
497 std::vector<string> archs = APT::Configuration::getArchitectures();
498 fprintf(output, "Architecture: %s\n", arch);
499 fprintf(output, "Architectures:");
500 for (std::vector<string>::const_iterator a = archs.begin(); a != archs.end(); ++a)
501 fprintf(output, " %s", a->c_str());
502 fprintf(output, "\n");
503
6d38011b 504 if (del.empty() == false)
6d5bd614 505 fprintf(output, "Remove: %s\n", del.c_str()+1);
6d38011b 506 if (inst.empty() == false)
6d5bd614 507 fprintf(output, "Install: %s\n", inst.c_str()+1);
93794bc9
DK
508 if (Upgrade == true)
509 fprintf(output, "Upgrade: yes\n");
510 if (DistUpgrade == true)
511 fprintf(output, "Dist-Upgrade: yes\n");
512 if (AutoRemove == true)
513 fprintf(output, "Autoremove: yes\n");
eb1000f6
DK
514 auto const solver = _config->Find("APT::Solver", "internal");
515 fprintf(output, "Solver: %s\n", solver.c_str());
516 auto const solverconf = std::string("APT::Solver::") + solver + "::";
517 if (_config->FindB(solverconf + "Strict-Pinning", _config->FindB("APT::Solver::Strict-Pinning", true)) == false)
93794bc9 518 fprintf(output, "Strict-Pinning: no\n");
eb1000f6
DK
519 auto const solverpref = _config->Find(solverconf + "Preferences", _config->Find("APT::Solver::Preferences", ""));
520 if (solverpref.empty() == false)
521 fprintf(output, "Preferences: %s\n", solverpref.c_str());
6d5bd614 522 fprintf(output, "\n");
e3674d91 523 return true;
ef00bd7a
DK
524}
525bool EDSP::WriteRequest(pkgDepCache &Cache, FileFd &output, bool const Upgrade,
526 bool const DistUpgrade, bool const AutoRemove,
527 OpProgress *Progress)
528{
529 if (Progress != NULL)
530 Progress->SubProgress(Cache.Head().PackageCount, _("Send request to solver"));
531 unsigned long p = 0;
532 string del, inst;
533 for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; ++Pkg, ++p)
534 {
535 if (Progress != NULL && p % 100 == 0)
536 Progress->Progress(p);
537 string* req;
538 pkgDepCache::StateCache &P = Cache[Pkg];
539 if (P.Delete() == true)
540 req = &del;
541 else if (P.NewInstall() == true || P.Upgrade() == true || P.ReInstall() == true ||
542 (P.Mode == pkgDepCache::ModeKeep && (P.iFlags & pkgDepCache::Protected) == pkgDepCache::Protected))
543 req = &inst;
544 else
545 continue;
546 req->append(" ").append(Pkg.FullName());
547 }
4e92b116 548 bool Okay = WriteOkay(output, "Request: EDSP 0.5\n");
ef00bd7a
DK
549
550 const char *arch = _config->Find("APT::Architecture").c_str();
551 std::vector<string> archs = APT::Configuration::getArchitectures();
4e92b116
DK
552 WriteOkay(Okay, output, "Architecture: ", arch, "\n",
553 "Architectures:");
ef00bd7a 554 for (std::vector<string>::const_iterator a = archs.begin(); a != archs.end(); ++a)
4e92b116
DK
555 WriteOkay(Okay, output, " ", *a);
556 WriteOkay(Okay, output, "\n");
ef00bd7a
DK
557
558 if (del.empty() == false)
4e92b116 559 WriteOkay(Okay, output, "Remove:", del, "\n");
ef00bd7a 560 if (inst.empty() == false)
4e92b116 561 WriteOkay(Okay, output, "Install:", inst, "\n");
ef00bd7a 562 if (Upgrade == true)
4e92b116 563 WriteOkay(Okay, output, "Upgrade: yes\n");
ef00bd7a 564 if (DistUpgrade == true)
4e92b116 565 WriteOkay(Okay, output, "Dist-Upgrade: yes\n");
ef00bd7a 566 if (AutoRemove == true)
4e92b116 567 WriteOkay(Okay, output, "Autoremove: yes\n");
ef00bd7a 568 if (_config->FindB("APT::Solver::Strict-Pinning", true) == false)
4e92b116 569 WriteOkay(Okay, output, "Strict-Pinning: no\n");
ef00bd7a
DK
570 string solverpref("APT::Solver::");
571 solverpref.append(_config->Find("APT::Solver", "internal")).append("::Preferences");
572 if (_config->Exists(solverpref) == true)
4e92b116
DK
573 WriteOkay(Okay, output, "Preferences: ", _config->Find(solverpref,""), "\n");
574 return WriteOkay(Okay, output, "\n");
e3674d91
DK
575}
576 /*}}}*/
2029276f 577// EDSP::ReadResponse - from the given file descriptor /*{{{*/
b57c0e35 578bool EDSP::ReadResponse(int const input, pkgDepCache &Cache, OpProgress *Progress) {
2a33cb16
DK
579 /* We build an map id to mmap offset here
580 In theory we could use the offset as ID, but then VersionCount
581 couldn't be used to create other versionmappings anymore and it
582 would be too easy for a (buggy) solver to segfault APTā€¦ */
583 unsigned long long const VersionCount = Cache.Head().VersionCount;
584 unsigned long VerIdx[VersionCount];
76d4aab0 585 for (pkgCache::PkgIterator P = Cache.PkgBegin(); P.end() == false; ++P) {
2a33cb16
DK
586 for (pkgCache::VerIterator V = P.VersionList(); V.end() == false; ++V)
587 VerIdx[V->ID] = V.Index();
76d4aab0
DK
588 Cache[P].Marked = true;
589 Cache[P].Garbage = false;
590 }
2a33cb16 591
c80a49f5
DK
592 FileFd in;
593 in.OpenDescriptor(input, FileFd::ReadOnly);
288a76d2 594 pkgTagFile response(&in, 100);
c80a49f5
DK
595 pkgTagSection section;
596
90e7fba4 597 std::set<decltype(Cache.PkgBegin()->ID)> seenOnce;
2029276f
DK
598 while (response.Step(section) == true) {
599 std::string type;
600 if (section.Exists("Install") == true)
601 type = "Install";
602 else if (section.Exists("Remove") == true)
603 type = "Remove";
e876223c 604 else if (section.Exists("Progress") == true) {
b57c0e35 605 if (Progress != NULL) {
c6660a4b 606 string msg = section.FindS("Message");
b57c0e35 607 if (msg.empty() == true)
c6660a4b
DK
608 msg = _("Prepare for receiving solution");
609 Progress->SubProgress(100, msg, section.FindI("Percentage", 0));
b57c0e35 610 }
e876223c 611 continue;
ebfeeaed 612 } else if (section.Exists("Error") == true) {
27c69dd0
DK
613 std::string msg = SubstVar(SubstVar(section.FindS("Message"), "\n .\n", "\n\n"), "\n ", "\n");
614 if (msg.empty() == true) {
615 msg = _("External solver failed without a proper error message");
a1e68c33 616 _error->Error("%s", msg.c_str());
27c69dd0
DK
617 } else
618 _error->Error("External solver failed with: %s", msg.substr(0,msg.find('\n')).c_str());
619 if (Progress != NULL)
620 Progress->Done();
ebfeeaed
DK
621 std::cerr << "The solver encountered an error of type: " << section.FindS("Error") << std::endl;
622 std::cerr << "The following information might help you to understand what is wrong:" << std::endl;
27c69dd0
DK
623 std::cerr << msg << std::endl << std::endl;
624 return false;
76d4aab0
DK
625 } else if (section.Exists("Autoremove") == true)
626 type = "Autoremove";
627 else
2029276f 628 continue;
29099cb6 629
2a33cb16
DK
630 size_t const id = section.FindULL(type.c_str(), VersionCount);
631 if (id == VersionCount) {
69a78835
DK
632 _error->Warning("Unable to parse %s request with id value '%s'!", type.c_str(), section.FindS(type.c_str()).c_str());
633 continue;
2a33cb16
DK
634 } else if (id > Cache.Head().VersionCount) {
635 _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());
636 continue;
69a78835 637 }
2029276f 638
2a33cb16 639 pkgCache::VerIterator Ver(Cache.GetCache(), Cache.GetCache().VerP + VerIdx[id]);
90e7fba4
DK
640 auto const Pkg = Ver.ParentPkg();
641 if (type == "Autoremove") {
642 Cache[Pkg].Marked = false;
643 Cache[Pkg].Garbage = true;
644 } else if (seenOnce.emplace(Pkg->ID).second == false) {
645 _error->Warning("Ignoring %s stanza received for package %s which already had a previous stanza effecting it!", type.c_str(), Pkg.FullName(false).c_str());
646 } else if (type == "Install") {
647 if (Pkg.CurrentVer() == Ver) {
648 _error->Warning("Ignoring Install stanza received for version %s of package %s which is already installed!",
649 Ver.VerStr(), Pkg.FullName(false).c_str());
650 } else {
651 Cache.SetCandidateVersion(Ver);
652 Cache.MarkInstall(Pkg, false, 0, false);
653 }
654 } else if (type == "Remove") {
655 if (Pkg->CurrentVer == 0)
656 _error->Warning("Ignoring Remove stanza received for version %s of package %s which isn't installed!",
657 Ver.VerStr(), Pkg.FullName(false).c_str());
658 else if (Pkg.CurrentVer() != Ver)
659 _error->Warning("Ignoring Remove stanza received for version %s of package %s which isn't the installed version %s!",
660 Ver.VerStr(), Pkg.FullName(false).c_str(), Pkg.CurrentVer().VerStr());
661 else
662 Cache.MarkDelete(Ver.ParentPkg(), false);
76d4aab0 663 }
2029276f
DK
664 }
665 return true;
666}
667 /*}}}*/
c8a4ce6c 668// ReadLine - first line from the given file descriptor /*{{{*/
6d5bd614
DK
669// ---------------------------------------------------------------------
670/* Little helper method to read a complete line into a string. Similar to
671 fgets but we need to use the low-level read() here as otherwise the
672 listparser will be confused later on as mixing of fgets and read isn't
2029276f 673 a supported action according to the manpages and results are undefined */
c8a4ce6c 674static bool ReadLine(int const input, std::string &line) {
6d5bd614
DK
675 char one;
676 ssize_t data = 0;
677 line.erase();
678 line.reserve(100);
679 while ((data = read(input, &one, sizeof(one))) != -1) {
680 if (data != 1)
681 continue;
682 if (one == '\n')
683 return true;
684 if (one == '\r')
685 continue;
686 if (line.empty() == true && isblank(one) != 0)
687 continue;
688 line += one;
689 }
690 return false;
691}
692 /*}}}*/
c8a4ce6c 693// StringToBool - convert yes/no to bool /*{{{*/
40795fca
DK
694// ---------------------------------------------------------------------
695/* we are not as lazy as we are in the global StringToBool as we really
696 only accept yes/no here - but we will ignore leading spaces */
c8a4ce6c 697static bool StringToBool(char const *answer, bool const defValue) {
40795fca
DK
698 for (; isspace(*answer) != 0; ++answer);
699 if (strncasecmp(answer, "yes", 3) == 0)
700 return true;
701 else if (strncasecmp(answer, "no", 2) == 0)
702 return false;
703 else
704 _error->Warning("Value '%s' is not a boolean 'yes' or 'no'!", answer);
705 return defValue;
706}
707 /*}}}*/
6d5bd614
DK
708// EDSP::ReadRequest - first stanza from the given file descriptor /*{{{*/
709bool EDSP::ReadRequest(int const input, std::list<std::string> &install,
40795fca
DK
710 std::list<std::string> &remove, bool &upgrade,
711 bool &distUpgrade, bool &autoRemove)
6d5bd614 712{
40795fca
DK
713 install.clear();
714 remove.clear();
715 upgrade = false;
716 distUpgrade = false;
717 autoRemove = false;
6d5bd614
DK
718 std::string line;
719 while (ReadLine(input, line) == true)
720 {
721 // Skip empty lines before request
722 if (line.empty() == true)
723 continue;
724 // The first Tag must be a request, so search for it
40795fca 725 if (line.compare(0, 8, "Request:") != 0)
6d5bd614
DK
726 continue;
727
728 while (ReadLine(input, line) == true)
729 {
730 // empty lines are the end of the request
731 if (line.empty() == true)
732 return true;
733
734 std::list<std::string> *request = NULL;
40795fca 735 if (line.compare(0, 8, "Install:") == 0)
6d5bd614 736 {
40795fca 737 line.erase(0, 8);
6d5bd614
DK
738 request = &install;
739 }
40795fca 740 else if (line.compare(0, 7, "Remove:") == 0)
6d5bd614 741 {
40795fca 742 line.erase(0, 7);
6d5bd614
DK
743 request = &remove;
744 }
40795fca 745 else if (line.compare(0, 8, "Upgrade:") == 0)
c8a4ce6c 746 upgrade = StringToBool(line.c_str() + 9, false);
40795fca 747 else if (line.compare(0, 13, "Dist-Upgrade:") == 0)
c8a4ce6c 748 distUpgrade = StringToBool(line.c_str() + 14, false);
40795fca 749 else if (line.compare(0, 11, "Autoremove:") == 0)
c8a4ce6c 750 autoRemove = StringToBool(line.c_str() + 12, false);
1f6cf9e7
DK
751 else if (line.compare(0, 13, "Architecture:") == 0)
752 _config->Set("APT::Architecture", line.c_str() + 14);
753 else if (line.compare(0, 14, "Architectures:") == 0)
754 {
755 std::string const archs = line.c_str() + 15;
756 _config->Set("APT::Architectures", SubstVar(archs, " ", ","));
757 }
eb1000f6
DK
758 else if (line.compare(0, 7, "Solver:") == 0)
759 ; // purely informational line
40795fca
DK
760 else
761 _error->Warning("Unknown line in EDSP Request stanza: %s", line.c_str());
762
6d5bd614
DK
763 if (request == NULL)
764 continue;
765 size_t end = line.length();
766 do {
767 size_t begin = line.rfind(' ');
768 if (begin == std::string::npos)
769 {
40795fca 770 request->push_back(line.substr(0, end));
6d5bd614
DK
771 break;
772 }
773 else if (begin < end)
774 request->push_back(line.substr(begin + 1, end));
775 line.erase(begin);
776 end = line.find_last_not_of(' ');
777 } while (end != std::string::npos);
778 }
779 }
780 return false;
781}
782 /*}}}*/
783// EDSP::ApplyRequest - first stanza from the given file descriptor /*{{{*/
c3b85126 784bool EDSP::ApplyRequest(std::list<std::string> const &install,
29099cb6
DK
785 std::list<std::string> const &remove,
786 pkgDepCache &Cache)
6d5bd614
DK
787{
788 for (std::list<std::string>::const_iterator i = install.begin();
d4f626ff
DK
789 i != install.end(); ++i) {
790 pkgCache::PkgIterator P = Cache.FindPkg(*i);
791 if (P.end() == true)
792 _error->Warning("Package %s is not known, so can't be installed", i->c_str());
793 else
794 Cache.MarkInstall(P, false);
795 }
6d5bd614
DK
796
797 for (std::list<std::string>::const_iterator i = remove.begin();
d4f626ff
DK
798 i != remove.end(); ++i) {
799 pkgCache::PkgIterator P = Cache.FindPkg(*i);
800 if (P.end() == true)
801 _error->Warning("Package %s is not known, so can't be installed", i->c_str());
802 else
803 Cache.MarkDelete(P);
804 }
6d5bd614
DK
805 return true;
806}
807 /*}}}*/
c3b85126
DK
808// EDSP::WriteSolution - to the given file descriptor /*{{{*/
809bool EDSP::WriteSolution(pkgDepCache &Cache, FILE* output)
e3674d91 810{
6d5bd614 811 bool const Debug = _config->FindB("Debug::EDSP::WriteSolution", false);
e3674d91
DK
812 for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; ++Pkg)
813 {
814 if (Cache[Pkg].Delete() == true)
d4f626ff
DK
815 {
816 fprintf(output, "Remove: %d\n", Pkg.CurrentVer()->ID);
817 if (Debug == true)
818 fprintf(output, "Package: %s\nVersion: %s\n", Pkg.FullName().c_str(), Pkg.CurrentVer().VerStr());
819 }
e3674d91 820 else if (Cache[Pkg].NewInstall() == true || Cache[Pkg].Upgrade() == true)
d4f626ff 821 {
294a8020
DK
822 pkgCache::VerIterator const CandVer = Cache.GetCandidateVersion(Pkg);
823 fprintf(output, "Install: %d\n", CandVer->ID);
d4f626ff 824 if (Debug == true)
294a8020 825 fprintf(output, "Package: %s\nVersion: %s\n", Pkg.FullName().c_str(), CandVer.VerStr());
d4f626ff 826 }
76d4aab0
DK
827 else if (Cache[Pkg].Garbage == true)
828 {
829 fprintf(output, "Autoremove: %d\n", Pkg.CurrentVer()->ID);
830 if (Debug == true)
831 fprintf(output, "Package: %s\nVersion: %s\n", Pkg.FullName().c_str(), Pkg.CurrentVer().VerStr());
76d4aab0 832 }
e3674d91
DK
833 else
834 continue;
e3674d91
DK
835 fprintf(output, "\n");
836 }
837
6d38011b 838 return true;
ef00bd7a
DK
839}
840bool EDSP::WriteSolution(pkgDepCache &Cache, FileFd &output)
841{
842 bool const Debug = _config->FindB("Debug::EDSP::WriteSolution", false);
4e92b116
DK
843 bool Okay = output.Failed() == false;
844 for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false && likely(Okay); ++Pkg)
ef00bd7a
DK
845 {
846 std::string action;
847 if (Cache[Pkg].Delete() == true)
4e92b116 848 WriteOkay(Okay, output, "Remove: ", Pkg.CurrentVer()->ID, "\n");
ef00bd7a 849 else if (Cache[Pkg].NewInstall() == true || Cache[Pkg].Upgrade() == true)
4e92b116 850 WriteOkay(Okay, output, "Install: ", Cache.GetCandidateVersion(Pkg)->ID, "\n");
ef00bd7a 851 else if (Cache[Pkg].Garbage == true)
4e92b116 852 WriteOkay(Okay, output, "Autoremove: ", Pkg.CurrentVer()->ID, "\n");
ef00bd7a
DK
853 else
854 continue;
855
ef00bd7a
DK
856 if (Debug)
857 {
4e92b116 858 WriteOkay(Okay, output, "Package: ", Pkg.FullName(), "\nVersion: ");
ef00bd7a 859 if (Cache[Pkg].Delete() == true || Cache[Pkg].Garbage == true)
4e92b116 860 WriteOkay(Okay, output, Pkg.CurrentVer().VerStr(), "\n\n");
ef00bd7a 861 else
4e92b116 862 WriteOkay(Okay, output, Cache.GetCandidateVersion(Pkg).VerStr(), "\n\n");
ef00bd7a
DK
863 }
864 else
4e92b116 865 WriteOkay(Okay, output, "\n");
ef00bd7a 866 }
ef00bd7a 867 return Okay;
6d38011b
DK
868}
869 /*}}}*/
e876223c
DK
870// EDSP::WriteProgess - pulse to the given file descriptor /*{{{*/
871bool EDSP::WriteProgress(unsigned short const percent, const char* const message, FILE* output) {
3d17b9ff
DK
872 fprintf(output, "Progress: %s\n", TimeRFC1123(time(NULL)).c_str());
873 fprintf(output, "Percentage: %d\n", percent);
874 fprintf(output, "Message: %s\n\n", message);
875 fflush(output);
e876223c 876 return true;
ef00bd7a
DK
877}
878bool EDSP::WriteProgress(unsigned short const percent, const char* const message, FileFd &output) {
4e92b116
DK
879 return WriteOkay(output, "Progress: ", TimeRFC1123(time(NULL)), "\n",
880 "Percentage: ", percent, "\n",
881 "Message: ", message, "\n\n") && output.Flush();
e876223c
DK
882}
883 /*}}}*/
ebfeeaed
DK
884// EDSP::WriteError - format an error message to be send to file descriptor /*{{{*/
885bool EDSP::WriteError(char const * const uuid, std::string const &message, FILE* output) {
886 fprintf(output, "Error: %s\n", uuid);
887 fprintf(output, "Message: %s\n\n", SubstVar(SubstVar(message, "\n\n", "\n.\n"), "\n", "\n ").c_str());
888 return true;
ef00bd7a
DK
889}
890bool EDSP::WriteError(char const * const uuid, std::string const &message, FileFd &output) {
4e92b116
DK
891 return WriteOkay(output, "Error: ", uuid, "\n",
892 "Message: ", SubstVar(SubstVar(message, "\n\n", "\n.\n"), "\n", "\n "),
893 "\n\n");
ebfeeaed
DK
894}
895 /*}}}*/
ac5fbff8 896// EDSP::ExecuteSolver - fork requested solver and setup ipc pipes {{{*/
5681b3fc 897pid_t EDSP::ExecuteSolver(const char* const solver, int * const solver_in, int * const solver_out, bool) {
741b7da9
DK
898 std::vector<std::string> const solverDirs = _config->FindVector("Dir::Bin::Solvers");
899 std::string file;
900 for (std::vector<std::string>::const_iterator dir = solverDirs.begin();
901 dir != solverDirs.end(); ++dir) {
902 file = flCombine(*dir, solver);
903 if (RealFileExists(file.c_str()) == true)
904 break;
905 file.clear();
906 }
ac5fbff8 907
741b7da9 908 if (file.empty() == true)
5681b3fc
DK
909 {
910 _error->Error("Can't call external solver '%s' as it is not in a configured directory!", solver);
911 return 0;
912 }
741b7da9
DK
913 int external[4] = {-1, -1, -1, -1};
914 if (pipe(external) != 0 || pipe(external + 2) != 0)
5681b3fc
DK
915 {
916 _error->Errno("Resolve", "Can't create needed IPC pipes for EDSP");
917 return 0;
918 }
741b7da9
DK
919 for (int i = 0; i < 4; ++i)
920 SetCloseExec(external[i], true);
ac5fbff8 921
741b7da9
DK
922 pid_t Solver = ExecFork();
923 if (Solver == 0) {
924 dup2(external[0], STDIN_FILENO);
925 dup2(external[3], STDOUT_FILENO);
926 const char* calling[2] = { file.c_str(), 0 };
927 execv(calling[0], (char**) calling);
928 std::cerr << "Failed to execute solver '" << solver << "'!" << std::endl;
929 _exit(100);
930 }
931 close(external[0]);
932 close(external[3]);
ac5fbff8 933
741b7da9 934 if (WaitFd(external[1], true, 5) == false)
5681b3fc
DK
935 {
936 _error->Errno("Resolve", "Timed out while Waiting on availability of solver stdin");
937 return 0;
938 }
ac5fbff8 939
741b7da9
DK
940 *solver_in = external[1];
941 *solver_out = external[2];
5681b3fc
DK
942 return Solver;
943}
944bool EDSP::ExecuteSolver(const char* const solver, int *solver_in, int *solver_out) {
945 if (ExecuteSolver(solver, solver_in, solver_out, true) == 0)
946 return false;
947 return true;
741b7da9
DK
948}
949 /*}}}*/
950// EDSP::ResolveExternal - resolve problems by asking external for help {{{*/
951bool EDSP::ResolveExternal(const char* const solver, pkgDepCache &Cache,
952 bool const upgrade, bool const distUpgrade,
b57c0e35 953 bool const autoRemove, OpProgress *Progress) {
741b7da9 954 int solver_in, solver_out;
5681b3fc
DK
955 pid_t const solver_pid = EDSP::ExecuteSolver(solver, &solver_in, &solver_out, true);
956 if (solver_pid == 0)
741b7da9
DK
957 return false;
958
ef00bd7a
DK
959 FileFd output;
960 if (output.OpenDescriptor(solver_in, FileFd::WriteOnly | FileFd::BufferedWrite, true) == false)
961 return _error->Errno("ResolveExternal", "Opening solver %s stdin on fd %d for writing failed", solver, solver_in);
b57c0e35 962
4e92b116 963 bool Okay = output.Failed() == false;
b57c0e35
DK
964 if (Progress != NULL)
965 Progress->OverallProgress(0, 100, 5, _("Execute external solver"));
4e92b116 966 Okay &= EDSP::WriteRequest(Cache, output, upgrade, distUpgrade, autoRemove, Progress);
b57c0e35
DK
967 if (Progress != NULL)
968 Progress->OverallProgress(5, 100, 20, _("Execute external solver"));
4e92b116 969 Okay &= EDSP::WriteScenario(Cache, output, Progress);
ef00bd7a 970 output.Close();
741b7da9 971
b57c0e35
DK
972 if (Progress != NULL)
973 Progress->OverallProgress(25, 100, 75, _("Execute external solver"));
4e92b116 974 if (Okay && EDSP::ReadResponse(solver_out, Cache, Progress) == false)
27c69dd0 975 return false;
741b7da9 976
5681b3fc 977 return ExecWait(solver_pid, solver);
ac5fbff8
DK
978}
979 /*}}}*/