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