]> git.saurik.com Git - apt.git/blame - apt-pkg/edsp.cc
show globalerrors before asking for confirmation
[apt.git] / apt-pkg / edsp.cc
CommitLineData
6d38011b
DK
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
3/* ######################################################################
4 Set of methods to help writing and reading everything needed for EDSP
5 ##################################################################### */
6 /*}}}*/
7// Include Files /*{{{*/
ea542140
DK
8#include <config.h>
9
6d38011b 10#include <apt-pkg/error.h>
472ff00e 11#include <apt-pkg/cacheset.h>
453b82a3
DK
12#include <apt-pkg/depcache.h>
13#include <apt-pkg/pkgcache.h>
14#include <apt-pkg/cacheiterators.h>
ac7f8f79
MV
15#include <apt-pkg/progress.h>
16#include <apt-pkg/fileutl.h>
17#include <apt-pkg/edsp.h>
18#include <apt-pkg/tagfile.h>
19#include <apt-pkg/strutl.h>
6d38011b 20
453b82a3
DK
21#include <ctype.h>
22#include <stddef.h>
23#include <string.h>
453b82a3 24#include <unistd.h>
6d38011b 25#include <stdio.h>
453b82a3 26#include <iostream>
453b82a3 27#include <limits>
472ff00e
DK
28#include <string>
29
ea542140 30#include <apti18n.h>
6d38011b
DK
31 /*}}}*/
32
472ff00e
DK
33using std::string;
34
d4f626ff 35// we could use pkgCache::DepType and ::Priority, but these would be localized stringsā€¦
c8a4ce6c 36const char * const PrioMap[] = {0, "important", "required", "standard",
d4f626ff 37 "optional", "extra"};
c8a4ce6c 38const char * const DepMap[] = {"", "Depends", "Pre-Depends", "Suggests",
d4f626ff
DK
39 "Recommends" , "Conflicts", "Replaces",
40 "Obsoletes", "Breaks", "Enhances"};
41
c8a4ce6c
DK
42
43// WriteScenarioVersion /*{{{*/
44static void WriteScenarioVersion(pkgDepCache &Cache, FILE* output, pkgCache::PkgIterator const &Pkg,
d4f626ff
DK
45 pkgCache::VerIterator const &Ver)
46{
47 fprintf(output, "Package: %s\n", Pkg.Name());
a221efc3 48 fprintf(output, "Source: %s\n", Ver.SourcePkgName());
d4f626ff
DK
49 fprintf(output, "Architecture: %s\n", Ver.Arch());
50 fprintf(output, "Version: %s\n", Ver.VerStr());
eed4639e 51 fprintf(output, "Source-Version: %s\n", Ver.SourceVerStr());
d4f626ff
DK
52 if (Pkg.CurrentVer() == Ver)
53 fprintf(output, "Installed: yes\n");
cbc702ea
DK
54 if (Pkg->SelectedState == pkgCache::State::Hold ||
55 (Cache[Pkg].Keep() == true && Cache[Pkg].Protect() == true))
d4f626ff
DK
56 fprintf(output, "Hold: yes\n");
57 fprintf(output, "APT-ID: %d\n", Ver->ID);
58 fprintf(output, "Priority: %s\n", PrioMap[Ver->Priority]);
59 if ((Pkg->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential)
60 fprintf(output, "Essential: yes\n");
61 fprintf(output, "Section: %s\n", Ver.Section());
894d672e 62 if ((Ver->MultiArch & pkgCache::Version::Allowed) == pkgCache::Version::Allowed)
d4f626ff 63 fprintf(output, "Multi-Arch: allowed\n");
894d672e 64 else if ((Ver->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign)
d4f626ff 65 fprintf(output, "Multi-Arch: foreign\n");
894d672e 66 else if ((Ver->MultiArch & pkgCache::Version::Same) == pkgCache::Version::Same)
d4f626ff 67 fprintf(output, "Multi-Arch: same\n");
b5ea5d4a
SZ
68 std::set<string> Releases;
69 for (pkgCache::VerFileIterator I = Ver.FileList(); I.end() == false; ++I) {
70 pkgCache::PkgFileIterator File = I.File();
b07aeb1a 71 if (File.Flagged(pkgCache::Flag::NotSource) == false) {
b5ea5d4a
SZ
72 string Release = File.RelStr();
73 if (!Release.empty())
74 Releases.insert(Release);
75 }
76 }
77 if (!Releases.empty()) {
78 fprintf(output, "APT-Release:\n");
79 for (std::set<string>::iterator R = Releases.begin(); R != Releases.end(); ++R)
80 fprintf(output, " %s\n", R->c_str());
d4f626ff 81 }
3c7567a5 82 fprintf(output, "APT-Pin: %d\n", Cache.GetPolicy().GetPriority(Ver));
294a8020 83 if (Cache.GetCandidateVersion(Pkg) == Ver)
d4f626ff
DK
84 fprintf(output, "APT-Candidate: yes\n");
85 if ((Cache[Pkg].Flags & pkgCache::Flag::Auto) == pkgCache::Flag::Auto)
86 fprintf(output, "APT-Automatic: yes\n");
87}
88 /*}}}*/
c8a4ce6c
DK
89// WriteScenarioDependency /*{{{*/
90static void WriteScenarioDependency( FILE* output, pkgCache::VerIterator const &Ver)
d4f626ff
DK
91{
92 std::string dependencies[pkgCache::Dep::Enhances + 1];
93 bool orGroup = false;
94 for (pkgCache::DepIterator Dep = Ver.DependsList(); Dep.end() == false; ++Dep)
95 {
8c7af4d4 96 if (Dep.IsImplicit() == true)
d4f626ff
DK
97 continue;
98 if (orGroup == false)
99 dependencies[Dep->Type].append(", ");
3addaba1 100 dependencies[Dep->Type].append(Dep.TargetPkg().Name());
d4f626ff
DK
101 if (Dep->Version != 0)
102 dependencies[Dep->Type].append(" (").append(pkgCache::CompTypeDeb(Dep->CompareOp)).append(" ").append(Dep.TargetVer()).append(")");
103 if ((Dep->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or)
104 {
105 dependencies[Dep->Type].append(" | ");
106 orGroup = true;
107 }
108 else
109 orGroup = false;
110 }
111 for (int i = 1; i < pkgCache::Dep::Enhances + 1; ++i)
112 if (dependencies[i].empty() == false)
113 fprintf(output, "%s: %s\n", DepMap[i], dependencies[i].c_str()+2);
114 string provides;
115 for (pkgCache::PrvIterator Prv = Ver.ProvidesList(); Prv.end() == false; ++Prv)
116 {
d5648746 117 if (Prv.IsMultiArchImplicit() == true)
d4f626ff
DK
118 continue;
119 provides.append(", ").append(Prv.Name());
2c53226b
DK
120 if (Prv->ProvideVersion != 0)
121 provides.append(" (= ").append(Prv.ProvideVersion()).append(")");
d4f626ff
DK
122 }
123 if (provides.empty() == false)
124 fprintf(output, "Provides: %s\n", provides.c_str()+2);
125}
126 /*}}}*/
c8a4ce6c
DK
127// WriteScenarioLimitedDependency /*{{{*/
128static void WriteScenarioLimitedDependency(FILE* output,
d4f626ff
DK
129 pkgCache::VerIterator const &Ver,
130 APT::PackageSet const &pkgset)
131{
132 std::string dependencies[pkgCache::Dep::Enhances + 1];
133 bool orGroup = false;
134 for (pkgCache::DepIterator Dep = Ver.DependsList(); Dep.end() == false; ++Dep)
135 {
8c7af4d4 136 if (Dep.IsImplicit() == true)
d4f626ff
DK
137 continue;
138 if (orGroup == false)
139 {
140 if (pkgset.find(Dep.TargetPkg()) == pkgset.end())
141 continue;
142 dependencies[Dep->Type].append(", ");
143 }
144 else if (pkgset.find(Dep.TargetPkg()) == pkgset.end())
145 {
146 if ((Dep->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or)
147 continue;
148 dependencies[Dep->Type].erase(dependencies[Dep->Type].end()-3, dependencies[Dep->Type].end());
149 orGroup = false;
150 continue;
151 }
3addaba1 152 dependencies[Dep->Type].append(Dep.TargetPkg().Name());
d4f626ff
DK
153 if (Dep->Version != 0)
154 dependencies[Dep->Type].append(" (").append(pkgCache::CompTypeDeb(Dep->CompareOp)).append(" ").append(Dep.TargetVer()).append(")");
155 if ((Dep->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or)
156 {
157 dependencies[Dep->Type].append(" | ");
158 orGroup = true;
159 }
160 else
161 orGroup = false;
162 }
163 for (int i = 1; i < pkgCache::Dep::Enhances + 1; ++i)
164 if (dependencies[i].empty() == false)
165 fprintf(output, "%s: %s\n", DepMap[i], dependencies[i].c_str()+2);
166 string provides;
167 for (pkgCache::PrvIterator Prv = Ver.ProvidesList(); Prv.end() == false; ++Prv)
168 {
d5648746 169 if (Prv.IsMultiArchImplicit() == true)
d4f626ff
DK
170 continue;
171 if (pkgset.find(Prv.ParentPkg()) == pkgset.end())
172 continue;
173 provides.append(", ").append(Prv.Name());
174 }
175 if (provides.empty() == false)
176 fprintf(output, "Provides: %s\n", provides.c_str()+2);
177}
178 /*}}}*/
33190fe3
DK
179static bool SkipUnavailableVersions(pkgDepCache &Cache, pkgCache::PkgIterator const &Pkg, pkgCache::VerIterator const &Ver)/*{{{*/
180{
181 /* versions which aren't current and aren't available in
182 any "online" source file are bad, expect if they are the choosen
183 candidate: The exception is for build-dep implementation as it creates
184 such pseudo (package) versions and removes them later on again.
185 We filter out versions at all so packages in 'rc' state only available
186 in dpkg/status aren't passed to solvers as they can't be installed. */
187 if (Pkg->CurrentVer != 0)
188 return false;
189 if (Cache.GetCandidateVersion(Pkg) == Ver)
190 return false;
191 for (pkgCache::VerFileIterator I = Ver.FileList(); I.end() == false; ++I)
192 if (I.File().Flagged(pkgCache::Flag::NotSource) == false)
193 return false;
194 return true;
195}
196 /*}}}*/
c8a4ce6c
DK
197// EDSP::WriteScenario - to the given file descriptor /*{{{*/
198bool EDSP::WriteScenario(pkgDepCache &Cache, FILE* output, OpProgress *Progress)
199{
200 if (Progress != NULL)
201 Progress->SubProgress(Cache.Head().VersionCount, _("Send scenario to solver"));
202 unsigned long p = 0;
203 std::vector<std::string> archs = APT::Configuration::getArchitectures();
204 for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; ++Pkg)
205 {
206 std::string const arch = Pkg.Arch();
207 if (std::find(archs.begin(), archs.end(), arch) == archs.end())
208 continue;
209 for (pkgCache::VerIterator Ver = Pkg.VersionList(); Ver.end() == false; ++Ver, ++p)
210 {
33190fe3
DK
211 if (SkipUnavailableVersions(Cache, Pkg, Ver))
212 continue;
c8a4ce6c
DK
213 WriteScenarioVersion(Cache, output, Pkg, Ver);
214 WriteScenarioDependency(output, Ver);
215 fprintf(output, "\n");
216 if (Progress != NULL && p % 100 == 0)
217 Progress->Progress(p);
218 }
219 }
220 return true;
221}
222 /*}}}*/
223// EDSP::WriteLimitedScenario - to the given file descriptor /*{{{*/
224bool EDSP::WriteLimitedScenario(pkgDepCache &Cache, FILE* output,
225 APT::PackageSet const &pkgset,
226 OpProgress *Progress)
227{
228 if (Progress != NULL)
229 Progress->SubProgress(Cache.Head().VersionCount, _("Send scenario to solver"));
230 unsigned long p = 0;
231 for (APT::PackageSet::const_iterator Pkg = pkgset.begin(); Pkg != pkgset.end(); ++Pkg, ++p)
232 for (pkgCache::VerIterator Ver = Pkg.VersionList(); Ver.end() == false; ++Ver)
233 {
33190fe3
DK
234 if (SkipUnavailableVersions(Cache, Pkg, Ver))
235 continue;
c8a4ce6c
DK
236 WriteScenarioVersion(Cache, output, Pkg, Ver);
237 WriteScenarioLimitedDependency(output, Ver, pkgset);
238 fprintf(output, "\n");
239 if (Progress != NULL && p % 100 == 0)
240 Progress->Progress(p);
241 }
242 if (Progress != NULL)
243 Progress->Done();
244 return true;
245}
246 /*}}}*/
c3b85126 247// EDSP::WriteRequest - to the given file descriptor /*{{{*/
93794bc9 248bool EDSP::WriteRequest(pkgDepCache &Cache, FILE* output, bool const Upgrade,
b57c0e35
DK
249 bool const DistUpgrade, bool const AutoRemove,
250 OpProgress *Progress)
6d38011b 251{
b57c0e35
DK
252 if (Progress != NULL)
253 Progress->SubProgress(Cache.Head().PackageCount, _("Send request to solver"));
254 unsigned long p = 0;
93794bc9 255 string del, inst;
b57c0e35 256 for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; ++Pkg, ++p)
6d38011b 257 {
b57c0e35
DK
258 if (Progress != NULL && p % 100 == 0)
259 Progress->Progress(p);
6d38011b 260 string* req;
036eb012
DK
261 pkgDepCache::StateCache &P = Cache[Pkg];
262 if (P.Delete() == true)
6d38011b 263 req = &del;
036eb012
DK
264 else if (P.NewInstall() == true || P.Upgrade() == true || P.ReInstall() == true ||
265 (P.Mode == pkgDepCache::ModeKeep && (P.iFlags & pkgDepCache::Protected) == pkgDepCache::Protected))
6d38011b 266 req = &inst;
6d38011b
DK
267 else
268 continue;
6d5bd614 269 req->append(" ").append(Pkg.FullName());
6d38011b 270 }
25252738 271 fprintf(output, "Request: EDSP 0.5\n");
caa32793
SZ
272
273 const char *arch = _config->Find("APT::Architecture").c_str();
274 std::vector<string> archs = APT::Configuration::getArchitectures();
275 fprintf(output, "Architecture: %s\n", arch);
276 fprintf(output, "Architectures:");
277 for (std::vector<string>::const_iterator a = archs.begin(); a != archs.end(); ++a)
278 fprintf(output, " %s", a->c_str());
279 fprintf(output, "\n");
280
6d38011b 281 if (del.empty() == false)
6d5bd614 282 fprintf(output, "Remove: %s\n", del.c_str()+1);
6d38011b 283 if (inst.empty() == false)
6d5bd614 284 fprintf(output, "Install: %s\n", inst.c_str()+1);
93794bc9
DK
285 if (Upgrade == true)
286 fprintf(output, "Upgrade: yes\n");
287 if (DistUpgrade == true)
288 fprintf(output, "Dist-Upgrade: yes\n");
289 if (AutoRemove == true)
290 fprintf(output, "Autoremove: yes\n");
eb1000f6
DK
291 auto const solver = _config->Find("APT::Solver", "internal");
292 fprintf(output, "Solver: %s\n", solver.c_str());
293 auto const solverconf = std::string("APT::Solver::") + solver + "::";
294 if (_config->FindB(solverconf + "Strict-Pinning", _config->FindB("APT::Solver::Strict-Pinning", true)) == false)
93794bc9 295 fprintf(output, "Strict-Pinning: no\n");
eb1000f6
DK
296 auto const solverpref = _config->Find(solverconf + "Preferences", _config->Find("APT::Solver::Preferences", ""));
297 if (solverpref.empty() == false)
298 fprintf(output, "Preferences: %s\n", solverpref.c_str());
6d5bd614 299 fprintf(output, "\n");
e3674d91
DK
300 return true;
301}
302 /*}}}*/
2029276f 303// EDSP::ReadResponse - from the given file descriptor /*{{{*/
b57c0e35 304bool EDSP::ReadResponse(int const input, pkgDepCache &Cache, OpProgress *Progress) {
2a33cb16
DK
305 /* We build an map id to mmap offset here
306 In theory we could use the offset as ID, but then VersionCount
307 couldn't be used to create other versionmappings anymore and it
308 would be too easy for a (buggy) solver to segfault APTā€¦ */
309 unsigned long long const VersionCount = Cache.Head().VersionCount;
310 unsigned long VerIdx[VersionCount];
76d4aab0 311 for (pkgCache::PkgIterator P = Cache.PkgBegin(); P.end() == false; ++P) {
2a33cb16
DK
312 for (pkgCache::VerIterator V = P.VersionList(); V.end() == false; ++V)
313 VerIdx[V->ID] = V.Index();
76d4aab0
DK
314 Cache[P].Marked = true;
315 Cache[P].Garbage = false;
316 }
2a33cb16 317
c80a49f5
DK
318 FileFd in;
319 in.OpenDescriptor(input, FileFd::ReadOnly);
288a76d2 320 pkgTagFile response(&in, 100);
c80a49f5
DK
321 pkgTagSection section;
322
90e7fba4 323 std::set<decltype(Cache.PkgBegin()->ID)> seenOnce;
2029276f
DK
324 while (response.Step(section) == true) {
325 std::string type;
326 if (section.Exists("Install") == true)
327 type = "Install";
328 else if (section.Exists("Remove") == true)
329 type = "Remove";
e876223c 330 else if (section.Exists("Progress") == true) {
b57c0e35 331 if (Progress != NULL) {
c6660a4b 332 string msg = section.FindS("Message");
b57c0e35 333 if (msg.empty() == true)
c6660a4b
DK
334 msg = _("Prepare for receiving solution");
335 Progress->SubProgress(100, msg, section.FindI("Percentage", 0));
b57c0e35 336 }
e876223c 337 continue;
ebfeeaed 338 } else if (section.Exists("Error") == true) {
27c69dd0
DK
339 std::string msg = SubstVar(SubstVar(section.FindS("Message"), "\n .\n", "\n\n"), "\n ", "\n");
340 if (msg.empty() == true) {
341 msg = _("External solver failed without a proper error message");
a1e68c33 342 _error->Error("%s", msg.c_str());
27c69dd0
DK
343 } else
344 _error->Error("External solver failed with: %s", msg.substr(0,msg.find('\n')).c_str());
345 if (Progress != NULL)
346 Progress->Done();
ebfeeaed
DK
347 std::cerr << "The solver encountered an error of type: " << section.FindS("Error") << std::endl;
348 std::cerr << "The following information might help you to understand what is wrong:" << std::endl;
27c69dd0
DK
349 std::cerr << msg << std::endl << std::endl;
350 return false;
76d4aab0
DK
351 } else if (section.Exists("Autoremove") == true)
352 type = "Autoremove";
353 else
2029276f 354 continue;
29099cb6 355
2a33cb16
DK
356 size_t const id = section.FindULL(type.c_str(), VersionCount);
357 if (id == VersionCount) {
69a78835
DK
358 _error->Warning("Unable to parse %s request with id value '%s'!", type.c_str(), section.FindS(type.c_str()).c_str());
359 continue;
2a33cb16
DK
360 } else if (id > Cache.Head().VersionCount) {
361 _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());
362 continue;
69a78835 363 }
2029276f 364
2a33cb16 365 pkgCache::VerIterator Ver(Cache.GetCache(), Cache.GetCache().VerP + VerIdx[id]);
90e7fba4
DK
366 auto const Pkg = Ver.ParentPkg();
367 if (type == "Autoremove") {
368 Cache[Pkg].Marked = false;
369 Cache[Pkg].Garbage = true;
370 } else if (seenOnce.emplace(Pkg->ID).second == false) {
371 _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());
372 } else if (type == "Install") {
373 if (Pkg.CurrentVer() == Ver) {
374 _error->Warning("Ignoring Install stanza received for version %s of package %s which is already installed!",
375 Ver.VerStr(), Pkg.FullName(false).c_str());
376 } else {
377 Cache.SetCandidateVersion(Ver);
378 Cache.MarkInstall(Pkg, false, 0, false);
379 }
380 } else if (type == "Remove") {
381 if (Pkg->CurrentVer == 0)
382 _error->Warning("Ignoring Remove stanza received for version %s of package %s which isn't installed!",
383 Ver.VerStr(), Pkg.FullName(false).c_str());
384 else if (Pkg.CurrentVer() != Ver)
385 _error->Warning("Ignoring Remove stanza received for version %s of package %s which isn't the installed version %s!",
386 Ver.VerStr(), Pkg.FullName(false).c_str(), Pkg.CurrentVer().VerStr());
387 else
388 Cache.MarkDelete(Ver.ParentPkg(), false);
76d4aab0 389 }
2029276f
DK
390 }
391 return true;
392}
393 /*}}}*/
c8a4ce6c 394// ReadLine - first line from the given file descriptor /*{{{*/
6d5bd614
DK
395// ---------------------------------------------------------------------
396/* Little helper method to read a complete line into a string. Similar to
397 fgets but we need to use the low-level read() here as otherwise the
398 listparser will be confused later on as mixing of fgets and read isn't
2029276f 399 a supported action according to the manpages and results are undefined */
c8a4ce6c 400static bool ReadLine(int const input, std::string &line) {
6d5bd614
DK
401 char one;
402 ssize_t data = 0;
403 line.erase();
404 line.reserve(100);
405 while ((data = read(input, &one, sizeof(one))) != -1) {
406 if (data != 1)
407 continue;
408 if (one == '\n')
409 return true;
410 if (one == '\r')
411 continue;
412 if (line.empty() == true && isblank(one) != 0)
413 continue;
414 line += one;
415 }
416 return false;
417}
418 /*}}}*/
c8a4ce6c 419// StringToBool - convert yes/no to bool /*{{{*/
40795fca
DK
420// ---------------------------------------------------------------------
421/* we are not as lazy as we are in the global StringToBool as we really
422 only accept yes/no here - but we will ignore leading spaces */
c8a4ce6c 423static bool StringToBool(char const *answer, bool const defValue) {
40795fca
DK
424 for (; isspace(*answer) != 0; ++answer);
425 if (strncasecmp(answer, "yes", 3) == 0)
426 return true;
427 else if (strncasecmp(answer, "no", 2) == 0)
428 return false;
429 else
430 _error->Warning("Value '%s' is not a boolean 'yes' or 'no'!", answer);
431 return defValue;
432}
433 /*}}}*/
6d5bd614
DK
434// EDSP::ReadRequest - first stanza from the given file descriptor /*{{{*/
435bool EDSP::ReadRequest(int const input, std::list<std::string> &install,
40795fca
DK
436 std::list<std::string> &remove, bool &upgrade,
437 bool &distUpgrade, bool &autoRemove)
6d5bd614 438{
40795fca
DK
439 install.clear();
440 remove.clear();
441 upgrade = false;
442 distUpgrade = false;
443 autoRemove = false;
6d5bd614
DK
444 std::string line;
445 while (ReadLine(input, line) == true)
446 {
447 // Skip empty lines before request
448 if (line.empty() == true)
449 continue;
450 // The first Tag must be a request, so search for it
40795fca 451 if (line.compare(0, 8, "Request:") != 0)
6d5bd614
DK
452 continue;
453
454 while (ReadLine(input, line) == true)
455 {
456 // empty lines are the end of the request
457 if (line.empty() == true)
458 return true;
459
460 std::list<std::string> *request = NULL;
40795fca 461 if (line.compare(0, 8, "Install:") == 0)
6d5bd614 462 {
40795fca 463 line.erase(0, 8);
6d5bd614
DK
464 request = &install;
465 }
40795fca 466 else if (line.compare(0, 7, "Remove:") == 0)
6d5bd614 467 {
40795fca 468 line.erase(0, 7);
6d5bd614
DK
469 request = &remove;
470 }
40795fca 471 else if (line.compare(0, 8, "Upgrade:") == 0)
c8a4ce6c 472 upgrade = StringToBool(line.c_str() + 9, false);
40795fca 473 else if (line.compare(0, 13, "Dist-Upgrade:") == 0)
c8a4ce6c 474 distUpgrade = StringToBool(line.c_str() + 14, false);
40795fca 475 else if (line.compare(0, 11, "Autoremove:") == 0)
c8a4ce6c 476 autoRemove = StringToBool(line.c_str() + 12, false);
1f6cf9e7
DK
477 else if (line.compare(0, 13, "Architecture:") == 0)
478 _config->Set("APT::Architecture", line.c_str() + 14);
479 else if (line.compare(0, 14, "Architectures:") == 0)
480 {
481 std::string const archs = line.c_str() + 15;
482 _config->Set("APT::Architectures", SubstVar(archs, " ", ","));
483 }
eb1000f6
DK
484 else if (line.compare(0, 7, "Solver:") == 0)
485 ; // purely informational line
40795fca
DK
486 else
487 _error->Warning("Unknown line in EDSP Request stanza: %s", line.c_str());
488
6d5bd614
DK
489 if (request == NULL)
490 continue;
491 size_t end = line.length();
492 do {
493 size_t begin = line.rfind(' ');
494 if (begin == std::string::npos)
495 {
40795fca 496 request->push_back(line.substr(0, end));
6d5bd614
DK
497 break;
498 }
499 else if (begin < end)
500 request->push_back(line.substr(begin + 1, end));
501 line.erase(begin);
502 end = line.find_last_not_of(' ');
503 } while (end != std::string::npos);
504 }
505 }
506 return false;
507}
508 /*}}}*/
509// EDSP::ApplyRequest - first stanza from the given file descriptor /*{{{*/
c3b85126 510bool EDSP::ApplyRequest(std::list<std::string> const &install,
29099cb6
DK
511 std::list<std::string> const &remove,
512 pkgDepCache &Cache)
6d5bd614
DK
513{
514 for (std::list<std::string>::const_iterator i = install.begin();
d4f626ff
DK
515 i != install.end(); ++i) {
516 pkgCache::PkgIterator P = Cache.FindPkg(*i);
517 if (P.end() == true)
518 _error->Warning("Package %s is not known, so can't be installed", i->c_str());
519 else
520 Cache.MarkInstall(P, false);
521 }
6d5bd614
DK
522
523 for (std::list<std::string>::const_iterator i = remove.begin();
d4f626ff
DK
524 i != remove.end(); ++i) {
525 pkgCache::PkgIterator P = Cache.FindPkg(*i);
526 if (P.end() == true)
527 _error->Warning("Package %s is not known, so can't be installed", i->c_str());
528 else
529 Cache.MarkDelete(P);
530 }
6d5bd614
DK
531 return true;
532}
533 /*}}}*/
c3b85126
DK
534// EDSP::WriteSolution - to the given file descriptor /*{{{*/
535bool EDSP::WriteSolution(pkgDepCache &Cache, FILE* output)
e3674d91 536{
6d5bd614 537 bool const Debug = _config->FindB("Debug::EDSP::WriteSolution", false);
e3674d91
DK
538 for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; ++Pkg)
539 {
540 if (Cache[Pkg].Delete() == true)
d4f626ff
DK
541 {
542 fprintf(output, "Remove: %d\n", Pkg.CurrentVer()->ID);
543 if (Debug == true)
544 fprintf(output, "Package: %s\nVersion: %s\n", Pkg.FullName().c_str(), Pkg.CurrentVer().VerStr());
545 }
e3674d91 546 else if (Cache[Pkg].NewInstall() == true || Cache[Pkg].Upgrade() == true)
d4f626ff 547 {
294a8020
DK
548 pkgCache::VerIterator const CandVer = Cache.GetCandidateVersion(Pkg);
549 fprintf(output, "Install: %d\n", CandVer->ID);
d4f626ff 550 if (Debug == true)
294a8020 551 fprintf(output, "Package: %s\nVersion: %s\n", Pkg.FullName().c_str(), CandVer.VerStr());
d4f626ff 552 }
76d4aab0
DK
553 else if (Cache[Pkg].Garbage == true)
554 {
555 fprintf(output, "Autoremove: %d\n", Pkg.CurrentVer()->ID);
556 if (Debug == true)
557 fprintf(output, "Package: %s\nVersion: %s\n", Pkg.FullName().c_str(), Pkg.CurrentVer().VerStr());
76d4aab0 558 }
e3674d91
DK
559 else
560 continue;
e3674d91
DK
561 fprintf(output, "\n");
562 }
563
6d38011b
DK
564 return true;
565}
566 /*}}}*/
e876223c
DK
567// EDSP::WriteProgess - pulse to the given file descriptor /*{{{*/
568bool EDSP::WriteProgress(unsigned short const percent, const char* const message, FILE* output) {
3d17b9ff
DK
569 fprintf(output, "Progress: %s\n", TimeRFC1123(time(NULL)).c_str());
570 fprintf(output, "Percentage: %d\n", percent);
571 fprintf(output, "Message: %s\n\n", message);
572 fflush(output);
e876223c
DK
573 return true;
574}
575 /*}}}*/
ebfeeaed
DK
576// EDSP::WriteError - format an error message to be send to file descriptor /*{{{*/
577bool EDSP::WriteError(char const * const uuid, std::string const &message, FILE* output) {
578 fprintf(output, "Error: %s\n", uuid);
579 fprintf(output, "Message: %s\n\n", SubstVar(SubstVar(message, "\n\n", "\n.\n"), "\n", "\n ").c_str());
580 return true;
581}
582 /*}}}*/
ac5fbff8 583// EDSP::ExecuteSolver - fork requested solver and setup ipc pipes {{{*/
5681b3fc 584pid_t EDSP::ExecuteSolver(const char* const solver, int * const solver_in, int * const solver_out, bool) {
741b7da9
DK
585 std::vector<std::string> const solverDirs = _config->FindVector("Dir::Bin::Solvers");
586 std::string file;
587 for (std::vector<std::string>::const_iterator dir = solverDirs.begin();
588 dir != solverDirs.end(); ++dir) {
589 file = flCombine(*dir, solver);
590 if (RealFileExists(file.c_str()) == true)
591 break;
592 file.clear();
593 }
ac5fbff8 594
741b7da9 595 if (file.empty() == true)
5681b3fc
DK
596 {
597 _error->Error("Can't call external solver '%s' as it is not in a configured directory!", solver);
598 return 0;
599 }
741b7da9
DK
600 int external[4] = {-1, -1, -1, -1};
601 if (pipe(external) != 0 || pipe(external + 2) != 0)
5681b3fc
DK
602 {
603 _error->Errno("Resolve", "Can't create needed IPC pipes for EDSP");
604 return 0;
605 }
741b7da9
DK
606 for (int i = 0; i < 4; ++i)
607 SetCloseExec(external[i], true);
ac5fbff8 608
741b7da9
DK
609 pid_t Solver = ExecFork();
610 if (Solver == 0) {
611 dup2(external[0], STDIN_FILENO);
612 dup2(external[3], STDOUT_FILENO);
613 const char* calling[2] = { file.c_str(), 0 };
614 execv(calling[0], (char**) calling);
615 std::cerr << "Failed to execute solver '" << solver << "'!" << std::endl;
616 _exit(100);
617 }
618 close(external[0]);
619 close(external[3]);
ac5fbff8 620
741b7da9 621 if (WaitFd(external[1], true, 5) == false)
5681b3fc
DK
622 {
623 _error->Errno("Resolve", "Timed out while Waiting on availability of solver stdin");
624 return 0;
625 }
ac5fbff8 626
741b7da9
DK
627 *solver_in = external[1];
628 *solver_out = external[2];
5681b3fc
DK
629 return Solver;
630}
631bool EDSP::ExecuteSolver(const char* const solver, int *solver_in, int *solver_out) {
632 if (ExecuteSolver(solver, solver_in, solver_out, true) == 0)
633 return false;
634 return true;
741b7da9
DK
635}
636 /*}}}*/
637// EDSP::ResolveExternal - resolve problems by asking external for help {{{*/
638bool EDSP::ResolveExternal(const char* const solver, pkgDepCache &Cache,
639 bool const upgrade, bool const distUpgrade,
b57c0e35 640 bool const autoRemove, OpProgress *Progress) {
741b7da9 641 int solver_in, solver_out;
5681b3fc
DK
642 pid_t const solver_pid = EDSP::ExecuteSolver(solver, &solver_in, &solver_out, true);
643 if (solver_pid == 0)
741b7da9
DK
644 return false;
645
646 FILE* output = fdopen(solver_in, "w");
647 if (output == NULL)
648 return _error->Errno("Resolve", "fdopen on solver stdin failed");
b57c0e35
DK
649
650 if (Progress != NULL)
651 Progress->OverallProgress(0, 100, 5, _("Execute external solver"));
652 EDSP::WriteRequest(Cache, output, upgrade, distUpgrade, autoRemove, Progress);
653 if (Progress != NULL)
654 Progress->OverallProgress(5, 100, 20, _("Execute external solver"));
655 EDSP::WriteScenario(Cache, output, Progress);
741b7da9
DK
656 fclose(output);
657
b57c0e35
DK
658 if (Progress != NULL)
659 Progress->OverallProgress(25, 100, 75, _("Execute external solver"));
660 if (EDSP::ReadResponse(solver_out, Cache, Progress) == false)
27c69dd0 661 return false;
741b7da9 662
5681b3fc 663 return ExecWait(solver_pid, solver);
ac5fbff8
DK
664}
665 /*}}}*/