|
@@ -17,11 +17,8 @@ pub struct LoopDevice {
|
|
|
img_path: Option<PathBuf>,
|
|
|
loop_device_path: Option<String>,
|
|
|
/// 尝试在drop时自动detach
|
|
|
- detach_on_drop: bool,
|
|
|
- /// mapper created
|
|
|
- mapper: bool,
|
|
|
+ try_detach_when_drop: bool,
|
|
|
}
|
|
|
-
|
|
|
impl LoopDevice {
|
|
|
pub fn attached(&self) -> bool {
|
|
|
self.loop_device_path.is_some()
|
|
@@ -103,36 +100,22 @@ impl LoopDevice {
|
|
|
/// # 错误
|
|
|
///
|
|
|
/// 如果循环设备未附加,则返回 `anyhow!("Loop device not attached")` 错误。
|
|
|
- pub fn partition_path(&mut self, nth: u8) -> Result<PathBuf> {
|
|
|
+ pub fn partition_path(&self, nth: u8) -> Result<PathBuf> {
|
|
|
if !self.attached() {
|
|
|
return Err(anyhow!("Loop device not attached"));
|
|
|
}
|
|
|
- let dev_path = self.loop_device_path.as_ref().unwrap();
|
|
|
- let direct_path = PathBuf::from(format!("{}p{}", dev_path, nth));
|
|
|
-
|
|
|
+ let s = format!("{}p{}", self.loop_device_path.as_ref().unwrap(), nth);
|
|
|
+ let s = PathBuf::from(s);
|
|
|
// 判断路径是否存在
|
|
|
- if !direct_path.exists() {
|
|
|
- mapper::create_mapper(self.loop_device_path.as_ref().unwrap())?;
|
|
|
- self.mapper = true;
|
|
|
- let device_name = direct_path.file_name().unwrap();
|
|
|
- let parent_path = direct_path.parent().unwrap();
|
|
|
- let new_path = parent_path.join("mapper").join(device_name);
|
|
|
- if new_path.exists() {
|
|
|
- return Ok(new_path);
|
|
|
- }
|
|
|
- log::error!(
|
|
|
- "Both {} and {} not exist!",
|
|
|
- direct_path.display(),
|
|
|
- new_path.display()
|
|
|
- );
|
|
|
- return Err(anyhow!("Unable to find partition path {}", nth));
|
|
|
+ if !s.exists() {
|
|
|
+ return Err(anyhow!("Partition not exist"));
|
|
|
}
|
|
|
- Ok(direct_path)
|
|
|
+ Ok(s)
|
|
|
}
|
|
|
|
|
|
- pub fn detach(&mut self) {
|
|
|
+ pub fn detach(&mut self) -> Result<()> {
|
|
|
if self.loop_device_path.is_none() {
|
|
|
- return;
|
|
|
+ return Ok(());
|
|
|
}
|
|
|
let loop_device = self.loop_device_path.take().unwrap();
|
|
|
let p = PathBuf::from(&loop_device);
|
|
@@ -141,97 +124,39 @@ impl LoopDevice {
|
|
|
p.display(),
|
|
|
p.exists()
|
|
|
);
|
|
|
+ let output = Command::new("losetup")
|
|
|
+ .arg("-d")
|
|
|
+ .arg(loop_device)
|
|
|
+ .output()?;
|
|
|
|
|
|
- if self.mapper {
|
|
|
- mapper::detach_mapper(&loop_device);
|
|
|
- log::trace!("Detach mapper device: {}", &loop_device);
|
|
|
- self.mapper = false;
|
|
|
- }
|
|
|
-
|
|
|
- let output = Command::new("losetup").arg("-d").arg(&loop_device).output();
|
|
|
-
|
|
|
- if output.is_err() {
|
|
|
- log::error!(
|
|
|
- "losetup failed to detach loop device [{}]: {}",
|
|
|
- &loop_device,
|
|
|
- output.unwrap_err()
|
|
|
- );
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- let output = output.unwrap();
|
|
|
-
|
|
|
- if !output.status.success() {
|
|
|
- log::error!(
|
|
|
- "losetup failed to detach loop device [{}]: {}, {}",
|
|
|
- loop_device,
|
|
|
+ if output.status.success() {
|
|
|
+ self.loop_device_path = None;
|
|
|
+ Ok(())
|
|
|
+ } else {
|
|
|
+ Err(anyhow::anyhow!(
|
|
|
+ "Failed to detach loop device: {}, {}",
|
|
|
output.status,
|
|
|
str::from_utf8(output.stderr.as_slice()).unwrap_or("<Unknown>")
|
|
|
- );
|
|
|
+ ))
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- #[allow(dead_code)]
|
|
|
- pub fn detach_on_drop(&self) -> bool {
|
|
|
- self.detach_on_drop
|
|
|
+ pub fn try_detach_when_drop(&self) -> bool {
|
|
|
+ self.try_detach_when_drop
|
|
|
}
|
|
|
|
|
|
#[allow(dead_code)]
|
|
|
pub fn set_try_detach_when_drop(&mut self, try_detach_when_drop: bool) {
|
|
|
- self.detach_on_drop = try_detach_when_drop;
|
|
|
+ self.try_detach_when_drop = try_detach_when_drop;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
impl Drop for LoopDevice {
|
|
|
fn drop(&mut self) {
|
|
|
- if self.detach_on_drop {
|
|
|
- self.detach();
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-mod mapper {
|
|
|
- use anyhow::anyhow;
|
|
|
- use anyhow::Result;
|
|
|
- use std::process::Command;
|
|
|
-
|
|
|
- pub(super) fn create_mapper(dev_path: &str) -> Result<()> {
|
|
|
- let output = Command::new("kpartx")
|
|
|
- .arg("-a")
|
|
|
- .arg("-v")
|
|
|
- .arg(dev_path)
|
|
|
- .output()
|
|
|
- .map_err(|e| anyhow!("Failed to run kpartx: {}", e))?;
|
|
|
- if output.status.success() {
|
|
|
- let output_str = String::from_utf8(output.stdout)?;
|
|
|
- log::trace!("kpartx output: {}", output_str);
|
|
|
- return Ok(());
|
|
|
- }
|
|
|
- Err(anyhow!("Failed to create mapper"))
|
|
|
- }
|
|
|
-
|
|
|
- pub(super) fn detach_mapper(dev_path: &str) {
|
|
|
- let output = Command::new("kpartx")
|
|
|
- .arg("-d")
|
|
|
- .arg("-v")
|
|
|
- .arg(dev_path)
|
|
|
- .output();
|
|
|
- if output.is_ok() {
|
|
|
- let output = output.unwrap();
|
|
|
- if !output.status.success() {
|
|
|
- log::error!(
|
|
|
- "kpartx failed to detach mapper device [{}]: {}, {}",
|
|
|
- dev_path,
|
|
|
- output.status,
|
|
|
- String::from_utf8(output.stderr).unwrap_or("<Unknown>".to_string())
|
|
|
- );
|
|
|
+ if self.try_detach_when_drop() {
|
|
|
+ if let Err(e) = self.detach() {
|
|
|
+ log::warn!("Failed to detach loop device: {}", e);
|
|
|
}
|
|
|
- } else {
|
|
|
- log::error!(
|
|
|
- "Failed to detach mapper device [{}]: {}",
|
|
|
- dev_path,
|
|
|
- output.unwrap_err()
|
|
|
- );
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -239,7 +164,7 @@ mod mapper {
|
|
|
pub struct LoopDeviceBuilder {
|
|
|
img_path: Option<PathBuf>,
|
|
|
loop_device_path: Option<String>,
|
|
|
- detach_on_drop: bool,
|
|
|
+ try_detach_when_drop: bool,
|
|
|
}
|
|
|
|
|
|
impl LoopDeviceBuilder {
|
|
@@ -247,7 +172,7 @@ impl LoopDeviceBuilder {
|
|
|
LoopDeviceBuilder {
|
|
|
img_path: None,
|
|
|
loop_device_path: None,
|
|
|
- detach_on_drop: true,
|
|
|
+ try_detach_when_drop: true,
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -257,8 +182,8 @@ impl LoopDeviceBuilder {
|
|
|
}
|
|
|
|
|
|
#[allow(dead_code)]
|
|
|
- pub fn detach_on_drop(mut self, detach_on_drop: bool) -> Self {
|
|
|
- self.detach_on_drop = detach_on_drop;
|
|
|
+ pub fn try_detach_when_drop(mut self, try_detach_when_drop: bool) -> Self {
|
|
|
+ self.try_detach_when_drop = try_detach_when_drop;
|
|
|
self
|
|
|
}
|
|
|
|
|
@@ -266,8 +191,7 @@ impl LoopDeviceBuilder {
|
|
|
let loop_dev = LoopDevice {
|
|
|
img_path: self.img_path,
|
|
|
loop_device_path: self.loop_device_path,
|
|
|
- detach_on_drop: self.detach_on_drop,
|
|
|
- mapper: false,
|
|
|
+ try_detach_when_drop: self.try_detach_when_drop,
|
|
|
};
|
|
|
|
|
|
Ok(loop_dev)
|
|
@@ -319,11 +243,11 @@ mod tests {
|
|
|
|
|
|
#[test]
|
|
|
fn test_parse_losetup_a_output() {
|
|
|
- let losetup_a_output = r#"/dev/loop1: []: (/data/bin/x86_64/disk.img)
|
|
|
+ let losetup_a_output = r#"/dev/loop1: []: (/data/bin/disk-image-x86_64.img)
|
|
|
/dev/loop29: []: (/var/lib/abc.img)
|
|
|
/dev/loop13: []: (/var/lib/snapd/snaps/gtk-common-themes_1535.snap
|
|
|
/dev/loop19: []: (/var/lib/snapd/snaps/gnome-42-2204_172.snap)"#;
|
|
|
- let disk_img_path = "/data/bin/x86_64/disk.img";
|
|
|
+ let disk_img_path = "/data/bin/disk-image-x86_64.img";
|
|
|
let loop_device_path =
|
|
|
__loop_device_path_by_disk_image_path(disk_img_path, losetup_a_output).unwrap();
|
|
|
assert_eq!(loop_device_path, "/dev/loop1");
|
|
@@ -331,11 +255,11 @@ mod tests {
|
|
|
|
|
|
#[test]
|
|
|
fn test_parse_lsblk_output_not_match() {
|
|
|
- let losetup_a_output = r#"/dev/loop1: []: (/data/bin/x86_64/disk.img)
|
|
|
+ let losetup_a_output = r#"/dev/loop1: []: (/data/bin/disk-image-x86_64.img)
|
|
|
/dev/loop29: []: (/var/lib/abc.img)
|
|
|
/dev/loop13: []: (/var/lib/snapd/snaps/gtk-common-themes_1535.snap
|
|
|
/dev/loop19: []: (/var/lib/snapd/snaps/gnome-42-2204_172.snap)"#;
|
|
|
- let disk_img_path = "/data/bin/riscv64/disk.img";
|
|
|
+ let disk_img_path = "/data/bin/disk-image-riscv64.img";
|
|
|
let loop_device_path =
|
|
|
__loop_device_path_by_disk_image_path(disk_img_path, losetup_a_output);
|
|
|
assert!(
|