From 4501977113cc592703cb785d2e040ddb54c5d528 Mon Sep 17 00:00:00 2001 From: Benjamin Gilbert Date: Wed, 8 Jul 2020 15:39:30 +0000 Subject: [PATCH] install: correctly detect DASDs if they're behind a symlink --- src/blockdev.rs | 27 ++++++++++++--------------- src/install.rs | 9 +++++++-- src/io.rs | 13 +++++++++++++ 3 files changed, 32 insertions(+), 17 deletions(-) diff --git a/src/blockdev.rs b/src/blockdev.rs index bfbcaac06..dabd0f903 100644 --- a/src/blockdev.rs +++ b/src/blockdev.rs @@ -18,7 +18,7 @@ use nix::{errno::Errno, mount}; use regex::Regex; use std::collections::HashMap; use std::convert::TryInto; -use std::fs::{metadata, read_dir, read_link, read_to_string, remove_dir, File, OpenOptions}; +use std::fs::{metadata, read_dir, read_to_string, remove_dir, File, OpenOptions}; use std::num::{NonZeroU32, NonZeroU64}; use std::os::linux::fs::MetadataExt; use std::os::raw::c_int; @@ -30,6 +30,7 @@ use std::thread::sleep; use std::time::Duration; use crate::errors::*; +use crate::io::resolve_link; #[derive(Debug)] pub struct Disk { @@ -374,21 +375,17 @@ impl Partition { // Now assume a kpartx "partition", where the path is a symlink to // an unpartitioned DM device node. // /sys/block/dm-1 - match read_link(Path::new(&self.path)) { - Ok(target) => { - let devdir = basedir.join( - Path::new(&target) - .file_name() - .chain_err(|| format!("target {} has no filename", self.path))?, - ); - if devdir.exists() { - return Ok(devdir); - } + let (target, is_link) = resolve_link(&self.path)?; + if is_link { + let devdir = basedir.join( + target + .file_name() + .chain_err(|| format!("target {} has no filename", target.display()))?, + ); + if devdir.exists() { + return Ok(devdir); } - // ignore if not symlink - Err(e) if e.kind() == std::io::ErrorKind::InvalidInput => (), - Err(e) => return Err(e).chain_err(|| format!("reading link {}", self.path)), - }; + } // Give up bail!( diff --git a/src/install.rs b/src/install.rs index 08605fca2..08a1a757f 100644 --- a/src/install.rs +++ b/src/install.rs @@ -101,7 +101,7 @@ pub fn install(config: &InstallConfig) -> Result<()> { } } - if config.device.starts_with("/dev/dasd") { + if is_dasd(config)? { #[cfg(target_arch = "s390x")] s390x::prepare_dasd(&config)?; } @@ -186,7 +186,7 @@ fn write_disk( let sector_size = get_sector_size(dest)?; // copy the image - let image_copy = if config.device.starts_with("/dev/dasd") { + let image_copy = if is_dasd(config)? { #[cfg(target_arch = "s390x")] { s390x::image_copy_s390x @@ -485,6 +485,11 @@ fn clear_partition_table(dest: &mut File, table: &mut dyn PartTable) -> Result<( Ok(()) } +fn is_dasd(config: &InstallConfig) -> Result { + let (target, _) = resolve_link(&config.device)?; + Ok(target.to_string_lossy().starts_with("/dev/dasd")) +} + #[cfg(test)] mod tests { use super::*; diff --git a/src/io.rs b/src/io.rs index f0b5042c5..96c992244 100644 --- a/src/io.rs +++ b/src/io.rs @@ -13,7 +13,9 @@ // limitations under the License. use error_chain::bail; +use std::fs::read_link; use std::io::{ErrorKind, Read, Write}; +use std::path::{Path, PathBuf}; use crate::errors::*; @@ -76,3 +78,14 @@ pub fn copy_exactly_n( } Ok(n) } + +// If path is a symlink, resolve it and return (target, true) +// If not, return (path, false) +pub fn resolve_link>(path: P) -> Result<(PathBuf, bool)> { + let path = path.as_ref(); + match read_link(path) { + Ok(target) => Ok((target, true)), + Err(e) if e.kind() == std::io::ErrorKind::InvalidInput => Ok((path.to_path_buf(), false)), + Err(e) => Err(e).chain_err(|| format!("reading link {}", path.display())), + } +}