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