use crate::unmount::*;
use colored::Colorize;
use log::error;
use std::fmt::Display;
use std::{env, io::ErrorKind, process};
#[repr(i32)]
pub enum ExitCode {
FileError = 1,
_ArgumentError = 2,
ConfigError = 3,
MountError = 4,
NonRoot = 5,
OOMError = 6,
ParseError = 7,
UnmountError = 8,
SectorSizeError = 9,
UnknownError = 10,
}
pub enum FileType {
MapFile,
ImageFile,
}
pub enum Token {
Pos,
Size,
CurrentPos,
}
impl ToString for Token {
fn to_string(&self) -> String {
match self {
Token::Pos => "position".to_string(),
Token::Size => "size".to_string(),
Token::CurrentPos => "current position".to_string(),
}
}
}
impl FileType {
pub fn to_string(&self) -> &str {
match self {
FileType::MapFile => "map file",
FileType::ImageFile => "image file",
}
}
}
pub const SET_CONFIG_ERROR: &str = "Unable to open or set configuration";
pub const READ_CONFIG_ERROR: &str = "Unable to read configuration";
pub const OOM_ERROR: &str = "Out of memory error!";
pub const MOUNT_ERROR: &str = "Unable to mount image";
pub const NO_DEVICE_UNMOUNT_ERROR: &str = "Unmount error: Unable to find device";
pub const UNMOUNT_ERROR: &str = "Unable to unmount device";
pub const FILE_NOT_FOUND_ERROR: &str = "Unable to find";
pub const SECTOR_SIZE_ERROR: &str = "Sector size is not a multiple of 512";
pub const CONTIGUOUS_ERROR: &str = "Position {pos} does not match size of previous line {size}\n\
Disk map is not contiguous or is overlapping";
pub const POSITION_SECTOR_ERROR: &str = "Position does not match sector size";
pub const SIZE_SECTOR_ERROR: &str = "Size does not match sector size";
pub const UNKNOWN_MAP_STATUS_ERROR: &str = "Unknown status character";
pub const NO_POSITION_ERROR: &str = "No position found";
pub const NO_SIZE_ERROR: &str = "No size found";
pub const NO_STATUS_ERROR: &str = "No status found";
pub const CONVERT_ERROR: &str = "Could not convert {entry} to decimal";
pub const START_NONZERO_ERROR: &str = "Disk map does not begin from 0";
pub const PARSE_ERROR: &str = "Unable to parse ddrescue map file";
pub const EMPTY_MAP_ERROR: &str = "Map file is empty";
pub const NO_CURRENT_POSITION_ERROR: &str = "Current position in status line is missing";
pub const NO_CURRENT_STATUS_ERROR: &str = "Current status is missing from the status line";
pub const UNKNOWN_CURRENT_STATUS_ERROR: &str = "Invalid status in status line";
pub const UNKNOWN_CURRRENT_PHASE_ERROR: &str = "Invalid phase in status line";
pub const CURRENT_PHASE_LESS_THAN_ONE_ERROR: &str =
"Invalid phase in status line: phase must be 1 or greater";
pub fn file_not_found(filetype: FileType) -> String {
format!("{FILE_NOT_FOUND_ERROR} {}", filetype.to_string())
}
pub fn convert_error_string(token: Token) -> String {
CONVERT_ERROR.replace("{entry}", &token.to_string())
}
pub fn parse_error(print: bool) -> ! {
if print {
print_error(PARSE_ERROR)
};
process::exit(ExitCode::ParseError as i32);
}
pub fn sector_error() -> ! {
print_error(SECTOR_SIZE_ERROR);
process::exit(ExitCode::SectorSizeError as i32);
}
pub fn print_error(error: impl Display) {
let error_string = format!("{error}");
eprintln!("{}", error_string.red().bold());
}
pub fn set_config_error() -> ! {
print_error(SET_CONFIG_ERROR);
process::exit(ExitCode::ConfigError as i32);
}
pub fn handle_string_write(result: Result<(), std::fmt::Error>) {
if result.is_err() {
print_error(OOM_ERROR);
process::exit(ExitCode::OOMError as i32);
}
}
pub fn read_config_error() -> ! {
print_error(READ_CONFIG_ERROR);
process::exit(ExitCode::ConfigError as i32);
}
pub fn root_error() {
let env_vars = env::vars().find(|n| n.0 == "USER");
if let Some((_, user)) = env_vars {
error!("User running as {user}, rather than root");
let arguments = env::args().reduce(|a, b| format!("{a} {b}")).unwrap();
print_error(format!("You must run as root.\nTry sudo {arguments}"));
process::exit(ExitCode::NonRoot as i32);
}
}
pub fn check_io_error(error: std::io::Error, filename: String, filetype: FileType) -> ! {
match error.kind() {
ErrorKind::NotFound => {
print_error(format!("{} {}", file_not_found(filetype), filename));
process::exit(ExitCode::FileError as i32);
}
error => {
print_error(format!("Unknown error while reading {filename} {}", error));
process::exit(ExitCode::UnknownError as i32);
}
}
}
pub fn mount_error() -> ! {
print_error(MOUNT_ERROR);
process::exit(ExitCode::MountError as i32);
}
pub fn no_unmount_device(device: String) -> ! {
print_error(format!("{NO_DEVICE_UNMOUNT_ERROR} {device}"));
process::exit(ExitCode::UnmountError as i32);
}
pub fn unmount_error() -> ! {
print_error(UNMOUNT_ERROR);
process::exit(ExitCode::UnmountError as i32);
}
pub fn mount_error_clean(device: &str) -> ! {
let _ = crate::unmount::unmount_image(device.to_string(), ImageError::HideError);
mount_error();
}