From 7445776b7e7eeeb1a15df7eb9c15585cf410fae9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= Date: Mon, 1 Sep 2025 14:47:01 +0200 Subject: [PATCH] gc: Open a connection to the daemon only when strictly necessary. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes guix/guix#1901. Previously, ‘guix gc --list-busy’ (which is invoked by ‘guix-daemon’) would open a connection to the daemon, which in turn attempts to create /var/guix/profiles/per-user/$USER. However, when ‘guix-daemon‘ is running as an unprivileged user, creating that directory fails with EPERM. Because of this, garbage collection would always fail when running the unprivileged daemon on Guix System. * guix/scripts/gc.scm (guix-gc): Remove upfront call to ‘open-connection’. Instead, use ‘with-store’ only for operations that require it. Change-Id: I1fbfd97cf7ba9e3087f7287b4776ea2f6623400d --- guix/scripts/gc.scm | 72 ++++++++++++++++++++++++++------------------- 1 file changed, 41 insertions(+), 31 deletions(-) diff --git a/guix/scripts/gc.scm b/guix/scripts/gc.scm index 7663efe7f82..c5017a6e52c 100644 --- a/guix/scripts/gc.scm +++ b/guix/scripts/gc.scm @@ -1,5 +1,5 @@ ;;; GNU Guix --- Functional package management for GNU -;;; Copyright © 2012-2013, 2015-2020, 2022 Ludovic Courtès +;;; Copyright © 2012-2013, 2015-2020, 2022, 2025 Ludovic Courtès ;;; Copyright © 2022 Efraim Flashner ;;; Copyright © 2022 Remco van 't Veer ;;; @@ -297,7 +297,6 @@ is deprecated; use '-D'~%")) (with-error-handling (let* ((opts (parse-options)) - (store (open-connection)) (paths (filter-map (match-lambda (('argument . arg) arg) (_ #f)) @@ -307,39 +306,44 @@ is deprecated; use '-D'~%")) (leave (G_ "extraneous arguments: ~{~a ~}~%") paths))) (define (list-relatives relatives) - (for-each (compose (lambda (path) - (for-each (cut simple-format #t "~a~%" <>) - (relatives store path))) - store-directory - symlink-target) - paths)) + (with-store store + (for-each (compose (lambda (path) + (for-each (cut simple-format #t "~a~%" <>) + (relatives store path))) + store-directory + symlink-target) + paths))) (case (assoc-ref opts 'action) ((collect-garbage) (assert-no-extra-arguments) (let ((min-freed (assoc-ref opts 'min-freed)) (free-space (assoc-ref opts 'free-space))) - (match (assq 'delete-generations opts) - (#f #t) - ((_ . pattern) - (delete-generations store pattern))) - (cond - (free-space - (ensure-free-space store free-space)) - (min-freed - (let-values (((paths freed) (collect-garbage store min-freed))) - (info (G_ "freed ~a~%") (number->size freed)))) - (else - (let-values (((paths freed) (collect-garbage store))) - (info (G_ "freed ~a~%") (number->size freed))))))) + (with-store store + (match (assq 'delete-generations opts) + (#f #t) + ((_ . pattern) + (delete-generations store pattern))) + (cond + (free-space + (ensure-free-space store free-space)) + (min-freed + (let-values (((paths freed) (collect-garbage store min-freed))) + (info (G_ "freed ~a~%") (number->size freed)))) + (else + (let-values (((paths freed) (collect-garbage store))) + (info (G_ "freed ~a~%") (number->size freed)))))))) ((list-roots) (assert-no-extra-arguments) (list-roots)) ((list-busy) + ;; Note: This is invoked by 'guix-daemon' so it must not open a + ;; connection to the daemon. (assert-no-extra-arguments) (list-busy)) ((delete) - (delete-paths store (map direct-store-path paths))) + (with-store store + (delete-paths store (map direct-store-path paths)))) ((list-references) (list-relatives references)) ((list-requisites) @@ -351,22 +355,28 @@ is deprecated; use '-D'~%")) (list-relatives valid-derivers)) ((optimize) (assert-no-extra-arguments) - (optimize-store store)) + (with-store store + (optimize-store store))) ((verify) (assert-no-extra-arguments) (let ((options (assoc-ref opts 'verify-options))) (exit - (verify-store store - #:check-contents? (memq 'contents options) - #:repair? (memq 'repair options))))) + (with-store store + (verify-store store + #:check-contents? (memq 'contents options) + #:repair? (memq 'repair options)))))) ((list-failures) - (for-each (cut simple-format #t "~a~%" <>) - (query-failed-paths store))) + (with-store store + (for-each (cut simple-format #t "~a~%" <>) + (query-failed-paths store)))) ((clear-failures) - (clear-failed-paths store (map direct-store-path paths))) + (with-store store + (clear-failed-paths store (map direct-store-path paths)))) ((list-dead) (for-each (cut simple-format #t "~a~%" <>) - (dead-paths store))) + (with-store store + (dead-paths store)))) ((list-live) (for-each (cut simple-format #t "~a~%" <>) - (live-paths store))))))) + (with-store store + (live-paths store))))))))