From 80dce054cb8da4a34b1863a7642baeeebf66ebbe Mon Sep 17 00:00:00 2001 From: Ivan Molodetskikh Date: Thu, 21 Sep 2023 19:35:02 +0400 Subject: Use double-fork when spawning subprocesses Fixes https://github.com/YaLTeR/niri/issues/10 --- src/utils.rs | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) (limited to 'src/utils.rs') diff --git a/src/utils.rs b/src/utils.rs index adf14abb..e5ba895c 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,6 +1,9 @@ +use std::ffi::OsStr; use std::fs::File; -use std::io::Read; +use std::io::{self, Read}; +use std::os::unix::process::CommandExt; use std::path::PathBuf; +use std::process::{Command, Stdio}; use std::time::Duration; use anyhow::{anyhow, Context}; @@ -107,3 +110,49 @@ pub fn make_screenshot_path() -> anyhow::Result { Ok(path) } + +/// Spawns the command to run independently of the compositor. +pub fn spawn(command: impl AsRef, args: impl IntoIterator>) { + let _span = tracy_client::span!(); + + let command = command.as_ref(); + + let mut process = Command::new(command); + process + .args(args) + .stdin(Stdio::null()) + .stdout(Stdio::null()) + .stderr(Stdio::null()); + + // Double-fork to avoid having to waitpid the child. + unsafe { + process.pre_exec(|| { + match libc::fork() { + -1 => return Err(io::Error::last_os_error()), + 0 => (), + _ => libc::_exit(0), + } + + Ok(()) + }); + } + + let mut child = match process.spawn() { + Ok(child) => child, + Err(err) => { + warn!("error spawning {command:?}: {err:?}"); + return; + } + }; + + match child.wait() { + Ok(status) => { + if !status.success() { + warn!("child did not exit successfully: {status:?}"); + } + } + Err(err) => { + warn!("error waiting for child: {err:?}"); + } + } +} -- cgit