1 #include <apt-pkg/pkgcache.h> 
   2 #include <apt-pkg/cacheset.h> 
   3 #include <apt-pkg/debsystem.h> 
   4 #include <apt-pkg/fileutl.h> 
   5 #include <apt-pkg/statechanges.h> 
   6 #include <apt-pkg/prettyprinters.h> 
  14 class StateChanges::Private
 
  17    APT::VersionVector hold
; 
  18    APT::VersionVector unhold
; 
  19    APT::VersionVector install
; 
  20    APT::VersionVector deinstall
; 
  21    APT::VersionVector purge
; 
  22    APT::VersionVector error
; 
  25 #define APT_GETTERSETTER(Name, Container) \ 
  26 void StateChanges::Name(pkgCache::VerIterator const &Ver) \ 
  28    Container.push_back(Ver); \ 
  30 APT::VersionVector& StateChanges::Name() \ 
  34 APT_GETTERSETTER(Hold
, d
->hold
) 
  35 APT_GETTERSETTER(Unhold
, d
->unhold
) 
  36 APT_GETTERSETTER(Install
, d
->install
) 
  37 APT_GETTERSETTER(Remove
, d
->deinstall
) 
  38 APT_GETTERSETTER(Purge
, d
->purge
) 
  39 #undef APT_GETTERSETTER 
  40 APT::VersionVector
& StateChanges::Error() 
  45 void StateChanges::clear() 
  55 bool StateChanges::empty() const 
  57    return d
->hold
.empty() && 
  60       d
->deinstall
.empty() && 
  65 bool StateChanges::Save(bool const DiscardOutput
) 
  67    bool const Debug 
= _config
->FindB("Debug::pkgDpkgPm", false); 
  69    if (d
->hold
.empty() && d
->unhold
.empty() && d
->install
.empty() && d
->deinstall
.empty() && d
->purge
.empty()) 
  72    std::vector
<std::string
> Args 
= debSystem::GetDpkgBaseCommand(); 
  73    // ensure dpkg knows about the package so that it keeps the status we set 
  74    if (d
->hold
.empty() == false || d
->install
.empty() == false) 
  76       APT::VersionVector makeDpkgAvailable
; 
  77       auto const notInstalled 
= [](pkgCache::VerIterator 
const &V
) { return V
.ParentPkg()->CurrentVer 
== 0; }; 
  78       std::copy_if(d
->hold
.begin(), d
->hold
.end(), std::back_inserter(makeDpkgAvailable
), notInstalled
); 
  79       std::copy_if(d
->install
.begin(), d
->install
.end(), std::back_inserter(makeDpkgAvailable
), notInstalled
); 
  81       if (makeDpkgAvailable
.empty() == false) 
  83          auto const BaseArgs 
= Args
.size(); 
  84          Args
.push_back("--merge-avail"); 
  85          // FIXME: supported only since 1.17.7 in dpkg 
  90             for (auto const &V
: makeDpkgAvailable
) 
  92                std::clog 
<< "echo 'Dummy record for " << V
.ParentPkg().FullName(false) << "' | "; 
  93                std::copy(Args
.begin(), Args
.end(), std::ostream_iterator
<std::string
>(std::clog
, " ")); 
  94                std::clog 
<< std::endl
; 
  99             pid_t 
const dpkgMergeAvail 
= debSystem::ExecDpkg(Args
, &dummyAvail
, nullptr, true); 
 101             FILE* dpkg 
= fdopen(dummyAvail
, "w"); 
 102             for (auto const &V
: makeDpkgAvailable
) 
 103                fprintf(dpkg
, "Package: %s\nVersion: 0~\nArchitecture: %s\nMaintainer: Dummy Example <dummy@example.org>\n" 
 104                      "Description: dummy package record\n A record is needed to put a package on hold, so here it is.\n\n", V
.ParentPkg().Name(), V
.Arch()); 
 107             ExecWait(dpkgMergeAvail
, "dpkg --merge-avail", true); 
 109          Args
.erase(Args
.begin() + BaseArgs
, Args
.end()); 
 112    bool const dpkgMultiArch 
= _system
->MultiArchSupported(); 
 114    Args
.push_back("--set-selections"); 
 118       auto const dpkgName 
