1 /*
2 * Copyright (C) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 use super::translate;
16
17 use hdc::config::{self, HdcCommand};
18
19 use std::collections::HashMap;
20 use std::io::{self, Error, ErrorKind};
21 use std::str::FromStr;
22
23 #[derive(Default, Debug, Clone)]
24 pub struct Parsed {
25 pub options: Vec<String>,
26 pub command: Option<HdcCommand>,
27 pub parameters: Vec<String>,
28 }
29
30 lazy_static! {
31 static ref CMD_MAP: HashMap<&'static str, HdcCommand> = {
32 let mut map = HashMap::new();
33
34 map.insert("version", HdcCommand::ClientVersion);
35 map.insert("help", HdcCommand::KernelHelp);
36 map.insert("discover", HdcCommand::KernelTargetDiscover);
37 map.insert("start", HdcCommand::KernelServerStart);
38 map.insert("kill", HdcCommand::KernelServerKill);
39 map.insert("keygen", HdcCommand::ClientKeyGenerate);
40 map.insert("list targets", HdcCommand::KernelTargetList);
41 map.insert("checkserver", HdcCommand::KernelCheckServer);
42 map.insert("checkdevice", HdcCommand::KernelCheckDevice);
43 map.insert("wait", HdcCommand::KernelWaitFor);
44 map.insert("tconn", HdcCommand::KernelTargetConnect);
45 map.insert("any", HdcCommand::KernelTargetAny);
46 map.insert("shell", HdcCommand::UnityExecute);
47 map.insert("target boot", HdcCommand::UnityReboot);
48 map.insert("target mount", HdcCommand::UnityRemount);
49 map.insert("smode", HdcCommand::UnityRootrun);
50 map.insert("tmode", HdcCommand::UnityRunmode);
51 map.insert("bugreport", HdcCommand::UnityBugreportInit);
52 map.insert("hilog", HdcCommand::UnityHilog);
53 map.insert("file send", HdcCommand::FileInit);
54 map.insert("file recv", HdcCommand::FileInit);
55 map.insert("fport", HdcCommand::ForwardInit);
56 map.insert("rport", HdcCommand::ForwardInit);
57 map.insert("fport ls", HdcCommand::ForwardList);
58 map.insert("fport rm", HdcCommand::ForwardRemove);
59 map.insert("install", HdcCommand::AppInit);
60 map.insert("uninstall", HdcCommand::AppUninstall);
61 map.insert("sideload", HdcCommand::AppSideload);
62 map.insert("jpid", HdcCommand::JdwpList);
63 map.insert("track-jpid", HdcCommand::JdwpTrack);
64 map.insert("alive", HdcCommand::KernelEnableKeepalive);
65 map.insert("update", HdcCommand::FlashdUpdateInit);
66 map.insert("flash", HdcCommand::FlashdFlashInit);
67 map.insert("erase", HdcCommand::FlashdErase);
68 map.insert("format", HdcCommand::FlashdFormat);
69
70 map
71 };
72 }
73
74 const MAX_CMD_LEN: usize = 3;
75
76 // TODO: trial tree
split_opt_and_cmd(input: Vec<String>) -> Parsed77 pub fn split_opt_and_cmd(input: Vec<String>) -> Parsed {
78 let mut cmd_opt: Option<HdcCommand> = None;
79 let mut cmd_index = input.len();
80 for len in 1..MAX_CMD_LEN {
81 for st in 0..input.len() {
82 if st + len > input.len() {
83 break;
84 }
85 let cmd = input[st..st + len].join(" ");
86 if let Some(command) = CMD_MAP.get(cmd.as_str()) {
87 cmd_index = st;
88 cmd_opt = Some(command.to_owned());
89 break;
90 }
91 }
92 if cmd_opt != None {
93 break;
94 }
95 }
96 Parsed {
97 options: input[..cmd_index].to_vec(),
98 command: cmd_opt,
99 parameters: input[cmd_index..].to_vec(),
100 }
101 }
102
parse_command(args: std::env::Args) -> io::Result<ParsedCommand>103 pub fn parse_command(args: std::env::Args) -> io::Result<ParsedCommand> {
104 let input = args.collect::<Vec<_>>()[1..].to_vec();
105 let parsed = split_opt_and_cmd(input);
106 match extract_global_params(parsed.options) {
107 Ok(parsed_cmd) => {
108 return Ok(ParsedCommand {
109 command: parsed.command,
110 parameters: parsed.parameters,
111 ..parsed_cmd
112 })
113 }
114 Err(e) => return Err(e),
115 };
116 }
117
118 #[derive(Default, Debug, PartialEq)]
119 pub struct ParsedCommand {
120 pub run_in_server: bool,
121 pub launch_server: bool,
122 pub spawned_server: bool,
123 pub connect_key: String,
124 pub log_level: usize,
125 pub server_addr: String,
126 pub command: Option<HdcCommand>,
127 pub parameters: Vec<String>,
128 }
129
extract_global_params(opts: Vec<String>) -> io::Result<ParsedCommand>130 pub fn extract_global_params(opts: Vec<String>) -> io::Result<ParsedCommand> {
131 let mut parsed_command = ParsedCommand {
132 launch_server: true,
133 log_level: 3,
134 server_addr: format!("0.0.0.0:{}", config::SERVER_DEFAULT_PORT),
135 ..Default::default()
136 };
137 let len = opts.len();
138 for i in 0..len {
139 let opt = opts[i].as_str();
140 let arg = if opt.len() > 2 {
141 &opt[2..]
142 } else if i < len - 1 {
143 opts[i + 1].as_str()
144 } else {
145 ""
146 };
147 if opt.starts_with("-h") {
148 if arg == "verbose" {
149 return Err(utils::error_other(translate::verbose()));
150 } else {
151 return Err(utils::error_other(translate::usage()));
152 }
153 } else if opt.starts_with("-v") {
154 return Err(utils::error_other(config::get_version()));
155 } else if opt.starts_with("-l") {
156 if let Ok(level) = arg.parse::<usize>() {
157 if level < config::LOG_LEVEL_ORDER.len() {
158 parsed_command.log_level = level;
159 } else {
160 return Err(utils::error_other(format!(
161 "-l content loglevel incorrect\n\n{}",
162 translate::usage()
163 )));
164 }
165 } else {
166 return Err(utils::error_other(format!(
167 "-l content loglevel incorrect\n\n{}",
168 translate::usage()
169 )));
170 }
171 } else if opt.starts_with("-m") {
172 parsed_command.run_in_server = true;
173 } else if opt.starts_with("-p") {
174 parsed_command.launch_server = false;
175 } else if opt.starts_with("-t") {
176 parsed_command.connect_key = arg.to_string();
177 } else if opt.starts_with("-s") {
178 match parse_server_listen_string(arg.to_string()) {
179 Ok(server_addr) => parsed_command.server_addr = server_addr,
180 Err(e) => {
181 return Err(utils::error_other(format!(
182 "{}\n\n{}",
183 e.to_string(),
184 translate::usage()
185 )));
186 }
187 }
188 } else if opt.starts_with("-b") {
189 // server spawned by client, no stdout
190 parsed_command.spawned_server = true;
191 }
192 }
193 Ok(parsed_command)
194 }
195
check_port(port_str: String) -> io::Result<u16>196 fn check_port(port_str: String) -> io::Result<u16> {
197 if let Ok(port) = port_str.parse::<u16>() {
198 return Ok(port);
199 }
200 Err(Error::new(ErrorKind::Other, "-s content port incorrect"))
201 }
202
parse_server_listen_string(arg: String) -> io::Result<String>203 fn parse_server_listen_string(arg: String) -> io::Result<String> {
204 let segments: Vec<&str> = arg.split(":").collect();
205 let port_str = segments.last().unwrap().to_string();
206 let port_len = port_str.len();
207 let port = check_port(port_str)?;
208
209 if segments.len() == 1 {
210 return Ok(format!(
211 // "{}{}:{}",
212 // config::IPV4_MAPPING_PREFIX,
213 "{}:{}",
214 config::LOCAL_HOST,
215 port
216 ));
217 }
218
219 let ip_str = &arg[..arg.len() - port_len - 1];
220 match std::net::IpAddr::from_str(&ip_str) {
221 Ok(ip_addr) => {
222 if ip_addr.is_ipv4() {
223 // return Ok(config::IPV4_MAPPING_PREFIX.to_string() + &arg);
224 return Ok(arg);
225 } else if ip_addr.is_ipv6() {
226 return Ok(arg);
227 } else {
228 return Err(Error::new(ErrorKind::Other, "-s content ip incorrect"));
229 }
230 }
231 _ => return Err(Error::new(ErrorKind::Other, "-s content ip incorrect")),
232 }
233 }
234