From 0227c0677ce63d04891d051b868b083535e4c024 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 19 Feb 2026 20:18:07 +0100 Subject: [PATCH] init: Introduce switchroot command This sets PATH, LD_LIBRARY_PATH and runs init scripts for the new root. In the future this could replace the entire set of services that should run, restarting any services for which a newer executable is available in the new root and stopping any services which don't exist in the new root. This behavior could also be useful for soft-reboots in the future to handle updates without rebooting the entire system. --- bootstrap/src/exec.rs | 1 + init.d/00_runtime | 6 +---- init.d/90_exit_initfs | 4 +--- init/src/main.rs | 56 +++++++++++++++++++++++-------------------- init/src/script.rs | 22 +++++++++-------- 5 files changed, 45 insertions(+), 44 deletions(-) diff --git a/bootstrap/src/exec.rs b/bootstrap/src/exec.rs index d5100fe5bc..33bb588455 100644 --- a/bootstrap/src/exec.rs +++ b/bootstrap/src/exec.rs @@ -100,6 +100,7 @@ pub fn main() -> ! { .filter(|var| !var.starts_with(b"INITFS_")) .collect::>() }; + envs.push(b"RUST_BACKTRACE=1"); //envs.push(b"LD_DEBUG=all"); envs.push(b"LD_LIBRARY_PATH=/scheme/initfs/lib"); diff --git a/init.d/00_runtime b/init.d/00_runtime index 58973a9c23..d7d4e3d10f 100644 --- a/init.d/00_runtime +++ b/init.d/00_runtime @@ -1,8 +1,4 @@ -# Various daemons that relibc needs to function as well as a bunch of env vars -# that should be set for every program. -export PATH /scheme/initfs/bin -export LD_LIBRARY_PATH /scheme/initfs/lib -export RUST_BACKTRACE 1 +# Various daemons that relibc needs to function. rtcd scheme null nulld scheme zero zerod diff --git a/init.d/90_exit_initfs b/init.d/90_exit_initfs index 80f22bad22..64291d12dd 100644 --- a/init.d/90_exit_initfs +++ b/init.d/90_exit_initfs @@ -1,4 +1,2 @@ cd / -export PATH /usr/bin -export LD_LIBRARY_PATH /usr/lib -run.d /usr/lib/init.d /etc/init.d +switchroot /usr /etc diff --git a/init/src/main.rs b/init/src/main.rs index 9ff4cbacb3..7699b6015b 100644 --- a/init/src/main.rs +++ b/init/src/main.rs @@ -42,6 +42,29 @@ impl InitConfig { } } +fn switch_root(prefix: &Path, etcdir: &Path, config: &InitConfig) { + unsafe { + env::set_var("PATH", prefix.join("bin")); + env::set_var("LD_LIBRARY_PATH", prefix.join("lib")); + } + let entries = match config::config_for_dirs(&[ + prefix.join("lib").join("init.d"), + etcdir.join("init.d"), + ]) { + Ok(list) => list, + Err(err) => { + eprintln!("init: failed to switchroot: '{prefix:?}', '{etcdir:?}': {err}"); + return; + } + }; + + for entry_path in entries { + if let Err(err) = run(&entry_path, config) { + eprintln!("init: failed to run '{}': {}", entry_path.display(), err); + } + } +} + fn run(file: &Path, config: &InitConfig) -> Result<()> { let (script, errors) = script::Script::from_file(file)?; @@ -69,20 +92,8 @@ fn run_command(cmd: Command, config: &InitConfig) { } Command::Echo(text) => println!("{text}"), Command::Export(var, value) => unsafe { env::set_var(var, value) }, - Command::RunD(dirs) => { - let entries = match config::config_for_dirs(&dirs) { - Ok(list) => list, - Err(err) => { - eprintln!("init: failed to run.d: '{dirs:?}': {err}"); - return; - } - }; - - for entry_path in entries { - if let Err(err) = run(&entry_path, config) { - eprintln!("init: failed to run '{}': {}", entry_path.display(), err); - } - } + Command::SwitchRoot(prefix, etcdir) => { + switch_root(&prefix, &etcdir, config); } Command::Stdio(stdio) => { if let Err(err) = switch_stdio(&stdio) { @@ -166,18 +177,11 @@ fn run_command(cmd: Command, config: &InitConfig) { fn main() { let init_config = InitConfig::new(); - let entries = match config::config_for_initfs("init") { - Ok(entries) => entries, - Err(err) => { - eprintln!("init: failed to find config files: {}", err); - return; - } - }; - for entry_path in entries { - if let Err(err) = run(&entry_path, &init_config) { - eprintln!("init: failed to run '{}': {}", entry_path.display(), err); - } - } + switch_root( + Path::new("/scheme/initfs"), + Path::new("/scheme/initfs/etc"), + &init_config, + ); libredox::call::setrens(0, 0).expect("init: failed to enter null namespace"); diff --git a/init/src/script.rs b/init/src/script.rs index 50d8ae2e5f..8c1b30772c 100644 --- a/init/src/script.rs +++ b/init/src/script.rs @@ -48,7 +48,7 @@ pub enum Command { // Misc Echo(String), - RunD(Vec), + SwitchRoot(PathBuf, PathBuf), Nothing, } @@ -80,15 +80,17 @@ impl Command { } Ok(Command::Export(var, value)) } - "run.d" => { - let args = args.map(|arg| PathBuf::from(arg)).collect::>(); - if args.is_empty() { - return Err( - "init: failed to run.d: no argument or all dirs are non-existent" - .to_owned(), - ); - } - Ok(Command::RunD(args)) + "switchroot" => { + let Some(prefix) = args.next() else { + return Err("init: failed to switchroot: no argument".to_owned()); + }; + let Some(etcdir) = args.next() else { + return Err("init: failed to switchroot: missing etcdir".to_owned()); + }; + Ok(Command::SwitchRoot( + PathBuf::from(prefix), + PathBuf::from(etcdir), + )) } "stdio" => { let Some(stdio) = args.next() else {