diff --git a/Cargo.toml b/Cargo.toml index a16a731b7..02ed56493 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -55,6 +55,7 @@ zstd = "0.4" [target.'cfg(unix)'.dependencies] mio = "0.6" mio-extras = "2.0" +daemonize = "0.4" [dependencies.fontconfig] optional = true diff --git a/src/config.rs b/src/config.rs index 76b1c9669..95429b14a 100644 --- a/src/config.rs +++ b/src/config.rs @@ -118,6 +118,9 @@ pub struct Config { #[serde(default)] pub keys: Vec, + + #[serde(default)] + pub daemon_options: DaemonOptions, } #[derive(Debug, Deserialize, Clone)] @@ -362,6 +365,36 @@ fn default_dpi() -> f64 { 96.0 } +#[derive(Default, Debug, Clone, Deserialize)] +pub struct DaemonOptions { + pub pid_file: Option, + pub stdout: Option, + pub stderr: Option, +} + +impl DaemonOptions { + pub fn pid_file(&self) -> PathBuf { + self.pid_file + .as_ref() + .cloned() + .unwrap_or_else(|| RUNTIME_DIR.join("pid")) + } + + pub fn stdout(&self) -> PathBuf { + self.stdout + .as_ref() + .cloned() + .unwrap_or_else(|| RUNTIME_DIR.join("log")) + } + + pub fn stderr(&self) -> PathBuf { + self.stderr + .as_ref() + .cloned() + .unwrap_or_else(|| RUNTIME_DIR.join("log")) + } +} + /// Configures an instance of a multiplexer that can be communicated /// with via a unix domain socket #[derive(Default, Debug, Clone, Deserialize)] @@ -483,6 +516,7 @@ impl Default for Config { keys: vec![], tls_servers: vec![], tls_clients: vec![], + daemon_options: Default::default(), } } } diff --git a/src/main.rs b/src/main.rs index ce4f5e086..9a0d31553 100644 --- a/src/main.rs +++ b/src/main.rs @@ -98,6 +98,10 @@ struct StartCommand { #[structopt(long = "no-auto-connect")] no_auto_connect: bool, + /// Detach from the foreground and become a background process + #[structopt(long = "daemonize")] + daemonize: bool, + /// Instead of executing your shell, run PROG. /// For example: `wezterm start -- bash -l` will spawn bash /// as if it were a login shell. @@ -129,7 +133,23 @@ enum CliSubCommand { List, } -fn run_terminal_gui(config: Arc, opts: &StartCommand) -> Result<(), Error> { +fn run_terminal_gui(config: Arc, opts: &StartCommand) -> Fallible<()> { + #[cfg(unix)] + { + if opts.daemonize { + use std::fs::OpenOptions; + let mut options = OpenOptions::new(); + options.write(true).create(true).append(true); + let stdout = options.open(config.daemon_options.stdout())?; + let stderr = options.open(config.daemon_options.stderr())?; + daemonize::Daemonize::new() + .stdout(stdout) + .stderr(stderr) + .pid_file(config.daemon_options.pid_file()) + .start()?; + } + } + let font_system = opts.font_system.unwrap_or(config.font_system); font_system.set_default();