Uber refactoring

This commit is contained in:
Roey Darwish Dror 2019-05-29 13:44:37 +03:00
parent 1182c96a08
commit bb7567e72b
10 changed files with 282 additions and 206 deletions

View File

@ -1,54 +0,0 @@
use super::block::BlockDevice;
use super::cryptsetup::EncryptedDevice;
use super::error::{Error, ErrorKind};
use super::mountstack::{Filesystem, MountStack};
use failure::ResultExt;
use log::{debug, info};
use std::fs;
use std::path::{Path, PathBuf};
pub struct ALMA<'a> {
block: BlockDevice,
encrypted_root: Option<EncryptedDevice<'a>>,
}
impl<'a> ALMA<'a> {
pub fn new(block: BlockDevice, encrypted_root: Option<EncryptedDevice<'a>>) -> Self {
Self {
block,
encrypted_root,
}
}
pub fn mount<'b>(&self, path: &'b Path) -> Result<MountStack<'b>, Error> {
let mut mount_stack = MountStack::new();
let root_device = if let Some(encrypted_root) = &self.encrypted_root {
PathBuf::from(encrypted_root.path())
} else {
self.block.partition_device_path(3)?
};
debug!("Root partition: {}", root_device.display());
info!("Mounting filesystems to {}", path.display());
mount_stack
.mount(&root_device, path, Filesystem::Ext4, None)
.context(ErrorKind::Mounting)?;
let boot_point = path.join("boot");
if !boot_point.exists() {
fs::create_dir(&boot_point).context(ErrorKind::CreateBoot)?;
}
mount_stack
.mount(
&self.block.partition_device_path(1)?,
boot_point,
Filesystem::Vfat,
None,
)
.context(ErrorKind::Mounting)?;
Ok(mount_stack)
}
}

View File

@ -1,68 +0,0 @@
use super::error::{Error, ErrorKind};
use super::process::CommandExt;
use super::tool::Tool;
use log::{debug, warn};
use std::path::{Path, PathBuf};
pub struct EncryptedDevice<'a> {
cryptsetup: &'a Tool,
name: &'a str,
path: PathBuf,
}
impl<'a> EncryptedDevice<'a> {
pub fn prepare(cryptsetup: &Tool, device: &Path) -> Result<(), Error> {
debug!("Preparing encrypted device in {}", device.display());
cryptsetup
.execute()
.arg("luksFormat")
.arg("-q")
.arg(device)
.run(ErrorKind::LuksSetup)?;
Ok(())
}
pub fn open(
cryptsetup: &'a Tool,
device: &Path,
name: &'a str,
) -> Result<EncryptedDevice<'a>, Error> {
debug!("Opening encrypted device {} as {}", device.display(), name);
cryptsetup
.execute()
.arg("open")
.arg(device)
.arg(name)
.run(ErrorKind::LuksOpen)?;
Ok(Self {
cryptsetup,
name,
path: PathBuf::from("/dev/mapper").join(name),
})
}
fn _close(&mut self) -> Result<(), Error> {
debug!("Closing encrypted device {}", self.name);
self.cryptsetup
.execute()
.arg("close")
.arg(self.name)
.run(ErrorKind::LuksClose)?;
Ok(())
}
pub fn path(&self) -> &Path {
&self.path
}
}
impl<'a> Drop for EncryptedDevice<'a> {
fn drop(&mut self) {
if self._close().is_err() {
warn!("Error closing {}", self.name);
}
}
}

View File

