blob: ee9478b311acfbe63c83bdd4a505ee2b5af3a1c4 [file] [log] [blame]
// 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.
// TODO Follow 2018 idioms
#![allow(elided_lifetimes_in_paths)]
use {
::cm_logger::klog,
::routing::config::RuntimeConfig,
anyhow::Error,
component_manager_lib::{
bootfs::BootfsSvc,
builtin_environment::{BuiltinEnvironment, BuiltinEnvironmentBuilder},
startup,
},
fidl_fuchsia_component_internal as finternal, fuchsia_async as fasync,
fuchsia_runtime::{job_default, process_self},
fuchsia_syslog as syslog,
fuchsia_zircon::JobCriticalOptions,
log::*,
std::path::PathBuf,
std::{panic, process},
};
extern "C" {
fn dl_set_loader_service(
handle: fuchsia_zircon::sys::zx_handle_t,
) -> fuchsia_zircon::sys::zx_handle_t;
}
fn main() {
// Set ourselves as critical to our job. If we do not fail gracefully, our
// job will be killed.
if let Err(err) =
job_default().set_critical(JobCriticalOptions::RETCODE_NONZERO, &process_self())
{
panic!("Component manager failed to set itself as critical: {}", err);
}
// Close any loader service passed to component manager so that the service session can be
// freed, as component manager won't make use of a loader service such as by calling dlopen.
// If userboot invoked component manager directly, this service was the only reason userboot
// continued to run and closing it will let userboot terminate.
let ldsvc = unsafe {
fuchsia_zircon::Handle::from_raw(dl_set_loader_service(
fuchsia_zircon::sys::ZX_HANDLE_INVALID,
))
};
drop(ldsvc);
let (runtime_config, bootfs_svc, boot_defaults) = build_runtime_config();
match runtime_config.log_destination {
finternal::LogDestination::Syslog => {
syslog::init().expect("failed to init syslog");
}
finternal::LogDestination::Klog => {
klog::KernelLogger::init();
}
}
info!("Component manager is starting up...");
if boot_defaults {
info!("Component manager was started with boot defaults");
}
let num_threads = runtime_config.num_threads;
let fut = async move {
let mut builtin_environment = match build_environment(runtime_config, bootfs_svc).await {
Ok(environment) => environment,
Err(error) => {
error!("Component manager setup failed: {}", error);
process::exit(1);
}
};
if let Err(error) = builtin_environment.run_root().await {
error!("Failed to start root component: {}", error);
process::exit(1);
}
};
let mut executor = fasync::SendExecutor::new(num_threads).expect("error creating executor");
executor.run(fut);
}
/// Loads component_manager's config.
///
/// This function panics on failure because the logger is not initialized yet.
fn build_runtime_config() -> (RuntimeConfig, Option<BootfsSvc>, bool) {
let args = match startup::Arguments::from_args() {
Ok(args) => args,
Err(err) => {
panic!("{}\n{}", err, startup::Arguments::usage());
}
};
let mut config: RuntimeConfig;
let mut bootfs_svc: Option<BootfsSvc> = None;
if args.host_bootfs {
// The Rust bootfs VFS has not been brought up yet, so to find the component manager's
// config we must find the config's offset and size in the bootfs VMO, and read from it
// directly.
bootfs_svc = Some(BootfsSvc::new().expect("Failed to create Rust bootfs"));
let canonicalized =
if args.config.starts_with("/boot/") { &args.config[6..] } else { &args.config };
let config_bytes =
match bootfs_svc.as_ref().unwrap().read_config_from_uninitialized_vfs(canonicalized) {
Ok(config) => config,
Err(error) => {
panic!("Failed to read config from uninitialized vfs with error {}.", error)
}
};
config = match RuntimeConfig::load_from_bytes(&config_bytes) {
Ok(config) => config,
Err(err) => {
panic!("Failed to load runtime config: {}", err)
}
};
} else {
// This is the legacy path where bootsvc is hosting a C++ bootfs VFS,
// and component manager can read its config using standard filesystem APIs.
let path = PathBuf::from(&args.config);
config = match RuntimeConfig::load_from_file(&path) {
Ok(config) => config,
Err(err) => {
panic!("Failed to load runtime config: {}", err)
}
};
}
match (config.root_component_url.as_ref(), args.root_component_url.as_ref()) {
(Some(_url), None) => (config, bootfs_svc, args.boot),
(None, Some(url)) => {
config.root_component_url = Some(url.clone());
(config, bootfs_svc, args.boot)
}
(None, None) => {
panic!(
"`root_component_url` not provided. This field must be provided either as a \
command line argument or config file parameter."
);
}
(Some(_), Some(_)) => {
panic!(
"`root_component_url` set in two places: as a command line argument \
and a config file parameter. This field can only be set in one of those places."
);
}
}
}
async fn build_environment(
config: RuntimeConfig,
bootfs_svc: Option<BootfsSvc>,
) -> Result<BuiltinEnvironment, Error> {
BuiltinEnvironmentBuilder::new()
.set_runtime_config(config)
.create_utc_clock(&bootfs_svc)
.await?
.add_elf_runner()?
.include_namespace_resolvers()
.set_bootfs_svc(bootfs_svc)
.build()
.await
}