]>
git.saurik.com Git - apt.git/blob - apt-pkg/edsp.cc
e54f0d1df0d659af0bbfba74c148b5943221c913
1 // -*- mode: cpp; mode: fold -*-
3 /* ######################################################################
4 Set of methods to help writing and reading everything needed for EDSP
5 ##################################################################### */
7 // Include Files /*{{{*/
10 #include <apt-pkg/error.h>
11 #include <apt-pkg/cacheset.h>
12 #include <apt-pkg/depcache.h>
13 #include <apt-pkg/pkgcache.h>
14 #include <apt-pkg/cacheiterators.h>
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>
35 // we could use pkgCache::DepType and ::Priority, but these would be localized stringsā¦
36 const char * const PrioMap
[] = {0, "important", "required", "standard",
38 const char * const DepMap
[] = {"", "Depends", "Pre-Depends", "Suggests",
39 "Recommends" , "Conflicts", "Replaces",
40 "Obsoletes", "Breaks", "Enhances"};
43 // WriteScenarioVersion /*{{{*/
44 static void WriteScenarioVersion(pkgDepCache
&Cache
, FILE* output
, pkgCache::PkgIterator
const &Pkg
,
45 pkgCache::VerIterator
const &Ver
)
47 fprintf(output
, "Package: %s\n", Pkg
.Name());
48 fprintf(output
, "Source: %s\n", Ver
.SourcePkgName());
49 fprintf(output
, "Architecture: %s\n", Ver
.Arch());
50 fprintf(output
, "Version: %s\n", Ver
.VerStr());
51 fprintf(output
, "Source-Version: %s\n", Ver
.SourceVerStr());
52 if (Pkg
.CurrentVer() == Ver
)
53 fprintf(output
, "Installed: yes\n");
54 if (Pkg
->SelectedState
== pkgCache::State::Hold
||
55 (Cache
[Pkg
].Keep() == true && Cache
[Pkg
].Protect() == true))
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());
62 if ((Ver
->MultiArch
& pkgCache::Version::Allowed
) == pkgCache::Version::Allowed
)
63 fprintf(output
, "Multi-Arch: allowed\n");
64 else if ((Ver
->MultiArch
& pkgCache::Version::Foreign
) == pkgCache::Version::Foreign
)
65 fprintf(output
, "Multi-Arch: foreign\n");
66 else if ((Ver
->MultiArch
& pkgCache::Version::Same
) == pkgCache::Version::Same
)
67 fprintf(output
, "Multi-Arch: same\n");
68 std::set
<string
> Releases
;
69 for (pkgCache::VerFileIterator I
= Ver
.FileList(); I
.end() == false; ++I
) {
70 pkgCache::PkgFileIterator File
= I
.File();
71 if (File
.Flagged(pkgCache::Flag::NotSource
) == false) {
72 string Release
= File
.RelStr();
74 Releases
.insert(Release
);
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());
82 fprintf(output
, "APT-Pin: %d\n", Cache
.GetPolicy().GetPriority(Ver
));
83 if (Cache
.GetCandidateVersion(Pkg
) == Ver
)
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");
89 // WriteScenarioDependency /*{{{*/
90 static void WriteScenarioDependency( FILE* output
, pkgCache::VerIterator
const &Ver
)
92 std::string dependencies
[pkgCache::Dep::Enhances
+ 1];
94 for (pkgCache::DepIterator Dep
= Ver
.DependsList(); Dep
.end() == false; ++Dep
)
96 if (Dep
.IsImplicit() == true)
99 dependencies
[Dep
->Type
].append(", ");
100 dependencies
[Dep
->Type
].append(Dep
.TargetPkg().Name());
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
)
105 dependencies
[Dep
->Type
].append(" | ");
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);
115 for (pkgCache::PrvIterator Prv
= Ver
.ProvidesList(); Prv
.end() == false; ++Prv
)
117 if (Prv
.IsMultiArchImplicit() == true)
119 provides
.append(", ").append(Prv
.Name());
120 if (Prv
->ProvideVersion
!= 0)
121 provides
.append(" (= ").append(Prv
.ProvideVersion()).append(")");
123 if (provides
.empty() == false)
124 fprintf(output
, "Provides: %s\n", provides
.c_str()+2);
127 // WriteScenarioLimitedDependency /*{{{*/
128 static void WriteScenarioLimitedDependency(FILE* output
,
129 pkgCache::VerIterator
const &Ver
,
130 APT::PackageSet
const &pkgset
)
132 std::string dependencies
[pkgCache::Dep::Enhances
+ 1];
133 bool orGroup
= false;
134 for (pkgCache::DepIterator Dep
= Ver
.DependsList(); Dep
.end() == false; ++Dep
)
136 if (Dep
.IsImplicit() == true)
138 if (orGroup
== false)
140 if (pkgset
.find(Dep
.TargetPkg()) == pkgset
.end())
142 dependencies
[Dep
->Type
].append(", ");
144 else if (pkgset
.find(Dep
.TargetPkg()) == pkgset
.end())
146 if ((Dep
->CompareOp
& pkgCache::Dep::Or
) == pkgCache::Dep::Or
)
148 dependencies
[Dep
->Type
].erase(dependencies
[Dep
->Type
].end()-3, dependencies
[Dep
->Type
].end());
152 dependencies
[Dep
->Type
].append(Dep
.TargetPkg().Name());
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
)
157 dependencies
[Dep
->Type
].append(" | ");
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);
167 for (pkgCache::PrvIterator Prv
= Ver
.ProvidesList(); Prv
.end() == false; ++Prv
)
169 if (Prv
.IsMultiArchImplicit() == true)
171 if (pkgset
.find(Prv
.ParentPkg()) == pkgset
.end())
173 provides
.append(", ").append(Prv
.Name());
175 if (provides
.empty() == false)
176 fprintf(output
, "Provides: %s\n", provides
.c_str()+2);
179 static bool SkipUnavailableVersions(pkgDepCache
&Cache
, pkgCache::PkgIterator
const &Pkg
, pkgCache::VerIterator
const &Ver
)/*{{{*/
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)
189 if (Cache
.GetCandidateVersion(Pkg
) == Ver
)
191 for (pkgCache::VerFileIterator I
= Ver
.FileList(); I
.end() == false; ++I
)
192 if (I
.File().Flagged(pkgCache::Flag::NotSource
) == false)
197 // EDSP::WriteScenario - to the given file descriptor /*{{{*/
198 bool EDSP::WriteScenario(pkgDepCache
&Cache
, FILE* output
, OpProgress
*Progress
)
200 if (Progress
!= NULL
)
201 Progress
->SubProgress(Cache
.Head().VersionCount
, _("Send scenario to solver"));
203 std::vector
<std::string
> archs
= APT::Configuration::getArchitectures();
204 for (pkgCache::PkgIterator Pkg
= Cache
.PkgBegin(); Pkg
.end() == false; ++Pkg
)
206 std::string
const arch
= Pkg
.Arch();
207 if (std::find(archs
.begin(), archs
.end(), arch
) == archs
.end())
209 for (pkgCache::VerIterator Ver
= Pkg
.VersionList(); Ver
.end() == false; ++Ver
, ++p
)
211 if (SkipUnavailableVersions(Cache
, Pkg
, Ver
))
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
);
223 // EDSP::WriteLimitedScenario - to the given file descriptor /*{{{*/
224 bool EDSP::WriteLimitedScenario(pkgDepCache
&Cache
, FILE* output
,
225 APT::PackageSet
const &pkgset
,
226 OpProgress
*Progress
)
228 if (Progress
!= NULL
)
229 Progress
->SubProgress(Cache
.Head().VersionCount
, _("Send scenario to solver"));
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
)
234 if (SkipUnavailableVersions(Cache
, Pkg
, Ver
))
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
);
242 if (Progress
!= NULL
)
247 // EDSP::WriteRequest - to the given file descriptor /*{{{*/
248 bool EDSP::WriteRequest(pkgDepCache
&Cache
, FILE* output
, bool const Upgrade
,
249 bool const DistUpgrade
, bool const AutoRemove
,
250 OpProgress
*Progress
)
252 if (Progress
!= NULL
)
253 Progress
->SubProgress(Cache
.Head().PackageCount
, _("Send request to solver"));
256 for (pkgCache::PkgIterator Pkg
= Cache
.PkgBegin(); Pkg
.end() == false; ++Pkg
, ++p
)
258 if (Progress
!= NULL
&& p
% 100 == 0)
259 Progress
->Progress(p
);
261 pkgDepCache::StateCache
&P
= Cache
[Pkg
];
262 if (P
.Delete() == true)
264 else if (P
.NewInstall() == true || P
.Upgrade() == true || P
.ReInstall() == true ||
265 (P
.Mode
== pkgDepCache::ModeKeep
&& (P
.iFlags
& pkgDepCache::Protected
) == pkgDepCache::Protected
))
269 req
->append(" ").append(Pkg
.FullName());
271 fprintf(output
, "Request: EDSP 0.5\n");
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");
281 if (del
.empty() == false)
282 fprintf(output
, "Remove: %s\n", del
.c_str()+1);
283 if (inst
.empty() == false)
284 fprintf(output
, "Install: %s\n", inst
.c_str()+1);
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");
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)
295 fprintf(output
, "Strict-Pinning: no\n");
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());
299 fprintf(output
, "\n");
303 // EDSP::ReadResponse - from the given file descriptor /*{{{*/
304 bool EDSP::ReadResponse(int const input
, pkgDepCache
&Cache
, OpProgress
*Progress
) {
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
];
311 for (pkgCache::PkgIterator P
= Cache
.PkgBegin(); P
.end() == false; ++P
) {
312 for (pkgCache::VerIterator V
= P
.VersionList(); V
.end() == false; ++V
)
313 VerIdx
[V
->ID
] = V
.Index();
314 Cache
[P
].Marked
= true;
315 Cache
[P
].Garbage
= false;
319 in
.OpenDescriptor(input
, FileFd::ReadOnly
);
320 pkgTagFile
response(&in
, 100);
321 pkgTagSection section
;
323 while (response
.Step(section
) == true) {
325 if (section
.Exists("Install") == true)
327 else if (section
.Exists("Remove") == true)
329 else if (section
.Exists("Progress") == true) {
330 if (Progress
!= NULL
) {
331 string msg
= section
.FindS("Message");
332 if (msg
.empty() == true)
333 msg
= _("Prepare for receiving solution");
334 Progress
->SubProgress(100, msg
, section
.FindI("Percentage", 0));
337 } else if (section
.Exists("Error") == true) {
338 std::string msg
= SubstVar(SubstVar(section
.FindS("Message"), "\n .\n", "\n\n"), "\n ", "\n");
339 if (msg
.empty() == true) {
340 msg
= _("External solver failed without a proper error message");
341 _error
->Error("%s", msg
.c_str());
343 _error
->Error("External solver failed with: %s", msg
.substr(0,msg
.find('\n')).c_str());
344 if (Progress
!= NULL
)
346 std::cerr
<< "The solver encountered an error of type: " << section
.FindS("Error") << std::endl
;
347 std::cerr
<< "The following information might help you to understand what is wrong:" << std::endl
;
348 std::cerr
<< msg
<< std::endl
<< std::endl
;
350 } else if (section
.Exists("Autoremove") == true)
355 size_t const id
= section
.FindULL(type
.c_str(), VersionCount
);
356 if (id
== VersionCount
) {
357 _error
->Warning("Unable to parse %s request with id value '%s'!", type
.c_str(), section
.FindS(type
.c_str()).c_str());
359 } else if (id
> Cache
.Head().VersionCount
) {
360 _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());
364 pkgCache::VerIterator
Ver(Cache
.GetCache(), Cache
.GetCache().VerP
+ VerIdx
[id
]);
365 Cache
.SetCandidateVersion(Ver
);
366 if (type
== "Install")
368 pkgCache::PkgIterator
const P
= Ver
.ParentPkg();
369 if (Cache
[P
].Mode
!= pkgDepCache::ModeInstall
)
370 Cache
.MarkInstall(P
, false, 0, false);
372 else if (type
== "Remove")
373 Cache
.MarkDelete(Ver
.ParentPkg(), false);
374 else if (type
== "Autoremove") {
375 Cache
[Ver
.ParentPkg()].Marked
= false;
376 Cache
[Ver
.ParentPkg()].Garbage
= true;
382 // ReadLine - first line from the given file descriptor /*{{{*/
383 // ---------------------------------------------------------------------
384 /* Little helper method to read a complete line into a string. Similar to
385 fgets but we need to use the low-level read() here as otherwise the
386 listparser will be confused later on as mixing of fgets and read isn't
387 a supported action according to the manpages and results are undefined */
388 static bool ReadLine(int const input
, std::string
&line
) {
393 while ((data
= read(input
, &one
, sizeof(one
))) != -1) {
400 if (line
.empty() == true && isblank(one
) != 0)
407 // StringToBool - convert yes/no to bool /*{{{*/
408 // ---------------------------------------------------------------------
409 /* we are not as lazy as we are in the global StringToBool as we really
410 only accept yes/no here - but we will ignore leading spaces */
411 static bool StringToBool(char const *answer
, bool const defValue
) {
412 for (; isspace(*answer
) != 0; ++answer
);
413 if (strncasecmp(answer
, "yes", 3) == 0)
415 else if (strncasecmp(answer
, "no", 2) == 0)
418 _error
->Warning("Value '%s' is not a boolean 'yes' or 'no'!", answer
);
422 // EDSP::ReadRequest - first stanza from the given file descriptor /*{{{*/
423 bool EDSP::ReadRequest(int const input
, std::list
<std::string
> &install
,
424 std::list
<std::string
> &remove
, bool &upgrade
,
425 bool &distUpgrade
, bool &autoRemove
)
433 while (ReadLine(input
, line
) == true)
435 // Skip empty lines before request
436 if (line
.empty() == true)
438 // The first Tag must be a request, so search for it
439 if (line
.compare(0, 8, "Request:") != 0)
442 while (ReadLine(input
, line
) == true)
444 // empty lines are the end of the request
445 if (line
.empty() == true)
448 std::list
<std::string
> *request
= NULL
;
449 if (line
.compare(0, 8, "Install:") == 0)
454 else if (line
.compare(0, 7, "Remove:") == 0)
459 else if (line
.compare(0, 8, "Upgrade:") == 0)
460 upgrade
= StringToBool(line
.c_str() + 9, false);
461 else if (line
.compare(0, 13, "Dist-Upgrade:") == 0)
462 distUpgrade
= StringToBool(line
.c_str() + 14, false);
463 else if (line
.compare(0, 11, "Autoremove:") == 0)
464 autoRemove
= StringToBool(line
.c_str() + 12, false);
465 else if (line
.compare(0, 13, "Architecture:") == 0)
466 _config
->Set("APT::Architecture", line
.c_str() + 14);
467 else if (line
.compare(0, 14, "Architectures:") == 0)
469 std::string
const archs
= line
.c_str() + 15;
470 _config
->Set("APT::Architectures", SubstVar(archs
, " ", ","));
472 else if (line
.compare(0, 7, "Solver:") == 0)
473 ; // purely informational line
475 _error
->Warning("Unknown line in EDSP Request stanza: %s", line
.c_str());
479 size_t end
= line
.length();
481 size_t begin
= line
.rfind(' ');
482 if (begin
== std::string::npos
)
484 request
->push_back(line
.substr(0, end
));
487 else if (begin
< end
)
488 request
->push_back(line
.substr(begin
+ 1, end
));
490 end
= line
.find_last_not_of(' ');
491 } while (end
!= std::string::npos
);
497 // EDSP::ApplyRequest - first stanza from the given file descriptor /*{{{*/
498 bool EDSP::ApplyRequest(std::list
<std::string
> const &install
,
499 std::list
<std::string
> const &remove
,
502 for (std::list
<std::string
>::const_iterator i
= install
.begin();
503 i
!= install
.end(); ++i
) {
504 pkgCache::PkgIterator P
= Cache
.FindPkg(*i
);
506 _error
->Warning("Package %s is not known, so can't be installed", i
->c_str());
508 Cache
.MarkInstall(P
, false);
511 for (std::list
<std::string
>::const_iterator i
= remove
.begin();
512 i
!= remove
.end(); ++i
) {
513 pkgCache::PkgIterator P
= Cache
.FindPkg(*i
);
515 _error
->Warning("Package %s is not known, so can't be installed", i
->c_str());
522 // EDSP::WriteSolution - to the given file descriptor /*{{{*/
523 bool EDSP::WriteSolution(pkgDepCache
&Cache
, FILE* output
)
525 bool const Debug
= _config
->FindB("Debug::EDSP::WriteSolution", false);
526 for (pkgCache::PkgIterator Pkg
= Cache
.PkgBegin(); Pkg
.end() == false; ++Pkg
)
528 if (Cache
[Pkg
].Delete() == true)
530 fprintf(output
, "Remove: %d\n", Pkg
.CurrentVer()->ID
);
532 fprintf(output
, "Package: %s\nVersion: %s\n", Pkg
.FullName().c_str(), Pkg
.CurrentVer().VerStr());
534 else if (Cache
[Pkg
].NewInstall() == true || Cache
[Pkg
].Upgrade() == true)
536 pkgCache::VerIterator
const CandVer
= Cache
.GetCandidateVersion(Pkg
);
537 fprintf(output
, "Install: %d\n", CandVer
->ID
);
539 fprintf(output
, "Package: %s\nVersion: %s\n", Pkg
.FullName().c_str(), CandVer
.VerStr());
541 else if (Cache
[Pkg
].Garbage
== true)
543 fprintf(output
, "Autoremove: %d\n", Pkg
.CurrentVer()->ID
);
545 fprintf(output
, "Package: %s\nVersion: %s\n", Pkg
.FullName().c_str(), Pkg
.CurrentVer().VerStr());
549 fprintf(output
, "\n");
555 // EDSP::WriteProgess - pulse to the given file descriptor /*{{{*/
556 bool EDSP::WriteProgress(unsigned short const percent
, const char* const message
, FILE* output
) {
557 fprintf(output
, "Progress: %s\n", TimeRFC1123(time(NULL
)).c_str());
558 fprintf(output
, "Percentage: %d\n", percent
);
559 fprintf(output
, "Message: %s\n\n", message
);
564 // EDSP::WriteError - format an error message to be send to file descriptor /*{{{*/
565 bool EDSP::WriteError(char const * const uuid
, std::string
const &message
, FILE* output
) {
566 fprintf(output
, "Error: %s\n", uuid
);
567 fprintf(output
, "Message: %s\n\n", SubstVar(SubstVar(message
, "\n\n", "\n.\n"), "\n", "\n ").c_str());
571 // EDSP::ExecuteSolver - fork requested solver and setup ipc pipes {{{*/
572 pid_t
EDSP::ExecuteSolver(const char* const solver
, int * const solver_in
, int * const solver_out
, bool) {
573 std::vector
<std::string
> const solverDirs
= _config
->FindVector("Dir::Bin::Solvers");
575 for (std::vector
<std::string
>::const_iterator dir
= solverDirs
.begin();
576 dir
!= solverDirs
.end(); ++dir
) {
577 file
= flCombine(*dir
, solver
);
578 if (RealFileExists(file
.c_str()) == true)
583 if (file
.empty() == true)
585 _error
->Error("Can't call external solver '%s' as it is not in a configured directory!", solver
);
588 int external
[4] = {-1, -1, -1, -1};
589 if (pipe(external
) != 0 || pipe(external
+ 2) != 0)
591 _error
->Errno("Resolve", "Can't create needed IPC pipes for EDSP");
594 for (int i
= 0; i
< 4; ++i
)
595 SetCloseExec(external
[i
], true);
597 pid_t Solver
= ExecFork();
599 dup2(external
[0], STDIN_FILENO
);
600 dup2(external
[3], STDOUT_FILENO
);
601 const char* calling
[2] = { file
.c_str(), 0 };
602 execv(calling
[0], (char**) calling
);
603 std::cerr
<< "Failed to execute solver '" << solver
<< "'!" << std::endl
;
609 if (WaitFd(external
[1], true, 5) == false)
611 _error
->Errno("Resolve", "Timed out while Waiting on availability of solver stdin");
615 *solver_in
= external
[1];
616 *solver_out
= external
[2];
619 bool EDSP::ExecuteSolver(const char* const solver
, int *solver_in
, int *solver_out
) {
620 if (ExecuteSolver(solver
, solver_in
, solver_out
, true) == 0)
625 // EDSP::ResolveExternal - resolve problems by asking external for help {{{*/
626 bool EDSP::ResolveExternal(const char* const solver
, pkgDepCache
&Cache
,
627 bool const upgrade
, bool const distUpgrade
,
628 bool const autoRemove
, OpProgress
*Progress
) {
629 int solver_in
, solver_out
;
630 pid_t
const solver_pid
= EDSP::ExecuteSolver(solver
, &solver_in
, &solver_out
, true);
634 FILE* output
= fdopen(solver_in
, "w");
636 return _error
->Errno("Resolve", "fdopen on solver stdin failed");
638 if (Progress
!= NULL
)
639 Progress
->OverallProgress(0, 100, 5, _("Execute external solver"));
640 EDSP::WriteRequest(Cache
, output
, upgrade
, distUpgrade
, autoRemove
, Progress
);
641 if (Progress
!= NULL
)
642 Progress
->OverallProgress(5, 100, 20, _("Execute external solver"));
643 EDSP::WriteScenario(Cache
, output
, Progress
);
646 if (Progress
!= NULL
)
647 Progress
->OverallProgress(25, 100, 75, _("Execute external solver"));
648 if (EDSP::ReadResponse(solver_out
, Cache
, Progress
) == false)
651 return ExecWait(solver_pid
, solver
);