blob: e572f88c61184d22fe19093ecd88928191ffd970 [file] [log] [blame]
// Copyright 2021 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::{format_err, Error},
argh::FromArgs,
fidl_fuchsia_fxfs::CryptProxy,
fuchsia_async as fasync,
fuchsia_component::server::MissingStartupHandle,
fuchsia_runtime::HandleType,
fuchsia_zircon as zx,
fxfs::{
filesystem::{mkfs, FxFilesystem, OpenOptions},
fsck,
log::*,
platform::{component::Component, RemoteCrypt},
serialized_types::LATEST_VERSION,
},
remote_block_device::RemoteBlockClient,
std::sync::Arc,
storage_device::{block_device::BlockDevice, DeviceHolder},
};
#[derive(FromArgs, PartialEq, Debug)]
/// fxfs
struct TopLevel {
#[argh(subcommand)]
nested: SubCommand,
/// enable additional logging
#[argh(switch)]
verbose: bool,
}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand)]
enum SubCommand {
Component(ComponentSubCommand),
Format(FormatSubCommand),
Fsck(FsckSubCommand),
}
#[derive(FromArgs, PartialEq, Debug)]
/// Format
#[argh(subcommand, name = "mkfs")]
struct FormatSubCommand {
/// make the default volume encrypted (using supplied crypt service)
#[argh(switch)]
encrypted: bool,
}
#[derive(FromArgs, PartialEq, Debug)]
/// Fsck
#[argh(subcommand, name = "fsck")]
struct FsckSubCommand {
/// check encrypted volumes (with supplied crypt service)
#[argh(switch)]
encrypted: bool,
}
#[derive(FromArgs, PartialEq, Debug)]
/// Component
#[argh(subcommand, name = "component")]
struct ComponentSubCommand {}
fn get_crypt_client() -> Result<Arc<RemoteCrypt>, Error> {
Ok(Arc::new(RemoteCrypt::new(CryptProxy::new(fasync::Channel::from_channel(
zx::Channel::from(
fuchsia_runtime::take_startup_handle(fuchsia_runtime::HandleInfo::new(
HandleType::User0,
2,
))
.ok_or(format_err!("Missing crypt service"))?,
),
)?))))
}
// The number of threads chosen here must exceed the number of concurrent system calls to paged VMOs
// that we allow since otherwise deadlocks are possible. Search for CONCURRENT_SYSCALLS.
#[fasync::run(10)]
async fn main() -> Result<(), Error> {
diagnostics_log::init!();
#[cfg(feature = "tracing")]
fuchsia_trace_provider::trace_provider_create_with_fdio();
info!(version = %LATEST_VERSION, "Started");
let args: TopLevel = argh::from_env();
if let TopLevel { nested: SubCommand::Component(_), .. } = args {
return Component::new()
.run(
fuchsia_runtime::take_startup_handle(HandleType::DirectoryRequest.into())
.ok_or(MissingStartupHandle)?
.into(),
fuchsia_runtime::take_startup_handle(HandleType::Lifecycle.into())
.map(|h| h.into()),
)
.await;
}
let client = RemoteBlockClient::new(zx::Channel::from(
fuchsia_runtime::take_startup_handle(fuchsia_runtime::HandleInfo::new(
HandleType::User0,
1,
))
.ok_or(format_err!("Missing device handle"))?,
))
.await?;
match args {
TopLevel { nested: SubCommand::Format(FormatSubCommand { encrypted }), .. } => {
mkfs(
DeviceHolder::new(BlockDevice::new(Box::new(client), false).await?),
if encrypted { Some(get_crypt_client()?) } else { None },
)
.await?;
Ok(())
}
TopLevel { nested: SubCommand::Fsck(FsckSubCommand { encrypted }), verbose } => {
let fs = FxFilesystem::open_with_options(
DeviceHolder::new(BlockDevice::new(Box::new(client), true).await?),
OpenOptions { read_only: true, trace: verbose, ..Default::default() },
)
.await?;
let mut options = fsck::default_options();
options.verbose = verbose;
fsck::fsck_with_options(
&fs,
if encrypted { Some(get_crypt_client()?) } else { None },
options,
)
.await
}
TopLevel { nested: SubCommand::Component(_), .. } => unreachable!(),
}
}