1use fidl::endpoints::{DiscoverableProtocolMarker, Proxy as _};
18use vfs::directory::helper::DirectlyMutable;
19use {fidl_fuchsia_net_stackmigrationdeprecated as fnet_migration, fuchsia_async as fasync};
20
21#[fasync::run_singlethreaded]
22pub async fn main() -> std::process::ExitCode {
23 let current_boot_version = {
25 let migration =
26 fuchsia_component::client::connect_to_protocol::<fnet_migration::StateMarker>()
27 .expect("connect to protocol");
28 let fnet_migration::InEffectVersion { current_boot, .. } =
29 migration.get_netstack_version().await.expect("failed to read netstack version");
30 current_boot
31 };
32
33 println!("netstack migration proxy using version {current_boot_version:?}");
34 let bin_path = match current_boot_version {
35 fnet_migration::NetstackVersion::Netstack2 => c"/pkg/bin/netstack",
36 fnet_migration::NetstackVersion::Netstack3 => c"/pkg/bin/netstack3",
37 };
38
39 let ns = fdio::Namespace::installed().expect("failed to get namespace");
40 let mut entries = ns
41 .export()
42 .expect("failed to export namespace entries")
43 .into_iter()
44 .filter_map(|fdio::NamespaceEntry { handle, path }| match path.as_str() {
45 "/" => {
46 panic!("unexpected non flat namespace, bad capabilities will bleed into netstack")
47 }
48 "/svc" => None,
49 x => {
50 Some((Some(handle), std::ffi::CString::new(x).expect("failed to create C string")))
51 }
52 })
53 .collect::<Vec<_>>();
54
55 let handle =
56 fuchsia_runtime::take_startup_handle(fuchsia_runtime::HandleType::DirectoryRequest.into())
57 .expect("missing startup handle");
58
59 let mut actions = vec![fdio::SpawnAction::add_handle(
60 fuchsia_runtime::HandleInfo::new(fuchsia_runtime::HandleType::DirectoryRequest, 0),
61 handle,
62 )];
63
64 actions.extend(entries.iter_mut().map(|(handle, path)| {
65 let handle = handle.take().unwrap();
68 fdio::SpawnAction::add_namespace_entry(path.as_c_str(), handle)
69 }));
70
71 let svc = vfs::directory::immutable::simple::simple();
72 for s in std::fs::read_dir("/svc").expect("failed to get /svc entries") {
73 let entry = s.expect("failed to get directory entry");
74 let name = entry.file_name();
75 let name = name.to_str().expect("failed to get file name");
76
77 let block_services = [
80 fidl_fuchsia_process::LauncherMarker::PROTOCOL_NAME,
81 fnet_migration::StateMarker::PROTOCOL_NAME,
82 ];
83 if block_services.into_iter().any(|s| s == name) {
84 continue;
85 }
86 svc.add_entry(
87 name,
88 vfs::service::endpoint(move |_, channel| {
89 fuchsia_component::client::connect_channel_to_protocol_at_path(
90 channel.into(),
91 entry.path().to_str().expect("failed to get entry path"),
92 )
93 .unwrap_or_else(|e| eprintln!("error connecting to protocol {:?}", e));
94 }),
95 )
96 .unwrap_or_else(|e| panic!("failed to add entry {name}: {e:?}"));
97 }
98
99 let svc_dir = vfs::directory::serve_read_only(svc);
100 let handle = svc_dir.into_client_end().unwrap().into();
101 actions.push(fdio::SpawnAction::add_namespace_entry(c"/svc", handle));
102
103 let config_vmo_handle_info = fuchsia_runtime::HandleType::ComponentConfigVmo.into();
105 if let Some(config_vmo) = fuchsia_runtime::take_startup_handle(config_vmo_handle_info) {
106 actions.push(fdio::SpawnAction::add_handle(config_vmo_handle_info, config_vmo))
107 }
108
109 let proc = fdio::spawn_etc(
110 &fuchsia_runtime::job_default(),
111 fdio::SpawnOptions::CLONE_ALL - fdio::SpawnOptions::CLONE_NAMESPACE,
112 bin_path,
113 &[bin_path],
114 None,
115 &mut actions[..],
116 )
117 .expect("failed to spawn netstack");
118
119 let signals = fasync::OnSignals::new(&proc, zx::Signals::PROCESS_TERMINATED)
120 .await
121 .expect("failed to observe process termination signals");
122 println!("netstack exited unexpectedly with {signals:?}");
123
124 std::process::ExitCode::FAILURE
127}