init: Introduce dependency handling
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
requires_weak 30_live
|
||||
notify hwd
|
||||
notify RSDP_ADDR=$ RSDP_SIZE=$ hwd
|
||||
pcid-spawner --initfs
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
requires_weak 30_live
|
||||
unset RSDP_ADDR RSDP_SIZE
|
||||
notify bcm2835-sdhcid
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
{
|
||||
"unit": {},
|
||||
"unit": {
|
||||
"default_dependencies": false
|
||||
},
|
||||
"service": {
|
||||
"cmd": "nulld",
|
||||
"type": {
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
{
|
||||
"unit": {},
|
||||
"unit": {
|
||||
"default_dependencies": false
|
||||
},
|
||||
"service": {
|
||||
"cmd": "randd",
|
||||
"args": [
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"unit": {
|
||||
"description": "Set time from realtime clock"
|
||||
"description": "Set time from realtime clock",
|
||||
"default_dependencies": false
|
||||
},
|
||||
"service": {
|
||||
"cmd": "rtcd",
|
||||
|
||||
@@ -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"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
{
|
||||
"unit": {},
|
||||
"unit": {
|
||||
"default_dependencies": false
|
||||
},
|
||||
"service": {
|
||||
"cmd": "zerod",
|
||||
"type": {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
requires_weak 00_runtime.target
|
||||
scheme log logd
|
||||
stdio /scheme/log
|
||||
scheme logging ramfs logging
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
requires_weak 30_live
|
||||
notify ps2d
|
||||
notify RSDP_ADDR=$ RSDP_SIZE=$ hwd
|
||||
pcid-spawner --initfs
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
requires_weak 40_drivers
|
||||
REDOXFS_PASSWORD_ADDR=$ REDOXFS_PASSWORD_SIZE=$ redoxfs --uuid $REDOXFS_UUID file $REDOXFS_BLOCK
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
{
|
||||
"unit": {},
|
||||
"unit": {
|
||||
"requires_weak": ["50_rootfs"]
|
||||
},
|
||||
"switchroot": {
|
||||
"prefix": "/usr",
|
||||
"etcdir": "/etc"
|
||||
|
||||
+37
-10
@@ -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<UnitId>,
|
||||
pending_units: &mut VecDeque<UnitId>,
|
||||
unit_store: &mut UnitStore,
|
||||
config: &mut InitConfig,
|
||||
) {
|
||||
@@ -85,7 +85,7 @@ impl SwitchRoot {
|
||||
|
||||
fn run(
|
||||
unit: &UnitId,
|
||||
pending_units: &mut Vec<UnitId>,
|
||||
pending_units: &mut VecDeque<UnitId>,
|
||||
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");
|
||||
|
||||
+5
-1
@@ -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<UnitId>),
|
||||
|
||||
// Service
|
||||
Service(Service),
|
||||
|
||||
@@ -57,6 +60,7 @@ impl Command {
|
||||
};
|
||||
|
||||
match cmd.as_str() {
|
||||
"requires_weak" => Ok(Command::RequiresWeak(args.map(UnitId).collect::<Vec<_>>())),
|
||||
"echo" => Ok(Command::Echo(args.collect::<Vec<_>>().join(" "))),
|
||||
"stdio" => {
|
||||
let Some(stdio) = args.next() else {
|
||||
|
||||
+35
-7
@@ -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<String>,
|
||||
#[serde(default = "true_bool")]
|
||||
pub default_dependencies: bool,
|
||||
#[serde(default)]
|
||||
pub requires: Vec<String>,
|
||||
#[serde(default)]
|
||||
pub requires_weak: Vec<String>,
|
||||
pub requires_weak: Vec<UnitId>,
|
||||
}
|
||||
|
||||
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)?;
|
||||
(
|
||||
|
||||
Reference in New Issue
Block a user