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 pkgCache
*Cache
= CacheFile
.GetPkgCache();
52 pkgDepCache
*DepCache
= CacheFile
.GetDepCache();
53 if (unlikely(Cache
== NULL
|| DepCache
== NULL
))
56 APT::PackageList pkgset
= APT::PackageList::FromCommandLine(CacheFile
, CmdL
.FileList
+ 1);
57 if (pkgset
.empty() == true)
58 return _error
->Error(_("No packages found"));
60 bool MarkAuto
= strcasecmp(CmdL
.FileList
[0],"auto") == 0;
61 int AutoMarkChanged
= 0;
63 for (APT::PackageList::const_iterator Pkg
= pkgset
.begin(); Pkg
!= pkgset
.end(); ++Pkg
)
65 if (Pkg
->CurrentVer
== 0)
67 ioprintf(c1out
,_("%s can not be marked as it is not installed.\n"), Pkg
.FullName(true).c_str());
70 else if ((((*DepCache
)[Pkg
].Flags
& pkgCache::Flag::Auto
) == pkgCache::Flag::Auto
) == MarkAuto
)
72 if (MarkAuto
== false)
73 ioprintf(c1out
,_("%s was already set to manually installed.\n"), Pkg
.FullName(true).c_str());
75 ioprintf(c1out
,_("%s was already set to automatically installed.\n"), Pkg
.FullName(true).c_str());
79 if (MarkAuto
== false)
80 ioprintf(c1out
,_("%s set to manually installed.\n"), Pkg
.FullName(true).c_str());
82 ioprintf(c1out
,_("%s set to automatically installed.\n"), Pkg
.FullName(true).c_str());
84 DepCache
->MarkAuto(Pkg
, MarkAuto
);
87 if (AutoMarkChanged
> 0 && _config
->FindB("APT::Mark::Simulate", false) == false)
88 return DepCache
->writeStateFile(NULL
);
92 /* DoMarkAuto - mark packages as automatically/manually installed {{{*/
93 /* Does the same as DoAuto but tries to do it exactly the same why as
94 the python implementation did it so it can be a drop-in replacement */
95 static bool DoMarkAuto(CommandLine
&CmdL
)
97 pkgCacheFile CacheFile
;
98 pkgCache
*Cache
= CacheFile
.GetPkgCache();
99 pkgDepCache
*DepCache
= CacheFile
.GetDepCache();
100 if (unlikely(Cache
== NULL
|| DepCache
== NULL
))
103 APT::PackageList pkgset
= APT::PackageList::FromCommandLine(CacheFile
, CmdL
.FileList
+ 1);
104 if (pkgset
.empty() == true)
105 return _error
->Error(_("No packages found"));
107 bool const MarkAuto
= strcasecmp(CmdL
.FileList
[0],"markauto") == 0;
108 bool const Verbose
= _config
->FindB("APT::MarkAuto::Verbose", false);
109 int AutoMarkChanged
= 0;
111 for (APT::PackageList::const_iterator Pkg
= pkgset
.begin(); Pkg
!= pkgset
.end(); ++Pkg
)
113 if (Pkg
->CurrentVer
== 0 ||
114 (((*DepCache
)[Pkg
].Flags
& pkgCache::Flag::Auto
) == pkgCache::Flag::Auto
) == MarkAuto
)
118 ioprintf(c1out
, "changing %s to %d\n", Pkg
.Name(), (MarkAuto
== false) ? 0 : 1);
120 DepCache
->MarkAuto(Pkg
, MarkAuto
);
123 if (AutoMarkChanged
> 0 && _config
->FindB("APT::Mark::Simulate", false) == false)
124 return DepCache
->writeStateFile(NULL
);
126 _error
->Notice(_("This command is deprecated. Please use 'apt-mark auto' and 'apt-mark manual' instead."));
131 /* ShowAuto - show automatically installed packages (sorted) {{{*/
132 static bool ShowAuto(CommandLine
&CmdL
)
134 pkgCacheFile CacheFile
;
135 pkgCache
*Cache
= CacheFile
.GetPkgCache();
136 pkgDepCache
*DepCache
= CacheFile
.GetDepCache();
137 if (unlikely(Cache
== NULL
|| DepCache
== NULL
))
140 std::vector
<string
> packages
;
142 bool const ShowAuto
= strcasecmp(CmdL
.FileList
[0],"showauto") == 0;
144 if (CmdL
.FileList
[1] == 0)
146 packages
.reserve(Cache
->HeaderP
->PackageCount
/ 3);
147 for (pkgCache::PkgIterator P
= Cache
->PkgBegin(); P
.end() == false; ++P
)
148 if (P
->CurrentVer
!= 0 &&
149 (((*DepCache
)[P
].Flags
& pkgCache::Flag::Auto
) == pkgCache::Flag::Auto
) == ShowAuto
)
150 packages
.push_back(P
.FullName(true));
154 APT::CacheSetHelper
helper(false); // do not show errors
155 APT::PackageSet pkgset
= APT::PackageSet::FromCommandLine(CacheFile
, CmdL
.FileList
+ 1, helper
);
156 packages
.reserve(pkgset
.size());
157 for (APT::PackageSet::const_iterator P
= pkgset
.begin(); P
!= pkgset
.end(); ++P
)
158 if (P
->CurrentVer
!= 0 &&
159 (((*DepCache
)[P
].Flags
& pkgCache::Flag::Auto
) == pkgCache::Flag::Auto
) == ShowAuto
)
160 packages
.push_back(P
.FullName(true));
163 std::sort(packages
.begin(), packages
.end());
165 for (vector
<string
>::const_iterator I
= packages
.begin(); I
!= packages
.end(); ++I
)
166 std::cout
<< *I
<< std::endl
;
171 // DoSelection - wrapping around dpkg selections /*{{{*/
172 static bool DoSelection(CommandLine
&CmdL
)
174 pkgCacheFile CacheFile
;
175 pkgCache
*Cache
= CacheFile
.GetPkgCache();
176 if (unlikely(Cache
== NULL
))
179 APT::VersionVector pkgset
= APT::VersionVector::FromCommandLine(CacheFile
, CmdL
.FileList
+ 1, APT::CacheSetHelper::INSTCAND
);
180 if (pkgset
.empty() == true)
181 return _error
->Error(_("No packages found"));
183 APT::StateChanges marks
;
184 if (strcasecmp(CmdL
.FileList
[0], "hold") == 0 || strcasecmp(CmdL
.FileList
[0], "unhold") == 0)
186 auto const part
= std::stable_partition(pkgset
.begin(), pkgset
.end(),
187 [](pkgCache::VerIterator
const &V
) { return V
.ParentPkg()->SelectedState
== pkgCache::State::Hold
; });
189 bool const MarkHold
= strcasecmp(CmdL
.FileList
[0],"hold") == 0;
190 auto const doneBegin
= MarkHold
? pkgset
.begin() : part
;
191 auto const doneEnd
= MarkHold
? part
: pkgset
.end();
192 std::for_each(doneBegin
, doneEnd
, [&MarkHold
](pkgCache::VerIterator
const &V
) {
193 if (MarkHold
== true)
194 ioprintf(c1out
, _("%s was already set on hold.\n"), V
.ParentPkg().FullName(true).c_str());
196 ioprintf(c1out
, _("%s was already not hold.\n"), V
.ParentPkg().FullName(true).c_str());
199 if (doneBegin
== pkgset
.begin() && doneEnd
== pkgset
.end())
202 auto const changeBegin
= MarkHold
? part
: pkgset
.begin();
203 auto const changeEnd
= MarkHold
? pkgset
.end() : part
;
204 std::move(changeBegin
, changeEnd
, std::back_inserter(MarkHold
? marks
.Hold() : marks
.Unhold()));
208 // FIXME: Maybe show a message for unchanged states here as well?
209 if (strcasecmp(CmdL
.FileList
[0], "purge") == 0)
210 std::swap(marks
.Purge(), pkgset
);
211 else if (strcasecmp(CmdL
.FileList
[0], "deinstall") == 0 || strcasecmp(CmdL
.FileList
[0], "remove") == 0)
212 std::swap(marks
.Remove(), pkgset
);
213 else //if (strcasecmp(CmdL.FileList[0], "install") == 0)
214 std::swap(marks
.Install(), pkgset
);
219 if (_config
->FindB("APT::Mark::Simulate", false) == false)
221 success
= marks
.Save();
222 if (success
== false)
223 _error
->Error(_("Executing dpkg failed. Are you root?"));
225 for (auto Ver
: marks
.Hold())
226 ioprintf(c1out
,_("%s set on hold.\n"), Ver
.ParentPkg().FullName(true).c_str());
227 for (auto Ver
: marks
.Unhold())
228 ioprintf(c1out
,_("Canceled hold on %s.\n"), Ver
.ParentPkg().FullName(true).c_str());
229 for (auto Ver
: marks
.Purge())
230 ioprintf(c1out
,_("Selected %s for purge.\n"), Ver
.ParentPkg().FullName(true).c_str());
231 for (auto Ver
: marks
.Remove())
232 ioprintf(c1out
,_("Selected %s for removal.\n"), Ver
.ParentPkg().FullName(true).c_str());
233 for (auto Ver
: marks
.Install())
234 ioprintf(c1out
,_("Selected %s for installation.\n"), Ver
.ParentPkg().FullName(true).c_str());
238 static bool ShowSelection(CommandLine
&CmdL
) /*{{{*/
240 pkgCacheFile CacheFile
;
241 pkgCache
*Cache
= CacheFile
.GetPkgCache();
242 if (unlikely(Cache
== NULL
))
245 pkgCache::State::PkgSelectedState selector
;
246 if (strncasecmp(CmdL
.FileList
[0], "showpurge", strlen("showpurge")) == 0)
247 selector
= pkgCache::State::Purge
;
248 else if (strncasecmp(CmdL
.FileList
[0], "showdeinstall", strlen("showdeinstall")) == 0 ||
249 strncasecmp(CmdL
.FileList
[0], "showremove", strlen("showremove")) == 0)
250 selector
= pkgCache::State::DeInstall
;
251 else if (strncasecmp(CmdL
.FileList
[0], "showhold", strlen("showhold")) == 0)
252 selector
= pkgCache::State::Hold
;
253 else //if (strcasecmp(CmdL.FileList[0], "showinstall", strlen("showinstall")) == 0)
254 selector
= pkgCache::State::Install
;
256 std::vector
<string
> packages
;
258 if (CmdL
.FileList
[1] == 0)
260 packages
.reserve(50); // how many holds are realistic? I hope just a few…
261 for (pkgCache::PkgIterator P
= Cache
->PkgBegin(); P
.end() == false; ++P
)
262 if (P
->SelectedState
== selector
)
263 packages
.push_back(P
.FullName(true));
267 APT::CacheSetHelper
helper(false); // do not show errors
268 APT::PackageSet pkgset
= APT::PackageSet::FromCommandLine(CacheFile
, CmdL
.FileList
+ 1, helper
);
269 packages
.reserve(pkgset
.size());
270 for (APT::PackageSet::const_iterator P
= pkgset
.begin(); P
!= pkgset
.end(); ++P
)
271 if (P
->SelectedState
== selector
)
272 packages
.push_back(P
.FullName(true));
275 std::sort(packages
.begin(), packages
.end());
277 for (vector
<string
>::const_iterator I
= packages
.begin(); I
!= packages
.end(); ++I
)
278 std::cout
<< *I
<< std::endl
;
283 static bool ShowHelp(CommandLine
&) /*{{{*/
286 _("Usage: apt-mark [options] {auto|manual} pkg1 [pkg2 ...]\n"
288 "apt-mark is a simple command line interface for marking packages\n"
289 "as manually or automatically installed. It can also be used to\n"
290 "manipulate the dpkg(1) selection states of packages, and to list\n"
291 "all packages with or without a certain marking.\n");
295 static std::vector
<aptDispatchWithHelp
> GetCommands() /*{{{*/
298 {"auto",&DoAuto
, _("Mark the given packages as automatically installed")},
299 {"manual",&DoAuto
, _("Mark the given packages as manually installed")},
300 {"hold",&DoSelection
, _("Mark a package as held back")},
301 {"unhold",&DoSelection
, _("Unset a package set as held back")},
302 {"install",&DoSelection
, nullptr},
303 {"remove",&DoSelection
, nullptr}, // dpkg uses deinstall, but we use remove everywhere else
304 {"deinstall",&DoSelection
, nullptr},
305 {"purge",&DoSelection
, nullptr},
306 {"showauto",&ShowAuto
, _("Print the list of automatically installed packages")},
307 {"showmanual",&ShowAuto
, _("Print the list of manually installed packages")},
308 {"showhold",&ShowSelection
, _("Print the list of package on hold")}, {"showholds",&ShowSelection
, nullptr},
309 {"showinstall",&ShowSelection
, nullptr}, {"showinstalls",&ShowSelection
, nullptr},
310 {"showdeinstall",&ShowSelection
, nullptr}, {"showdeinstalls",&ShowSelection
, nullptr},
311 {"showremove",&ShowSelection
, nullptr}, {"showremoves",&ShowSelection
, nullptr},
312 {"showpurge",&ShowSelection
, nullptr}, {"showpurges",&ShowSelection
, nullptr},
313 // obsolete commands for compatibility
314 {"markauto", &DoMarkAuto
, nullptr},
315 {"unmarkauto", &DoMarkAuto
, nullptr},
316 {nullptr, nullptr, nullptr}
320 int main(int argc
,const char *argv
[]) /*{{{*/
325 auto const Cmds
= ParseCommandLine(CmdL
, APT_CMD::APT_MARK
, &_config
, &_system
, argc
, argv
, &ShowHelp
, &GetCommands
);
329 return DispatchCommandLine(CmdL
, Cmds
);