]> git.saurik.com Git - apt.git/blame - cmdline/apt-mark.cc
The entire concept of PendingError() is flawed :/.
[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;
fdf9eef4
DK
51 pkgDepCache * const DepCache = CacheFile.GetDepCache();
52 if (unlikely(DepCache == nullptr))
c98fb5e0
DK
53 return false;
54
c4cca791 55 APT::PackageList pkgset = APT::PackageList::FromCommandLine(CacheFile, CmdL.FileList + 1);
c98fb5e0
DK
56 if (pkgset.empty() == true)
57 return _error->Error(_("No packages found"));
58
59 bool MarkAuto = strcasecmp(CmdL.FileList[0],"auto") == 0;
60 int AutoMarkChanged = 0;
61
c4cca791 62 for (APT::PackageList::const_iterator Pkg = pkgset.begin(); Pkg != pkgset.end(); ++Pkg)
c98fb5e0
DK
63 {
64 if (Pkg->CurrentVer == 0)
65 {
66 ioprintf(c1out,_("%s can not be marked as it is not installed.\n"), Pkg.FullName(true).c_str());
67 continue;
68 }
69 else if ((((*DepCache)[Pkg].Flags & pkgCache::Flag::Auto) == pkgCache::Flag::Auto) == MarkAuto)
70 {
71 if (MarkAuto == false)
72 ioprintf(c1out,_("%s was already set to manually installed.\n"), Pkg.FullName(true).c_str());
73 else
74 ioprintf(c1out,_("%s was already set to automatically installed.\n"), Pkg.FullName(true).c_str());
75 continue;
76 }
77
78 if (MarkAuto == false)
79 ioprintf(c1out,_("%s set to manually installed.\n"), Pkg.FullName(true).c_str());
80 else
81 ioprintf(c1out,_("%s set to automatically installed.\n"), Pkg.FullName(true).c_str());
82
83 DepCache->MarkAuto(Pkg, MarkAuto);
84 ++AutoMarkChanged;
85 }
86 if (AutoMarkChanged > 0 && _config->FindB("APT::Mark::Simulate", false) == false)
87 return DepCache->writeStateFile(NULL);
88 return true;
89}
90 /*}}}*/
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 */
c3ccac92 94static bool DoMarkAuto(CommandLine &CmdL)
c98fb5e0
DK
95{
96 pkgCacheFile CacheFile;
fdf9eef4
DK
97 pkgDepCache * const DepCache = CacheFile.GetDepCache();
98 if (unlikely(DepCache == nullptr))
c98fb5e0
DK
99 return false;
100
c4cca791 101 APT::PackageList pkgset = APT::PackageList::FromCommandLine(CacheFile, CmdL.FileList + 1);
c98fb5e0
DK
102 if (pkgset.empty() == true)
103 return _error->Error(_("No packages found"));
104
105 bool const MarkAuto = strcasecmp(CmdL.FileList[0],"markauto") == 0;
106 bool const Verbose = _config->FindB("APT::MarkAuto::Verbose", false);
107 int AutoMarkChanged = 0;
108
c4cca791 109 for (APT::PackageList::const_iterator Pkg = pkgset.begin(); Pkg != pkgset.end(); ++Pkg)
c98fb5e0
DK
110 {
111 if (Pkg->CurrentVer == 0 ||
112 (((*DepCache)[Pkg].Flags & pkgCache::Flag::Auto) == pkgCache::Flag::Auto) == MarkAuto)
113 continue;
114
115 if (Verbose == true)
116 ioprintf(c1out, "changing %s to %d\n", Pkg.Name(), (MarkAuto == false) ? 0 : 1);
117
118 DepCache->MarkAuto(Pkg, MarkAuto);
119 ++AutoMarkChanged;
120 }
121 if (AutoMarkChanged > 0 && _config->FindB("APT::Mark::Simulate", false) == false)
122 return DepCache->writeStateFile(NULL);
123
124 _error->Notice(_("This command is deprecated. Please use 'apt-mark auto' and 'apt-mark manual' instead."));
125
126 return true;
127}
128 /*}}}*/
129/* ShowAuto - show automatically installed packages (sorted) {{{*/
c3ccac92 130static bool ShowAuto(CommandLine &CmdL)
c98fb5e0
DK
131{
132 pkgCacheFile CacheFile;
fdf9eef4
DK
133 pkgDepCache * const DepCache = CacheFile.GetDepCache();
134 if (unlikely(DepCache == nullptr))
c98fb5e0
DK
135 return false;
136
137 std::vector<string> packages;
138
139 bool const ShowAuto = strcasecmp(CmdL.FileList[0],"showauto") == 0;
140
141 if (CmdL.FileList[1] == 0)
142 {
fdf9eef4
DK
143 packages.reserve(DepCache->Head().PackageCount / 3);
144 for (pkgCache::PkgIterator P = DepCache->PkgBegin(); P.end() == false; ++P)
c98fb5e0
DK
145 if (P->CurrentVer != 0 &&
146 (((*DepCache)[P].Flags & pkgCache::Flag::Auto) == pkgCache::Flag::Auto) == ShowAuto)
147 packages.push_back(P.FullName(true));
148 }
149 else
150 {
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));
158 }
159
160 std::sort(packages.begin(), packages.end());
161
a09e4489
DK
162 for (vector<string>::const_iterator I = packages.begin(); I != packages.end(); ++I)
163 std::cout << *I << std::endl;
164
165 return true;
166}
167 /*}}}*/
64e3414e
DK
168// DoSelection - wrapping around dpkg selections /*{{{*/
169static bool DoSelection(CommandLine &CmdL)
a09e4489
DK
170{
171 pkgCacheFile CacheFile;
fdf9eef4
DK
172 pkgCache * const Cache = CacheFile.GetPkgCache();
173 if (unlikely(Cache == nullptr))
a09e4489
DK
174 return false;
175
c1553e72 176 APT::VersionVector pkgset = APT::VersionVector::FromCommandLine(CacheFile, CmdL.FileList + 1, APT::CacheSetHelper::INSTCAND);
b2a893dd
DK
177 if (pkgset.empty() == true)
178 return _error->Error(_("No packages found"));
179
b49068c5 180 APT::StateChanges marks;
64e3414e
DK
181 if (strcasecmp(CmdL.FileList[0], "hold") == 0 || strcasecmp(CmdL.FileList[0], "unhold") == 0)
182 {
183 auto const part = std::stable_partition(pkgset.begin(), pkgset.end(),
184 [](pkgCache::VerIterator const &V) { return V.ParentPkg()->SelectedState == pkgCache::State::Hold; });
185
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());
192 else
193 ioprintf(c1out, _("%s was already not hold.\n"), V.ParentPkg().FullName(true).c_str());
194 });
195
196 if (doneBegin == pkgset.begin() && doneEnd == pkgset.end())
197 return true;
198
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()));
202 }
203 else
204 {
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);
212 }
b49068c5 213 pkgset.clear();
6fddb156 214
b49068c5
DK
215 bool success = true;
216 if (_config->FindB("APT::Mark::Simulate", false) == false)
6fddb156 217 {
b49068c5
DK
218 success = marks.Save();
219 if (success == false)
220 _error->Error(_("Executing dpkg failed. Are you root?"));
6fddb156 221 }
b49068c5
DK
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());
64e3414e
DK
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());
b49068c5 232 return success;
a09e4489
DK
233}
234 /*}}}*/
64e3414e 235static bool ShowSelection(CommandLine &CmdL) /*{{{*/
a09e4489
DK
236{
237 pkgCacheFile CacheFile;
fdf9eef4
DK
238 pkgCache * const Cache = CacheFile.GetPkgCache();
239 if (unlikely(Cache == nullptr))
a09e4489
DK
240 return false;
241
64e3414e
DK
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;
252
a09e4489
DK
253 std::vector<string> packages;
254
255 if (CmdL.FileList[1] == 0)
256 {
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)
64e3414e 259 if (P->SelectedState == selector)
a09e4489
DK
260 packages.push_back(P.FullName(true));
261 }
262 else
263 {
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)
64e3414e 268 if (P->SelectedState == selector)
a09e4489
DK
269 packages.push_back(P.FullName(true));
270 }
271
272 std::sort(packages.begin(), packages.end());
273
c98fb5e0
DK
274 for (vector<string>::const_iterator I = packages.begin(); I != packages.end(); ++I)
275 std::cout << *I << std::endl;
276
277 return true;
278}
279 /*}}}*/
f6777222 280static bool ShowHelp(CommandLine &) /*{{{*/
c98fb5e0 281{
cbbee23e 282 std::cout <<
c98fb5e0
DK
283 _("Usage: apt-mark [options] {auto|manual} pkg1 [pkg2 ...]\n"
284 "\n"
285 "apt-mark is a simple command line interface for marking packages\n"
d04e44ac
JR
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");
c98fb5e0
DK
289 return true;
290}
291 /*}}}*/
f6777222 292static std::vector<aptDispatchWithHelp> GetCommands() /*{{{*/
c98fb5e0 293{
011188e3 294 return {
cbbee23e
DK
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}
314 };
011188e3
DK
315}
316 /*}}}*/
317int main(int argc,const char *argv[]) /*{{{*/
318{
ad7e0941 319 CommandLine CmdL;
90986d4d 320 auto const Cmds = ParseCommandLine(CmdL, APT_CMD::APT_MARK, &_config, &_system, argc, argv, &ShowHelp, &GetCommands);
c98fb5e0 321
d9e518c6 322 InitOutput();
c98fb5e0 323
e7e10e47 324 return DispatchCommandLine(CmdL, Cmds);
c98fb5e0
DK
325}
326 /*}}}*/