|
@@ -1,45 +1,65 @@
|
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
mod fuse_daemon;
|
|
mod fuse_daemon;
|
|
|
|
+use btconfig::{config_keys, ConfigBuilderExt, CredStoreCfg, NodeCredConsumer};
|
|
use fuse_daemon::FuseDaemon;
|
|
use fuse_daemon::FuseDaemon;
|
|
-mod config;
|
|
|
|
mod fuse_fs;
|
|
mod fuse_fs;
|
|
|
|
|
|
-use config::{Config, ConfigRef, EnvVars, FsKind};
|
|
|
|
-
|
|
|
|
|
|
+use ::config::Config as ExtConfig;
|
|
use btfproto::{client::FsClient, local_fs::LocalFs, server::FsProvider};
|
|
use btfproto::{client::FsClient, local_fs::LocalFs, server::FsProvider};
|
|
use btlib::{
|
|
use btlib::{
|
|
- config_helpers::from_envvar,
|
|
|
|
- crypto::{
|
|
|
|
- tpm::{TpmCredStore, TpmCreds},
|
|
|
|
- CredStore, Creds, CredsPriv,
|
|
|
|
- },
|
|
|
|
|
|
+ crypto::{Creds, CredsPriv},
|
|
|
|
+ error::BtErr,
|
|
Result,
|
|
Result,
|
|
};
|
|
};
|
|
use btmsg::{transmitter, BlockAddr};
|
|
use btmsg::{transmitter, BlockAddr};
|
|
|
|
+use serde::Deserialize;
|
|
use std::{
|
|
use std::{
|
|
fs::{self},
|
|
fs::{self},
|
|
io,
|
|
io,
|
|
|
|
+ num::NonZeroUsize,
|
|
path::{Path, PathBuf},
|
|
path::{Path, PathBuf},
|
|
sync::Arc,
|
|
sync::Arc,
|
|
};
|
|
};
|
|
use tokio::sync::oneshot;
|
|
use tokio::sync::oneshot;
|
|
|
|
|
|
-const ENVVARS: EnvVars = EnvVars {
|
|
|
|
- block_dir: "BT_BLOCKDIR",
|
|
|
|
- tabrmd: "BT_TABRMD",
|
|
|
|
- mnt_options: "BT_MNTOPTS",
|
|
|
|
- remote_ip: "BT_REMOTEIP",
|
|
|
|
- remote_path: "BT_REMOTEPATH",
|
|
|
|
-};
|
|
|
|
|
|
+#[derive(Debug, PartialEq, Eq, Clone, Deserialize)]
|
|
|
|
+#[serde(tag = "type")]
|
|
|
|
+pub enum FsKind {
|
|
|
|
+ Local { path: PathBuf },
|
|
|
|
+ Remote { addr: BlockAddr },
|
|
|
|
+}
|
|
|
|
|
|
-const DEFAULT_CONFIG: ConfigRef<'static> = ConfigRef {
|
|
|
|
- block_dir: "./bt",
|
|
|
|
- mnt_dir: "./mnt",
|
|
|
|
- tpm_state_file: "./tpm_state",
|
|
|
|
- tabrmd: "bus_type=session",
|
|
|
|
- mnt_options: "default_permissions",
|
|
|
|
- threads: None,
|
|
|
|
-};
|
|
|
|
|
|
+impl FsKind {
|
|
|
|
+ config_keys! {
|
|
|
|
+ const STRUCT_KEY = "fskind";
|
|
|
|
+ const TAG = "type";
|
|
|
|
+ const PATH = "path";
|
|
|
|
+ const ADDR = "addr";
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+#[derive(Debug, Clone, Deserialize)]
|
|
|
|
+struct AppConfig {
|
|
|
|
+ credstore: CredStoreCfg,
|
|
|
|
+ fskind: FsKind,
|
|
|
|
+ mntdir: PathBuf,
|
|
|
|
+ mntoptions: String,
|
|
|
|
+ threads: Option<NonZeroUsize>,
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl AppConfig {
|
|
|
|
+ fn new() -> Result<Self> {
|
|
|
|
+ ExtConfig::builder()
|
|
|
|
+ .set_default(FsKind::TAG, "Local")?
|
|
|
|
+ .set_default(FsKind::PATH, "./state/blocks")?
|
|
|
|
+ .set_default("mntdir", "./state/mnt")?
|
|
|
|
+ .set_default("mntoptions", "default_permissions")?
|
|
|
|
+ .btconfig()?
|
|
|
|
+ .build()?
|
|
|
|
+ .try_deserialize()
|
|
|
|
+ .bterr()
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
|
|
trait PathExt {
|
|
trait PathExt {
|
|
fn try_create_dir(&self) -> io::Result<()>;
|
|
fn try_create_dir(&self) -> io::Result<()>;
|
|
@@ -57,11 +77,6 @@ impl<T: AsRef<Path>> PathExt for T {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-fn node_creds(state_file: PathBuf, tabrmd_cfg: &str) -> Result<TpmCreds> {
|
|
|
|
- let cred_store = TpmCredStore::from_tabrmd(tabrmd_cfg, state_file)?;
|
|
|
|
- cred_store.node_creds()
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
async fn local_provider(btdir: PathBuf, node_creds: Arc<dyn Creds>) -> Result<impl FsProvider> {
|
|
async fn local_provider(btdir: PathBuf, node_creds: Arc<dyn Creds>) -> Result<impl FsProvider> {
|
|
btdir.try_create_dir()?;
|
|
btdir.try_create_dir()?;
|
|
let empty = fs::read_dir(&btdir)?.next().is_none();
|
|
let empty = fs::read_dir(&btdir)?.next().is_none();
|
|
@@ -81,10 +96,8 @@ async fn remote_provider<C: 'static + Creds + Send + Sync>(
|
|
Ok(client)
|
|
Ok(client)
|
|
}
|
|
}
|
|
|
|
|
|
-async fn run_daemon(config: Config, mounted_signal: Option<oneshot::Sender<()>>) {
|
|
|
|
- let node_creds = Arc::new(
|
|
|
|
- node_creds(config.tpm_state_file, &config.tabrmd).expect("failed to get node creds"),
|
|
|
|
- );
|
|
|
|
|
|
+async fn run_daemon(config: AppConfig, mounted_signal: Option<oneshot::Sender<()>>) {
|
|
|
|
+ let node_creds = config.credstore.consume(NodeCredConsumer).unwrap().unwrap();
|
|
let fallback_path = {
|
|
let fallback_path = {
|
|
let writecap = node_creds
|
|
let writecap = node_creds
|
|
.writecap()
|
|
.writecap()
|
|
@@ -92,21 +105,22 @@ async fn run_daemon(config: Config, mounted_signal: Option<oneshot::Sender<()>>)
|
|
.unwrap();
|
|
.unwrap();
|
|
Arc::new(writecap.bind_path())
|
|
Arc::new(writecap.bind_path())
|
|
};
|
|
};
|
|
- let mut daemon = match config.fs_kind {
|
|
|
|
- FsKind::Local(btdir) => {
|
|
|
|
|
|
+ let mut daemon = match config.fskind {
|
|
|
|
+ FsKind::Local { path: btdir } => {
|
|
log::info!("starting daemon with local provider using {:?}", btdir);
|
|
log::info!("starting daemon with local provider using {:?}", btdir);
|
|
let provider = local_provider(btdir, node_creds)
|
|
let provider = local_provider(btdir, node_creds)
|
|
.await
|
|
.await
|
|
.expect("failed to create local provider");
|
|
.expect("failed to create local provider");
|
|
FuseDaemon::new(
|
|
FuseDaemon::new(
|
|
- config.mnt_dir,
|
|
|
|
|
|
+ config.mntdir,
|
|
|
|
+ &config.mntoptions,
|
|
config.threads,
|
|
config.threads,
|
|
fallback_path,
|
|
fallback_path,
|
|
mounted_signal,
|
|
mounted_signal,
|
|
provider,
|
|
provider,
|
|
)
|
|
)
|
|
}
|
|
}
|
|
- FsKind::Remote(remote_addr) => {
|
|
|
|
|
|
+ FsKind::Remote { addr: remote_addr } => {
|
|
log::info!(
|
|
log::info!(
|
|
"starting daemon with remote provider using {:?}",
|
|
"starting daemon with remote provider using {:?}",
|
|
remote_addr.socket_addr()
|
|
remote_addr.socket_addr()
|
|
@@ -115,7 +129,8 @@ async fn run_daemon(config: Config, mounted_signal: Option<oneshot::Sender<()>>)
|
|
.await
|
|
.await
|
|
.expect("failed to create remote provider");
|
|
.expect("failed to create remote provider");
|
|
FuseDaemon::new(
|
|
FuseDaemon::new(
|
|
- config.mnt_dir,
|
|
|
|
|
|
+ config.mntdir,
|
|
|
|
+ &config.mntoptions,
|
|
config.threads,
|
|
config.threads,
|
|
fallback_path,
|
|
fallback_path,
|
|
mounted_signal,
|
|
mounted_signal,
|
|
@@ -131,15 +146,7 @@ async fn run_daemon(config: Config, mounted_signal: Option<oneshot::Sender<()>>)
|
|
#[tokio::main]
|
|
#[tokio::main]
|
|
async fn main() {
|
|
async fn main() {
|
|
env_logger::init();
|
|
env_logger::init();
|
|
- let mut args = std::env::args_os().skip(1).map(PathBuf::from);
|
|
|
|
- let builder = Config::builder()
|
|
|
|
- .with_block_dir(from_envvar(ENVVARS.block_dir).unwrap().map(PathBuf::from))
|
|
|
|
- .with_remote_ip(from_envvar(ENVVARS.remote_ip).unwrap())
|
|
|
|
- .with_remote_path(from_envvar(ENVVARS.remote_path).unwrap())
|
|
|
|
- .with_mnt_dir(args.next())
|
|
|
|
- .with_tabrmd(from_envvar(ENVVARS.tabrmd).unwrap())
|
|
|
|
- .with_mnt_options(from_envvar(ENVVARS.mnt_options).unwrap());
|
|
|
|
- let config = builder.build();
|
|
|
|
|
|
+ let config = AppConfig::new().unwrap();
|
|
run_daemon(config, None).await;
|
|
run_daemon(config, None).await;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -148,7 +155,11 @@ mod test {
|
|
use super::*;
|
|
use super::*;
|
|
|
|
|
|
use btfproto::{local_fs::ModeAuthorizer, server::new_fs_server};
|
|
use btfproto::{local_fs::ModeAuthorizer, server::new_fs_server};
|
|
- use btlib::{crypto::Creds, log::BuilderExt, Epoch, Principaled};
|
|
|
|
|
|
+ use btlib::{
|
|
|
|
+ crypto::{tpm::TpmCredStore, CredStore, Creds},
|
|
|
|
+ log::BuilderExt,
|
|
|
|
+ Epoch, Principaled,
|
|
|
|
+ };
|
|
use btmsg::Receiver;
|
|
use btmsg::Receiver;
|
|
use ctor::ctor;
|
|
use ctor::ctor;
|
|
use std::{
|
|
use std::{
|
|
@@ -242,7 +253,7 @@ mod test {
|
|
const ROOT_PASSWD: &str = "password";
|
|
const ROOT_PASSWD: &str = "password";
|
|
|
|
|
|
struct TestCase<R: Receiver> {
|
|
struct TestCase<R: Receiver> {
|
|
- config: Config,
|
|
|
|
|
|
+ config: AppConfig,
|
|
handle: Option<JoinHandle<()>>,
|
|
handle: Option<JoinHandle<()>>,
|
|
node_principal: OsString,
|
|
node_principal: OsString,
|
|
stop_flag: Option<()>,
|
|
stop_flag: Option<()>,
|
|
@@ -265,13 +276,8 @@ mod test {
|
|
let tmp = TempDir::new("btfuse").unwrap();
|
|
let tmp = TempDir::new("btfuse").unwrap();
|
|
let (mounted_tx, mounted_rx) = oneshot::channel();
|
|
let (mounted_tx, mounted_rx) = oneshot::channel();
|
|
let (swtpm, cred_store) = swtpm();
|
|
let (swtpm, cred_store) = swtpm();
|
|
- let builder = Config::builder()
|
|
|
|
- .with_threads(Some(NonZeroUsize::new(1).unwrap()))
|
|
|
|
- .with_mnt_dir(Some(tmp.path().join("mnt")))
|
|
|
|
- .with_tpm_state_file(Some(swtpm.state_path().to_owned().into()))
|
|
|
|
- .with_tabrmd(Some(swtpm.tabrmd_config().to_owned()));
|
|
|
|
let block_dir = tmp.path().join("bt");
|
|
let block_dir = tmp.path().join("bt");
|
|
- let (config, receiver) = if remote {
|
|
|
|
|
|
+ let (fs_kind, receiver) = if remote {
|
|
let node_creds = Arc::new(cred_store.node_creds().unwrap());
|
|
let node_creds = Arc::new(cred_store.node_creds().unwrap());
|
|
let bind_path = node_creds.bind_path().unwrap();
|
|
let bind_path = node_creds.bind_path().unwrap();
|
|
block_dir.try_create_dir().unwrap();
|
|
block_dir.try_create_dir().unwrap();
|
|
@@ -280,12 +286,22 @@ mod test {
|
|
.unwrap();
|
|
.unwrap();
|
|
let ip_addr = IpAddr::V6(Ipv6Addr::LOCALHOST);
|
|
let ip_addr = IpAddr::V6(Ipv6Addr::LOCALHOST);
|
|
let receiver = new_fs_server(ip_addr, node_creds.clone(), Arc::new(local_fs)).unwrap();
|
|
let receiver = new_fs_server(ip_addr, node_creds.clone(), Arc::new(local_fs)).unwrap();
|
|
- let builder = builder
|
|
|
|
- .with_remote_ip(Some(ip_addr.to_string()))
|
|
|
|
- .with_remote_path(Some(bind_path.to_string()));
|
|
|
|
- (builder.build(), Some(receiver))
|
|
|
|
|
|
+ let fs_kind = FsKind::Remote {
|
|
|
|
+ addr: BlockAddr::new(ip_addr, Arc::new(bind_path)),
|
|
|
|
+ };
|
|
|
|
+ (fs_kind, Some(receiver))
|
|
} else {
|
|
} else {
|
|
- (builder.with_block_dir(Some(block_dir)).build(), None)
|
|
|
|
|
|
+ (FsKind::Local { path: block_dir }, None)
|
|
|
|
+ };
|
|
|
|
+ let config = AppConfig {
|
|
|
|
+ threads: Some(NonZeroUsize::new(1).unwrap()),
|
|
|
|
+ mntdir: tmp.path().join("mnt"),
|
|
|
|
+ credstore: CredStoreCfg::Tpm {
|
|
|
|
+ path: swtpm.state_path().to_owned().into(),
|
|
|
|
+ tabrmd: swtpm.tabrmd_config().to_owned(),
|
|
|
|
+ },
|
|
|
|
+ fskind: fs_kind,
|
|
|
|
+ mntoptions: "default_permissions".to_string(),
|
|
};
|
|
};
|
|
let config_clone = config.clone();
|
|
let config_clone = config.clone();
|
|
let handle = tokio::spawn(async move {
|
|
let handle = tokio::spawn(async move {
|
|
@@ -334,13 +350,13 @@ mod test {
|
|
|
|
|
|
impl<R: Receiver> TestCase<R> {
|
|
impl<R: Receiver> TestCase<R> {
|
|
fn mnt_dir(&self) -> &Path {
|
|
fn mnt_dir(&self) -> &Path {
|
|
- &self.config.mnt_dir
|
|
|
|
|
|
+ &self.config.mntdir
|
|
}
|
|
}
|
|
|
|
|
|
/// Signals to the daemon that it must stop.
|
|
/// Signals to the daemon that it must stop.
|
|
fn signal_stop(&mut self) {
|
|
fn signal_stop(&mut self) {
|
|
if let Some(_) = self.stop_flag.take() {
|
|
if let Some(_) = self.stop_flag.take() {
|
|
- unmount(&self.config.mnt_dir)
|
|
|
|
|
|
+ unmount(&self.config.mntdir)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|