]> git.saurik.com Git - apt.git/blob - cmdline/apt-mark.cc
report all instead of first error up the acquire chain
[apt.git] / cmdline / apt-mark.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 /* #####################################################################
4 apt-mark - show and change auto-installed bit information
5 ##################################################################### */
6 /*}}}*/
7 // Include Files /*{{{*/
8 #include <config.h>
9
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>
24
25 #include <apt-private/private-cmndline.h>
26 #include <apt-private/private-output.h>
27 #include <apt-private/private-main.h>
28
29 #include <errno.h>
30 #include <fcntl.h>
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>
42
43 #include <apti18n.h>
44 /*}}}*/
45 using namespace std;
46
47 /* DoAuto - mark packages as automatically/manually installed {{{*/
48 static bool DoAuto(CommandLine &CmdL)
49 {
50 pkgCacheFile CacheFile;
51 pkgDepCache * const DepCache = CacheFile.GetDepCache();
52 if (unlikely(DepCache == nullptr))
53 return false;
54
55 APT::PackageList pkgset = APT::PackageList::FromCommandLine(CacheFile, CmdL.FileList + 1);
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
62 for (APT::PackageList::const_iterator Pkg = pkgset.begin(); Pkg != pkgset.end(); ++Pkg)
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 */
94 static bool DoMarkAuto(CommandLine &CmdL)
95 {
96 pkgCacheFile CacheFile;
97 pkgDepCache * const DepCache = CacheFile.GetDepCache();
98 if (unlikely(DepCache == nullptr))
99 return false;
100
101 APT::PackageList pkgset = APT::PackageList::FromCommandLine(CacheFile, CmdL.FileList + 1);
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
109 for (APT::PackageList::const_iterator Pkg = pkgset.begin(); Pkg != pkgset.end(); ++Pkg)
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) {{{*/
130 static bool ShowAuto(CommandLine &CmdL)
131 {
132 pkgCacheFile CacheFile;
133 pkgDepCache * const DepCache = CacheFile.GetDepCache();
134 if (unlikely(DepCache == nullptr))
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 {
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));
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
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 /*}}}*/
168 // DoSelection - wrapping around dpkg selections /*{{{*/
169 static bool DoSelection(CommandLine &CmdL)
170 {
171 pkgCacheFile CacheFile;
172 pkgCache * const Cache = CacheFile.GetPkgCache();
173 if (unlikely(Cache == nullptr))
174 return false;
175
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"));
179
180 APT::StateChanges marks;
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 }
213 pkgset.clear();
214
215 bool success = true;
216 if (_config->FindB("APT::Mark::Simulate", false) == false)
217 {
218 success = marks.Save();
219 if (success == false)
220 _error->Error(_("Executing dpkg failed. Are you root?"));
221 }
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());
232 return success;
233 }
234 /*}}}*/
235 static bool ShowSelection(CommandLine &CmdL) /*{{{*/
236 {
237 pkgCacheFile CacheFile;
238 pkgCache * const Cache = CacheFile.GetPkgCache();
239 if (unlikely(Cache == nullptr))
240 return false;
241
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
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)
259 if (P->SelectedState == selector)
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)
268 if (P->SelectedState == selector)
269 packages.push_back(P.FullName(true));
270 }
271
272 std::sort(packages.begin(), packages.end());
273
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 /*}}}*/
280 static bool ShowHelp(CommandLine &) /*{{{*/
281 {
282 std::cout <<
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"
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");
289 return true;
290 }
291 /*}}}*/
292 static std::vector<aptDispatchWithHelp> GetCommands() /*{{{*/
293 {
294 return {
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 };
315 }
316 /*}}}*/
317 int main(int argc,const char *argv[]) /*{{{*/
318 {
319 CommandLine CmdL;
320 auto const Cmds = ParseCommandLine(CmdL, APT_CMD::APT_MARK, &_config, &_system, argc, argv, &ShowHelp, &GetCommands);
321
322 InitOutput();
323
324 return DispatchCommandLine(CmdL, Cmds);
325 }
326 /*}}}*/