Loop device support

This commit is contained in:
Roey Darwish Dror
2019-06-17 20:34:24 +03:00
parent 379f11af42
commit d4cdd187a0
8 changed files with 192 additions and 10 deletions

View File

@@ -1,6 +1,11 @@
use byte_unit::Byte;
use std::path::PathBuf;
use structopt::StructOpt;
fn parse_bytes(src: &str) -> Result<Byte, &'static str> {
Byte::from_string(src).map_err(|_| "Invalid image size")
}
#[derive(StructOpt)]
#[structopt(name = "alma", about = "Arch Linux Mobile Appliance")]
pub struct App {
@@ -26,9 +31,9 @@ pub enum Command {
#[derive(StructOpt)]
pub struct CreateCommand {
/// Path starting with /dev/disk/by-id for the USB drive
/// Either a path to a removable block device or a nonexiting file if --image is specified
#[structopt(parse(from_os_str))]
pub block_device: PathBuf,
pub path: PathBuf,
/// Additional pacakges to install
#[structopt(short = "p", long = "extra-packages", value_name = "package")]
@@ -43,8 +48,16 @@ pub struct CreateCommand {
pub encrypted_root: bool,
/// Path to preset files
#[structopt(long = "presets")]
#[structopt(long = "presets", value_name = "preset")]
pub presets: Vec<PathBuf>,
/// Create an image with a certain size in the given path instead of using an actual block device
#[structopt(
long = "image",
parse(try_from_str = "parse_bytes"),
value_name = "size"
)]
pub image: Option<Byte>,
}
#[derive(StructOpt)]

View File

@@ -82,6 +82,12 @@ pub enum ErrorKind {
#[fail(display = "Error executing preset script")]
PresetScript,
#[fail(display = "Error creating the image")]
Image,
#[fail(display = "Error setting up a loop device: {}", _0)]
Losetup(String),
}
impl Fail for Error {

View File

@@ -10,6 +10,7 @@ use crate::error::*;
use crate::process::CommandExt;
use crate::storage::*;
use crate::tool::Tool;
use byte_unit::Byte;
use failure::{Fail, ResultExt};
use log::{debug, error, info, warn};
use nix::sys::signal;
@@ -75,6 +76,21 @@ fn fix_fstab(fstab: &str) -> String {
.join("\n")
}
fn create_image(path: &Path, size: Byte) -> Result<LoopDevice, Error> {
{
let file = fs::OpenOptions::new()
.write(true)
.create_new(true)
.open(path)
.context(ErrorKind::Image)?;
file.set_len(size.get_bytes() as u64)
.context(ErrorKind::Image)?;
}
LoopDevice::create(path)
}
fn create(command: CreateCommand) -> Result<(), Error> {
let presets = presets::Presets::load(&command.presets)?;
@@ -95,7 +111,21 @@ fn create(command: CreateCommand) -> Result<(), Error> {
None
};
let storage_device = storage::StorageDevice::from_path(command.block_device)?;
let image_loop = if let Some(size) = command.image {
Some(create_image(&command.path, size)?)
} else {
None
};
let storage_device = storage::StorageDevice::from_path(
image_loop
.as_ref()
.map(|loop_dev| {
info!("Using loop device at {}", loop_dev.path().display());
loop_dev.path()
})
.unwrap_or(&command.path),
)?;
let mount_point = tempdir().context(ErrorKind::TmpDirError)?;
let disk_path = storage_device.path();
@@ -300,7 +330,7 @@ fn chroot(command: ChrootCommand) -> Result<(), Error> {
None
};
let storage_device = storage::StorageDevice::from_path(command.block_device)?;
let storage_device = storage::StorageDevice::from_path(&command.block_device)?;
let mount_point = tempdir().context(ErrorKind::TmpDirError)?;
let boot_partition = storage_device.get_partition(BOOT_PARTITION_INDEX)?;

View File

@@ -0,0 +1,52 @@
use crate::error::{Error, ErrorKind};
use crate::tool::Tool;
use failure::ResultExt;
use log::info;
use std::path::{Path, PathBuf};
#[derive(Debug)]
pub struct LoopDevice {
path: PathBuf,
losetup: Tool,
}
impl LoopDevice {
pub fn create(file: &Path) -> Result<Self, Error> {
let losetup = Tool::find("losetup")?;
let output = losetup
.execute()
.args(&["--find", "-P", "--show"])
.arg(file)
.output()
.context(ErrorKind::Image)?;
if !output.status.success() {
Err(ErrorKind::Losetup(
String::from_utf8(output.stderr).unwrap(),
))?
}
Ok(LoopDevice {
path: PathBuf::from(String::from_utf8(output.stdout).unwrap().trim()),
losetup,
})
}
pub fn path(&self) -> &Path {
&self.path
}
}
impl Drop for LoopDevice {
fn drop(&mut self) {
info!("Detaching loop device {}", self.path.display());
self.losetup
.execute()
.arg("-d")
.arg(&self.path)
.spawn()
.unwrap()
.wait()
.ok();
}
}

View File

@@ -1,5 +1,6 @@
mod crypt;
mod filesystem;
mod loop_device;
mod markers;
mod mount_stack;
mod partition;
@@ -7,6 +8,7 @@ mod storage_device;
pub use crypt::EncryptedDevice;
pub use filesystem::{Filesystem, FilesystemType};
pub use loop_device::LoopDevice;
pub use markers::BlockDevice;
pub use mount_stack::MountStack;
pub use storage_device::StorageDevice;

View File

@@ -4,16 +4,18 @@ use crate::error::{Error, ErrorKind};
use failure::ResultExt;
use log::debug;
use std::fs::read_to_string;
use std::marker::PhantomData;
use std::path::{Path, PathBuf};
#[derive(Debug)]
pub struct StorageDevice {
pub struct StorageDevice<'a> {
name: String,
path: PathBuf,
origin: PhantomData<&'a Origin>,
}
impl StorageDevice {
pub fn from_path(path: PathBuf) -> Result<Self, Error> {
impl<'a> StorageDevice<'a> {
pub fn from_path(path: &'a Path) -> Result<Self, Error> {
let real_path = path.canonicalize().context(ErrorKind::DeviceQuery)?;
let device_name = real_path
.file_name()
@@ -30,6 +32,7 @@ impl StorageDevice {
let _self = Self {
name: device_name,
path: real_path,
origin: PhantomData,
};
if !(_self.is_removable_device()? || _self.is_loop_device()) {
return Err(ErrorKind::DangerousDevice)?;
@@ -78,10 +81,10 @@ impl StorageDevice {
}
}
impl BlockDevice for StorageDevice {
impl<'a> BlockDevice for StorageDevice<'a> {
fn path(&self) -> &Path {
&self.path
}
}
impl Origin for StorageDevice {}
impl<'a> Origin for StorageDevice<'a> {}