]> git.saurik.com Git - apt.git/blame - cmdline/apt-mark.cc
use function pointers instead of weak symbols for cmdline parsing
[apt.git] / cmdline / apt-mark.cc
CommitLineData
c98fb5e0
DK
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
3/* #####################################################################
4 apt-mark - show and change auto-installed bit information
5 ##################################################################### */
6 /*}}}*/
7// Include Files /*{{{*/
ea542140
DK
8#include <config.h>
9
c98fb5e0
DK
10#include <apt-pkg/cachefile.h>
11#include <apt-pkg/cacheset.h>
12#include <apt-pkg/cmndline.h>
13#include <apt-pkg/error.h>
453b82a3 14#include <apt-pkg/fileutl.h>
c98fb5e0 15#include <apt-pkg/init.h>
472ff00e 16#include <apt-pkg/pkgsystem.h>
453b82a3 17#include <apt-pkg/strutl.h>
b49068c5 18#include <apt-pkg/statechanges.h>
453b82a3
DK
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>
24
25#include <apt-private/private-cmndline.h>
d9e518c6 26#include <apt-private/private-output.h>
e7e10e47 27#include <apt-private/private-main.h>
c98fb5e0 28
6fddb156 29#include <errno.h>
6fddb156 30#include <fcntl.h>
453b82a3
DK
31#include <stddef.h>
32#include <stdio.h>
33#include <stdlib.h>
34#include <string.h>
35#include <sys/wait.h>
36#include <unistd.h>
37#include <algorithm>
38#include <fstream>
39#include <iostream>
40#include <string>
41#include <vector>
b9179170 42
ea542140 43#include <apti18n.h>
c98fb5e0
DK
44 /*}}}*/
45using namespace std;
46
c98fb5e0 47/* DoAuto - mark packages as automatically/manually installed {{{*/
c3ccac92 48static bool DoAuto(CommandLine &CmdL)
c98fb5e0
DK
49{
50 pkgCacheFile CacheFile;
51 pkgCache *Cache = CacheFile.GetPkgCache();
52 pkgDepCache *DepCache = CacheFile.GetDepCache();
53 if (unlikely(Cache == NULL || DepCache == NULL))
54 return false;
55
c4cca791 56 APT::PackageList pkgset = APT::PackageList::FromCommandLine(CacheFile, CmdL.FileList + 1);
c98fb5e0
DK
57 if (pkgset.empty() == true)
58 return _error->Error(_("No packages found"));
59
60 bool MarkAuto = strcasecmp(CmdL.FileList[0],"auto") == 0;
61 int AutoMarkChanged = 0;
62
c4cca791 63 for (APT::PackageList::const_iterator Pkg = pkgset.begin(); Pkg != pkgset.end(); ++Pkg)
c98fb5e0
DK
64 {
65 if (Pkg->CurrentVer == 0)
66 {
67 ioprintf(c1out,_("%s can not be marked as it is not installed.\n"), Pkg.FullName(true).c_str());
68 continue;
69 }
70 else if ((((*DepCache)[Pkg].Flags & pkgCache::Flag::Auto) == pkgCache::Flag::Auto) == MarkAuto)
71 {
72 if (MarkAuto == false)
73 ioprintf(c1out,_("%s was already set to manually installed.\n"), Pkg.FullName(true).c_str());
74 else
75 ioprintf(c1out,_("%s was already set to automatically installed.\n"), Pkg.FullName(true).c_str());
76 continue;
77 }
78
79 if (MarkAuto == false)
80 ioprintf(c1out,_("%s set to manually installed.\n"), Pkg.FullName(true).c_str());
81 else
82 ioprintf(c1out,_("%s set to automatically installed.\n"), Pkg.FullName(true).c_str());
83
84 DepCache->MarkAuto(Pkg, MarkAuto);
85 ++AutoMarkChanged;
86 }
87 if (AutoMarkChanged > 0 && _config->FindB("APT::Mark::Simulate", false) == false)
88 return DepCache->writeStateFile(NULL);
89 return true;
90}
91 /*}}}*/
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 */
c3ccac92 95static bool DoMarkAuto(CommandLine &CmdL)
c98fb5e0
DK
96{
97 pkgCacheFile CacheFile;
98 pkgCache *Cache = CacheFile.GetPkgCache();
99 pkgDepCache *DepCache = CacheFile.GetDepCache();
100 if (unlikely(Cache == NULL || DepCache == NULL))
101 return false;
102
c4cca791 103 APT::PackageList pkgset = APT::PackageList::FromCommandLine(CacheFile, CmdL.FileList + 1);
c98fb5e0
DK
104 if (pkgset.empty() == true)
105 return _error->Error(_("No packages found"));
106
107 bool const MarkAuto = strcasecmp(CmdL.FileList[0],"markauto") == 0;
108 bool const Verbose = _config->FindB("APT::MarkAuto::Verbose", false);
109 int AutoMarkChanged = 0;
110
c4cca791 111 for (APT::PackageList::const_iterator Pkg = pkgset.begin(); Pkg != pkgset.end(); ++Pkg)
c98fb5e0
DK
112 {
113 if (Pkg->CurrentVer == 0 ||
114 (((*DepCache)[Pkg].Flags & pkgCache::Flag::Auto) == pkgCache::Flag::Auto) == MarkAuto)
115 continue;
116
117 if (Verbose == true)
118 ioprintf(c1out, "changing %s to %d\n", Pkg.Name(), (MarkAuto == false) ? 0 : 1);
119
120 DepCache->MarkAuto(Pkg, MarkAuto);
121 ++AutoMarkChanged;
122 }
123 if (AutoMarkChanged > 0 && _config->FindB("APT::Mark::Simulate", false) == false)
124 return DepCache->writeStateFile(NULL);
125
126 _error->Notice(_("This command is deprecated. Please use 'apt-mark auto' and 'apt-mark manual' instead."));
127
128 return true;
129}
130 /*}}}*/
131/* ShowAuto - show automatically installed packages (sorted) {{{*/
c3ccac92 132static bool ShowAuto(CommandLine &CmdL)
c98fb5e0
DK
133{
134 pkgCacheFile CacheFile;
135 pkgCache *Cache = CacheFile.GetPkgCache();
136 pkgDepCache *DepCache = CacheFile.GetDepCache();
137 if (unlikely(Cache == NULL || DepCache == NULL))
138 return false;
139
140 std::vector<string> packages;
141
142 bool const ShowAuto = strcasecmp(CmdL.FileList[0],"showauto") == 0;
143
144 if (CmdL.FileList[1] == 0)
145 {
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));
151 }
152 else
153 {
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));
161 }
162
163 std::sort(packages.begin(), packages.end());
164
a09e4489
DK
165 for (vector<string>::const_iterator I = packages.begin(); I != packages.end(); ++I)
166 std::cout << *I << std::endl;
167
168 return true;
169}
170 /*}}}*/
64e3414e
DK
171// DoSelection - wrapping around dpkg selections /*{{{*/
172static bool DoSelection(CommandLine &CmdL)
a09e4489
DK
173{
174 pkgCacheFile CacheFile;
175 pkgCache *Cache = CacheFile.GetPkgCache();
176 if (unlikely(Cache == NULL))
177 return false;
178
c1553e72 179 APT::VersionVector pkgset = APT::VersionVector::FromCommandLine(CacheFile, CmdL.FileList + 1, APT::CacheSetHelper::INSTCAND);
b2a893dd
DK
180 if (pkgset.empty() == true)
181 return _error->Error(_("No packages found"));
182
b49068c5 183 APT::StateChanges marks;
64e3414e
DK
184 if (strcasecmp(CmdL.FileList[0], "hold") == 0 || strcasecmp(CmdL.FileList[0], "unhold") == 0)
185 {
186 auto const part = std::stable_partition(pkgset.begin(), pkgset.end(),
187 [](pkgCache::VerIterator const &V) { return V.ParentPkg()->SelectedState == pkgCache::State::Hold; });
188
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());
195 else
196 ioprintf(c1out, _("%s was already not hold.\n"), V.ParentPkg().FullName(true).c_str());
197 });
198
199 if (doneBegin == pkgset.begin() && doneEnd == pkgset.end())
200 return true;
201
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()));
205 }
206 else
207 {
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);
215 }
b49068c5 216 pkgset.clear();
6fddb156 217
b49068c5
DK
218 bool success = true;
219 if (_config->FindB("APT::Mark::Simulate", false) == false)
6fddb156 220 {
b49068c5
DK
221 success = marks.Save();
222 if (success == false)
223 _error->Error(_("Executing dpkg failed. Are you root?"));
6fddb156 224 }
b49068c5
DK
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());
64e3414e
DK
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());
b49068c5 235 return success;
a09e4489
DK
236}
237 /*}}}*/
64e3414e 238static bool ShowSelection(CommandLine &CmdL) /*{{{*/
a09e4489
DK
239{
240 pkgCacheFile CacheFile;
241 pkgCache *Cache = CacheFile.GetPkgCache();
242 if (unlikely(Cache == NULL))
243 return false;
244
64e3414e
DK
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;
255
a09e4489
DK
256 std::vector<string> packages;
257
258 if (CmdL.FileList[1] == 0)
259 {
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)
64e3414e 262 if (P->SelectedState == selector)
a09e4489
DK
263 packages.push_back(P.FullName(true));
264 }
265 else
266 {
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)
64e3414e 271 if (P->SelectedState == selector)
a09e4489
DK
272 packages.push_back(P.FullName(true));
273 }
274
275 std::sort(packages.begin(), packages.end());
276
c98fb5e0
DK
277 for (vector<string>::const_iterator I = packages.begin(); I != packages.end(); ++I)
278 std::cout << *I << std::endl;
279
280 return true;
281}
282 /*}}}*/
8561c2fe 283bool ShowHelp(CommandLine &) /*{{{*/
c98fb5e0 284{
cbbee23e 285 std::cout <<
c98fb5e0
DK
286 _("Usage: apt-mark [options] {auto|manual} pkg1 [pkg2 ...]\n"
287 "\n"
288 "apt-mark is a simple command line interface for marking packages\n"
d04e44ac
JR
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");
c98fb5e0
DK
292 return true;
293}
294 /*}}}*/
6079b276 295std::vector<aptDispatchWithHelp> GetCommands() /*{{{*/
c98fb5e0 296{
011188e3 297 return {
cbbee23e
DK
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}
317 };
011188e3
DK
318}
319 /*}}}*/
320int main(int argc,const char *argv[]) /*{{{*/
321{
322 InitLocale();
c98fb5e0 323
ad7e0941 324 CommandLine CmdL;
90986d4d 325 auto const Cmds = ParseCommandLine(CmdL, APT_CMD::APT_MARK, &_config, &_system, argc, argv, &ShowHelp, &GetCommands);
c98fb5e0 326
d9e518c6 327 InitOutput();
c98fb5e0 328
e7e10e47 329 return DispatchCommandLine(CmdL, Cmds);
c98fb5e0
DK
330}
331 /*}}}*/