diff --git a/init/src/main.rs b/init/src/main.rs index 0ebb4cf47d..0f839a5011 100644 --- a/init/src/main.rs +++ b/init/src/main.rs @@ -54,6 +54,7 @@ impl InitConfig { struct SwitchRoot { prefix: PathBuf, etcdir: PathBuf, + target: Option, } impl SwitchRoot { @@ -82,11 +83,44 @@ impl SwitchRoot { self.etcdir.join("init.d"), ]; - let (loaded_units, errors) = unit_store.load_units(); + let (loaded_units, errors) = unit_store.load_units(UnitId("00_runtime.target".to_owned())); for error in errors { eprintln!("init: {error}"); } pending_units.extend(loaded_units); + + if let Some(target) = self.target { + let (loaded_units, errors) = unit_store.load_units(target); + for error in errors { + eprintln!("init: {error}"); + } + pending_units.extend(loaded_units); + } else { + let entries = match config::config_for_dirs(&unit_store.config_dirs) { + Ok(entries) => entries, + Err(err) => { + eprintln!( + "init: failed to read configs from {}: {err}", + unit_store + .config_dirs + .iter() + .map(|dir| dir.display().to_string()) + .collect::>() + .join(", ") + ); + return; + } + }; + for entry in entries { + let (loaded_units, errors) = unit_store.load_units(UnitId( + entry.file_name().unwrap().to_str().unwrap().to_owned(), + )); + for error in errors { + eprintln!("init: {error}"); + } + pending_units.extend(loaded_units); + } + } } } @@ -149,9 +183,13 @@ fn main() { let mut unit_store = UnitStore::new(); let mut pending_units = VecDeque::new(); + let runtime_target = UnitId("00_runtime.target".to_owned()); + let initfs_target = UnitId("90_initfs.target".to_owned()); + SwitchRoot { prefix: Path::new("/scheme/initfs").to_owned(), etcdir: Path::new("/scheme/initfs/etc").to_owned(), + target: Some(initfs_target.clone()), } .apply(&mut pending_units, &mut unit_store, &mut init_config); @@ -162,9 +200,6 @@ fn main() { eprintln!("init: failed to switch stdio to '/scheme/log': {err}"); } - let runtime_target = UnitId("00_runtime.target".to_owned()); - let initfs_target = UnitId("90_initfs.target".to_owned()); - 'a: while let Some(unit) = pending_units.pop_front() { if let Some(condition_architecture) = &unit_store.unit(&unit).info.condition_architecture { if !condition_architecture @@ -203,6 +238,8 @@ fn main() { SwitchRoot { prefix: PathBuf::from("/usr"), etcdir: PathBuf::from("/etc"), + // FIXME make target non-optional once there is a multi-user.target unit + target: None, //UnitId("multi-user.target".to_owned()), } .apply(&mut pending_units, &mut unit_store, &mut init_config); } diff --git a/init/src/unit.rs b/init/src/unit.rs index 2b77b0e5f7..0c796202fd 100644 --- a/init/src/unit.rs +++ b/init/src/unit.rs @@ -20,36 +20,46 @@ impl UnitStore { } } - pub fn load_units(&mut self) -> (Vec, Vec) { - let mut loaded_units = vec![]; - let mut errors = vec![]; - - let entries = match config::config_for_dirs(&self.config_dirs) { - Ok(entries) => entries, - Err(err) => { - errors.push(format!( - "failed to read configs from {}: {err}", - self.config_dirs - .iter() - .map(|dir| dir.display().to_string()) - .collect::>() - .join(", ") - )); - return (loaded_units, errors); - } + fn load_single_unit(&mut self, unit_id: UnitId) -> (Option, Vec) { + let Some(path) = self + .config_dirs + .iter() + .rev() + .map(|dir| dir.join(&unit_id.0)) + .find(|path| path.exists()) + else { + return (None, vec![format!("unit {} not found", unit_id.0)]); }; - for entry in entries { - let (unit, new_errors) = match Unit::from_file(&entry) { - Ok(unit) => unit, - Err(err) => { - errors.push(format!("{}: {err}", entry.display())); - continue; - } - }; + let (unit, errors) = match Unit::from_file(&path) { + Ok(unit) => unit, + Err(err) => { + return (None, vec![format!("{}: {err}", path.display())]); + } + }; + assert_eq!(unit_id, unit.id); + self.units.insert(unit_id.clone(), unit); + + (Some(unit_id), errors) + } + + pub fn load_units(&mut self, root_unit: UnitId) -> (Vec, Vec) { + let mut loaded_units = vec![]; + let mut pending_units = vec![root_unit]; + let mut errors = vec![]; + + while let Some(unit_id) = pending_units.pop() { + if self.units.contains_key(&unit_id) { + continue; + } + let (unit, new_errors) = self.load_single_unit(unit_id); errors.extend(new_errors); - loaded_units.push(unit.id.clone()); - self.units.insert(unit.id.clone(), unit); + if let Some(unit) = unit { + loaded_units.push(unit.clone()); + for dep in &self.unit(&unit).info.requires_weak { + pending_units.push(dep.clone()); + } + } } (loaded_units, errors)