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