]>
git.saurik.com Git - apt.git/blob - apt-pkg/edsp.cc
3c6a7e30f903131412a414ff6449096a99ec3cc4
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/edsp.h>
11 #include <apt-pkg/error.h>
12 #include <apt-pkg/cacheset.h>
13 #include <apt-pkg/configuration.h>
14 #include <apt-pkg/tagfile.h>
15 #include <apt-pkg/fileutl.h>
16 #include <apt-pkg/progress.h>
17 #include <apt-pkg/depcache.h>
18 #include <apt-pkg/pkgcache.h>
19 #include <apt-pkg/cacheiterators.h>
20 #include <apt-pkg/strutl.h>
21 #include <apt-pkg/pkgrecords.h>
41 // we could use pkgCache::DepType and ::Priority, but these would be localized stringsā¦
42 const char * const EDSP::PrioMap
[] = {0, "important", "required", "standard",
44 const char * const EDSP::DepMap
[] = {"", "Depends", "Pre-Depends", "Suggests",
45 "Recommends" , "Conflicts", "Replaces",
46 "Obsoletes", "Breaks", "Enhances"};
48 // EDSP::WriteScenario - to the given file descriptor /*{{{*/
49 bool EDSP::WriteScenario(pkgDepCache
&Cache
, FILE* output
, OpProgress
*Progress
)
52 Progress
->SubProgress(Cache
.Head().VersionCount
, _("Send scenario to solver"));
54 std::vector
<std::string
> archs
= APT::Configuration::getArchitectures();
55 for (pkgCache::PkgIterator Pkg
= Cache
.PkgBegin(); Pkg
.end() == false; ++Pkg
)
57 std::string
const arch
= Pkg
.Arch();
58 if (std::find(archs
.begin(), archs
.end(), arch
) == archs
.end())
60 for (pkgCache::VerIterator Ver
= Pkg
.VersionList(); Ver
.end() == false; ++Ver
, ++p
)
62 WriteScenarioVersion(Cache
, output
, Pkg
, Ver
);
63 WriteScenarioDependency(output
, Ver
);
64 fprintf(output
, "\n");
65 if (Progress
!= NULL
&& p
% 100 == 0)
66 Progress
->Progress(p
);
72 // EDSP::WriteLimitedScenario - to the given file descriptor /*{{{*/
73 bool EDSP::WriteLimitedScenario(pkgDepCache
&Cache
, FILE* output
,
74 APT::PackageSet
const &pkgset
,
78 Progress
->SubProgress(Cache
.Head().VersionCount
, _("Send scenario to solver"));
80 for (APT::PackageSet::const_iterator Pkg
= pkgset
.begin(); Pkg
!= pkgset
.end(); ++Pkg
, ++p
)
81 for (pkgCache::VerIterator Ver
= Pkg
.VersionList(); Ver
.end() == false; ++Ver
)
83 WriteScenarioVersion(Cache
, output
, Pkg
, Ver
);
84 WriteScenarioLimitedDependency(output
, Ver
, pkgset
);
85 fprintf(output
, "\n");
86 if (Progress
!= NULL
&& p
% 100 == 0)
87 Progress
->Progress(p
);
94 // EDSP::WriteScenarioVersion /*{{{*/
95 void EDSP::WriteScenarioVersion(pkgDepCache
&Cache
, FILE* output
, pkgCache::PkgIterator
const &Pkg
,
96 pkgCache::VerIterator
const &Ver
)
98 fprintf(output
, "Package: %s\n", Pkg
.Name());
99 #if APT_PKG_ABI >= 413
100 fprintf(output
, "Source: %s\n", Ver
.SourcePkgName());
102 pkgRecords
Recs(Cache
);
103 pkgRecords::Parser
&rec
= Recs
.Lookup(Ver
.FileList());
104 string srcpkg
= rec
.SourcePkg().empty() ? Pkg
.Name() : rec
.SourcePkg();
105 fprintf(output
, "Source: %s\n", srcpkg
.c_str());
107 fprintf(output
, "Architecture: %s\n", Ver
.Arch());
108 fprintf(output
, "Version: %s\n", Ver
.VerStr());
109 if (Pkg
.CurrentVer() == Ver
)
110 fprintf(output
, "Installed: yes\n");
111 if (Pkg
->SelectedState
== pkgCache::State::Hold
||
112 (Cache
[Pkg
].Keep() == true && Cache
[Pkg
].Protect() == true))
113 fprintf(output
, "Hold: yes\n");
114 fprintf(output
, "APT-ID: %d\n", Ver
->ID
);
115 fprintf(output
, "Priority: %s\n", PrioMap
[Ver
->Priority
]);
116 if ((Pkg
->Flags
& pkgCache::Flag::Essential
) == pkgCache::Flag::Essential
)
117 fprintf(output
, "Essential: yes\n");
118 fprintf(output
, "Section: %s\n", Ver
.Section());
119 if ((Ver
->MultiArch
& pkgCache::Version::Allowed
) == pkgCache::Version::Allowed
)
120 fprintf(output
, "Multi-Arch: allowed\n");
121 else if ((Ver
->MultiArch
& pkgCache::Version::Foreign
) == pkgCache::Version::Foreign
)
122 fprintf(output
, "Multi-Arch: foreign\n");
123 else if ((Ver
->MultiArch
& pkgCache::Version::Same
) == pkgCache::Version::Same
)
124 fprintf(output
, "Multi-Arch: same\n");
125 signed short Pin
= std::numeric_limits
<signed short>::min();
126 std::set
<string
> Releases
;
127 for (pkgCache::VerFileIterator I
= Ver
.FileList(); I
.end() == false; ++I
) {
128 pkgCache::PkgFileIterator File
= I
.File();
129 signed short const p
= Cache
.GetPolicy().GetPriority(File
);
132 if ((File
->Flags
& pkgCache::Flag::NotSource
) != pkgCache::Flag::NotSource
) {
133 string Release
= File
.RelStr();
134 if (!Release
.empty())
135 Releases
.insert(Release
);
138 if (!Releases
.empty()) {
139 fprintf(output
, "APT-Release:\n");
140 for (std::set
<string
>::iterator R
= Releases
.begin(); R
!= Releases
.end(); ++R
)
141 fprintf(output
, " %s\n", R
->c_str());
143 fprintf(output
, "APT-Pin: %d\n", Pin
);
144 if (Cache
.GetCandidateVer(Pkg
) == Ver
)
145 fprintf(output
, "APT-Candidate: yes\n");
146 if ((Cache
[Pkg
].Flags
& pkgCache::Flag::Auto
) == pkgCache::Flag::Auto
)
147 fprintf(output
, "APT-Automatic: yes\n");
150 // EDSP::WriteScenarioDependency /*{{{*/
151 void EDSP::WriteScenarioDependency( FILE* output
, pkgCache::VerIterator
const &Ver
)
153 std::string dependencies
[pkgCache::Dep::Enhances
+ 1];
154 bool orGroup
= false;
155 for (pkgCache::DepIterator Dep
= Ver
.DependsList(); Dep
.end() == false; ++Dep
)
157 if (Dep
.IsMultiArchImplicit() == true)
159 if (orGroup
== false)
160 dependencies
[Dep
->Type
].append(", ");
161 dependencies
[Dep
->Type
].append(Dep
.TargetPkg().Name());
162 if (Dep
->Version
!= 0)
163 dependencies
[Dep
->Type
].append(" (").append(pkgCache::CompTypeDeb(Dep
->CompareOp
)).append(" ").append(Dep
.TargetVer()).append(")");
164 if ((Dep
->CompareOp
& pkgCache::Dep::Or
) == pkgCache::Dep::Or
)
166 dependencies
[Dep
->Type
].append(" | ");
172 for (int i
= 1; i
< pkgCache::Dep::Enhances
+ 1; ++i
)
173 if (dependencies
[i
].empty() == false)
174 fprintf(output
, "%s: %s\n", DepMap
[i
], dependencies
[i
].c_str()+2);
176 for (pkgCache::PrvIterator Prv
= Ver
.ProvidesList(); Prv
.end() == false; ++Prv
)
178 if (Prv
.IsMultiArchImplicit() == true)
180 provides
.append(", ").append(Prv
.Name());
182 if (provides
.empty() == false)
183 fprintf(output
, "Provides: %s\n", provides
.c_str()+2);
186 // EDSP::WriteScenarioLimitedDependency /*{{{*/
187 void EDSP::WriteScenarioLimitedDependency(FILE* output
,
188 pkgCache::VerIterator
const &Ver
,
189 APT::PackageSet
const &pkgset
)
191 std::string dependencies
[pkgCache::Dep::Enhances
+ 1];
192 bool orGroup
= false;
193 for (pkgCache::DepIterator Dep
= Ver
.DependsList(); Dep
.end() == false; ++Dep
)
195 if (Dep
.IsMultiArchImplicit() == true)
197 if (orGroup
== false)
199 if (pkgset
.find(Dep
.TargetPkg()) == pkgset
.end())
201 dependencies
[Dep
->Type
].append(", ");
203 else if (pkgset
.find(Dep
.TargetPkg()) == pkgset
.end())
205 if ((Dep
->CompareOp
& pkgCache::Dep::Or
) == pkgCache::Dep::Or
)
207 dependencies
[Dep
->Type
].erase(dependencies
[Dep
->Type
].end()-3, dependencies
[Dep
->Type
].end());
211 dependencies
[Dep
->Type
].append(Dep
.TargetPkg().Name());
212 if (Dep
->Version
!= 0)
213 dependencies
[Dep
->Type
].append(" (").append(pkgCache::CompTypeDeb(Dep
->CompareOp
)).append(" ").append(Dep
.TargetVer()).append(")");
214 if ((Dep
->CompareOp
& pkgCache::Dep::Or
) == pkgCache::Dep::Or
)
216 dependencies
[Dep
->Type
].append(" | ");
222 for (int i
= 1; i
< pkgCache::Dep::Enhances
+ 1; ++i
)
223 if (dependencies
[i
].empty() == false)
224 fprintf(output
, "%s: %s\n", DepMap
[i
], dependencies
[i
].c_str()+2);
226 for (pkgCache::PrvIterator Prv
= Ver
.ProvidesList(); Prv
.end() == false; ++Prv
)
228 if (Prv
.IsMultiArchImplicit() == true)
230 if (pkgset
.find(Prv
.ParentPkg()) == pkgset
.end())
232 provides
.append(", ").append(Prv
.Name());
234 if (provides
.empty() == false)
235 fprintf(output
, "Provides: %s\n", provides
.c_str()+2);
238 // EDSP::WriteRequest - to the given file descriptor /*{{{*/
239 bool EDSP::WriteRequest(pkgDepCache
&Cache
, FILE* output
, bool const Upgrade
,
240 bool const DistUpgrade
, bool const AutoRemove
,
241 OpProgress
*Progress
)
243 if (Progress
!= NULL
)
244 Progress
->SubProgress(Cache
.Head().PackageCount
, _("Send request to solver"));
247 for (pkgCache::PkgIterator Pkg
= Cache
.PkgBegin(); Pkg
.end() == false; ++Pkg
, ++p
)
249 if (Progress
!= NULL
&& p
% 100 == 0)
250 Progress
->Progress(p
);
252 pkgDepCache::StateCache
&P
= Cache
[Pkg
];
253 if (P
.Delete() == true)
255 else if (P
.NewInstall() == true || P
.Upgrade() == true || P
.ReInstall() == true ||
256 (P
.Mode
== pkgDepCache::ModeKeep
&& (P
.iFlags
& pkgDepCache::Protected
) == pkgDepCache::Protected
))
260 req
->append(" ").append(Pkg
.FullName());
262 fprintf(output
, "Request: EDSP 0.5\n");
264 const char *arch
= _config
->Find("APT::Architecture").c_str();
265 std::vector
<string
> archs
= APT::Configuration::getArchitectures();
266 fprintf(output
, "Architecture: %s\n", arch
);
267 fprintf(output
, "Architectures:");
268 for (std::vector
<string
>::const_iterator a
= archs
.begin(); a
!= archs
.end(); ++a
)
269 fprintf(output
, " %s", a
->c_str());
270 fprintf(output
, "\n");
272 if (del
.empty() == false)
273 fprintf(output
, "Remove: %s\n", del
.c_str()+1);
274 if (inst
.empty() == false)
275 fprintf(output
, "Install: %s\n", inst
.c_str()+1);
277 fprintf(output
, "Upgrade: yes\n");
278 if (DistUpgrade
== true)
279 fprintf(output
, "Dist-Upgrade: yes\n");
280 if (AutoRemove
== true)
281 fprintf(output
, "Autoremove: yes\n");
282 if (_config
->FindB("APT::Solver::Strict-Pinning", true) == false)
283 fprintf(output
, "Strict-Pinning: no\n");
284 string
solverpref("APT::Solver::");
285 solverpref
.append(_config
->Find("APT::Solver", "internal")).append("::Preferences");
286 if (_config
->Exists(solverpref
) == true)
287 fprintf(output
, "Preferences: %s\n", _config
->Find(solverpref
,"").c_str());
288 fprintf(output
, "\n");
293 // EDSP::ReadResponse - from the given file descriptor /*{{{*/
294 bool EDSP::ReadResponse(int const input
, pkgDepCache
&Cache
, OpProgress
*Progress
) {
295 /* We build an map id to mmap offset here
296 In theory we could use the offset as ID, but then VersionCount
297 couldn't be used to create other versionmappings anymore and it
298 would be too easy for a (buggy) solver to segfault APTā¦ */
299 unsigned long long const VersionCount
= Cache
.Head().VersionCount
;
300 unsigned long VerIdx
[VersionCount
];
301 for (pkgCache::PkgIterator P
= Cache
.PkgBegin(); P
.end() == false; ++P
) {
302 for (pkgCache::VerIterator V
= P
.VersionList(); V
.end() == false; ++V
)
303 VerIdx
[V
->ID
] = V
.Index();
304 Cache
[P
].Marked
= true;
305 Cache
[P
].Garbage
= false;
309 in
.OpenDescriptor(input
, FileFd::ReadOnly
);
310 pkgTagFile
response(&in
, 100);
311 pkgTagSection section
;
313 while (response
.Step(section
) == true) {
315 if (section
.Exists("Install") == true)
317 else if (section
.Exists("Remove") == true)
319 else if (section
.Exists("Progress") == true) {
320 if (Progress
!= NULL
) {
321 string msg
= section
.FindS("Message");
322 if (msg
.empty() == true)
323 msg
= _("Prepare for receiving solution");
324 Progress
->SubProgress(100, msg
, section
.FindI("Percentage", 0));
327 } else if (section
.Exists("Error") == true) {
328 std::string msg
= SubstVar(SubstVar(section
.FindS("Message"), "\n .\n", "\n\n"), "\n ", "\n");
329 if (msg
.empty() == true) {
330 msg
= _("External solver failed without a proper error message");
331 _error
->Error("%s", msg
.c_str());
333 _error
->Error("External solver failed with: %s", msg
.substr(0,msg
.find('\n')).c_str());
334 if (Progress
!= NULL
)
336 std::cerr
<< "The solver encountered an error of type: " << section
.FindS("Error") << std::endl
;
337 std::cerr
<< "The following information might help you to understand what is wrong:" << std::endl
;
338 std::cerr
<< msg
<< std::endl
<< std::endl
;
340 } else if (section
.Exists("Autoremove") == true)
345 size_t const id
= section
.FindULL(type
.c_str(), VersionCount
);
346 if (id
== VersionCount
) {
347 _error
->Warning("Unable to parse %s request with id value '%s'!", type
.c_str(), section
.FindS(type
.c_str()).c_str());
349 } else if (id
> Cache
.Head().VersionCount
) {
350 _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());
354 pkgCache::VerIterator
Ver(Cache
.GetCache(), Cache
.GetCache().VerP
+ VerIdx
[id
]);
355 Cache
.SetCandidateVersion(Ver
);
356 if (type
== "Install")
357 Cache
.MarkInstall(Ver
.ParentPkg(), false, 0, false);
358 else if (type
== "Remove")
359 Cache
.MarkDelete(Ver
.ParentPkg(), false);
360 else if (type
== "Autoremove") {
361 Cache
[Ver
.ParentPkg()].Marked
= false;
362 Cache
[Ver
.ParentPkg()].Garbage
= true;
368 // EDSP::ReadLine - first line from the given file descriptor /*{{{*/
369 // ---------------------------------------------------------------------
370 /* Little helper method to read a complete line into a string. Similar to
371 fgets but we need to use the low-level read() here as otherwise the
372 listparser will be confused later on as mixing of fgets and read isn't
373 a supported action according to the manpages and results are undefined */
374 bool EDSP::ReadLine(int const input
, std::string
&line
) {
379 while ((data
= read(input
, &one
, sizeof(one
))) != -1) {
386 if (line
.empty() == true && isblank(one
) != 0)
393 // EDSP::StringToBool - convert yes/no to bool /*{{{*/
394 // ---------------------------------------------------------------------
395 /* we are not as lazy as we are in the global StringToBool as we really
396 only accept yes/no here - but we will ignore leading spaces */
397 bool EDSP::StringToBool(char const *answer
, bool const defValue
) {
398 for (; isspace(*answer
) != 0; ++answer
);
399 if (strncasecmp(answer
, "yes", 3) == 0)
401 else if (strncasecmp(answer
, "no", 2) == 0)
404 _error
->Warning("Value '%s' is not a boolean 'yes' or 'no'!", answer
);
408 // EDSP::ReadRequest - first stanza from the given file descriptor /*{{{*/
409 bool EDSP::ReadRequest(int const input
, std::list
<std::string
> &install
,
410 std::list
<std::string
> &remove
, bool &upgrade
,
411 bool &distUpgrade
, bool &autoRemove
)
419 while (ReadLine(input
, line
) == true)
421 // Skip empty lines before request
422 if (line
.empty() == true)
424 // The first Tag must be a request, so search for it
425 if (line
.compare(0, 8, "Request:") != 0)
428 while (ReadLine(input
, line
) == true)
430 // empty lines are the end of the request
431 if (line
.empty() == true)
434 std::list
<std::string
> *request
= NULL
;
435 if (line
.compare(0, 8, "Install:") == 0)
440 else if (line
.compare(0, 7, "Remove:") == 0)
445 else if (line
.compare(0, 8, "Upgrade:") == 0)
446 upgrade
= EDSP::StringToBool(line
.c_str() + 9, false);
447 else if (line
.compare(0, 13, "Dist-Upgrade:") == 0)
448 distUpgrade
= EDSP::StringToBool(line
.c_str() + 14, false);
449 else if (line
.compare(0, 11, "Autoremove:") == 0)
450 autoRemove
= EDSP::StringToBool(line
.c_str() + 12, false);
451 else if (line
.compare(0, 13, "Architecture:") == 0)
452 _config
->Set("APT::Architecture", line
.c_str() + 14);
453 else if (line
.compare(0, 14, "Architectures:") == 0)
455 std::string
const archs
= line
.c_str() + 15;
456 _config
->Set("APT::Architectures", SubstVar(archs
, " ", ","));
459 _error
->Warning("Unknown line in EDSP Request stanza: %s", line
.c_str());
463 size_t end
= line
.length();
465 size_t begin
= line
.rfind(' ');
466 if (begin
== std::string::npos
)
468 request
->push_back(line
.substr(0, end
));
471 else if (begin
< end
)
472 request
->push_back(line
.substr(begin
+ 1, end
));
474 end
= line
.find_last_not_of(' ');
475 } while (end
!= std::string::npos
);
481 // EDSP::ApplyRequest - first stanza from the given file descriptor /*{{{*/
482 bool EDSP::ApplyRequest(std::list
<std::string
> const &install
,
483 std::list
<std::string
> const &remove
,
486 for (std::list
<std::string
>::const_iterator i
= install
.begin();
487 i
!= install
.end(); ++i
) {
488 pkgCache::PkgIterator P
= Cache
.FindPkg(*i
);
490 _error
->Warning("Package %s is not known, so can't be installed", i
->c_str());
492 Cache
.MarkInstall(P
, false);
495 for (std::list
<std::string
>::const_iterator i
= remove
.begin();
496 i
!= remove
.end(); ++i
) {
497 pkgCache::PkgIterator P
= Cache
.FindPkg(*i
);
499 _error
->Warning("Package %s is not known, so can't be installed", i
->c_str());
506 // EDSP::WriteSolution - to the given file descriptor /*{{{*/
507 bool EDSP::WriteSolution(pkgDepCache
&Cache
, FILE* output
)
509 bool const Debug
= _config
->FindB("Debug::EDSP::WriteSolution", false);
510 for (pkgCache::PkgIterator Pkg
= Cache
.PkgBegin(); Pkg
.end() == false; ++Pkg
)
512 if (Cache
[Pkg
].Delete() == true)
514 fprintf(output
, "Remove: %d\n", Pkg
.CurrentVer()->ID
);
516 fprintf(output
, "Package: %s\nVersion: %s\n", Pkg
.FullName().c_str(), Pkg
.CurrentVer().VerStr());
518 else if (Cache
[Pkg
].NewInstall() == true || Cache
[Pkg
].Upgrade() == true)
520 fprintf(output
, "Install: %d\n", Cache
.GetCandidateVer(Pkg
)->ID
);
522 fprintf(output
, "Package: %s\nVersion: %s\n", Pkg
.FullName().c_str(), Cache
.GetCandidateVer(Pkg
).VerStr());
524 else if (Cache
[Pkg
].Garbage
== true)
526 fprintf(output
, "Autoremove: %d\n", Pkg
.CurrentVer()->ID
);
528 fprintf(output
, "Package: %s\nVersion: %s\n", Pkg
.FullName().c_str(), Pkg
.CurrentVer().VerStr());
532 fprintf(output
, "\n");
538 // EDSP::WriteProgess - pulse to the given file descriptor /*{{{*/
539 bool EDSP::WriteProgress(unsigned short const percent
, const char* const message
, FILE* output
) {
540 fprintf(output
, "Progress: %s\n", TimeRFC1123(time(NULL
)).c_str());
541 fprintf(output
, "Percentage: %d\n", percent
);
542 fprintf(output
, "Message: %s\n\n", message
);
547 // EDSP::WriteError - format an error message to be send to file descriptor /*{{{*/
548 bool EDSP::WriteError(char const * const uuid
, std::string
const &message
, FILE* output
) {
549 fprintf(output
, "Error: %s\n", uuid
);
550 fprintf(output
, "Message: %s\n\n", SubstVar(SubstVar(message
, "\n\n", "\n.\n"), "\n", "\n ").c_str());
554 // EDSP::ExecuteSolver - fork requested solver and setup ipc pipes {{{*/
555 pid_t
EDSP::ExecuteSolver(const char* const solver
, int * const solver_in
, int * const solver_out
, bool) {
556 std::vector
<std::string
> const solverDirs
= _config
->FindVector("Dir::Bin::Solvers");
558 for (std::vector
<std::string
>::const_iterator dir
= solverDirs
.begin();
559 dir
!= solverDirs
.end(); ++dir
) {
560 file
= flCombine(*dir
, solver
);
561 if (RealFileExists(file
.c_str()) == true)
566 if (file
.empty() == true)
568 _error
->Error("Can't call external solver '%s' as it is not in a configured directory!", solver
);
571 int external
[4] = {-1, -1, -1, -1};
572 if (pipe(external
) != 0 || pipe(external
+ 2) != 0)
574 _error
->Errno("Resolve", "Can't create needed IPC pipes for EDSP");
577 for (int i
= 0; i
< 4; ++i
)
578 SetCloseExec(external
[i
], true);
580 pid_t Solver
= ExecFork();
582 dup2(external
[0], STDIN_FILENO
);
583 dup2(external
[3], STDOUT_FILENO
);
584 const char* calling
[2] = { file
.c_str(), 0 };
585 execv(calling
[0], (char**) calling
);
586 std::cerr
<< "Failed to execute solver '" << solver
<< "'!" << std::endl
;
592 if (WaitFd(external
[1], true, 5) == false)
594 _error
->Errno("Resolve", "Timed out while Waiting on availability of solver stdin");
598 *solver_in
= external
[1];
599 *solver_out
= external
[2];
602 bool EDSP::ExecuteSolver(const char* const solver
, int *solver_in
, int *solver_out
) {
603 if (ExecuteSolver(solver
, solver_in
, solver_out
, true) == 0)
608 // EDSP::ResolveExternal - resolve problems by asking external for help {{{*/
609 bool EDSP::ResolveExternal(const char* const solver
, pkgDepCache
&Cache
,
610 bool const upgrade
, bool const distUpgrade
,
611 bool const autoRemove
, OpProgress
*Progress
) {
612 int solver_in
, solver_out
;
613 pid_t
const solver_pid
= EDSP::ExecuteSolver(solver
, &solver_in
, &solver_out
, true);
617 FILE* output
= fdopen(solver_in
, "w");
619 return _error
->Errno("Resolve", "fdopen on solver stdin failed");
621 if (Progress
!= NULL
)
622 Progress
->OverallProgress(0, 100, 5, _("Execute external solver"));
623 EDSP::WriteRequest(Cache
, output
, upgrade
, distUpgrade
, autoRemove
, Progress
);
624 if (Progress
!= NULL
)
625 Progress
->OverallProgress(5, 100, 20, _("Execute external solver"));
626 EDSP::WriteScenario(Cache
, output
, Progress
);
629 if (Progress
!= NULL
)
630 Progress
->OverallProgress(25, 100, 75, _("Execute external solver"));
631 if (EDSP::ReadResponse(solver_out
, Cache
, Progress
) == false)
634 return ExecWait(solver_pid
, solver
);