diff --git a/Cargo.toml b/Cargo.toml index f8bd3be76..d73ced618 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,7 +30,7 @@ bch_bindgen = { path = "bch_bindgen" } strum = { version = "0.26", features = ["derive"] } strum_macros = "0.26" zeroize = { version = "1", features = ["std", "zeroize_derive"] } -rustix = { version = "0.38.34", features = ["termios"] } +rustix = { version = "0.38.34", features = ["fs", "termios"] } owo-colors = "4" [dependencies.env_logger] diff --git a/src/key.rs b/src/key.rs index 1cf3a88a8..1fd6ce0be 100644 --- a/src/key.rs +++ b/src/key.rs @@ -1,8 +1,9 @@ use std::{ ffi::{c_long, CStr, CString}, fs, - io::{stdin, IsTerminal}, + io::{self, stdin, IsTerminal}, mem, + os::fd::{AsFd, BorrowedFd}, path::Path, process::{Command, Stdio}, ptr, thread, @@ -143,10 +144,10 @@ impl Passphrase { } pub fn new(uuid: &Uuid) -> Result { - if stdin().is_terminal() { - Self::new_from_prompt(uuid) - } else { - Self::new_from_stdin() + match get_stdin_type() { + StdinType::Terminal => Self::new_from_prompt(uuid), + StdinType::DevNull => Self::new_from_askpassword(uuid).unwrap_or_else(|err| Err(err)), + StdinType::Other => Self::new_from_stdin(), } } @@ -158,6 +159,8 @@ impl Passphrase { let output = Command::new("systemd-ask-password") .arg("--icon=drive-harddisk") .arg(format!("--id=bcachefs:{}", uuid.as_hyphenated())) + .arg(format!("--keyname={}", uuid.as_hyphenated())) + .arg("--accept-cached") .arg("-n") .arg("Enter passphrase: ") .stdin(Stdio::inherit()) @@ -253,3 +256,31 @@ impl Passphrase { Ok((passphrase_key, sb_key)) } } + +fn is_dev_null(fd: BorrowedFd) -> io::Result { + let stat = rustix::fs::fstat(fd)?; + let file_type = rustix::fs::FileType::from_raw_mode(stat.st_mode); + if file_type != rustix::fs::FileType::CharacterDevice { + return Ok(false); + } + let major = rustix::fs::major(stat.st_rdev); + let minor = rustix::fs::minor(stat.st_rdev); + Ok(major == 1 && minor == 3) +} + +enum StdinType { + Terminal, + DevNull, + Other, +} + +fn get_stdin_type() -> StdinType { + let stdin = stdin(); + if stdin.is_terminal() { + StdinType::Terminal + } else if is_dev_null(stdin.as_fd()).unwrap_or(false) { + StdinType::DevNull + } else { + StdinType::Other + } +}