• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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