• 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::do_gpu_display_add;
18 #[cfg(feature = "gpu")]
19 pub use crate::gpu::do_gpu_display_list;
20 #[cfg(feature = "gpu")]
21 pub use crate::gpu::do_gpu_display_remove;
22 #[cfg(feature = "gpu")]
23 pub use crate::gpu::do_gpu_set_display_mouse_mode;
24 #[cfg(feature = "gpu")]
25 pub use crate::gpu::ModifyGpuResult;
26 pub use crate::sys::handle_request;
27 pub use crate::sys::handle_request_with_timeout;
28 use crate::BatControlCommand;
29 use crate::BatControlResult;
30 use crate::BatteryType;
31 #[cfg(feature = "audio")]
32 use crate::SndControlCommand;
33 use crate::SwapCommand;
34 use crate::UsbControlCommand;
35 use crate::UsbControlResult;
36 use crate::VmRequest;
37 use crate::VmResponse;
38 use crate::USB_CONTROL_MAX_PORTS;
39 
40 #[sorted]
41 #[derive(Error, Debug)]
42 enum ModifyBatError {
43     #[error("{0}")]
44     BatControlErr(BatControlResult),
45 }
46 
47 #[sorted]
48 #[derive(Error, Debug)]
49 pub enum ModifyUsbError {
50     #[error("failed to open device {0}: {1}")]
51     FailedToOpenDevice(PathBuf, base::Error),
52     #[error("socket failed")]
53     SocketFailed,
54     #[error("unexpected response: {0}")]
55     UnexpectedResponse(VmResponse),
56     #[error("{0}")]
57     UsbControl(UsbControlResult),
58 }
59 
60 pub type ModifyUsbResult<T> = std::result::Result<T, ModifyUsbError>;
61 
62 pub type VmsRequestResult = std::result::Result<(), ()>;
63 
64 /// Send a `VmRequest` that expects a `VmResponse::Ok` reply.
vms_request<T: AsRef<Path> + std::fmt::Debug>( request: &VmRequest, socket_path: T, ) -> VmsRequestResult65 pub fn vms_request<T: AsRef<Path> + std::fmt::Debug>(
66     request: &VmRequest,
67     socket_path: T,
68 ) -> VmsRequestResult {
69     match handle_request(request, socket_path)? {
70         VmResponse::Ok => Ok(()),
71         r => {
72             println!("unexpected response: {r}");
73             Err(())
74         }
75     }
76 }
77 
78 #[cfg(feature = "pci-hotplug")]
79 /// 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>80 pub fn do_net_add<T: AsRef<Path> + std::fmt::Debug>(
81     tap_name: &str,
82     socket_path: T,
83 ) -> AnyHowResult<u8> {
84     let request =
85         VmRequest::HotPlugNetCommand(crate::NetControlCommand::AddTap(tap_name.to_owned()));
86     let response = handle_request(&request, socket_path).map_err(|()| anyhow!("socket error: "))?;
87     match response {
88         VmResponse::PciHotPlugResponse { bus } => Ok(bus),
89         e => Err(anyhow!("Unexpected response: {:#}", e)),
90     }
91 }
92 
93 #[cfg(not(feature = "pci-hotplug"))]
94 /// 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>95 pub fn do_net_add<T: AsRef<Path> + std::fmt::Debug>(
96     _tap_name: &str,
97     _socket_path: T,
98 ) -> AnyHowResult<u8> {
99     anyhow::bail!("Unsupported: pci-hotplug feature disabled");
100 }
101 
102 #[cfg(feature = "pci-hotplug")]
103 /// 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<()>104 pub fn do_net_remove<T: AsRef<Path> + std::fmt::Debug>(
105     bus_num: u8,
106     socket_path: T,
107 ) -> AnyHowResult<()> {
108     let request = VmRequest::HotPlugNetCommand(crate::NetControlCommand::RemoveTap(bus_num));
109     let response = handle_request(&request, socket_path).map_err(|()| anyhow!("socket error: "))?;
110     match response {
111         VmResponse::Ok => Ok(()),
112         e => Err(anyhow!("Unexpected response: {:#}", e)),
113     }
114 }
115 
116 #[cfg(not(feature = "pci-hotplug"))]
117 /// 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<()>118 pub fn do_net_remove<T: AsRef<Path> + std::fmt::Debug>(
119     _bus_num: u8,
120     _socket_path: T,
121 ) -> AnyHowResult<()> {
122     anyhow::bail!("Unsupported: pci-hotplug feature disabled");
123 }
124 
do_usb_attach<T: AsRef<Path> + std::fmt::Debug>( socket_path: T, dev_path: &Path, ) -> ModifyUsbResult<UsbControlResult>125 pub fn do_usb_attach<T: AsRef<Path> + std::fmt::Debug>(
126     socket_path: T,
127     dev_path: &Path,
128 ) -> ModifyUsbResult<UsbControlResult> {
129     let usb_file = open_file_or_duplicate(dev_path, OpenOptions::new().read(true).write(true))
130         .map_err(|e| ModifyUsbError::FailedToOpenDevice(dev_path.into(), e))?;
131 
132     let request = VmRequest::UsbCommand(UsbControlCommand::AttachDevice { file: usb_file });
133     let response =
134         handle_request(&request, socket_path).map_err(|_| ModifyUsbError::SocketFailed)?;
135     match response {
136         VmResponse::UsbResponse(usb_resp) => Ok(usb_resp),
137         r => Err(ModifyUsbError::UnexpectedResponse(r)),
138     }
139 }
140 
do_security_key_attach<T: AsRef<Path> + std::fmt::Debug>( socket_path: T, dev_path: &Path, ) -> ModifyUsbResult<UsbControlResult>141 pub fn do_security_key_attach<T: AsRef<Path> + std::fmt::Debug>(
142     socket_path: T,
143     dev_path: &Path,
144 ) -> ModifyUsbResult<UsbControlResult> {
145     let usb_file = open_file_or_duplicate(dev_path, OpenOptions::new().read(true).write(true))
146         .map_err(|e| ModifyUsbError::FailedToOpenDevice(dev_path.into(), e))?;
147 
148     let request = VmRequest::UsbCommand(UsbControlCommand::AttachSecurityKey { file: usb_file });
149     let response =
150         handle_request(&request, socket_path).map_err(|_| ModifyUsbError::SocketFailed)?;
151     match response {
152         VmResponse::UsbResponse(usb_resp) => Ok(usb_resp),
153         r => Err(ModifyUsbError::UnexpectedResponse(r)),
154     }
155 }
156 
do_usb_detach<T: AsRef<Path> + std::fmt::Debug>( socket_path: T, port: u8, ) -> ModifyUsbResult<UsbControlResult>157 pub fn do_usb_detach<T: AsRef<Path> + std::fmt::Debug>(
158     socket_path: T,
159     port: u8,
160 ) -> ModifyUsbResult<UsbControlResult> {
161     let request = VmRequest::UsbCommand(UsbControlCommand::DetachDevice { port });
162     let response =
163         handle_request(&request, socket_path).map_err(|_| ModifyUsbError::SocketFailed)?;
164     match response {
165         VmResponse::UsbResponse(usb_resp) => Ok(usb_resp),
166         r => Err(ModifyUsbError::UnexpectedResponse(r)),
167     }
168 }
169 
do_usb_list<T: AsRef<Path> + std::fmt::Debug>( socket_path: T, ) -> ModifyUsbResult<UsbControlResult>170 pub fn do_usb_list<T: AsRef<Path> + std::fmt::Debug>(
171     socket_path: T,
172 ) -> ModifyUsbResult<UsbControlResult> {
173     let mut ports: [u8; USB_CONTROL_MAX_PORTS] = Default::default();
174     for (index, port) in ports.iter_mut().enumerate() {
175         *port = index as u8
176     }
177     let request = VmRequest::UsbCommand(UsbControlCommand::ListDevice { ports });
178     let response =
179         handle_request(&request, socket_path).map_err(|_| ModifyUsbError::SocketFailed)?;
180     match response {
181         VmResponse::UsbResponse(usb_resp) => Ok(usb_resp),
182         r => Err(ModifyUsbError::UnexpectedResponse(r)),
183     }
184 }
185 
186 pub type DoModifyBatteryResult = std::result::Result<(), ()>;
187 
do_modify_battery<T: AsRef<Path> + std::fmt::Debug>( socket_path: T, battery_type: &str, property: &str, target: &str, ) -> DoModifyBatteryResult188 pub fn do_modify_battery<T: AsRef<Path> + std::fmt::Debug>(
189     socket_path: T,
190     battery_type: &str,
191     property: &str,
192     target: &str,
193 ) -> DoModifyBatteryResult {
194     let response = match battery_type.parse::<BatteryType>() {
195         Ok(type_) => match BatControlCommand::new(property.to_string(), target.to_string()) {
196             Ok(cmd) => {
197                 let request = VmRequest::BatCommand(type_, cmd);
198                 Ok(handle_request(&request, socket_path)?)
199             }
200             Err(e) => Err(ModifyBatError::BatControlErr(e)),
201         },
202         Err(e) => Err(ModifyBatError::BatControlErr(e)),
203     };
204 
205     match response {
206         Ok(response) => {
207             println!("{}", response);
208             Ok(())
209         }
210         Err(e) => {
211             println!("error {}", e);
212             Err(())
213         }
214     }
215 }
216 
217 #[cfg(feature = "audio")]
218 /// Send a `VmRequest` for muting/unmuting snd all snd devices`
do_snd_mute_all<T: AsRef<Path> + std::fmt::Debug>( socket_path: T, muted: bool, ) -> std::result::Result<(), ()>219 pub fn do_snd_mute_all<T: AsRef<Path> + std::fmt::Debug>(
220     socket_path: T,
221     muted: bool,
222 ) -> std::result::Result<(), ()> {
223     let request = VmRequest::SndCommand(SndControlCommand::MuteAll(muted));
224     let response = handle_request(&request, socket_path)?;
225     match response {
226         VmResponse::Ok => Ok(()),
227         e => {
228             println!("Unexpected response: {:#}", e);
229             Err(())
230         }
231     }
232 }
233 
234 #[cfg(not(feature = "audio"))]
235 /// Send a `VmRequest` for muting/unmuting snd all snd devices`
do_snd_mute_all<T: AsRef<Path> + std::fmt::Debug>( _socket_path: T, _muted: bool, ) -> std::result::Result<(), ()>236 pub fn do_snd_mute_all<T: AsRef<Path> + std::fmt::Debug>(
237     _socket_path: T,
238     _muted: bool,
239 ) -> std::result::Result<(), ()> {
240     println!("Unsupported: audio feature disabled");
241     Err(())
242 }
243 
do_swap_status<T: AsRef<Path> + std::fmt::Debug>(socket_path: T) -> VmsRequestResult244 pub fn do_swap_status<T: AsRef<Path> + std::fmt::Debug>(socket_path: T) -> VmsRequestResult {
245     let response = handle_request(&VmRequest::Swap(SwapCommand::Status), socket_path)?;
246     match &response {
247         VmResponse::SwapStatus(_) => {
248             println!("{}", response);
249             Ok(())
250         }
251         r => {
252             println!("unexpected response: {r:?}");
253             Err(())
254         }
255     }
256 }
257 
258 pub type HandleRequestResult = std::result::Result<VmResponse, ()>;
259