statechanges.cc 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  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>
  7. #include <algorithm>
  8. #include <memory>
  9. namespace APT
  10. {
  11. class StateChanges::Private
  12. {
  13. public:
  14. APT::VersionVector hold;
  15. APT::VersionVector unhold;
  16. APT::VersionVector install;
  17. APT::VersionVector deinstall;
  18. APT::VersionVector purge;
  19. APT::VersionVector error;
  20. };
  21. #define APT_GETTERSETTER(Name, Container) \
  22. void StateChanges::Name(pkgCache::VerIterator const &Ver) \
  23. { \
  24. if (Ver.end() == false) \
  25. Container.push_back(Ver); \
  26. }\
  27. APT::VersionVector& StateChanges::Name() \
  28. { \
  29. return Container; \
  30. }
  31. APT_GETTERSETTER(Hold, d->hold)
  32. APT_GETTERSETTER(Unhold, d->unhold)
  33. APT_GETTERSETTER(Install, d->install)
  34. APT_GETTERSETTER(Remove, d->deinstall)
  35. APT_GETTERSETTER(Purge, d->purge)
  36. #undef APT_GETTERSETTER
  37. APT::VersionVector& StateChanges::Error()
  38. {
  39. return d->error;
  40. }
  41. void StateChanges::clear()
  42. {
  43. d->hold.clear();
  44. d->unhold.clear();
  45. d->install.clear();
  46. d->deinstall.clear();
  47. d->purge.clear();
  48. d->error.clear();
  49. }
  50. bool StateChanges::empty() const
  51. {
  52. return d->hold.empty() &&
  53. d->unhold.empty() &&
  54. d->install.empty() &&
  55. d->deinstall.empty() &&
  56. d->purge.empty() &&
  57. d->error.empty();
  58. }
  59. bool StateChanges::Save(bool const DiscardOutput)
  60. {
  61. bool const Debug = _config->FindB("Debug::pkgDpkgPm", false);
  62. d->error.clear();
  63. if (d->hold.empty() && d->unhold.empty() && d->install.empty() && d->deinstall.empty() && d->purge.empty())
  64. return true;
  65. std::vector<std::string> Args = debSystem::GetDpkgBaseCommand();
  66. // ensure dpkg knows about the package so that it keeps the status we set
  67. if (d->hold.empty() == false || d->install.empty() == false)
  68. {
  69. APT::VersionVector makeDpkgAvailable;
  70. auto const notInstalled = [](pkgCache::VerIterator const &V) { return V.ParentPkg()->CurrentVer == 0; };
  71. std::copy_if(d->hold.begin(), d->hold.end(), std::back_inserter(makeDpkgAvailable), notInstalled);
  72. std::copy_if(d->install.begin(), d->install.end(), std::back_inserter(makeDpkgAvailable), notInstalled);
  73. if (makeDpkgAvailable.empty() == false)
  74. {
  75. auto const BaseArgs = Args.size();
  76. Args.push_back("--merge-avail");
  77. // FIXME: supported only since 1.17.7 in dpkg
  78. Args.push_back("-");
  79. int dummyAvail = -1;
  80. if (Debug)
  81. {
  82. for (auto const &V: makeDpkgAvailable)
  83. {
  84. std::clog << "echo 'Dummy record for " << V.ParentPkg().FullName(false) << "' | ";
  85. std::copy(Args.begin(), Args.end(), std::ostream_iterator<std::string>(std::clog, " "));
  86. std::clog << std::endl;
  87. }
  88. }
  89. else
  90. {
  91. pid_t const dpkgMergeAvail = debSystem::ExecDpkg(Args, &dummyAvail, nullptr, true);
  92. FILE* dpkg = fdopen(dummyAvail, "w");
  93. for (auto const &V: makeDpkgAvailable)
  94. fprintf(dpkg, "Package: %s\nVersion: 0~\nArchitecture: %s\nMaintainer: Dummy Example <dummy@example.org>\n"
  95. "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());
  96. fclose(dpkg);
  97. ExecWait(dpkgMergeAvail, "dpkg --merge-avail", true);
  98. }
  99. Args.erase(Args.begin() + BaseArgs, Args.end());
  100. }
  101. }
  102. bool const dpkgMultiArch = _system->MultiArchSupported();
  103. Args.push_back("--set-selections");
  104. if (Debug)
  105. {
  106. std::string state;
  107. auto const dpkgName = [&](pkgCache::VerIterator const &V) {
  108. pkgCache::PkgIterator P = V.ParentPkg();
  109. if (strcmp(V.Arch(), "none") == 0)
  110. ioprintf(std::clog, "echo '%s %s' | ", P.Name(), state.c_str());
  111. else if (dpkgMultiArch == false)
  112. ioprintf(std::clog, "echo '%s %s' | ", P.FullName(true).c_str(), state.c_str());
  113. else
  114. ioprintf(std::clog, "echo '%s:%s %s' | ", P.Name(), V.Arch(), state.c_str());
  115. std::copy(Args.begin(), Args.end(), std::ostream_iterator<std::string>(std::clog, " "));
  116. std::clog << std::endl;
  117. };
  118. for (auto const &V: d->unhold)
  119. {
  120. if (V.ParentPkg()->CurrentVer != 0)
  121. state = "install";
  122. else
  123. state = "deinstall";
  124. dpkgName(V);
  125. }
  126. if (d->purge.empty() == false)
  127. {
  128. state = "purge";
  129. std::for_each(d->purge.begin(), d->purge.end(), dpkgName);
  130. }
  131. if (d->deinstall.empty() == false)
  132. {
  133. state = "deinstall";
  134. std::for_each(d->deinstall.begin(), d->deinstall.end(), dpkgName);
  135. }
  136. if (d->hold.empty() == false)
  137. {
  138. state = "hold";
  139. std::for_each(d->hold.begin(), d->hold.end(), dpkgName);
  140. }
  141. if (d->install.empty() == false)
  142. {
  143. state = "install";
  144. std::for_each(d->install.begin(), d->install.end(), dpkgName);
  145. }
  146. }
  147. else
  148. {
  149. int selections = -1;
  150. pid_t const dpkgSelections = debSystem::ExecDpkg(Args, &selections, nullptr, DiscardOutput);
  151. FILE* dpkg = fdopen(selections, "w");
  152. std::string state;
  153. auto const dpkgName = [&](pkgCache::VerIterator const &V) {
  154. pkgCache::PkgIterator P = V.ParentPkg();
  155. if (strcmp(V.Arch(), "none") == 0)
  156. fprintf(dpkg, "%s %s\n", P.Name(), state.c_str());
  157. else if (dpkgMultiArch == false)
  158. fprintf(dpkg, "%s %s\n", P.FullName(true).c_str(), state.c_str());
  159. else
  160. fprintf(dpkg, "%s:%s %s\n", P.Name(), V.Arch(), state.c_str());
  161. };
  162. for (auto const &V: d->unhold)
  163. {
  164. if (V.ParentPkg()->CurrentVer != 0)
  165. state = "install";
  166. else
  167. state = "deinstall";
  168. dpkgName(V);
  169. }
  170. if (d->purge.empty() == false)
  171. {
  172. state = "purge";
  173. std::for_each(d->purge.begin(), d->purge.end(), dpkgName);
  174. }
  175. if (d->deinstall.empty() == false)
  176. {
  177. state = "deinstall";
  178. std::for_each(d->deinstall.begin(), d->deinstall.end(), dpkgName);
  179. }
  180. if (d->hold.empty() == false)
  181. {
  182. state = "hold";
  183. std::for_each(d->hold.begin(), d->hold.end(), dpkgName);
  184. }
  185. if (d->install.empty() == false)
  186. {
  187. state = "install";
  188. std::for_each(d->install.begin(), d->install.end(), dpkgName);
  189. }
  190. fclose(dpkg);
  191. if (ExecWait(dpkgSelections, "dpkg --set-selections") == false)
  192. {
  193. std::move(d->purge.begin(), d->purge.end(), std::back_inserter(d->error));
  194. d->purge.clear();
  195. std::move(d->deinstall.begin(), d->deinstall.end(), std::back_inserter(d->error));
  196. d->deinstall.clear();
  197. std::move(d->hold.begin(), d->hold.end(), std::back_inserter(d->error));
  198. d->hold.clear();
  199. std::move(d->unhold.begin(), d->unhold.end(), std::back_inserter(d->error));
  200. d->unhold.clear();
  201. std::move(d->install.begin(), d->install.end(), std::back_inserter(d->error));
  202. d->install.clear();
  203. }
  204. }
  205. return d->error.empty();
  206. }
  207. StateChanges::StateChanges() : d(new StateChanges::Private()) {}
  208. StateChanges::StateChanges(StateChanges&&) = default;
  209. StateChanges& StateChanges::operator=(StateChanges&&) = default;
  210. StateChanges::~StateChanges() = default;
  211. }