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