diff --git a/crates/keyfork/Cargo.toml b/crates/keyfork/Cargo.toml index 3771f5e..a655680 100644 --- a/crates/keyfork/Cargo.toml +++ b/crates/keyfork/Cargo.toml @@ -47,3 +47,4 @@ clap_complete = { version = "4.4.6", optional = true } sequoia-openpgp = { workspace = true } keyforkd-models.workspace = true base64.workspace = true +nix = { version = "0.29.0", default-features = false, features = ["process"] } diff --git a/crates/keyfork/src/cli/recover.rs b/crates/keyfork/src/cli/recover.rs index 48bc3ec..3df6044 100644 --- a/crates/keyfork/src/cli/recover.rs +++ b/crates/keyfork/src/cli/recover.rs @@ -1,6 +1,10 @@ use super::Keyfork; use clap::{Parser, Subcommand}; use std::path::PathBuf; +use nix::{ + sys::wait::waitpid, + unistd::{fork, ForkResult}, +}; use keyfork_mnemonic::{English, Mnemonic}; use keyfork_prompt::{ @@ -80,12 +84,32 @@ impl RecoverSubcommands { pub struct Recover { #[command(subcommand)] command: RecoverSubcommands, + + /// Daemonize the server once started, restoring control back to the shell. + #[arg(long, global=true)] + daemon: bool, } impl Recover { pub fn handle(&self, _k: &Keyfork) -> Result<()> { let seed = self.command.handle()?; let mnemonic = Mnemonic::try_from_slice(&seed)?; + if self.daemon { + // SAFETY: Forking threaded programs is unsafe. We know we don't have multiple + // threads at this point. + match unsafe { fork() }? { + ForkResult::Parent { child } => { + // wait for the child to die, so we don't exit prematurely + waitpid(Some(child), None)?; + return Ok(()); + }, + ForkResult::Child => { + if let ForkResult::Parent { .. } = unsafe { fork() }? { + return Ok(()); + } + }, + } + } tokio::runtime::Builder::new_multi_thread() .enable_all() .build()