From 931f13840bad7bd3cb98b7806f09ca2b3cf7cd10 Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Fri, 8 Apr 2022 11:53:02 +0200 Subject: mapped-devices: Ensure 'cryptsetup open' gets a tty. Fixes . Regression introduced in 400c9ed3d779308e56038305d40cd93acb496180. 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*'. --- gnu/build/file-systems.scm | 30 +++++++++++++++++++++++- gnu/system/mapped-devices.scm | 53 +++++++++++++++++++++++-------------------- 2 files changed, 58 insertions(+), 25 deletions(-) diff --git a/gnu/build/file-systems.scm b/gnu/build/file-systems.scm index d95340df83..d5f38c6774 100644 --- a/gnu/build/file-systems.scm +++ b/gnu/build/file-systems.scm @@ -1,5 +1,5 @@ ;;; GNU Guix --- Functional package management for GNU -;;; Copyright © 2014, 2015, 2016, 2017, 2018, 2020, 2021 Ludovic Courtès +;;; Copyright © 2014-2018, 2020-2022 Ludovic Courtès ;;; Copyright © 2016, 2017 David Craven ;;; Copyright © 2017 Mathieu Othacehe ;;; Copyright © 2019 Guillaume Le Vaillant @@ -54,6 +54,7 @@ bind-mount + system*/tty mount-flags->bit-mask check-file-system mount-file-system @@ -67,6 +68,33 @@ ;;; ;;; 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) "Bind-mount SOURCE at TARGET." (mount source target "" MS_BIND)) diff --git a/gnu/system/mapped-devices.scm b/gnu/system/mapped-devices.scm index 96a381d5fe..e6b8970c12 100644 --- a/gnu/system/mapped-devices.scm +++ b/gnu/system/mapped-devices.scm @@ -1,5 +1,5 @@ ;;; GNU Guix --- Functional package management for GNU -;;; Copyright © 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021 Ludovic Courtès +;;; Copyright © 2014-2022 Ludovic Courtès ;;; Copyright © 2016 Andreas Enge ;;; Copyright © 2017, 2018 Mark H Weaver ;;; @@ -202,7 +202,8 @@ option of @command{guix system}.\n") ;; XXX: 'use-modules' should be at the top level. (use-modules (rnrs bytevectors) ;bytevector? ((gnu build file-systems) - #:select (find-partition-by-luks-uuid)) + #:select (find-partition-by-luks-uuid + system*/tty)) ((guix build utils) #:select (mkdir-p))) ;; Create '/run/cryptsetup/' if it does not exist, as device locking @@ -211,28 +212,32 @@ option of @command{guix system}.\n") ;; Use 'cryptsetup-static', not 'cryptsetup', to avoid pulling the ;; whole world inside the initrd (for when we're in an initrd). - (zero? (system* #$(file-append cryptsetup-static "/sbin/cryptsetup") - "open" "--type" "luks" - - ;; Note: We cannot use the "UUID=source" syntax here - ;; because 'cryptsetup' implements it by searching the - ;; udev-populated /dev/disk/by-id directory but udev may - ;; be unavailable at the time we run this. - (if (bytevector? source) - (or (let loop ((tries-left 10)) - (and (positive? tries-left) - (or (find-partition-by-luks-uuid source) - ;; If the underlying partition is - ;; not found, try again after - ;; waiting a second, up to ten - ;; times. FIXME: This should be - ;; dealt with in a more robust way. - (begin (sleep 1) - (loop (- tries-left 1)))))) - (error "LUKS partition not found" source)) - source) - - #$target))))))) + ;; 'cryptsetup open' requires standard input to be a tty to allow + ;; 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 + ;; because 'cryptsetup' implements it by searching the + ;; udev-populated /dev/disk/by-id directory but udev may + ;; be unavailable at the time we run this. + (if (bytevector? source) + (or (let loop ((tries-left 10)) + (and (positive? tries-left) + (or (find-partition-by-luks-uuid source) + ;; If the underlying partition is + ;; not found, try again after + ;; waiting a second, up to ten + ;; times. FIXME: This should be + ;; dealt with in a more robust way. + (begin (sleep 1) + (loop (- tries-left 1)))))) + (error "LUKS partition not found" source)) + source) + + #$target))))))) (define (close-luks-device source targets) "Return a gexp that closes TARGET, a LUKS device." -- cgit v1.2.3