• 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, 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