@@ -367,6 +367,8 @@ void LocalStore::findRuntimeRoots(Roots & roots, bool censor)
367367{
368368 UncheckedRoots unchecked;
369369
370+ std::string pids = std::to_string (getpid ());
371+
370372 auto procDir = AutoCloseDir{opendir (" /proc" )};
371373 if (procDir) {
372374 struct dirent * ent;
@@ -375,7 +377,7 @@ void LocalStore::findRuntimeRoots(Roots & roots, bool censor)
375377 auto storePathRegex = std::regex (quoteRegexChars (storeDir) + R"( /[0-9a-z]+[0-9a-zA-Z\+\-\._\?=]*)" );
376378 while (errno = 0 , ent = readdir (procDir.get ())) {
377379 checkInterrupt ();
378- if (std::regex_match (ent->d_name , digitsRegex)) {
380+ if (std::regex_match (ent->d_name , digitsRegex) && strcmp (pids. c_str (), ent-> d_name ) ) {
379381 try {
380382 readProcLink (fmt (" /proc/%s/exe" ,ent->d_name ), unchecked);
381383 readProcLink (fmt (" /proc/%s/cwd" , ent->d_name ), unchecked);
@@ -469,7 +471,7 @@ struct GCLimitReached { };
469471
470472void LocalStore::collectGarbage (const GCOptions & options, GCResults & results)
471473{
472- bool shouldDelete = options. action == GCOptions::gcDeleteDead || options.action == GCOptions::gcDeleteSpecific ;
474+ bool shouldDelete = std::holds_alternative<GCDelete>( options.action ) ;
473475 bool gcKeepOutputs = settings.gcKeepOutputs ;
474476 bool gcKeepDerivations = settings.gcKeepDerivations ;
475477
@@ -494,10 +496,12 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
494496 consequences if `keep-outputs' or `keep-derivations' are true
495497 (the garbage collector will recurse into deleting the outputs
496498 or derivers, respectively). So disable them. */
497- if (options.action == GCOptions::gcDeleteSpecific && options.ignoreLiveness ) {
498- gcKeepOutputs = false ;
499- gcKeepDerivations = false ;
500- }
499+ std::visit (overloaded{[&](GCDelete del){
500+ if (del.pathsToDelete .has_value () && del.ignoreLiveness ) {
501+ gcKeepOutputs = false ;
502+ gcKeepDerivations = false ;
503+ }
504+ }, [](GCReturn arg){}}, options.action );
501505
502506 if (shouldDelete)
503507 deletePath (reservedPath);
@@ -617,8 +621,16 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
617621 permanent roots cannot increase now. */
618622 printInfo (" finding garbage collector roots..." );
619623 Roots rootMap;
620- if (!options.ignoreLiveness )
621- findRootsNoTemp (rootMap, true );
624+
625+ std::visit (overloaded{
626+ [&](GCDelete del) {
627+ if (!del.ignoreLiveness )
628+ findRootsNoTemp (rootMap, true );
629+ },
630+ [&](GCReturn r){
631+ findRootsNoTemp (rootMap, true );
632+ }},
633+ options.action );
622634
623635 for (auto & i : rootMap) roots.insert (i.first );
624636
@@ -721,9 +733,9 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
721733 return markAlive ();
722734 }
723735
724- if (options. action == GCOptions::gcDeleteSpecific
725- && !options. pathsToDelete .count (*path))
726- return ;
736+ if (const GCDelete * del = std::get_if<GCDelete>(&options. action ))
737+ if (del-> pathsToDelete . has_value () && !del-> pathsToDelete -> paths .count (*path))
738+ return ;
727739
728740 {
729741 auto hashPart = std::string (path->hashPart ());
@@ -781,27 +793,7 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
781793 if (auto p = getEnv (" _NIX_TEST_GC_SYNC" ))
782794 readFile (*p);
783795
784- /* Either delete all garbage paths, or just the specified
785- paths (for gcDeleteSpecific). */
786- if (options.action == GCOptions::gcDeleteSpecific || options.action == GCOptions::gcDeleteDead) {
787-
788- for (auto & i : options.pathsToDelete ) {
789- deleteReferrersClosure (i);
790- if (options.action == GCOptions::gcDeleteSpecific && !dead.count (i))
791- throw Error (
792- " Cannot delete path '%1%' since it is still alive. "
793- " To find out why, use: "
794- " nix-store --query --roots" ,
795- printStorePath (i));
796- }
797-
798- } else if (options.maxFreed > 0 ) {
799-
800- if (shouldDelete)
801- printInfo (" deleting garbage..." );
802- else
803- printInfo (" determining live/dead paths..." );
804-
796+ auto findOrDeleteRoots = [&](){
805797 try {
806798 AutoCloseDir dir (opendir (realStoreDir.get ().c_str ()));
807799 if (!dir) throw SysError (" opening directory '%1%'" , realStoreDir);
@@ -825,65 +817,87 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
825817 }
826818 } catch (GCLimitReached & e) {
827819 }
828- }
820+ };
829821
830- if (options.action == GCOptions::gcReturnLive) {
831- for (auto & i : alive)
832- results.paths .insert (printStorePath (i));
833- return ;
834- }
822+ /* Either delete all garbage paths, or just the specified
823+ paths (for gcDeleteSpecific). */
824+ std::visit (overloaded{
825+ [&](GCDelete del){
826+ if (del.pathsToDelete .has_value ()) {
827+ for (auto & i : del.pathsToDelete ->paths ) {
828+ deleteReferrersClosure (i);
829+ if (!del.pathsToDelete ->skipAlive && !dead.count (i))
830+ throw Error (
831+ " Cannot delete path '%1%' since it is still alive. "
832+ " To find out why, use: "
833+ " nix-store --query --roots" ,
834+ printStorePath (i));
835+ }
836+ } else if (options.maxFreed > 0 ) {
837+ printInfo (" deleting garbage..." );
838+ findOrDeleteRoots ();
839+ }
835840
836- if (options. action == GCOptions::gcReturnDead) {
837- for ( auto & i : dead)
838- results. paths . insert ( printStorePath (i));
839- return ;
840- }
841+ /* Unlink all files in /nix/store/.links that have a link count of 1,
842+ which indicates that there are no other links and so they can be
843+ safely deleted. FIXME: race condition with optimisePath(): we
844+ might see a link count of 1 just before optimisePath() increases
845+ the link count. */
841846
842- /* Unlink all files in /nix/store/.links that have a link count of 1,
843- which indicates that there are no other links and so they can be
844- safely deleted. FIXME: race condition with optimisePath(): we
845- might see a link count of 1 just before optimisePath() increases
846- the link count. */
847- if (options.action == GCOptions::gcDeleteDead || options.action == GCOptions::gcDeleteSpecific) {
848- printInfo (" deleting unused links..." );
847+ printInfo (" deleting unused links..." );
849848
850- AutoCloseDir dir (opendir (linksDir.c_str ()));
851- if (!dir) throw SysError (" opening directory '%1%'" , linksDir);
849+ AutoCloseDir dir (opendir (linksDir.c_str ()));
850+ if (!dir) throw SysError (" opening directory '%1%'" , linksDir);
852851
853- int64_t actualSize = 0 , unsharedSize = 0 ;
852+ int64_t actualSize = 0 , unsharedSize = 0 ;
854853
855- struct dirent * dirent;
856- while (errno = 0 , dirent = readdir (dir.get ())) {
857- checkInterrupt ();
858- std::string name = dirent->d_name ;
859- if (name == " ." || name == " .." ) continue ;
860- Path path = linksDir + " /" + name;
854+ struct dirent * dirent;
855+ while (errno = 0 , dirent = readdir (dir.get ())) {
856+ checkInterrupt ();
857+ std::string name = dirent->d_name ;
858+ if (name == " ." || name == " .." ) continue ;
859+ Path path = linksDir + " /" + name;
861860
862- auto st = lstat (path);
861+ auto st = lstat (path);
863862
864- if (st.st_nlink != 1 ) {
865- actualSize += st.st_size ;
866- unsharedSize += (st.st_nlink - 1 ) * st.st_size ;
867- continue ;
868- }
863+ if (st.st_nlink != 1 ) {
864+ actualSize += st.st_size ;
865+ unsharedSize += (st.st_nlink - 1 ) * st.st_size ;
866+ continue ;
867+ }
869868
870- printMsg (lvlTalkative, " deleting unused link '%1%'" , path);
869+ printMsg (lvlTalkative, " deleting unused link '%1%'" , path);
871870
872- if (unlink (path.c_str ()) == -1 )
873- throw SysError (" deleting '%1%'" , path);
871+ if (unlink (path.c_str ()) == -1 )
872+ throw SysError (" deleting '%1%'" , path);
874873
875- /* Do not accound for deleted file here. Rely on deletePath()
876- accounting. */
877- }
874+ /* Do not accound for deleted file here. Rely on deletePath()
875+ accounting. */
876+ }
878877
879- struct stat st;
880- if (stat (linksDir.c_str (), &st) == -1 )
881- throw SysError (" statting '%1%'" , linksDir);
882- int64_t overhead = st.st_blocks * 512ULL ;
878+ struct stat st;
879+ if (stat (linksDir.c_str (), &st) == -1 )
880+ throw SysError (" statting '%1%'" , linksDir);
881+ int64_t overhead = st.st_blocks * 512ULL ;
883882
884- printInfo (" note: currently hard linking saves %.2f MiB" ,
885- ((unsharedSize - actualSize - overhead) / (1024.0 * 1024.0 )));
886- }
883+ printInfo (" note: currently hard linking saves %.2f MiB" ,
884+ ((unsharedSize - actualSize - overhead) / (1024.0 * 1024.0 )));
885+ },
886+ [&](GCReturn ret){
887+ printInfo (" determining live/dead paths..." );
888+ findOrDeleteRoots ();
889+ if (ret == GCReturn::Live) {
890+ for (auto & i : alive)
891+ results.paths .insert (printStorePath (i));
892+ return ;
893+ }
894+
895+ if (ret == GCReturn::Dead) {
896+ for (auto & i : dead)
897+ results.paths .insert (printStorePath (i));
898+ return ;
899+ }
900+ }}, options.action );
887901
888902 /* While we're at it, vacuum the database. */
889903 // if (options.action == GCOptions::gcDeleteDead) vacuumDB();
@@ -945,8 +959,7 @@ void LocalStore::autoGC(bool sync)
945959 promise.set_value ();
946960 });
947961
948- GCOptions options;
949- options.maxFreed = settings.maxFree - avail;
962+ GCOptions options{.action = GCAction{GCDelete{}}, .maxFreed = settings.maxFree - avail};
950963
951964 printInfo (" running auto-GC to free %d bytes" , options.maxFreed );
952965
0 commit comments