Enhanced flexibility in how resource images are mounted.

Can now choose location at which resource image is mounted with
mount_at() method. This method also returns a handle which can be
used to later unmount the image.
This commit is contained in:
Bruce Leidl 2019-08-20 14:04:17 -04:00
parent 2e781e2183
commit 9fb11e3317

View File

@ -112,16 +112,24 @@ impl ResourceImage {
}
}
pub fn mount(&mut self) -> Result<()> {
if CommandLine::noverity() {
self.mount_noverity()?;
} else {
self.mount_verity()?;
}
/// Mount resource image at default mount path and process manifest file if it exists
pub fn mount(&mut self) -> Result<()> {
let _ = self.mount_at(self.mount_path())?;
self.process_manifest_file()
}
/// Mount resource image at specified path without processing manifest file.
/// Returns a ResourceMount object which can be stored and later used to unmount
/// the image.
pub fn mount_at<P: AsRef<Path>>(&mut self, mount_path: P) -> Result<ResourceMount> {
if CommandLine::noverity() {
self.mount_noverity(mount_path.as_ref())
} else {
self.mount_verity(mount_path.as_ref())
}
}
pub fn is_compressed(&self) -> bool {
self.header.has_flag(ImageHeader::FLAG_DATA_COMPRESSED)
}
@ -175,18 +183,20 @@ impl ResourceImage {
Ok(())
}
fn mount_verity(&self) -> Result<()> {
fn mount_verity(&self, mount_path: &Path) -> Result<ResourceMount> {
let verity_dev = self.setup_verity_device()?;
let verity_path = format!("/dev/mapper/{}", verity_dev);
info!("Mounting dm-verity device to {}", self.mount_path().display());
info!("Mounting dm-verity device to {}", mount_path.display());
fs::create_dir_all(self.mount_path())?;
fs::create_dir_all(mount_path)?;
util::mount(&verity_dev.to_string_lossy(), self.mount_path(), None)
util::mount(verity_path, mount_path, None)?;
Ok(ResourceMount::new_verity(mount_path, verity_dev))
}
pub fn setup_verity_device(&self) -> Result<PathBuf> {
pub fn setup_verity_device(&self) -> Result<String> {
if !CommandLine::nosignatures() {
match self.header.public_key()? {
Some(pubkey) => {
@ -202,9 +212,7 @@ impl ResourceImage {
if !self.has_verity_hashtree() {
self.generate_verity_hashtree()?;
}
let devname = self.verity().setup(&self.metainfo())?;
Ok(Path::new("/dev/mapper").join(devname))
// verity::setup_image_device(self.path(), &self.metainfo())
self.verity().setup(&self.metainfo())
}
pub fn generate_verity_hashtree(&self) -> Result<()> {
@ -246,22 +254,23 @@ impl ResourceImage {
// Mount the resource image but use a simple loop mount rather than setting up a dm-verity
// device for the image.
fn mount_noverity(&self) -> Result<()> {
fn mount_noverity(&self, mount_path: &Path) -> Result<ResourceMount> {
info!("loop mounting image to {} (noverity)", self.mount_path().display());
if self.is_compressed() {
self.decompress()?;
}
let mount_path = self.mount_path();
let loopdev = LoopDevice::create(self.path(), Some(4096), true)?;
info!("Loop device created: {}", loopdev);
info!("Mounting to: {}", mount_path.display());
fs::create_dir_all(&mount_path)?;
fs::create_dir_all(mount_path)?;
util::mount(&loopdev.device_str(), mount_path, Some("-oro"))
util::mount(&loopdev.device_str(), mount_path, Some("-oro"))?;
Ok(ResourceMount::new_loop(mount_path, loopdev))
}
// Return the path at which to mount this resource image.
@ -492,3 +501,50 @@ fn maybe_add_dir_entry(entry: DirEntry,
Ok(())
}
enum ResourceMountType {
Unmounted,
Verity(String),
Loop(LoopDevice),
}
pub struct ResourceMount {
mountpoint: PathBuf,
mounttype: ResourceMountType,
}
impl ResourceMount {
fn new_verity(mountpoint: &Path, dev: String) -> ResourceMount {
Self::new(mountpoint, ResourceMountType::Verity(dev))
}
fn new_loop(mountpoint: &Path, loopdev: LoopDevice) -> ResourceMount {
Self::new(mountpoint, ResourceMountType::Loop(loopdev))
}
fn new(mountpoint: &Path, mounttype: ResourceMountType) -> ResourceMount {
let mountpoint = mountpoint.to_path_buf();
ResourceMount {
mountpoint, mounttype
}
}
pub fn unmount(&mut self) -> Result<()> {
match self.mounttype {
ResourceMountType::Verity(ref dev) => {
util::umount(&self.mountpoint)?;
Verity::close_device(dev.as_str())?;
self.mounttype = ResourceMountType::Unmounted;
},
ResourceMountType::Loop(ref loopdev) => {
util::umount(&self.mountpoint)?;
loopdev.detach()?;
self.mounttype = ResourceMountType::Unmounted;
},
ResourceMountType::Unmounted => {
warn!("Resource image is already unmounted from {}", self.mountpoint.display());
},
}
Ok(())
}
}