//! Internal system commands for advanced operations use crate::commands::Command; use apt_ostree::lib::error::{AptOstreeError, AptOstreeResult}; use apt_ostree::lib::ostree::OstreeManager; use apt_ostree::lib::apt::AptManager; use std::fs; use std::path::Path; use std::process::Command as ProcessCommand; use std::os::unix::fs::PermissionsExt; /// Internals command - Internal system commands for advanced operations pub struct InternalsCommand; impl InternalsCommand { pub fn new() -> Self { InternalsCommand } } #[cfg(feature = "development")] impl Command for InternalsCommand { fn execute(&self, args: &[String]) -> AptOstreeResult<()> { if args.is_empty() || args.contains(&"--help".to_string()) || args.contains(&"-h".to_string()) { self.show_help(); return Ok(()); } let subcommand = &args[0]; let sub_args = &args[1..]; match subcommand.as_str() { "diagnostics" => self.handle_diagnostics(sub_args), "validate-state" => self.handle_validate_state(sub_args), "debug-dump" => self.handle_debug_dump(sub_args), _ => { println!("Unknown internals subcommand: {}", subcommand); println!("Use 'apt-ostree internals --help' for available subcommands"); Ok(()) } } } fn name(&self) -> &'static str { "internals" } fn description(&self) -> &'static str { "Internal system commands for advanced operations" } fn show_help(&self) { println!("Usage: apt-ostree internals [OPTIONS]"); println!(); println!("Internal system commands for apt-ostree."); println!("These commands are for advanced system operations and diagnostics."); println!(); println!("Subcommands:"); println!(" diagnostics Internal system diagnostics"); println!(" validate-state System state validation"); println!(" debug-dump Debug information dump"); println!(); println!("Options:"); println!(" --help, -h Show this help message"); println!(); println!("Examples:"); println!(" apt-ostree internals diagnostics"); println!(" apt-ostree internals validate-state"); println!(" apt-ostree internals debug-dump"); } } impl InternalsCommand { fn handle_diagnostics(&self, _args: &[String]) -> AptOstreeResult<()> { println!("🔍 Running Internal Diagnostics"); println!("==============================="); // Check system components self.check_ostree_system()?; self.check_apt_system()?; self.check_daemon_status()?; self.check_file_permissions()?; println!("Diagnostics completed successfully"); Ok(()) } fn handle_validate_state(&self, _args: &[String]) -> AptOstreeResult<()> { println!("✅ Validating System State"); println!("==========================="); // Validate OSTree state let ostree_manager = OstreeManager::new(); if ostree_manager.is_available() { println!("OSTree: Available"); self.validate_ostree_state(&ostree_manager)?; } else { println!("OSTree: Not available"); } // Validate APT state let apt_manager = AptManager::new(); self.validate_apt_state(&apt_manager)?; println!("System state validation completed"); Ok(()) } fn handle_debug_dump(&self, _args: &[String]) -> AptOstreeResult<()> { println!("🐛 Debug Information Dump"); println!("========================="); // System information self.dump_system_info()?; // OSTree information self.dump_ostree_info()?; // APT information self.dump_apt_info()?; // Daemon information self.dump_daemon_info()?; println!("Debug information dump completed"); Ok(()) } fn check_ostree_system(&self) -> AptOstreeResult<()> { println!("Checking OSTree system..."); let ostree_manager = OstreeManager::new(); if ostree_manager.is_available() { println!(" ✓ OSTree is available"); if ostree_manager.is_ostree_booted() { println!(" ✓ System is booted from OSTree"); } else { println!(" ⚠ System is not booted from OSTree"); } } else { println!(" ❌ OSTree is not available"); } Ok(()) } fn check_apt_system(&self) -> AptOstreeResult<()> { println!("Checking APT system..."); let _apt_manager = AptManager::new(); // Check if apt-get is available if ProcessCommand::new("apt-get").arg("--version").output().is_ok() { println!(" ✓ apt-get is available"); } else { println!(" ❌ apt-get is not available"); } // Check APT cache directory let cache_dir = "/var/cache/apt"; if Path::new(cache_dir).exists() { println!(" ✓ APT cache directory exists: {}", cache_dir); } else { println!(" ❌ APT cache directory missing: {}", cache_dir); } Ok(()) } fn check_daemon_status(&self) -> AptOstreeResult<()> { println!("Checking daemon status..."); // Check if daemon service is running let output = ProcessCommand::new("systemctl") .arg("is-active") .arg("apt-ostreed") .output(); match output { Ok(output) => { let status = String::from_utf8_lossy(&output.stdout).trim().to_string(); if status == "active" { println!(" ✓ apt-ostreed service is active"); } else { println!(" ⚠ apt-ostreed service status: {}", status); } } Err(_) => { println!(" ❌ Could not check apt-ostreed service status"); } } Ok(()) } fn check_file_permissions(&self) -> AptOstreeResult<()> { println!("Checking file permissions..."); // Check key directories let dirs = [ ("/etc/apt", "APT configuration"), ("/var/lib/apt", "APT state"), ("/var/cache/apt", "APT cache"), ("/var/lib/ostree", "OSTree data"), ]; for (path, description) in &dirs { if Path::new(path).exists() { let metadata = fs::metadata(path) .map_err(|_| AptOstreeError::System(format!("Could not read metadata for {}", path)))?; let permissions = metadata.permissions(); let mode = permissions.mode(); println!(" ✓ {}: {:o}", description, mode & 0o777); } else { println!(" ❌ {}: directory does not exist", description); } } Ok(()) } fn validate_ostree_state(&self, ostree_manager: &OstreeManager) -> AptOstreeResult<()> { println!("Validating OSTree state..."); // Check deployments match ostree_manager.list_deployments() { Ok(deployments) => { println!(" ✓ Found {} deployments", deployments.len()); for deployment in &deployments { let status = if deployment.booted { "Booted" } else { "Available" }; println!(" - {}: {} ({})", deployment.id, status, deployment.commit); } } Err(e) => { println!(" ❌ Failed to list deployments: {}", e); } } // Check current deployment match ostree_manager.get_current_deployment() { Ok(Some(current)) => { println!(" ✓ Current deployment: {} ({})", current.id, current.commit); } Ok(None) => { println!(" ⚠ No current deployment found"); } Err(e) => { println!(" ❌ Failed to get current deployment: {}", e); } } Ok(()) } fn validate_apt_state(&self, _apt_manager: &AptManager) -> AptOstreeResult<()> { println!("Validating APT state..."); // Check APT sources let sources_list = "/etc/apt/sources.list"; if Path::new(sources_list).exists() { println!(" ✓ APT sources list exists"); } else { println!(" ⚠ APT sources list missing"); } // Check APT cache let cache_dir = "/var/cache/apt"; if Path::new(cache_dir).exists() { let entries = fs::read_dir(cache_dir) .map_err(|_| AptOstreeError::System("Could not read APT cache directory".to_string()))?; let count = entries.count(); println!(" ✓ APT cache contains {} entries", count); } Ok(()) } fn dump_system_info(&self) -> AptOstreeResult<()> { println!("System Information:"); println!("==================="); // OS information if let Ok(os_release) = fs::read_to_string("/etc/os-release") { for line in os_release.lines() { if line.starts_with("PRETTY_NAME=") || line.starts_with("VERSION=") { println!(" {}", line); } } } // Architecture if let Ok(output) = ProcessCommand::new("uname").arg("-m").output() { let arch = String::from_utf8_lossy(&output.stdout).trim().to_string(); println!(" Architecture: {}", arch); } // Kernel version if let Ok(output) = ProcessCommand::new("uname").arg("-r").output() { let kernel = String::from_utf8_lossy(&output.stdout).trim().to_string(); println!(" Kernel: {}", kernel); } Ok(()) } fn dump_ostree_info(&self) -> AptOstreeResult<()> { println!("OSTree Information:"); println!("==================="); let ostree_manager = OstreeManager::new(); if ostree_manager.is_available() { let system_info = ostree_manager.get_system_info(); println!(" OS: {}", system_info.os); println!(" Kernel: {}", system_info.kernel); println!(" Architecture: {}", system_info.architecture); match ostree_manager.get_repo_info() { Ok(repo_info) => { println!(" Repository: {}", repo_info.path); println!(" Available refs: {}", repo_info.refs.len()); } Err(e) => { println!(" ❌ Failed to get repo info: {}", e); } } } else { println!(" OSTree not available"); } Ok(()) } fn dump_apt_info(&self) -> AptOstreeResult<()> { println!("APT Information:"); println!("================"); // APT version if let Ok(output) = ProcessCommand::new("apt-get").arg("--version").output() { let version = String::from_utf8_lossy(&output.stdout).lines().next().unwrap_or("Unknown").to_string(); println!(" Version: {}", version); } // APT configuration let config_dirs = ["/etc/apt/apt.conf.d", "/etc/apt/sources.list.d"]; for dir in &config_dirs { if Path::new(dir).exists() { if let Ok(entries) = fs::read_dir(dir) { let count = entries.count(); println!(" Config files in {}: {}", dir, count); } } } Ok(()) } fn dump_daemon_info(&self) -> AptOstreeResult<()> { println!("Daemon Information:"); println!("==================="); // Service status if let Ok(output) = ProcessCommand::new("systemctl").arg("show").arg("apt-ostreed").arg("--property=ActiveState").output() { let status = String::from_utf8_lossy(&output.stdout).lines().next().unwrap_or("Unknown").to_string(); println!(" Service status: {}", status); } // Process information if let Ok(output) = ProcessCommand::new("pgrep").arg("-f").arg("apt-ostreed").output() { let pids: Vec = String::from_utf8_lossy(&output.stdout).lines().map(|s| s.to_string()).collect(); if !pids.is_empty() { println!(" Running processes: {}", pids.join(", ")); } else { println!(" No running processes found"); } } Ok(()) } }