• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 use std::fs::OpenOptions;
6 use std::path::Path;
7 use std::path::PathBuf;
8 
9 #[cfg(feature = "pci-hotplug")]
10 use anyhow::anyhow;
11 use anyhow::Result as AnyHowResult;
12 use base::open_file_or_duplicate;
13 use remain::sorted;
14 use thiserror::Error;
15 
16 #[cfg(feature = "gpu")]
17 pub use crate::gpu::*;
18 pub use crate::sys::handle_request;
19 #[cfg(any(target_os = "android", target_os = "linux"))]
20 pub use crate::sys::handle_request_with_timeout;
21 pub use crate::*;
22 
23 #[sorted]
24 #[derive(Error, Debug)]
25 enum ModifyBatError {
26     #[error("{0}")]
27     BatControlErr(BatControlResult),
28 }
29 
30 #[sorted]
31 #[derive(Error, Debug)]
32 pub enum ModifyUsbError {
33     #[error("failed to open device {0}: {1}")]
34     FailedToOpenDevice(PathBuf, base::Error),
35     #[error("socket failed")]
36     SocketFailed,
37     #[error("unexpected response: {0}")]
38     UnexpectedResponse(VmResponse),
39     #[error("{0}")]
40     UsbControl(UsbControlResult),
41 }
42 
43 pub type ModifyUsbResult<T> = std::result::Result<T, ModifyUsbError>;
44 
45 pub type VmsRequestResult = std::result::Result<(), ()>;
46 
47 /// Send a `VmRequest` that expects a `VmResponse::Ok` reply.
vms_request<T: AsRef<Path> + std::fmt::Debug>( request: &VmRequest, socket_path: T, ) -> VmsRequestResult48 pub fn vms_request<T: AsRef<Path> + std::fmt::Debug>(
49     request: &VmRequest,
50     socket_path: T,
51 ) -> VmsRequestResult {
52     match handle_request(request, socket_path)? {
53         VmResponse::Ok => Ok(()),
54         r => {
55             println!("unexpected response: {r}");
56             Err(())
57         }
58     }
59 }
60 
61 #[cfg(feature = "pci-hotplug")]
62 /// Send a `VmRequest` for PCI hotplug that expects `VmResponse::PciResponse::AddOk(bus)`
do_net_add<T: AsRef<Path> + std::fmt::Debug>( tap_name: &str, socket_path: T, ) -> AnyHowResult<u8>63 pub fn do_net_add<T: AsRef<Path> + std::fmt::Debug>(
64     tap_name: &str,
65     socket_path: T,
66 ) -> AnyHowResult<u8> {
67     let request = VmRequest::HotPlugNetCommand(NetControlCommand::AddTap(tap_name.to_owned()));
68     let response = handle_request(&request, socket_path).map_err(|()| anyhow!("socket error: "))?;
69     match response {
70         VmResponse::PciHotPlugResponse { bus } => Ok(bus),
71         e => Err(anyhow!("Unexpected response: {:#}", e)),
72     }
73 }
74 
75 #[cfg(not(feature = "pci-hotplug"))]
76 /// Send a `VmRequest` for PCI hotplug that expects `VmResponse::PciResponse::AddOk(bus)`
do_net_add<T: AsRef<Path> + std::fmt::Debug>( _tap_name: &str, _socket_path: T, ) -> AnyHowResult<u8>77 pub fn do_net_add<T: AsRef<Path> + std::fmt::Debug>(
78     _tap_name: &str,
79     _socket_path: T,
80 ) -> AnyHowResult<u8> {
81     bail!("Unsupported: pci-hotplug feature disabled");
82 }
83 
84 #[cfg(feature = "pci-hotplug")]
85 /// Send a `VmRequest` for removing hotplugged PCI device that expects `VmResponse::Ok`
do_net_remove<T: AsRef<Path> + std::fmt::Debug>( bus_num: u8, socket_path: T, ) -> AnyHowResult<()>86 pub fn do_net_remove<T: AsRef<Path> + std::fmt::Debug>(
87     bus_num: u8,
88     socket_path: T,
89 ) -> AnyHowResult<()> {
90     let request = VmRequest::HotPlugNetCommand(NetControlCommand::RemoveTap(bus_num));
91     let response = handle_request(&request, socket_path).map_err(|()| anyhow!("socket error: "))?;
92     match response {
93         VmResponse::Ok => Ok(()),
94         e => Err(anyhow!("Unexpected response: {:#}", e)),
95     }
96 }
97 
98 #[cfg(not(feature = "pci-hotplug"))]
99 /// Send a `VmRequest` for removing hotplugged PCI device that expects `VmResponse::Ok`
do_net_remove<T: AsRef<Path> + std::fmt::Debug>( _bus_num: u8, _socket_path: T, ) -> AnyHowResult<()>100 pub fn do_net_remove<T: AsRef<Path> + std::fmt::Debug>(
101     _bus_num: u8,
102     _socket_path: T,
103 ) -> AnyHowResult<()> {
104     bail!("Unsupported: pci-hotplug feature disabled");
105 }
106 
do_usb_attach<T: AsRef<Path> + std::fmt::Debug>( socket_path: T, dev_path: &Path, ) -> ModifyUsbResult<UsbControlResult>107 pub fn do_usb_attach<T: AsRef<Path> + std::fmt::Debug>(
108     socket_path: T,
109     dev_path: &Path,
110 ) -> ModifyUsbResult<UsbControlResult> {
111     let usb_file = open_file_or_duplicate(dev_path, OpenOptions::new().read(true).write(true))
112         .map_err(|e| ModifyUsbError::FailedToOpenDevice(dev_path.into(), e))?;
113 
114     let request = VmRequest::UsbCommand(UsbControlCommand::AttachDevice { file: usb_file });
115     let response =
116         handle_request(&request, socket_path).map_err(|_| ModifyUsbError::SocketFailed)?;
117     match response {
118         VmResponse::UsbResponse(usb_resp) => Ok(usb_resp),
119         r => Err(ModifyUsbError::UnexpectedResponse(r)),
120     }
121 }
122 
do_security_key_attach<T: AsRef<Path> + std::fmt::Debug>( socket_path: T, dev_path: &Path, ) -> ModifyUsbResult<UsbControlResult>123 pub fn do_security_key_attach<T: AsRef<Path> + std::fmt::Debug>(
124     socket_path: T,
125     dev_path: &Path,
126 ) -> ModifyUsbResult<UsbControlResult> {
127     let usb_file = open_file_or_duplicate(dev_path, OpenOptions::new().read(true).write(true))
128         .map_err(|e| ModifyUsbError::FailedToOpenDevice(dev_path.into(), e))?;
129 
130     let request = VmRequest::UsbCommand(UsbControlCommand::AttachSecurityKey { file: usb_file });
131     let response =
132         handle_request(&request, socket_path).map_err(|_| ModifyUsbError::SocketFailed)?;
133     match response {
134         VmResponse::UsbResponse(usb_resp) => Ok(usb_resp),
135         r => Err(ModifyUsbError::UnexpectedResponse(r)),
136     }
137 }
138 
do_usb_detach<T: AsRef<Path> + std::fmt::Debug>( socket_path: T, port: u8, ) -> ModifyUsbResult<UsbControlResult>139 pub fn do_usb_detach<T: AsRef<Path> + std::fmt::Debug>(
140     socket_path: T,
141     port: u8,
142 ) -> ModifyUsbResult<UsbControlResult> {
143     let request = VmRequest::UsbCommand(UsbControlCommand::DetachDevice { port });
144     let response =
145         handle_request(&request, socket_path).map_err(|_| ModifyUsbError::SocketFailed)?;
146     match response {
147         VmResponse::UsbResponse(usb_resp) => Ok(usb_resp),
148         r => Err(ModifyUsbError::UnexpectedResponse(r)),
149     }
150 }
151 
do_usb_list<T: AsRef<Path> + std::fmt::Debug>( socket_path: T, ) -> ModifyUsbResult<UsbControlResult>152 pub fn do_usb_list<T: AsRef<Path> + std::fmt::Debug>(
153     socket_path: T,
154 ) -> ModifyUsbResult<UsbControlResult> {
155     let mut ports: [u8; USB_CONTROL_MAX_PORTS] = Default::default();
156     for (index, port) in ports.iter_mut().enumerate() {
157         *port = index as u8
158     }
159     let request = VmRequest::UsbCommand(UsbControlCommand::ListDevice { ports });
160     let response =
161         handle_request(&request, socket_path).map_err(|_| ModifyUsbError::SocketFailed)?;
162     match response {
163         VmResponse::UsbResponse(usb_resp) => Ok(usb_resp),
164         r => Err(ModifyUsbError::UnexpectedResponse(r)),
165     }
166 }
167 
168 pub type DoModifyBatteryResult = std::result::Result<(), ()>;
169 
do_modify_battery<T: AsRef<Path> + std::fmt::Debug>( socket_path: T, battery_type: &str, property: &str, target: &str, ) -> DoModifyBatteryResult170 pub fn do_modify_battery<T: AsRef<Path> + std::fmt::Debug>(
171     socket_path: T,
172     battery_type: &str,
173     property: &str,
174     target: &str,
175 ) -> DoModifyBatteryResult {
176     let response = match battery_type.parse::<BatteryType>() {
177         Ok(type_) => match BatControlCommand::new(property.to_string(), target.to_string()) {
178             Ok(cmd) => {
179                 let request = VmRequest::BatCommand(type_, cmd);
180                 Ok(handle_request(&request, socket_path)?)
181             }
182             Err(e) => Err(ModifyBatError::BatControlErr(e)),
183         },
184         Err(e) => Err(ModifyBatError::BatControlErr(e)),
185     };
186 
187     match response {
188         Ok(response) => {
189             println!("{}", response);
190             Ok(())
191         }
192         Err(e) => {
193             println!("error {}", e);
194             Err(())
195         }
196     }
197 }
198 
do_swap_status<T: AsRef<Path> + std::fmt::Debug>(socket_path: T) -> VmsRequestResult199 pub fn do_swap_status<T: AsRef<Path> + std::fmt::Debug>(socket_path: T) -> VmsRequestResult {
200     let response = handle_request(&VmRequest::Swap(SwapCommand::Status), socket_path)?;
201     match &response {
202         VmResponse::SwapStatus(_) => {
203             println!("{}", response);
204             Ok(())
205         }
206         r => {
207             println!("unexpected response: {r:?}");
208             Err(())
209         }
210     }
211 }
212 
213 pub type HandleRequestResult = std::result::Result<VmResponse, ()>;
214