]> git.saurik.com Git - apt.git/blob - cmdline/apt-mark.cc
Deal with killed acquire methods properly instead of hanging
[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 pkgCache *Cache = CacheFile.GetPkgCache();
52 pkgDepCache *DepCache = CacheFile.GetDepCache();
53 if (unlikely(Cache == NULL || DepCache == NULL))
54 return false;
55
56 APT::PackageList pkgset = APT::PackageList::FromCommandLine(CacheFile, CmdL.FileList + 1);
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
63 for (APT::PackageList::const_iterator Pkg = pkgset.begin(); Pkg != pkgset.end(); ++Pkg)
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 */
95 static bool DoMarkAuto(CommandLine &CmdL)
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
103 APT::PackageList pkgset = APT::PackageList::FromCommandLine(CacheFile, CmdL.FileList + 1);
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
111 for (APT::PackageList::const_iterator Pkg = pkgset.begin(); Pkg != pkgset.end(); ++Pkg)
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) {{{*/
132 static bool ShowAuto(CommandLine &CmdL)
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
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 /*}}}*/
171 // DoSelection - wrapping around dpkg selections /*{{{*/
172 static bool DoSelection(CommandLine &CmdL)
173 {
174 pkgCacheFile CacheFile;
175 pkgCache *Cache = CacheFile.GetPkgCache();
176 if (unlikely(Cache == NULL))
177 return false;
178
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"));
182
183 APT::StateChanges marks;
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 }
216 pkgset.clear();
217
218 bool success = true;
219 if (_config->FindB("APT::Mark::Simulate", false) == false)
220 {
221 success = marks.Save();
222 if (success == false)
223 _error->Error(_("Executing dpkg failed. Are you root?"));
224 }
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());
235 return success;
236 }
237 /*}}}*/
238 static bool ShowSelection(CommandLine &CmdL) /*{{{*/
239 {
240 pkgCacheFile CacheFile;
241 pkgCache *Cache = CacheFile.GetPkgCache();
242 if (unlikely(Cache == NULL))
243 return false;
244
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
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)
262 if (P->SelectedState == selector)
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)
271 if (P->SelectedState == selector)
272 packages.push_back(P.FullName(true));
273 }
274
275 std::sort(packages.begin(), packages.end());
276
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 /*}}}*/
283 bool ShowHelp(CommandLine &) /*{{{*/
284 {
285 std::cout <<
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"
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");
292 return true;
293 }
294 /*}}}*/
295 std::vector<aptDispatchWithHelp> GetCommands() /*{{{*/
296 {
297 return {
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 };
318 }
319 /*}}}*/
320 int main(int argc,const char *argv[]) /*{{{*/
321 {
322 InitLocale();
323
324 CommandLine CmdL;
325 auto const Cmds = ParseCommandLine(CmdL, APT_CMD::APT_MARK, &_config, &_system, argc, argv);
326
327 InitOutput();
328
329 return DispatchCommandLine(CmdL, Cmds);
330 }
331 /*}}}*/