@ -1,15 +1,11 @@
mod alma;
mod block;
mod cryptsetup;
mod error; mod error;
mod mountstack;
mod process; mod process;
mod storage;
mod tool; mod tool;
use crate::alma::ALMA;
use crate::cryptsetup::EncryptedDevice;
use crate::error::*; use crate::error::*;
use crate::process::CommandExt; use crate::process::CommandExt;
use crate::storage::*;
use crate::tool::Tool; use crate::tool::Tool;
use failure::{Fail, ResultExt}; use failure::{Fail, ResultExt};
use log::{debug, error, info, warn}; use log::{debug, error, info, warn};
@ -17,7 +13,7 @@ use nix::sys::signal;
use simplelog::*; use simplelog::*;
use std::fs; use std::fs;
use std::io::Write; use std::io::Write;
use std::path::PathBuf; use std::path::{Path, PathBuf};
use std::process::exit; use std::process::exit;
use std::thread; use std::thread;
use std::time::Duration; use std::time::Duration;
@ -89,6 +85,34 @@ struct ChrootCommand {
command: Vec<String>, command: Vec<String>,
} }
fn mount<'a>(
mount_path: &Path,
boot_filesystem: &'a Filesystem,
root_filesystem: &'a Filesystem,
) -> Result<MountStack<'a>, Error> {
let mut mount_stack = MountStack::new();
debug!(
"Root partition: {}",
root_filesystem.block().path().display()
);
info!("Mounting filesystems to {}", mount_path.display());
mount_stack
.mount(&root_filesystem, mount_path.into(), None)
.context(ErrorKind::Mounting)?;
let boot_point = mount_path.join("boot");
if !boot_point.exists() {
fs::create_dir(&boot_point).context(ErrorKind::CreateBoot)?;
}
mount_stack
.mount(&boot_filesystem, boot_point, None)
.context(ErrorKind::Mounting)?;
Ok(mount_stack)
}
fn fix_fstab(fstab: &str) -> String { fn fix_fstab(fstab: &str) -> String {
fstab fstab
.lines() .lines()
@ -115,11 +139,9 @@ fn create(command: CreateCommand) -> Result<(), Error> {
None None
}; };
let block_device = block::BlockDevice::from_path(command.block_device)?; let storage_device = storage::StorageDevice::from_path(command.block_device)?;
let mount_point = tempdir().context(ErrorKind::TmpDirError)?; let mount_point = tempdir().context(ErrorKind::TmpDirError)?;
let disk_path = storage_device.path();
let disk_path = block_device.device_path();
info!("Partitioning the block device"); info!("Partitioning the block device");
debug!("{:?}", disk_path); debug!("{:?}", disk_path);
@ -141,38 +163,31 @@ fn create(command: CreateCommand) -> Result<(), Error> {
thread::sleep(Duration::from_millis(1000)); thread::sleep(Duration::from_millis(1000));
info!("Formatting filesystems"); info!("Formatting filesystems");
let boot_partition = block_device.partition_device_path(1)?; let boot_partition = storage_device.get_partition(1)?;
mkfat let boot_filesystem = Filesystem::format(&boot_partition, FilesystemType::Vfat, &mkfat)?;
.execute()
.arg("-F32")
.arg(&boot_partition)
.run(ErrorKind::Formatting)?;
let root_partition = block_device.partition_device_path(3)?; let root_partition_base = storage_device.get_partition(3)?;
let encrypted_root = if let Some(cryptsetup) = &cryptsetup { let encrypted_root = if let Some(cryptsetup) = &cryptsetup {
info!("Encrypting the root filesystem"); info!("Encrypting the root filesystem");
EncryptedDevice::prepare(&cryptsetup, &root_partition)?; EncryptedDevice::prepare(&cryptsetup, &root_partition_base)?;
Some(EncryptedDevice::open( Some(EncryptedDevice::open(
cryptsetup, cryptsetup,
&root_partition, &root_partition_base,
"alma_root", "alma_root".into(),
)?) )?)
} else { } else {
None None
}; };
mkext4 let root_partition = if let Some(e) = encrypted_root.as_ref() {
.execute() e as &BlockDevice
.arg("-F") } else {
.arg(if let Some(device) = &encrypted_root { &root_partition_base as &BlockDevice
device.path() };
} else {
&root_partition
})
.run(ErrorKind::Formatting)?;
let alma = ALMA::new(block_device, encrypted_root); let root_filesystem = Filesystem::format(root_partition, FilesystemType::Ext4, &mkext4)?;
let mount_stack = alma.mount(mount_point.path())?;
let mount_stack = mount(mount_point.path(), &boot_filesystem, &root_filesystem)?;
info!("Bootstrapping system"); info!("Bootstrapping system");
pacstrap pacstrap
@ -246,7 +261,7 @@ fn create(command: CreateCommand) -> Result<(), Error> {
let uuid = blkid let uuid = blkid
.unwrap() .unwrap()
.execute() .execute()
.arg(root_partition) .arg(root_partition.path())
.args(&["-o", "value", "-s", "UUID"]) .args(&["-o", "value", "-s", "UUID"])
.run_text_output(ErrorKind::Partitioning)?; .run_text_output(ErrorKind::Partitioning)?;
let trimmed = uuid.trim(); let trimmed = uuid.trim();
@ -295,22 +310,31 @@ fn chroot(command: ChrootCommand) -> Result<(), Error> {
None None
}; };
let block_device = block::BlockDevice::from_path(command.block_device)?; let storage_device = storage::StorageDevice::from_path(command.block_device)?;
let mount_point = tempdir().context(ErrorKind::TmpDirError)?; let mount_point = tempdir().context(ErrorKind::TmpDirError)?;
let root_partition = block_device.partition_device_path(3)?;
let boot_partition = storage_device.get_partition(1)?;
let boot_filesystem = Filesystem::from_partition(&boot_partition, FilesystemType::Vfat);
let root_partition_base = storage_device.get_partition(3)?;
let encrypted_root = if let Some(cryptsetup) = &cryptsetup { let encrypted_root = if let Some(cryptsetup) = &cryptsetup {
Some(EncryptedDevice::open( Some(EncryptedDevice::open(
cryptsetup, cryptsetup,
&root_partition, &root_partition_base,
"alma_root", "alma_root".into(),
)?) )?)
} else { } else {
None None
}; };
let alma = ALMA::new(block_device, encrypted_root); let root_partition = if let Some(e) = encrypted_root.as_ref() {
let mount_stack = alma.mount(mount_point.path())?; e as &BlockDevice
} else {
&root_partition_base as &BlockDevice
};
let root_filesystem = Filesystem::from_partition(root_partition, FilesystemType::Ext4);
let mount_stack = mount(mount_point.path(), &boot_filesystem, &root_filesystem)?;
arch_chroot arch_chroot
.execute() .execute()

80
src/storage/crypt.rs Normal file
View File

@ -0,0 +1,80 @@
use super::markers::BlockDevice;
use crate::error::{Error, ErrorKind};
use crate::process::CommandExt;
use crate::tool::Tool;
use log::{debug, warn};
use std::marker::PhantomData;
use std::path::{Path, PathBuf};
#[derive(Debug)]
pub struct EncryptedDevice<'t, 'o> {
cryptsetup: &'t Tool,
name: String,
path: PathBuf,
origin: PhantomData<&'o BlockDevice>,
}
impl<'t, 'o> EncryptedDevice<'t, 'o> {
pub fn prepare(cryptsetup: &Tool, device: &BlockDevice) -> Result<(), Error> {
debug!("Preparing encrypted device in {}", device.path().display());
cryptsetup
.execute()
.arg("luksFormat")
.arg("-q")
.arg(device.path())
.run(ErrorKind::LuksSetup)?;
Ok(())
}
pub fn open(
cryptsetup: &'t Tool,
device: &'o BlockDevice,
name: String,
) -> Result<EncryptedDevice<'t, 'o>, Error> {
debug!(
"Opening encrypted device {} as {}",
device.path().display(),
name
);
cryptsetup
.execute()
.arg("open")
.arg(device.path())
.arg(&name)
.run(ErrorKind::LuksOpen)?;
let path = PathBuf::from("/dev/mapper").join(&name);
Ok(Self {
cryptsetup,
name,
path,
origin: PhantomData,
})
}
fn _close(&mut self) -> Result<(), Error> {
debug!("Closing encrypted device {}", self.name);
self.cryptsetup
.execute()
.arg("close")
.arg(&self.name)
.run(ErrorKind::LuksClose)?;
Ok(())
}
}
impl<'t, 'o> Drop for EncryptedDevice<'t, 'o> {
fn drop(&mut self) {
if self._close().is_err() {
warn!("Error closing {}", self.name);
}
}
}
impl<'t, 'o> BlockDevice for EncryptedDevice<'t, 'o> {
fn path(&self) -> &Path {
&self.path
}
}

57
src/storage/filesystem.rs Normal file
View File

@ -0,0 +1,57 @@
use super::markers::BlockDevice;
use crate::{
error::{Error, ErrorKind},
process::CommandExt,
tool::Tool,
};
#[derive(Debug, Clone, Copy)]
pub enum FilesystemType {
Ext4,
Vfat,
}
impl FilesystemType {
pub fn to_mount_type(self) -> &'static str {
match self {
FilesystemType::Ext4 => "ext4",
FilesystemType::Vfat => "vfat",
}
}
}
#[derive(Debug)]
pub struct Filesystem<'a> {
fs_type: FilesystemType,
block: &'a BlockDevice,
}
impl<'a> Filesystem<'a> {
pub fn format(
block: &'a BlockDevice,
fs_type: FilesystemType,
mkfs: &Tool,
) -> Result<Self, Error> {
let mut command = mkfs.execute();
match fs_type {
FilesystemType::Ext4 => command.arg("-F").arg(block.path()),
FilesystemType::Vfat => command.arg("-F32").arg(block.path()),
};
command.run(ErrorKind::Formatting)?;
Ok(Self { fs_type, block })
}
pub fn from_partition(block: &'a BlockDevice, fs_type: FilesystemType) -> Self {
Self { fs_type, block }
}
pub fn block(&self) -> &BlockDevice {
self.block
}
pub fn fs_type(&self) -> FilesystemType {
self.fs_type
}
}

