From 07c802b93a241d566161d3077b3254df4067fa1e Mon Sep 17 00:00:00 2001 From: Jonas Maier <> Date: Thu, 5 Mar 2026 17:37:52 +0100 Subject: lots of shenanigans to have proper execve reload --- src/main.rs | 38 +++++++++++++++++++++++++++++++++++++- src/run/builtin.rs | 10 +++++++--- src/run/mod.rs | 5 +++++ 3 files changed, 49 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index 81cc5d3..6687937 100644 --- a/src/main.rs +++ b/src/main.rs @@ -248,6 +248,35 @@ fn event_loop() { se.raw.disable(); } +#[cfg(debug_assertions)] +fn reload_shell() { + use std::{env, ffi::CString, ptr}; + + // path to this executable + let exe = env::current_exe().unwrap(); + let exe_c = CString::new(exe.as_os_str().as_bytes()).unwrap(); + + // argv + let args: Vec = env::args().map(|a| CString::new(a).unwrap()).collect(); + + let mut argv: Vec<*const libc::c_char> = args.iter().map(|a| a.as_ptr()).collect(); + argv.push(ptr::null()); + + // environment + let env: Vec = env::vars() + .map(|(k, v)| CString::new(format!("{}={}", k, v)).unwrap()) + .collect(); + + let mut envp: Vec<*const libc::c_char> = env.iter().map(|e| e.as_ptr()).collect(); + envp.push(ptr::null()); + + unsafe { + libc::execve(exe_c.as_ptr(), argv.as_ptr(), envp.as_ptr()); + } + + eprintln!("exec failed"); +} + fn main() { if !io::stdin().is_terminal() { println!("need to run in a tty"); @@ -261,7 +290,14 @@ fn main() { let res = std::panic::catch_unwind(event_loop); match res { Ok(_) => break, - Err(_) => continue, + Err(_) => + { + #[cfg(debug_assertions)] + if run::RELOAD.load(std::sync::atomic::Ordering::SeqCst) { + reload_shell(); + println!("failed to reload shell"); + } + } } } diff --git a/src/run/builtin.rs b/src/run/builtin.rs index 0f90e51..da6f4f2 100644 --- a/src/run/builtin.rs +++ b/src/run/builtin.rs @@ -43,9 +43,13 @@ impl Builtin for re { session.raw.disable(); match Command::new("cargo").arg("build").status() { Ok(status) if status.success() => { - let _ = Command::new("cargo").arg("run").status(); - session.raw.disable(); - std::process::exit(0); + // build of new shell succeeded + + // unwind the entire stack intentionally to free resources + // the catch handler will check the boolean and execve into + // the new executable + super::RELOAD.store(true, std::sync::atomic::Ordering::SeqCst); + std::panic::resume_unwind(Box::new(42)); } _ => (), } diff --git a/src/run/mod.rs b/src/run/mod.rs index 6484e30..0000547 100644 --- a/src/run/mod.rs +++ b/src/run/mod.rs @@ -2,12 +2,17 @@ use std::collections::HashMap; use std::fs; use std::os::unix::fs::PermissionsExt; use std::path::PathBuf; +#[cfg(debug_assertions)] +use std::sync::atomic::AtomicBool; use crate::parse::Ast; use crate::*; mod builtin; +#[cfg(debug_assertions)] +pub static RELOAD: AtomicBool = AtomicBool::new(false); + pub fn run(se: &mut Session, cmd: Vec) { let parsed = parse::do_parse(&cmd); -- cgit v1.2.3