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