blob: 1978a7d8983c335728eddfd12352f65be5a7611a [file] [log] [blame]
// Copyright 2018 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.
// #![deny(warnings)]
#![feature(async_await, await_macro, try_from, futures_api)]
use failure::{Error, ResultExt};
use fidl::endpoints::RequestStream;
use fidl::endpoints::ServiceMarker;
use fuchsia_app::server::ServicesServer;
use fuchsia_async as fasync;
use fuchsia_syslog::{fx_log_err, fx_log_info};
use futures::{TryFutureExt, TryStreamExt};
use parking_lot::Mutex;
use std::convert::{TryFrom, TryInto};
use std::env;
use std::path::PathBuf;
use std::process;
use std::sync::Arc;
mod accessor;
mod instance;
mod store;
use fidl_fuchsia_stash::{SecureStoreMarker, StoreMarker, StoreRequest, StoreRequestStream};
struct StashSettings {
backing_file: String,
secure_mode: bool,
}
impl Default for StashSettings {
fn default() -> StashSettings {
StashSettings {
backing_file: "/data/stash.store".to_string(),
secure_mode: false,
}
}
}
impl TryFrom<env::Args> for StashSettings {
type Error = ();
fn try_from(mut args: env::Args) -> Result<StashSettings, ()> {
// ignore arg[0]
let _ = args.next();
let mut res = StashSettings::default();
while let Some(flag) = args.next() {
match flag.as_str() {
"--backing_file" => {
if let Some(f) = args.next() {
res.backing_file = f;
} else {
return Err(());
}
}
"--secure" => res.secure_mode = true,
_ => return Err(()),
}
}
return Ok(res);
}
}
fn main() -> Result<(), Error> {
fuchsia_syslog::init_with_tags(&["stash"])?;
let r_opts: Result<StashSettings, ()> = env::args().try_into();
match r_opts {
Err(_) => {
print_help();
process::exit(1);
}
Ok(opts) => {
let mut executor = fasync::Executor::new().context("Error creating executor")?;
let store_manager = Arc::new(Mutex::new(store::StoreManager::new(PathBuf::from(
&opts.backing_file,
))?));
let marker = if opts.secure_mode {
SecureStoreMarker::NAME
} else {
StoreMarker::NAME
};
let fut = ServicesServer::new()
.add_service((marker, move |chan| {
stash_server(
store_manager.clone(),
!opts.secure_mode,
chan,
)
})).start()
.context("Error starting stash server")?;
executor
.run_singlethreaded(fut)
.context("failed to execute stash service future")?;
}
}
Ok(())
}
fn print_help() {
println!(
r"stash
garnet service for storing key/value pairs
USAGE:
stash [FLAGS]
FLAGS:
--secure Disables support for handling raw bytes. This flag Should be used
when running in critical path of verified boot.
--backing_file <FILE> location of backing file for the store"
)
}
fn stash_server(
store_manager: Arc<Mutex<store::StoreManager>>,
enable_bytes: bool,
chan: fasync::Channel,
) {
fasync::spawn(async move {
fx_log_info!("new connection");
let mut state = instance::Instance {
client_name: None,
enable_bytes: enable_bytes,
store_manager: store_manager,
};
let mut stream = StoreRequestStream::from_channel(chan);
while let Some(req) = await!(stream.try_next()).context("error running stash server")? {
match req {
StoreRequest::Identify {
name,
control_handle,
} => {
if let Err(e) = state.identify(name.clone()) {
control_handle.shutdown();
return Err(e);
}
fx_log_info!("identified new client: {}", name);
}
StoreRequest::CreateAccessor {
read_only,
control_handle,
accessor_request,
} => {
if let Err(e) = state.create_accessor(read_only, accessor_request) {
control_handle.shutdown();
return Err(e);
}
fx_log_info!("created new accessor");
}
}
}
Ok(())
}.unwrap_or_else(|e: failure::Error| fx_log_err!("couldn't run stash service: {:?}", e)));
}