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