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