1 // Copyright 2024 Google LLC
2 
3 //! The dump_modem binary is used to capture kernel/userspace logs in bugreport
4 
5 use std::fs;
6 
7 const MODEM_STAT: &str = "/data/vendor/modem_stat/debug.txt";
8 const SSRDUMP_DIR: &str = "/data/vendor/ssrdump";
9 const RFSD_ERR_LOG_DIR: &str = "/data/vendor/log/rfsd";
10 const WAKEUP_EVENTS: &str = "/sys/devices/platform/cpif/wakeup_events";
11 const CPIF_LOGBUFFER: &str = "/dev/logbuffer_cpif";
12 const PCIE_EVENT_STATS: &str = "/sys/devices/platform/cpif/modem/pcie_event_stats";
13 
handle_io_error(file: &str, err: std::io::Error)14 fn handle_io_error(file: &str, err: std::io::Error) {
15     match err.kind() {
16         std::io::ErrorKind::NotFound => println!("{file} not found!"),
17         std::io::ErrorKind::PermissionDenied => println!("Permission denied to access {file}"),
18         _ => println!("I/O error accessing {file}: {err}"),
19     }
20 }
21 
print_file(file: &str) -> Result<(), std::io::Error>22 fn print_file(file: &str) -> Result<(), std::io::Error> {
23     fs::metadata(file)?;
24 
25     let data = fs::read_to_string(file)?;
26 
27     if data.is_empty() {
28         println!("{file} is empty");
29     } else {
30         print!("{data}");
31     }
32 
33     Ok(())
34 }
35 
print_file_and_handle_error(file: &str)36 fn print_file_and_handle_error(file: &str) {
37     if let Err(err) = print_file(file) {
38         handle_io_error(file, err);
39     }
40 }
41 
print_matching_files_in_dir(dir: &str, filename: &str)42 fn print_matching_files_in_dir(dir: &str, filename: &str) {
43     let Ok(entries) = fs::read_dir(dir) else {
44         return println!("Cannot open directory {dir}");
45     };
46 
47     for entry in entries {
48         let Ok(entry) = entry else {
49             continue;
50         };
51         if entry.path().is_file() && entry.file_name().to_string_lossy().starts_with(filename) {
52             if let Some(path_str) = entry.path().to_str() {
53                 println!("{}", path_str);
54                 print_file_and_handle_error(path_str);
55             }
56         }
57     }
58 }
59 
60 // Capture modem stat log if it exists
modem_stat()61 fn modem_stat() {
62     println!("------ Modem Stat ------");
63     print_file_and_handle_error(MODEM_STAT);
64     println!();
65 }
66 
67 // Capture crash signatures from all modem crashes
modem_ssr_history()68 fn modem_ssr_history() {
69     println!("------ Modem SSR history ------");
70     print_matching_files_in_dir(SSRDUMP_DIR, "crashinfo_modem");
71     println!();
72 }
73 
74 // Capture rfsd error logs from all existing log files
rfsd_error_log()75 fn rfsd_error_log() {
76     println!("------ RFSD error log ------");
77     print_matching_files_in_dir(RFSD_ERR_LOG_DIR, "rfslog");
78     println!();
79 }
80 
81 // Capture modem wakeup events if the sysfs attribute exists
wakeup_events()82 fn wakeup_events() {
83     println!("------ Wakeup event counts ------");
84     print_file_and_handle_error(WAKEUP_EVENTS);
85     println!();
86 }
87 
88 // Capture kernel driver logbuffer if it exists
cpif_logbuffer()89 fn cpif_logbuffer() {
90     println!("------ CPIF Logbuffer ------");
91     print_file_and_handle_error(CPIF_LOGBUFFER);
92     println!();
93 }
94 
95 // Capture modem pcie stats if the sysfs attribute exists
pcie_event_stats()96 fn pcie_event_stats() {
97     println!("------ PCIe event stats ------");
98     print_file_and_handle_error(PCIE_EVENT_STATS);
99     println!();
100 }
101 
main()102 fn main() {
103     modem_stat();
104     modem_ssr_history();
105     rfsd_error_log();
106     wakeup_events();
107     cpif_logbuffer();
108     pcie_event_stats();
109 }
110