1use crate::platform::PlatformServices;
6use anyhow::Error;
7use fidl_fuchsia_virtualization::LinuxManagerProxy;
8use std::fmt;
9use {guest_cli_args as arguments, zx_status};
10
11#[derive(Debug, PartialEq, serde::Serialize, serde::Deserialize)]
12pub enum WipeResult {
13 WipeCompleted,
14 IncorrectGuestState,
15 WipeFailure(i32),
16 UnsupportedGuest(arguments::GuestType),
17}
18
19impl fmt::Display for WipeResult {
20 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
21 match self {
22 WipeResult::WipeCompleted => write!(f, "Successfully wiped guest"),
23 WipeResult::WipeFailure(status) => {
24 write!(f, "Failed to wipe data: {}", zx_status::Status::from_raw(*status))
25 }
26 WipeResult::IncorrectGuestState => {
27 write!(
28 f,
29 concat!(
30 "The VM has already started. Please stop the guest ",
31 "(by restarting the host or issuing a guest stop command) and retry."
32 )
33 )
34 }
35 WipeResult::UnsupportedGuest(guest) => {
36 write!(f, "Wipe is not supported for '{}'. Only 'termina' is supported", guest)
37 }
38 }
39 }
40}
41
42pub async fn handle_wipe<P: PlatformServices>(
43 services: &P,
44 args: &arguments::wipe_args::WipeArgs,
45) -> Result<WipeResult, Error> {
46 if args.guest_type != arguments::GuestType::Termina {
47 return Ok(WipeResult::UnsupportedGuest(args.guest_type));
48 }
49
50 let linux_manager = services.connect_to_linux_manager().await?;
51 do_wipe(linux_manager).await
52}
53
54async fn do_wipe(proxy: LinuxManagerProxy) -> Result<WipeResult, Error> {
55 let result = match proxy.wipe_data().await?.map_err(zx_status::Status::from_raw) {
56 Err(zx_status::Status::BAD_STATE) => WipeResult::IncorrectGuestState,
57 Err(status) => WipeResult::WipeFailure(status.into_raw()),
58 Ok(()) => WipeResult::WipeCompleted,
59 };
60
61 Ok(result)
62}
63
64#[cfg(test)]
65mod test {
66 use super::*;
67 use crate::platform::FuchsiaPlatformServices;
68 use fidl::endpoints::create_proxy_and_stream;
69 use fidl_fuchsia_virtualization::LinuxManagerMarker;
70 use fuchsia_async as fasync;
71 use futures::StreamExt;
72
73 fn serve_mock_manager(response: zx_status::Status) -> LinuxManagerProxy {
74 let (proxy, mut stream) = create_proxy_and_stream::<LinuxManagerMarker>();
75 fasync::Task::local(async move {
76 let responder = stream
77 .next()
78 .await
79 .expect("mock manager expected a request")
80 .unwrap()
81 .into_wipe_data()
82 .expect("unexpected call to mock manager");
83
84 if response == zx_status::Status::OK {
85 responder.send(Ok(())).expect("failed to send mock response");
86 } else {
87 responder.send(Err(response.into_raw())).expect("failed to send mock response");
88 }
89 })
90 .detach();
91
92 proxy
93 }
94
95 #[fasync::run_until_stalled(test)]
96 async fn unsupported_guest_type() {
97 let services = FuchsiaPlatformServices::new();
98 let result = handle_wipe(
99 &services,
100 &arguments::wipe_args::WipeArgs { guest_type: arguments::GuestType::Debian },
101 )
102 .await
103 .unwrap();
104
105 assert_eq!(result, WipeResult::UnsupportedGuest(arguments::GuestType::Debian));
106 }
107
108 #[fasync::run_until_stalled(test)]
109 async fn incorrect_guest_state() {
110 let proxy = serve_mock_manager(zx_status::Status::BAD_STATE);
111 let result = do_wipe(proxy).await.unwrap();
112 assert_eq!(result, WipeResult::IncorrectGuestState);
113 }
114
115 #[fasync::run_until_stalled(test)]
116 async fn guest_wipe_failure() {
117 let proxy = serve_mock_manager(zx_status::Status::NOT_FOUND);
118 let result = do_wipe(proxy).await.unwrap();
119 assert_eq!(result, WipeResult::WipeFailure(zx_status::Status::NOT_FOUND.into_raw()));
120 }
121
122 #[fasync::run_until_stalled(test)]
123 async fn guest_successfully_wiped() {
124 let proxy = serve_mock_manager(zx_status::Status::OK);
125 let result = do_wipe(proxy).await.unwrap();
126 assert_eq!(result, WipeResult::WipeCompleted);
127 }
128}