]> git.saurik.com Git - apt.git/blob - cmdline/apt-mark.cc
provide a 'dpkg --set-selections' wrapper to set/release holds
[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 <apt-pkg/cachefile.h>
9 #include <apt-pkg/cacheset.h>
10 #include <apt-pkg/cmndline.h>
11 #include <apt-pkg/error.h>
12 #include <apt-pkg/init.h>
13 #include <apt-pkg/strutl.h>
14
15 #include <config.h>
16 #include <apti18n.h>
17
18 #include <algorithm>
19 /*}}}*/
20 using namespace std;
21
22 ostream c0out(0);
23 ostream c1out(0);
24 ostream c2out(0);
25 ofstream devnull("/dev/null");
26 /* DoAuto - mark packages as automatically/manually installed {{{*/
27 bool DoAuto(CommandLine &CmdL)
28 {
29 pkgCacheFile CacheFile;
30 pkgCache *Cache = CacheFile.GetPkgCache();
31 pkgDepCache *DepCache = CacheFile.GetDepCache();
32 if (unlikely(Cache == NULL || DepCache == NULL))
33 return false;
34
35 APT::PackageSet pkgset = APT::PackageSet::FromCommandLine(CacheFile, CmdL.FileList + 1);
36 if (pkgset.empty() == true)
37 return _error->Error(_("No packages found"));
38
39 bool MarkAuto = strcasecmp(CmdL.FileList[0],"auto") == 0;
40 int AutoMarkChanged = 0;
41
42 for (APT::PackageSet::const_iterator Pkg = pkgset.begin(); Pkg != pkgset.end(); ++Pkg)
43 {
44 if (Pkg->CurrentVer == 0)
45 {
46 ioprintf(c1out,_("%s can not be marked as it is not installed.\n"), Pkg.FullName(true).c_str());
47 continue;
48 }
49 else if ((((*DepCache)[Pkg].Flags & pkgCache::Flag::Auto) == pkgCache::Flag::Auto) == MarkAuto)
50 {
51 if (MarkAuto == false)
52 ioprintf(c1out,_("%s was already set to manually installed.\n"), Pkg.FullName(true).c_str());
53 else
54 ioprintf(c1out,_("%s was already set to automatically installed.\n"), Pkg.FullName(true).c_str());
55 continue;
56 }
57
58 if (MarkAuto == false)
59 ioprintf(c1out,_("%s set to manually installed.\n"), Pkg.FullName(true).c_str());
60 else
61 ioprintf(c1out,_("%s set to automatically installed.\n"), Pkg.FullName(true).c_str());
62
63 DepCache->MarkAuto(Pkg, MarkAuto);
64 ++AutoMarkChanged;
65 }
66 if (AutoMarkChanged > 0 && _config->FindB("APT::Mark::Simulate", false) == false)
67 return DepCache->writeStateFile(NULL);
68 return true;
69 }
70 /*}}}*/
71 /* DoMarkAuto - mark packages as automatically/manually installed {{{*/
72 /* Does the same as DoAuto but tries to do it exactly the same why as
73 the python implementation did it so it can be a drop-in replacement */
74 bool DoMarkAuto(CommandLine &CmdL)
75 {
76 pkgCacheFile CacheFile;
77 pkgCache *Cache = CacheFile.GetPkgCache();
78 pkgDepCache *DepCache = CacheFile.GetDepCache();
79 if (unlikely(Cache == NULL || DepCache == NULL))
80 return false;
81
82 APT::PackageSet pkgset = APT::PackageSet::FromCommandLine(CacheFile, CmdL.FileList + 1);
83 if (pkgset.empty() == true)
84 return _error->Error(_("No packages found"));
85
86 bool const MarkAuto = strcasecmp(CmdL.FileList[0],"markauto") == 0;
87 bool const Verbose = _config->FindB("APT::MarkAuto::Verbose", false);
88 int AutoMarkChanged = 0;
89
90 for (APT::PackageSet::const_iterator Pkg = pkgset.begin(); Pkg != pkgset.end(); ++Pkg)
91 {
92 if (Pkg->CurrentVer == 0 ||
93 (((*DepCache)[Pkg].Flags & pkgCache::Flag::Auto) == pkgCache::Flag::Auto) == MarkAuto)
94 continue;
95
96 if (Verbose == true)
97 ioprintf(c1out, "changing %s to %d\n", Pkg.Name(), (MarkAuto == false) ? 0 : 1);
98
99 DepCache->MarkAuto(Pkg, MarkAuto);
100 ++AutoMarkChanged;
101 }
102 if (AutoMarkChanged > 0 && _config->FindB("APT::Mark::Simulate", false) == false)
103 return DepCache->writeStateFile(NULL);
104
105 _error->Notice(_("This command is deprecated. Please use 'apt-mark auto' and 'apt-mark manual' instead."));
106
107 return true;
108 }
109 /*}}}*/
110 /* ShowAuto - show automatically installed packages (sorted) {{{*/
111 bool ShowAuto(CommandLine &CmdL)
112 {
113 pkgCacheFile CacheFile;
114 pkgCache *Cache = CacheFile.GetPkgCache();
115 pkgDepCache *DepCache = CacheFile.GetDepCache();
116 if (unlikely(Cache == NULL || DepCache == NULL))
117 return false;
118
119 std::vector<string> packages;
120
121 bool const ShowAuto = strcasecmp(CmdL.FileList[0],"showauto") == 0;
122
123 if (CmdL.FileList[1] == 0)
124 {
125 packages.reserve(Cache->HeaderP->PackageCount / 3);
126 for (pkgCache::PkgIterator P = Cache->PkgBegin(); P.end() == false; ++P)
127 if (P->CurrentVer != 0 &&
128 (((*DepCache)[P].Flags & pkgCache::Flag::Auto) == pkgCache::Flag::Auto) == ShowAuto)
129 packages.push_back(P.FullName(true));
130 }
131 else
132 {
133 APT::CacheSetHelper helper(false); // do not show errors
134 APT::PackageSet pkgset = APT::PackageSet::FromCommandLine(CacheFile, CmdL.FileList + 1, helper);
135 packages.reserve(pkgset.size());
136 for (APT::PackageSet::const_iterator P = pkgset.begin(); P != pkgset.end(); ++P)
137 if (P->CurrentVer != 0 &&
138 (((*DepCache)[P].Flags & pkgCache::Flag::Auto) == pkgCache::Flag::Auto) == ShowAuto)
139 packages.push_back(P.FullName(true));
140 }
141
142 std::sort(packages.begin(), packages.end());
143
144 for (vector<string>::const_iterator I = packages.begin(); I != packages.end(); ++I)
145 std::cout << *I << std::endl;
146
147 return true;
148 }
149 /*}}}*/
150 /* DoHold - mark packages as hold by dpkg {{{*/
151 bool DoHold(CommandLine &CmdL)
152 {
153 pkgCacheFile CacheFile;
154 pkgCache *Cache = CacheFile.GetPkgCache();
155 if (unlikely(Cache == NULL))
156 return false;
157
158 APT::PackageSet pkgset = APT::PackageSet::FromCommandLine(CacheFile, CmdL.FileList + 1);
159 if (pkgset.empty() == true)
160 return _error->Error(_("No packages found"));
161
162 bool const MarkHold = strcasecmp(CmdL.FileList[0],"hold") == 0;
163
164 for (APT::PackageSet::iterator Pkg = pkgset.begin(); Pkg != pkgset.end(); ++Pkg)
165 {
166 if ((Pkg->SelectedState == pkgCache::State::Hold) == MarkHold)
167 {
168 if (MarkHold == true)
169 ioprintf(c1out,_("%s was already set on hold.\n"), Pkg.FullName(true).c_str());
170 else
171 ioprintf(c1out,_("%s was already not hold.\n"), Pkg.FullName(true).c_str());
172 pkgset.erase(Pkg);
173 continue;
174 }
175 }
176
177 if (pkgset.empty() == true)
178 return true;
179
180 if (_config->FindB("APT::Mark::Simulate", false) == true)
181 {
182 for (APT::PackageSet::iterator Pkg = pkgset.begin(); Pkg != pkgset.end(); ++Pkg)
183 {
184 if (MarkHold == false)
185 ioprintf(c1out,_("%s set on hold.\n"), Pkg.FullName(true).c_str());
186 else
187 ioprintf(c1out,_("Canceled hold on %s.\n"), Pkg.FullName(true).c_str());
188 }
189 return true;
190 }
191
192 string dpkgcall = _config->Find("Dir::Bin::dpkg", "dpkg");
193 std::vector<string> const dpkgoptions = _config->FindVector("DPkg::options");
194 for (std::vector<string>::const_iterator o = dpkgoptions.begin();
195 o != dpkgoptions.end(); ++o)
196 dpkgcall.append(" ").append(*o);
197 dpkgcall.append(" --set-selections");
198 FILE *dpkg = popen(dpkgcall.c_str(), "w");
199 if (dpkg == NULL)
200 return _error->Errno("DoHold", "fdopen on dpkg stdin failed");
201
202 for (APT::PackageSet::iterator Pkg = pkgset.begin(); Pkg != pkgset.end(); ++Pkg)
203 {
204 if (MarkHold == true)
205 {
206 fprintf(dpkg, "%s hold\n", Pkg.FullName(true).c_str());
207 ioprintf(c1out,_("%s set on hold.\n"), Pkg.FullName(true).c_str());
208 }
209 else
210 {
211 fprintf(dpkg, "%s install\n", Pkg.FullName(true).c_str());
212 ioprintf(c1out,_("Canceled hold on %s.\n"), Pkg.FullName(true).c_str());
213 }
214 }
215
216 int const status = pclose(dpkg);
217 if (status == -1)
218 return _error->Errno("DoHold", "dpkg execution failed in the end");
219 if (WIFEXITED(status) == false || WEXITSTATUS(status) != 0)
220 return _error->Error(_("Executing dpkg failed. Are you root?"));
221 return true;
222 }
223 /*}}}*/
224 /* ShowHold - show packages set on hold in dpkg status {{{*/
225 bool ShowHold(CommandLine &CmdL)
226 {
227 pkgCacheFile CacheFile;
228 pkgCache *Cache = CacheFile.GetPkgCache();
229 if (unlikely(Cache == NULL))
230 return false;
231
232 std::vector<string> packages;
233
234 if (CmdL.FileList[1] == 0)
235 {
236 packages.reserve(50); // how many holds are realistic? I hope just a few…
237 for (pkgCache::PkgIterator P = Cache->PkgBegin(); P.end() == false; ++P)
238 if (P->SelectedState == pkgCache::State::Hold)
239 packages.push_back(P.FullName(true));
240 }
241 else
242 {
243 APT::CacheSetHelper helper(false); // do not show errors
244 APT::PackageSet pkgset = APT::PackageSet::FromCommandLine(CacheFile, CmdL.FileList + 1, helper);
245 packages.reserve(pkgset.size());
246 for (APT::PackageSet::const_iterator P = pkgset.begin(); P != pkgset.end(); ++P)
247 if (P->SelectedState == pkgCache::State::Hold)
248 packages.push_back(P.FullName(true));
249 }
250
251 std::sort(packages.begin(), packages.end());
252
253 for (vector<string>::const_iterator I = packages.begin(); I != packages.end(); ++I)
254 std::cout << *I << std::endl;
255
256 return true;
257 }
258 /*}}}*/
259 // ShowHelp - Show a help screen /*{{{*/
260 // ---------------------------------------------------------------------
261 /* */
262 bool ShowHelp(CommandLine &CmdL)
263 {
264 ioprintf(cout,_("%s %s for %s compiled on %s %s\n"),PACKAGE,VERSION,
265 COMMON_ARCH,__DATE__,__TIME__);
266
267 cout <<
268 _("Usage: apt-mark [options] {auto|manual} pkg1 [pkg2 ...]\n"
269 "\n"
270 "apt-mark is a simple command line interface for marking packages\n"
271 "as manual or automatical installed. It can also list marks.\n"
272 "\n"
273 "Commands:\n"
274 " auto - Mark the given packages as automatically installed\n"
275 " manual - Mark the given packages as manually installed\n"
276 "\n"
277 "Options:\n"
278 " -h This help text.\n"
279 " -q Loggable output - no progress indicator\n"
280 " -qq No output except for errors\n"
281 " -s No-act. Just prints what would be done.\n"
282 " -f read/write auto/manual marking in the given file\n"
283 " -c=? Read this configuration file\n"
284 " -o=? Set an arbitrary configuration option, eg -o dir::cache=/tmp\n"
285 "See the apt-mark(8) and apt.conf(5) manual pages for more information.")
286 << std::endl;
287 return true;
288 }
289 /*}}}*/
290 int main(int argc,const char *argv[]) /*{{{*/
291 {
292 CommandLine::Args Args[] = {
293 {'h',"help","help",0},
294 {0,"version","version",0},
295 {'q',"quiet","quiet",CommandLine::IntLevel},
296 {'q',"silent","quiet",CommandLine::IntLevel},
297 {'v',"verbose","APT::MarkAuto::Verbose",0},
298 {'s',"simulate","APT::Mark::Simulate",0},
299 {'s',"just-print","APT::Mark::Simulate",0},
300 {'s',"recon","APT::Mark::Simulate",0},
301 {'s',"dry-run","APT::Mark::Simulate",0},
302 {'s',"no-act","APT::Mark::Simulate",0},
303 {'f',"file","Dir::State::extended_states",CommandLine::HasArg},
304 {'c',"config-file",0,CommandLine::ConfigFile},
305 {'o',"option",0,CommandLine::ArbItem},
306 {0,0,0,0}};
307 CommandLine::Dispatch Cmds[] = {{"help",&ShowHelp},
308 {"auto",&DoAuto},
309 {"manual",&DoAuto},
310 {"hold",&DoHold},
311 {"unhold",&DoHold},
312 {"showauto",&ShowAuto},
313 {"showmanual",&ShowAuto},
314 {"showhold",&ShowHold},
315 // be nice and forgive the typo
316 {"showholds",&ShowHold},
317 // be nice and forgive it as it is technical right
318 {"install",&DoHold},
319 // obsolete commands for compatibility
320 {"markauto", &DoMarkAuto},
321 {"unmarkauto", &DoMarkAuto},
322 {0,0}};
323
324 // Set up gettext support
325 setlocale(LC_ALL,"");
326 textdomain(PACKAGE);
327
328 // Parse the command line and initialize the package library
329 CommandLine CmdL(Args,_config);
330 if (pkgInitConfig(*_config) == false ||
331 CmdL.Parse(argc,argv) == false ||
332 pkgInitSystem(*_config,_system) == false)
333 {
334 if (_config->FindB("version") == true)
335 ShowHelp(CmdL);
336 _error->DumpErrors();
337 return 100;
338 }
339
340 // See if the help should be shown
341 if (_config->FindB("help") == true ||
342 _config->FindB("version") == true ||
343 CmdL.FileSize() == 0)
344 {
345 ShowHelp(CmdL);
346 return 0;
347 }
348
349 // Deal with stdout not being a tty
350 if (!isatty(STDOUT_FILENO) && _config->FindI("quiet", -1) == -1)
351 _config->Set("quiet","1");
352
353 // Setup the output streams
354 c0out.rdbuf(cout.rdbuf());
355 c1out.rdbuf(cout.rdbuf());
356 c2out.rdbuf(cout.rdbuf());
357 if (_config->FindI("quiet",0) > 0)
358 c0out.rdbuf(devnull.rdbuf());
359 if (_config->FindI("quiet",0) > 1)
360 c1out.rdbuf(devnull.rdbuf());
361
362 // Match the operation
363 CmdL.DispatchArg(Cmds);
364
365 // Print any errors or warnings found during parsing
366 bool const Errors = _error->PendingError();
367 if (_config->FindI("quiet",0) > 0)
368 _error->DumpErrors();
369 else
370 _error->DumpErrors(GlobalError::DEBUG);
371 return Errors == true ? 100 : 0;
372 }
373 /*}}}*/