| // Copyright 2019 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| use { |
| anyhow::{Context as _, Error}, |
| fidl_test_processbuilder::{EnvVar, UtilRequest, UtilRequestStream}, |
| fuchsia_async as fasync, |
| fuchsia_component::server::ServiceFs, |
| fuchsia_runtime::{self as fruntime, HandleInfo, HandleType}, |
| fuchsia_zircon::{self as zx, AsHandleRef}, |
| futures::prelude::*, |
| std::env, |
| std::fs, |
| }; |
| |
| async fn run_util_server(mut stream: UtilRequestStream) -> Result<(), Error> { |
| // If we've been given a lifecycle channel, figure out its koid |
| let lifecycle_koid: u64 = |
| match fruntime::take_startup_handle(HandleInfo::new(HandleType::Lifecycle, 0)) { |
| Some(handle) => handle |
| .as_handle_ref() |
| .get_koid() |
| .expect("failed to get basic lifecycle handle info") |
| .raw_koid(), |
| None => zx::sys::ZX_KOID_INVALID, |
| }; |
| |
| while let Some(req) = stream.try_next().await.context("error running echo server")? { |
| match req { |
| UtilRequest::GetArguments { responder } => { |
| let args: Vec<String> = env::args().collect(); |
| responder |
| .send(&mut args.iter().map(String::as_ref)) |
| .context("error sending response")? |
| } |
| UtilRequest::GetArgumentCount { responder } => { |
| responder.send(env::args().len() as u64).context("error sending response")? |
| } |
| UtilRequest::GetEnvironment { responder } => { |
| let mut vars: Vec<EnvVar> = |
| env::vars().map(|v| EnvVar { key: v.0, value: v.1 }).collect(); |
| responder.send(&mut vars.iter_mut()).context("error sending response")?; |
| } |
| UtilRequest::GetEnvironmentCount { responder } => { |
| responder.send(env::vars().count() as u64).context("error sending response")?; |
| } |
| UtilRequest::DumpNamespace { responder } => { |
| let mut contents = Vec::new(); |
| let mut a = |
| |entry: &fs::DirEntry| contents.push(format!("{}", entry.path().display())); |
| visit(std::path::Path::new("/"), &mut a)?; |
| responder.send(&contents.join(", ")).context("error sending response")?; |
| } |
| UtilRequest::ReadFile { path, responder } => { |
| let contents = fs::read_to_string(path) |
| .unwrap_or_else(|e| format!("read_to_string failed: {}", e)); |
| responder.send(&contents).context("error sending response")?; |
| } |
| UtilRequest::GetLifecycleKoid { responder } => { |
| responder.send(lifecycle_koid as u64)?; |
| } |
| } |
| } |
| Ok(()) |
| } |
| |
| fn visit(dir: &std::path::Path, cb: &mut dyn FnMut(&fs::DirEntry)) -> Result<(), Error> { |
| if dir.is_dir() { |
| for entry in fs::read_dir(dir)? { |
| let entry = entry?; |
| let path = entry.path(); |
| cb(&entry); |
| if path.is_dir() { |
| visit(&path, cb)?; |
| } |
| } |
| } |
| Ok(()) |
| } |
| |
| enum IncomingServices { |
| Util(UtilRequestStream), |
| } |
| |
| #[fasync::run_singlethreaded] |
| async fn main() -> Result<(), Error> { |
| // Note that the util doesn't add services under a subdirectory as would be typical for a |
| // component, as that isn't necessary for these tests. |
| let mut fs = ServiceFs::new_local(); |
| fs.add_fidl_service(IncomingServices::Util); |
| |
| fs.take_and_serve_directory_handle()?; |
| |
| const MAX_CONCURRENT: usize = 10; |
| fs.for_each_concurrent(MAX_CONCURRENT, |IncomingServices::Util(stream)| { |
| run_util_server(stream).unwrap_or_else(|e| println!("{:?}", e)) |
| }) |
| .await; |
| Ok(()) |
| } |