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