elf_runner/
runtime_dir.rs1use fidl::endpoints::ServerEnd;
6use fidl_fuchsia_io as fio;
7use pseudo_fs::{
8 LazyPseudoDirectory, LazyPseudoDirectoryState, PseudoDirectory, PseudoFile, ToPseudoDirectory,
9};
10use std::sync::Arc;
11use vfs::ToObjectRequest;
12use vfs::directory::entry::{DirectoryEntry, OpenRequest};
13use vfs::directory::helper::DirectlyMutable;
14use vfs::execution_scope::ExecutionScope;
15
16pub struct RuntimeDirectory(Arc<LazyPseudoDirectory<RuntimeDirectoryInfo>>);
18
19struct RuntimeDirectoryInfo {
20 args: Box<[Box<str>]>,
21 job_id: Option<u64>,
22 process_id: Option<u64>,
23 process_start_time: Option<i64>,
24 process_start_time_utc_estimate: Option<Box<str>>,
25}
26
27impl ToPseudoDirectory for RuntimeDirectoryInfo {
28 fn to_pseudo_directory(self) -> Arc<PseudoDirectory> {
29 let args_dir = PseudoDirectory::new();
43 for (i, arg) in self.args.iter().enumerate() {
44 args_dir
45 .add_entry(i.to_string(), PseudoFile::from_data(arg.as_bytes()))
46 .expect("Failed to add arg to runtime/args directory");
47 }
48
49 let elf_dir = PseudoDirectory::new();
50 if let Some(job_id) = self.job_id {
51 elf_dir
52 .add_entry("job_id", PseudoFile::from_data(job_id.to_string()))
53 .expect("Failed to add job_id to runtime/elf directory");
54 }
55 if let Some(process_id) = self.process_id {
56 elf_dir
57 .add_entry("process_id", PseudoFile::from_data(process_id.to_string()))
58 .expect("Failed to add process_id to runtime/elf directory");
59 }
60 if let Some(process_start_time) = self.process_start_time {
61 elf_dir
62 .add_entry(
63 "process_start_time",
64 PseudoFile::from_data(process_start_time.to_string()),
65 )
66 .expect("Failed to add process_start_time to runtime/elf directory");
67 }
68 if let Some(process_start_time_utc_estimate) = self.process_start_time_utc_estimate {
69 elf_dir
70 .add_entry(
71 "process_start_time_utc_estimate",
72 PseudoFile::from_data(process_start_time_utc_estimate.as_bytes()),
73 )
74 .expect("Failed to add process_start_time_utc_estimate to runtime/elf directory");
75 }
76
77 let dir = PseudoDirectory::new();
78 dir.add_entry("args", args_dir).expect("Failed to add args directory to runtime directory");
79 dir.add_entry("elf", elf_dir).expect("Failed to add elf directory to runtime directory");
80 dir
81 }
82}
83
84impl RuntimeDirectory {
85 pub fn add_process_id(&self, value: u64) {
86 match self.0.state() {
87 LazyPseudoDirectoryState::Data(mut data) => data.process_id = Some(value),
88 LazyPseudoDirectoryState::Directory(dir) => get_elf_dir(&*dir)
89 .add_entry("process_id", PseudoFile::from_data(value.to_string()))
90 .expect("failed to add process_id"),
91 }
92 }
93
94 pub fn add_process_start_time(&self, value: i64) {
95 match self.0.state() {
96 LazyPseudoDirectoryState::Data(mut data) => data.process_start_time = Some(value),
97 LazyPseudoDirectoryState::Directory(dir) => get_elf_dir(&*dir)
98 .add_entry("process_start_time", PseudoFile::from_data(value.to_string()))
99 .expect("failed to add process_start_time"),
100 }
101 }
102
103 pub fn add_process_start_time_utc_estimate(&self, value: String) {
104 match self.0.state() {
105 LazyPseudoDirectoryState::Data(mut data) => {
106 data.process_start_time_utc_estimate = Some(value.into_boxed_str())
107 }
108 LazyPseudoDirectoryState::Directory(dir) => get_elf_dir(&*dir)
109 .add_entry("process_start_time_utc_estimate", PseudoFile::from_data(value))
110 .expect("failed to add process_start_time_utc_estimate"),
111 }
112 }
113
114 #[cfg(test)]
116 pub fn empty() -> Self {
117 RuntimeDirectory(LazyPseudoDirectory::new(RuntimeDirectoryInfo {
118 args: Box::default(),
119 job_id: None,
120 process_id: None,
121 process_start_time: None,
122 process_start_time_utc_estimate: None,
123 }))
124 }
125}
126
127pub struct RuntimeDirBuilder {
128 args: Box<[Box<str>]>,
129 job_id: Option<u64>,
130 server_end: ServerEnd<fio::DirectoryMarker>,
131}
132
133impl RuntimeDirBuilder {
134 pub fn new(server_end: ServerEnd<fio::DirectoryMarker>) -> Self {
135 Self { args: Box::default(), job_id: None, server_end }
136 }
137
138 pub fn args(mut self, args: Vec<String>) -> Self {
139 self.args = args.into_iter().map(|arg| arg.into_boxed_str()).collect();
140 self
141 }
142
143 pub fn job_id(mut self, job_id: u64) -> Self {
144 self.job_id = Some(job_id);
145 self
146 }
147
148 pub fn serve(self) -> RuntimeDirectory {
149 let runtime_directory = LazyPseudoDirectory::new(RuntimeDirectoryInfo {
150 args: self.args,
151 job_id: self.job_id,
152 process_id: None,
153 process_start_time: None,
154 process_start_time_utc_estimate: None,
155 });
156 let flags = fio::PERM_READABLE | fio::PERM_WRITABLE;
157 let object_request = flags.to_object_request(self.server_end);
158 object_request.handle(|object_request| {
159 let open_request =
160 OpenRequest::new(ExecutionScope::new(), flags, vfs::Path::dot(), object_request);
161 runtime_directory.clone().open_entry(open_request)
162 });
163
164 RuntimeDirectory(runtime_directory)
165 }
166}
167
168fn get_elf_dir(dir: &PseudoDirectory) -> Arc<PseudoDirectory> {
169 dir.get_entry("elf")
170 .expect("elf directory should be present")
171 .into_any()
172 .downcast::<PseudoDirectory>()
173 .expect("could not downcast elf to a directory")
174}
175
176#[cfg(test)]
177mod tests {
178 use super::*;
179 use fuchsia_fs::directory::read_file_to_string;
180
181 async fn force_create_directory(client: &fio::DirectoryProxy) {
182 fuchsia_fs::directory::open_directory(client, "elf", fio::PERM_READABLE)
183 .await
184 .expect("failed to open elf directory");
185 }
186
187 #[fuchsia::test]
188 async fn test_read_job_id() {
189 let (client, server_end) = fidl::endpoints::create_proxy::<fio::DirectoryMarker>();
190 RuntimeDirBuilder::new(server_end).job_id(1234).serve();
191
192 assert_eq!(
193 read_file_to_string(&client, "elf/job_id").await.expect("failed to read file"),
194 "1234"
195 );
196 }
197
198 #[fuchsia::test]
199 async fn test_read_args() {
200 let (client, server_end) = fidl::endpoints::create_proxy::<fio::DirectoryMarker>();
201 RuntimeDirBuilder::new(server_end)
202 .args(vec!["arg1".to_string(), "arg2".to_string()])
203 .serve();
204
205 assert_eq!(
206 read_file_to_string(&client, "args/0").await.expect("failed to read file"),
207 "arg1"
208 );
209 assert_eq!(
210 read_file_to_string(&client, "args/1").await.expect("failed to read file"),
211 "arg2"
212 );
213 }
214
215 #[fuchsia::test]
216 async fn test_add_process_id_before_connecting() {
217 let (client, server_end) = fidl::endpoints::create_proxy::<fio::DirectoryMarker>();
218 let runtime_directory = RuntimeDirBuilder::new(server_end).serve();
219 assert!(runtime_directory.0.state().is_data());
220
221 runtime_directory.add_process_id(1234);
222 assert_eq!(
223 read_file_to_string(&client, "elf/process_id").await.expect("failed to read file"),
224 "1234"
225 );
226 }
227
228 #[fuchsia::test]
229 async fn test_add_process_id_after_connecting() {
230 let (client, server_end) = fidl::endpoints::create_proxy::<fio::DirectoryMarker>();
231 let runtime_directory = RuntimeDirBuilder::new(server_end).serve();
232 force_create_directory(&client).await;
233 assert!(runtime_directory.0.state().is_directory());
234
235 runtime_directory.add_process_id(1234);
236 assert_eq!(
237 read_file_to_string(&client, "elf/process_id").await.expect("failed to read file"),
238 "1234"
239 );
240 }
241
242 #[fuchsia::test]
243 async fn test_add_process_start_time_before_connecting() {
244 let (client, server_end) = fidl::endpoints::create_proxy::<fio::DirectoryMarker>();
245 let runtime_directory = RuntimeDirBuilder::new(server_end).serve();
246 assert!(runtime_directory.0.state().is_data());
247
248 runtime_directory.add_process_start_time(1234);
249 assert_eq!(
250 read_file_to_string(&client, "elf/process_start_time")
251 .await
252 .expect("failed to read file"),
253 "1234"
254 );
255 }
256
257 #[fuchsia::test]
258 async fn test_add_process_start_time_after_connecting() {
259 let (client, server_end) = fidl::endpoints::create_proxy::<fio::DirectoryMarker>();
260 let runtime_directory = RuntimeDirBuilder::new(server_end).serve();
261 force_create_directory(&client).await;
262 assert!(runtime_directory.0.state().is_directory());
263
264 runtime_directory.add_process_start_time(1234);
265 assert_eq!(
266 read_file_to_string(&client, "elf/process_start_time")
267 .await
268 .expect("failed to read file"),
269 "1234"
270 );
271 }
272
273 #[fuchsia::test]
274 async fn test_add_process_start_time_utc_estimate_before_connecting() {
275 let (client, server_end) = fidl::endpoints::create_proxy::<fio::DirectoryMarker>();
276 let runtime_directory = RuntimeDirBuilder::new(server_end).serve();
277 assert!(runtime_directory.0.state().is_data());
278
279 runtime_directory.add_process_start_time_utc_estimate("start-time".to_string());
280 assert_eq!(
281 read_file_to_string(&client, "elf/process_start_time_utc_estimate")
282 .await
283 .expect("failed to read file"),
284 "start-time"
285 );
286 }
287
288 #[fuchsia::test]
289 async fn test_add_process_start_time_utc_estimate_after_connecting() {
290 let (client, server_end) = fidl::endpoints::create_proxy::<fio::DirectoryMarker>();
291 let runtime_directory = RuntimeDirBuilder::new(server_end).serve();
292 force_create_directory(&client).await;
293 assert!(runtime_directory.0.state().is_directory());
294
295 runtime_directory
296 .add_process_start_time_utc_estimate("start-time-utc-estimate".to_string());
297 assert_eq!(
298 read_file_to_string(&client, "elf/process_start_time_utc_estimate")
299 .await
300 .expect("failed to read file"),
301 "start-time-utc-estimate"
302 );
303 }
304}