diff options
| author | Ivan Molodetskikh <yalterz@gmail.com> | 2023-09-21 19:35:02 +0400 |
|---|---|---|
| committer | Ivan Molodetskikh <yalterz@gmail.com> | 2023-09-21 19:35:02 +0400 |
| commit | 80dce054cb8da4a34b1863a7642baeeebf66ebbe (patch) | |
| tree | 763c84d99dba6757fd6d022e2d2d83025d921d43 /src/utils.rs | |
| parent | 109668fa30bf65e56a2723ff29bcadc3e9a6e4ca (diff) | |
| download | niri-80dce054cb8da4a34b1863a7642baeeebf66ebbe.tar.gz niri-80dce054cb8da4a34b1863a7642baeeebf66ebbe.tar.bz2 niri-80dce054cb8da4a34b1863a7642baeeebf66ebbe.zip | |
Use double-fork when spawning subprocesses
Fixes https://github.com/YaLTeR/niri/issues/10
Diffstat (limited to 'src/utils.rs')
| -rw-r--r-- | src/utils.rs | 51 |
1 files changed, 50 insertions, 1 deletions
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<PathBuf> { Ok(path) } + +/// Spawns the command to run independently of the compositor. +pub fn spawn(command: impl AsRef<OsStr>, args: impl IntoIterator<Item = impl AsRef<OsStr>>) { + 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:?}"); + } + } +} |
