1 #include "store-api.hh"
2 #include "profiles.hh"
3 #include "shared.hh"
4 #include "globals.hh"
5 #include "legacy.hh"
6 
7 #include <iostream>
8 #include <cerrno>
9 
10 using namespace nix;
11 
12 std::string deleteOlderThan;
13 bool dryRun = false;
14 
15 
16 /* If `-d' was specified, remove all old generations of all profiles.
17  * Of course, this makes rollbacks to before this point in time
18  * impossible. */
19 
removeOldGenerations(std::string dir)20 void removeOldGenerations(std::string dir)
21 {
22     if (access(dir.c_str(), R_OK) != 0) return;
23 
24     bool canWrite = access(dir.c_str(), W_OK) == 0;
25 
26     for (auto & i : readDirectory(dir)) {
27         checkInterrupt();
28 
29         auto path = dir + "/" + i.name;
30         auto type = i.type == DT_UNKNOWN ? getFileType(path) : i.type;
31 
32         if (type == DT_LNK && canWrite) {
33             std::string link;
34             try {
35                 link = readLink(path);
36             } catch (SysError & e) {
37                 if (e.errNo == ENOENT) continue;
38             }
39             if (link.find("link") != string::npos) {
40                 printInfo(format("removing old generations of profile %1%") % path);
41                 if (deleteOlderThan != "")
42                     deleteGenerationsOlderThan(path, deleteOlderThan, dryRun);
43                 else
44                     deleteOldGenerations(path, dryRun);
45             }
46         } else if (type == DT_DIR) {
47             removeOldGenerations(path);
48         }
49     }
50 }
51 
_main(int argc,char ** argv)52 static int _main(int argc, char * * argv)
53 {
54     {
55         bool removeOld = false;
56 
57         GCOptions options;
58 
59         parseCmdLine(argc, argv, [&](Strings::iterator & arg, const Strings::iterator & end) {
60             if (*arg == "--help")
61                 showManPage("nix-collect-garbage");
62             else if (*arg == "--version")
63                 printVersion("nix-collect-garbage");
64             else if (*arg == "--delete-old" || *arg == "-d") removeOld = true;
65             else if (*arg == "--delete-older-than") {
66                 removeOld = true;
67                 deleteOlderThan = getArg(*arg, arg, end);
68             }
69             else if (*arg == "--dry-run") dryRun = true;
70             else if (*arg == "--max-freed") {
71                 long long maxFreed = getIntArg<long long>(*arg, arg, end, true);
72                 options.maxFreed = maxFreed >= 0 ? maxFreed : 0;
73             }
74             else
75                 return false;
76             return true;
77         });
78 
79         initPlugins();
80 
81         auto profilesDir = settings.nixStateDir + "/profiles";
82         if (removeOld) removeOldGenerations(profilesDir);
83 
84         // Run the actual garbage collector.
85         if (!dryRun) {
86             auto store = openStore();
87             options.action = GCOptions::gcDeleteDead;
88             GCResults results;
89             PrintFreed freed(true, results);
90             store->collectGarbage(options, results);
91         }
92 
93         return 0;
94     }
95 }
96 
97 static RegisterLegacyCommand s1("nix-collect-garbage", _main);
98