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.
This commit is contained in:
@@ -100,6 +100,7 @@ pub fn main() -> ! {
|
||||
.filter(|var| !var.starts_with(b"INITFS_"))
|
||||
.collect::<Vec<_>>()
|
||||
};
|
||||
envs.push(b"RUST_BACKTRACE=1");
|
||||
//envs.push(b"LD_DEBUG=all");
|
||||
envs.push(b"LD_LIBRARY_PATH=/scheme/initfs/lib");
|
||||
|
||||
|
||||
+1
-5
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
+30
-26
@@ -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");
|
||||
|
||||
|
||||
+12
-10
@@ -48,7 +48,7 @@ pub enum Command {
|
||||
|
||||
// Misc
|
||||
Echo(String),
|
||||
RunD(Vec<PathBuf>),
|
||||
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::<Vec<_>>();
|
||||
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 {
|
||||
|
||||
Reference in New Issue
Block a user