diff --git a/bcachefs.8 b/bcachefs.8 index 8ff51a7da..7f1c89189 100644 --- a/bcachefs.8 +++ b/bcachefs.8 @@ -380,6 +380,12 @@ is the path where the filesystem should be mounted. If not set, then the filesys but all steps preceding mounting the filesystem (e.g. asking for passphrase) will still be performed. .Pp the options are as follows: .Bl -tag -width Ds +.It Fl f , Fl -passphrase-file Ns = Ns Ar passphrase_file +Path to passphrase/key file +.sp +Precedes key_location/unlock_policy: if the filesystem can be decrypted by the specified passphrase +file, it is decrypted. (i.e. Regardless if "fail" is specified for key_location/unlock_policy.) +.El .It Fl o Ar options Mount options provided as a comma-separated list. See user guide for complete list. .Bl -tag -width Ds -compact @@ -393,6 +399,8 @@ Run fsck during mount Fix errors without asking during fsck .It Cm read_only Mount in read only mode +.It Cm passphrase_file Ns = Ns Ar passphrase_file +Path to passphrase/key file .It Cm version_upgrade .El .It Fl k , Fl -key-location Ns = Ns ( Cm fail | wait | ask ) @@ -408,6 +416,7 @@ prompt the user for password. .El .It Fl c , Fl -colorize Ns = Ns ( Cm true | false ) Force color on/off. Default: auto-detect TTY +.El .It Fl v Be verbose. Can be specified more than once. .El diff --git a/src/commands/mount.rs b/src/commands/mount.rs index 5782b3aba..4be17bdb8 100644 --- a/src/commands/mount.rs +++ b/src/commands/mount.rs @@ -305,6 +305,18 @@ fn devs_str_sbs_from_device( } } +fn parse_passphrase_file_from_mount_options(options: impl AsRef) -> Option { + options + .as_ref() + .split(',') + .fold(None, |_, next| match next { + x if x.starts_with("passphrase_file") => { + Some(PathBuf::from(x.split('=').nth(1).unwrap().to_string())) + } + _ => None, + }) +} + fn cmd_mount_inner(opt: Cli) -> Result<()> { // Grab the udev information once let udev_info = udev_bcachefs_info()?; @@ -338,18 +350,12 @@ fn cmd_mount_inner(opt: Cli) -> Result<()> { if unsafe { bcachefs::bch2_sb_is_encrypted(first_sb.sb) } { let _key_handle: KeyHandle = KeyHandle::new_from_search(&uuid).or_else(|_| { - opt.passphrase_file - .and_then(|path| match Passphrase::new_from_file(&first_sb, path) { - Ok(p) => Some(KeyHandle::new(&first_sb, &p)), - Err(e) => { - error!( - "Failed to read passphrase from file, falling back to prompt: {}", - e - ); - None - } - }) - .unwrap_or_else(|| opt.unlock_policy.apply(&first_sb)) + attempt_unlock_master_key( + opt.passphrase_file, + &opt.options, + opt.unlock_policy, + first_sb, + ) })?; } @@ -373,6 +379,48 @@ fn cmd_mount_inner(opt: Cli) -> Result<()> { } } +fn attempt_unlock_master_key( + passphrase_file: Option, + options: &String, + unlock_policy: UnlockPolicy, + first_sb: bch_sb_handle, +) -> Result { + // Unlock by key_file CLI option + passphrase_file + .and_then( + |path| match Passphrase::new_from_file(&first_sb, path.clone()) { + Ok(p) => Some(KeyHandle::new(&first_sb, &p)), + Err(e) => { + error!( + "Failed to read passphrase from path \"{}\". Error: {}", + path.display(), + e + ); + None + } + }, + ) + // Unlock by key_file mount option + .unwrap_or_else(|| { + parse_passphrase_file_from_mount_options(options) + .and_then(|path: PathBuf| { + match Passphrase::new_from_file(&first_sb, path.clone()) { + Ok(p) => Some(KeyHandle::new(&first_sb, &p)), + Err(e) => { + error!( + "Failed to read passphrase from path \"{}\". Error: {}", + path.display(), + e + ); + None + } + } + }) + // Unlock by unlock policy + .unwrap_or_else(|| unlock_policy.apply(&first_sb)) + }) +} + pub fn mount(mut argv: Vec, symlink_cmd: Option<&str>) -> i32 { // If the bcachefs tool is being called as "bcachefs mount dev ..." (as opposed to via a // symlink like "/usr/sbin/mount.bcachefs dev ...", then we need to pop the 0th argument