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>
27 #include <apt-private/private-main.h>
47 /* DoAuto - mark packages as automatically/manually installed {{{*/
48 static bool DoAuto(CommandLine
&CmdL
)
50 pkgCacheFile CacheFile
;
51 pkgDepCache
* const DepCache
= CacheFile
.GetDepCache();
52 if (unlikely(DepCache
== nullptr))
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 pkgDepCache
* const DepCache
= CacheFile
.GetDepCache();
98 if (unlikely(DepCache
== nullptr))
101 APT::PackageList pkgset
= APT::PackageList::FromCommandLine(CacheFile
, CmdL
.FileList
+ 1);
102 if (pkgset
.empty() == true)
103 return _error
->Error(_("No packages found"));
105 bool const MarkAuto
= strcasecmp(CmdL
.FileList
[0],"markauto") == 0;
106 bool const Verbose
= _config
->FindB("APT::MarkAuto::Verbose", false);
107 int AutoMarkChanged
= 0;
109 for (APT::PackageList::const_iterator Pkg
= pkgset
.begin(); Pkg
!= pkgset
.end(); ++Pkg
)
111 if (Pkg
->CurrentVer
== 0 ||
112 (((*DepCache
)[Pkg
].Flags
& pkgCache::Flag::Auto
) == pkgCache::Flag::Auto
) == MarkAuto
)
116 ioprintf(c1out
, "changing %s to %d\n", Pkg
.Name(), (MarkAuto
== false) ? 0 : 1);
118 DepCache
->MarkAuto(Pkg
, MarkAuto
);
121 if (AutoMarkChanged
> 0 && _config
->FindB("APT::Mark::Simulate", false) == false)
122 return DepCache
->writeStateFile(NULL
);
124 _error
->Notice(_("This command is deprecated. Please use 'apt-mark auto' and 'apt-mark manual' instead."));
129 /* ShowAuto - show automatically installed packages (sorted) {{{*/
130 static bool ShowAuto(CommandLine
&CmdL
)
132 pkgCacheFile CacheFile
;
133 pkgDepCache
* const DepCache
= CacheFile
.GetDepCache();
134 if (unlikely(DepCache
== nullptr))
137 std::vector
<string
> packages
;
139 bool const ShowAuto
= strcasecmp(CmdL
.FileList
[0],"showauto") == 0;
141 if (CmdL
.FileList
[1] == 0)
143 packages
.reserve(DepCache
->Head().PackageCount
/ 3);
144 for (pkgCache::PkgIterator P
= DepCache
->PkgBegin(); P
.end() == false; ++P
)
145 if (P
->CurrentVer
!= 0 &&
146 (((*DepCache
)[P
].Flags
& pkgCache::Flag::Auto
) == pkgCache::Flag::Auto
) == ShowAuto
)
147 packages
.push_back(P
.FullName(true));
151 APT::CacheSetHelper
helper(false); // do not show errors
152 APT::PackageSet pkgset
= APT::PackageSet::FromCommandLine(CacheFile
, CmdL
.FileList
+ 1, helper
);
153 packages
.reserve(pkgset
.size());
154 for (APT::PackageSet::const_iterator P
= pkgset
.begin(); P
!= pkgset
.end(); ++P
)
155 if (P
->CurrentVer
!= 0 &&
156 (((*DepCache
)[P
].Flags
& pkgCache::Flag::Auto
) == pkgCache::Flag::Auto
) == ShowAuto
)
157 packages
.push_back(P
.FullName(true));
160 std::sort(packages
.begin(), packages
.end());
162 for (vector
<string
>::const_iterator I
= packages
.begin(); I
!= packages
.end(); ++I
)
163 std::cout
<< *I
<< std::endl
;
168 // DoSelection - wrapping around dpkg selections /*{{{*/
169 static bool DoSelection(CommandLine
&CmdL
)
171 pkgCacheFile CacheFile
;
172 pkgCache
* const Cache
= CacheFile
.GetPkgCache();
173 if (unlikely(Cache
== nullptr))
176 APT::VersionVector pkgset
= APT::VersionVector::FromCommandLine(CacheFile
, CmdL
.FileList
+ 1, APT::CacheSetHelper::INSTCAND
);
177 if (pkgset
.empty() == true)
178 return _error
->Error(_("No packages found"));
180 APT::StateChanges marks
;
181 if (strcasecmp(CmdL
.FileList
[0], "hold") == 0 || strcasecmp(CmdL
.FileList
[0], "unhold") == 0)
183 auto const part
= std::stable_partition(pkgset
.begin(), pkgset
.end(),
184 [](pkgCache::VerIterator
const &V
) { return V
.ParentPkg()->SelectedState
== pkgCache::State::Hold
; });
186 bool const MarkHold
= strcasecmp(CmdL
.FileList
[0],"hold") == 0;
187 auto const doneBegin
= MarkHold
? pkgset
.begin() : part
;
188 auto const doneEnd
= MarkHold
? part
: pkgset
.end();
189 std::for_each(doneBegin
, doneEnd
, [&MarkHold
](pkgCache::VerIterator
const &V
) {
190 if (MarkHold
== true)
191 ioprintf(c1out
, _("%s was already set on hold.\n"), V
.ParentPkg().FullName(true).c_str());
193 ioprintf(c1out
, _("%s was already not hold.\n"), V
.ParentPkg().FullName(true).c_str());
196 if (doneBegin
== pkgset
.begin() && doneEnd
== pkgset
.end())
199 auto const changeBegin
= MarkHold
? part
: pkgset
.begin();
200 auto const changeEnd
= MarkHold
? pkgset
.end() : part
;
201 std::move(changeBegin
, changeEnd
, std::back_inserter(MarkHold
? marks
.Hold() : marks
.Unhold()));
205 // FIXME: Maybe show a message for unchanged states here as well?
206 if (strcasecmp(CmdL
.FileList
[0], "purge") == 0)
207 std::swap(marks
.Purge(), pkgset
);
208 else if (strcasecmp(CmdL
.FileList
[0], "deinstall") == 0 || strcasecmp(CmdL
.FileList
[0], "remove") == 0)
209 std::swap(marks
.Remove(), pkgset
);
210 else //if (strcasecmp(CmdL.FileList[0], "install") == 0)
211 std::swap(marks
.Install(), pkgset
);
216 if (_config
->FindB("APT::Mark::Simulate", false) == false)
218 success
= marks
.Save();
219 if (success
== false)
220 _error
->Error(_("Executing dpkg failed. Are you root?"));
222 for (auto Ver
: marks
.Hold())
223 ioprintf(c1out
,_("%s set on hold.\n"), Ver
.ParentPkg().FullName(true).c_str());
224 for (auto Ver
: marks
.Unhold())
225 ioprintf(c1out
,_("Canceled hold on %s.\n"), Ver
.ParentPkg().FullName(true).c_str());
226 for (auto Ver
: marks
.Purge())
227 ioprintf(c1out
,_("Selected %s for purge.\n"), Ver
.ParentPkg().FullName(true).c_str());
228 for (auto Ver
: marks
.Remove())
229 ioprintf(c1out
,_("Selected %s for removal.\n"), Ver
.ParentPkg().FullName(true).c_str());
230 for (auto Ver
: marks
.Install())
231 ioprintf(c1out
,_("Selected %s for installation.\n"), Ver
.ParentPkg().FullName(true).c_str());
235 static bool ShowSelection(CommandLine
&CmdL
) /*{{{*/
237 pkgCacheFile CacheFile
;
238 pkgCache
* const Cache
= CacheFile
.GetPkgCache();
239 if (unlikely(Cache
== nullptr))
242 pkgCache::State::PkgSelectedState selector
;
243 if (strncasecmp(CmdL
.FileList
[0], "showpurge", strlen("showpurge")) == 0)
244 selector
= pkgCache::State::Purge
;
245 else if (strncasecmp(CmdL
.FileList
[0], "showdeinstall", strlen("showdeinstall")) == 0 ||
246 strncasecmp(CmdL
.FileList
[0], "showremove", strlen("showremove")) == 0)
247 selector
= pkgCache::State::DeInstall
;
248 else if (strncasecmp(CmdL
.FileList
[0], "showhold", strlen("showhold")) == 0)
249 selector
= pkgCache::State::Hold
;
250 else //if (strcasecmp(CmdL.FileList[0], "showinstall", strlen("showinstall")) == 0)
251 selector
= pkgCache::State::Install
;
253 std::vector
<string
> packages
;
255 if (CmdL
.FileList
[1] == 0)
257 packages
.reserve(50); // how many holds are realistic? I hope just a few…
258 for (pkgCache::PkgIterator P
= Cache
->PkgBegin(); P
.end() == false; ++P
)
259 if (P
->SelectedState
== selector
)
260 packages
.push_back(P
.FullName(true));
264 APT::CacheSetHelper
helper(false); // do not show errors
265 APT::PackageSet pkgset
= APT::PackageSet::FromCommandLine(CacheFile
, CmdL
.FileList
+ 1, helper
);
266 packages
.reserve(pkgset
.size());
267 for (APT::PackageSet::const_iterator P
= pkgset
.begin(); P
!= pkgset
.end(); ++P
)
268 if (P
->SelectedState
== selector
)
269 packages
.push_back(P
.FullName(true));
272 std::sort(packages
.begin(), packages
.end());
274 for (vector
<string
>::const_iterator I
= packages
.begin(); I
!= packages
.end(); ++I
)
275 std::cout
<< *I
<< std::endl
;
280 static bool ShowHelp(CommandLine
&) /*{{{*/
283 _("Usage: apt-mark [options] {auto|manual} pkg1 [pkg2 ...]\n"
285 "apt-mark is a simple command line interface for marking packages\n"
286 "as manually or automatically installed. It can also be used to\n"
287 "manipulate the dpkg(1) selection states of packages, and to list\n"
288 "all packages with or without a certain marking.\n");
292 static std::vector
<aptDispatchWithHelp
> GetCommands() /*{{{*/
295 {"auto",&DoAuto
, _("Mark the given packages as automatically installed")},
296 {"manual",&DoAuto
, _("Mark the given packages as manually installed")},
297 {"hold",&DoSelection
, _("Mark a package as held back")},
298 {"unhold",&DoSelection
, _("Unset a package set as held back")},
299 {"install",&DoSelection
, nullptr},
300 {"remove",&DoSelection
, nullptr}, // dpkg uses deinstall, but we use remove everywhere else
301 {"deinstall",&DoSelection
, nullptr},
302 {"purge",&DoSelection
, nullptr},
303 {"showauto",&ShowAuto
, _("Print the list of automatically installed packages")},
304 {"showmanual",&ShowAuto
, _("Print the list of manually installed packages")},
305 {"showhold",&ShowSelection
, _("Print the list of package on hold")}, {"showholds",&ShowSelection
, nullptr},
306 {"showinstall",&ShowSelection
, nullptr}, {"showinstalls",&ShowSelection
, nullptr},
307 {"showdeinstall",&ShowSelection
, nullptr}, {"showdeinstalls",&ShowSelection
, nullptr},
308 {"showremove",&ShowSelection
, nullptr}, {"showremoves",&ShowSelection
, nullptr},
309 {"showpurge",&ShowSelection
, nullptr}, {"showpurges",&ShowSelection
, nullptr},
310 // obsolete commands for compatibility
311 {"markauto", &DoMarkAuto
, nullptr},
312 {"unmarkauto", &DoMarkAuto
, nullptr},
313 {nullptr, nullptr, nullptr}
317 int main(int argc
,const char *argv
[]) /*{{{*/
320 auto const Cmds
= ParseCommandLine(CmdL
, APT_CMD::APT_MARK
, &_config
, &_system
, argc
, argv
, &ShowHelp
, &GetCommands
);
324 return DispatchCommandLine(CmdL
, Cmds
);