1use anyhow::{bail, format_err, Context};
6use fidl::endpoints::ServerEnd;
7use fidl::HandleBased;
8use fuchsia_component::directory::AsRefDirectory;
9use fuchsia_component::server::ServiceFs;
10use futures::prelude::*;
11use log::info;
12use std::collections::HashSet;
13use vfs::remote;
14use {
15 fidl_fuchsia_io as fio, fidl_fuchsia_process as fprocess, fidl_fuchsia_process_lifecycle as fpl,
16};
17
18pub async fn main(
19 ns_entries: Vec<fprocess::NameInfo>,
20 directory_request: ServerEnd<fio::DirectoryMarker>,
21 lifecycle: ServerEnd<fpl::LifecycleMarker>,
22) -> Result<(), anyhow::Error> {
23 if lifecycle.is_invalid_handle() {
24 bail!("No valid handle found for lifecycle events");
25 }
26 if directory_request.is_invalid_handle() {
27 bail!("No valid handle found for outgoing directory");
28 }
29 let Some(svc) = ns_entries.iter().find(|e| e.path == "/svc") else {
30 bail!("No /svc in namespace");
31 };
32 svc.directory
33 .as_ref_directory()
34 .open("fuchsia.device.fs.lifecycle.Lifecycle", fio::Flags::empty(), lifecycle.into())
35 .context("Failed to connect to fuchsia.device.fs.Lifecycle")?;
36
37 let mut fs = ServiceFs::new();
38
39 let mut expose = HashSet::new();
40 expose.insert("dev");
41 for entry in ns_entries {
42 let path = entry
43 .path
44 .strip_prefix("/")
45 .ok_or_else(|| format_err!("Encountered illegal namespace path: {}", entry.path))?;
46 if !expose.remove(path) {
47 continue;
48 }
49 fs.add_entry_at(path, remote::remote_dir(entry.directory.into_proxy()));
50 }
51 if !expose.is_empty() {
52 let missing = expose.into_iter().collect::<Vec<_>>().join(",");
53 bail!("Failed to expose all entries: {missing}");
54 }
55
56 info!("[devfs] Initialized.");
57
58 fs.serve_connection(directory_request).context("failed to serve outgoing namespace")?;
59 fs.collect::<()>().await;
60 Err(format_err!("devfs ended unexpectedly"))
61}