mapped-devices: Ensure 'cryptsetup open' gets a tty.

Fixes <https://issues.guix.gnu.org/54770>.
Regression introduced in 400c9ed3d7.

Previously, for an encrypted /home (say), "cryptsetup open" would be
invoked by shepherd, with /dev/null as its standard input.  It would
thus run in non-interactive mode and, instead of asking for a
passphrase, fail with:

  Nothing to read on input.

This change ensures it runs in interactive mode.

* gnu/build/file-systems.scm (system*/console, system*/tty): New
procedures.
* gnu/system/mapped-devices.scm (open-luks-device): Use 'system*/tty'
instead of 'system*'.
This commit is contained in:
Ludovic Courtès 2022-04-08 11:53:02 +02:00
parent df473496ed
commit 931f13840b
No known key found for this signature in database
GPG key ID: 090B11993D9AEBB5
2 changed files with 56 additions and 23 deletions

View file

@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU ;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2014, 2015, 2016, 2017, 2018, 2020, 2021 Ludovic Courtès <ludo@gnu.org> ;;; Copyright © 2014-2018, 2020-2022 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2016, 2017 David Craven <david@craven.ch> ;;; Copyright © 2016, 2017 David Craven <david@craven.ch>
;;; Copyright © 2017 Mathieu Othacehe <m.othacehe@gmail.com> ;;; Copyright © 2017 Mathieu Othacehe <m.othacehe@gmail.com>
;;; Copyright © 2019 Guillaume Le Vaillant <glv@posteo.net> ;;; Copyright © 2019 Guillaume Le Vaillant <glv@posteo.net>
@ -54,6 +54,7 @@ (define-module (gnu build file-systems)
bind-mount bind-mount
system*/tty
mount-flags->bit-mask mount-flags->bit-mask
check-file-system check-file-system
mount-file-system mount-file-system
@ -67,6 +68,33 @@ (define-module (gnu build file-systems)
;;; ;;;
;;; Code: ;;; Code:
(define (system*/console program . args)
"Run PROGRAM with ARGS in a tty on top of /dev/console. The return value is
as for 'system*'."
(match (primitive-fork)
(0
(dynamic-wind
(const #t)
(lambda ()
(login-tty (open-fdes "/dev/console" O_RDWR))
(apply execlp program program args))
(lambda ()
(primitive-_exit 127))))
(pid
(cdr (waitpid pid)))))
(define (system*/tty program . args)
"Run PROGRAM with ARGS, creating a tty if its standard input isn't one.
The return value is as for 'system*'.
This is necessary for commands such as 'cryptsetup open' or 'fsck' that may
need to interact with the user but might be invoked from shepherd, where
standard input is /dev/null."
(apply (if (isatty? (current-input-port))
system*
system*/console)
program args))
(define (bind-mount source target) (define (bind-mount source target)
"Bind-mount SOURCE at TARGET." "Bind-mount SOURCE at TARGET."
(mount source target "" MS_BIND)) (mount source target "" MS_BIND))

View file

@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU ;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021 Ludovic Courtès <ludo@gnu.org> ;;; Copyright © 2014-2022 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2016 Andreas Enge <andreas@enge.fr> ;;; Copyright © 2016 Andreas Enge <andreas@enge.fr>
;;; Copyright © 2017, 2018 Mark H Weaver <mhw@netris.org> ;;; Copyright © 2017, 2018 Mark H Weaver <mhw@netris.org>
;;; ;;;
@ -202,7 +202,8 @@ (define (open-luks-device source targets)
;; XXX: 'use-modules' should be at the top level. ;; XXX: 'use-modules' should be at the top level.
(use-modules (rnrs bytevectors) ;bytevector? (use-modules (rnrs bytevectors) ;bytevector?
((gnu build file-systems) ((gnu build file-systems)
#:select (find-partition-by-luks-uuid)) #:select (find-partition-by-luks-uuid
system*/tty))
((guix build utils) #:select (mkdir-p))) ((guix build utils) #:select (mkdir-p)))
;; Create '/run/cryptsetup/' if it does not exist, as device locking ;; Create '/run/cryptsetup/' if it does not exist, as device locking
@ -211,28 +212,32 @@ (define (open-luks-device source targets)
;; Use 'cryptsetup-static', not 'cryptsetup', to avoid pulling the ;; Use 'cryptsetup-static', not 'cryptsetup', to avoid pulling the
;; whole world inside the initrd (for when we're in an initrd). ;; whole world inside the initrd (for when we're in an initrd).
(zero? (system* #$(file-append cryptsetup-static "/sbin/cryptsetup") ;; 'cryptsetup open' requires standard input to be a tty to allow
"open" "--type" "luks" ;; for interaction but shepherd sets standard input to /dev/null;
;; thus, explicitly request a tty.
(zero? (system*/tty
#$(file-append cryptsetup-static "/sbin/cryptsetup")
"open" "--type" "luks"
;; Note: We cannot use the "UUID=source" syntax here ;; Note: We cannot use the "UUID=source" syntax here
;; because 'cryptsetup' implements it by searching the ;; because 'cryptsetup' implements it by searching the
;; udev-populated /dev/disk/by-id directory but udev may ;; udev-populated /dev/disk/by-id directory but udev may
;; be unavailable at the time we run this. ;; be unavailable at the time we run this.
(if (bytevector? source) (if (bytevector? source)
(or (let loop ((tries-left 10)) (or (let loop ((tries-left 10))
(and (positive? tries-left) (and (positive? tries-left)
(or (find-partition-by-luks-uuid source) (or (find-partition-by-luks-uuid source)
;; If the underlying partition is ;; If the underlying partition is
;; not found, try again after ;; not found, try again after
;; waiting a second, up to ten ;; waiting a second, up to ten
;; times. FIXME: This should be ;; times. FIXME: This should be
;; dealt with in a more robust way. ;; dealt with in a more robust way.
(begin (sleep 1) (begin (sleep 1)
(loop (- tries-left 1)))))) (loop (- tries-left 1))))))
(error "LUKS partition not found" source)) (error "LUKS partition not found" source))
source) source)
#$target))))))) #$target)))))))
(define (close-luks-device source targets) (define (close-luks-device source targets)
"Return a gexp that closes TARGET, a LUKS device." "Return a gexp that closes TARGET, a LUKS device."