Add boot diag tasks
This commit is contained in:
parent
f272b0c482
commit
2b2a5160fd
3 changed files with 219 additions and 31 deletions
|
|
@ -13,7 +13,7 @@
|
|||
// You should have received a copy of the GNU General Public License
|
||||
// along with Deja-Vu. If not, see <https://www.gnu.org/licenses/>.
|
||||
//
|
||||
use crate::diags::Groups as DiagGroups;
|
||||
use crate::diags;
|
||||
use core::{
|
||||
action::Action,
|
||||
components::{
|
||||
|
|
@ -26,6 +26,7 @@ use core::{
|
|||
system::{
|
||||
boot::{self, SafeMode},
|
||||
cpu::get_cpu_name,
|
||||
disk::PartitionTableType,
|
||||
drivers,
|
||||
},
|
||||
tasks::{Task, TaskResult, TaskType, Tasks},
|
||||
|
|
@ -34,6 +35,7 @@ use core::{
|
|||
use std::{
|
||||
env,
|
||||
iter::zip,
|
||||
path::PathBuf,
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
|
||||
|
|
@ -53,7 +55,7 @@ pub struct App {
|
|||
action_tx: mpsc::UnboundedSender<Action>,
|
||||
components: Vec<Box<dyn Component>>,
|
||||
config: Config,
|
||||
diag_groups: DiagGroups,
|
||||
diag_groups: diags::Groups,
|
||||
frame_rate: f64,
|
||||
last_tick_key_events: Vec<KeyEvent>,
|
||||
should_quit: bool,
|
||||
|
|
@ -94,7 +96,7 @@ impl App {
|
|||
Box::new(popup::Popup::new()),
|
||||
],
|
||||
config: Config::new()?,
|
||||
diag_groups: DiagGroups::new(),
|
||||
diag_groups: diags::Groups::new(),
|
||||
frame_rate,
|
||||
last_tick_key_events: Vec::new(),
|
||||
should_quit: false,
|
||||
|
|
@ -180,13 +182,126 @@ impl App {
|
|||
self.list.select_first_item();
|
||||
}
|
||||
Mode::BootScan => {
|
||||
if self.tasks.idle() {
|
||||
self.tasks.add(TaskType::Sleep);
|
||||
}
|
||||
self.action_tx.send(Action::DisplayPopup(
|
||||
popup::Type::Info,
|
||||
String::from("Gathering info..."),
|
||||
))?;
|
||||
|
||||
// Get System32 path
|
||||
let system32 = if cfg!(windows) {
|
||||
if let Ok(path) = env::var("SYSTEMROOT") {
|
||||
format!("{path}/System32")
|
||||
} else {
|
||||
self.action_tx.send(Action::Error(String::from(
|
||||
"ERROR\n\n\nFailed to find SYSTEMROOT",
|
||||
)))?;
|
||||
return Ok(());
|
||||
}
|
||||
} else {
|
||||
String::from(".")
|
||||
};
|
||||
|
||||
// Add tasks
|
||||
let disk_list = self.clone.disk_list.lock().unwrap();
|
||||
if let Some(disk_index) = self.clone.disk_index_dest {
|
||||
if let Some(disk) = disk_list.get(disk_index) {
|
||||
let table_type = disk.part_type.clone();
|
||||
let letter_boot = disk.get_part_letter(self.clone.part_index_boot.unwrap());
|
||||
let letter_os = disk.get_part_letter(self.clone.part_index_os.unwrap());
|
||||
|
||||
// Safety check
|
||||
if letter_boot.is_empty() || letter_os.is_empty() {
|
||||
self.action_tx.send(Action::Error(String::from(
|
||||
"ERROR\n\n\nFailed to get drive letters for the destination",
|
||||
)))?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// BCD
|
||||
self.tasks.add(TaskType::Command(
|
||||
PathBuf::from(format!("{system32}/bcdedit.exe")),
|
||||
vec![
|
||||
String::from("/store"),
|
||||
format!(
|
||||
"{letter_boot}{}\\Boot\\BCD",
|
||||
if table_type == PartitionTableType::Guid {
|
||||
"\\EFI\\Microsoft"
|
||||
} else {
|
||||
""
|
||||
}
|
||||
),
|
||||
String::from("/enum"),
|
||||
],
|
||||
));
|
||||
|
||||
// Bitlocker
|
||||
self.tasks.add(TaskType::Command(
|
||||
PathBuf::from(format!("{system32}/manage-bde.exe")),
|
||||
vec![String::from("-status"), format!("{letter_os}:")],
|
||||
));
|
||||
self.tasks.add(TaskType::Command(
|
||||
PathBuf::from(format!("{system32}/manage-bde.exe")),
|
||||
vec![
|
||||
String::from("-protectors"),
|
||||
String::from("-get"),
|
||||
format!("{letter_os}:"),
|
||||
],
|
||||
));
|
||||
|
||||
// DISM Health
|
||||
self.tasks.add(TaskType::Command(
|
||||
PathBuf::from(format!("{system32}/dism.exe")),
|
||||
vec![format!("{letter_os}:")],
|
||||
));
|
||||
|
||||
// Filesystem Health
|
||||
self.tasks.add(TaskType::Command(
|
||||
PathBuf::from(format!("{system32}/chkdsk.exe")),
|
||||
vec![format!("{letter_os}:")],
|
||||
));
|
||||
|
||||
// Registry
|
||||
self.tasks.add(TaskType::Command(
|
||||
PathBuf::from(format!("{system32}/reg.exe")),
|
||||
vec![
|
||||
String::from("load"),
|
||||
String::from("HKLM\\TmpSoftware"),
|
||||
format!("{letter_os}:\\Windows\\System32\\config\\SOFTWARE"),
|
||||
],
|
||||
));
|
||||
self.tasks.add(TaskType::Command(
|
||||
PathBuf::from(format!("{system32}/reg.exe")),
|
||||
vec![
|
||||
String::from("load"),
|
||||
String::from("HKLM\\TmpSystem"),
|
||||
format!("{letter_os}:\\Windows\\System32\\config\\SYSTEM"),
|
||||
],
|
||||
));
|
||||
self.tasks.add(TaskType::Command(
|
||||
PathBuf::from(format!("{system32}/reg.exe")),
|
||||
vec![
|
||||
String::from("load"),
|
||||
String::from("HKU\\TmpDefault"),
|
||||
format!("{letter_os}:\\Windows\\System32\\config\\DEFAULT"),
|
||||
],
|
||||
));
|
||||
self.tasks.add(TaskType::Command(
|
||||
PathBuf::from(format!("{system32}/reg.exe")),
|
||||
vec![String::from("unload"), String::from("HKLM\\TmpSoftware")],
|
||||
));
|
||||
self.tasks.add(TaskType::Command(
|
||||
PathBuf::from(format!("{system32}/reg.exe")),
|
||||
vec![String::from("unload"), String::from("HKLM\\TmpSystem")],
|
||||
));
|
||||
self.tasks.add(TaskType::Command(
|
||||
PathBuf::from(format!("{system32}/reg.exe")),
|
||||
vec![String::from("unload"), String::from("HKU\\TmpDefault")],
|
||||
));
|
||||
|
||||
// Files/Folders
|
||||
// TODO: Check for critical folders (e.g. /Windows, /Windows/System32, etc)
|
||||
}
|
||||
}
|
||||
}
|
||||
Mode::InjectDrivers | Mode::InstallDrivers => self.clone.scan_drivers(),
|
||||
Mode::ScanDisks => {
|
||||
|
|
@ -414,8 +529,9 @@ impl App {
|
|||
}
|
||||
|
||||
fn handle_task(&mut self, task: &Task) -> Result<()> {
|
||||
info!("Handling Task: {task:?}");
|
||||
match self.cur_mode {
|
||||
Mode::BootDiags => {
|
||||
Mode::BootScan => {
|
||||
if let TaskType::Command(cmd_path, cmd_args) = &task.task_type {
|
||||
let mut cmd_name = "";
|
||||
if let Some(path) = cmd_path.file_name() {
|
||||
|
|
@ -423,9 +539,9 @@ impl App {
|
|||
cmd_name = cmd_str;
|
||||
}
|
||||
};
|
||||
match cmd_name {
|
||||
"bcdedit" => {
|
||||
// Boot config
|
||||
let diag_type = diags::get_type(cmd_name);
|
||||
match diag_type {
|
||||
diags::Type::BootConfigData => {
|
||||
let title = "Boot Files";
|
||||
if let Some(result) = &task.result {
|
||||
let passed: bool;
|
||||
|
|
@ -449,18 +565,10 @@ impl App {
|
|||
.update(title.to_string(), passed, info.to_owned());
|
||||
}
|
||||
}
|
||||
"manage-bde" => {
|
||||
// Bitlocker
|
||||
}
|
||||
"chkdsk" => {
|
||||
// File system
|
||||
}
|
||||
"reg" => {
|
||||
// Registry
|
||||
}
|
||||
"dir" => {
|
||||
// Files/Folders
|
||||
}
|
||||
diags::Type::Bitlocker => {}
|
||||
diags::Type::FileSystem => {}
|
||||
diags::Type::Registry => {}
|
||||
diags::Type::FilesAndFolders => {}
|
||||
_ => {
|
||||
warn!("Unrecognized command: {:?}", &cmd_path)
|
||||
}
|
||||
|
|
@ -660,7 +768,19 @@ fn build_left_items(app: &App) -> Action {
|
|||
}
|
||||
}
|
||||
}
|
||||
Mode::BootDiags | Mode::BootSetup => {
|
||||
Mode::BootDiags => {
|
||||
select_num = 0;
|
||||
let (new_title, _) = get_mode_strings(app.cur_mode);
|
||||
title = new_title;
|
||||
app.diag_groups.get().iter().for_each(|group| {
|
||||
items.push(if group.passed {
|
||||
group.title.clone()
|
||||
} else {
|
||||
format!("{} - Issues detected!", group.title)
|
||||
});
|
||||
});
|
||||
}
|
||||
Mode::BootSetup => {
|
||||
select_num = 0;
|
||||
let (new_title, _) = get_mode_strings(app.cur_mode);
|
||||
title = new_title;
|
||||
|
|
@ -715,6 +835,14 @@ fn build_right_items(app: &App) -> Action {
|
|||
)],
|
||||
line_colors: vec![Color::Reset],
|
||||
},
|
||||
DVLine {
|
||||
line_parts: vec![String::from("-----")],
|
||||
line_colors: vec![Color::Reset],
|
||||
},
|
||||
DVLine {
|
||||
line_parts: vec![format!("diag_groups: {:?}", &app.diag_groups)],
|
||||
line_colors: vec![Color::Yellow],
|
||||
},
|
||||
DVLine {
|
||||
line_parts: vec![String::from("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")],
|
||||
line_colors: vec![Color::Reset],
|
||||
|
|
@ -774,6 +902,20 @@ fn build_right_items(app: &App) -> Action {
|
|||
]);
|
||||
});
|
||||
}
|
||||
Mode::BootDiags => {
|
||||
app.diag_groups.get().iter().for_each(|group| {
|
||||
let mut lines = Vec::new();
|
||||
group.info.iter().for_each(|text| {
|
||||
text.lines().for_each(|line| {
|
||||
lines.push(DVLine {
|
||||
line_parts: vec![String::from(line)],
|
||||
line_colors: vec![Color::Reset],
|
||||
});
|
||||
});
|
||||
});
|
||||
items.push(lines);
|
||||
});
|
||||
}
|
||||
Mode::InjectDrivers | Mode::InstallDrivers => {
|
||||
items.push(vec![DVLine {
|
||||
line_parts: vec![String::from("CPU")],
|
||||
|
|
|
|||
|
|
@ -15,21 +15,44 @@
|
|||
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub enum Type {
|
||||
Bitlocker,
|
||||
BootConfigData,
|
||||
FileSystem,
|
||||
FilesAndFolders,
|
||||
Registry,
|
||||
Unknown,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Groups {
|
||||
items: HashMap<String, Line>,
|
||||
order: Vec<String>,
|
||||
}
|
||||
|
||||
impl Groups {
|
||||
pub fn new() -> Self {
|
||||
Groups {
|
||||
items: HashMap::new(),
|
||||
order: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get(&self) -> Vec<&Line> {
|
||||
let mut lines = Vec::new();
|
||||
self.order.iter().for_each(|key| {
|
||||
if let Some(line) = self.items.get(key) {
|
||||
lines.push(line);
|
||||
}
|
||||
});
|
||||
lines
|
||||
}
|
||||
|
||||
pub fn update(&mut self, title: String, passed: bool, info: String) {
|
||||
if let Some(line) = self.items.get_mut(&title) {
|
||||
line.update(passed, info);
|
||||
} else {
|
||||
self.order.push(title.clone());
|
||||
self.items.insert(
|
||||
title.clone(),
|
||||
Line {
|
||||
|
|
@ -42,10 +65,11 @@ impl Groups {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Line {
|
||||
title: String,
|
||||
passed: bool,
|
||||
info: Vec<String>,
|
||||
pub title: String,
|
||||
pub passed: bool,
|
||||
pub info: Vec<String>,
|
||||
}
|
||||
|
||||
impl Line {
|
||||
|
|
@ -54,3 +78,25 @@ impl Line {
|
|||
self.info.push(info);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_type(cmd_name: &str) -> Type {
|
||||
if cmd_name == "exa" {
|
||||
return Type::BootConfigData;
|
||||
}
|
||||
if cmd_name == "bcdedit" {
|
||||
return Type::BootConfigData;
|
||||
}
|
||||
if cmd_name == "dir" {
|
||||
return Type::FilesAndFolders;
|
||||
}
|
||||
if cmd_name == "reg" {
|
||||
return Type::Registry;
|
||||
}
|
||||
if cmd_name == "chkdsk" {
|
||||
return Type::FileSystem;
|
||||
}
|
||||
if cmd_name == "manage-bde" {
|
||||
return Type::Bitlocker;
|
||||
}
|
||||
Type::Unknown
|
||||
}
|
||||
|
|
|
|||
|
|
@ -173,6 +173,11 @@ impl App {
|
|||
))?;
|
||||
}
|
||||
Mode::PreClone => {
|
||||
self.action_tx.send(Action::DisplayPopup(
|
||||
popup::Type::Info,
|
||||
String::from("Formatting destination disk"),
|
||||
))?;
|
||||
|
||||
// Get System32 path
|
||||
let system32 = if cfg!(windows) {
|
||||
if let Ok(path) = env::var("SYSTEMROOT") {
|
||||
|
|
@ -187,11 +192,6 @@ impl App {
|
|||
String::from(".")
|
||||
};
|
||||
|
||||
self.action_tx.send(Action::DisplayPopup(
|
||||
popup::Type::Info,
|
||||
String::from("Formatting destination disk"),
|
||||
))?;
|
||||
|
||||
// (Re)Enable volume mounting
|
||||
self.tasks.add(TaskType::Command(
|
||||
PathBuf::from(format!("{system32}/mountvol.exe")),
|
||||
|
|
|
|||
Loading…
Reference in a new issue