7
src/storage/markers.rs Normal file
View File

@ -0,0 +1,7 @@
use std::path::Path;
pub trait BlockDevice: std::fmt::Debug {
fn path(&self) -> &Path;
}
pub trait Origin {}

12
src/storage/mod.rs Normal file
View File

@ -0,0 +1,12 @@
mod crypt;
mod filesystem;
mod markers;
mod mount_stack;
mod partition;
mod storage_device;
pub use crypt::EncryptedDevice;
pub use filesystem::{Filesystem, FilesystemType};
pub use markers::BlockDevice;
pub use mount_stack::MountStack;
pub use storage_device::StorageDevice;

View File

@ -1,52 +1,38 @@
use super::error::{Error, ErrorKind}; use super::Filesystem;
use crate::error::{Error, ErrorKind};
use failure::Fail; use failure::Fail;
use log::{debug, warn}; use log::{debug, warn};
use nix; use nix;
use nix::mount::{mount, umount, MsFlags}; use nix::mount::{mount, umount, MsFlags};
use std::borrow::Cow; use std::marker::PhantomData;
use std::path::Path; use std::path::PathBuf;
#[derive(Debug, Clone, Copy)]
pub enum Filesystem {
Ext4,
Vfat,
}
impl Filesystem {
fn to_type(self) -> &'static str {
match self {
Filesystem::Ext4 => "ext4",
Filesystem::Vfat => "vfat",
}
}
}
pub struct MountStack<'a> { pub struct MountStack<'a> {
targets: Vec<Cow<'a, Path>>, targets: Vec<PathBuf>,
filesystems: PhantomData<Filesystem<'a>>,
} }
impl<'a> MountStack<'a> { impl<'a> MountStack<'a> {
pub fn new() -> Self { pub fn new() -> Self {
MountStack { MountStack {
targets: Vec::new(), targets: Vec::new(),
filesystems: PhantomData,
} }
} }
#[must_use] #[must_use]
pub fn mount<T: Into<Cow<'a, Path>>>( pub fn mount(
&mut self, &mut self,
source: &Path, filesystem: &'a Filesystem,
target: T, target: PathBuf,
filesystem: Filesystem,
options: Option<&str>, options: Option<&str>,
) -> nix::Result<()> { ) -> nix::Result<()> {
let target = target.into(); let source = filesystem.block().path();
debug!("Mounting {:?} to {:?}", filesystem, target);
debug!("Mounting {:?} ({:?}) to {:?}", source, filesystem, target);
mount( mount(
Some(source), Some(source),
target.as_ref(), &target,
Some(filesystem.to_type()), Some(filesystem.fs_type().to_mount_type()),
MsFlags::MS_NOATIME, MsFlags::MS_NOATIME,
options, options,
)?; )?;
@ -59,7 +45,7 @@ impl<'a> MountStack<'a> {
while let Some(target) = self.targets.pop() { while let Some(target) = self.targets.pop() {
debug!("Unmounting {}", target.display()); debug!("Unmounting {}", target.display());
if let Err(e) = umount(target.as_ref()) { if let Err(e) = umount(&target) {
warn!("Unable to umount {}: {}", target.display(), e); warn!("Unable to umount {}: {}", target.display(), e);
result = Err(Error::from(e.context(ErrorKind::UmountFailure))); result = Err(Error::from(e.context(ErrorKind::UmountFailure)));
}; };

24
src/storage/partition.rs Normal file
View File

@ -0,0 +1,24 @@
use super::markers::{BlockDevice, Origin};
use std::marker::PhantomData;
use std::path::{Path, PathBuf};
#[derive(Debug)]
pub struct Partition<'a> {
path: PathBuf,
origin: PhantomData<&'a Origin>,
}
impl<'a> Partition<'a> {
pub fn new<T: Origin + 'a>(path: PathBuf) -> Self {
Self {
path,
origin: PhantomData,
}
}
}
impl<'a> BlockDevice for Partition<'a> {
fn path(&self) -> &Path {
&self.path
}
}

View File

@ -1,15 +1,18 @@
use super::error::{Error, ErrorKind}; use super::markers::{BlockDevice, Origin};
use super::partition::Partition;
use crate::error::{Error, ErrorKind};
use failure::ResultExt; use failure::ResultExt;
use log::debug; use log::debug;
use std::fs::read_to_string; use std::fs::read_to_string;
use std::path::PathBuf; use std::path::{Path, PathBuf};
#[derive(Debug)] #[derive(Debug)]
pub struct BlockDevice { pub struct StorageDevice {
name: String, name: String,
path: PathBuf,
} }
impl BlockDevice { impl StorageDevice {
pub fn from_path(path: PathBuf) -> Result<Self, Error> { pub fn from_path(path: PathBuf) -> Result<Self, Error> {
let real_path = path.canonicalize().context(ErrorKind::DeviceQuery)?; let real_path = path.canonicalize().context(ErrorKind::DeviceQuery)?;
let device_name = real_path let device_name = real_path
@ -24,8 +27,11 @@ impl BlockDevice {
); );
drop(path); drop(path);
let _self = Self { name: device_name }; let _self = Self {
if !(_self.is_removable()? || _self.is_loop_device()) { name: device_name,
path: real_path,
};
if !(_self.is_removable_device()? || _self.is_loop_device()) {
return Err(ErrorKind::DangerousDevice)?; return Err(ErrorKind::DangerousDevice)?;
} }
@ -38,7 +44,7 @@ impl BlockDevice {
path path
} }
fn is_removable(&self) -> Result<bool, Error> { fn is_removable_device(&self) -> Result<bool, Error> {
let mut path = self.sys_path(); let mut path = self.sys_path();
path.push("removable"); path.push("removable");
@ -55,13 +61,7 @@ impl BlockDevice {
path.exists() path.exists()
} }
pub fn device_path(&self) -> PathBuf { pub fn get_partition(&self, index: u8) -> Result<Partition, Error> {
let mut path = PathBuf::from("/dev");
path.push(self.name.clone());
path
}
pub fn partition_device_path(&self, index: u8) -> Result<PathBuf, Error> {
let name = if self.name.chars().rev().next().unwrap().is_digit(10) { let name = if self.name.chars().rev().next().unwrap().is_digit(10) {
format!("{}p{}", self.name, index) format!("{}p{}", self.name, index)
} else { } else {
@ -74,6 +74,14 @@ impl BlockDevice {
if !path.exists() { if !path.exists() {
return Err(ErrorKind::NoSuchPartition(index).into()); return Err(ErrorKind::NoSuchPartition(index).into());
} }
Ok(path) Ok(Partition::new::<Self>(path))
} }
} }
impl BlockDevice for StorageDevice {
fn path(&self) -> &Path {
&self.path
}
}
impl Origin for StorageDevice {}