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