Use double-fork when spawning subprocesses

Fixes https://github.com/YaLTeR/niri/issues/10
This commit is contained in:
Ivan Molodetskikh
2023-09-21 19:35:02 +04:00
parent 109668fa30
commit 80dce054cb
3 changed files with 54 additions and 10 deletions
+2 -6
View File
@@ -1,5 +1,3 @@
use std::process::Command;
use smithay::backend::input::{
AbsolutePositionEvent, Axis, AxisSource, ButtonState, Device, DeviceCapability, Event,
GestureBeginEvent, GestureEndEvent, GesturePinchUpdateEvent as _, GestureSwipeUpdateEvent as _,
@@ -19,7 +17,7 @@ use smithay::wayland::tablet_manager::{TabletDescriptor, TabletSeatTrait};
use crate::config::{Action, Config, Modifiers};
use crate::niri::State;
use crate::utils::get_monotonic_time;
use crate::utils::{get_monotonic_time, spawn};
pub enum CompositorMod {
Super,
@@ -149,9 +147,7 @@ impl State {
}
Action::Spawn(command) => {
if let Some((command, args)) = command.split_first() {
if let Err(err) = Command::new(command).args(args).spawn() {
warn!("error spawning {command}: {err}");
}
spawn(command, args);
}
}
Action::Screenshot => {
+2 -3
View File
@@ -25,6 +25,7 @@ use portable_atomic::Ordering;
use smithay::reexports::calloop::EventLoop;
use smithay::reexports::wayland_server::Display;
use tracing_subscriber::EnvFilter;
use utils::spawn;
#[derive(Parser)]
#[command(author, version, about, long_about = None)]
@@ -76,9 +77,7 @@ fn main() {
let mut data = LoopData { display, state };
if let Some((command, args)) = cli.command.split_first() {
if let Err(err) = std::process::Command::new(command).args(args).spawn() {
warn!("error spawning command: {err:?}");
}
spawn(command, args);
}
event_loop
+50 -1
View File
@@ -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:?}");
}
}
}