118 lines
3.7 kB
1
use anyhow::Result;
2
use rustyline::Editor;
3
use rustyline::error::ReadlineError;
4
5
use crate::process::Process;
6
use crate::scanner::{MemoryScanner, ScanValueType};
7
8
pub fn run_interactive_mode(process_name: &str) -> Result<()> {
9
println!(
10
"# Scanning for process \"{}\" like how pgrep -f works",
11
process_name
12
);
13
14
let process = Process::find_by_name(process_name)?;
15
let mut scanner = MemoryScanner::new(process)?;
16
17
println!("Please enter current value, or \"help\" for other commands.");
18
19
let mut rl = Editor::<(), rustyline::history::DefaultHistory>::new()?;
20
let mut first_scan = true;
21
22
loop {
23
let prompt = if first_scan {
24
"> ".to_string()
25
} else {
26
format!("{}> ", scanner.get_matches_count())
27
};
28
29
let readline = rl.readline(&prompt);
30
match readline {
31
Ok(line) => {
32
let _ = rl.add_history_entry(&line);
33
let line = line.trim();
34
35
if line.is_empty() {
36
continue;
37
}
38
39
if line == "help" {
40
print_help();
41
continue;
42
}
43
44
if line == "exit" || line == "quit" {
45
break;
46
}
47
48
if line.starts_with("set ") {
49
handle_set_command(&mut scanner, line)?;
50
continue;
51
}
52
match parse_value(line) {
53
Ok(value) => {
54
if first_scan {
55
match scanner.scan_for_value(value) {
56
Ok(_) => first_scan = false,
57
Err(e) => println!("Error scanning: {}", e),
58
}
59
} else {
60
match scanner.filter_matches(value) {
61
Ok(_) => {}
62
Err(e) => println!("Error filtering: {}", e),
63
}
64
}
65
}
66
Err(e) => println!("Invalid value: {}", e),
67
}
68
}
69
Err(ReadlineError::Interrupted) | Err(ReadlineError::Eof) => {
70
println!("Exiting...");
71
break;
72
}
73
Err(err) => {
74
println!("Error: {}", err);
75
break;
76
}
77
}
78
}
79
80
Ok(())
81
}
82
83
fn print_help() {
84
println!("Available commands:");
85
println!(" <value> - Search for value or narrow down existing results");
86
println!(" set <idx> <value> - Set value at the memory address at index <idx>");
87
println!(" help - Show this help message");
88
println!(" exit/quit - Exit the program");
89
}
90
91
fn handle_set_command(scanner: &mut MemoryScanner, command: &str) -> Result<()> {
92
let parts: Vec<&str> = command.split_whitespace().collect();
93
if parts.len() != 3 {
94
anyhow::bail!("Invalid set command format. Use: set <idx> <value>");
95
}
96
97
let idx = match parts[1].parse::<usize>() {
98
Ok(idx) => idx,
99
Err(_) => anyhow::bail!("Invalid index: {}", parts[1]),
100
};
101
102
let value = match parse_value(parts[2])? {
103
ScanValueType::I32(val) => val,
104
_ => anyhow::bail!("Only i32 values are currently supported for setting"),
105
};
106
107
scanner.set_value(idx, value)
108
}
109
110
fn parse_value(value_str: &str) -> Result<ScanValueType> {
111
if let Ok(val) = value_str.parse::<i32>() {
112
return Ok(ScanValueType::I32(val));
113
}
114
115
// TODO missing implementation for all the other types
116
117
anyhow::bail!("Could not parse '{}' as a valid number", value_str)
118
}
119