Add a flag for non-removable devices (fix #24)

This commit is contained in:
Roey Darwish Dror 2019-08-13 21:43:55 +03:00
parent 25cdc44c7c
commit 750653c222
8 changed files with 56 additions and 25 deletions

1
Cargo.lock generated
View File

@ -13,6 +13,7 @@ name = "alma"
version = "0.9.0" version = "0.9.0"
dependencies = [ dependencies = [
"byte-unit 3.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "byte-unit 3.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"console 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)",
"dialoguer 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "dialoguer 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",

View File

@ -17,3 +17,4 @@ nix = "0.15.0"
env_logger = "0.6.2" env_logger = "0.6.2"
pretty_env_logger = "0.3.0" pretty_env_logger = "0.3.0"
dialoguer = "0.4.0" dialoguer = "0.4.0"
console = "0.7.7"

View File

@ -60,9 +60,16 @@ pub struct CreateCommand {
)] )]
pub image: Option<Byte>, pub image: Option<Byte>,
/// Overwrite existing image files. Use with caution /// Overwrite existing image files. Use with caution!
#[structopt(long = "overwrite")] #[structopt(long = "overwrite")]
pub overwrite: bool, pub overwrite: bool,
/// Allow installation on non-removable devices. Use with extreme caution!
///
/// If no device is specified in the command line, the device selection menu will
/// show non-removable devices
#[structopt(long = "allow-non-removable")]
pub allow_non_removable: bool,
} }
#[derive(StructOpt)] #[derive(StructOpt)]
@ -71,6 +78,10 @@ pub struct ChrootCommand {
#[structopt(parse(from_os_str))] #[structopt(parse(from_os_str))]
pub block_device: PathBuf, pub block_device: PathBuf,
/// Allow installation on non-removable devices. Use with extreme caution!
#[structopt(long = "allow-non-removable")]
pub allow_non_removable: bool,
/// Optional command to run /// Optional command to run
#[structopt()] #[structopt()]
pub command: Vec<String>, pub command: Vec<String>,

View File

@ -92,8 +92,8 @@ pub enum ErrorKind {
#[fail(display = "Error setting up a loop device: {}", _0)] #[fail(display = "Error setting up a loop device: {}", _0)]
Losetup(String), Losetup(String),
#[fail(display = "Error querying removeable devices")] #[fail(display = "Error querying storage devices")]
RemoveableDevicesQuery, StorageDevicesQuery,
#[fail(display = "There are no removable devices")] #[fail(display = "There are no removable devices")]
NoRemovableDevices, NoRemovableDevices,

View File

@ -12,6 +12,7 @@ use crate::process::CommandExt;
use crate::storage::*; use crate::storage::*;
use crate::tool::Tool; use crate::tool::Tool;
use byte_unit::Byte; use byte_unit::Byte;
use console::style;
use dialoguer::{theme::ColorfulTheme, Select}; use dialoguer::{theme::ColorfulTheme, Select};
use failure::{Fail, ResultExt}; use failure::{Fail, ResultExt};
use log::{debug, error, info, log_enabled, Level, LevelFilter}; use log::{debug, error, info, log_enabled, Level, LevelFilter};
@ -91,13 +92,22 @@ fn create_image(path: &Path, size: Byte, overwrite: bool) -> Result<LoopDevice,
LoopDevice::create(path) LoopDevice::create(path)
} }
fn select_block_device() -> Result<PathBuf, Error> { fn select_block_device(allow_non_removable: bool) -> Result<PathBuf, Error> {
let devices = get_removable_devices()?; let devices = get_storage_devices(allow_non_removable)?;
if devices.is_empty() { if devices.is_empty() {
Err(ErrorKind::NoRemovableDevices)? Err(ErrorKind::NoRemovableDevices)?
} }
if allow_non_removable {
println!(
"{}\n",
style("Showing non-removable devices. Make sure you select the correct device.")
.red()
.bold()
);
}
let selection = Select::with_theme(&ColorfulTheme::default()) let selection = Select::with_theme(&ColorfulTheme::default())
.with_prompt("Select a removable device") .with_prompt("Select a removable device")
.default(0) .default(0)
@ -132,7 +142,7 @@ fn create(command: CreateCommand) -> Result<(), Error> {
let storage_device_path = if let Some(path) = command.path { let storage_device_path = if let Some(path) = command.path {
path path
} else { } else {
select_block_device()? select_block_device(command.allow_non_removable)?
}; };
let image_loop = if let Some(size) = command.image { let image_loop = if let Some(size) = command.image {
@ -149,6 +159,7 @@ fn create(command: CreateCommand) -> Result<(), Error> {
loop_dev.path() loop_dev.path()
}) })
.unwrap_or(&storage_device_path), .unwrap_or(&storage_device_path),
command.allow_non_removable,
)?; )?;
let mount_point = tempdir().context(ErrorKind::TmpDirError)?; let mount_point = tempdir().context(ErrorKind::TmpDirError)?;
@ -373,13 +384,18 @@ fn chroot(command: ChrootCommand) -> Result<(), Error> {
let mut cryptsetup; let mut cryptsetup;
let mut loop_device: Option<LoopDevice>; let mut loop_device: Option<LoopDevice>;
let storage_device = match storage::StorageDevice::from_path(&command.block_device) { let storage_device =
Ok(b) => b, match storage::StorageDevice::from_path(&command.block_device, command.allow_non_removable)
Err(_) => { {
loop_device = Some(LoopDevice::create(&command.block_device)?); Ok(b) => b,
storage::StorageDevice::from_path(loop_device.as_ref().unwrap().path())? Err(_) => {
} loop_device = Some(LoopDevice::create(&command.block_device)?);
}; storage::StorageDevice::from_path(
loop_device.as_ref().unwrap().path(),
command.allow_non_removable,
)?
}
};
let mount_point = tempdir().context(ErrorKind::TmpDirError)?; let mount_point = tempdir().context(ErrorKind::TmpDirError)?;
let boot_partition = storage_device.get_partition(BOOT_PARTITION_INDEX)?; let boot_partition = storage_device.get_partition(BOOT_PARTITION_INDEX)?;

View File

@ -12,5 +12,5 @@ pub use filesystem::{Filesystem, FilesystemType};
pub use loop_device::LoopDevice; pub use loop_device::LoopDevice;
pub use markers::BlockDevice; pub use markers::BlockDevice;
pub use mount_stack::MountStack; pub use mount_stack::MountStack;
pub use removeable_devices::get_removable_devices; pub use removeable_devices::get_storage_devices;
pub use storage_device::StorageDevice; pub use storage_device::StorageDevice;

View File

@ -27,22 +27,24 @@ fn trimmed(source: String) -> String {
String::from(source.trim_end()) String::from(source.trim_end())
} }
pub fn get_removable_devices() -> Result<Vec<Device>, Error> { pub fn get_storage_devices(allow_non_removable: bool) -> Result<Vec<Device>, Error> {
let mut result = Vec::new(); let mut result = Vec::new();
for entry in fs::read_dir("/sys/block").context(ErrorKind::RemoveableDevicesQuery)? { for entry in fs::read_dir("/sys/block").context(ErrorKind::StorageDevicesQuery)? {
let entry = entry.context(ErrorKind::RemoveableDevicesQuery)?; let entry = entry.context(ErrorKind::StorageDevicesQuery)?;
let removable = fs::read_to_string(entry.path().join("removable")) let removable = allow_non_removable
.context(ErrorKind::RemoveableDevicesQuery)?; || fs::read_to_string(entry.path().join("removable"))
.map(|v| v == "1\n")
.context(ErrorKind::StorageDevicesQuery)?;
if removable != "1\n" { if !removable {
continue; continue;
} }
let model = fs::read_to_string(entry.path().join("device/model")) let model = fs::read_to_string(entry.path().join("device/model"))
.map(trimmed) .map(trimmed)
.context(ErrorKind::RemoveableDevicesQuery)?; .context(ErrorKind::StorageDevicesQuery)?;
if model == "CD-ROM" { if model == "CD-ROM" {
continue; continue;
@ -58,10 +60,10 @@ pub fn get_removable_devices() -> Result<Vec<Device>, Error> {
model, model,
vendor: fs::read_to_string(entry.path().join("device/vendor")) vendor: fs::read_to_string(entry.path().join("device/vendor"))
.map(trimmed) .map(trimmed)
.context(ErrorKind::RemoveableDevicesQuery)?, .context(ErrorKind::StorageDevicesQuery)?,
size: Byte::from_bytes( size: Byte::from_bytes(
fs::read_to_string(entry.path().join("size")) fs::read_to_string(entry.path().join("size"))
.context(ErrorKind::RemoveableDevicesQuery)? .context(ErrorKind::StorageDevicesQuery)?
.trim() .trim()
.parse::<u128>() .parse::<u128>()
.unwrap() .unwrap()

View File

@ -15,7 +15,7 @@ pub struct StorageDevice<'a> {
} }
impl<'a> StorageDevice<'a> { impl<'a> StorageDevice<'a> {
pub fn from_path(path: &'a Path) -> Result<Self, Error> { pub fn from_path(path: &'a Path, allow_non_removable: bool) -> Result<Self, Error> {
debug!("path: {:?}", path); debug!("path: {:?}", path);
let path = path.canonicalize().context(ErrorKind::DeviceQuery)?; let path = path.canonicalize().context(ErrorKind::DeviceQuery)?;
let device_name = path let device_name = path
@ -31,7 +31,7 @@ impl<'a> StorageDevice<'a> {
path, path,
origin: PhantomData, origin: PhantomData,
}; };
if !(_self.is_removable_device()? || _self.is_loop_device()) { if !allow_non_removable && (!(_self.is_removable_device()? || _self.is_loop_device())) {
return Err(ErrorKind::DangerousDevice)?; return Err(ErrorKind::DangerousDevice)?;
} }