• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 use crate::*;
5 use base::{info, net::UnixSeqpacket, validate_raw_descriptor, RawDescriptor, Tube};
6 
7 use std::fs::OpenOptions;
8 use std::num::ParseIntError;
9 use std::path::{Path, PathBuf};
10 
11 enum ModifyBatError {
12     BatControlErr(BatControlResult),
13 }
14 
15 impl fmt::Display for ModifyBatError {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result16     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
17         use self::ModifyBatError::*;
18 
19         match self {
20             BatControlErr(e) => write!(f, "{}", e),
21         }
22     }
23 }
24 
25 pub enum ModifyUsbError {
26     ArgMissing(&'static str),
27     ArgParse(&'static str, String),
28     ArgParseInt(&'static str, String, ParseIntError),
29     FailedDescriptorValidate(base::Error),
30     PathDoesNotExist(PathBuf),
31     SocketFailed,
32     UnexpectedResponse(VmResponse),
33     UnknownCommand(String),
34     UsbControl(UsbControlResult),
35 }
36 
37 impl std::fmt::Display for ModifyUsbError {
fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result38     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
39         use self::ModifyUsbError::*;
40 
41         match self {
42             ArgMissing(a) => write!(f, "argument missing: {}", a),
43             ArgParse(name, value) => {
44                 write!(f, "failed to parse argument {} value `{}`", name, value)
45             }
46             ArgParseInt(name, value, e) => write!(
47                 f,
48                 "failed to parse integer argument {} value `{}`: {}",
49                 name, value, e
50             ),
51             FailedDescriptorValidate(e) => write!(f, "failed to validate file descriptor: {}", e),
52             PathDoesNotExist(p) => write!(f, "path `{}` does not exist", p.display()),
53             SocketFailed => write!(f, "socket failed"),
54             UnexpectedResponse(r) => write!(f, "unexpected response: {}", r),
55             UnknownCommand(c) => write!(f, "unknown command: `{}`", c),
56             UsbControl(e) => write!(f, "{}", e),
57         }
58     }
59 }
60 
61 pub type ModifyUsbResult<T> = std::result::Result<T, ModifyUsbError>;
62 
raw_descriptor_from_path(path: &Path) -> ModifyUsbResult<RawDescriptor>63 fn raw_descriptor_from_path(path: &Path) -> ModifyUsbResult<RawDescriptor> {
64     if !path.exists() {
65         return Err(ModifyUsbError::PathDoesNotExist(path.to_owned()));
66     }
67     let raw_descriptor = path
68         .file_name()
69         .and_then(|fd_osstr| fd_osstr.to_str())
70         .map_or(
71             Err(ModifyUsbError::ArgParse(
72                 "USB_DEVICE_PATH",
73                 path.to_string_lossy().into_owned(),
74             )),
75             |fd_str| {
76                 fd_str.parse::<libc::c_int>().map_err(|e| {
77                     ModifyUsbError::ArgParseInt("USB_DEVICE_PATH", fd_str.to_owned(), e)
78                 })
79             },
80         )?;
81     validate_raw_descriptor(raw_descriptor).map_err(ModifyUsbError::FailedDescriptorValidate)
82 }
83 
84 pub type VmsRequestResult = std::result::Result<(), ()>;
85 
vms_request(request: &VmRequest, socket_path: &Path) -> VmsRequestResult86 pub fn vms_request(request: &VmRequest, socket_path: &Path) -> VmsRequestResult {
87     let response = handle_request(request, socket_path)?;
88     info!("request response was {}", response);
89     Ok(())
90 }
91 
do_usb_attach( socket_path: &Path, bus: u8, addr: u8, vid: u16, pid: u16, dev_path: &Path, ) -> ModifyUsbResult<UsbControlResult>92 pub fn do_usb_attach(
93     socket_path: &Path,
94     bus: u8,
95     addr: u8,
96     vid: u16,
97     pid: u16,
98     dev_path: &Path,
99 ) -> ModifyUsbResult<UsbControlResult> {
100     let usb_file: File = if dev_path.parent() == Some(Path::new("/proc/self/fd")) {
101         // Special case '/proc/self/fd/*' paths. The FD is already open, just use it.
102         // Safe because we will validate |raw_fd|.
103         unsafe { File::from_raw_descriptor(raw_descriptor_from_path(&dev_path)?) }
104     } else {
105         OpenOptions::new()
106             .read(true)
107             .write(true)
108             .open(&dev_path)
109             .map_err(|_| ModifyUsbError::UsbControl(UsbControlResult::FailedToOpenDevice))?
110     };
111 
112     let request = VmRequest::UsbCommand(UsbControlCommand::AttachDevice {
113         bus,
114         addr,
115         vid,
116         pid,
117         file: usb_file,
118     });
119     let response =
120         handle_request(&request, socket_path).map_err(|_| ModifyUsbError::SocketFailed)?;
121     match response {
122         VmResponse::UsbResponse(usb_resp) => Ok(usb_resp),
123         r => Err(ModifyUsbError::UnexpectedResponse(r)),
124     }
125 }
126 
do_usb_detach(socket_path: &Path, port: u8) -> ModifyUsbResult<UsbControlResult>127 pub fn do_usb_detach(socket_path: &Path, port: u8) -> ModifyUsbResult<UsbControlResult> {
128     let request = VmRequest::UsbCommand(UsbControlCommand::DetachDevice { port });
129     let response =
130         handle_request(&request, socket_path).map_err(|_| ModifyUsbError::SocketFailed)?;
131     match response {
132         VmResponse::UsbResponse(usb_resp) => Ok(usb_resp),
133         r => Err(ModifyUsbError::UnexpectedResponse(r)),
134     }
135 }
136 
do_usb_list(socket_path: &Path) -> ModifyUsbResult<UsbControlResult>137 pub fn do_usb_list(socket_path: &Path) -> ModifyUsbResult<UsbControlResult> {
138     let mut ports: [u8; USB_CONTROL_MAX_PORTS] = Default::default();
139     for (index, port) in ports.iter_mut().enumerate() {
140         *port = index as u8
141     }
142     let request = VmRequest::UsbCommand(UsbControlCommand::ListDevice { ports });
143     let response =
144         handle_request(&request, socket_path).map_err(|_| ModifyUsbError::SocketFailed)?;
145     match response {
146         VmResponse::UsbResponse(usb_resp) => Ok(usb_resp),
147         r => Err(ModifyUsbError::UnexpectedResponse(r)),
148     }
149 }
150 
151 pub type DoModifyBatteryResult = std::result::Result<(), ()>;
152 
do_modify_battery( socket_path: &Path, battery_type: &str, property: &str, target: &str, ) -> DoModifyBatteryResult153 pub fn do_modify_battery(
154     socket_path: &Path,
155     battery_type: &str,
156     property: &str,
157     target: &str,
158 ) -> DoModifyBatteryResult {
159     let response = match battery_type.parse::<BatteryType>() {
160         Ok(type_) => match BatControlCommand::new(property.to_string(), target.to_string()) {
161             Ok(cmd) => {
162                 let request = VmRequest::BatCommand(type_, cmd);
163                 Ok(handle_request(&request, socket_path)?)
164             }
165             Err(e) => Err(ModifyBatError::BatControlErr(e)),
166         },
167         Err(e) => Err(ModifyBatError::BatControlErr(e)),
168     };
169 
170     match response {
171         Ok(response) => {
172             println!("{}", response);
173             Ok(())
174         }
175         Err(e) => {
176             println!("error {}", e);
177             Err(())
178         }
179     }
180 }
181 
182 pub type HandleRequestResult = std::result::Result<VmResponse, ()>;
183 
handle_request(request: &VmRequest, socket_path: &Path) -> HandleRequestResult184 pub fn handle_request(request: &VmRequest, socket_path: &Path) -> HandleRequestResult {
185     match UnixSeqpacket::connect(&socket_path) {
186         Ok(s) => {
187             let socket = Tube::new(s);
188             if let Err(e) = socket.send(request) {
189                 error!(
190                     "failed to send request to socket at '{:?}': {}",
191                     socket_path, e
192                 );
193                 return Err(());
194             }
195             match socket.recv() {
196                 Ok(response) => Ok(response),
197                 Err(e) => {
198                     error!(
199                         "failed to send request to socket at '{:?}': {}",
200                         socket_path, e
201                     );
202                     Err(())
203                 }
204             }
205         }
206         Err(e) => {
207             error!("failed to connect to socket at '{:?}': {}", socket_path, e);
208             Err(())
209         }
210     }
211 }
212