]> git.saurik.com Git - apt.git/blob - apt-pkg/packagemanager.cc
support dpkg debug mode in APT::StateChanges
[apt.git] / apt-pkg / packagemanager.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 // $Id: packagemanager.cc,v 1.30 2003/04/27 03:04:15 doogie Exp $
4 /* ######################################################################
5
6 Package Manager - Abstacts the package manager
7
8 More work is needed in the area of transitioning provides, ie exim
9 replacing smail. This can cause interesting side effects.
10
11 Other cases involving conflicts+replaces should be tested.
12
13 ##################################################################### */
14 /*}}}*/
15 // Include Files /*{{{*/
16 #include <config.h>
17
18 #include <apt-pkg/packagemanager.h>
19 #include <apt-pkg/orderlist.h>
20 #include <apt-pkg/depcache.h>
21 #include <apt-pkg/error.h>
22 #include <apt-pkg/edsp.h>
23 #include <apt-pkg/version.h>
24 #include <apt-pkg/acquire-item.h>
25 #include <apt-pkg/algorithms.h>
26 #include <apt-pkg/configuration.h>
27 #include <apt-pkg/macros.h>
28 #include <apt-pkg/pkgcache.h>
29 #include <apt-pkg/cacheiterators.h>
30 #include <apt-pkg/strutl.h>
31 #include <apt-pkg/install-progress.h>
32 #include <apt-pkg/prettyprinters.h>
33
34 #include <stddef.h>
35 #include <list>
36 #include <string>
37 #include <iostream>
38
39 #include <apti18n.h>
40 /*}}}*/
41 using namespace std;
42
43 bool pkgPackageManager::SigINTStop = false;
44
45 // PM::PackageManager - Constructor /*{{{*/
46 // ---------------------------------------------------------------------
47 /* */
48 pkgPackageManager::pkgPackageManager(pkgDepCache *pCache) : Cache(*pCache),
49 List(NULL), Res(Incomplete), d(NULL)
50 {
51 FileNames = new string[Cache.Head().PackageCount];
52 Debug = _config->FindB("Debug::pkgPackageManager",false);
53 NoImmConfigure = !_config->FindB("APT::Immediate-Configure",true);
54 ImmConfigureAll = _config->FindB("APT::Immediate-Configure-All",false);
55 }
56 /*}}}*/
57 // PM::PackageManager - Destructor /*{{{*/
58 // ---------------------------------------------------------------------
59 /* */
60 pkgPackageManager::~pkgPackageManager()
61 {
62 delete List;
63 delete [] FileNames;
64 }
65 /*}}}*/
66 // PM::GetArchives - Queue the archives for download /*{{{*/
67 // ---------------------------------------------------------------------
68 /* */
69 bool pkgPackageManager::GetArchives(pkgAcquire *Owner,pkgSourceList *Sources,
70 pkgRecords *Recs)
71 {
72 if (CreateOrderList() == false)
73 return false;
74
75 bool const ordering =
76 _config->FindB("PackageManager::UnpackAll",true) ?
77 List->OrderUnpack() : List->OrderCritical();
78 if (ordering == false)
79 return _error->Error("Internal ordering error");
80
81 for (pkgOrderList::iterator I = List->begin(); I != List->end(); ++I)
82 {
83 PkgIterator Pkg(Cache,*I);
84 FileNames[Pkg->ID] = string();
85
86 // Skip packages to erase
87 if (Cache[Pkg].Delete() == true)
88 continue;
89
90 // Skip Packages that need configure only.
91 if (Pkg.State() == pkgCache::PkgIterator::NeedsConfigure &&
92 Cache[Pkg].Keep() == true)
93 continue;
94
95 // Skip already processed packages
96 if (List->IsNow(Pkg) == false)
97 continue;
98
99 new pkgAcqArchive(Owner,Sources,Recs,Cache[Pkg].InstVerIter(Cache),
100 FileNames[Pkg->ID]);
101 }
102
103 return true;
104 }
105 /*}}}*/
106 // PM::FixMissing - Keep all missing packages /*{{{*/
107 // ---------------------------------------------------------------------
108 /* This is called to correct the installation when packages could not
109 be downloaded. */
110 bool pkgPackageManager::FixMissing()
111 {
112 pkgDepCache::ActionGroup group(Cache);
113 pkgProblemResolver Resolve(&Cache);
114 List->SetFileList(FileNames);
115
116 bool Bad = false;
117 for (PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
118 {
119 if (List->IsMissing(I) == false)
120 continue;
121
122 // Okay, this file is missing and we need it. Mark it for keep
123 Bad = true;
124 Cache.MarkKeep(I, false, false);
125 }
126
127 // We have to empty the list otherwise it will not have the new changes
128 delete List;
129 List = 0;
130
131 if (Bad == false)
132 return true;
133
134 // Now downgrade everything that is broken
135 return Resolve.ResolveByKeep() == true && Cache.BrokenCount() == 0;
136 }
137 /*}}}*/
138 // PM::ImmediateAdd - Add the immediate flag recursivly /*{{{*/
139 // ---------------------------------------------------------------------
140 /* This adds the immediate flag to the pkg and recursively to the
141 dependencies
142 */
143 void pkgPackageManager::ImmediateAdd(PkgIterator I, bool UseInstallVer, unsigned const int &Depth)
144 {
145 DepIterator D;
146
147 if(UseInstallVer)
148 {
149 if(Cache[I].InstallVer == 0)
150 return;
151 D = Cache[I].InstVerIter(Cache).DependsList();
152 } else {
153 if (I->CurrentVer == 0)
154 return;
155 D = I.CurrentVer().DependsList();
156 }
157
158 for ( /* nothing */ ; D.end() == false; ++D)
159 if (D->Type == pkgCache::Dep::Depends || D->Type == pkgCache::Dep::PreDepends)
160 {
161 if(!List->IsFlag(D.TargetPkg(), pkgOrderList::Immediate))
162 {
163 if(Debug)
164 clog << OutputInDepth(Depth) << "ImmediateAdd(): Adding Immediate flag to " << APT::PrettyPkg(&Cache, D.TargetPkg()) << " cause of " << D.DepType() << " " << I.FullName() << endl;
165 List->Flag(D.TargetPkg(),pkgOrderList::Immediate);
166 ImmediateAdd(D.TargetPkg(), UseInstallVer, Depth + 1);
167 }
168 }
169 return;
170 }
171 /*}}}*/
172 // PM::CreateOrderList - Create the ordering class /*{{{*/
173 // ---------------------------------------------------------------------
174 /* This populates the ordering list with all the packages that are
175 going to change. */
176 bool pkgPackageManager::CreateOrderList()
177 {
178 if (List != 0)
179 return true;
180
181 delete List;
182 List = new pkgOrderList(&Cache);
183
184 if (Debug && ImmConfigureAll)
185 clog << "CreateOrderList(): Adding Immediate flag for all packages because of APT::Immediate-Configure-All" << endl;
186
187 // Generate the list of affected packages and sort it
188 for (PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
189 {
190 // Ignore no-version packages
191 if (I->VersionList == 0)
192 continue;
193
194 // Mark the package and its dependents for immediate configuration
195 if ((((I->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential) &&
196 NoImmConfigure == false) || ImmConfigureAll)
197 {
198 if(Debug && !ImmConfigureAll)
199 clog << "CreateOrderList(): Adding Immediate flag for " << I.FullName() << endl;
200 List->Flag(I,pkgOrderList::Immediate);
201
202 if (!ImmConfigureAll) {
203 // Look for other install packages to make immediate configurea
204 ImmediateAdd(I, true);
205
206 // And again with the current version.
207 ImmediateAdd(I, false);
208 }
209 }
210
211 // Not interesting
212 if ((Cache[I].Keep() == true ||
213 Cache[I].InstVerIter(Cache) == I.CurrentVer()) &&
214 I.State() == pkgCache::PkgIterator::NeedsNothing &&
215 (Cache[I].iFlags & pkgDepCache::ReInstall) != pkgDepCache::ReInstall &&
216 (I.Purge() != false || Cache[I].Mode != pkgDepCache::ModeDelete ||
217 (Cache[I].iFlags & pkgDepCache::Purge) != pkgDepCache::Purge))
218 continue;
219
220 // Append it to the list
221 List->push_back(I);
222 }
223
224 return true;
225 }
226 /*}}}*/
227 // PM::DepAlwaysTrue - Returns true if this dep is irrelevant /*{{{*/
228 // ---------------------------------------------------------------------
229 /* The restriction on provides is to eliminate the case when provides
230 are transitioning between valid states [ie exim to smail] */
231 bool pkgPackageManager::DepAlwaysTrue(DepIterator D)
232 {
233 if (D.TargetPkg()->ProvidesList != 0)
234 return false;
235
236 if ((Cache[D] & pkgDepCache::DepInstall) != 0 &&
237 (Cache[D] & pkgDepCache::DepNow) != 0)
238 return true;
239 return false;
240 }
241 /*}}}*/
242 // PM::CheckRConflicts - Look for reverse conflicts /*{{{*/
243 // ---------------------------------------------------------------------
244 /* This looks over the reverses for a conflicts line that needs early
245 removal. */
246 bool pkgPackageManager::CheckRConflicts(PkgIterator Pkg,DepIterator D,
247 const char *Ver)
248 {
249 for (;D.end() == false; ++D)
250 {
251 if (D->Type != pkgCache::Dep::Conflicts &&
252 D->Type != pkgCache::Dep::Obsoletes)
253 continue;
254
255 // The package hasn't been changed
256 if (List->IsNow(Pkg) == false)
257 continue;
258
259 // Ignore self conflicts, ignore conflicts from irrelevant versions
260 if (D.IsIgnorable(Pkg) || D.ParentVer() != D.ParentPkg().CurrentVer())
261 continue;
262
263 if (Cache.VS().CheckDep(Ver,D->CompareOp,D.TargetVer()) == false)
264 continue;
265
266 if (EarlyRemove(D.ParentPkg(), &D) == false)
267 return _error->Error("Reverse conflicts early remove for package '%s' failed",
268 Pkg.FullName().c_str());
269 }
270 return true;
271 }
272 /*}}}*/
273 // PM::CheckRBreaks - Look for reverse breaks /*{{{*/
274 bool pkgPackageManager::CheckRBreaks(PkgIterator const &Pkg, DepIterator D,
275 const char * const Ver)
276 {
277 for (;D.end() == false; ++D)
278 {
279 if (D->Type != pkgCache::Dep::DpkgBreaks)
280 continue;
281
282 PkgIterator const DP = D.ParentPkg();
283 if (Cache[DP].Delete() == false)
284 continue;
285
286 // Ignore self conflicts, ignore conflicts from irrelevant versions
287 if (D.IsIgnorable(Pkg) || D.ParentVer() != DP.CurrentVer())
288 continue;
289
290 if (Cache.VS().CheckDep(Ver, D->CompareOp, D.TargetVer()) == false)
291 continue;
292
293 // no earlyremove() here as user has already agreed to the permanent removal
294 if (SmartRemove(DP) == false)
295 return _error->Error("Internal Error, Could not early remove %s (%d)",DP.FullName().c_str(), 4);
296 }
297 return true;
298 }
299 /*}}}*/
300 // PM::ConfigureAll - Run the all out configuration /*{{{*/
301 // ---------------------------------------------------------------------
302 /* This configures every package. It is assumed they are all unpacked and
303 that the final configuration is valid. This is also used to catch packages
304 that have not been configured when using ImmConfigureAll */
305 bool pkgPackageManager::ConfigureAll()
306 {
307 pkgOrderList OList(&Cache);
308
309 // Populate the order list
310 for (pkgOrderList::iterator I = List->begin(); I != List->end(); ++I)
311 if (List->IsFlag(pkgCache::PkgIterator(Cache,*I),
312 pkgOrderList::UnPacked) == true)
313 OList.push_back(*I);
314
315 if (OList.OrderConfigure() == false)
316 return false;
317
318 std::string const conf = _config->Find("PackageManager::Configure","all");
319 bool const ConfigurePkgs = (conf == "all");
320
321 // Perform the configuring
322 for (pkgOrderList::iterator I = OList.begin(); I != OList.end(); ++I)
323 {
324 PkgIterator Pkg(Cache,*I);
325
326 /* Check if the package has been configured, this can happen if SmartConfigure
327 calls its self */
328 if (List->IsFlag(Pkg,pkgOrderList::Configured)) continue;
329
330 if (ConfigurePkgs == true && SmartConfigure(Pkg, 0) == false) {
331 if (ImmConfigureAll)
332 _error->Error(_("Could not perform immediate configuration on '%s'. "
333 "Please see man 5 apt.conf under APT::Immediate-Configure for details. (%d)"),Pkg.FullName().c_str(),1);
334 else
335 _error->Error("Internal error, packages left unconfigured. %s",Pkg.FullName().c_str());
336 return false;
337 }
338
339 List->Flag(Pkg,pkgOrderList::Configured,pkgOrderList::States);
340 }
341
342 return true;
343 }
344 /*}}}*/
345 // PM::NonLoopingSmart - helper to avoid loops while calling Smart methods /*{{{*/
346 // -----------------------------------------------------------------------
347 /* ensures that a loop of the form A depends B, B depends A (and similar)
348 is not leading us down into infinite recursion segfault land */
349 bool pkgPackageManager::NonLoopingSmart(SmartAction const action, pkgCache::PkgIterator &Pkg,
350 pkgCache::PkgIterator DepPkg, int const Depth, bool const PkgLoop,
351 bool * const Bad, bool * const Changed)
352 {
353 if (PkgLoop == false)
354 List->Flag(Pkg,pkgOrderList::Loop);
355 bool success = false;
356 switch(action)
357 {
358 case UNPACK_IMMEDIATE: success = SmartUnPack(DepPkg, true, Depth + 1); break;
359 case UNPACK: success = SmartUnPack(DepPkg, false, Depth + 1); break;
360 case CONFIGURE: success = SmartConfigure(DepPkg, Depth + 1); break;
361 }
362 if (PkgLoop == false)
363 List->RmFlag(Pkg,pkgOrderList::Loop);
364
365 if (success == false)
366 return false;
367
368 if (Bad != NULL)
369 *Bad = false;
370 if (Changed != NULL && List->IsFlag(DepPkg,pkgOrderList::Loop) == false)
371 *Changed = true;
372 return true;
373 }
374 /*}}}*/
375 // PM::SmartConfigure - Perform immediate configuration of the pkg /*{{{*/
376 // ---------------------------------------------------------------------
377 /* This function tries to put the system in a state where Pkg can be configured.
378 This involves checking each of Pkg's dependencies and unpacking and
379 configuring packages where needed. */
380 bool pkgPackageManager::SmartConfigure(PkgIterator Pkg, int const Depth)
381 {
382 // If this is true, only check and correct and dependencies without the Loop flag
383 bool const PkgLoop = List->IsFlag(Pkg,pkgOrderList::Loop);
384
385 if (Debug) {
386 VerIterator InstallVer = VerIterator(Cache,Cache[Pkg].InstallVer);
387 clog << OutputInDepth(Depth) << "SmartConfigure " << Pkg.FullName() << " (" << InstallVer.VerStr() << ")";
388 if (PkgLoop)
389 clog << " (Only Correct Dependencies)";
390 clog << endl;
391 }
392
393 VerIterator const instVer = Cache[Pkg].InstVerIter(Cache);
394
395 /* Because of the ordered list, most dependencies should be unpacked,
396 however if there is a loop (A depends on B, B depends on A) this will not
397 be the case, so check for dependencies before configuring. */
398 bool Bad = false, Changed = false;
399 const unsigned int max_loops = _config->FindI("APT::pkgPackageManager::MaxLoopCount", 5000);
400 unsigned int i=0;
401 std::list<DepIterator> needConfigure;
402 do
403 {
404 // Check each dependency and see if anything needs to be done
405 // so that it can be configured
406 Changed = false;
407 for (DepIterator D = instVer.DependsList(); D.end() == false; )
408 {
409 // Compute a single dependency element (glob or)
410 pkgCache::DepIterator Start, End;
411 D.GlobOr(Start,End);
412
413 if (End->Type != pkgCache::Dep::Depends && End->Type != pkgCache::Dep::PreDepends)
414 continue;
415 Bad = true;
416
417 // the first pass checks if we its all good, i.e. if we have
418 // to do anything at all
419 for (DepIterator Cur = Start; true; ++Cur)
420 {
421 std::unique_ptr<Version *[]> VList(Cur.AllTargets());
422
423 for (Version **I = VList.get(); *I != 0; ++I)
424 {
425 VerIterator Ver(Cache,*I);
426 PkgIterator DepPkg = Ver.ParentPkg();
427
428 // Check if the current version of the package is available and will satisfy this dependency
429 if (DepPkg.CurrentVer() == Ver && List->IsNow(DepPkg) == true &&
430 List->IsFlag(DepPkg,pkgOrderList::Removed) == false &&
431 DepPkg.State() == PkgIterator::NeedsNothing &&
432 (Cache[DepPkg].iFlags & pkgDepCache::ReInstall) != pkgDepCache::ReInstall)
433 {
434 Bad = false;
435 break;
436 }
437
438 // Check if the version that is going to be installed will satisfy the dependency
439 if (Cache[DepPkg].InstallVer != *I || List->IsNow(DepPkg) == false)
440 continue;
441
442 if (PkgLoop == true)
443 {
444 if (Debug)
445 std::clog << OutputInDepth(Depth) << "Package " << APT::PrettyPkg(&Cache, Pkg) << " loops in SmartConfigure";
446 if (List->IsFlag(DepPkg,pkgOrderList::UnPacked))
447 Bad = false;
448 else if (Debug)
449 std::clog << ", but it isn't unpacked yet";
450 if (Debug)
451 std::clog << std::endl;
452 }
453 }
454
455 if (Cur == End || Bad == false)
456 break;
457 }
458
459 // this dependency is in a good state, so we can stop
460 if (Bad == false)
461 {
462 if (Debug)
463 std::clog << OutputInDepth(Depth) << "Found ok dep " << APT::PrettyPkg(&Cache, Start.TargetPkg()) << std::endl;
464 continue;
465 }
466
467 // Check for dependencies that have not been unpacked,
468 // probably due to loops.
469 for (DepIterator Cur = Start; true; ++Cur)
470 {
471 std::unique_ptr<Version *[]> VList(Cur.AllTargets());
472
473 for (Version **I = VList.get(); *I != 0; ++I)
474 {
475 VerIterator Ver(Cache,*I);
476 PkgIterator DepPkg = Ver.ParentPkg();
477
478 // Check if the current version of the package is available and will satisfy this dependency
479 if (DepPkg.CurrentVer() == Ver && List->IsNow(DepPkg) == true &&
480 List->IsFlag(DepPkg,pkgOrderList::Removed) == false &&
481 DepPkg.State() == PkgIterator::NeedsNothing &&
482 (Cache[DepPkg].iFlags & pkgDepCache::ReInstall) != pkgDepCache::ReInstall)
483 continue;
484
485 // Check if the version that is going to be installed will satisfy the dependency
486 if (Cache[DepPkg].InstallVer != *I || List->IsNow(DepPkg) == false)
487 continue;
488
489 if (PkgLoop == true)
490 {
491 if (Debug)
492 std::clog << OutputInDepth(Depth) << "Package " << APT::PrettyPkg(&Cache, Pkg) << " loops in SmartConfigure";
493 if (List->IsFlag(DepPkg,pkgOrderList::UnPacked))
494 Bad = false;
495 else if (Debug)
496 std::clog << ", but it isn't unpacked yet";
497 if (Debug)
498 std::clog << std::endl;
499 }
500 else
501 {
502 if (Debug)
503 clog << OutputInDepth(Depth) << "Unpacking " << DepPkg.FullName() << " to avoid loop " << APT::PrettyDep(&Cache, Cur) << endl;
504 if (NonLoopingSmart(UNPACK_IMMEDIATE, Pkg, DepPkg, Depth, PkgLoop, &Bad, &Changed) == false)
505 return false;
506 }
507 // at this point we either unpacked a Dep or we are in a loop,
508 // no need to unpack a second one
509 break;
510 }
511
512 if (Cur == End || Bad == false)
513 break;
514 }
515
516 if (Bad == false)
517 continue;
518
519 needConfigure.push_back(Start);
520 }
521 if (i++ > max_loops)
522 return _error->Error("Internal error: MaxLoopCount reached in SmartUnPack (1) for %s, aborting", Pkg.FullName().c_str());
523 } while (Changed == true);
524
525 // now go over anything that needs configuring
526 Bad = false, Changed = false, i = 0;
527 do
528 {
529 Changed = false;
530 for (std::list<DepIterator>::const_iterator D = needConfigure.begin(); D != needConfigure.end(); ++D)
531 {
532 // Compute a single dependency element (glob or) without modifying D
533 pkgCache::DepIterator Start, End;
534 {
535 pkgCache::DepIterator Discard = *D;
536 Discard.GlobOr(Start,End);
537 }
538
539 if (End->Type != pkgCache::Dep::Depends && End->Type != pkgCache::Dep::PreDepends)
540 continue;
541 Bad = true;
542
543 // Search for dependencies which are unpacked but aren't configured yet (maybe loops)
544 for (DepIterator Cur = Start; true; ++Cur)
545 {
546 std::unique_ptr<Version *[]> VList(Cur.AllTargets());
547
548 for (Version **I = VList.get(); *I != 0; ++I)
549 {
550 VerIterator Ver(Cache,*I);
551 PkgIterator DepPkg = Ver.ParentPkg();
552
553 // Check if the version that is going to be installed will satisfy the dependency
554 if (Cache[DepPkg].InstallVer != *I)
555 continue;
556
557 if (List->IsFlag(DepPkg,pkgOrderList::UnPacked))
558 {
559 if (List->IsFlag(DepPkg,pkgOrderList::Loop) && PkgLoop)
560 {
561 // This dependency has already been dealt with by another SmartConfigure on Pkg
562 Bad = false;
563 break;
564 }
565 if (Debug)
566 std::clog << OutputInDepth(Depth) << "Configure already unpacked " << APT::PrettyPkg(&Cache, DepPkg) << std::endl;
567 if (NonLoopingSmart(CONFIGURE, Pkg, DepPkg, Depth, PkgLoop, &Bad, &Changed) == false)
568 return false;
569 break;
570
571 }
572 else if (List->IsFlag(DepPkg,pkgOrderList::Configured))
573 {
574 Bad = false;
575 break;
576 }
577 }
578 if (Cur == End || Bad == false)
579 break;
580 }
581
582
583 if (Bad == true && Changed == false && Debug == true)
584 std::clog << OutputInDepth(Depth) << "Could not satisfy " << APT::PrettyDep(&Cache, *D) << std::endl;
585 }
586 if (i++ > max_loops)
587 return _error->Error("Internal error: MaxLoopCount reached in SmartUnPack (2) for %s, aborting", Pkg.FullName().c_str());
588 } while (Changed == true);
589
590 if (Bad == true)
591 return _error->Error(_("Could not configure '%s'. "),Pkg.FullName().c_str());
592
593 // Check for reverse conflicts.
594 if (CheckRBreaks(Pkg,Pkg.RevDependsList(), instVer.VerStr()) == false)
595 return false;
596
597 for (PrvIterator P = instVer.ProvidesList(); P.end() == false; ++P)
598 if (Pkg->Group != P.OwnerPkg()->Group)
599 CheckRBreaks(Pkg,P.ParentPkg().RevDependsList(),P.ProvideVersion());
600
601 if (PkgLoop) return true;
602
603 static std::string const conf = _config->Find("PackageManager::Configure","all");
604 static bool const ConfigurePkgs = (conf == "all" || conf == "smart");
605
606 if (List->IsFlag(Pkg,pkgOrderList::Configured))
607 return _error->Error("Internal configure error on '%s'.", Pkg.FullName().c_str());
608
609 if (ConfigurePkgs == true && Configure(Pkg) == false)
610 return false;
611
612 List->Flag(Pkg,pkgOrderList::Configured,pkgOrderList::States);
613
614 if ((Cache[Pkg].InstVerIter(Cache)->MultiArch & pkgCache::Version::Same) == pkgCache::Version::Same)
615 for (PkgIterator P = Pkg.Group().PackageList();
616 P.end() == false; P = Pkg.Group().NextPkg(P))
617 {
618 if (Pkg == P || List->IsFlag(P,pkgOrderList::Configured) == true ||
619 List->IsFlag(P,pkgOrderList::UnPacked) == false ||
620 Cache[P].InstallVer == 0 || (P.CurrentVer() == Cache[P].InstallVer &&
621 (Cache[Pkg].iFlags & pkgDepCache::ReInstall) != pkgDepCache::ReInstall))
622 continue;
623 if (SmartConfigure(P, (Depth +1)) == false)
624 return false;
625 }
626
627 // Sanity Check
628 if (List->IsFlag(Pkg,pkgOrderList::Configured) == false)
629 return _error->Error(_("Could not configure '%s'. "),Pkg.FullName().c_str());
630
631 return true;
632 }
633 /*}}}*/
634 // PM::EarlyRemove - Perform removal of packages before their time /*{{{*/
635 // ---------------------------------------------------------------------
636 /* This is called to deal with conflicts arising from unpacking */
637 bool pkgPackageManager::EarlyRemove(PkgIterator Pkg)
638 {
639 return EarlyRemove(Pkg, NULL);
640 }
641 bool pkgPackageManager::EarlyRemove(PkgIterator Pkg, DepIterator const * const Dep)
642 {
643 if (List->IsNow(Pkg) == false)
644 return true;
645
646 // Already removed it
647 if (List->IsFlag(Pkg,pkgOrderList::Removed) == true)
648 return true;
649
650 // Woops, it will not be re-installed!
651 if (List->IsFlag(Pkg,pkgOrderList::InList) == false)
652 return false;
653
654 // these breaks on M-A:same packages can be dealt with. They 'loop' by design
655 if (Dep != NULL && (*Dep)->Type == pkgCache::Dep::DpkgBreaks && Dep->IsMultiArchImplicit() == true)
656 return true;
657
658 // Essential packages get special treatment
659 bool IsEssential = false;
660 if ((Pkg->Flags & pkgCache::Flag::Essential) != 0 ||
661 (Pkg->Flags & pkgCache::Flag::Important) != 0)
662 IsEssential = true;
663
664 /* Check for packages that are the dependents of essential packages and
665 promote them too */
666 if (Pkg->CurrentVer != 0)
667 {
668 for (pkgCache::DepIterator D = Pkg.RevDependsList(); D.end() == false &&
669 IsEssential == false; ++D)
670 if (D->Type == pkgCache::Dep::Depends || D->Type == pkgCache::Dep::PreDepends)
671 if ((D.ParentPkg()->Flags & pkgCache::Flag::Essential) != 0 ||
672 (D.ParentPkg()->Flags & pkgCache::Flag::Important) != 0)
673 IsEssential = true;
674 }
675
676 if (IsEssential == true)
677 {
678 if (_config->FindB("APT::Force-LoopBreak",false) == false)
679 return _error->Error(_("This installation run will require temporarily "
680 "removing the essential package %s due to a "
681 "Conflicts/Pre-Depends loop. This is often bad, "
682 "but if you really want to do it, activate the "
683 "APT::Force-LoopBreak option."),Pkg.FullName().c_str());
684 }
685 // dpkg will auto-deconfigure it, no need for the big remove hammer
686 else if (Dep != NULL && (*Dep)->Type == pkgCache::Dep::DpkgBreaks)
687 return true;
688
689 bool Res = SmartRemove(Pkg);
690 if (Cache[Pkg].Delete() == false)
691 List->Flag(Pkg,pkgOrderList::Removed,pkgOrderList::States);
692
693 return Res;
694 }
695 /*}}}*/
696 // PM::SmartRemove - Removal Helper /*{{{*/
697 // ---------------------------------------------------------------------
698 /* */
699 bool pkgPackageManager::SmartRemove(PkgIterator Pkg)
700 {
701 if (List->IsNow(Pkg) == false)
702 return true;
703
704 List->Flag(Pkg,pkgOrderList::Configured,pkgOrderList::States);
705
706 return Remove(Pkg,(Cache[Pkg].iFlags & pkgDepCache::Purge) == pkgDepCache::Purge);
707 }
708 /*}}}*/
709 // PM::SmartUnPack - Install helper /*{{{*/
710 // ---------------------------------------------------------------------
711 /* This puts the system in a state where it can Unpack Pkg, if Pkg is already
712 unpacked, or when it has been unpacked, if Immediate==true it configures it. */
713 bool pkgPackageManager::SmartUnPack(PkgIterator Pkg)
714 {
715 return SmartUnPack(Pkg, true, 0);
716 }
717 bool pkgPackageManager::SmartUnPack(PkgIterator Pkg, bool const Immediate, int const Depth)
718 {
719 bool PkgLoop = List->IsFlag(Pkg,pkgOrderList::Loop);
720
721 if (Debug) {
722 clog << OutputInDepth(Depth) << "SmartUnPack " << Pkg.FullName();
723 VerIterator InstallVer = VerIterator(Cache,Cache[Pkg].InstallVer);
724 if (Pkg.CurrentVer() == 0)
725 clog << " (install version " << InstallVer.VerStr() << ")";
726 else
727 clog << " (replace version " << Pkg.CurrentVer().VerStr() << " with " << InstallVer.VerStr() << ")";
728 if (PkgLoop)
729 clog << " (Only Perform PreUnpack Checks)";
730 if (Immediate)
731 clog << " immediately";
732 clog << endl;
733 }
734
735 VerIterator const instVer = Cache[Pkg].InstVerIter(Cache);
736
737 /* PreUnpack Checks: This loop checks and attempts to rectify any problems that would prevent the package being unpacked.
738 It addresses: PreDepends, Conflicts, Obsoletes and Breaks (DpkgBreaks). Any resolutions that do not require it should
739 avoid configuration (calling SmartUnpack with Immediate=true), this is because when unpacking some packages with
740 complex dependency structures, trying to configure some packages while breaking the loops can complicate things.
741 This will be either dealt with if the package is configured as a dependency of Pkg (if and when Pkg is configured),
742 or by the ConfigureAll call at the end of the for loop in OrderInstall. */
743 bool SomethingBad = false, Changed = false;
744 bool couldBeTemporaryRemoved = Depth != 0 && List->IsFlag(Pkg,pkgOrderList::Removed) == false;
745 const unsigned int max_loops = _config->FindI("APT::pkgPackageManager::MaxLoopCount", 5000);
746 unsigned int i = 0;
747 do
748 {
749 Changed = false;
750 for (DepIterator D = instVer.DependsList(); D.end() == false; )
751 {
752 // Compute a single dependency element (glob or)
753 pkgCache::DepIterator Start, End;
754 D.GlobOr(Start,End);
755
756 if (End->Type == pkgCache::Dep::PreDepends)
757 {
758 bool Bad = true;
759 if (Debug)
760 clog << OutputInDepth(Depth) << "PreDepends order for " << Pkg.FullName() << std::endl;
761
762 // Look for easy targets: packages that are already okay
763 for (DepIterator Cur = Start; Bad == true; ++Cur)
764 {
765 std::unique_ptr<Version *[]> VList(Cur.AllTargets());
766 for (Version **I = VList.get(); *I != 0; ++I)
767 {
768 VerIterator Ver(Cache,*I);
769 PkgIterator Pkg = Ver.ParentPkg();
770
771 // See if the current version is ok
772 if (Pkg.CurrentVer() == Ver && List->IsNow(Pkg) == true &&
773 Pkg.State() == PkgIterator::NeedsNothing &&
774 (Cache[Pkg].iFlags & pkgDepCache::ReInstall) != pkgDepCache::ReInstall)
775 {
776 Bad = false;
777 if (Debug)
778 clog << OutputInDepth(Depth) << "Found ok package " << Pkg.FullName() << endl;
779 break;
780 }
781 }
782 if (Cur == End)
783 break;
784 }
785
786 // Look for something that could be configured.
787 for (DepIterator Cur = Start; Bad == true && Cur.end() == false; ++Cur)
788 {
789 std::unique_ptr<Version *[]> VList(Cur.AllTargets());
790 for (Version **I = VList.get(); *I != 0; ++I)
791 {
792 VerIterator Ver(Cache,*I);
793 PkgIterator DepPkg = Ver.ParentPkg();
794
795 // Not the install version
796 if (Cache[DepPkg].InstallVer != *I)
797 continue;
798
799 if (Cache[DepPkg].Keep() == true && DepPkg.State() == PkgIterator::NeedsNothing &&
800 (Cache[DepPkg].iFlags & pkgDepCache::ReInstall) != pkgDepCache::ReInstall)
801 continue;
802
803 if (List->IsFlag(DepPkg,pkgOrderList::Configured))
804 {
805 Bad = false;
806 break;
807 }
808
809 // check if it needs unpack or if if configure is enough
810 if (List->IsFlag(DepPkg,pkgOrderList::UnPacked) == false)
811 {
812 // two packages pre-depending on each other can't be handled sanely
813 if (List->IsFlag(DepPkg,pkgOrderList::Loop) && PkgLoop)
814 {
815 // this isn't an error as there is potential for something else to satisfy it
816 // (like a provides or an or-group member)
817 if (Debug)
818 clog << OutputInDepth(Depth) << "Unpack loop detected between " << DepPkg.FullName() << " and " << Pkg.FullName() << endl;
819 continue;
820 }
821
822 if (Debug)
823 clog << OutputInDepth(Depth) << "Trying to SmartUnpack " << DepPkg.FullName() << endl;
824 if (NonLoopingSmart(UNPACK_IMMEDIATE, Pkg, DepPkg, Depth, PkgLoop, &Bad, &Changed) == false)
825 return false;
826 }
827 else
828 {
829 if (Debug)
830 clog << OutputInDepth(Depth) << "Trying to SmartConfigure " << DepPkg.FullName() << endl;
831 if (NonLoopingSmart(CONFIGURE, Pkg, DepPkg, Depth, PkgLoop, &Bad, &Changed) == false)
832 return false;
833 }
834 break;
835 }
836 }
837
838 if (Bad == true)
839 SomethingBad = true;
840 }
841 else if (End->Type == pkgCache::Dep::Conflicts ||
842 End->Type == pkgCache::Dep::Obsoletes ||
843 End->Type == pkgCache::Dep::DpkgBreaks)
844 {
845 std::unique_ptr<Version *[]> VList(End.AllTargets());
846 for (Version **I = VList.get(); *I != 0; ++I)
847 {
848 VerIterator Ver(Cache,*I);
849 PkgIterator ConflictPkg = Ver.ParentPkg();
850 if (ConflictPkg.CurrentVer() != Ver)
851 {
852 if (Debug)
853 std::clog << OutputInDepth(Depth) << "Ignore not-installed version " << Ver.VerStr() << " of " << ConflictPkg.FullName() << " for " << APT::PrettyDep(&Cache, End) << std::endl;
854 continue;
855 }
856
857 if (List->IsNow(ConflictPkg) == false)
858 {
859 if (Debug)
860 std::clog << OutputInDepth(Depth) << "Ignore already dealt-with version " << Ver.VerStr() << " of " << ConflictPkg.FullName() << " for " << APT::PrettyDep(&Cache, End) << std::endl;
861 continue;
862 }
863
864 if (List->IsFlag(ConflictPkg,pkgOrderList::Removed) == true)
865 {
866 if (Debug)
867 clog << OutputInDepth(Depth) << "Ignoring " << APT::PrettyDep(&Cache, End) << " as " << ConflictPkg.FullName() << "was temporarily removed" << endl;
868 continue;
869 }
870
871 if (List->IsFlag(ConflictPkg,pkgOrderList::Loop) && PkgLoop)
872 {
873 if (End->Type == pkgCache::Dep::DpkgBreaks && End.IsMultiArchImplicit() == true)
874 {
875 if (Debug)
876 clog << OutputInDepth(Depth) << "Because dependency is MultiArchImplicit we ignored looping on: " << APT::PrettyPkg(&Cache, ConflictPkg) << endl;
877 continue;
878 }
879 if (Debug)
880 {
881 if (End->Type == pkgCache::Dep::DpkgBreaks)
882 clog << OutputInDepth(Depth) << "Because of breaks knot, deconfigure " << ConflictPkg.FullName() << " temporarily" << endl;
883 else
884 clog << OutputInDepth(Depth) << "Because of conflict knot, removing " << ConflictPkg.FullName() << " temporarily" << endl;
885 }
886 if (EarlyRemove(ConflictPkg, &End) == false)
887 return _error->Error("Internal Error, Could not early remove %s (%d)",ConflictPkg.FullName().c_str(), 3);
888 SomethingBad = true;
889 continue;
890 }
891
892 if (Cache[ConflictPkg].Delete() == false)
893 {
894 if (Debug)
895 {
896 clog << OutputInDepth(Depth) << "Unpacking " << ConflictPkg.FullName() << " to avoid " << APT::PrettyDep(&Cache, End);
897 if (PkgLoop == true)
898 clog << " (Looping)";
899 clog << std::endl;
900 }
901 // we would like to avoid temporary removals and all that at best via a simple unpack
902 _error->PushToStack();
903 if (NonLoopingSmart(UNPACK, Pkg, ConflictPkg, Depth, PkgLoop, NULL, &Changed) == false)
904 {
905 // but if it fails ignore this failure and look for alternative ways of solving
906 if (Debug)
907 {
908 clog << OutputInDepth(Depth) << "Avoidance unpack of " << ConflictPkg.FullName() << " failed for " << APT::PrettyDep(&Cache, End) << " ignoring:" << std::endl;
909 _error->DumpErrors(std::clog, GlobalError::DEBUG, false);
910 }
911 _error->RevertToStack();
912 // ignorance can only happen if a) one of the offenders is already gone
913 if (List->IsFlag(ConflictPkg,pkgOrderList::Removed) == true)
914 {
915 if (Debug)
916 clog << OutputInDepth(Depth) << "But " << ConflictPkg.FullName() << " was temporarily removed in the meantime to satisfy " << APT::PrettyDep(&Cache, End) << endl;
917 }
918 else if (List->IsFlag(Pkg,pkgOrderList::Removed) == true)
919 {
920 if (Debug)
921 clog << OutputInDepth(Depth) << "But " << Pkg.FullName() << " was temporarily removed in the meantime to satisfy " << APT::PrettyDep(&Cache, End) << endl;
922 }
923 // or b) we can make one go (removal or dpkg auto-deconfigure)
924 else
925 {
926 if (Debug)
927 clog << OutputInDepth(Depth) << "So temprorary remove/deconfigure " << ConflictPkg.FullName() << " to satisfy " << APT::PrettyDep(&Cache, End) << endl;
928 if (EarlyRemove(ConflictPkg, &End) == false)
929 return _error->Error("Internal Error, Could not early remove %s (%d)",ConflictPkg.FullName().c_str(), 2);
930 }
931 }
932 else
933 _error->MergeWithStack();
934 }
935 else
936 {
937 if (Debug)
938 clog << OutputInDepth(Depth) << "Removing " << ConflictPkg.FullName() << " now to avoid " << APT::PrettyDep(&Cache, End) << endl;
939 // no earlyremove() here as user has already agreed to the permanent removal
940 if (SmartRemove(Pkg) == false)
941 return _error->Error("Internal Error, Could not early remove %s (%d)",ConflictPkg.FullName().c_str(), 1);
942 }
943 }
944 }
945 }
946 if (i++ > max_loops)
947 return _error->Error("Internal error: APT::pkgPackageManager::MaxLoopCount reached in SmartConfigure for %s, aborting", Pkg.FullName().c_str());
948 } while (Changed == true);
949
950 if (SomethingBad == true)
951 return _error->Error("Couldn't configure %s, probably a dependency cycle.", Pkg.FullName().c_str());
952
953 if (couldBeTemporaryRemoved == true && List->IsFlag(Pkg,pkgOrderList::Removed) == true)
954 {
955 if (Debug)
956 std::clog << OutputInDepth(Depth) << "Prevent unpack as " << APT::PrettyPkg(&Cache, Pkg) << " is currently temporarily removed" << std::endl;
957 return true;
958 }
959
960 // Check for reverse conflicts.
961 if (CheckRConflicts(Pkg,Pkg.RevDependsList(),
962 instVer.VerStr()) == false)
963 return false;
964
965 for (PrvIterator P = instVer.ProvidesList();
966 P.end() == false; ++P)
967 if (Pkg->Group != P.OwnerPkg()->Group)
968 CheckRConflicts(Pkg,P.ParentPkg().RevDependsList(),P.ProvideVersion());
969
970 if (PkgLoop)
971 return true;
972
973 List->Flag(Pkg,pkgOrderList::UnPacked,pkgOrderList::States);
974
975 if (Immediate == true && (instVer->MultiArch & pkgCache::Version::Same) == pkgCache::Version::Same)
976 {
977 /* Do lockstep M-A:same unpacking in two phases:
978 First unpack all installed architectures, then the not installed.
979 This way we avoid that M-A: enabled packages are installed before
980 their older non-M-A enabled packages are replaced by newer versions */
981 bool const installed = Pkg->CurrentVer != 0;
982 if (installed == true &&
983 (instVer != Pkg.CurrentVer() ||
984 ((Cache[Pkg].iFlags & pkgDepCache::ReInstall) == pkgDepCache::ReInstall)) &&
985 Install(Pkg,FileNames[Pkg->ID]) == false)
986 return false;
987 for (PkgIterator P = Pkg.Group().PackageList();
988 P.end() == false; P = Pkg.Group().NextPkg(P))
989 {
990 if (P->CurrentVer == 0 || P == Pkg || List->IsFlag(P,pkgOrderList::UnPacked) == true ||
991 Cache[P].InstallVer == 0 || (P.CurrentVer() == Cache[P].InstallVer &&
992 (Cache[Pkg].iFlags & pkgDepCache::ReInstall) != pkgDepCache::ReInstall))
993 continue;
994 if (SmartUnPack(P, false, Depth + 1) == false)
995 return false;
996 }
997 if (installed == false && Install(Pkg,FileNames[Pkg->ID]) == false)
998 return false;
999 for (PkgIterator P = Pkg.Group().PackageList();
1000 P.end() == false; P = Pkg.Group().NextPkg(P))
1001 {
1002 if (P->CurrentVer != 0 || P == Pkg || List->IsFlag(P,pkgOrderList::UnPacked) == true ||
1003 List->IsFlag(P,pkgOrderList::Configured) == true ||
1004 Cache[P].InstallVer == 0 || (P.CurrentVer() == Cache[P].InstallVer &&
1005 (Cache[Pkg].iFlags & pkgDepCache::ReInstall) != pkgDepCache::ReInstall))
1006 continue;
1007 if (SmartUnPack(P, false, Depth + 1) == false)
1008 return false;
1009 }
1010 }
1011 // packages which are already unpacked don't need to be unpacked again
1012 else if ((instVer != Pkg.CurrentVer() ||
1013 ((Cache[Pkg].iFlags & pkgDepCache::ReInstall) == pkgDepCache::ReInstall)) &&
1014 Install(Pkg,FileNames[Pkg->ID]) == false)
1015 return false;
1016
1017 if (Immediate == true) {
1018 // Perform immedate configuration of the package.
1019 if (SmartConfigure(Pkg, Depth + 1) == false)
1020 _error->Error(_("Could not perform immediate configuration on '%s'. "
1021 "Please see man 5 apt.conf under APT::Immediate-Configure for details. (%d)"),Pkg.FullName().c_str(),2);
1022 }
1023
1024 return true;
1025 }
1026 /*}}}*/
1027 // PM::OrderInstall - Installation ordering routine /*{{{*/
1028 // ---------------------------------------------------------------------
1029 /* */
1030 pkgPackageManager::OrderResult pkgPackageManager::OrderInstall()
1031 {
1032 if (CreateOrderList() == false)
1033 return Failed;
1034
1035 Reset();
1036
1037 if (Debug == true)
1038 clog << "Beginning to order" << endl;
1039
1040 std::string const planner = _config->Find("APT::Planner", "internal");
1041 unsigned int flags = 0;
1042 if (_config->FindB("APT::Immediate-Configure", true) == false)
1043 flags |= EIPP::Request::NO_IMMEDIATE_CONFIGURATION;
1044 else if (_config->FindB("APT::Immediate-Configure-All", false))
1045 flags |= EIPP::Request::IMMEDIATE_CONFIGURATION_ALL;
1046 else if (_config->FindB("APT::Force-LoopBreak", false))
1047 flags |= EIPP::Request::ALLOW_TEMPORARY_REMOVE_OF_ESSENTIALS;
1048 auto const ret = EIPP::OrderInstall(planner.c_str(), this, flags, nullptr);
1049 if (planner != "internal")
1050 return ret ? Completed : Failed;
1051
1052 bool const ordering =
1053 _config->FindB("PackageManager::UnpackAll",true) ?
1054 List->OrderUnpack(FileNames) : List->OrderCritical();
1055 if (ordering == false)
1056 {
1057 _error->Error("Internal ordering error");
1058 return Failed;
1059 }
1060
1061 if (Debug == true)
1062 clog << "Done ordering" << endl;
1063
1064 bool DoneSomething = false;
1065 for (pkgOrderList::iterator I = List->begin(); I != List->end(); ++I)
1066 {
1067 PkgIterator Pkg(Cache,*I);
1068
1069 if (List->IsNow(Pkg) == false)
1070 {
1071 if (Debug == true)
1072 clog << "Skipping already done " << Pkg.FullName() << endl;
1073 continue;
1074 }
1075
1076 if (List->IsMissing(Pkg) == true)
1077 {
1078 if (Debug == true)
1079 clog << "Sequence completed at " << Pkg.FullName() << endl;
1080 if (DoneSomething == false)
1081 {
1082 _error->Error("Internal Error, ordering was unable to handle the media swap");
1083 return Failed;
1084 }
1085 return Incomplete;
1086 }
1087
1088 // Sanity check
1089 if (Cache[Pkg].Keep() == true &&
1090 Pkg.State() == pkgCache::PkgIterator::NeedsNothing &&
1091 (Cache[Pkg].iFlags & pkgDepCache::ReInstall) != pkgDepCache::ReInstall)
1092 {
1093 _error->Error("Internal Error, trying to manipulate a kept package (%s)",Pkg.FullName().c_str());
1094 return Failed;
1095 }
1096
1097 // Perform a delete or an install
1098 if (Cache[Pkg].Delete() == true)
1099 {
1100 if (SmartRemove(Pkg) == false)
1101 return Failed;
1102 }
1103 else
1104 if (SmartUnPack(Pkg,List->IsFlag(Pkg,pkgOrderList::Immediate),0) == false)
1105 return Failed;
1106 DoneSomething = true;
1107
1108 if (ImmConfigureAll) {
1109 /* ConfigureAll here to pick up and packages left unconfigured because they were unpacked in the
1110 "PreUnpack Checks" section */
1111 if (!ConfigureAll())
1112 return Failed;
1113 }
1114 }
1115
1116 // Final run through the configure phase
1117 if (ConfigureAll() == false)
1118 return Failed;
1119
1120 // Sanity check
1121 for (pkgOrderList::iterator I = List->begin(); I != List->end(); ++I)
1122 {
1123 if (List->IsFlag(*I,pkgOrderList::Configured) == false)
1124 {
1125 _error->Error("Internal error, packages left unconfigured. %s",
1126 PkgIterator(Cache,*I).FullName().c_str());
1127 return Failed;
1128 }
1129 }
1130
1131 return Completed;
1132 }
1133 // PM::DoInstallPostFork - compat /*{{{*/
1134 // ---------------------------------------------------------------------
1135 /*}}}*/
1136 pkgPackageManager::OrderResult
1137 pkgPackageManager::DoInstallPostFork(int statusFd)
1138 {
1139 APT::Progress::PackageManager *progress = new
1140 APT::Progress::PackageManagerProgressFd(statusFd);
1141 pkgPackageManager::OrderResult res = DoInstallPostFork(progress);
1142 delete progress;
1143 return res;
1144 }
1145 /*}}}*/
1146 // PM::DoInstallPostFork - Does install part that happens after the fork /*{{{*/
1147 // ---------------------------------------------------------------------
1148 pkgPackageManager::OrderResult
1149 pkgPackageManager::DoInstallPostFork(APT::Progress::PackageManager *progress)
1150 {
1151 bool goResult = Go(progress);
1152 if(goResult == false)
1153 return Failed;
1154
1155 return Res;
1156 }
1157 /*}}}*/
1158 // PM::DoInstall - Does the installation /*{{{*/
1159 // ---------------------------------------------------------------------
1160 /* compat */
1161 pkgPackageManager::OrderResult
1162 pkgPackageManager::DoInstall(int statusFd)
1163 {
1164 APT::Progress::PackageManager *progress = new
1165 APT::Progress::PackageManagerProgressFd(statusFd);
1166 OrderResult res = DoInstall(progress);
1167 delete progress;
1168 return res;
1169 }
1170 /*}}}*/
1171 // PM::DoInstall - Does the installation /*{{{*/
1172 // ---------------------------------------------------------------------
1173 /* This uses the filenames in FileNames and the information in the
1174 DepCache to perform the installation of packages.*/
1175 pkgPackageManager::OrderResult
1176 pkgPackageManager::DoInstall(APT::Progress::PackageManager *progress)
1177 {
1178 if(DoInstallPreFork() == Failed)
1179 return Failed;
1180
1181 return DoInstallPostFork(progress);
1182 }
1183 /*}}}*/