about summary refs log tree commit diff
path: root/third_party/nix/src/nix-collect-garbage/nix-collect-garbage.cc
blob: ac8c7d9399fb0f0e2cd0c6528c56e7f6592c6dcf (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
#include <cerrno>
#include <iostream>

#include <glog/logging.h>

#include "libmain/shared.hh"
#include "libstore/globals.hh"
#include "libstore/profiles.hh"
#include "libstore/store-api.hh"
#include "nix/legacy.hh"

using namespace nix;

std::string deleteOlderThan;
bool dryRun = false;

/* If `-d' was specified, remove all old generations of all profiles.
 * Of course, this makes rollbacks to before this point in time
 * impossible. */

void removeOldGenerations(const std::string& dir) {
  if (access(dir.c_str(), R_OK) != 0) {
    return;
  }

  bool canWrite = access(dir.c_str(), W_OK) == 0;

  for (auto& i : readDirectory(dir)) {
    checkInterrupt();

    auto path = dir + "/" + i.name;
    auto type = i.type == DT_UNKNOWN ? getFileType(path) : i.type;

    if (type == DT_LNK && canWrite) {
      std::string link;
      try {
        link = readLink(path);
      } catch (SysError& e) {
        if (e.errNo == ENOENT) {
          continue;
        }
      }
      if (link.find("link") != std::string::npos) {
        LOG(INFO) << "removing old generations of profile " << path;
        if (!deleteOlderThan.empty()) {
          deleteGenerationsOlderThan(path, deleteOlderThan, dryRun);
        } else {
          deleteOldGenerations(path, dryRun);
        }
      }
    } else if (type == DT_DIR) {
      removeOldGenerations(path);
    }
  }
}

static int _main(int argc, char** argv) {
  {
    bool removeOld = false;

    GCOptions options;

    parseCmdLine(argc, argv,
                 [&](Strings::iterator& arg, const Strings::iterator& end) {
                   if (*arg == "--help") {
                     showManPage("nix-collect-garbage");
                   } else if (*arg == "--version") {
                     printVersion("nix-collect-garbage");
                   } else if (*arg == "--delete-old" || *arg == "-d") {
                     removeOld = true;
                   } else if (*arg == "--delete-older-than") {
                     removeOld = true;
                     deleteOlderThan = getArg(*arg, arg, end);
                   } else if (*arg == "--dry-run") {
                     dryRun = true;
                   } else if (*arg == "--max-freed") {
                     auto maxFreed = getIntArg<long long>(*arg, arg, end, true);
                     options.maxFreed = maxFreed >= 0 ? maxFreed : 0;
                   } else {
                     return false;
                   }
                   return true;
                 });

    auto profilesDir = settings.nixStateDir + "/profiles";
    if (removeOld) {
      removeOldGenerations(profilesDir);
    }

    // Run the actual garbage collector.
    if (!dryRun) {
      auto store = openStore();
      options.action = GCOptions::gcDeleteDead;
      GCResults results;
      PrintFreed freed(true, results);
      store->collectGarbage(options, results);
    }

    return 0;
  }
}

static RegisterLegacyCommand s1("nix-collect-garbage", _main);