diff --git a/init.d.aarch64-unknown-redox/40_drivers b/init.d.aarch64-unknown-redox/40_drivers index e0eb8e2b1c..54796e015f 100644 --- a/init.d.aarch64-unknown-redox/40_drivers +++ b/init.d.aarch64-unknown-redox/40_drivers @@ -1,3 +1,4 @@ +requires_weak 30_live notify hwd notify RSDP_ADDR=$ RSDP_SIZE=$ hwd pcid-spawner --initfs diff --git a/init.d.aarch64-unknown-redox/40_drivers.raspi3bp b/init.d.aarch64-unknown-redox/40_drivers.raspi3bp index ce5444645a..714b796548 100644 --- a/init.d.aarch64-unknown-redox/40_drivers.raspi3bp +++ b/init.d.aarch64-unknown-redox/40_drivers.raspi3bp @@ -1,2 +1,3 @@ +requires_weak 30_live unset RSDP_ADDR RSDP_SIZE notify bcm2835-sdhcid diff --git a/init.d/00_nulld.service b/init.d/00_nulld.service index 70063c252c..705cc5bd92 100644 --- a/init.d/00_nulld.service +++ b/init.d/00_nulld.service @@ -1,5 +1,7 @@ { - "unit": {}, + "unit": { + "default_dependencies": false + }, "service": { "cmd": "nulld", "type": { diff --git a/init.d/00_randd.service b/init.d/00_randd.service index d0feb1c3fb..8618105bf9 100644 --- a/init.d/00_randd.service +++ b/init.d/00_randd.service @@ -1,5 +1,7 @@ { - "unit": {}, + "unit": { + "default_dependencies": false + }, "service": { "cmd": "randd", "args": [ diff --git a/init.d/00_rtcd.service b/init.d/00_rtcd.service index 5395f03ed1..6c3157d44b 100644 --- a/init.d/00_rtcd.service +++ b/init.d/00_rtcd.service @@ -1,6 +1,7 @@ { "unit": { - "description": "Set time from realtime clock" + "description": "Set time from realtime clock", + "default_dependencies": false }, "service": { "cmd": "rtcd", diff --git a/init.d/00_runtime.target b/init.d/00_runtime.target new file mode 100644 index 0000000000..82d1dd7d30 --- /dev/null +++ b/init.d/00_runtime.target @@ -0,0 +1,12 @@ +{ + "unit": { + "description": "Various daemons that relibc needs to function.", + "default_dependencies": false, + "requires_weak": [ + "00_nulld.service", + "00_randd.service", + "00_rtcd.service", + "00_zerod.service" + ] + } +} diff --git a/init.d/00_zerod.service b/init.d/00_zerod.service index 78916b7ea2..133cc9b52b 100644 --- a/init.d/00_zerod.service +++ b/init.d/00_zerod.service @@ -1,5 +1,7 @@ { - "unit": {}, + "unit": { + "default_dependencies": false + }, "service": { "cmd": "zerod", "type": { diff --git a/init.d/10_logging b/init.d/10_logging index bc1528d194..1908fe00b1 100644 --- a/init.d/10_logging +++ b/init.d/10_logging @@ -1,3 +1,4 @@ +requires_weak 00_runtime.target scheme log logd stdio /scheme/log scheme logging ramfs logging diff --git a/init.d/20_graphics b/init.d/20_graphics index ecfd423b4c..45930814cf 100644 --- a/init.d/20_graphics +++ b/init.d/20_graphics @@ -1,3 +1,4 @@ +requires_weak 10_logging scheme input inputd notify FRAMEBUFFER_ADDR=$ FRAMEBUFFER_VIRT=$ FRAMEBUFFER_WIDTH=$ FRAMEBUFFER_HEIGHT=$ FRAMEBUFFER_STRIDE=$ vesad scheme fbbootlog fbbootlogd diff --git a/init.d/30_live b/init.d/30_live index a5db207150..68020e9f76 100644 --- a/init.d/30_live +++ b/init.d/30_live @@ -1,2 +1,3 @@ +requires_weak 20_graphics # Note: Needs to start before drivers to ensure it gets priority when redoxfs searches for disks notify lived diff --git a/init.d/40_drivers b/init.d/40_drivers index 82daf676c1..8ee66e2da5 100644 --- a/init.d/40_drivers +++ b/init.d/40_drivers @@ -1,3 +1,4 @@ +requires_weak 30_live notify ps2d notify RSDP_ADDR=$ RSDP_SIZE=$ hwd pcid-spawner --initfs diff --git a/init.d/50_rootfs b/init.d/50_rootfs index ece2c67124..798451ab66 100644 --- a/init.d/50_rootfs +++ b/init.d/50_rootfs @@ -1 +1,2 @@ +requires_weak 40_drivers REDOXFS_PASSWORD_ADDR=$ REDOXFS_PASSWORD_SIZE=$ redoxfs --uuid $REDOXFS_UUID file $REDOXFS_BLOCK diff --git a/init.d/90_exit_initfs.switchroot b/init.d/90_exit_initfs.switchroot index 68a2bc311b..054b414d60 100644 --- a/init.d/90_exit_initfs.switchroot +++ b/init.d/90_exit_initfs.switchroot @@ -1,5 +1,7 @@ { - "unit": {}, + "unit": { + "requires_weak": ["50_rootfs"] + }, "switchroot": { "prefix": "/usr", "etcdir": "/etc" diff --git a/init/src/main.rs b/init/src/main.rs index 158761b3a2..4acad75895 100644 --- a/init/src/main.rs +++ b/init/src/main.rs @@ -1,8 +1,8 @@ -use std::collections::BTreeMap; +use std::collections::{BTreeMap, VecDeque}; +use std::env; use std::ffi::OsString; use std::io::Result; use std::path::{Path, PathBuf}; -use std::{env, mem}; use libredox::flag::{O_RDONLY, O_WRONLY}; use serde::Deserialize; @@ -58,7 +58,7 @@ struct SwitchRoot { impl SwitchRoot { fn apply( self, - pending_units: &mut Vec, + pending_units: &mut VecDeque, unit_store: &mut UnitStore, config: &mut InitConfig, ) { @@ -85,7 +85,7 @@ impl SwitchRoot { fn run( unit: &UnitId, - pending_units: &mut Vec, + pending_units: &mut VecDeque, unit_store: &mut UnitStore, config: &mut InitConfig, ) -> Result<()> { @@ -104,12 +104,25 @@ fn run( if config.log_debug { eprintln!( "Starting {}", - unit.info.description.as_ref().unwrap_or(&unit.id.0) + unit.info.description.as_ref().unwrap_or(&unit.id.0), ); } service.spawn(&config.envs); } + unit::UnitKind::Target {} => { + if config.log_debug { + eprintln!( + "Started target {}", + unit.info.description.as_ref().unwrap_or(&unit.id.0), + ); + } + } unit::UnitKind::SwitchRoot { switchroot } => { + eprintln!( + "init: switchroot to {} {}", + switchroot.prefix.display(), + switchroot.etcdir.display() + ); switchroot.clone().apply(pending_units, unit_store, config); } } @@ -119,6 +132,7 @@ fn run( fn run_command(cmd: Command, config: &mut InitConfig) { match cmd { + Command::RequiresWeak(_) => {} // handled by unit parsing code Command::Nothing => {} Command::Echo(text) => println!("{text}"), Command::Stdio(stdio) => { @@ -144,7 +158,7 @@ fn run_command(cmd: Command, config: &mut InitConfig) { fn main() { let mut init_config = InitConfig::new(); let mut unit_store = UnitStore::new(); - let mut pending_units = vec![]; + let mut pending_units = VecDeque::new(); SwitchRoot { prefix: Path::new("/scheme/initfs").to_owned(), @@ -152,12 +166,25 @@ fn main() { } .apply(&mut pending_units, &mut unit_store, &mut init_config); - while !pending_units.is_empty() { - for unit in mem::take(&mut pending_units) { - if let Err(err) = run(&unit, &mut pending_units, &mut unit_store, &mut init_config) { - eprintln!("init: failed to run {}: {}", unit.0, err); + let runtime_target = UnitId("00_runtime.target".to_owned()); + + 'a: while let Some(unit) = pending_units.pop_front() { + if unit_store.unit(&unit).info.default_dependencies { + if pending_units.contains(&runtime_target) { + pending_units.push_back(unit); + continue 'a; } } + for dep in &unit_store.unit(&unit).info.requires_weak { + if pending_units.contains(dep) { + pending_units.push_back(unit); + continue 'a; + } + } + + if let Err(err) = run(&unit, &mut pending_units, &mut unit_store, &mut init_config) { + eprintln!("init: failed to run {}: {}", unit.0, err); + } } 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 0da2ac3183..08298f14cc 100644 --- a/init/src/script.rs +++ b/init/src/script.rs @@ -1,8 +1,8 @@ use std::collections::BTreeMap; -use std::path::PathBuf; use std::{env, io, iter}; use crate::service::{Service, ServiceType}; +use crate::unit::UnitId; fn subst_env<'a>(arg: &str) -> String { if arg.starts_with('$') { @@ -39,6 +39,9 @@ impl Script { #[derive(Clone, Debug)] pub enum Command { + // Dependencies + RequiresWeak(Vec), + // Service Service(Service), @@ -57,6 +60,7 @@ impl Command { }; match cmd.as_str() { + "requires_weak" => Ok(Command::RequiresWeak(args.map(UnitId).collect::>())), "echo" => Ok(Command::Echo(args.collect::>().join(" "))), "stdio" => { let Some(stdio) = args.next() else { diff --git a/init/src/unit.rs b/init/src/unit.rs index 377ceedf60..a03a66bc40 100644 --- a/init/src/unit.rs +++ b/init/src/unit.rs @@ -5,7 +5,7 @@ use std::{fs, io}; use serde::Deserialize; use crate::SwitchRoot; -use crate::script::Script; +use crate::script::{Command, Script}; use crate::service::Service; pub struct UnitStore { @@ -56,12 +56,17 @@ impl UnitStore { (loaded_units, errors) } + pub fn unit(&self, unit: &UnitId) -> &Unit { + self.units.get(unit).unwrap() + } + pub fn unit_mut(&mut self, unit: &UnitId) -> &mut Unit { self.units.get_mut(unit).unwrap() } } -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Deserialize)] +#[serde(transparent)] pub struct UnitId(pub String); pub struct Unit { @@ -74,15 +79,20 @@ pub struct Unit { #[derive(Deserialize)] pub struct UnitInfo { pub description: Option, + #[serde(default = "true_bool")] + pub default_dependencies: bool, #[serde(default)] - pub requires: Vec, - #[serde(default)] - pub requires_weak: Vec, + pub requires_weak: Vec, +} + +fn true_bool() -> bool { + true } pub enum UnitKind { LegacyScript { script: Script }, Service { service: Service }, + Target {}, SwitchRoot { switchroot: SwitchRoot }, } @@ -92,6 +102,11 @@ struct SerializedService { service: Service, } +#[derive(Deserialize)] +struct SerializedTarget { + unit: UnitInfo, +} + #[derive(Deserialize)] struct SerializedSwitchRoot { unit: UnitInfo, @@ -114,11 +129,20 @@ impl Unit { let (info, kind, errors) = match config_path.extension().map(|ext| ext.to_str().unwrap()) { None => { let (script, warnings) = Script::from_str(&config)?; + let mut requires_weak = vec![]; + for command in &script.0 { + match command { + Command::RequiresWeak(deps) => { + requires_weak.extend(deps.into_iter().cloned()) + } + _ => {} + } + } ( UnitInfo { description: None, - requires: vec![], - requires_weak: vec![], + default_dependencies: true, + requires_weak, }, UnitKind::LegacyScript { script }, warnings, @@ -134,6 +158,10 @@ impl Unit { vec![], ) } + Some("target") => { + let target: SerializedTarget = serde_json::from_str(&config)?; + (target.unit, UnitKind::Target {}, vec![]) + } Some("switchroot") => { let switchroot: SerializedSwitchRoot = serde_json::from_str(&config)?; (