= [&](pkgCache::VerIterator 
const &V
) { 
 119          pkgCache::PkgIterator P 
= V
.ParentPkg(); 
 120          if (strcmp(V
.Arch(), "none") == 0) 
 121             ioprintf(std::clog
, "echo '%s %s' | ", P
.Name(), state
.c_str()); 
 122          else if (dpkgMultiArch 
== false) 
 123             ioprintf(std::clog
, "echo '%s %s' | ", P
.FullName(true).c_str(), state
.c_str()); 
 125             ioprintf(std::clog
, "echo '%s:%s %s' | ", P
.Name(), V
.Arch(), state
.c_str()); 
 126          std::copy(Args
.begin(), Args
.end(), std::ostream_iterator
<std::string
>(std::clog
, " ")); 
 127          std::clog 
<< std::endl
; 
 129       for (auto const &V
: d
->unhold
) 
 131          if (V
.ParentPkg()->CurrentVer 
!= 0) 
 137       if (d
->purge
.empty() == false) 
 140          std::for_each(d
->purge
.begin(), d
->purge
.end(), dpkgName
); 
 142       if (d
->deinstall
.empty() == false) 
 145          std::for_each(d
->deinstall
.begin(), d
->deinstall
.end(), dpkgName
); 
 147       if (d
->hold
.empty() == false) 
 150          std::for_each(d
->hold
.begin(), d
->hold
.end(), dpkgName
); 
 152       if (d
->install
.empty() == false) 
 155          std::for_each(d
->install
.begin(), d
->install
.end(), dpkgName
); 
 161       pid_t 
const dpkgSelections 
= debSystem::ExecDpkg(Args
, &selections
, nullptr, DiscardOutput
); 
 163       FILE* dpkg 
= fdopen(selections
, "w"); 
 165       auto const dpkgName 
= [&](pkgCache::VerIterator 
const &V
) { 
 166          pkgCache::PkgIterator P 
= V
.ParentPkg(); 
 167          if (strcmp(V
.Arch(), "none") == 0) 
 168             fprintf(dpkg
, "%s %s\n", P
.Name(), state
.c_str()); 
 169          else if (dpkgMultiArch 
== false) 
 170             fprintf(dpkg
, "%s %s\n", P
.FullName(true).c_str(), state
.c_str()); 
 172             fprintf(dpkg
, "%s:%s %s\n", P
.Name(), V
.Arch(), state
.c_str()); 
 174       for (auto const &V
: d
->unhold
) 
 176          if (V
.ParentPkg()->CurrentVer 
!= 0) 
 182       if (d
->purge
.empty() == false) 
 185          std::for_each(d
->purge
.begin(), d
->purge
.end(), dpkgName
); 
 187       if (d
->deinstall
.empty() == false) 
 190          std::for_each(d
->deinstall
.begin(), d
->deinstall
.end(), dpkgName
); 
 192       if (d
->hold
.empty() == false) 
 195          std::for_each(d
->hold
.begin(), d
->hold
.end(), dpkgName
); 
 197       if (d
->install
.empty() == false) 
 200          std::for_each(d
->install
.begin(), d
->install
.end(), dpkgName
); 
 204       if (ExecWait(dpkgSelections
, "dpkg --set-selections") == false) 
 206          std::move(d
->purge
.begin(), d
->purge
.end(), std::back_inserter(d
->error
)); 
 208          std::move(d
->deinstall
.begin(), d
->deinstall
.end(), std::back_inserter(d
->error
)); 
 209          d
->deinstall
.clear(); 
 210          std::move(d
->hold
.begin(), d
->hold
.end(), std::back_inserter(d
->error
)); 
 212          std::move(d
->unhold
.begin(), d
->unhold
.end(), std::back_inserter(d
->error
)); 
 214          std::move(d
->install
.begin(), d
->install
.end(), std::back_inserter(d
->error
)); 
 218    return d
->error
.empty(); 
 221 StateChanges::StateChanges() : d(new StateChanges::Private()) {} 
 222 StateChanges::StateChanges(StateChanges
&&) = default; 
 223 StateChanges
& StateChanges::operator=(StateChanges
&&) = default; 
 224 StateChanges::~StateChanges() = default;