aboutsummaryrefslogtreecommitdiff
path: root/src/utils.rs
diff options
context:
space:
mode:
authorIvan Molodetskikh <yalterz@gmail.com>2023-09-21 19:35:02 +0400
committerIvan Molodetskikh <yalterz@gmail.com>2023-09-21 19:35:02 +0400
commit80dce054cb8da4a34b1863a7642baeeebf66ebbe (patch)
tree763c84d99dba6757fd6d022e2d2d83025d921d43 /src/utils.rs
parent109668fa30bf65e56a2723ff29bcadc3e9a6e4ca (diff)
downloadniri-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.rs51
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:?}");
+ }
+ }
+}