]>
git.saurik.com Git - apt.git/blob - apt-pkg/edsp.cc
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 PrioMap
[] = {0, "important", "required", "standard",
44 const char * const DepMap
[] = {"", "Depends", "Pre-Depends", "Suggests",
45 "Recommends" , "Conflicts", "Replaces",
46 "Obsoletes", "Breaks", "Enhances"};
49 // WriteScenarioVersion /*{{{*/
50 static void WriteScenarioVersion(pkgDepCache
&Cache
, FILE* output
, pkgCache::PkgIterator
const &Pkg
,
51 pkgCache::VerIterator
const &Ver
)
53 fprintf(output
, "Package: %s\n", Pkg
.Name());
54 #if APT_PKG_ABI >= 413
55 fprintf(output
, "Source: %s\n", Ver
.SourcePkgName());
57 pkgRecords
Recs(Cache
);
58 pkgRecords::Parser
&rec
= Recs
.Lookup(Ver
.FileList());
59 string srcpkg
= rec
.SourcePkg().empty() ? Pkg
.Name() : rec
.SourcePkg();
60 fprintf(output
, "Source: %s\n", srcpkg
.c_str());
62 fprintf(output
, "Architecture: %s\n", Ver
.Arch());
63 fprintf(output
, "Version: %s\n", Ver
.VerStr());
64 if (Pkg
.CurrentVer() == Ver
)
65 fprintf(output
, "Installed: yes\n");
66 if (Pkg
->SelectedState
== pkgCache::State::Hold
||
67 (Cache
[Pkg
].Keep() == true && Cache
[Pkg
].Protect() == true))
68 fprintf(output
, "Hold: yes\n");
69 fprintf(output
, "APT-ID: %d\n", Ver
->ID
);
70 fprintf(output
, "Priority: %s\n", PrioMap
[Ver
->Priority
]);
71 if ((Pkg
->Flags
& pkgCache::Flag::Essential
) == pkgCache::Flag::Essential
)
72 fprintf(output
, "Essential: yes\n");
73 fprintf(output
, "Section: %s\n", Ver
.Section());
74 if ((Ver
->MultiArch
& pkgCache::Version::Allowed
) == pkgCache::Version::Allowed
)
75 fprintf(output
, "Multi-Arch: allowed\n");
76 else if ((Ver
->MultiArch
& pkgCache::Version::Foreign
) == pkgCache::Version::Foreign
)
77 fprintf(output
, "Multi-Arch: foreign\n");
78 else if ((Ver
->MultiArch
& pkgCache::Version::Same
) == pkgCache::Version::Same
)
79 fprintf(output
, "Multi-Arch: same\n");
80 signed short Pin
= std::numeric_limits
<signed short>::min();
81 std::set
<string
> Releases
;
82 for (pkgCache::VerFileIterator I
= Ver
.FileList(); I
.end() == false; ++I
) {
83 pkgCache::PkgFileIterator File
= I
.File();
84 signed short const p
= Cache
.GetPolicy().GetPriority(File
);
87 if (File
.Flagged(pkgCache::Flag::NotSource
) == false) {
88 string Release
= File
.RelStr();
90 Releases
.insert(Release
);
93 if (!Releases
.empty()) {
94 fprintf(output
, "APT-Release:\n");
95 for (std::set
<string
>::iterator R
= Releases
.begin(); R
!= Releases
.end(); ++R
)
96 fprintf(output
, " %s\n", R
->c_str());
98 fprintf(output
, "APT-Pin: %d\n", Pin
);
99 if (Cache
.GetCandidateVer(Pkg
) == Ver
)
100 fprintf(output
, "APT-Candidate: yes\n");
101 if ((Cache
[Pkg
].Flags
& pkgCache::Flag::Auto
) == pkgCache::Flag::Auto
)
102 fprintf(output
, "APT-Automatic: yes\n");
105 // WriteScenarioDependency /*{{{*/
106 static void WriteScenarioDependency( FILE* output
, pkgCache::VerIterator
const &Ver
)
108 std::string dependencies
[pkgCache::Dep::Enhances
+ 1];
109 bool orGroup
= false;
110 for (pkgCache::DepIterator Dep
= Ver
.DependsList(); Dep
.end() == false; ++Dep
)
112 if (Dep
.IsMultiArchImplicit() == true)
114 if (orGroup
== false)
115 dependencies
[Dep
->Type
].append(", ");
116 dependencies
[Dep
->Type
].append(Dep
.TargetPkg().Name());
117 if (Dep
->Version
!= 0)
118 dependencies
[Dep
->Type
].append(" (").append(pkgCache::CompTypeDeb(Dep
->CompareOp
)).append(" ").append(Dep
.TargetVer()).append(")");
119 if ((Dep
->CompareOp
& pkgCache::Dep::Or
) == pkgCache::Dep::Or
)
121 dependencies
[Dep
->Type
].append(" | ");
127 for (int i
= 1; i
< pkgCache::Dep::Enhances
+ 1; ++i
)
128 if (dependencies
[i
].empty() == false)
129 fprintf(output
, "%s: %s\n", DepMap
[i
], dependencies
[i
].c_str()+2);
131 for (pkgCache::PrvIterator Prv
= Ver
.ProvidesList(); Prv
.end() == false; ++Prv
)
133 if (Prv
.IsMultiArchImplicit() == true)
135 provides
.append(", ").append(Prv
.Name());
137 if (provides
.empty() == false)
138 fprintf(output
, "Provides: %s\n", provides
.c_str()+2);
141 // WriteScenarioLimitedDependency /*{{{*/
142 static void WriteScenarioLimitedDependency(FILE* output
,
143 pkgCache::VerIterator
const &Ver
,
144 APT::PackageSet
const &pkgset
)
146 std::string dependencies
[pkgCache::Dep::Enhances
+ 1];
147 bool orGroup
= false;
148 for (pkgCache::DepIterator Dep
= Ver
.DependsList(); Dep
.end() == false; ++Dep
)
150 if (Dep
.IsMultiArchImplicit() == true)
152 if (orGroup
== false)
154 if (pkgset
.find(Dep
.TargetPkg()) == pkgset
.end())
156 dependencies
[Dep
->Type
].append(", ");
158 else if (pkgset
.find(Dep
.TargetPkg()) == pkgset
.end())
160 if ((Dep
->CompareOp
& pkgCache::Dep::Or
) == pkgCache::Dep::Or
)
162 dependencies
[Dep
->Type
].erase(dependencies
[Dep
->Type
].end()-3, dependencies
[Dep
->Type
].end());
166 dependencies
[Dep
->Type
].append(Dep
.TargetPkg().Name());
167 if (Dep
->Version
!= 0)
168 dependencies
[Dep
->Type
].append(" (").append(pkgCache::CompTypeDeb(Dep
->CompareOp
)).append(" ").append(Dep
.TargetVer()).append(")");
169 if ((Dep
->CompareOp
& pkgCache::Dep::Or
) == pkgCache::Dep::Or
)
171 dependencies
[Dep
->Type
].append(" | ");
177 for (int i
= 1; i
< pkgCache::Dep::Enhances
+ 1; ++i
)
178 if (dependencies
[i
].empty() == false)
179 fprintf(output
, "%s: %s\n", DepMap
[i
], dependencies
[i
].c_str()+2);
181 for (pkgCache::PrvIterator Prv
= Ver
.ProvidesList(); Prv
.end() == false; ++Prv
)
183 if (Prv
.IsMultiArchImplicit() == true)
185 if (pkgset
.find(Prv
.ParentPkg()) == pkgset
.end())
187 provides
.append(", ").append(Prv
.Name());
189 if (provides
.empty() == false)
190 fprintf(output
, "Provides: %s\n", provides
.c_str()+2);
193 // EDSP::WriteScenario - to the given file descriptor /*{{{*/
194 bool EDSP::WriteScenario(pkgDepCache
&Cache
, FILE* output
, OpProgress
*Progress
)
196 if (Progress
!= NULL
)
197 Progress
->SubProgress(Cache
.Head().VersionCount
, _("Send scenario to solver"));
199 std::vector
<std::string
> archs
= APT::Configuration::getArchitectures();
200 for (pkgCache::PkgIterator Pkg
= Cache
.PkgBegin(); Pkg
.end() == false; ++Pkg
)
202 std::string
const arch
= Pkg
.Arch();
203 if (std::find(archs
.begin(), archs
.end(), arch
) == archs
.end())
205 for (pkgCache::VerIterator Ver
= Pkg
.VersionList(); Ver
.end() == false; ++Ver
, ++p
)
207 WriteScenarioVersion(Cache
, output
, Pkg
, Ver
);
208 WriteScenarioDependency(output
, Ver
);
209 fprintf(output
, "\n");
210 if (Progress
!= NULL
&& p
% 100 == 0)
211 Progress
->Progress(p
);
217 // EDSP::WriteLimitedScenario - to the given file descriptor /*{{{*/
218 bool EDSP::WriteLimitedScenario(pkgDepCache
&Cache
, FILE* output
,
219 APT::PackageSet
const &pkgset
,
220 OpProgress
*Progress
)
222 if (Progress
!= NULL
)
223 Progress
->SubProgress(Cache
.Head().VersionCount
, _("Send scenario to solver"));
225 for (APT::PackageSet::const_iterator Pkg
= pkgset
.begin(); Pkg
!= pkgset
.end(); ++Pkg
, ++p
)
226 for (pkgCache::VerIterator Ver
= Pkg
.VersionList(); Ver
.end() == false; ++Ver
)
228 WriteScenarioVersion(Cache
, output
, Pkg
, Ver
);
229 WriteScenarioLimitedDependency(output
, Ver
, pkgset
);
230 fprintf(output
, "\n");
231 if (Progress
!= NULL
&& p
% 100 == 0)
232 Progress
->Progress(p
);
234 if (Progress
!= NULL
)
239 // EDSP::WriteRequest - to the given file descriptor /*{{{*/
240 bool EDSP::WriteRequest(pkgDepCache
&Cache
, FILE* output
, bool const Upgrade
,
241 bool const DistUpgrade
, bool const AutoRemove
,
242 OpProgress
*Progress
)
244 if (Progress
!= NULL
)
245 Progress
->SubProgress(Cache
.Head().PackageCount
, _("Send request to solver"));
248 for (pkgCache::PkgIterator Pkg
= Cache
.PkgBegin(); Pkg
.end() == false; ++Pkg
, ++p
)
250 if (Progress
!= NULL
&& p
% 100 == 0)
251 Progress
->Progress(p
);
253 pkgDepCache::StateCache
&P
= Cache
[Pkg
];
254 if (P
.Delete() == true)
256 else if (P
.NewInstall() == true || P
.Upgrade() == true || P
.ReInstall() == true ||
257 (P
.Mode
== pkgDepCache::ModeKeep
&& (P
.iFlags
& pkgDepCache::Protected
) == pkgDepCache::Protected
))
261 req
->append(" ").append(Pkg
.FullName());
263 fprintf(output
, "Request: EDSP 0.5\n");
265 const char *arch
= _config
->Find("APT::Architecture").c_str();
266 std::vector
<string
> archs
= APT::Configuration::getArchitectures();
267 fprintf(output
, "Architecture: %s\n", arch
);
268 fprintf(output
, "Architectures:");
269 for (std::vector
<string
>::const_iterator a
= archs
.begin(); a
!= archs
.end(); ++a
)
270 fprintf(output
, " %s", a
->c_str());
271 fprintf(output
, "\n");
273 if (del
.empty() == false)
274 fprintf(output
, "Remove: %s\n", del
.c_str()+1);
275 if (inst
.empty() == false)
276 fprintf(output
, "Install: %s\n", inst
.c_str()+1);
278 fprintf(output
, "Upgrade: yes\n");
279 if (DistUpgrade
== true)
280 fprintf(output
, "Dist-Upgrade: yes\n");
281 if (AutoRemove
== true)
282 fprintf(output
, "Autoremove: yes\n");
283 if (_config
->FindB("APT::Solver::Strict-Pinning", true) == false)
284 fprintf(output
, "Strict-Pinning: no\n");
285 string
solverpref("APT::Solver::");
286 solverpref
.append(_config
->Find("APT::Solver", "internal")).append("::Preferences");
287 if (_config
->Exists(solverpref
) == true)
288 fprintf(output
, "Preferences: %s\n", _config
->Find(solverpref
,"").c_str());
289 fprintf(output
, "\n");
294 // EDSP::ReadResponse - from the given file descriptor /*{{{*/
295 bool EDSP::ReadResponse(int const input
, pkgDepCache
&Cache
, OpProgress
*Progress
) {
296 /* We build an map id to mmap offset here
297 In theory we could use the offset as ID, but then VersionCount
298 couldn't be used to create other versionmappings anymore and it
299 would be too easy for a (buggy) solver to segfault APTā¦ */
300 unsigned long long const VersionCount
= Cache
.Head().VersionCount
;
301 unsigned long VerIdx
[VersionCount
];
302 for (pkgCache::PkgIterator P
= Cache
.PkgBegin(); P
.end() == false; ++P
) {
303 for (pkgCache::VerIterator V
= P
.VersionList(); V
.end() == false; ++V
)
304 VerIdx
[V
->ID
] = V
.Index();
305 Cache
[P
].Marked
= true;
306 Cache
[P
].Garbage
= false;
310 in
.OpenDescriptor(input
, FileFd::ReadOnly
);
311 pkgTagFile
response(&in
, 100);
312 pkgTagSection section
;
314 while (response
.Step(section
) == true) {
316 if (section
.Exists("Install") == true)
318 else if (section
.Exists("Remove") == true)
320 else if (section
.Exists("Progress") == true) {
321 if (Progress
!= NULL
) {
322 string msg
= section
.FindS("Message");
323 if (msg
.empty() == true)
324 msg
= _("Prepare for receiving solution");
325 Progress
->SubProgress(100, msg
, section
.FindI("Percentage", 0));
328 } else if (section
.Exists("Error") == true) {
329 std::string msg
= SubstVar(SubstVar(section
.FindS("Message"), "\n .\n", "\n\n"), "\n ", "\n");
330 if (msg
.empty() == true) {
331 msg
= _("External solver failed without a proper error message");
332 _error
->Error("%s", msg
.c_str());
334 _error
->Error("External solver failed with: %s", msg
.substr(0,msg
.find('\n')).c_str());
335 if (Progress
!= NULL
)
337 std::cerr
<< "The solver encountered an error of type: " << section
.FindS("Error") << std::endl
;
338 std::cerr
<< "The following information might help you to understand what is wrong:" << std::endl
;
339 std::cerr
<< msg
<< std::endl
<< std::endl
;
341 } else if (section
.Exists("Autoremove") == true)
346 size_t const id
= section
.FindULL(type
.c_str(), VersionCount
);
347 if (id
== VersionCount
) {
348 _error
->Warning("Unable to parse %s request with id value '%s'!", type
.c_str(), section
.FindS(type
.c_str()).c_str());
350 } else if (id
> Cache
.Head().VersionCount
) {
351 _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());
355 pkgCache::VerIterator
Ver(Cache
.GetCache(), Cache
.GetCache().VerP
+ VerIdx
[id
]);
356 Cache
.SetCandidateVersion(Ver
);
357 if (type
== "Install")
358 Cache
.MarkInstall(Ver
.ParentPkg(), false, 0, false);
359 else if (type
== "Remove")
360 Cache
.MarkDelete(Ver
.ParentPkg(), false);
361 else if (type
== "Autoremove") {
362 Cache
[Ver
.ParentPkg()].Marked
= false;
363 Cache
[Ver
.ParentPkg()].Garbage
= true;
369 // ReadLine - first line from the given file descriptor /*{{{*/
370 // ---------------------------------------------------------------------
371 /* Little helper method to read a complete line into a string. Similar to
372 fgets but we need to use the low-level read() here as otherwise the
373 listparser will be confused later on as mixing of fgets and read isn't
374 a supported action according to the manpages and results are undefined */
375 static bool ReadLine(int const input
, std::string
&line
) {
380 while ((data
= read(input
, &one
, sizeof(one
))) != -1) {
387 if (line
.empty() == true && isblank(one
) != 0)
394 // StringToBool - convert yes/no to bool /*{{{*/
395 // ---------------------------------------------------------------------
396 /* we are not as lazy as we are in the global StringToBool as we really
397 only accept yes/no here - but we will ignore leading spaces */
398 static bool StringToBool(char const *answer
, bool const defValue
) {
399 for (; isspace(*answer
) != 0; ++answer
);
400 if (strncasecmp(answer
, "yes", 3) == 0)
402 else if (strncasecmp(answer
, "no", 2) == 0)
405 _error
->Warning("Value '%s' is not a boolean 'yes' or 'no'!", answer
);
409 // EDSP::ReadRequest - first stanza from the given file descriptor /*{{{*/
410 bool EDSP::ReadRequest(int const input
, std::list
<std::string
> &install
,
411 std::list
<std::string
> &remove
, bool &upgrade
,
412 bool &distUpgrade
, bool &autoRemove
)
420 while (ReadLine(input
, line
) == true)
422 // Skip empty lines before request
423 if (line
.empty() == true)
425 // The first Tag must be a request, so search for it
426 if (line
.compare(0, 8, "Request:") != 0)
429 while (ReadLine(input
, line
) == true)
431 // empty lines are the end of the request
432 if (line
.empty() == true)
435 std::list
<std::string
> *request
= NULL
;
436 if (line
.compare(0, 8, "Install:") == 0)
441 else if (line
.compare(0, 7, "Remove:") == 0)
446 else if (line
.compare(0, 8, "Upgrade:") == 0)
447 upgrade
= StringToBool(line
.c_str() + 9, false);
448 else if (line
.compare(0, 13, "Dist-Upgrade:") == 0)
449 distUpgrade
= StringToBool(line
.c_str() + 14, false);
450 else if (line
.compare(0, 11, "Autoremove:") == 0)
451 autoRemove
= StringToBool(line
.c_str() + 12, false);
452 else if (line
.compare(0, 13, "Architecture:") == 0)
453 _config
->Set("APT::Architecture", line
.c_str() + 14);
454 else if (line
.compare(0, 14, "Architectures:") == 0)
456 std::string
const archs
= line
.c_str() + 15;
457 _config
->Set("APT::Architectures", SubstVar(archs
, " ", ","));
460 _error
->Warning("Unknown line in EDSP Request stanza: %s", line
.c_str());
464 size_t end
= line
.length();
466 size_t begin
= line
.rfind(' ');
467 if (begin
== std::string::npos
)
469 request
->push_back(line
.substr(0, end
));
472 else if (begin
< end
)
473 request
->push_back(line
.substr(begin
+ 1, end
));
475 end
= line
.find_last_not_of(' ');
476 } while (end
!= std::string::npos
);
482 // EDSP::ApplyRequest - first stanza from the given file descriptor /*{{{*/
483 bool EDSP::ApplyRequest(std::list
<std::string
> const &install
,
484 std::list
<std::string
> const &remove
,
487 for (std::list
<std::string
>::const_iterator i
= install
.begin();
488 i
!= install
.end(); ++i
) {
489 pkgCache::PkgIterator P
= Cache
.FindPkg(*i
);
491 _error
->Warning("Package %s is not known, so can't be installed", i
->c_str());
493 Cache
.MarkInstall(P
, false);
496 for (std::list
<std::string
>::const_iterator i
= remove
.begin();
497 i
!= remove
.end(); ++i
) {
498 pkgCache::PkgIterator P
= Cache
.FindPkg(*i
);
500 _error
->Warning("Package %s is not known, so can't be installed", i
->c_str());
507 // EDSP::WriteSolution - to the given file descriptor /*{{{*/
508 bool EDSP::WriteSolution(pkgDepCache
&Cache
, FILE* output
)
510 bool const Debug
= _config
->FindB("Debug::EDSP::WriteSolution", false);
511 for (pkgCache::PkgIterator Pkg
= Cache
.PkgBegin(); Pkg
.end() == false; ++Pkg
)
513 if (Cache
[Pkg
].Delete() == true)
515 fprintf(output
, "Remove: %d\n", Pkg
.CurrentVer()->ID
);
517 fprintf(output
, "Package: %s\nVersion: %s\n", Pkg
.FullName().c_str(), Pkg
.CurrentVer().VerStr());
519 else if (Cache
[Pkg
].NewInstall() == true || Cache
[Pkg
].Upgrade() == true)
521 fprintf(output
, "Install: %d\n", Cache
.GetCandidateVer(Pkg
)->ID
);
523 fprintf(output
, "Package: %s\nVersion: %s\n", Pkg
.FullName().c_str(), Cache
.GetCandidateVer(Pkg
).VerStr());
525 else if (Cache
[Pkg
].Garbage
== true)
527 fprintf(output
, "Autoremove: %d\n", Pkg
.CurrentVer()->ID
);
529 fprintf(output
, "Package: %s\nVersion: %s\n", Pkg
.FullName().c_str(), Pkg
.CurrentVer().VerStr());
533 fprintf(output
, "\n");
539 // EDSP::WriteProgess - pulse to the given file descriptor /*{{{*/
540 bool EDSP::WriteProgress(unsigned short const percent
, const char* const message
, FILE* output
) {
541 fprintf(output
, "Progress: %s\n", TimeRFC1123(time(NULL
)).c_str());
542 fprintf(output
, "Percentage: %d\n", percent
);
543 fprintf(output
, "Message: %s\n\n", message
);
548 // EDSP::WriteError - format an error message to be send to file descriptor /*{{{*/
549 bool EDSP::WriteError(char const * const uuid
, std::string
const &message
, FILE* output
) {
550 fprintf(output
, "Error: %s\n", uuid
);
551 fprintf(output
, "Message: %s\n\n", SubstVar(SubstVar(message
, "\n\n", "\n.\n"), "\n", "\n ").c_str());
555 // EDSP::ExecuteSolver - fork requested solver and setup ipc pipes {{{*/
556 pid_t
EDSP::ExecuteSolver(const char* const solver
, int * const solver_in
, int * const solver_out
, bool) {
557 std::vector
<std::string
> const solverDirs
= _config
->FindVector("Dir::Bin::Solvers");
559 for (std::vector
<std::string
>::const_iterator dir
= solverDirs
.begin();
560 dir
!= solverDirs
.end(); ++dir
) {
561 file
= flCombine(*dir
, solver
);
562 if (RealFileExists(file
.c_str()) == true)
567 if (file
.empty() == true)
569 _error
->Error("Can't call external solver '%s' as it is not in a configured directory!", solver
);
572 int external
[4] = {-1, -1, -1, -1};
573 if (pipe(external
) != 0 || pipe(external
+ 2) != 0)
575 _error
->Errno("Resolve", "Can't create needed IPC pipes for EDSP");
578 for (int i
= 0; i
< 4; ++i
)
579 SetCloseExec(external
[i
], true);
581 pid_t Solver
= ExecFork();
583 dup2(external
[0], STDIN_FILENO
);
584 dup2(external
[3], STDOUT_FILENO
);
585 const char* calling
[2] = { file
.c_str(), 0 };
586 execv(calling
[0], (char**) calling
);
587 std::cerr
<< "Failed to execute solver '" << solver
<< "'!" << std::endl
;
593 if (WaitFd(external
[1], true, 5) == false)
595 _error
->Errno("Resolve", "Timed out while Waiting on availability of solver stdin");
599 *solver_in
= external
[1];
600 *solver_out
= external
[2];
603 bool EDSP::ExecuteSolver(const char* const solver
, int *solver_in
, int *solver_out
) {
604 if (ExecuteSolver(solver
, solver_in
, solver_out
, true) == 0)
609 // EDSP::ResolveExternal - resolve problems by asking external for help {{{*/
610 bool EDSP::ResolveExternal(const char* const solver
, pkgDepCache
&Cache
,
611 bool const upgrade
, bool const distUpgrade
,
612 bool const autoRemove
, OpProgress
*Progress
) {
613 int solver_in
, solver_out
;
614 pid_t
const solver_pid
= EDSP::ExecuteSolver(solver
, &solver_in
, &solver_out
, true);
618 FILE* output
= fdopen(solver_in
, "w");
620 return _error
->Errno("Resolve", "fdopen on solver stdin failed");
622 if (Progress
!= NULL
)
623 Progress
->OverallProgress(0, 100, 5, _("Execute external solver"));
624 EDSP::WriteRequest(Cache
, output
, upgrade
, distUpgrade
, autoRemove
, Progress
);
625 if (Progress
!= NULL
)
626 Progress
->OverallProgress(5, 100, 20, _("Execute external solver"));
627 EDSP::WriteScenario(Cache
, output
, Progress
);
630 if (Progress
!= NULL
)
631 Progress
->OverallProgress(25, 100, 75, _("Execute external solver"));
632 if (EDSP::ReadResponse(solver_out
, Cache
, Progress
) == false)
635 return ExecWait(solver_pid
, solver
);