Merge branch 'master' into core-updates
[jackhill/guix/guix.git] / nix / libstore / gc.cc
1 #include "globals.hh"
2 #include "misc.hh"
3 #include "local-store.hh"
4
5 #include <functional>
6 #include <queue>
7 #include <algorithm>
8
9 #include <sys/types.h>
10 #include <sys/stat.h>
11 #include <errno.h>
12 #include <fcntl.h>
13 #include <unistd.h>
14 #include <climits>
15
16
17 namespace nix {
18
19
20 static string gcLockName = "gc.lock";
21 static string tempRootsDir = "temproots";
22 static string gcRootsDir = "gcroots";
23
24
25 /* Acquire the global GC lock. This is used to prevent new build
26 processes from starting after the temporary root files have been
27 read. To be precise: when they try to create a new temporary root
28 file, they will block until the garbage collector has finished /
29 yielded the GC lock. */
30 int LocalStore::openGCLock(LockType lockType)
31 {
32 Path fnGCLock = (format("%1%/%2%")
33 % settings.nixStateDir % gcLockName).str();
34
35 debug(format("acquiring global GC lock `%1%'") % fnGCLock);
36
37 AutoCloseFD fdGCLock = open(fnGCLock.c_str(), O_RDWR | O_CREAT, 0600);
38 if (fdGCLock == -1)
39 throw SysError(format("opening global GC lock `%1%'") % fnGCLock);
40 closeOnExec(fdGCLock);
41
42 if (!lockFile(fdGCLock, lockType, false)) {
43 printMsg(lvlError, format("waiting for the big garbage collector lock..."));
44 lockFile(fdGCLock, lockType, true);
45 }
46
47 /* !!! Restrict read permission on the GC root. Otherwise any
48 process that can open the file for reading can DoS the
49 collector. */
50
51 return fdGCLock.borrow();
52 }
53
54
55 static void makeSymlink(const Path & link, const Path & target)
56 {
57 /* Create directories up to `gcRoot'. */
58 createDirs(dirOf(link));
59
60 /* Create the new symlink. */
61 Path tempLink = (format("%1%.tmp-%2%-%3%")
62 % link % getpid() % rand()).str();
63 createSymlink(target, tempLink);
64
65 /* Atomically replace the old one. */
66 if (rename(tempLink.c_str(), link.c_str()) == -1)
67 throw SysError(format("cannot rename `%1%' to `%2%'")
68 % tempLink % link);
69 }
70
71
72 void LocalStore::syncWithGC()
73 {
74 AutoCloseFD fdGCLock = openGCLock(ltRead);
75 }
76
77
78 void LocalStore::addIndirectRoot(const Path & path)
79 {
80 string hash = printHash32(hashString(htSHA1, path));
81 Path realRoot = canonPath((format("%1%/%2%/auto/%3%")
82 % settings.nixStateDir % gcRootsDir % hash).str());
83 makeSymlink(realRoot, path);
84 }
85
86
87 Path addPermRoot(StoreAPI & store, const Path & _storePath,
88 const Path & _gcRoot, bool indirect, bool allowOutsideRootsDir)
89 {
90 Path storePath(canonPath(_storePath));
91 Path gcRoot(canonPath(_gcRoot));
92 assertStorePath(storePath);
93
94 if (isInStore(gcRoot))
95 throw Error(format(
96 "creating a garbage collector root (%1%) in the store is forbidden "
97 "(are you running nix-build inside the store?)") % gcRoot);
98
99 if (indirect) {
100 /* Don't clobber the link if it already exists and doesn't
101 point to the store. */
102 if (pathExists(gcRoot) && (!isLink(gcRoot) || !isInStore(readLink(gcRoot))))
103 throw Error(format("cannot create symlink `%1%'; already exists") % gcRoot);
104 makeSymlink(gcRoot, storePath);
105 store.addIndirectRoot(gcRoot);
106 }
107
108 else {
109 if (!allowOutsideRootsDir) {
110 Path rootsDir = canonPath((format("%1%/%2%") % settings.nixStateDir % gcRootsDir).str());
111
112 if (string(gcRoot, 0, rootsDir.size() + 1) != rootsDir + "/")
113 throw Error(format(
114 "path `%1%' is not a valid garbage collector root; "
115 "it's not in the directory `%2%'")
116 % gcRoot % rootsDir);
117 }
118
119 if (baseNameOf(gcRoot) == baseNameOf(storePath))
120 writeFile(gcRoot, "");
121 else
122 makeSymlink(gcRoot, storePath);
123 }
124
125 /* Check that the root can be found by the garbage collector.
126 !!! This can be very slow on machines that have many roots.
127 Instead of reading all the roots, it would be more efficient to
128 check if the root is in a directory in or linked from the
129 gcroots directory. */
130 if (settings.checkRootReachability) {
131 Roots roots = store.findRoots();
132 if (roots.find(gcRoot) == roots.end())
133 printMsg(lvlError,
134 format(
135 "warning: `%1%' is not in a directory where the garbage collector looks for roots; "
136 "therefore, `%2%' might be removed by the garbage collector")
137 % gcRoot % storePath);
138 }
139
140 /* Grab the global GC root, causing us to block while a GC is in
141 progress. This prevents the set of permanent roots from
142 increasing while a GC is in progress. */
143 store.syncWithGC();
144
145 return gcRoot;
146 }
147
148
149 void LocalStore::addTempRoot(const Path & path)
150 {
151 /* Create the temporary roots file for this process. */
152 if (fdTempRoots == -1) {
153
154 while (1) {
155 Path dir = (format("%1%/%2%") % settings.nixStateDir % tempRootsDir).str();
156 createDirs(dir);
157
158 fnTempRoots = (format("%1%/%2%")
159 % dir % getpid()).str();
160
161 AutoCloseFD fdGCLock = openGCLock(ltRead);
162
163 if (pathExists(fnTempRoots))
164 /* It *must* be stale, since there can be no two
165 processes with the same pid. */
166 unlink(fnTempRoots.c_str());
167
168 fdTempRoots = openLockFile(fnTempRoots, true);
169
170 fdGCLock.close();
171
172 debug(format("acquiring read lock on `%1%'") % fnTempRoots);
173 lockFile(fdTempRoots, ltRead, true);
174
175 /* Check whether the garbage collector didn't get in our
176 way. */
177 struct stat st;
178 if (fstat(fdTempRoots, &st) == -1)
179 throw SysError(format("statting `%1%'") % fnTempRoots);
180 if (st.st_size == 0) break;
181
182 /* The garbage collector deleted this file before we could
183 get a lock. (It won't delete the file after we get a
184 lock.) Try again. */
185 }
186
187 }
188
189 /* Upgrade the lock to a write lock. This will cause us to block
190 if the garbage collector is holding our lock. */
191 debug(format("acquiring write lock on `%1%'") % fnTempRoots);
192 lockFile(fdTempRoots, ltWrite, true);
193
194 string s = path + '\0';
195 writeFull(fdTempRoots, s);
196
197 /* Downgrade to a read lock. */
198 debug(format("downgrading to read lock on `%1%'") % fnTempRoots);
199 lockFile(fdTempRoots, ltRead, true);
200 }
201
202
203 typedef std::shared_ptr<AutoCloseFD> FDPtr;
204 typedef list<FDPtr> FDs;
205
206
207 static void readTempRoots(PathSet & tempRoots, FDs & fds)
208 {
209 /* Read the `temproots' directory for per-process temporary root
210 files. */
211 DirEntries tempRootFiles = readDirectory(
212 (format("%1%/%2%") % settings.nixStateDir % tempRootsDir).str());
213
214 for (auto & i : tempRootFiles) {
215 Path path = (format("%1%/%2%/%3%") % settings.nixStateDir % tempRootsDir % i.name).str();
216
217 debug(format("reading temporary root file `%1%'") % path);
218 FDPtr fd(new AutoCloseFD(open(path.c_str(), O_RDWR, 0666)));
219 if (*fd == -1) {
220 /* It's okay if the file has disappeared. */
221 if (errno == ENOENT) continue;
222 throw SysError(format("opening temporary roots file `%1%'") % path);
223 }
224
225 /* This should work, but doesn't, for some reason. */
226 //FDPtr fd(new AutoCloseFD(openLockFile(path, false)));
227 //if (*fd == -1) continue;
228
229 /* Try to acquire a write lock without blocking. This can
230 only succeed if the owning process has died. In that case
231 we don't care about its temporary roots. */
232 if (lockFile(*fd, ltWrite, false)) {
233 printMsg(lvlError, format("removing stale temporary roots file `%1%'") % path);
234 unlink(path.c_str());
235 writeFull(*fd, "d");
236 continue;
237 }
238
239 /* Acquire a read lock. This will prevent the owning process
240 from upgrading to a write lock, therefore it will block in
241 addTempRoot(). */
242 debug(format("waiting for read lock on `%1%'") % path);
243 lockFile(*fd, ltRead, true);
244
245 /* Read the entire file. */
246 string contents = readFile(*fd);
247
248 /* Extract the roots. */
249 string::size_type pos = 0, end;
250
251 while ((end = contents.find((char) 0, pos)) != string::npos) {
252 Path root(contents, pos, end - pos);
253 debug(format("got temporary root `%1%'") % root);
254 assertStorePath(root);
255 tempRoots.insert(root);
256 pos = end + 1;
257 }
258
259 fds.push_back(fd); /* keep open */
260 }
261 }
262
263
264 static void foundRoot(StoreAPI & store,
265 const Path & path, const Path & target, Roots & roots)
266 {
267 Path storePath = toStorePath(target);
268 if (store.isValidPath(storePath))
269 roots[path] = storePath;
270 else
271 printMsg(lvlInfo, format("skipping invalid root from `%1%' to `%2%'") % path % storePath);
272 }
273
274
275 static void findRoots(StoreAPI & store, const Path & path, unsigned char type, Roots & roots)
276 {
277 try {
278
279 if (type == DT_UNKNOWN)
280 type = getFileType(path);
281
282 if (type == DT_DIR) {
283 for (auto & i : readDirectory(path))
284 findRoots(store, path + "/" + i.name, i.type, roots);
285 }
286
287 else if (type == DT_LNK) {
288 Path target = readLink(path);
289 if (isInStore(target))
290 foundRoot(store, path, target, roots);
291
292 /* Handle indirect roots. */
293 else {
294 target = absPath(target, dirOf(path));
295 if (!pathExists(target)) {
296 if (isInDir(path, settings.nixStateDir + "/" + gcRootsDir + "/auto")) {
297 printMsg(lvlInfo, format("removing stale link from `%1%' to `%2%'") % path % target);
298 unlink(path.c_str());
299 }
300 } else {
301 struct stat st2 = lstat(target);
302 if (!S_ISLNK(st2.st_mode)) return;
303 Path target2 = readLink(target);
304 if (isInStore(target2)) foundRoot(store, target, target2, roots);
305 }
306 }
307 }
308
309 else if (type == DT_REG) {
310 Path storePath = settings.nixStore + "/" + baseNameOf(path);
311 if (store.isValidPath(storePath))
312 roots[path] = storePath;
313 }
314
315 }
316
317 catch (SysError & e) {
318 /* We only ignore permanent failures. */
319 if (e.errNo == EACCES || e.errNo == ENOENT || e.errNo == ENOTDIR)
320 printMsg(lvlInfo, format("cannot read potential root `%1%'") % path);
321 else
322 throw;
323 }
324 }
325
326
327 Roots LocalStore::findRoots()
328 {
329 Roots roots;
330
331 /* Process direct roots in {gcroots,manifests,profiles}. */
332 nix::findRoots(*this, settings.nixStateDir + "/" + gcRootsDir, DT_UNKNOWN, roots);
333 if (pathExists(settings.nixStateDir + "/manifests"))
334 nix::findRoots(*this, settings.nixStateDir + "/manifests", DT_UNKNOWN, roots);
335 nix::findRoots(*this, settings.nixStateDir + "/profiles", DT_UNKNOWN, roots);
336
337 return roots;
338 }
339
340
341 static void addAdditionalRoots(StoreAPI & store, PathSet & roots)
342 {
343 debug(format("executing `%1% gc --list-busy' to find additional roots")
344 % settings.guixProgram);
345
346 const Strings args = { "gc", "--list-busy" };
347 string result = runProgram(settings.guixProgram, false, args);
348
349 StringSet paths = tokenizeString<StringSet>(result, "\n");
350
351 foreach (StringSet::iterator, i, paths) {
352 if (isInStore(*i)) {
353 Path path = toStorePath(*i);
354 if (roots.find(path) == roots.end() && store.isValidPath(path)) {
355 debug(format("got additional root `%1%'") % path);
356 roots.insert(path);
357 }
358 }
359 }
360 }
361
362
363 struct GCLimitReached { };
364
365
366 struct LocalStore::GCState
367 {
368 GCOptions options;
369 GCResults & results;
370 PathSet roots;
371 PathSet tempRoots;
372 PathSet dead;
373 PathSet alive;
374 bool gcKeepOutputs;
375 bool gcKeepDerivations;
376 unsigned long long bytesInvalidated;
377 bool moveToTrash = true;
378 Path trashDir;
379 bool shouldDelete;
380 GCState(GCResults & results_) : results(results_), bytesInvalidated(0) { }
381 };
382
383
384 bool LocalStore::isActiveTempFile(const GCState & state,
385 const Path & path, const string & suffix)
386 {
387 return hasSuffix(path, suffix)
388 && state.tempRoots.find(string(path, 0, path.size() - suffix.size())) != state.tempRoots.end();
389 }
390
391
392 void LocalStore::deleteGarbage(GCState & state, const Path & path)
393 {
394 unsigned long long bytesFreed;
395
396 /* When deduplication is on, store items always have at least two links:
397 the one at PATH, and one in /gnu/store/.links. In that case, increase
398 bytesFreed when PATH has two or fewer links. */
399 size_t linkThreshold =
400 (settings.autoOptimiseStore && isStorePath(path)) ? 2 : 1;
401
402 deletePath(path, bytesFreed, linkThreshold);
403 state.results.bytesFreed += bytesFreed;
404 }
405
406
407 void LocalStore::deletePathRecursive(GCState & state, const Path & path)
408 {
409 checkInterrupt();
410
411 unsigned long long size = 0;
412
413 if (isValidPath(path)) {
414 PathSet referrers;
415 queryReferrers(path, referrers);
416 foreach (PathSet::iterator, i, referrers)
417 if (*i != path) deletePathRecursive(state, *i);
418 size = queryPathInfo(path).narSize;
419 invalidatePathChecked(path);
420 }
421
422 struct stat st;
423 if (lstat(path.c_str(), &st)) {
424 if (errno == ENOENT) return;
425 throw SysError(format("getting status of %1%") % path);
426 }
427
428 if (state.options.maxFreed != ULLONG_MAX) {
429 auto freed = state.results.bytesFreed + state.bytesInvalidated;
430 double fraction = ((double) freed) / (double) state.options.maxFreed;
431 unsigned int percentage = (fraction > 1. ? 1. : fraction) * 100.;
432 printMsg(lvlInfo, format("[%1%%%] deleting '%2%'") % percentage % path);
433 } else {
434 auto freed = state.results.bytesFreed + state.bytesInvalidated;
435 freed /= 1024ULL * 1024ULL;
436 printMsg(lvlInfo, format("[%1% MiB] deleting '%2%'") % freed % path);
437 }
438
439 state.results.paths.insert(path);
440
441 /* If the path is not a regular file or symlink, move it to the
442 trash directory. The move is to ensure that later (when we're
443 not holding the global GC lock) we can delete the path without
444 being afraid that the path has become alive again. Otherwise
445 delete it right away. */
446 if (state.moveToTrash && S_ISDIR(st.st_mode)) {
447 // Estimate the amount freed using the narSize field. FIXME:
448 // if the path was not valid, need to determine the actual
449 // size.
450 try {
451 if (chmod(path.c_str(), st.st_mode | S_IWUSR) == -1)
452 throw SysError(format("making `%1%' writable") % path);
453 Path tmp = state.trashDir + "/" + baseNameOf(path);
454 if (rename(path.c_str(), tmp.c_str()))
455 throw SysError(format("unable to rename `%1%' to `%2%'") % path % tmp);
456 state.bytesInvalidated += size;
457 } catch (SysError & e) {
458 if (e.errNo == ENOSPC) {
459 printMsg(lvlInfo, format("note: can't create move `%1%': %2%") % path % e.msg());
460 deleteGarbage(state, path);
461 }
462 }
463 } else
464 deleteGarbage(state, path);
465
466 if (state.results.bytesFreed + state.bytesInvalidated > state.options.maxFreed) {
467 printMsg(lvlInfo, format("deleted or invalidated more than %1% bytes; stopping") % state.options.maxFreed);
468 throw GCLimitReached();
469 }
470 }
471
472
473 bool LocalStore::canReachRoot(GCState & state, PathSet & visited, const Path & path)
474 {
475 if (visited.find(path) != visited.end()) return false;
476
477 if (state.alive.find(path) != state.alive.end()) {
478 return true;
479 }
480
481 if (state.dead.find(path) != state.dead.end()) {
482 return false;
483 }
484
485 if (state.roots.find(path) != state.roots.end()) {
486 printMsg(lvlDebug, format("cannot delete `%1%' because it's a root") % path);
487 state.alive.insert(path);
488 return true;
489 }
490
491 visited.insert(path);
492
493 if (!isValidPath(path)) return false;
494
495 PathSet incoming;
496
497 /* Don't delete this path if any of its referrers are alive. */
498 queryReferrers(path, incoming);
499
500 /* If gc-keep-derivations is set and this is a derivation, then
501 don't delete the derivation if any of the outputs are alive. */
502 if (state.gcKeepDerivations && isDerivation(path)) {
503 PathSet outputs = queryDerivationOutputs(path);
504 foreach (PathSet::iterator, i, outputs)
505 if (isValidPath(*i) && queryDeriver(*i) == path)
506 incoming.insert(*i);
507 }
508
509 /* If gc-keep-outputs is set, then don't delete this path if there
510 are derivers of this path that are not garbage. */
511 if (state.gcKeepOutputs) {
512 PathSet derivers = queryValidDerivers(path);
513 foreach (PathSet::iterator, i, derivers)
514 incoming.insert(*i);
515 }
516
517 foreach (PathSet::iterator, i, incoming)
518 if (*i != path)
519 if (canReachRoot(state, visited, *i)) {
520 state.alive.insert(path);
521 return true;
522 }
523
524 return false;
525 }
526
527
528 void LocalStore::tryToDelete(GCState & state, const Path & path)
529 {
530 checkInterrupt();
531
532 if (path == linksDir || path == state.trashDir) return;
533
534 startNest(nest, lvlDebug, format("considering whether to delete `%1%'") % path);
535
536 if (!isValidPath(path)) {
537 /* A lock file belonging to a path that we're building right
538 now isn't garbage. */
539 if (isActiveTempFile(state, path, ".lock")) return;
540
541 /* Don't delete .chroot directories for derivations that are
542 currently being built. */
543 if (isActiveTempFile(state, path, ".chroot")) return;
544 }
545
546 PathSet visited;
547
548 if (canReachRoot(state, visited, path)) {
549 printMsg(lvlDebug, format("cannot delete `%1%' because it's still reachable") % path);
550 } else {
551 /* No path we visited was a root, so everything is garbage.
552 But we only delete ‘path’ and its referrers here so that
553 ‘nix-store --delete’ doesn't have the unexpected effect of
554 recursing into derivations and outputs. */
555 state.dead.insert(visited.begin(), visited.end());
556 if (state.shouldDelete)
557 deletePathRecursive(state, path);
558 }
559 }
560
561
562 /* Unlink all files in /nix/store/.links that have a link count of 1,
563 which indicates that there are no other links and so they can be
564 safely deleted. FIXME: race condition with optimisePath(): we
565 might see a link count of 1 just before optimisePath() increases
566 the link count. */
567 void LocalStore::removeUnusedLinks(const GCState & state)
568 {
569 AutoCloseDir dir = opendir(linksDir.c_str());
570 if (!dir) throw SysError(format("opening directory `%1%'") % linksDir);
571
572 long long actualSize = 0, unsharedSize = 0;
573
574 struct dirent * dirent;
575 while (errno = 0, dirent = readdir(dir)) {
576 checkInterrupt();
577 string name = dirent->d_name;
578 if (name == "." || name == "..") continue;
579 Path path = linksDir + "/" + name;
580
581 #ifdef HAVE_STATX
582 # define st_size stx_size
583 # define st_nlink stx_nlink
584 static int statx_flags = AT_SYMLINK_NOFOLLOW | AT_STATX_DONT_SYNC;
585 struct statx st;
586
587 if (statx(AT_FDCWD, path.c_str(), statx_flags,
588 STATX_SIZE | STATX_NLINK, &st) == -1) {
589 if (errno == EINVAL) {
590 /* Old 3.10 kernels (CentOS 7) don't support
591 AT_STATX_DONT_SYNC, so try again without it. */
592 statx_flags &= ~AT_STATX_DONT_SYNC;
593 if (statx(AT_FDCWD, path.c_str(), statx_flags,
594 STATX_SIZE | STATX_NLINK, &st) == -1)
595 throw SysError(format("statting `%1%'") % path);
596 } else {
597 throw SysError(format("statting `%1%'") % path);
598 }
599 }
600 #else
601 struct stat st;
602 if (lstat(path.c_str(), &st) == -1)
603 throw SysError(format("statting `%1%'") % path);
604 #endif
605
606 if (st.st_nlink != 1) {
607 actualSize += st.st_size;
608 unsharedSize += (st.st_nlink - 1) * st.st_size;
609 continue;
610 }
611
612 printMsg(lvlTalkative, format("deleting unused link `%1%'") % path);
613
614 if (unlink(path.c_str()) == -1)
615 throw SysError(format("deleting `%1%'") % path);
616
617 state.results.bytesFreed += st.st_size;
618 #undef st_size
619 #undef st_nlink
620 }
621
622 struct stat st;
623 if (stat(linksDir.c_str(), &st) == -1)
624 throw SysError(format("statting `%1%'") % linksDir);
625 long long overhead = st.st_size;
626
627 printMsg(lvlInfo, format("note: currently hard linking saves %.2f MiB")
628 % ((unsharedSize - actualSize - overhead) / (1024.0 * 1024.0)));
629 }
630
631
632 void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
633 {
634 GCState state(results);
635 state.options = options;
636 state.trashDir = settings.nixStore + "/trash";
637 state.gcKeepOutputs = settings.gcKeepOutputs;
638 state.gcKeepDerivations = settings.gcKeepDerivations;
639
640 /* Using `--ignore-liveness' with `--delete' can have unintended
641 consequences if `gc-keep-outputs' or `gc-keep-derivations' are
642 true (the garbage collector will recurse into deleting the
643 outputs or derivers, respectively). So disable them. */
644 if (options.action == GCOptions::gcDeleteSpecific && options.ignoreLiveness) {
645 state.gcKeepOutputs = false;
646 state.gcKeepDerivations = false;
647 }
648
649 state.shouldDelete = options.action == GCOptions::gcDeleteDead || options.action == GCOptions::gcDeleteSpecific;
650
651 /* Acquire the global GC root. This prevents
652 a) New roots from being added.
653 b) Processes from creating new temporary root files. */
654 AutoCloseFD fdGCLock = openGCLock(ltWrite);
655
656 /* Find the roots. Since we've grabbed the GC lock, the set of
657 permanent roots cannot increase now. */
658 printMsg(lvlError, format("finding garbage collector roots..."));
659 Roots rootMap = options.ignoreLiveness ? Roots() : findRoots();
660
661 foreach (Roots::iterator, i, rootMap) state.roots.insert(i->second);
662
663 /* Add additional roots returned by 'guix gc --list-busy'. This is
664 typically used to add running programs to the set of roots (to prevent
665 them from being garbage collected). */
666 if (!options.ignoreLiveness)
667 addAdditionalRoots(*this, state.roots);
668
669 /* Read the temporary roots. This acquires read locks on all
670 per-process temporary root files. So after this point no paths
671 can be added to the set of temporary roots. */
672 FDs fds;
673 readTempRoots(state.tempRoots, fds);
674 state.roots.insert(state.tempRoots.begin(), state.tempRoots.end());
675
676 /* After this point the set of roots or temporary roots cannot
677 increase, since we hold locks on everything. So everything
678 that is not reachable from `roots' is garbage. */
679
680 if (state.shouldDelete) {
681 if (pathExists(state.trashDir)) deleteGarbage(state, state.trashDir);
682 try {
683 createDirs(state.trashDir);
684 } catch (SysError & e) {
685 if (e.errNo == ENOSPC) {
686 printMsg(lvlInfo, format("note: can't create trash directory: %1%") % e.msg());
687 state.moveToTrash = false;
688 }
689 }
690 }
691
692 /* Now either delete all garbage paths, or just the specified
693 paths (for gcDeleteSpecific). */
694
695 if (options.action == GCOptions::gcDeleteSpecific) {
696
697 foreach (PathSet::iterator, i, options.pathsToDelete) {
698 assertStorePath(*i);
699 tryToDelete(state, *i);
700 if (state.dead.find(*i) == state.dead.end())
701 throw Error(format("cannot delete path `%1%' since it is still alive") % *i);
702 }
703
704 } else if (options.maxFreed > 0) {
705
706 if (state.shouldDelete)
707 printMsg(lvlError, format("deleting garbage..."));
708 else
709 printMsg(lvlError, format("determining live/dead paths..."));
710
711 try {
712
713 AutoCloseDir dir = opendir(settings.nixStore.c_str());
714 if (!dir) throw SysError(format("opening directory `%1%'") % settings.nixStore);
715
716 /* Read the store and immediately delete all paths that
717 aren't valid. When using --max-freed etc., deleting
718 invalid paths is preferred over deleting unreachable
719 paths, since unreachable paths could become reachable
720 again. We don't use readDirectory() here so that GCing
721 can start faster. */
722 Paths entries;
723 struct dirent * dirent;
724 while (errno = 0, dirent = readdir(dir)) {
725 checkInterrupt();
726 string name = dirent->d_name;
727 if (name == "." || name == "..") continue;
728 Path path = settings.nixStore + "/" + name;
729 if (isValidPath(path))
730 entries.push_back(path);
731 else
732 tryToDelete(state, path);
733 }
734
735 dir.close();
736
737 /* Now delete the unreachable valid paths. Randomise the
738 order in which we delete entries to make the collector
739 less biased towards deleting paths that come
740 alphabetically first (e.g. /nix/store/000...). This
741 matters when using --max-freed etc. */
742 vector<Path> entries_(entries.begin(), entries.end());
743 random_shuffle(entries_.begin(), entries_.end());
744
745 foreach (vector<Path>::iterator, i, entries_)
746 tryToDelete(state, *i);
747
748 } catch (GCLimitReached & e) {
749 }
750 }
751
752 if (state.options.action == GCOptions::gcReturnLive) {
753 state.results.paths = state.alive;
754 return;
755 }
756
757 if (state.options.action == GCOptions::gcReturnDead) {
758 state.results.paths = state.dead;
759 return;
760 }
761
762 /* Allow other processes to add to the store from here on. */
763 fdGCLock.close();
764 fds.clear();
765
766 /* Delete the trash directory. */
767 printMsg(lvlInfo, format("deleting `%1%'") % state.trashDir);
768 deleteGarbage(state, state.trashDir);
769
770 /* Clean up the links directory. */
771 if (options.action == GCOptions::gcDeleteDead || options.action == GCOptions::gcDeleteSpecific) {
772 printMsg(lvlError, format("deleting unused links..."));
773 removeUnusedLinks(state);
774 }
775
776 /* While we're at it, vacuum the database. */
777 //if (options.action == GCOptions::gcDeleteDead) vacuumDB();
778 }
779
780
781 }