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