// Copyright 2024 Google LLC //! The dump_modem binary is used to capture kernel/userspace logs in bugreport use std::fs; const MODEM_STAT: &str = "/data/vendor/modem_stat/debug.txt"; const SSRDUMP_DIR: &str = "/data/vendor/ssrdump"; const RFSD_ERR_LOG_DIR: &str = "/data/vendor/log/rfsd"; const WAKEUP_EVENTS: &str = "/sys/devices/platform/cpif/wakeup_events"; const CPIF_LOGBUFFER: &str = "/dev/logbuffer_cpif"; const PCIE_EVENT_STATS: &str = "/sys/devices/platform/cpif/modem/pcie_event_stats"; fn handle_io_error(file: &str, err: std::io::Error) { match err.kind() { std::io::ErrorKind::NotFound => println!("{file} not found!"), std::io::ErrorKind::PermissionDenied => println!("Permission denied to access {file}"), _ => println!("I/O error accessing {file}: {err}"), } } fn print_file(file: &str) -> Result<(), std::io::Error> { fs::metadata(file)?; let data = fs::read_to_string(file)?; if data.is_empty() { println!("{file} is empty"); } else { print!("{data}"); } Ok(()) } fn print_file_and_handle_error(file: &str) { if let Err(err) = print_file(file) { handle_io_error(file, err); } } fn print_matching_files_in_dir(dir: &str, filename: &str) { let Ok(entries) = fs::read_dir(dir) else { return println!("Cannot open directory {dir}"); }; for entry in entries { let Ok(entry) = entry else { continue; }; if entry.path().is_file() && entry.file_name().to_string_lossy().starts_with(filename) { if let Some(path_str) = entry.path().to_str() { println!("{}", path_str); print_file_and_handle_error(path_str); } } } } // Capture modem stat log if it exists fn modem_stat() { println!("------ Modem Stat ------"); print_file_and_handle_error(MODEM_STAT); println!(); } // Capture crash signatures from all modem crashes fn modem_ssr_history() { println!("------ Modem SSR history ------"); print_matching_files_in_dir(SSRDUMP_DIR, "crashinfo_modem"); println!(); } // Capture rfsd error logs from all existing log files fn rfsd_error_log() { println!("------ RFSD error log ------"); print_matching_files_in_dir(RFSD_ERR_LOG_DIR, "rfslog"); println!(); } // Capture modem wakeup events if the sysfs attribute exists fn wakeup_events() { println!("------ Wakeup event counts ------"); print_file_and_handle_error(WAKEUP_EVENTS); println!(); } // Capture kernel driver logbuffer if it exists fn cpif_logbuffer() { println!("------ CPIF Logbuffer ------"); print_file_and_handle_error(CPIF_LOGBUFFER); println!(); } // Capture modem pcie stats if the sysfs attribute exists fn pcie_event_stats() { println!("------ PCIe event stats ------"); print_file_and_handle_error(PCIE_EVENT_STATS); println!(); } fn main() { modem_stat(); modem_ssr_history(); rfsd_error_log(); wakeup_events(); cpif_logbuffer(); pcie_event_stats(); }