apt  2.2.4
About: Apt (Advanced Package Tool) is a management system for software packages (Debian/Ubuntu). Release series 2.2.
  Fossies Dox: apt-2.2.4.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

apt-mark.cc
Go to the documentation of this file.
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 /* #####################################################################
4  apt-mark - show and change auto-installed bit information
5  ##################################################################### */
6  /*}}}*/
7 // Include Files /*{{{*/
8 #include <config.h>
9 
10 #include <apt-pkg/cachefile.h>
11 #include <apt-pkg/cacheset.h>
12 #include <apt-pkg/cmndline.h>
13 #include <apt-pkg/configuration.h>
14 #include <apt-pkg/depcache.h>
15 #include <apt-pkg/error.h>
16 #include <apt-pkg/fileutl.h>
17 #include <apt-pkg/init.h>
18 #include <apt-pkg/macros.h>
19 #include <apt-pkg/pkgcache.h>
20 #include <apt-pkg/pkgsystem.h>
21 #include <apt-pkg/statechanges.h>
22 #include <apt-pkg/strutl.h>
23 
27 
28 #include <algorithm>
29 #include <fstream>
30 #include <iostream>
31 #include <string>
32 #include <vector>
33 #include <errno.h>
34 #include <fcntl.h>
35 #include <stddef.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <sys/wait.h>
40 #include <unistd.h>
41 
42 #include <apti18n.h>
43  /*}}}*/
44 using namespace std;
45 
46 /* DoAuto - mark packages as automatically/manually installed {{{*/
47 static bool DoAuto(CommandLine &CmdL)
48 {
50  pkgDepCache * const DepCache = CacheFile.GetDepCache();
51  if (unlikely(DepCache == nullptr))
52  return false;
53 
55  if (pkgset.empty() == true)
56  return _error->Error(_("No packages found"));
57 
58  bool MarkAuto = strcasecmp(CmdL.FileList[0],"auto") == 0;
59 
60  vector<string> PackagesMarked;
61 
62  for (APT::PackageList::const_iterator Pkg = pkgset.begin(); Pkg != pkgset.end(); ++Pkg)
63  {
64  if (Pkg->CurrentVer == 0)
65  {
66  ioprintf(c1out,_("%s can not be marked as it is not installed.\n"), Pkg.FullName(true).c_str());
67  continue;
68  }
69  else if ((((*DepCache)[Pkg].Flags & pkgCache::Flag::Auto) == pkgCache::Flag::Auto) == MarkAuto)
70  {
71  if (MarkAuto == false)
72  ioprintf(c1out,_("%s was already set to manually installed.\n"), Pkg.FullName(true).c_str());
73  else
74  ioprintf(c1out,_("%s was already set to automatically installed.\n"), Pkg.FullName(true).c_str());
75  continue;
76  }
77 
78  PackagesMarked.push_back(Pkg.FullName(true));
79  DepCache->MarkAuto(Pkg, MarkAuto);
80  }
81 
82  bool MarkWritten = false;
83  bool IsSimulation = _config->FindB("APT::Mark::Simulate", false);
84  if (PackagesMarked.size() > 0 && !IsSimulation) {
85  MarkWritten = DepCache->writeStateFile(NULL);
86  if(!MarkWritten) {
87  return MarkWritten;
88  }
89  }
90 
91  if(IsSimulation || MarkWritten) {
92  for (vector<string>::const_iterator I = PackagesMarked.begin(); I != PackagesMarked.end(); ++I) {
93  if (MarkAuto == false)
94  ioprintf(c1out,_("%s set to manually installed.\n"), (*I).c_str());
95  else
96  ioprintf(c1out,_("%s set to automatically installed.\n"), (*I).c_str());
97  }
98  }
99  return true;
100 }
101  /*}}}*/
102 /* DoMarkAuto - mark packages as automatically/manually installed {{{*/
103 /* Does the same as DoAuto but tries to do it exactly the same why as
104  the python implementation did it so it can be a drop-in replacement */
105 static bool DoMarkAuto(CommandLine &CmdL)
106 {
108  pkgDepCache * const DepCache = CacheFile.GetDepCache();
109  if (unlikely(DepCache == nullptr))
110  return false;
111 
113  if (pkgset.empty() == true)
114  return _error->Error(_("No packages found"));
115 
116  bool const MarkAuto = strcasecmp(CmdL.FileList[0],"markauto") == 0;
117  bool const Verbose = _config->FindB("APT::MarkAuto::Verbose", false);
118  int AutoMarkChanged = 0;
119 
120  for (APT::PackageList::const_iterator Pkg = pkgset.begin(); Pkg != pkgset.end(); ++Pkg)
121  {
122  if (Pkg->CurrentVer == 0 ||
123  (((*DepCache)[Pkg].Flags & pkgCache::Flag::Auto) == pkgCache::Flag::Auto) == MarkAuto)
124  continue;
125 
126  if (Verbose == true)
127  ioprintf(c1out, "changing %s to %d\n", Pkg.Name(), (MarkAuto == false) ? 0 : 1);
128 
129  DepCache->MarkAuto(Pkg, MarkAuto);
130  ++AutoMarkChanged;
131  }
132  if (AutoMarkChanged > 0 && _config->FindB("APT::Mark::Simulate", false) == false)
133  return DepCache->writeStateFile(NULL);
134 
135  _error->Notice(_("This command is deprecated. Please use 'apt-mark auto' and 'apt-mark manual' instead."));
136 
137  return true;
138 }
139  /*}}}*/
140 // helper for Install-Recommends-Sections and Never-MarkAuto-Sections /*{{{*/
141 static bool
142 ConfigValueInSubTree(const char *SubTree, const char *needle)
143 {
144  // copied from depcache.cc
145  Configuration::Item const *Opts;
146  Opts = _config->Tree(SubTree);
147  if (Opts != 0 && Opts->Child != 0)
148  {
149  Opts = Opts->Child;
150  for (; Opts != 0; Opts = Opts->Next)
151  {
152  if (Opts->Value.empty() == true)
153  continue;
154  if (strcmp(needle, Opts->Value.c_str()) == 0)
155  return true;
156  }
157  }
158  return false;
159 }
160  /*}}}*/
161 /* DoMinimize - minimize manually installed {{{*/
162 /* Traverses dependencies of meta packages and marks them as manually
163  * installed. */
164 static bool DoMinimize(CommandLine &CmdL)
165 {
166 
168  pkgDepCache *const DepCache = CacheFile.GetDepCache();
169  if (unlikely(DepCache == nullptr))
170  return false;
171 
172  if (CmdL.FileList[1] != nullptr)
173  return _error->Error(_("%s does not take any arguments"), "apt-mark minimize-manual");
174 
175  auto Debug = _config->FindB("Debug::AptMark::Minimize", false);
176  auto is_root = [&DepCache](pkgCache::PkgIterator const &pkg) {
177  auto ver = pkg.CurrentVer();
178  return ver.end() == false && ((*DepCache)[pkg].Flags & pkgCache::Flag::Auto) == 0 &&
179  ver->Section != 0 &&
180  ConfigValueInSubTree("APT::Never-MarkAuto-Sections", ver.Section());
181  };
182 
183  APT::PackageSet roots;
184  for (auto Pkg = DepCache->PkgBegin(); Pkg.end() == false; ++Pkg)
185  {
186  if (is_root(Pkg))
187  {
188  if (Debug)
189  std::clog << "Found root " << Pkg.Name() << std::endl;
190  roots.insert(Pkg);
191  }
192  }
193 
194  APT::PackageSet workset(roots);
195  APT::PackageSet seen;
196  APT::PackageSet changed;
197 
198  pkgDepCache::ActionGroup group(*DepCache);
199 
200  while (workset.empty() == false)
201  {
202  if (Debug)
203  std::clog << "Iteration\n";
204 
205  APT::PackageSet workset2;
206  for (auto &Pkg : workset)
207  {
208  if (seen.find(Pkg) != seen.end())
209  continue;
210 
211  seen.insert(Pkg);
212 
213  if (Debug)
214  std::cerr << " Visiting " << Pkg.FullName(true) << "\n";
215  if (roots.find(Pkg) == roots.end() && ((*DepCache)[Pkg].Flags & pkgCache::Flag::Auto) == 0)
216  {
217  DepCache->MarkAuto(Pkg, true);
218  changed.insert(Pkg);
219  }
220 
221  // Visit dependencies, add them to next working set
222  for (auto Dep = Pkg.CurrentVer().DependsList(); !Dep.end(); ++Dep)
223  {
224  if (DepCache->IsImportantDep(Dep) == false)
225  continue;
226  std::unique_ptr<pkgCache::Version *[]> targets(Dep.AllTargets());
227  for (int i = 0; targets[i] != nullptr; i++)
228  {
229  pkgCache::VerIterator Tgt(*DepCache, targets[i]);
230  if (Tgt.ParentPkg()->CurrentVer != 0 && Tgt.ParentPkg().CurrentVer()->ID == Tgt->ID)
231  workset2.insert(Tgt.ParentPkg());
232  }
233  }
234  }
235 
236  workset = std::move(workset2);
237  }
238 
239  if (changed.empty()) {
240  cout << _("No changes necessary") << endl;
241  return true;
242  }
243 
244  ShowList(c1out, _("The following packages will be marked as automatically installed:"), changed,
245  [](const pkgCache::PkgIterator &) { return true; },
247  &PrettyFullName);
248 
249  if (_config->FindB("APT::Mark::Simulate", false) == false)
250  {
251  if (YnPrompt(_("Do you want to continue?"), false) == false)
252  return true;
253 
254  return DepCache->writeStateFile(NULL);
255  }
256 
257  return true;
258 }
259  /*}}}*/
260 
261 /* ShowAuto - show automatically installed packages (sorted) {{{*/
262 static bool ShowAuto(CommandLine &CmdL)
263 {
265  pkgDepCache * const DepCache = CacheFile.GetDepCache();
266  if (unlikely(DepCache == nullptr))
267  return false;
268 
269  std::vector<string> packages;
270 
271  bool const ShowAuto = strcasecmp(CmdL.FileList[0],"showauto") == 0;
272 
273  if (CmdL.FileList[1] == 0)
274  {
275  packages.reserve(DepCache->Head().PackageCount / 3);
276  for (pkgCache::PkgIterator P = DepCache->PkgBegin(); P.end() == false; ++P)
277  if (P->CurrentVer != 0 &&
278  (((*DepCache)[P].Flags & pkgCache::Flag::Auto) == pkgCache::Flag::Auto) == ShowAuto)
279  packages.push_back(P.FullName(true));
280  }
281  else
282  {
283  APT::CacheSetHelper helper(false); // do not show errors
285  packages.reserve(pkgset.size());
286  for (APT::PackageSet::const_iterator P = pkgset.begin(); P != pkgset.end(); ++P)
287  if (P->CurrentVer != 0 &&
288  (((*DepCache)[P].Flags & pkgCache::Flag::Auto) == pkgCache::Flag::Auto) == ShowAuto)
289  packages.push_back(P.FullName(true));
290  }
291 
292  std::sort(packages.begin(), packages.end());
293 
294  for (vector<string>::const_iterator I = packages.begin(); I != packages.end(); ++I)
295  std::cout << *I << std::endl;
296 
297  return true;
298 }
299  /*}}}*/
300 // DoSelection - wrapping around dpkg selections /*{{{*/
301 static bool DoSelection(CommandLine &CmdL)
302 {
304  pkgCache * const Cache = CacheFile.GetPkgCache();
305  if (unlikely(Cache == nullptr))
306  return false;
307 
309  if (pkgset.empty() == true)
310  return _error->Error(_("No packages found"));
311 
312  APT::StateChanges marks;
313  if (strcasecmp(CmdL.FileList[0], "hold") == 0 || strcasecmp(CmdL.FileList[0], "unhold") == 0)
314  {
315  auto const part = std::stable_partition(pkgset.begin(), pkgset.end(),
316  [](pkgCache::VerIterator const &V) { return V.ParentPkg()->SelectedState == pkgCache::State::Hold; });
317 
318  bool const MarkHold = strcasecmp(CmdL.FileList[0],"hold") == 0;
319  auto const doneBegin = MarkHold ? pkgset.begin() : part;
320  auto const doneEnd = MarkHold ? part : pkgset.end();
321  std::for_each(doneBegin, doneEnd, [&MarkHold](pkgCache::VerIterator const &V) {
322  if (MarkHold == true)
323  ioprintf(c1out, _("%s was already set on hold.\n"), V.ParentPkg().FullName(true).c_str());
324  else
325  ioprintf(c1out, _("%s was already not hold.\n"), V.ParentPkg().FullName(true).c_str());
326  });
327 
328  if (doneBegin == pkgset.begin() && doneEnd == pkgset.end())
329  return true;
330 
331  auto const changeBegin = MarkHold ? part : pkgset.begin();
332  auto const changeEnd = MarkHold ? pkgset.end() : part;
333  std::move(changeBegin, changeEnd, std::back_inserter(MarkHold ? marks.Hold() : marks.Unhold()));
334  }
335  else
336  {
337  // FIXME: Maybe show a message for unchanged states here as well?
338  if (strcasecmp(CmdL.FileList[0], "purge") == 0)
339  std::swap(marks.Purge(), pkgset);
340  else if (strcasecmp(CmdL.FileList[0], "deinstall") == 0 || strcasecmp(CmdL.FileList[0], "remove") == 0)
341  std::swap(marks.Remove(), pkgset);
342  else //if (strcasecmp(CmdL.FileList[0], "install") == 0)
343  std::swap(marks.Install(), pkgset);
344  }
345  pkgset.clear();
346 
347  bool success = true;
348  if (_config->FindB("APT::Mark::Simulate", false) == false)
349  {
350  success = marks.Save();
351  if (success == false)
352  _error->Error(_("Executing dpkg failed. Are you root?"));
353  }
354  for (auto Ver : marks.Hold())
355  ioprintf(c1out,_("%s set on hold.\n"), Ver.ParentPkg().FullName(true).c_str());
356  for (auto Ver : marks.Unhold())
357  ioprintf(c1out,_("Canceled hold on %s.\n"), Ver.ParentPkg().FullName(true).c_str());
358  for (auto Ver : marks.Purge())
359  ioprintf(c1out,_("Selected %s for purge.\n"), Ver.ParentPkg().FullName(true).c_str());
360  for (auto Ver : marks.Remove())
361  ioprintf(c1out,_("Selected %s for removal.\n"), Ver.ParentPkg().FullName(true).c_str());
362  for (auto Ver : marks.Install())
363  ioprintf(c1out,_("Selected %s for installation.\n"), Ver.ParentPkg().FullName(true).c_str());
364  return success;
365 }
366  /*}}}*/
367 static bool ShowSelection(CommandLine &CmdL) /*{{{*/
368 {
370  pkgCache * const Cache = CacheFile.GetPkgCache();
371  if (unlikely(Cache == nullptr))
372  return false;
373 
375  if (strncasecmp(CmdL.FileList[0], "showpurge", strlen("showpurge")) == 0)
376  selector = pkgCache::State::Purge;
377  else if (strncasecmp(CmdL.FileList[0], "showdeinstall", strlen("showdeinstall")) == 0 ||
378  strncasecmp(CmdL.FileList[0], "showremove", strlen("showremove")) == 0)
379  selector = pkgCache::State::DeInstall;
380  else if (strncasecmp(CmdL.FileList[0], "showhold", strlen("showhold")) == 0 || strncasecmp(CmdL.FileList[0], "showheld", strlen("showheld")) == 0)
381  selector = pkgCache::State::Hold;
382  else //if (strcasecmp(CmdL.FileList[0], "showinstall", strlen("showinstall")) == 0)
383  selector = pkgCache::State::Install;
384 
385  std::vector<string> packages;
386 
387  if (CmdL.FileList[1] == 0)
388  {
389  packages.reserve(50); // how many holds are realistic? I hope just a few…
390  for (pkgCache::PkgIterator P = Cache->PkgBegin(); P.end() == false; ++P)
391  if (P->SelectedState == selector)
392  packages.push_back(P.FullName(true));
393  }
394  else
395  {
396  APT::CacheSetHelper helper(false); // do not show errors
398  packages.reserve(pkgset.size());
399  for (APT::PackageSet::const_iterator P = pkgset.begin(); P != pkgset.end(); ++P)
400  if (P->SelectedState == selector)
401  packages.push_back(P.FullName(true));
402  }
403 
404  std::sort(packages.begin(), packages.end());
405 
406  for (vector<string>::const_iterator I = packages.begin(); I != packages.end(); ++I)
407  std::cout << *I << std::endl;
408 
409  return true;
410 }
411  /*}}}*/
412 static bool ShowHelp(CommandLine &) /*{{{*/
413 {
414  std::cout <<
415  _("Usage: apt-mark [options] {auto|manual} pkg1 [pkg2 ...]\n"
416  "\n"
417  "apt-mark is a simple command line interface for marking packages\n"
418  "as manually or automatically installed. It can also be used to\n"
419  "manipulate the dpkg(1) selection states of packages, and to list\n"
420  "all packages with or without a certain marking.\n");
421  return true;
422 }
423  /*}}}*/
424 static std::vector<aptDispatchWithHelp> GetCommands() /*{{{*/
425 {
426  return {
427  {"auto",&DoAuto, _("Mark the given packages as automatically installed")},
428  {"manual",&DoAuto, _("Mark the given packages as manually installed")},
429  {"minimize-manual", &DoMinimize, _("Mark all dependencies of meta packages as automatically installed.")},
430  {"hold",&DoSelection, _("Mark a package as held back")},
431  {"unhold",&DoSelection, _("Unset a package set as held back")},
432  {"install",&DoSelection, nullptr},
433  {"remove",&DoSelection, nullptr}, // dpkg uses deinstall, but we use remove everywhere else
434  {"deinstall",&DoSelection, nullptr},
435  {"purge",&DoSelection, nullptr},
436  {"showauto",&ShowAuto, _("Print the list of automatically installed packages")},
437  {"showmanual",&ShowAuto, _("Print the list of manually installed packages")},
438  {"showhold",&ShowSelection, _("Print the list of packages on hold")}, {"showholds",&ShowSelection, nullptr}, {"showheld",&ShowSelection, nullptr},
439  {"showinstall",&ShowSelection, nullptr}, {"showinstalls",&ShowSelection, nullptr},
440  {"showdeinstall",&ShowSelection, nullptr}, {"showdeinstalls",&ShowSelection, nullptr},
441  {"showremove",&ShowSelection, nullptr}, {"showremoves",&ShowSelection, nullptr},
442  {"showpurge",&ShowSelection, nullptr}, {"showpurges",&ShowSelection, nullptr},
443  // obsolete commands for compatibility
444  {"markauto", &DoMarkAuto, nullptr},
445  {"unmarkauto", &DoMarkAuto, nullptr},
446  {nullptr, nullptr, nullptr}
447  };
448 }
449  /*}}}*/
450 int main(int argc,const char *argv[]) /*{{{*/
451 {
452  CommandLine CmdL;
453  auto const Cmds = ParseCommandLine(CmdL, APT_CMD::APT_MARK, &_config, &_system, argc, argv, &ShowHelp, &GetCommands);
454 
455  InitOutput();
456 
457  return DispatchCommandLine(CmdL, Cmds);
458 }
459  /*}}}*/
static bool std::string const metaIndex const *const pkgAcqMetaClearSig *const pkgAcquire::Item *const I
static bool ShowHelp(CommandLine &)
Definition: apt-mark.cc:412
static bool ConfigValueInSubTree(const char *SubTree, const char *needle)
Definition: apt-mark.cc:142
static std::vector< aptDispatchWithHelp > GetCommands()
Definition: apt-mark.cc:424
static bool ShowAuto(CommandLine &CmdL)
Definition: apt-mark.cc:262
static bool DoAuto(CommandLine &CmdL)
Definition: apt-mark.cc:47
static bool DoMarkAuto(CommandLine &CmdL)
Definition: apt-mark.cc:105
static bool DoMinimize(CommandLine &CmdL)
Definition: apt-mark.cc:164
static bool ShowSelection(CommandLine &CmdL)
Definition: apt-mark.cc:367
static bool DoSelection(CommandLine &CmdL)
Definition: apt-mark.cc:301
int main(int argc, const char *argv[])
Definition: apt-mark.cc:450
const_iterator find(pkgCache::PkgIterator const &P) const
Definition: cacheset.h:385
bool empty() const APT_OVERRIDE
Definition: cacheset.h:361
size_t size() const APT_OVERRIDE
Definition: cacheset.h:363
const_iterator begin() const
Definition: cacheset.h:371
bool insert(pkgCache::PkgIterator const &P) APT_OVERRIDE
Definition: cacheset.h:357
static PackageContainer FromCommandLine(pkgCacheFile &Cache, const char **cmdline, CacheSetHelper &helper)
returns all packages specified on the commandline
Definition: cacheset.h:478
const_iterator end() const
Definition: cacheset.h:372
APT::VersionVector & Purge()
Definition: statechanges.cc:41
APT::VersionVector & Install()
Definition: statechanges.cc:39
APT::VersionVector & Hold()
Definition: statechanges.cc:37
bool Save(bool const DiscardOutput=false)
Definition: statechanges.cc:68
APT::VersionVector & Remove()
Definition: statechanges.cc:40
APT::VersionVector & Unhold()
Definition: statechanges.cc:38
bool empty() const APT_OVERRIDE
Definition: cacheset.h:815
const_iterator begin() const
Definition: cacheset.h:825
void clear() APT_OVERRIDE
Definition: cacheset.h:816
static VersionContainer FromCommandLine(pkgCacheFile &Cache, const char **cmdline, CacheSetHelper::VerSelector const fallback, CacheSetHelper &helper)
returns all versions specified on the commandline
Definition: cacheset.h:870
const_iterator end() const
Definition: cacheset.h:826
const char ** FileList
Definition: cmndline.h:78
pkgDepCache * GetDepCache()
Definition: cachefile.h:74
pkgCache * GetPkgCache()
Definition: cachefile.h:73
Represents an active action group.
Definition: depcache.h:166
void MarkAuto(const PkgIterator &Pkg, bool Auto)
Definition: depcache.cc:2066
PkgIterator PkgBegin()
Definition: depcache.h:356
bool IsImportantDep(DepIterator Dep) const
Definition: depcache.h:364
bool writeStateFile(OpProgress *const prog, bool const InstalledOnly=true)
Definition: depcache.cc:340
Header & Head()
Definition: depcache.h:354
Configuration * _config
pkgCache - Structure definitions for the cache file
pkgSystem * _system
Definition: pkgsystem.cc:24
std::vector< CommandLine::Dispatch > ParseCommandLine(CommandLine &CmdL, APT_CMD const Binary, Configuration *const *const Cnf, pkgSystem **const Sys, int const argc, const char *argv[], bool(*ShowHelp)(CommandLine &), std::vector< aptDispatchWithHelp >(*GetCommands)(void))
unsigned short DispatchCommandLine(CommandLine &CmdL, std::vector< CommandLine::Dispatch > const &Cmds)
bool YnPrompt(char const *const Question, bool const Default, bool const ShowGlobalErrors, std::ostream &c1o, std::ostream &c2o)
std::string PrettyFullName(pkgCache::PkgIterator const &Pkg)
bool InitOutput(std::basic_streambuf< char > *const out)
APT_PUBLIC std::ostream c1out
bool ShowList(std::ostream &out, std::string const &Title, Container const &cont, PredicateC Predicate, DisplayP PkgDisplay, DisplayV VerboseDisplay)
map_id_t PackageCount
Definition: pkgcache.h:335
void ioprintf(ostream &out, const char *format,...)
Definition: strutl.cc:1433