// -*- mode: cpp; mode: fold -*- // Description /*{{{*/ /* ##################################################################### apt-mark - show and change auto-installed bit information ##################################################################### */ /*}}}*/ // Include Files /*{{{*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /*}}}*/ using namespace std; /* DoAuto - mark packages as automatically/manually installed {{{*/ static bool DoAuto(CommandLine &CmdL) { pkgCacheFile CacheFile; pkgCache *Cache = CacheFile.GetPkgCache(); pkgDepCache *DepCache = CacheFile.GetDepCache(); if (unlikely(Cache == NULL || DepCache == NULL)) return false; APT::PackageList pkgset = APT::PackageList::FromCommandLine(CacheFile, CmdL.FileList + 1); if (pkgset.empty() == true) return _error->Error(_("No packages found")); bool MarkAuto = strcasecmp(CmdL.FileList[0],"auto") == 0; int AutoMarkChanged = 0; for (APT::PackageList::const_iterator Pkg = pkgset.begin(); Pkg != pkgset.end(); ++Pkg) { if (Pkg->CurrentVer == 0) { ioprintf(c1out,_("%s can not be marked as it is not installed.\n"), Pkg.FullName(true).c_str()); continue; } else if ((((*DepCache)[Pkg].Flags & pkgCache::Flag::Auto) == pkgCache::Flag::Auto) == MarkAuto) { if (MarkAuto == false) ioprintf(c1out,_("%s was already set to manually installed.\n"), Pkg.FullName(true).c_str()); else ioprintf(c1out,_("%s was already set to automatically installed.\n"), Pkg.FullName(true).c_str()); continue; } if (MarkAuto == false) ioprintf(c1out,_("%s set to manually installed.\n"), Pkg.FullName(true).c_str()); else ioprintf(c1out,_("%s set to automatically installed.\n"), Pkg.FullName(true).c_str()); DepCache->MarkAuto(Pkg, MarkAuto); ++AutoMarkChanged; } if (AutoMarkChanged > 0 && _config->FindB("APT::Mark::Simulate", false) == false) return DepCache->writeStateFile(NULL); return true; } /*}}}*/ /* DoMarkAuto - mark packages as automatically/manually installed {{{*/ /* Does the same as DoAuto but tries to do it exactly the same why as the python implementation did it so it can be a drop-in replacement */ static bool DoMarkAuto(CommandLine &CmdL) { pkgCacheFile CacheFile; pkgCache *Cache = CacheFile.GetPkgCache(); pkgDepCache *DepCache = CacheFile.GetDepCache(); if (unlikely(Cache == NULL || DepCache == NULL)) return false; APT::PackageList pkgset = APT::PackageList::FromCommandLine(CacheFile, CmdL.FileList + 1); if (pkgset.empty() == true) return _error->Error(_("No packages found")); bool const MarkAuto = strcasecmp(CmdL.FileList[0],"markauto") == 0; bool const Verbose = _config->FindB("APT::MarkAuto::Verbose", false); int AutoMarkChanged = 0; for (APT::PackageList::const_iterator Pkg = pkgset.begin(); Pkg != pkgset.end(); ++Pkg) { if (Pkg->CurrentVer == 0 || (((*DepCache)[Pkg].Flags & pkgCache::Flag::Auto) == pkgCache::Flag::Auto) == MarkAuto) continue; if (Verbose == true) ioprintf(c1out, "changing %s to %d\n", Pkg.Name(), (MarkAuto == false) ? 0 : 1); DepCache->MarkAuto(Pkg, MarkAuto); ++AutoMarkChanged; } if (AutoMarkChanged > 0 && _config->FindB("APT::Mark::Simulate", false) == false) return DepCache->writeStateFile(NULL); _error->Notice(_("This command is deprecated. Please use 'apt-mark auto' and 'apt-mark manual' instead.")); return true; } /*}}}*/ /* ShowAuto - show automatically installed packages (sorted) {{{*/ static bool ShowAuto(CommandLine &CmdL) { pkgCacheFile CacheFile; pkgCache *Cache = CacheFile.GetPkgCache(); pkgDepCache *DepCache = CacheFile.GetDepCache(); if (unlikely(Cache == NULL || DepCache == NULL)) return false; std::vector packages; bool const ShowAuto = strcasecmp(CmdL.FileList[0],"showauto") == 0; if (CmdL.FileList[1] == 0) { packages.reserve(Cache->HeaderP->PackageCount / 3); for (pkgCache::PkgIterator P = Cache->PkgBegin(); P.end() == false; ++P) if (P->CurrentVer != 0 && (((*DepCache)[P].Flags & pkgCache::Flag::Auto) == pkgCache::Flag::Auto) == ShowAuto) packages.push_back(P.FullName(true)); } else { APT::CacheSetHelper helper(false); // do not show errors APT::PackageSet pkgset = APT::PackageSet::FromCommandLine(CacheFile, CmdL.FileList + 1, helper); packages.reserve(pkgset.size()); for (APT::PackageSet::const_iterator P = pkgset.begin(); P != pkgset.end(); ++P) if (P->CurrentVer != 0 && (((*DepCache)[P].Flags & pkgCache::Flag::Auto) == pkgCache::Flag::Auto) == ShowAuto) packages.push_back(P.FullName(true)); } std::sort(packages.begin(), packages.end()); for (vector::const_iterator I = packages.begin(); I != packages.end(); ++I) std::cout << *I << std::endl; return true; } /*}}}*/ // DoSelection - wrapping around dpkg selections /*{{{*/ static bool DoSelection(CommandLine &CmdL) { pkgCacheFile CacheFile; pkgCache *Cache = CacheFile.GetPkgCache(); if (unlikely(Cache == NULL)) return false; APT::VersionVector pkgset = APT::VersionVector::FromCommandLine(CacheFile, CmdL.FileList + 1, APT::CacheSetHelper::INSTCAND); if (pkgset.empty() == true) return _error->Error(_("No packages found")); APT::StateChanges marks; if (strcasecmp(CmdL.FileList[0], "hold") == 0 || strcasecmp(CmdL.FileList[0], "unhold") == 0) { auto const part = std::stable_partition(pkgset.begin(), pkgset.end(), [](pkgCache::VerIterator const &V) { return V.ParentPkg()->SelectedState == pkgCache::State::Hold; }); bool const MarkHold = strcasecmp(CmdL.FileList[0],"hold") == 0; auto const doneBegin = MarkHold ? pkgset.begin() : part; auto const doneEnd = MarkHold ? part : pkgset.end(); std::for_each(doneBegin, doneEnd, [&MarkHold](pkgCache::VerIterator const &V) { if (MarkHold == true) ioprintf(c1out, _("%s was already set on hold.\n"), V.ParentPkg().FullName(true).c_str()); else ioprintf(c1out, _("%s was already not hold.\n"), V.ParentPkg().FullName(true).c_str()); }); if (doneBegin == pkgset.begin() && doneEnd == pkgset.end()) return true; auto const changeBegin = MarkHold ? part : pkgset.begin(); auto const changeEnd = MarkHold ? pkgset.end() : part; std::move(changeBegin, changeEnd, std::back_inserter(MarkHold ? marks.Hold() : marks.Unhold())); } else { // FIXME: Maybe show a message for unchanged states here as well? if (strcasecmp(CmdL.FileList[0], "purge") == 0) std::swap(marks.Purge(), pkgset); else if (strcasecmp(CmdL.FileList[0], "deinstall") == 0 || strcasecmp(CmdL.FileList[0], "remove") == 0) std::swap(marks.Remove(), pkgset); else //if (strcasecmp(CmdL.FileList[0], "install") == 0) std::swap(marks.Install(), pkgset); } pkgset.clear(); bool success = true; if (_config->FindB("APT::Mark::Simulate", false) == false) { success = marks.Save(); if (success == false) _error->Error(_("Executing dpkg failed. Are you root?")); } for (auto Ver : marks.Hold()) ioprintf(c1out,_("%s set on hold.\n"), Ver.ParentPkg().FullName(true).c_str()); for (auto Ver : marks.Unhold()) ioprintf(c1out,_("Canceled hold on %s.\n"), Ver.ParentPkg().FullName(true).c_str()); for (auto Ver : marks.Purge()) ioprintf(c1out,_("Selected %s for purge.\n"), Ver.ParentPkg().FullName(true).c_str()); for (auto Ver : marks.Remove()) ioprintf(c1out,_("Selected %s for removal.\n"), Ver.ParentPkg().FullName(true).c_str()); for (auto Ver : marks.Install()) ioprintf(c1out,_("Selected %s for installation.\n"), Ver.ParentPkg().FullName(true).c_str()); return success; } /*}}}*/ static bool ShowSelection(CommandLine &CmdL) /*{{{*/ { pkgCacheFile CacheFile; pkgCache *Cache = CacheFile.GetPkgCache(); if (unlikely(Cache == NULL)) return false; pkgCache::State::PkgSelectedState selector; if (strncasecmp(CmdL.FileList[0], "showpurge", strlen("showpurge")) == 0) selector = pkgCache::State::Purge; else if (strncasecmp(CmdL.FileList[0], "showdeinstall", strlen("showdeinstall")) == 0 || strncasecmp(CmdL.FileList[0], "showremove", strlen("showremove")) == 0) selector = pkgCache::State::DeInstall; else if (strncasecmp(CmdL.FileList[0], "showhold", strlen("showhold")) == 0) selector = pkgCache::State::Hold; else //if (strcasecmp(CmdL.FileList[0], "showinstall", strlen("showinstall")) == 0) selector = pkgCache::State::Install; std::vector packages; if (CmdL.FileList[1] == 0) { packages.reserve(50); // how many holds are realistic? I hope just a few… for (pkgCache::PkgIterator P = Cache->PkgBegin(); P.end() == false; ++P) if (P->SelectedState == selector) packages.push_back(P.FullName(true)); } else { APT::CacheSetHelper helper(false); // do not show errors APT::PackageSet pkgset = APT::PackageSet::FromCommandLine(CacheFile, CmdL.FileList + 1, helper); packages.reserve(pkgset.size()); for (APT::PackageSet::const_iterator P = pkgset.begin(); P != pkgset.end(); ++P) if (P->SelectedState == selector) packages.push_back(P.FullName(true)); } std::sort(packages.begin(), packages.end()); for (vector::const_iterator I = packages.begin(); I != packages.end(); ++I) std::cout << *I << std::endl; return true; } /*}}}*/ // ShowHelp - Show a help screen /*{{{*/ bool ShowHelp(CommandLine &, CommandLine::DispatchWithHelp const * Cmds) { ioprintf(std::cout, "%s %s (%s)\n", PACKAGE, PACKAGE_VERSION, COMMON_ARCH); std::cout << _("Usage: apt-mark [options] {auto|manual} pkg1 [pkg2 ...]\n" "\n" "apt-mark is a simple command line interface for marking packages\n" "as manually or automatically installed. It can also list marks.\n") << std::endl << _("Commands:") << std::endl; for (; Cmds->Handler != nullptr; ++Cmds) { if (Cmds->Help == nullptr) continue; std::cout << " " << Cmds->Match << " - " << Cmds->Help << std::endl; } std::cout << std::endl << _("Options:\n" " -h This help text.\n" " -q Loggable output - no progress indicator\n" " -qq No output except for errors\n" " -s No-act. Just prints what would be done.\n" " -f read/write auto/manual marking in the given file\n" " -c=? Read this configuration file\n" " -o=? Set an arbitrary configuration option, eg -o dir::cache=/tmp\n" "See the apt-mark(8) and apt.conf(5) manual pages for more information.") << std::endl; return true; } /*}}}*/ std::vector GetCommands() /*{{{*/ { return { {"auto",&DoAuto, _("Mark the given packages as automatically installed")}, {"manual",&DoAuto, _("Mark the given packages as manually installed")}, {"hold",&DoSelection, _("Mark a package as held back")}, {"unhold",&DoSelection, _("Unset a package set as held back")}, {"install",&DoSelection, nullptr}, {"remove",&DoSelection, nullptr}, // dpkg uses deinstall, but we use remove everywhere else {"deinstall",&DoSelection, nullptr}, {"purge",&DoSelection, nullptr}, {"showauto",&ShowAuto, _("Print the list of automatically installed packages")}, {"showmanual",&ShowAuto, _("Print the list of manually installed packages")}, {"showhold",&ShowSelection, _("Print the list of package on hold")}, {"showholds",&ShowSelection, nullptr}, {"showinstall",&ShowSelection, nullptr}, {"showinstalls",&ShowSelection, nullptr}, {"showdeinstall",&ShowSelection, nullptr}, {"showdeinstalls",&ShowSelection, nullptr}, {"showremove",&ShowSelection, nullptr}, {"showremoves",&ShowSelection, nullptr}, {"showpurge",&ShowSelection, nullptr}, {"showpurges",&ShowSelection, nullptr}, // obsolete commands for compatibility {"markauto", &DoMarkAuto, nullptr}, {"unmarkauto", &DoMarkAuto, nullptr}, {nullptr, nullptr, nullptr} }; } /*}}}*/ int main(int argc,const char *argv[]) /*{{{*/ { InitLocale(); CommandLine CmdL; auto const Cmds = ParseCommandLine(CmdL, APT_CMD::APT_MARK, &_config, &_system, argc, argv); InitOutput(); return DispatchCommandLine(CmdL, Cmds); } /*}}}*/