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