diff --git a/src/stage1.rs b/src/stage1.rs index cbb1483..19c77a8 100644 --- a/src/stage1.rs +++ b/src/stage1.rs @@ -398,12 +398,7 @@ fn prepare(opts: &Options, mig_info: &mut MigrateInfo) -> Result<()> { let new_init_path = path_append(&takeover_dir, format!("/bin/{}", env!("CARGO_PKG_NAME"))); // Assets::write_stage2_script(&takeover_dir, &new_init_path, &tty, opts.get_s2_log_level())?; - let block_dev_info = if get_os_name()?.starts_with(BALENA_OS_NAME) { - // can't use default root dir due to overlayfs - BlockDeviceInfo::new_for_dir(BALENA_DATA_MP)? - } else { - BlockDeviceInfo::new()? - }; + let block_dev_info = get_block_dev_info()?; let flash_dev = if let Some(flash_dev) = opts.flash_to() { if let Some(flash_dev) = block_dev_info.get_devices().get(flash_dev) { @@ -431,41 +426,7 @@ fn prepare(opts: &Options, mig_info: &mut MigrateInfo) -> Result<()> { )); } - let log_device = if let Some(log_dev_path) = opts.log_to() { - if let Some(log_dev) = block_dev_info.get_devices().get(log_dev_path) { - if let Some(partition_info) = log_dev.get_partition_info() { - if let Some(fs_type) = partition_info.fs_type() { - const SUPPORTED_LOG_FS_TYPES: [&str; 3] = ["vfat", "ext3", "ext4"]; - if SUPPORTED_LOG_FS_TYPES.iter().any(|val| *val == fs_type) { - Some(LogDevice { - dev_name: log_dev_path.clone(), - fs_type: fs_type.to_owned(), - }) - } else { - warn!("The log device's ('{}') files system type '{}' is not in the list of supported file systems: {:?}. Your device will not be able to write stage2 logs", - log_dev_path.display(), - fs_type, - SUPPORTED_LOG_FS_TYPES); - None - } - } else { - warn!("We could not detect the filesystemm type for the log device '{}'. Your device will not be able to write stage2 logs", - log_dev_path.display()); - None - } - } else { - warn!("The log device '{}' is not a partition. Your device will not be able to write stage2 logs", - log_dev_path.display()); - None - } - } else { - warn!("The log device '{}' could not be found. Your device will not be able to write stage2 logs", - log_dev_path.display()); - None - } - } else { - None - }; + let log_device = get_log_device(opts, &block_dev_info); // collect partitions that need to be unmounted @@ -547,6 +508,73 @@ fn prepare(opts: &Options, mig_info: &mut MigrateInfo) -> Result<()> { Ok(()) } +/// Returns information about the block devices on the system. +fn get_block_dev_info() -> Result { + let block_dev_info = if get_os_name()?.starts_with(BALENA_OS_NAME) { + // can't use default root dir due to overlayfs + BlockDeviceInfo::new_for_dir(BALENA_DATA_MP)? + } else { + BlockDeviceInfo::new()? + }; + Ok(block_dev_info) +} + +/// Gets the log device to use for stage 2 logs. Returns `None` if the user +/// didn't request a log device, or if the requested log device is not usable. +/// If the log device is not usable, an error message is logged. +fn get_log_device(opts: &Options, block_dev_info: &BlockDeviceInfo) -> Option { + let log_dev_path = if let Some(path) = opts.log_to() { + path + } else { + info!("No stage 2 log device requested"); + return None; + }; + + let log_dev = if let Some(dev) = block_dev_info.get_devices().get(log_dev_path) { + dev + } else { + error!( + "The log device '{}' could not be found, so it can't be used for stage 2 logs", + log_dev_path.display() + ); + return None; + }; + + let partition_info = if let Some(partition_info) = log_dev.get_partition_info() { + partition_info + } else { + error!( + "The log device '{}' is not a partition, so it can't be used for stage 2 logs", + log_dev_path.display() + ); + return None; + }; + + let fs_type = if let Some(fs_type) = partition_info.fs_type() { + fs_type + } else { + error!( + "We could not detect the filesystem type for the log device '{}', so it can't be used for stage 2 logs", + log_dev_path.display() + ); + return None; + }; + + const SUPPORTED_LOG_FS_TYPES: [&str; 3] = ["vfat", "ext3", "ext4"]; + if !SUPPORTED_LOG_FS_TYPES.contains(&fs_type) { + error!("The log device's ('{}') files system type '{}' is not one of the supported file systems: {:?}. It can't be used for stage 2 logs", + log_dev_path.display(), + fs_type, + SUPPORTED_LOG_FS_TYPES); + return None; + } + + Some(LogDevice { + dev_name: log_dev_path.clone(), + fs_type: fs_type.to_owned(), + }) +} + pub fn stage1(opts: &Options) -> Result<()> { Logger::set_default_level(opts.log_level()); Logger::set_brief_info(true); diff --git a/src/stage1/checks.rs b/src/stage1/checks.rs index e07897e..6b336e5 100644 --- a/src/stage1/checks.rs +++ b/src/stage1/checks.rs @@ -1,15 +1,36 @@ use log::error; +use super::{block_device_info::BlockDeviceInfo, get_block_dev_info, get_log_device}; use crate::common::{is_admin, Error, Options, Result}; /// Performs checks to ensure that the program can run properly with the /// provided command-line options. Returns an error if the program cannot run /// for some reason. -pub(crate) fn do_early_checks(_opts: &Options) -> Result<()> { +pub(crate) fn do_early_checks(opts: &Options) -> Result<()> { if !is_admin()? { error!("please run this program as root"); return Err(Error::displayed()); } + let block_dev_info = get_block_dev_info()?; + + if !check_log_device(opts, &block_dev_info) { + error!("the requested log device is not suitable for writing stage2 logs"); + return Err(Error::displayed()); + } + Ok(()) } + +/// Checks if the log device requested with `--log-device` is suitable for +/// writing stage2 logs. +fn check_log_device(opts: &Options, block_dev_info: &BlockDeviceInfo) -> bool { + if opts.log_to().is_none() { + // No log device requested: that's fine! + return true; + }; + + // But if the user requested a log device, we must be able to get it. If we + // can't, *that* is a problem! + get_log_device(opts, block_dev_info).is_some() +}