1 // -*- mode: cpp; mode: fold -*-
3 /* #####################################################################
4 apt-mark - show and change auto-installed bit information
5 ##################################################################### */
7 // Include Files /*{{{*/
10 #include <apt-pkg/cachefile.h>
11 #include <apt-pkg/cacheset.h>
12 #include <apt-pkg/cmndline.h>
13 #include <apt-pkg/error.h>
14 #include <apt-pkg/fileutl.h>
15 #include <apt-pkg/init.h>
16 #include <apt-pkg/pkgsystem.h>
17 #include <apt-pkg/strutl.h>
18 #include <apt-pkg/statechanges.h>
19 #include <apt-pkg/cacheiterators.h>
20 #include <apt-pkg/configuration.h>
21 #include <apt-pkg/depcache.h>
22 #include <apt-pkg/macros.h>
23 #include <apt-pkg/pkgcache.h>
25 #include <apt-private/private-cmndline.h>
26 #include <apt-private/private-output.h>
46 /* DoAuto - mark packages as automatically/manually installed {{{*/
47 static bool DoAuto(CommandLine
&CmdL
)
49 pkgCacheFile CacheFile
;
50 pkgCache
*Cache
= CacheFile
.GetPkgCache();
51 pkgDepCache
*DepCache
= CacheFile
.GetDepCache();
52 if (unlikely(Cache
== NULL
|| DepCache
== NULL
))
55 APT::PackageList pkgset
= APT::PackageList::FromCommandLine(CacheFile
, CmdL
.FileList
+ 1);
56 if (pkgset
.empty() == true)
57 return _error
->Error(_("No packages found"));
59 bool MarkAuto
= strcasecmp(CmdL
.FileList
[0],"auto") == 0;
60 int AutoMarkChanged
= 0;
62 for (APT::PackageList::const_iterator Pkg
= pkgset
.begin(); Pkg
!= pkgset
.end(); ++Pkg
)
64 if (Pkg
->CurrentVer
== 0)
66 ioprintf(c1out
,_("%s can not be marked as it is not installed.\n"), Pkg
.FullName(true).c_str());
69 else if ((((*DepCache
)[Pkg
].Flags
& pkgCache::Flag::Auto
) == pkgCache::Flag::Auto
) == MarkAuto
)
71 if (MarkAuto
== false)
72 ioprintf(c1out
,_("%s was already set to manually installed.\n"), Pkg
.FullName(true).c_str());
74 ioprintf(c1out
,_("%s was already set to automatically installed.\n"), Pkg
.FullName(true).c_str());
78 if (MarkAuto
== false)
79 ioprintf(c1out
,_("%s set to manually installed.\n"), Pkg
.FullName(true).c_str());
81 ioprintf(c1out
,_("%s set to automatically installed.\n"), Pkg
.FullName(true).c_str());
83 DepCache
->MarkAuto(Pkg
, MarkAuto
);
86 if (AutoMarkChanged
> 0 && _config
->FindB("APT::Mark::Simulate", false) == false)
87 return DepCache
->writeStateFile(NULL
);
91 /* DoMarkAuto - mark packages as automatically/manually installed {{{*/
92 /* Does the same as DoAuto but tries to do it exactly the same why as
93 the python implementation did it so it can be a drop-in replacement */
94 static bool DoMarkAuto(CommandLine
&CmdL
)
96 pkgCacheFile CacheFile
;
97 pkgCache
*Cache
= CacheFile
.GetPkgCache();
98 pkgDepCache
*DepCache
= CacheFile
.GetDepCache();
99 if (unlikely(Cache
== NULL
|| DepCache
== NULL
))
102 APT::PackageList pkgset
= APT::PackageList::FromCommandLine(CacheFile
, CmdL
.FileList
+ 1);
103 if (pkgset
.empty() == true)
104 return _error
->Error(_("No packages found"));
106 bool const MarkAuto
= strcasecmp(CmdL
.FileList
[0],"markauto") == 0;
107 bool const Verbose
= _config
->FindB("APT::MarkAuto::Verbose", false);
108 int AutoMarkChanged
= 0;
110 for (APT::PackageList::const_iterator Pkg
= pkgset
.begin(); Pkg
!= pkgset
.end(); ++Pkg
)
112 if (Pkg
->CurrentVer
== 0 ||
113 (((*DepCache
)[Pkg
].Flags
& pkgCache::Flag::Auto
) == pkgCache::Flag::Auto
) == MarkAuto
)
117 ioprintf(c1out
, "changing %s to %d\n", Pkg
.Name(), (MarkAuto
== false) ? 0 : 1);
119 DepCache
->MarkAuto(Pkg
, MarkAuto
);
122 if (AutoMarkChanged
> 0 && _config
->FindB("APT::Mark::Simulate", false) == false)
123 return DepCache
->writeStateFile(NULL
);
125 _error
->Notice(_("This command is deprecated. Please use 'apt-mark auto' and 'apt-mark manual' instead."));
130 /* ShowAuto - show automatically installed packages (sorted) {{{*/
131 static bool ShowAuto(CommandLine
&CmdL
)
133 pkgCacheFile CacheFile
;
134 pkgCache
*Cache
= CacheFile
.GetPkgCache();
135 pkgDepCache
*DepCache
= CacheFile
.GetDepCache();
136 if (unlikely(Cache
== NULL
|| DepCache
== NULL
))
139 std::vector
<string
> packages
;
141 bool const ShowAuto
= strcasecmp(CmdL
.FileList
[0],"showauto") == 0;
143 if (CmdL
.FileList
[1] == 0)
145 packages
.reserve(Cache
->HeaderP
->PackageCount
/ 3);
146 for (pkgCache::PkgIterator P
= Cache
->PkgBegin(); P
.end() == false; ++P
)
147 if (P
->CurrentVer
!= 0 &&
148 (((*DepCache
)[P
].Flags
& pkgCache::Flag::Auto
) == pkgCache::Flag::Auto
) == ShowAuto
)
149 packages
.push_back(P
.FullName(true));
153 APT::CacheSetHelper
helper(false); // do not show errors
154 APT::PackageSet pkgset
= APT::PackageSet::FromCommandLine(CacheFile
, CmdL
.FileList
+ 1, helper
);
155 packages
.reserve(pkgset
.size());
156 for (APT::PackageSet::const_iterator P
= pkgset
.begin(); P
!= pkgset
.end(); ++P
)
157 if (P
->CurrentVer
!= 0 &&
158 (((*DepCache
)[P
].Flags
& pkgCache::Flag::Auto
) == pkgCache::Flag::Auto
) == ShowAuto
)
159 packages
.push_back(P
.FullName(true));
162 std::sort(packages
.begin(), packages
.end());
164 for (vector
<string
>::const_iterator I
= packages
.begin(); I
!= packages
.end(); ++I
)
165 std::cout
<< *I
<< std::endl
;
170 // DoSelection - wrapping around dpkg selections /*{{{*/
171 static bool DoSelection(CommandLine
&CmdL
)
173 pkgCacheFile CacheFile
;
174 pkgCache
*Cache
= CacheFile
.GetPkgCache();
175 if (unlikely(Cache
== NULL
))
178 APT::VersionVector pkgset
= APT::VersionVector::FromCommandLine(CacheFile
, CmdL
.FileList
+ 1, APT::CacheSetHelper::INSTCAND
);
179 if (pkgset
.empty() == true)
180 return _error
->Error(_("No packages found"));
182 APT::StateChanges marks
;
183 if (strcasecmp(CmdL
.FileList
[0], "hold") == 0 || strcasecmp(CmdL
.FileList
[0], "unhold") == 0)
185 auto const part
= std::stable_partition(pkgset
.begin(), pkgset
.end(),
186 [](pkgCache::VerIterator
const &V
) { return V
.ParentPkg()->SelectedState
== pkgCache::State::Hold
; });
188 bool const MarkHold
= strcasecmp(CmdL
.FileList
[0],"hold") == 0;
189 auto const doneBegin
= MarkHold
? pkgset
.begin() : part
;
190 auto const doneEnd
= MarkHold
? part
: pkgset
.end();
191 std::for_each(doneBegin
, doneEnd
, [&MarkHold
](pkgCache::VerIterator
const &V
) {
192 if (MarkHold
== true)
193 ioprintf(c1out
, _("%s was already set on hold.\n"), V
.ParentPkg().FullName(true).c_str());
195 ioprintf(c1out
, _("%s was already not hold.\n"), V
.ParentPkg().FullName(true).c_str());
198 if (doneBegin
== pkgset
.begin() && doneEnd
== pkgset
.end())
201 auto const changeBegin
= MarkHold
? part
: pkgset
.begin();
202 auto const changeEnd
= MarkHold
? pkgset
.end() : part
;
203 std::move(changeBegin
, changeEnd
, std::back_inserter(MarkHold
? marks
.Hold() : marks
.Unhold()));
207 // FIXME: Maybe show a message for unchanged states here as well?
208 if (strcasecmp(CmdL
.FileList
[0], "purge") == 0)
209 std::swap(marks
.Purge(), pkgset
);
210 else if (strcasecmp(CmdL
.FileList
[0], "deinstall") == 0 || strcasecmp(CmdL
.FileList
[0], "remove") == 0)
211 std::swap(marks
.Remove(), pkgset
);
212 else //if (strcasecmp(CmdL.FileList[0], "install") == 0)
213 std::swap(marks
.Install(), pkgset
);
218 if (_config
->FindB("APT::Mark::Simulate", false) == false)
220 success
= marks
.Save();
221 if (success
== false)
222 _error
->Error(_("Executing dpkg failed. Are you root?"));
224 for (auto Ver
: marks
.Hold())
225 ioprintf(c1out
,_("%s set on hold.\n"), Ver
.ParentPkg().FullName(true).c_str());
226 for (auto Ver
: marks
.Unhold())
227 ioprintf(c1out
,_("Canceled hold on %s.\n"), Ver
.ParentPkg().FullName(true).c_str());
228 for (auto Ver
: marks
.Purge())
229 ioprintf(c1out
,_("Selected %s for purge.\n"), Ver
.ParentPkg().FullName(true).c_str());
230 for (auto Ver
: marks
.Remove())
231 ioprintf(c1out
,_("Selected %s for removal.\n"), Ver
.ParentPkg().FullName(true).c_str());
232 for (auto Ver
: marks
.Install())
233 ioprintf(c1out
,_("Selected %s for installation.\n"), Ver
.ParentPkg().FullName(true).c_str());
237 static bool ShowSelection(CommandLine
&CmdL
) /*{{{*/
239 pkgCacheFile CacheFile
;
240 pkgCache
*Cache
= CacheFile
.GetPkgCache();
241 if (unlikely(Cache
== NULL
))
244 pkgCache::State::PkgSelectedState selector
;
245 if (strncasecmp(CmdL
.FileList
[0], "showpurge", strlen("showpurge")) == 0)
246 selector
= pkgCache::State::Purge
;
247 else if (strncasecmp(CmdL
.FileList
[0], "showdeinstall", strlen("showdeinstall")) == 0 ||
248 strncasecmp(CmdL
.FileList
[0], "showremove", strlen("showremove")) == 0)
249 selector
= pkgCache::State::DeInstall
;
250 else if (strncasecmp(CmdL
.FileList
[0], "showhold", strlen("showhold")) == 0)
251 selector
= pkgCache::State::Hold
;
252 else //if (strcasecmp(CmdL.FileList[0], "showinstall", strlen("showinstall")) == 0)
253 selector
= pkgCache::State::Install
;
255 std::vector
<string
> packages
;
257 if (CmdL
.FileList
[1] == 0)
259 packages
.reserve(50); // how many holds are realistic? I hope just a few…
260 for (pkgCache::PkgIterator P
= Cache
->PkgBegin(); P
.end() == false; ++P
)
261 if (P
->SelectedState
== selector
)
262 packages
.push_back(P
.FullName(true));
266 APT::CacheSetHelper
helper(false); // do not show errors
267 APT::PackageSet pkgset
= APT::PackageSet::FromCommandLine(CacheFile
, CmdL
.FileList
+ 1, helper
);
268 packages
.reserve(pkgset
.size());
269 for (APT::PackageSet::const_iterator P
= pkgset
.begin(); P
!= pkgset
.end(); ++P
)
270 if (P
->SelectedState
== selector
)
271 packages
.push_back(P
.FullName(true));
274 std::sort(packages
.begin(), packages
.end());
276 for (vector
<string
>::const_iterator I
= packages
.begin(); I
!= packages
.end(); ++I
)
277 std::cout
<< *I
<< std::endl
;
282 // ShowHelp - Show a help screen /*{{{*/
283 static bool ShowHelp(CommandLine
&, CommandLine::DispatchWithHelp
const * Cmds
)
285 ioprintf(std::cout
, "%s %s (%s)\n", PACKAGE
, PACKAGE_VERSION
, COMMON_ARCH
);
288 _("Usage: apt-mark [options] {auto|manual} pkg1 [pkg2 ...]\n"
290 "apt-mark is a simple command line interface for marking packages\n"
291 "as manually or automatically installed. It can also list marks.\n")
293 << _("Commands:") << std::endl
;
295 for (; Cmds
->Handler
!= nullptr; ++Cmds
)
297 if (Cmds
->Help
== nullptr)
299 std::cout
<< " " << Cmds
->Match
<< " - " << Cmds
->Help
<< std::endl
;
302 std::cout
<< std::endl
304 " -h This help text.\n"
305 " -q Loggable output - no progress indicator\n"
306 " -qq No output except for errors\n"
307 " -s No-act. Just prints what would be done.\n"
308 " -f read/write auto/manual marking in the given file\n"
309 " -c=? Read this configuration file\n"
310 " -o=? Set an arbitrary configuration option, eg -o dir::cache=/tmp\n"
311 "See the apt-mark(8) and apt.conf(5) manual pages for more information.")
316 int main(int argc
,const char *argv
[]) /*{{{*/
318 CommandLine::DispatchWithHelp Cmds
[] = {
319 {"auto",&DoAuto
, _("Mark the given packages as automatically installed")},
320 {"manual",&DoAuto
, _("Mark the given packages as manually installed")},
321 {"hold",&DoSelection
, _("Mark a package as held back")},
322 {"unhold",&DoSelection
, _("Unset a package set as held back")},
323 {"install",&DoSelection
, nullptr},
324 {"remove",&DoSelection
, nullptr}, // dpkg uses deinstall, but we use remove everywhere else
325 {"deinstall",&DoSelection
, nullptr},
326 {"purge",&DoSelection
, nullptr},
327 {"showauto",&ShowAuto
, _("Print the list of automatically installed packages")},
328 {"showmanual",&ShowAuto
, _("Print the list of manually installed packages")},
329 {"showhold",&ShowSelection
, _("Print the list of package on hold")}, {"showholds",&ShowSelection
, nullptr},
330 {"showinstall",&ShowSelection
, nullptr}, {"showinstalls",&ShowSelection
, nullptr},
331 {"showdeinstall",&ShowSelection
, nullptr}, {"showdeinstalls",&ShowSelection
, nullptr},
332 {"showremove",&ShowSelection
, nullptr}, {"showremoves",&ShowSelection
, nullptr},
333 {"showpurge",&ShowSelection
, nullptr}, {"showpurges",&ShowSelection
, nullptr},
334 // obsolete commands for compatibility
335 {"markauto", &DoMarkAuto
, nullptr},
336 {"unmarkauto", &DoMarkAuto
, nullptr},
337 {nullptr, nullptr, nullptr}
340 std::vector
<CommandLine::Args
> Args
= getCommandArgs("apt-mark", CommandLine::GetCommand(Cmds
, argc
, argv
));
342 // Set up gettext support
343 setlocale(LC_ALL
,"");
347 ParseCommandLine(CmdL
, Cmds
, Args
.data(), &_config
, &_system
, argc
, argv
, ShowHelp
);
351 // Match the operation
352 CmdL
.DispatchArg(Cmds
);
354 // Print any errors or warnings found during parsing
355 bool const Errors
= _error
->PendingError();
356 if (_config
->FindI("quiet",0) > 0)
357 _error
->DumpErrors();
359 _error
->DumpErrors(GlobalError::DEBUG
);
360 return Errors
== true ? 100 : 0;