"Fossies" - the Fresh Open Source Software Archive

Member "apt-1.9.4/cmdline/apt-mark.cc" (19 Sep 2019, 15971 Bytes) of package /linux/misc/apt-1.9.4.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "apt-mark.cc" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 1.8.2_vs_1.9.2.

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